Skip to content

Commit dd28f00

Browse files
authored
feat: hint alternatives when field-projecting from an unknown type (#11482)
This PR gives suggestions based on the currently-available constants when projecting from an unknown type. ## Example: single suggestion in namespace This was the originally motivating example, as the string refactor led to a number of anonymous-lambda-expressions with `Char` functions that were no longer recognized as such. ```lean4 example := (·.isWhitespace) ``` Before: ``` Invalid field notation: Type of x✝ is not known; cannot resolve field `isWhitespace` ``` The message is unchanged, but this PR adds a hint: ``` Hint: Consider replacing the field projection `.isWhitespace` with a call to the function `Char.isWhitespace`. ``` ## Example: single suggestion in namespace ```lean4 example := fun n => n.succ ``` Before: ``` Invalid field notation: Type of n is not known; cannot resolve field `succ` ``` The message is unchanged, but this PR adds a hint: ``` Hint: Consider replacing the field projection with a call to one of the following: • `Fin.succ` • `Nat.succ` • `Std.PRange.succ` ```
1 parent 54fbe93 commit dd28f00

File tree

2 files changed

+52
-2
lines changed

2 files changed

+52
-2
lines changed

src/Lean/Elab/App.lean

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1376,8 +1376,17 @@ private def resolveLValAux (e : Expr) (eType : Expr) (lval : LVal) : TermElabM L
13761376
has function type{inlineExprTrailing eType}"
13771377

13781378
| .mvar .., .fieldName _ fieldName _ _ =>
1379-
throwNamedError lean.invalidField m!"Invalid field notation: Type of{indentExpr e}\nis not \
1380-
known; cannot resolve field `{fieldName}`"
1379+
let possibleConstants := (← getEnv).constants.fold (fun accum name _ =>
1380+
match name with
1381+
| .str _ s => if s = fieldName && !name.isInternal then accum.push name else accum
1382+
| _ => accum) #[]
1383+
let hint := match possibleConstants with
1384+
| #[] => MessageData.nil
1385+
| #[opt] => .hint' m!"Consider replacing the field projection `.{fieldName}` with a call to the function `{.ofConstName opt}`."
1386+
| opts => .hint' m!"Consider replacing the field projection with a call to one of the following:\
1387+
{MessageData.joinSep (opts.toList.map (indentD m!"• `{.ofConstName ·}`")) .nil}"
1388+
throwNamedError lean.invalidField (m!"Invalid field notation: Type of{indentExpr e}\nis not \
1389+
known; cannot resolve field `{fieldName}`" ++ hint)
13811390
| .mvar .., .fieldIdx _ i =>
13821391
throwError m!"Invalid projection: Type of{indentExpr e}\nis not known; cannot resolve \
13831392
projection `{i}`"

tests/lean/run/invalid_field_notation_mvar.lean

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,30 +9,48 @@ def Foo.f5 (f : Foo) : Nat := f.n
99
error: Invalid field notation: Type of
1010
f
1111
is not known; cannot resolve field `n`
12+
13+
Hint: Consider replacing the field projection with a call to one of the following:
14+
• `BitVec.DivModArgs.n`
15+
• `Foo.n`
1216
---
1317
error: Invalid field notation: Type of
1418
g
1519
is not known; cannot resolve field `n`
20+
21+
Hint: Consider replacing the field projection with a call to one of the following:
22+
• `BitVec.DivModArgs.n`
23+
• `Foo.n`
1624
---
1725
error: Invalid field notation: Type of
1826
f
1927
is not known; cannot resolve field `f1`
28+
29+
Hint: Consider replacing the field projection `.f1` with a call to the function `Foo.f1`.
2030
---
2131
error: Invalid field notation: Type of
2232
g
2333
is not known; cannot resolve field `f2`
34+
35+
Hint: Consider replacing the field projection `.f2` with a call to the function `Foo.f2`.
2436
---
2537
error: Invalid field notation: Type of
2638
h
2739
is not known; cannot resolve field `f3`
40+
41+
Hint: Consider replacing the field projection `.f3` with a call to the function `Foo.f3`.
2842
---
2943
error: Invalid field notation: Type of
3044
f
3145
is not known; cannot resolve field `f4`
46+
47+
Hint: Consider replacing the field projection `.f4` with a call to the function `Foo.f4`.
3248
---
3349
error: Invalid field notation: Type of
3450
g
3551
is not known; cannot resolve field `f5`
52+
53+
Hint: Consider replacing the field projection `.f5` with a call to the function `Foo.f5`.
3654
---
3755
error: Invalid field notation: Type of
3856
h
@@ -51,3 +69,26 @@ is not known; cannot resolve field `foo`
5169
-/
5270
#guard_msgs in
5371
example := fun x => (id x).foo
72+
73+
/--
74+
error: Invalid field notation: Type of
75+
x✝
76+
is not known; cannot resolve field `isWhitespace`
77+
78+
Hint: Consider replacing the field projection `.isWhitespace` with a call to the function `Char.isWhitespace`.
79+
-/
80+
#guard_msgs in
81+
example := (·.isWhitespace)
82+
83+
/--
84+
error: Invalid field notation: Type of
85+
x
86+
is not known; cannot resolve field `succ`
87+
88+
Hint: Consider replacing the field projection with a call to one of the following:
89+
• `Fin.succ`
90+
• `Nat.succ`
91+
• `Std.PRange.succ`
92+
-/
93+
#guard_msgs in
94+
example := fun x => x.succ

0 commit comments

Comments
 (0)