leanprover-community / leanprover-community/lean
Infinite loops in the elaborator
Nobody has claimed this yet.
- Dominant language
- C++
- Stars
- 433
- Forks
- 79
- PR merge metrics
- No merged PRs in 30d
Description
It has been noted by Abel and Coquand in a recent preprint that Lean's type theory allows looping proof terms. See also here for more discussion. It is unclear what effect this has on typechecking, but in principle it shouldn't matter -- the only terms that we can get to loop are proofs, i.e. have types in Prop. Proof irrelevance states that any two proofs of the same proposition are definitionally equal, so there should be no need to reduce any proof terms in order to check them for equality, since the proof-irrelevance rule always applies.
Sadly, the elaborator does not always deal with this properly and fixing that is the actual target of this issue. In current Lean (537f4891732f), the following bit of code goes into an infinite loop in the elaborator:
def top := ∀ p : Prop, p → p
def pext := ∀ (A B : Prop), A → B → A = B
def supercast (h : pext) (A B : Prop) (a : A) (b : B) : B
:= @cast A B (h A B a b) a
def omega : pext → top :=
λ h A a, supercast h (top → top) A
(λ z: top, z (top → top) (λ x, x) z) a
def Omega : pext → top :=
λ h, omega h (top → top) (λ x, x) (omega h)
def Omega' : pext → top := λ h, (λ p x, x)
theorem loopy : Omega = Omega' := rfl -- loops
A naive solution to this which seems not to break other aspects of elaboration is to add a proof-irrelevant (is_def_eq_proof_irrel) equality check before delta-reduction in type_context::is_def_eq_core_core. This prevents definitions from being unfolded in proofs and stops the elaborator loop in the above code, but a fully unfolded term:
theorem loopy : (λ h, (λ h A a, (λ (h': (∀ (A B : Prop), A → B → A = B)) T U t u, (λ α β (h: α = β) (a: α), (eq.rec a h: β)) T U (h' T U t u) t) h ((∀ p : Prop, p → p) → (∀ p : Prop, p → p)) A (λ z: (∀ p : Prop, p → p), z ((∀ p : Prop, p → p) → (∀ p : Prop, p → p)) (λ x, x) z) a) h ((∀ p : Prop, p → p) → (∀ p : Prop, p → p)) (λ x, x) ((λ h A a, (λ (h': (∀ (A B : Prop), A → B → A = B)) T U t u, (λ α β (h: α = β) (a: α), (eq.rec a h: β)) T U (h' T U t u) t) h ((∀ p : Prop, p → p) → (∀ p : Prop, p → p)) A (λ z: (∀ p : Prop, p → p), z ((∀ p : Prop, p → p) → (∀ p : Prop, p → p)) (λ x, x) z) a) h)) = (λ h, (λ p x, x)) := rfl
still gets stuck repeatedly calling type_checker::infer_type_core. At the moment I am unsure how to fix the latter. There is also the question of whether we want to fix it, i.e. prevent the elaborator from reducing proofs, in the first place -- as Mario mentioned, perhaps Turing-complete computation can be useful in proofs.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Reproduce the provided loopy examples in current Lean, then inspect type_context::is_def_eq_core_core in src/library/type_context.cpp and the repeated calls through type_checker::infer_type_core. Compare behavior with and without the proof-irrelevant equality check; done means the elaborator no longer loops while the intended proof-equality behavior remains clear.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 25/100