Compare commits

..

3 Commits

Author SHA1 Message Date
Leonardo de Moura
7818ebdbdc fix: erase macro scopes when matching case tags
After the change to `apply` subgoal naming, the remaining subgoal may
inherit a parent tag that carries hygienic macro scopes (e.g.
`e_a._@._internal._hyg.0`). Appending a constructor-alt name then yields
a tag like `e_a.yield._@._internal._hyg.0`, in which `yield` is not the
literal terminal component, so `case yield` used to fail.

`findTag?` now erases macro scopes from the metavariable's user name
before comparing, so user-written case tags continue to match as
expected. Case tags written by the user are never macro-scoped, so
erasing scopes on the mvar side is sufficient.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 14:11:45 +00:00
Leonardo de Moura
3676797373 test: update tests affected by new apply subgoal tagging
Updates expected outputs and `#guard_msgs` docstrings to reflect the new
`apply` subgoal tagging behavior: when only one unassigned subgoal
remains, it now inherits the parent goal's tag instead of producing a
suffixed tag.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 13:34:28 +00:00
Leonardo de Moura
08688898a2 fix: filter assigned metavariables before computing apply subgoal tags 2026-04-19 15:18:04 +02:00
34 changed files with 26 additions and 27 deletions

View File

@@ -13,11 +13,10 @@ public section
namespace Lean
/-!
# `Loop` type backing `repeat`/`while`/`repeat ... until`
# `while` and `repeat` loop support
The parsers and elaborators for `repeat`, `while`, and `repeat ... until` live in
`Lean.Parser.Do` and `Lean.Elab.BuiltinDo.Repeat`. This module only provides the
`Loop` type (and `ForIn` instance) that those elaborators expand to.
The parsers for `repeat`, `while`, and `repeat ... until` are
`@[builtin_doElem_parser]` definitions in `Lean.Parser.Do`.
-/
inductive Loop where
@@ -34,4 +33,23 @@ partial def Loop.forIn {β : Type u} {m : Type u → Type v} [Monad m] (_ : Loop
instance [Monad m] : ForIn m Loop Unit where
forIn := Loop.forIn
-- The canonical parsers for `repeat`/`while`/`repeat ... until` live in `Lean.Parser.Do`
-- as `@[builtin_doElem_parser]` definitions. We register the expansion macros here so
-- they are available to `prelude` files in `Init`, which do not import `Lean.Elab`.
macro_rules
| `(doElem| repeat%$tk $seq) => `(doElem| for%$tk _ in Loop.mk do $seq)
macro_rules
| `(doElem| while%$tk $h : $cond do $seq) =>
`(doElem| repeat%$tk if $h:ident : $cond then $seq else break)
macro_rules
| `(doElem| while%$tk $cond do $seq) =>
`(doElem| repeat%$tk if $cond then $seq else break)
macro_rules
| `(doElem| repeat%$tk $seq until $cond) =>
`(doElem| repeat%$tk do $seq:doSeq; if $cond then break)
end Lean

View File

@@ -139,14 +139,8 @@ partial def ofElem (stx : TSyntax `doElem) : TermElabM ControlInfo := do
}
| `(doRepeat| repeat $bodySeq) =>
let info ofSeq bodySeq
-- Match `for ... in` and report `numRegularExits := 1` unconditionally. Reporting `0` when
-- the body has no `break` causes `ofSeq` (in any enclosing sequence whose `ControlInfo` is
-- inferred, e.g. a surrounding `for`/`if`/`match`/`try` body) to stop aggregating after this
-- element and miss any `return`/`break`/`continue` that follows. The corresponding elaborator
-- then sees the actual control flow disagree with the inferred info and throws errors like
-- "Early returning ... but the info said there is no early return". See #13437 for details.
return { info with
numRegularExits := 1,
numRegularExits := if info.breaks then 1 else 0,
continues := false,
breaks := false
}

View File

@@ -46,7 +46,7 @@ def eqnAffectingOptions : Array (Lean.Option Bool) := #[backward.eqns.nonrecursi
keyed by declaration name. Only populated when at least one option has a non-default value.
Stores an association list of (option name, value) pairs for options that differ from defaults. -/
builtin_initialize eqnOptionsExt : MapDeclarationExtension (Array (Name × DataValue))
mkMapDeclarationExtension (asyncMode := .local)
mkMapDeclarationExtension (asyncMode := .async .asyncEnv)
def eqnThmSuffixBase := "eq"
def eqnThmSuffixBasePrefix := eqnThmSuffixBase ++ "_"

View File

@@ -145,6 +145,7 @@ public partial def wrapInstance (inst expectedType : Expr) (compile : Bool := tr
else
let name mkAuxDeclName
let wrapped mkAuxDefinition name expectedType inst (compile := false)
setReducibilityStatus name .implicitReducible
if isMeta then modifyEnv (markMeta · name)
if compile then
compileDecls (logErrors := logCompileErrors) #[name]

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -46,7 +46,7 @@ instCD2._aux_1
#guard_msgs in
#print instCD2
/--
info: private def instCD2._aux_1 : C D2 :=
info: @[implicit_reducible] private def instCD2._aux_1 : C D2 :=
instCI2
-/
#guard_msgs in

View File

@@ -489,18 +489,4 @@ example : IO Bool := do
for (x, y) in ([] : List (Nat × Nat)) do count := count + 1
return Float.abs count > 0
-- A `repeat` (without `break`) followed by an early `return` inside an enclosing `for`. The for
-- elaborator computes the loop body's `ControlInfo` via `inferControlInfoSeq`, which stops
-- aggregating once it encounters an element with `numRegularExits := 0`. If `repeat` reported
-- `numRegularExits := 0` for break-less bodies, the trailing `return 2` would be skipped during
-- inference and the for elaborator would later throw "Early returning ... but the info said there
-- is no early return". This test pins down that `repeat` reports `numRegularExits := 1`, matching
-- `for ... in`.
example : IO Nat := do
for _ in [1, 2] do
repeat
pure ()
return 2
return 1
end Repros