Modifies how the declaration command elaborator reports when there are unassigned metavariables. The visible effects are that (1) now errors like "don't know how to synthesize implicit argument" and "failed to infer 'let' declaration type" take precedence over universe level issues, (2) universe level metavariables are reported as metavariables (rather than as `u_1`, `u_2`, etc.), and (3) if the universe level metavariables appear in `let` binding types or `fun` binder types, the error is localized there. Motivation: Reporting unsolved expression metavariables is more important than universe level issues (typically universe issues are from unsolved expression metavariables). Furthermore, `let` and `fun` binders can't introduce universe polymorphism, so we can "blame" such bindings for universe metavariables, if possible. Example 1: Now the errors are on `x` and `none` (reporting expression metavariables) rather than on `example` (which reported universe level metavariables). ```lean example : IO Unit := do let x := none pure () ``` Example 2: Now there is a "failed to infer universe levels in 'let' declaration type" error on `PUnit`. ```lean def foo : IO Unit := do let x : PUnit := PUnit.unit pure () ``` In more detail: * `elabMutualDef` used to turn all level mvars into fresh level parameters before doing an analysis for "hidden levels". This analysis turns out to be exactly the same as instead creating fresh parameters for level mvars in only pre-definitions' types and then looking for level metavariables in their bodies. With this PR, error messages refer to the same level metavariables in the Infoview, rather than obscure generated `u_1`, `u_2`, ... level parameters. * This PR made it possible to push the "hidden levels" check into `addPreDefinitions`, after the checks for unassigned expression mvars. It used to be that if the "hidden levels" check produced an "invalid occurrence of universe level" error it would suppress errors for unassigned expression mvars, and now it is the other way around. * There is now a list of `LevelMVarErrorInfo` objects in the `TermElabM` state. These record expressions that should receive a localized error if they still contain level metavariables. Currently `let` expressions and binder types in general register such info. Error messages make use of a new `exposeLevelMVars` function that adds pretty printer annotations that try to expose all universe level metavariables. * When there are universe level metavariables, for error recovery the definition is still added to the environment after assigning each metavariable to level 0. * There's a new `Lean.Util.CollectLevelMVars` module for collecting level metavariables from expressions. Closes #2058
87 lines
1.8 KiB
Text
87 lines
1.8 KiB
Text
/-!
|
||
# Localized error messages with unassigned metavariables
|
||
-/
|
||
|
||
set_option pp.mvars false
|
||
|
||
|
||
/-!
|
||
Test: now reports "don't know how to synthesize implicit argument" rather than an error on the `example` command.
|
||
-/
|
||
|
||
/--
|
||
error: don't know how to synthesize implicit argument 'α'
|
||
@none ?_
|
||
context:
|
||
⊢ Type _
|
||
---
|
||
error: failed to infer 'let' declaration type
|
||
-/
|
||
#guard_msgs in
|
||
example : IO Unit := do
|
||
let x := none
|
||
pure ()
|
||
|
||
|
||
/-!
|
||
Test: now reports that the universe levels are not assigned at the 'let' rather than an error on the `example` command.
|
||
-/
|
||
|
||
/--
|
||
error: failed to infer universe levels in 'let' declaration type
|
||
PUnit.{_}
|
||
-/
|
||
#guard_msgs in
|
||
def foo : IO Unit := do
|
||
let x : PUnit := PUnit.unit
|
||
pure ()
|
||
|
||
-- specializes to 0 on error
|
||
/--
|
||
info: def foo : IO Unit :=
|
||
let x := PUnit.unit.{0};
|
||
pure.{0, 0} Unit.unit
|
||
-/
|
||
#guard_msgs in set_option pp.universes true in #print foo
|
||
|
||
|
||
/-!
|
||
Test: Works for `have` too.
|
||
-/
|
||
|
||
/--
|
||
error: failed to infer universe levels in 'have' declaration type
|
||
PUnit.{_}
|
||
-/
|
||
#guard_msgs in
|
||
def foo' : IO Unit := do
|
||
have x : PUnit := PUnit.unit
|
||
pure ()
|
||
|
||
|
||
/-!
|
||
Test: Works for `fun` binders.
|
||
-/
|
||
|
||
/--
|
||
error: failed to infer universe levels in binder type
|
||
PUnit.{_}
|
||
-/
|
||
#guard_msgs in
|
||
example : Nat := (fun x : PUnit => 2) PUnit.unit
|
||
|
||
|
||
/-!
|
||
Test: A failure not in a binder, right now reports an error on `example`.
|
||
A change is that before the error was about level parameters rather than metavariables since
|
||
the def elaborator would turn all metavariables into parameters before this analysis.
|
||
-/
|
||
|
||
/--
|
||
error: declaration '_example' contains universe level metavariables at the expression
|
||
Function.const ({α : Sort _} → α → α) 2 @id.{_}
|
||
in the declaration body
|
||
Function.const ({α : Sort _} → α → α) 2 @id.{_}
|
||
-/
|
||
#guard_msgs in
|
||
example : Nat := Function.const _ 2 @id
|