Skip to content

Commit d0c0698

Browse files
committed
[ re #1771 ] Check parameters for positive uses
It's fine to allow positive occurences in (strictly positive) parameters but we do need to check that these occurences are strictly positive!
1 parent b24a9a5 commit d0c0698

File tree

4 files changed

+81
-18
lines changed

4 files changed

+81
-18
lines changed

src/Core/Termination.idr

Lines changed: 33 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import Control.Monad.State
1313
import Libraries.Data.NameMap
1414
import Libraries.Data.SortedMap
1515
import Data.List
16+
import Data.String
1617

1718
%default covering
1819

@@ -610,28 +611,43 @@ nameIn defs tyns _ = pure False
610611

611612
-- Check an argument type doesn't contain a negative occurrence of any of
612613
-- the given type names
613-
posArg : {auto c : Ref Ctxt Defs} ->
614-
Defs -> List Name -> NF [] -> Core Terminating
614+
posArg : {auto c : Ref Ctxt Defs} ->
615+
Defs -> List Name -> NF [] -> Core Terminating
616+
617+
posArgs : {auto c : Ref Ctxt Defs} ->
618+
Defs -> List Name -> List (Closure []) -> Core Terminating
619+
posArgs defs tyn [] = pure IsTerminating
620+
posArgs defs tyn (x :: xs)
621+
= do xNF <- evalClosure defs x
622+
logNF "totality.positivity" 50 "Checking parameter for positivity" [] xNF
623+
IsTerminating <- posArg defs tyn xNF
624+
| err => pure err
625+
posArgs defs tyn xs
626+
615627
-- a tyn can only appear in the parameter positions of
616628
-- tc; report positivity failure if it appears anywhere else
617-
posArg defs tyns nf@(NTCon _ tc _ _ args) =
629+
posArg defs tyns nf@(NTCon loc tc _ _ args) =
618630
do logNF "totality.positivity" 50 "Found a type constructor" [] nf
619-
let testargs : List (Closure [])
620-
= case !(lookupDefExact tc (gamma defs)) of
621-
Just (TCon _ _ params _ _ _ _ _) =>
622-
dropParams 0 params (map snd args)
623-
_ => map snd args
624-
if !(anyM (nameIn defs tyns)
625-
!(traverse (evalClosure defs) testargs))
626-
then pure (NotTerminating NotStrictlyPositive)
627-
else pure IsTerminating
631+
testargs <- case !(lookupDefExact tc (gamma defs)) of
632+
Just (TCon _ _ params _ _ _ _ _) => do
633+
log "totality.positivity" 50 $
634+
unwords [show tc, "has", show (length params), "parameters"]
635+
pure $ splitParams 0 params (map snd args)
636+
_ => throw (GenericMsg loc (show tc ++ " not a data type"))
637+
let (params, indices) = testargs
638+
False <- anyM (nameIn defs tyns) !(traverse (evalClosure defs) indices)
639+
| True => pure (NotTerminating NotStrictlyPositive)
640+
posArgs defs tyns params
628641
where
629-
dropParams : Nat -> List Nat -> List (Closure []) -> List (Closure [])
630-
dropParams i ps [] = []
631-
dropParams i ps (x :: xs)
642+
splitParams : Nat -> List Nat -> List (Closure []) ->
643+
( List (Closure []) -- parameters (to be checked for strict positivity)
644+
, List (Closure []) -- indices (to be checked for no mention at all)
645+
)
646+
splitParams i ps [] = ([], [])
647+
splitParams i ps (x :: xs)
632648
= if i `elem` ps
633-
then dropParams (S i) ps xs
634-
else x :: dropParams (S i) ps xs
649+
then mapFst (x ::) (splitParams (S i) ps xs)
650+
else mapSnd (x ::) (splitParams (S i) ps xs)
635651
-- a tyn can not appear as part of ty
636652
posArg defs tyns nf@(NBind fc x (Pi _ _ e ty) sc)
637653
= do logNF "totality.positivity" 50 "Found a Pi-type" [] nf
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
%default total
2+
3+
data Wrap : Type -> Type where
4+
MkWrap : a -> Wrap a
5+
6+
unwrap : Wrap a -> a
7+
unwrap (MkWrap v) = v
8+
9+
data F : Type where
10+
MkF : Wrap (Not F) -> F
11+
12+
yesF : Not F -> F
13+
yesF = MkF . MkWrap
14+
15+
notF : Not F
16+
notF (MkF f) = unwrap f (yesF $ unwrap f)
17+
18+
argh : Void
19+
argh = notF (yesF notF)

tests/idris2/positivity004/expected

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,3 +50,30 @@ Issue1771-2:6:1--6:18
5050
6 | yesF : Not F -> F
5151
^^^^^^^^^^^^^^^^^
5252

53+
1/1: Building Issue1771-3 (Issue1771-3.idr)
54+
Error: F is not total, not strictly positive
55+
56+
Issue1771-3:9:1--10:26
57+
09 | data F : Type where
58+
10 | MkF : Wrap (Not F) -> F
59+
60+
Error: MkF is not total, not strictly positive
61+
62+
Issue1771-3:10:3--10:6
63+
06 | unwrap : Wrap a -> a
64+
07 | unwrap (MkWrap v) = v
65+
08 |
66+
09 | data F : Type where
67+
10 | MkF : Wrap (Not F) -> F
68+
^^^
69+
70+
Error: yesF is not total, possibly not terminating due to calls to Main.F, Main.MkF
71+
72+
Issue1771-3:12:1--12:18
73+
08 |
74+
09 | data F : Type where
75+
10 | MkF : Wrap (Not F) -> F
76+
11 |
77+
12 | yesF : Not F -> F
78+
^^^^^^^^^^^^^^^^^
79+

tests/idris2/positivity004/run

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
rm -rf build
22

33
$1 --no-banner --no-color --console-width 0 Issue1771-1.idr --check || true
4-
$1 --no-banner --no-color --console-width 0 Issue1771-2.idr --check || true
4+
$1 --no-banner --no-color --console-width 0 Issue1771-2.idr --check || true
5+
$1 --no-banner --no-color --console-width 0 Issue1771-3.idr --check || true

0 commit comments

Comments
 (0)