The `delabConstWithSignature` delaborator is responsible for pretty printing constants with a declaration-like signature, with binders, a colon, and a type. This is used by the `#check` command when it is given just an identifier. It used to accumulate binders from pi types indiscriminately, but this led to unfriendly behavior. For example, `#check String.append` would give ``` String.append (a✝ : String) (a✝¹ : String) : String ``` with inaccessible names. These appear because `String.append` is defined using patterns, so it never names these parameters. Now the delaborator stops accumulating binders once it reaches an inaccessible name, and for example `#check String.append` now gives ``` String.append : String → String → String ``` We do not synthesize names for the sake of enabling binder syntax because the binder names are part of the API of a function — one can use `(arg := ...)` syntax to pass arguments by name. The delaborator also now stops accumulating binders once it reaches a parameter with a name already seen before — we then rely on the main delaborator to provide that parameter with a fresh name when pretty printing the pi type. As a special case, instance parameters with inaccessible names are included as binders, pretty printing like `[LT α]`, rather than relegating them (and all the remaining parameters) to after the colon. It would be more accurate to pretty print this as `[inst✝ : LT α]`, but we make the simplifying assumption that such instance parameters are generally used via typeclass inference. Likely `inst✝` would not directly appear in pretty printer output, and even if it appears in a hover, users can likely figure out what is going on. (We may consider making such `inst✝` variables pretty print as `‹LT α›` or `infer_instance` in the future, to make this more consistent.) Something we note here is that we do not do anything to make sure parameters that can be used as named arguments actually appear named after the colon (nor do we assure that the names are the correct names). For example, one sees `foo : String → String → String` rather than `foo : String → (baz : String) → String`. We can investigate this later if it is wanted. We also give `delabConstWithSignature` a `universes` flag to enable turning off pretty printing universe levels parameters. Closes #2846
74 lines
2.4 KiB
Text
74 lines
2.4 KiB
Text
/-!
|
||
# `delabConstWithSignature` avoids using inaccessible names
|
||
-/
|
||
|
||
/-!
|
||
Defined without named arguments, prints without named arguments.
|
||
-/
|
||
/-- info: String.append : String → String → String -/
|
||
#guard_msgs in #check String.append
|
||
|
||
/-!
|
||
The List argument is not named, it is not printed as a named argument.
|
||
-/
|
||
/-- info: List.length.{u_1} {α : Type u_1} : List α → Nat -/
|
||
#guard_msgs in #check List.length
|
||
|
||
/-!
|
||
All arguments are named, all are printed as named arguments.
|
||
-/
|
||
/-- info: Nat.pos_pow_of_pos {n : Nat} (m : Nat) (h : 0 < n) : 0 < n ^ m -/
|
||
#guard_msgs in #check Nat.pos_pow_of_pos
|
||
|
||
/-!
|
||
The hypothesis is not a named argument, so it's not printed as a named argument.
|
||
-/
|
||
def Nat.pos_pow_of_pos' {n : Nat} (m : Nat) : 0 < n → 0 < n ^ m := Nat.pos_pow_of_pos m
|
||
|
||
/-- info: Nat.pos_pow_of_pos' {n : Nat} (m : Nat) : 0 < n → 0 < n ^ m -/
|
||
#guard_msgs in #check Nat.pos_pow_of_pos'
|
||
|
||
/-!
|
||
Repetition of a named argument, only the first is printed as a named argument.
|
||
-/
|
||
def foo (n n : Nat) : Fin (n + 1) := 0
|
||
|
||
/-- info: foo (n : Nat) : (n : Nat) → Fin (n + 1) -/
|
||
#guard_msgs in #check foo
|
||
|
||
/-!
|
||
Repetition of a named argument, only the first is printed as a named argument.
|
||
This is checking that shadowing is handled correctly (that's not the responsibility of
|
||
`delabConstWithSignature`, but it assumes that the main delaborator will handle this correctly).
|
||
-/
|
||
def foo' (n n : Nat) (a : Fin ((by clear n; exact n) + 1)) : Fin (n + 1) := 0
|
||
|
||
/-- info: foo' (n : Nat) : (n_1 : Nat) → Fin (n + 1) → Fin (n_1 + 1) -/
|
||
#guard_msgs in #check foo'
|
||
|
||
/-!
|
||
Named argument after inaccesible name, still stays after the colon.
|
||
But, it does not print using named pi notation since this is not a dependent type.
|
||
-/
|
||
def foo'' : String → (needle : String) → String := fun _ yo => yo
|
||
|
||
/-- info: foo'' : String → String → String -/
|
||
#guard_msgs in #check foo''
|
||
|
||
/-!
|
||
Named argument after inaccessible name, still stays after the colon.
|
||
Here, because it's a dependent type the named pi notation shows the name.
|
||
-/
|
||
def bar : String → (n : Nat) → Fin (n+1) := fun _ n => ⟨0, Nat.zero_lt_succ n⟩
|
||
|
||
/-- info: bar : String → (n : Nat) → Fin (n + 1) -/
|
||
#guard_msgs in #check bar
|
||
|
||
/-!
|
||
Instance argument is an inaccessible name, and we assume that it is a nameless instance,
|
||
so it goes before the colon.
|
||
-/
|
||
def bar' [LT α] (x : α) : x < x := sorry
|
||
|
||
/-- info: bar'.{u_1} {α : Type u_1} [LT α] (x : α) : x < x -/
|
||
#guard_msgs in #check bar'
|