Skip to content

Commit 9c1c43f

Browse files
committed
Basic termination checker
1 parent 0d1b974 commit 9c1c43f

File tree

6 files changed

+127
-7
lines changed

6 files changed

+127
-7
lines changed

Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ alllib: lib \
1818
lib/Agda/Core/TCM/TCM.hs \
1919
lib/Agda/Core/TCM/Instances.hs \
2020
lib/Agda/Core/Checkers/Converter.hs \
21-
lib/Agda/Core/Checkers/TypeCheck.hs
21+
lib/Agda/Core/Checkers/TypeCheck.hs \
22+
lib/Agda/Core/Checkers/Terminate.hs
2223

2324
# alllib: lib lib/*.hs
2425

agda-core.cabal

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@ library
2424
Agda.Core.Checkers.Converter
2525
Agda.Core.Rules.Typing
2626
Agda.Core.Checkers.TypeCheck
27+
Agda.Core.Checkers.Terminate
2728
Agda.Core.Prelude
29+
Agda.Core.Name
2830
Scope.All
2931
Scope.Core
3032
Scope.Diff

app/Main.hs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ import Agda.Core.Syntax.Term qualified as Core
3939
import Agda.Core.TCM.TCM qualified as Core
4040
import Agda.Core.Prelude qualified as Core
4141
import Agda.Core.Checkers.TypeCheck (checkType)
42+
import Agda.Core.Checkers.Terminate (checkTermination, SubTermContext(..))
4243

4344
import Agda.Utils.Either (maybeRight)
4445
import Agda.Utils.Maybe (mapMaybe, isNothing, fromMaybe)
@@ -306,7 +307,7 @@ agdaCorePostModule ACEnv{toCorePreSignature = ioPreSig} nameMap _ tlm defs = do
306307
reportSDoc "agda-core.check" 2 lineInDoc
307308
reportSDocWarning "agda-core.check" 1 $ text "Warning : Typechecking backend is in developpement"
308309
reportSDocWarning "agda-core.check" 1 $ text "__IMPOSSIBLE__ will be called if terms for which compilation failed are called"
309-
for_ defs \def -> do
310+
for_ (zip (iterate Scope.inThere Scope.inHere) defs) $ \(i, def) -> do
310311
case def of
311312
Left n -> reportSDocFailure "agda-core.check" $ text $ "Skiped " <> n <> " : term not compiled"
312313
Right Core.Definition{ defName, theDef = Core.FunctionDefn funBody, defType } -> do
@@ -315,9 +316,12 @@ agdaCorePostModule ACEnv{toCorePreSignature = ioPreSig} nameMap _ tlm defs = do
315316
let sig = preSignatureToSignature preSig
316317
let fl = Core.More fl
317318
env = Core.MkTCEnv sig fl
319+
case checkTermination StCtxEmpty i [] funBody of
320+
False -> reportSDocFailure "agda-core.check" $ text $ "Termination error for: " <> show defName
321+
True -> reportSDoc "agda-core.check" 1 $ text $ "before TC: " <> show funBody <> " with name: " <> defName <> ", typchecking against: " <> show defType
318322
case Core.runTCM (checkType CtxEmpty funBody defType) env of
319-
Left err -> reportSDoc "agda-core.check" 3 $ text $ " Type checking error: " ++ err
320-
Right ok -> reportSDoc "agda-core.check" 3 $ text " Type checking success"
323+
Left err -> reportSDoc "agda-core.check" 3 $ text $ " Type checking error: " ++ err
324+
Right ok -> reportSDoc "agda-core.check" 3 $ text " Type checking success"
321325
Right Core.Definition{ defName } ->
322326
reportSDocWarning "agda-core.check" 2 $ text $ "Skiped " <> defName <> " : not a function"
323327

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
open import Agda.Core.Prelude
2+
open import Agda.Core.Name
3+
open import Agda.Core.Syntax
4+
open import Agda.Core.Reduce
5+
open import Agda.Core.Rules.Conversion
6+
open import Agda.Core.Rules.Typing
7+
open import Agda.Core.TCM.Instances
8+
open import Agda.Core.Checkers.Converter
9+
10+
11+
module Agda.Core.Checkers.Terminate
12+
{{@0 globals : Globals}}
13+
{{@0 sig : Signature}}
14+
where
15+
16+
private open module @0 G = Globals globals
17+
18+
private variable
19+
@0 x : Name
20+
@0 α : Scope Name
21+
@0 rβ : RScope Name
22+
23+
data SubTermContext : @0 Scope Name Set where
24+
StCtxEmpty : SubTermContext mempty
25+
StCtxExtend : (@0 x : Name) Maybe (NameIn α) SubTermContext α SubTermContext (α ▸ x) -- here x, is a subterm of y.
26+
{-# COMPILE AGDA2HS SubTermContext #-}
27+
28+
private -- it should use a RScope instead of β and then could be public
29+
raiseNameIn : {@0 α β : Scope Name} Singleton β NameIn α NameIn (α <> β)
30+
raiseNameIn r n = weakenNameIn (subJoinDrop r subRefl) n
31+
{-# COMPILE AGDA2HS raiseNameIn #-}
32+
33+
34+
lookupSt :: SubTermContext α) (x : NameIn α) Maybe (NameIn α)
35+
lookupSt StCtxEmpty x = nameInEmptyCase x
36+
lookupSt (StCtxExtend namesubterm nameparent c) name = case (nameInBindCase name
37+
(λ q lookupSt c (⟨ _ ⟩ q))
38+
(λ _ nameparent)) of λ where
39+
(Just n) Just (raiseNameIn (sing _) n)
40+
Nothing Nothing
41+
{-# COMPILE AGDA2HS lookupSt #-}
42+
43+
checkSubtermVar : SubTermContext α NameIn α NameIn α Bool
44+
checkSubtermVar ctx (⟨ _ ⟩ ( param ⟨ _ ⟩)) arg = case (lookupSt ctx arg) of λ where
45+
(Just (⟨ _ ⟩ ( parent ⟨ _ ⟩))) case (param == parent) of λ where
46+
True True
47+
False False -- this needs eventually to check recursively
48+
Nothing False
49+
{-# COMPILE AGDA2HS checkSubtermVar #-}
50+
51+
checkSubterm : SubTermContext α NameIn α Term α Bool
52+
checkSubterm con param (TVar arg) = checkSubtermVar con param arg
53+
checkSubterm con name term = False
54+
{-# COMPILE AGDA2HS checkSubterm #-}
55+
56+
57+
-- At some point make the lists vecs for more security
58+
compareArgsToParams : SubTermContext α List (NameIn α) List (Term α) List Bool
59+
compareArgsToParams con (param ∷ params) (arg ∷ args) = checkSubterm con param arg ∷ compareArgsToParams con params args
60+
compareArgsToParams _ _ _ = []
61+
{-# COMPILE AGDA2HS compareArgsToParams #-}
62+
63+
opaque
64+
unfolding RScope extScope
65+
updateEnv : SubTermContext α (cs : RScope Name) NameIn α SubTermContext (extScope α cs)
66+
updateEnv env [] _ = env
67+
updateEnv env (Erased x ∷ s) name = updateEnv (StCtxExtend x (Just name) env) s (weakenNameIn (subWeaken subRefl) name)
68+
{-# COMPILE AGDA2HS updateEnv #-}
69+
70+
{-# NON_TERMINATING #-} -- need to find a way to not need those
71+
handleBranches : {@0 d : NameData} {@0 cs : RScope (NameCon d)} SubTermContext α NameIn defScope List (NameIn α) NameIn α (bs : Branches α d cs) List Bool
72+
73+
getDecreasingArgs : SubTermContext α NameIn defScope List (NameIn α) Term α List Bool
74+
75+
handleBranches con funName params name BsNil = map (λ _ True) params
76+
handleBranches {α} con funName params name (BsCons (BBranch (c ⟨ w ⟩ ) (fields ⟨ p ⟩ ) clause) branches) =
77+
zipWith (λ x y x && y)
78+
(getDecreasingArgs (updateEnv con fields name) funName
79+
(map (weakenNameIn (subExtScope (sing fields) subRefl)) params)
80+
( subst0 (λ f Term (α ◂▸ f)) p clause ))
81+
(handleBranches con funName params name branches)
82+
83+
{-# COMPILE AGDA2HS handleBranches #-}
84+
85+
86+
getDecreasingArgs con funName params (TApp u v) = case unApps (TApp u v) of λ where
87+
(fun , args) zipWith (λ x y x && y) (foldr (zipWith (λ x y x && y)) (map (λ _ True) params) (map (getDecreasingArgs con funName params) args)) (case fun of λ where
88+
(TDef d) case (d == funName) of λ where
89+
True compareArgsToParams con params args
90+
False map (λ _ True) params
91+
x getDecreasingArgs con funName params x)
92+
getDecreasingArgs con funName params (TLam name body) =
93+
getDecreasingArgs (StCtxExtend name Nothing con) funName (map (weakenNameIn (subWeaken subRefl)) params) body
94+
getDecreasingArgs con funName params (TLet name body1 body2) =
95+
zipWith (λ x y x && y) (getDecreasingArgs con funName params body1)
96+
(getDecreasingArgs (StCtxExtend name Nothing con) funName (map (weakenNameIn (subWeaken subRefl)) params) body2)
97+
getDecreasingArgs con funName params (TCase _ _ (TVar nameVar) branches _) = -- we only accept pattern matching on variable for now.
98+
handleBranches con funName params nameVar branches
99+
getDecreasingArgs _ _ params _ = map (λ _ True) params
100+
{-# COMPILE AGDA2HS getDecreasingArgs #-}
101+
102+
checkTermination : SubTermContext α → NameIn defScope → List (NameIn α) → Term α → Bool
103+
-- unfold the function to get all the arguments and build the env
104+
checkTermination c def params (TLam x body) = checkTermination (StCtxExtend x Nothing c) def ((map (weakenNameIn (subWeaken subRefl)) params) ++ ((⟨ x ⟩ Zero ⟨ IsZero refl ⟩) ∷ [])) body
105+
checkTermination c def params body = any id (getDecreasingArgs c def params body)
106+
{-# COMPILE AGDA2HS checkTermination #-}

src/Agda/Core/Name.agda

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,9 @@ private variable
5454
@0 α : Scope Name
5555

5656
indexToNat : Index Nat
57-
indexToNat Zero = zero
58-
indexToNat (Suc n) = suc (indexToNat n)
57+
indexToNat Zero = 0
58+
indexToNat (Suc n) = 1 + (indexToNat n)
59+
{-# COMPILE AGDA2HS indexToNat #-}
5960

6061
natToIndex : Nat Index
6162
natToIndex zero = Zero
@@ -64,6 +65,7 @@ natToIndex (suc n) = Suc (natToIndex n)
6465
instance
6566
iEqForIndex : Eq Index
6667
iEqForIndex ._==_ = λ n m (indexToNat n) == (indexToNat m)
68+
{-# COMPILE AGDA2HS iEqForIndex #-}
6769

6870
instance
6971
iOrdFromLessThanIndex : OrdFromLessThan Index

src/Agda/Core/Syntax/Weakening.agda

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,17 @@ private variable
1616
@0 c : NameCon d
1717
@0 cs : RScope (NameCon d)
1818

19+
weakenNameIn : α ⊆ β NameIn α NameIn β
20+
weakenNameIn p (⟨ a ⟩ b) = ⟨ a ⟩ coerce p b
21+
1922
weakenTerm : α ⊆ β Term α Term β
2023
weakenTermS : α ⊆ β TermS α rγ TermS β rγ
2124
weakenSort : α ⊆ β Sort α Sort β
2225
weakenType : α ⊆ β Type α Type β
2326
weakenBranch : α ⊆ β Branch α {d = d} c Branch β {d = d} c
2427
weakenBranches : α ⊆ β Branches α d cs Branches β d cs
2528

26-
weakenTerm p (TVar (⟨ x ⟩ k)) = TVar (⟨ x ⟩ coerce p k)
29+
weakenTerm p (TVar x) = TVar (weakenNameIn p x)
2730
weakenTerm p (TDef d) = TDef d
2831
weakenTerm p (TData d ps is) = TData d (weakenTermS p ps) (weakenTermS p is)
2932
weakenTerm p (TCon c vs) = TCon c (weakenTermS p vs)
@@ -52,6 +55,7 @@ weakenBranches p (BsCons b bs) = BsCons (weakenBranch p b) (weakenBranches p bs)
5255
{-# COMPILE AGDA2HS weakenTerm #-}
5356
{-# COMPILE AGDA2HS weakenTermS #-}
5457
{-# COMPILE AGDA2HS weakenType #-}
58+
{-# COMPILE AGDA2HS weakenNameIn #-}
5559
{-# COMPILE AGDA2HS weakenSort #-}
5660
{-# COMPILE AGDA2HS weakenBranch #-}
5761

@@ -110,3 +114,4 @@ lookupVar (CtxExtend g y s) x = raiseType (sing _) (nameInBindCase x
110114
(λ q lookupVar g (⟨ _ ⟩ q))
111115
(λ _ s))
112116
{-# COMPILE AGDA2HS lookupVar #-}
117+

0 commit comments

Comments
 (0)