diff --git a/src/Init/Meta.lean b/src/Init/Meta.lean index da95e2a864..a5e9d492dc 100644 --- a/src/Init/Meta.lean +++ b/src/Init/Meta.lean @@ -21,8 +21,11 @@ def isLetterLike (c : Char) : Bool := (0x2100 ≤ c.val && c.val ≤ 0x214f) || -- Letter like block (0x1d49c ≤ c.val && c.val ≤ 0x1d59f) -- Latin letters, Script, Double-struck, Fractur +def isNumericSubscript (c : Char) : Bool := + 0x2080 ≤ c.val && c.val ≤ 0x2089 + def isSubScriptAlnum (c : Char) : Bool := - (0x2080 ≤ c.val && c.val ≤ 0x2089) || -- numeric subscripts + isNumericSubscript c || (0x2090 ≤ c.val && c.val ≤ 0x209c) || (0x1d62 ≤ c.val && c.val ≤ 0x1d6a) diff --git a/src/Lean/Elab/AutoBound.lean b/src/Lean/Elab/AutoBound.lean new file mode 100644 index 0000000000..d7313ea277 --- /dev/null +++ b/src/Lean/Elab/AutoBound.lean @@ -0,0 +1,35 @@ +/- +Copyright (c) 2020 Microsoft Corporation. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Leonardo de Moura +-/ +import Lean.Data.Options + +/- Basic support for auto bound implicit local names -/ + +namespace Lean.Elab + +builtin_initialize + registerOption `autoBoundImplicitLocal { + defValue := true + group := "" + 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}" + } + +def getAutoBoundImplicitLocalOption (opts : Options) : Bool := + opts.get `autoBoundImplicitLocal true + +private def allNumeral (s : Substring) : Bool := + s.all fun c => c.isDigit || isNumericSubscript c + +def isValidAutoBoundImplicitName (n : Name) : Bool := + match n.eraseMacroScopes with + | Name.str Name.anonymous s _ => s.length > 0 && (isGreek s[0] || s[0].isLower) && allNumeral (s.toSubstring.drop 1) + | _ => false + +def isValidAutoBoundLevelName (n : Name) : Bool := + match n.eraseMacroScopes with + | Name.str Name.anonymous s _ => s.length > 0 && s[0].isLower && allNumeral (s.toSubstring.drop 1) + | _ => false + +end Lean.Elab diff --git a/src/Lean/Elab/Level.lean b/src/Lean/Elab/Level.lean index 0e3cf61bff..6daa79ed3d 100644 --- a/src/Lean/Elab/Level.lean +++ b/src/Lean/Elab/Level.lean @@ -6,6 +6,7 @@ Authors: Leonardo de Moura import Lean.Meta.LevelDefEq import Lean.Elab.Exception import Lean.Elab.Log +import Lean.Elab.AutoBound namespace Lean.Elab.Level @@ -33,17 +34,11 @@ instance : MonadNameGenerator LevelElabM where setNGen ngen := modify fun s => { s with ngen := ngen } - def mkFreshLevelMVar : LevelElabM Level := do let mvarId ← mkFreshId modify fun s => { s with mctx := s.mctx.addLevelMVarDecl mvarId } return mkLevelMVar mvarId -private def isValidAutoBoundLevelName (n : Name) : Bool := - match n.eraseMacroScopes with - | Name.str Name.anonymous s _ => s.length == 1 && s[0].isLower - | _ => false - partial def elabLevel (stx : Syntax) : LevelElabM Level := withRef stx do let kind := stx.getKind if kind == `Lean.Parser.Level.paren then diff --git a/src/Lean/Elab/Term.lean b/src/Lean/Elab/Term.lean index 11d1577e8a..7827c250a4 100644 --- a/src/Lean/Elab/Term.lean +++ b/src/Lean/Elab/Term.lean @@ -16,6 +16,7 @@ import Lean.Util.RecDepth import Lean.Elab.Log import Lean.Elab.Level import Lean.Elab.Attributes +import Lean.Elab.AutoBound namespace Lean.Elab.Term /- @@ -297,16 +298,6 @@ def withLevelNames {α} (levelNames : List Name) (x : TermElabM α) : TermElabM def withoutErrToSorry {α} (x : TermElabM α) : TermElabM α := withReader (fun ctx => { ctx with errToSorry := false }) x -builtin_initialize - registerOption `autoBoundImplicitLocal { - defValue := true - group := "" - descr := "Unbound local variables in declaration headers become implicit arguments if they are a lower case or greek letter. For example, `def f (x : Vector α n) : Vector α n :=` automatically introduces the implicit variables {α n}" - } - -private def getAutoBoundImplicitLocalOption (opts : Options) : Bool := - opts.get `autoBoundImplicitLocal true - /-- Execute `x` with `autoBoundImplicit = (options.get `autoBoundImplicitLocal) && flag` -/ def withAutoBoundImplicitLocal {α} (x : TermElabM α) (flag := true) : TermElabM α := do let flag := getAutoBoundImplicitLocalOption (← getOptions) && flag @@ -1217,11 +1208,6 @@ private def mkConsts (candidates : List (Name × List String)) (explicitLevels : let const ← mkConst constName explicitLevels pure $ (const, projs) :: result -def isValidAutoBoundImplicitName (n : Name) : Bool := - match n.eraseMacroScopes with - | Name.str Name.anonymous s _ => s.length == 1 && (isGreek s[0] || s[0].isLower) - | _ => false - def resolveName (n : Name) (preresolved : List (Name × List String)) (explicitLevels : List Level) : TermElabM (List (Expr × List String)) := do match (← resolveLocalName n) with | some (e, projs) => diff --git a/tests/lean/autoBoundImplicits1.lean b/tests/lean/autoBoundImplicits1.lean index b90003505d..7f57885ed1 100644 --- a/tests/lean/autoBoundImplicits1.lean +++ b/tests/lean/autoBoundImplicits1.lean @@ -16,7 +16,7 @@ def mkVec : Vec α 0 := ⟨ #[], rfl ⟩ def Vec.map (xs : Vec α n) (f : α → β) : Vec β n := ⟨ xs.val.map f, sorry ⟩ -/- unbound implicit locals must be greek or lower case letters -/ +/- unbound implicit locals must be greek or lower case letters followed by numerical digits -/ def Vec.map2 (xs : Vec α size /- error: unknown identifier size -/) (f : α → β) : Vec β n := ⟨ xs.val.map f, sorry ⟩ @@ -65,3 +65,8 @@ def findSomeRev? (as : Array α) (f : α → Option β) : Option β := Id.run <| findSomeRevM? as f end Ex1 + +def apply {α : Type u₁} {β : α → Type u₂} (f : (a : α) → β a) (a : α) : β a := + f a + +def pair (a : α₁) := (a, a)