-
Notifications
You must be signed in to change notification settings - Fork 364
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
Non-terminating function over tuples passed with --termination-depth=2
#6059
Labels
false
Proof of the empty type which checks without known-unsafe flags (e.g. without --type-in-type)
termination
Issues relating to the termination checker
type: bug
Issues and pull requests about actual bugs
Milestone
Comments
@nad wrote:
No, Can you break it? I cannot: open import Agda.Builtin.Nat
data D : Set where
c : Nat → Nat → D
mutual
f : D → Set
f (c (suc n) 0) = g (c n)
f (c n (suc m)) = f (c (suc n) m)
g : (Nat → D) → Set
g h = f (h 42)
|
{-# OPTIONS --termination-depth=2 #-}
open import Agda.Builtin.Nat
open import Agda.Builtin.Equality
data D : Set where
c : Nat → Nat → D
mutual
f : (x : D) → Nat
f (c (suc n) 0) = g (c n)
f (c n (suc (suc m))) = f (c (suc n) m)
f _ = zero
g : (h : Nat → D) → Nat
g h = f (h 2)
loop : f (c 1 0) ≡ zero
loop = refl Loops. |
Closed
And leads to inconsistency: {-# OPTIONS --termination-depth=2 #-}
data ⊥ : Set where
record ⊤ : Set where
data Nat : Set where
zero : Nat
suc : Nat → Nat
{-# BUILTIN NATURAL Nat #-}
data _≡_ (A : Set) : Set → Set₁ where
refl : A ≡ A
cast : ∀{A B : Set} → A ≡ B → A → B
cast refl x = x
cast⁻¹ : ∀{A B : Set} → A ≡ B → B → A
cast⁻¹ refl x = x
-- Exploit the termination checker bug to prove ⊥.
data D : Set where
_,_ : Nat → Nat → D
P : D → Set
P (suc _ , _) = ⊥
P (_ , suc (suc _)) = ⊥
P (0 , 0) = ⊤
P (0 , 1) = ⊤
-- This does not hold definitionally (no exact split), so prove it.
lem : ∀ n {m} → P (n , suc (suc m)) ≡ ⊥
lem 0 = refl
lem (suc n) = refl
mutual
f : (x : D) → P x
-- The loop:
f (suc n , _) = cast (lem n) (g (n ,_)) -- this call to g is fishy!
f (n , suc (suc m)) = cast⁻¹ (lem n) (f (suc n , m))
-- Base cases:
f (0 , 0) = record{}
f (0 , 1) = record{}
g : (h : Nat → D) → P (h 2)
g h = f (h 2)
loop : ⊥
loop = f (1 , 0) I can trace this issue back to at least Agda 2.4.2.4 (my oldest Agda). |
andreasabel
added
the
false
Proof of the empty type which checks without known-unsafe flags (e.g. without --type-in-type)
label
Aug 31, 2022
andreasabel
added a commit
that referenced
this issue
Aug 31, 2022
Underapplied constructor terms are now unrelated to constructor patterns in the termination order.
andreasabel
added a commit
that referenced
this issue
Aug 31, 2022
Underapplied constructor terms are now unrelated to constructor patterns in the termination order.
The use of |
Yeah, now one stumbled over this in 9 years, given the counterexample is contrived and requires |
andreasabel
changed the title
Strange code in the termination checker
Non-terminating function over tuples passed with Oct 24, 2022
--termination-depth=2
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Labels
false
Proof of the empty type which checks without known-unsafe flags (e.g. without --type-in-type)
termination
Issues relating to the termination checker
type: bug
Issues and pull requests about actual bugs
In the following code there is special treatment of the cases "empty, singleton" and "singleton, empty", but in other cases where the lists have different lengths the extra elements are simply discarded:
agda/src/full/Agda/Termination/TermCheck.hs
Lines 1418 to 1430 in efa6fe4
@andreasabel, can you take a look at this? Do the lists necessarily have the same length? Or should we return
Order.unknown
more often?The text was updated successfully, but these errors were encountered: