Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

dot ident notation cannot refer to recursive call #6601

Open
3 tasks done
cppio opened this issue Jan 10, 2025 · 2 comments · May be fixed by #6602
Open
3 tasks done

dot ident notation cannot refer to recursive call #6601

cppio opened this issue Jan 10, 2025 · 2 comments · May be fixed by #6602
Labels
bug Something isn't working

Comments

@cppio
Copy link
Contributor

cppio commented Jan 10, 2025

Prerequisites

Please put an X between the brackets as you perform the following steps:

Description

The dot ident notation currently cannot be used to refer to the function being recursively defined, and attempting to do so results in a confusing error message.

Steps to Reproduce

def Nat.id : Nat → Nat
  | .zero => .zero
  | .succ n => .succ (.id n)

Expected behavior: .id n is equivalent to Nat.id n and n.id, which both succeed with no errors.

Actual behavior: The following error:

invalid dotted identifier notation, unknown identifier `Nat.id` from expected type
  Nat

Versions

Lean 4.16.0-nightly-2025-01-10
Appears in Lean 4.0.0-m5

Impact

Add 👍 to issues you consider important. If others are impacted by this issue, please ask them to add 👍 to it.

@cppio cppio added the bug Something isn't working label Jan 10, 2025
@cppio cppio linked a pull request Jan 10, 2025 that will close this issue
@cppio cppio changed the title dot ident notation cannot find mutually defined definition dot ident notation cannot refer to recursive call Jan 10, 2025
@cppio
Copy link
Contributor Author

cppio commented Jan 11, 2025

Currently when the identifier is not found in the environment, the expected type is unfolded and the identifier is then searched for in the namespace of the unfolded type. This means that fixing this bug (as done in #6602) can break code that relies on the fallback occurring for a dot ident with the same name as the current function.
This can occur when defining an alias to another type, and defining a function that just applies the function of the same name from the original type. For example, code such as the following will be broken by the change:

opaque f : Nat → Nat
def MyEq (x y : Nat) := f x = f y -- an example type which unfolds to Eq
def MyEq.symm : MyEq x y → MyEq y x := .symm

In MyEq.symm, .symm currently cannot find MyEq.symm, so MyEq is unfolded and .symm resolves to Eq.symm. After fixing this bug, .symm will resolve to MyEq.symm, causing a termination error.

The fix for this pattern is simple: mark the definition as nonrec. This is consistent with the postfix dot notation:

def MyEq.symm (h : MyEq x y) : MyEq y x := h.symm -- fail to show termination
nonrec def MyEq.symm (h : MyEq x y) : MyEq y x := h.symm -- works

This pattern of delegating to the same function name in the original type occurs in batteries and mathlib, for example in https://github.com/leanprover-community/batteries/blob/66225aab4f6bd1687053b03916105f7cab140507/Batteries/Data/UnionFind/Lemmas.lean#L100-L101. All of the breakage in batteries and mathlib can be fixed by adding nonrec to the appropriate definitions.

@nomeata
Copy link
Collaborator

nomeata commented Jan 11, 2025

Thanks for the analysis, in particular that it needs the unfold-and-look-again ambiguity.

Especially since postfix dot notation works already as you suggest, I agree with your analysis and fix, and that the broken code was only working accidentally.

Thanks for that!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants