forked from leanprover/lean4
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This PR changes how generalized field notation ("dot notation") resolves the name of the function, adds a feature where terms such as `x.toString` can resolve as `toString x` as a last resort, and modifies the `Function` dot notation to always use the first explicit argument rather than the first function argument. The new rule is that if `x : S`, then `x.f` resolves the name `S.f` relative to the root namespace (hence it now responds to `export` and `open). Breaking change: aliases now resolve differently. Before, if `x : S`, and `S.f` is an alias for `S'.f`, then `x.f` would use `S'.f` and look for an argument of type `S'`. Now, it looks for an argument of type `S`, which is more generally useful behavior. Code making use of the old behavior should consider defining `S` or `S'` in terms of the other, since dot notation can unfold definitions during resolution. This also fixes a bug in explicit field notation (`@x.f`) where `x` could be passed as the wrong argument. Closes leanprover#3031
- Loading branch information
Showing
4 changed files
with
216 additions
and
68 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
/-! | ||
# Tests for generalized field notation through aliases and "top-level" dot notation | ||
https://github.com/leanprover/lean4/issues/3031 | ||
-/ | ||
|
||
/-! | ||
Alias dot notation. There used to be a different kind of alias dot notation; | ||
in the following example, it would have looked for an argument of type `Common.String`. | ||
Now it looks for one of type `String`, allowing libraries to add "extension methods" from within their own namespaces. | ||
-/ | ||
def Common.String.a (s : String) : Nat := s.length | ||
|
||
export Common (String.a) | ||
|
||
/-- info: String.a "x" : Nat -/ | ||
#guard_msgs in #check String.a "x" | ||
/-- info: String.a "x" : Nat -/ | ||
#guard_msgs in #check "x".a | ||
|
||
/-! | ||
Declarations take precedence over aliases | ||
-/ | ||
def String.a (s : String) : Nat := s.length + 100 | ||
/-- info: "x".a : Nat -/ | ||
#guard_msgs in #check "x".a | ||
/-- info: 100 -/ | ||
#guard_msgs in #eval "".a | ||
|
||
/-! | ||
Private declarations take precedence over aliases | ||
-/ | ||
private def String.b (s : String) : Nat := 0 | ||
def Common.String.b (s : String) : Nat := 1 | ||
export Common (String.b) | ||
/-- info: 0 -/ | ||
#guard_msgs in #eval "".b | ||
|
||
/-! | ||
Multiple aliases is an error | ||
-/ | ||
def Common.String.c (s : String) : Nat := 0 | ||
def Common'.String.c (s : String) : Nat := 0 | ||
export Common (String.c) | ||
export Common' (String.c) | ||
/-- | ||
error: invalid field notation 'c', the name 'String.c' is ambiguous, possible interpretations: 'Common'.String.c', 'Common.String.c' | ||
-/ | ||
#guard_msgs in #eval "".c | ||
|
||
/-! | ||
Aliases work with inheritance | ||
-/ | ||
namespace Ex1 | ||
structure A | ||
structure B extends A | ||
def Common.A.x (_ : A) : Nat := 0 | ||
export Common (A.x) | ||
/-- info: fun b => A.x b.toA : B → Nat -/ | ||
#guard_msgs in #check fun (b : B) => b.x | ||
end Ex1 | ||
|
||
/-! | ||
`open` also works | ||
-/ | ||
def Common.String.parse (_ : String) : List Nat := [] | ||
|
||
namespace ExOpen1 | ||
/-- | ||
error: invalid field 'parse', the environment does not contain 'String.parse' | ||
"" | ||
has type | ||
String | ||
-/ | ||
#guard_msgs in #check "".parse | ||
section | ||
open Common | ||
/-- info: String.parse "" : List Nat -/ | ||
#guard_msgs in #check "".parse | ||
end | ||
section | ||
open Common (String.parse) | ||
/-- info: String.parse "" : List Nat -/ | ||
#guard_msgs in #check "".parse | ||
end | ||
end ExOpen1 | ||
|
||
|
||
namespace Ex2 | ||
class A (n : Nat) where | ||
x : Nat | ||
|
||
/-! | ||
"Top-level" dot notation. As a last resort, field notation looks for a top-level declaration or alias | ||
and supplies the value as the first explicit argument. | ||
-/ | ||
instance : ToString (A n) where | ||
toString a := s!"A.x is {a.x}" | ||
|
||
/-- info: fun a => toString a : A 2 → String -/ | ||
#guard_msgs in #check fun (a : A 2) => a.toString | ||
|
||
/-! | ||
Incidental fix: `@` for generalized field notation was failing if there were implicit arguments. | ||
True projections were ok. | ||
-/ | ||
def A.x' {n : Nat} (a : A n) := a.x | ||
|
||
/-- info: fun a => a.x' : A 2 → Nat -/ | ||
#guard_msgs in #check fun (a : A 2) => @a.x' | ||
end Ex2 | ||
|
||
namespace Ex3 | ||
variable (f : α → β) (g : β → γ) | ||
/-! | ||
Functions use the "top-level" dot notation rule: they use the first explicit argument, rather than the first function argument. | ||
-/ | ||
/-- info: g ∘ f : α → γ -/ | ||
#guard_msgs in #check g.comp f | ||
end Ex3 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters