Skip to content

Conversation

@robsimmons
Copy link
Contributor

@robsimmons robsimmons commented Dec 1, 2025

This PR refines several error error messages, mostly involving invalid use of field notation, generalized field notation, and numeric projection. Provides a new error explanation for field notation.

Error message changes

In general:

  • Uses a slightly different convention for expression-type pairs, where the expression is always given indentExpr and the type is given inlineExpr treatment. This is something of a workaround for the fact that the Format type is awkward for embedding possibly-linebreaking expressions in not-linebreaking text, which may be a separate issue worth addressing.
  • Tries to give slightly more "why" reasoning — the environment does not contain String.parse, and therefore you can't project .parse from a String.

Some specific examples:

No such projection function

#check "".parse

before:

error: Invalid field `parse`: The environment does not contain `String.parse`
  ""
has type
  String

after:

error: Invalid field `parse`: The environment does not contain `String.parse`, so it is not possible to project the field `parse` from an expression
  ""
of type `String`

Type does not have the correct form

example (x : α) := (foo x).foo

before:

error: Invalid field notation: Type is not of the form `C ...` where C is a constant
  foo x
has type
  α

after:

error: Invalid field notation: Field projection operates on types of the form `C ...` where C is a constant. The expression
  foo x
has type `α` which does not have the necessary form.

Refactoring

Includes some refactoring changes as well:

  • factors out multiple uses of number (1, 2, 3, 212, 222) to ordinal ("first", "second", "third", "212th", "222nd") conversion into Lean.Elab.ErrorUtils
  • significant refactoring of resolveLValAux in Lean.Elab.App — in place of five helper functions, a special-case function case analysis, and a case analysis on the projection type and structure, there's now a single case analysis on the projection type and structure. This allows several error messages to be more explicit (there were a number of cases where index projection was being described as field projection in an error messages) and gave the opportunity to slightly improve positining for several errors: field notation errors should appear on foo.bar, but field projection errors should appear only on the bar part of foo.bar.

@robsimmons robsimmons changed the title docs: error explanation for invalid field access, associated error message refactoring doc: error explanation for invalid field access, associated error message refactoring Dec 2, 2025
@robsimmons robsimmons changed the title doc: error explanation for invalid field access, associated error message refactoring feat: improve error messages for invalid field access Dec 2, 2025
@robsimmons robsimmons added the changelog-language Language features and metaprograms label Dec 2, 2025
@robsimmons robsimmons marked this pull request as ready for review December 2, 2025 13:23
Copy link
Contributor Author

@robsimmons robsimmons left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Kha can I request a spot-check on my use of the module system for non-exported error functionality here?

Comment on lines +6 to +17
module

prelude
import Init.Notation
import Init.Data.String

/--
Translate numbers (1, 2, 3, 212, 322 ...) to ordinals with appropriate English-language names for
small ordinals (0 through 10 become "zeroth" through "tenth") and postfixes for other numbers
(212 becomes "212th" and 1292 becomes "1292nd").
-/
def _root_.Nat.toOrdinal : Nat -> String
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lean.Elab.ErrorUtils has no public sections, so all its definitions default private

public import Lean.Meta.Tactic.ElimInfo
public import Lean.Elab.Binders
public import Lean.Elab.RecAppSyntax
import all Lean.Elab.ErrorUtils
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm using the error utils with import all

Comment on lines +5 to +7
/-- error: Unknown constant `Nat.toOrdinal` -/
#guard_msgs in
#check Nat.toOrdinal
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

...and then I'm checking after the fact that I didn't accidentally add them to the Lean import

@github-actions github-actions bot added the toolchain-available A toolchain is available for this PR, at leanprover/lean4-pr-releases:pr-release-NNNN label Dec 2, 2025
@leanprover-community-bot
Copy link
Collaborator

Mathlib CI status (docs):

  • ❗ Batteries/Mathlib CI will not be attempted unless your PR branches off the nightly-with-mathlib branch. Try git rebase 5e165e358c7a4dc0e8962dd8f4c283ab7a6baf0f --onto 5bd331e85d9d110a29fb3367dbb21854010ffcbd. You can force Mathlib CI using the force-mathlib-ci label. (2025-12-02 15:32:43)

@leanprover-bot
Copy link
Collaborator

Reference manual CI status:

  • ❗ Reference manual CI will not be attempted unless your PR branches off the nightly-with-manual branch. Try git rebase 5e165e358c7a4dc0e8962dd8f4c283ab7a6baf0f --onto d3dda9f6d4428a906c096067ecb75e432afc4615. You can force reference manual CI using the force-manual-ci label. (2025-12-02 15:32:44)

@robsimmons
Copy link
Contributor Author

Discussed the question I had for @Kha synchronously — the answer is that it's probably not a great idea in general to be doing the namespace polluting additions I'm doing in the current ErrorUtils, if I'm going to do them the private export + import all import is a reasonable approach. We haven't really settled on an overall pattern for this "internal module" structure.

@robsimmons robsimmons added this pull request to the merge queue Dec 2, 2025
Merged via the queue into master with commit edcef51 Dec 2, 2025
16 checks passed
Lean's field notation is very powerful, but this can also make it confusing: the expression
`color.value` can either be a single [identifier](lean-manual://section/identifiers-and-resolution),
it can be a reference to the [field of a structure](lean-manual://section/structure-fiels), and it
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo in url? structure-fiel(d)s

algebraic-dev pushed a commit that referenced this pull request Dec 8, 2025
This PR refines several error error messages, mostly involving invalid
use of field notation, generalized field notation, and numeric
projection. Provides a new error explanation for field notation.

## Error message changes

In general:
- Uses a slightly different convention for expression-type pairs, where
the expression is always given `indentExpr` and the type is given
`inlineExpr` treatment. This is something of a workaround for the fact
that the `Format` type is awkward for embedding possibly-linebreaking
expressions in not-linebreaking text, which may be a separate issue
worth addressing.
- Tries to give slightly more "why" reasoning — the environment does not
contain `String.parse`, and _therefore you can't project `.parse` from a
`String`_.

Some specific examples:

### No such projection function
```lean4
#check "".parse
```
before:
```
error: Invalid field `parse`: The environment does not contain `String.parse`
  ""
has type
  String
```
after:
```
error: Invalid field `parse`: The environment does not contain `String.parse`, so it is not possible to project the field `parse` from an expression
  ""
of type `String`
```

### Type does not have the correct form
```lean4
example (x : α) := (foo x).foo
```
before:
```
error: Invalid field notation: Type is not of the form `C ...` where C is a constant
  foo x
has type
  α
```
after:
```
error: Invalid field notation: Field projection operates on types of the form `C ...` where C is a constant. The expression
  foo x
has type `α` which does not have the necessary form.
```

## Refactoring
Includes some refactoring changes as well:
- factors out multiple uses of number (1, 2, 3, 212, 222) to ordinal
("first", "second", "third", "212th", "222nd") conversion into
Lean.Elab.ErrorUtils
- significant refactoring of `resolveLValAux` in `Lean.Elab.App` — in
place of five helper functions, a special-case function case analysis,
and a case analysis on the projection type and structure, there's now a
single case analysis on the projection type and structure. This allows
several error messages to be more explicit (there were a number of cases
where index projection was being described as field projection in an
error messages) and gave the opportunity to slightly improve positining
for several errors: field *notation* errors should appear on `foo.bar`,
but field *projection* errors should appear only on the `bar` part of
`foo.bar`.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

changelog-language Language features and metaprograms toolchain-available A toolchain is available for this PR, at leanprover/lean4-pr-releases:pr-release-NNNN

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants