This PR introduces a clarifying note to "undefined identifier" error messages when the undefined identifier is in a syntactic position where autobinding might generally apply, but where and autobinding is disabled. A corresponding note is made in the `lean.unknownIdentifier` error explanation. The core intended audience for this error message change is "newcomer who would otherwise be baffled why the thing that works in this Mathlib project gets 'unknown identifier' errors in this non-Mathlib project." ## Modified behavior ### Example 1 ```lean4 set_option autoImplicit true in set_option relaxedAutoImplicit false in def thisBreaks (x : α₂) (y : size₂) := () ``` Before: ``` Unknown identifier `size₂` ``` After: ``` Unknown identifier `size₂` Note: It is not possible to treat `size₂` as an implicitly bound variable here because it has multiple characters while the `relaxedAutoImplicit` option is set to `false`. ``` ### Example 2 ```lean4 set_option autoImplicit false in def thisAlsoBreaks (x : α₃) (y : size₃) := () ``` Before: ``` Unknown identifier `α₃` Unknown identifier `size₃` ``` After: ``` Unknown identifier `α₃` Note: It is not possible to treat `α₃` as an implicitly bound variable here because the `autoImplicit` option is set to `false`. Unknown identifier `size₃` Note: It is not possible to treat `size₃` as an implicitly bound variable here because the `autoImplicit` option is set to `false`. ``` ## How this works The elaboration process knows whether it is considering syntax where we be able to auto-bind implicits thanks to information in the `Lean.Elab.Term.Context`. Before this PR, this contains: * `autoBoundImplicit`, a boolean that is true when we are considering syntax that might be able to auto-bind implicit AND when the `autoImplicit` flag is set to true * `autoBoundImplicits`, an array of `Expr` variables that we've autobound After this PR, this contains: * `autoBoundImplicitCtx`, an option which is `some` **whenever** we are considering syntax that might be able to auto-bind implicit, and carries the array of exprs as well as a copy of the `autoImplicit` flag's value. (The latter lets us re-implement the `autoBoundImplicit` flag for backward compatibility.) Therefore, rather than having access to "elaboration is in an autobinding context && flag is enabled", it's possible to recover both of those individual values, and give different information to the user in cases where we didn't attempt autobinding but would have if different options had been set. ## Rationale The revised error message avoids offering much guidance — it doesn't actively suggest setting the option to a different value or suggest adding an implicit binding. Care needs to be taken here to make sure advice is not misleading; as the accepted RFC in #6462 points out, a substantial portion of autobinding failures are just going to be misspellings. I considered and then rejected a code action here to that would add a local `set_option autoImplicit true`. This seems undesirable or counterproductive — if a project like Mathlib has proactively disabled `autoImplicit`, its odd to be pushing local exceptions. A hint prompting the user to add an implicit binding would be more proper, but only in certain circumstances — we want to be conservative in suggesting specific code actions! In a situation like this one, we'd want to _avoid_ giving the suggestion of adding a `{HasArr}` binding, which I think either requires tricky heuristics or means we'd want the elaboration to play through the consequences of auto-binding and make sure it doesn't cause any follow-on errors before suggesting adding an implicit binding. ``` set_option autoImplicit true set_option relaxedAutoImplicit false instance has_arr : HasArr Preorder := { Arr := Function } ``` Additionally, it seems like it would make the most sense to offer to auto-bind _all_ the relevant unknown identifiers at once. To avoid being misleading, this too would seem to require playing through the consequences of autobinding before being able to safely suggest the change. This is enough additional complexity that I'm leaving it for future work. --------- Co-authored-by: David Thrane Christiansen <david@davidchristiansen.dk>
17 lines
536 B
Text
17 lines
536 B
Text
|
|
set_option autoImplicit true in
|
|
set_option relaxedAutoImplicit true in
|
|
set_option linter.unusedVariables false in
|
|
def thisWorks (x : α₁) (y : size₁) := ()
|
|
|
|
set_option autoImplicit true in
|
|
set_option relaxedAutoImplicit false in
|
|
def thisBreaks (x : α₂) (y : size₂) := ()
|
|
|
|
set_option autoImplicit false in
|
|
set_option relaxedAutoImplicit true in
|
|
def thisAlsoBreaks (x : α₃) (y : size₃) := ()
|
|
|
|
set_option autoImplicit false in
|
|
set_option relaxedAutoImplicit false in
|
|
def thisDefinitelyBreaks (x : α₄) (y : size₄) := ()
|