feat: relax auto-implicit restrictions

The new options `relaxedAutoBoundImplicitLocal` can be used to
disable this feature.

closes #1011
This commit is contained in:
Leonardo de Moura 2022-02-08 12:12:52 -08:00
parent 398b9c136a
commit 59acf01bc9
14 changed files with 30 additions and 13 deletions

View file

@ -21,3 +21,5 @@ theorem dep_congr [DecidableEq ι] {p : ι → Set α} [∀ i, Inhabited (p i)]
* Various improvements to go-to-definition & find-all-references accuracy.
* Auto generated congruence lemmas with support for casts on proofs and `Decidable` instances (see [whishlist](https://github.com/leanprover/lean4/issues/988)).
* [Relax auto-implicit restrictions](https://github.com/leanprover/lean4/pull/1011). The command `set_option relaxedAutoBoundImplicitLocal false` disables the relaxations.

View file

@ -11,9 +11,15 @@ namespace Lean.Elab
register_builtin_option autoBoundImplicitLocal : Bool := {
defValue := true
descr := "Unbound local variables in declaration headers become implicit arguments if they are a lower case or greek letter followed by numeric digits. For example, `def f (x : Vector α n) : Vector α n :=` automatically introduces the implicit variables {α n}."
descr := "Unbound local variables in declaration headers become implicit arguments. In \"relaxed\" mode (default), any atomic identifier is eligible, otherwise only a lower case or greek letter followed by numeric digits are eligible. For example, `def f (x : Vector α n) : Vector α n :=` automatically introduces the implicit variables {α n}."
}
register_builtin_option relaxedAutoBoundImplicitLocal : Bool := {
defValue := true
descr := "When \"relaxed\" mode is enabled, any atomic nonempty identifier is eligible for auto bound implicit locals (see optin `autoBoundImplicitLocal`."
}
private def isValidAutoBoundSuffix (s : String) : Bool :=
s.toSubstring.drop 1 |>.all fun c => c.isDigit || isSubScriptAlnum c || c == '_' || c == '\''
@ -31,14 +37,14 @@ When, we try again, a `x` with a new macro scope is created and this process kee
Therefore, we do consider identifier with macro scopes anymore.
-/
def isValidAutoBoundImplicitName (n : Name) : Bool :=
def isValidAutoBoundImplicitName (n : Name) (relaxed : Bool) : Bool :=
match n with
| Name.str Name.anonymous s _ => s.length > 0 && (isGreek s[0] || s[0].isLower) && isValidAutoBoundSuffix s
| Name.str Name.anonymous s _ => s.length > 0 && (relaxed || ((isGreek s[0] || s[0].isLower) && isValidAutoBoundSuffix s))
| _ => false
def isValidAutoBoundLevelName (n : Name) : Bool :=
def isValidAutoBoundLevelName (n : Name) (relaxed : Bool) : Bool :=
match n with
| Name.str Name.anonymous s _ => s.length > 0 && s[0].isLower && isValidAutoBoundSuffix s
| Name.str Name.anonymous s _ => s.length > 0 && (relaxed || (s[0].isLower && isValidAutoBoundSuffix s))
| _ => false
end Lean.Elab

View file

@ -72,7 +72,7 @@ partial def elabLevel (stx : Syntax) : LevelElabM Level := withRef stx do
else if kind == identKind then
let paramName := stx.getId
unless (← get).levelNames.contains paramName do
if (← read).autoBoundImplicit && isValidAutoBoundLevelName paramName then
if (← read).autoBoundImplicit && isValidAutoBoundLevelName paramName (relaxedAutoBoundImplicitLocal.get (← read).options) then
modify fun s => { s with levelNames := paramName :: s.levelNames }
else
throwError "unknown universe level '{paramName}'"

View file

@ -1418,7 +1418,7 @@ def resolveName (stx : Syntax) (n : Name) (preresolved : List (Name × List Stri
throw ex
where process (candidates : List (Name × List String)) : TermElabM (List (Expr × List String)) := do
if candidates.isEmpty then
if (← read).autoBoundImplicit && isValidAutoBoundImplicitName n then
if (← read).autoBoundImplicit && isValidAutoBoundImplicitName n (relaxedAutoBoundImplicitLocal.get (← getOptions)) then
throwAutoBoundImplicitLocal n
else
throwError "unknown identifier '{Lean.mkConst n}'"

5
tests/lean/1011.lean Normal file
View file

@ -0,0 +1,5 @@
def f (x : A) := x
set_option relaxedAutoBoundImplicitLocal false
def g (x : A) := x

View file

@ -0,0 +1 @@
1011.lean:5:11-5:12: error: unknown identifier 'A'

View file

@ -1,5 +1,5 @@
def myid (a : α) := a -- works
set_option relaxedAutoBoundImplicitLocal false
#check myid 10
#check myid true

View file

@ -1,6 +1,6 @@
def f [Add α] (a : α) : α :=
a + a
set_option relaxedAutoBoundImplicitLocal false
def BV (n : Nat) := { a : Array Bool // a.size = n }
def allZero (bv : BV n) : Prop :=

View file

@ -1,3 +1,4 @@
set_option relaxedAutoBoundImplicitLocal false
inductive Foo where
| bar : F
--^ textDocument/completion

View file

@ -1,5 +1,5 @@
{"textDocument": {"uri": "file://533.lean"},
"position": {"line": 1, "character": 10}}
"position": {"line": 2, "character": 10}}
{"items":
[{"label": "False", "kind": 22, "detail": "Prop"},
{"label": "Fin", "kind": 22, "detail": "Nat → Type"},

View file

@ -1,3 +1,4 @@
set_option relaxedAutoBoundImplicitLocal false
inductive Foo
| mk : (a b : Bar) → Foo
--^ textDocument/hover

View file

@ -1,3 +1,3 @@
{"textDocument": {"uri": "file://hoverException.lean"},
"position": {"line": 1, "character": 14}}
"position": {"line": 2, "character": 14}}
null

View file

@ -1,3 +1,4 @@
set_option relaxedAutoBoundImplicitLocal false
instance has_arr : HasArr Preorder := { Arr := Function }
def foo : Nat := { first := 10 }

View file

@ -1,3 +1,3 @@
structSorryBug.lean:1:19-1:25: error: unknown identifier 'HasArr'
structSorryBug.lean:3:17-3:32: error: invalid {...} notation, structure type expected
structSorryBug.lean:2:19-2:25: error: unknown identifier 'HasArr'
structSorryBug.lean:4:17-4:32: error: invalid {...} notation, structure type expected
Nat