Zulip Chat Archive
Stream: lean4
Topic: termination compiler app error
Mario Carneiro (Dec 15 2021 at 21:41):
I think the error here is somewhere in the termination checker, but I haven't minimized it further than this:
def heapifyDown (lt : α → α → Bool) (a : Array α) (i : Fin a.size) : Array α :=
let left := 2 * i.1 + 1
let right := left + 1
have left_le : i ≤ left := sorry
have right_le : i ≤ right := sorry
have i_le : i ≤ i := Nat.le_refl _
have j : {j : Fin a.size // i ≤ j} := if h : left < a.size then
if lt (a.get i) (a.get ⟨left, h⟩) then ⟨⟨left, h⟩, left_le⟩ else ⟨i, i_le⟩ else ⟨i, i_le⟩
have j := if h : right < a.size then
if lt (a.get j) (a.get ⟨right, h⟩) then ⟨⟨right, h⟩, right_le⟩ else j else j
if h : i ≠ j then
let a' := a.swap i j
have : a'.size - j < a.size - i := sorry
heapifyDown lt a' ⟨j.1.1, a.size_swap i j ▸ j.1.2⟩
else
a
termination_by measure fun ⟨_, _, a, i⟩ => a.size - i.1
decreasing_by assumption
gives an error on the def heapifyDown
saying:
application type mismatch
LE.le snd✝
argument has type
Fin (Array.size fst✝)
but function has type
Fin x✝ → Fin x✝ → Prop
Leonardo de Moura (Dec 15 2021 at 21:46):
@Mario Carneiro Thanks for reporting the issue. I will be very grateful if you manage to minimize the example.
Mario Carneiro (Dec 15 2021 at 21:47):
smaller version
def heapifyDown (a : Array α) (i : Fin a.size) : Array α :=
have : i < i := sorry
heapifyDown a ⟨i.1, a.size_swap i i ▸ i.2⟩
termination_by measure fun ⟨_, a, i⟩ => i.1
decreasing_by assumption
Leonardo de Moura (Dec 15 2021 at 21:47):
Thanks! :)
Mario Carneiro (Dec 15 2021 at 21:47):
removing the a.size_swap i i ▸
makes the error go away. I think the version of the goal in the assumption
context is ill typed
Mario Carneiro (Dec 15 2021 at 21:58):
Replacing assumption
with done
and setting pp.all
reveals the context:
unsolved goals
fst✝¹ : Type u_1
fst✝ : Array.{u_1} fst✝¹
snd✝ : Fin (@Array.size.{u_1} fst✝¹ fst✝)
this : @LT.lt.{0} (Fin (@Array.size.{u_1} fst✝¹ fst✝)) (@instLTFin (@Array.size.{u_1} fst✝¹ fst✝)) snd✝ snd✝
⊢ (@measure.{u_1 + 2}
(@PSigma.{u_1 + 2, u_1 + 1} (Type u_1)
fun {α : Type u_1} =>
@PSigma.{u_1 + 1, 1} (Array.{u_1} α) fun (a : Array.{u_1} α) => Fin (@Array.size.{u_1} α a))
fun
(x :
@PSigma.{u_1 + 2, u_1 + 1} (Type u_1)
fun {α : Type u_1} =>
@PSigma.{u_1 + 1, 1} (Array.{u_1} α) fun (a : Array.{u_1} α) => Fin (@Array.size.{u_1} α a)) =>
heapifyDown._unary.match_1.{u_1, 1}
(fun
(x :
@PSigma.{u_1 + 2, u_1 + 1} (Type u_1)
fun {α : Type u_1} =>
@PSigma.{u_1 + 1, 1} (Array.{u_1} α) fun (a : Array.{u_1} α) => Fin (@Array.size.{u_1} α a)) =>
Nat)
x
fun (x : Type u_1) (a : Array.{u_1} x) (i : Fin (@Array.size.{u_1} x a)) =>
@Fin.val (@Array.size.{u_1} x a) i).1
(@PSigma.mk.{u_1 + 2, u_1 + 1} (Type u_1)
(fun {α : Type u_1} =>
@PSigma.{u_1 + 1, 1} (Array.{u_1} α) fun (a : Array.{u_1} α) => Fin (@Array.size.{u_1} α a))
fst✝¹
(@PSigma.mk.{u_1 + 1, 1} (Array.{u_1} fst✝¹) (fun (a : Array.{u_1} fst✝¹) => Fin (@Array.size.{u_1} fst✝¹ a)) fst✝
(@Fin.mk (@Array.size.{u_1} fst✝¹ fst✝) (@Fin.val (@Array.size.{u_1} fst✝¹ fst✝) snd✝)
(@Eq.ndrec.{0, 1} Nat (@Array.size.{u_1} fst✝¹ (@Array.swap.{u_1} fst✝¹ fst✝ snd✝ snd✝))
(fun (x : Nat) => @LT.lt.{0} Nat instLTNat (@Fin.val x snd✝) x)
(@Eq.ndrec.{0, 1} Nat (@Array.size.{u_1} fst✝¹ fst✝)
(fun (x : Nat) => @LT.lt.{0} Nat instLTNat (@Fin.val x snd✝) x)
(@Fin.isLt (@Array.size.{u_1} fst✝¹ fst✝) snd✝)
(@Array.size.{u_1} fst✝¹ (@Array.swap.{u_1} fst✝¹ fst✝ snd✝ snd✝))
(@Eq.symm.{1} Nat (@Array.size.{u_1} fst✝¹ (@Array.swap.{u_1} fst✝¹ fst✝ snd✝ snd✝))
(@Array.size.{u_1} fst✝¹ fst✝) (@Array.size_swap.{u_1} fst✝¹ fst✝ snd✝ snd✝)))
(@Array.size.{u_1} fst✝¹ fst✝) (@Array.size_swap.{u_1} fst✝¹ fst✝ snd✝ snd✝)))))
(@PSigma.mk.{u_1 + 2, u_1 + 1} (Type u_1)
(fun {α : Type u_1} =>
@PSigma.{u_1 + 1, 1} (Array.{u_1} α) fun (a : Array.{u_1} α) => Fin (@Array.size.{u_1} α a))
fst✝¹
(@PSigma.mk.{u_1 + 1, 1} (Array.{u_1} fst✝¹) (fun (a : Array.{u_1} fst✝¹) => Fin (@Array.size.{u_1} fst✝¹ a)) fst✝
snd✝))
which contains a subterm fun (x : Nat) => @LT.lt.{0} Nat instLTNat (@Fin.val x snd✝) x
which is ill typed because snd✝ : Fin (@Array.size.{u_1} fst✝¹ fst✝)
instead of Fin x
. This looks like the kind of replacement that rw
will sometimes do that yields the motive is not type correct
error in lean 3
Mario Carneiro (Dec 15 2021 at 22:01):
Oh, the termination compiler is a red herring. This has the same error:
def heapifyDown' (a : Array α) (i : Fin a.size) : Array α := sorry
def heapifyDown (a : Array α) (i : Fin a.size) : Array α :=
heapifyDown' a ⟨i.1, a.size_swap i i ▸ i.2⟩
Mario Carneiro (Dec 15 2021 at 22:03):
minimized more:
example (a : Array α) (i : Fin a.size) : i.1 < a.size := a.size_swap i i ▸ i.2
Mario Carneiro (Dec 15 2021 at 22:15):
minimized more:
variable (a : Nat) (i : Fin a) (h : 1 = a)
#check (h ▸ i.2 : i < a) -- h ▸ Eq.symm h ▸ i.isLt : i.val < a
example : i < a := h ▸ i.2
-- application type mismatch
-- i.val
-- argument has type
-- Fin a
-- but function has type
-- Fin x✝ → Nat
The check result is very weird (and there are in fact two Eq.ndrec
nodes being generated), but I don't think it is the issue. It seems like this actually is a motive is not type correct
error, but it passes elaboration and gets caught late
Leonardo de Moura (Dec 16 2021 at 00:19):
I pushed a fix for this. The ▸
notation now type checks the generated motives like the rw
tactic.
Last updated: Dec 20 2023 at 11:08 UTC