on master help sign in
Make coverage checking more conservative
9f202dcEdwin Brady
idris.cabal+3
@@ -751,6 +751,9 @@ Extra-source-files:
751 test/totality010/run
751 test/totality010/run
752 test/totality010/*.idr
752 test/totality010/*.idr
753 test/totality010/expected
753 test/totality010/expected
754+ test/totality011/run
755+ test/totality011/*.lidr
756+ test/totality011/expected
754
757
755 test/tutorial001/run
758 test/tutorial001/run
756 test/tutorial001/*.idr
759 test/tutorial001/*.idr
src/Idris/Coverage.hs+29−14
@@ -59,10 +59,16 @@ genClauses fc n xs given
59 let lhs_tms' = zipWith mergePlaceholders lhs_tms
59 let lhs_tms' = zipWith mergePlaceholders lhs_tms
60 (map (stripUnmatchable i) (map flattenArgs given))
60 (map (stripUnmatchable i) (map flattenArgs given))
61 let lhss = map pUnApply lhs_tms'
61 let lhss = map pUnApply lhs_tms'
62+ nty <- case lookupTyExact n (tt_ctxt i) of
63+ Just t -> return (normalise (tt_ctxt i) [] t)
64+ _ -> fail "Can't happen - genClauses, lookupTyExact"
62
65
63 let argss = transpose lhss
66 let argss = transpose lhss
64− let all_args = map (genAll i) argss
67+ let all_args = map (genAll i) (zip (genPH i nty) argss)
65 logCoverage 5 $ "COVERAGE of " ++ show n
68 logCoverage 5 $ "COVERAGE of " ++ show n
69+ logCoverage 5 $ "using type " ++ show nty
70+ logCoverage 5 $ "non-concrete args " ++ show (genPH i nty)
71+
66 logCoverage 5 $ show (lhs_tms, lhss)
72 logCoverage 5 $ show (lhs_tms, lhss)
67 logCoverage 5 $ show (map length argss) ++ "\n" ++ show (map length all_args)
73 logCoverage 5 $ show (map length argss) ++ "\n" ++ show (map length all_args)
68 logCoverage 10 $ show argss ++ "\n" ++ show all_args
74 logCoverage 10 $ show argss ++ "\n" ++ show all_args
@@ -89,6 +95,18 @@ genClauses fc n xs given
89 | (f, args) <- unApply term = map (\t -> delab' i t True True) args
95 | (f, args) <- unApply term = map (\t -> delab' i t True True) args
90 | otherwise = []
96 | otherwise = []
91
97
98+ -- if an argument has a non-concrete type (i.e. it's a function
99+ -- that calculates something from a previous argument) we'll also
100+ -- need to generate a placeholder pattern for it since it could be
101+ -- anything based on earlier values
102+ genPH :: IState -> Type -> [Bool]
103+ genPH ist (Bind n (Pi _ ty _) sc) = notConcrete ist ty : genPH ist sc
104+ genPH ist ty = []
105+
106+ notConcrete ist t | (P _ n _, args) <- unApply t,
107+ not (isConName n (tt_ctxt ist)) = True
108+ notConcrete _ _ = False
109+
92 pUnApply (PApp _ f args) = map getTm args
110 pUnApply (PApp _ f args) = map getTm args
93 pUnApply _ = []
111 pUnApply _ = []
94
112
@@ -172,16 +190,14 @@ recoverableCoverage ctxt (Elaborating _ _ _ e) = recoverableCoverage ctxt e
172recoverableCoverage ctxt (ElaboratingArg _ _ _ e) = recoverableCoverage ctxt e
190recoverableCoverage ctxt (ElaboratingArg _ _ _ e) = recoverableCoverage ctxt e
173recoverableCoverage _ _ = False
191recoverableCoverage _ _ = False
174
192
175−-- FIXME: Just look for which one is the deepest, then generate all
176−-- possibilities up to that depth.
177−-- This and below issues for this function are tracked as Issue #1741 on the issue tracker.
178−-- https://github.com/idris-lang/Idris-dev/issues/1741
179−genAll :: IState -> [PTerm] -> [PTerm]
193+genAll :: IState -> (Bool, [PTerm]) -> [PTerm]
180−genAll i args
194+genAll i (addPH, args)
181 = case filter (/=Placeholder) $ fnub (concatMap otherPats (fnub args)) of
195 = case filter (/=Placeholder) $ fnub (concatMap otherPats (fnub args)) of
182 [] -> [Placeholder]
196 [] -> [Placeholder]
183− xs -> inventConsts xs
197+ xs -> ph $ inventConsts xs
184 where
198 where
199+ ph ts = if addPH then Placeholder : ts else ts
200+
185 -- if they're constants, invent a new one to make sure that
201 -- if they're constants, invent a new one to make sure that
186 -- constants which are not explicitly handled are covered
202 -- constants which are not explicitly handled are covered
187 inventConsts cs@(PConstant fc c : _) = map (PConstant NoFC) (ic' (mapMaybe getConst cs))
203 inventConsts cs@(PConstant fc c : _) = map (PConstant NoFC) (ic' (mapMaybe getConst cs))
@@ -204,7 +220,6 @@ genAll i args
204 ic' xs@(B64 _ : _) = firstMissing xs (lotsOfNums B64)
220 ic' xs@(B64 _ : _) = firstMissing xs (lotsOfNums B64)
205 ic' xs@(Ch _ : _) = firstMissing xs lotsOfChars
221 ic' xs@(Ch _ : _) = firstMissing xs lotsOfChars
206 ic' xs@(Str _ : _) = firstMissing xs lotsOfStrings
222 ic' xs@(Str _ : _) = firstMissing xs lotsOfStrings
207− -- TODO: Bit vectors
208 -- The rest are types with only one case
223 -- The rest are types with only one case
209 ic' xs = xs
224 ic' xs = xs
210
225
@@ -219,19 +234,19 @@ genAll i args
219 nubMap f acc (x : xs) = nubMap f (fnub' acc (f x)) xs
234 nubMap f acc (x : xs) = nubMap f (fnub' acc (f x)) xs
220
235
221 otherPats :: PTerm -> [PTerm]
236 otherPats :: PTerm -> [PTerm]
222− otherPats o@(PRef fc hl n) = ops fc n [] o
237+ otherPats o@(PRef fc hl n) = ph $ ops fc n [] o
223− otherPats o@(PApp _ (PRef fc hl n) xs) = ops fc n xs o
238+ otherPats o@(PApp _ (PRef fc hl n) xs) = ph $ ops fc n xs o
224 otherPats o@(PPair fc hls _ l r)
239 otherPats o@(PPair fc hls _ l r)
225− = ops fc pairCon
240+ = ph $ ops fc pairCon
226 ([pimp (sUN "A") Placeholder True,
241 ([pimp (sUN "A") Placeholder True,
227 pimp (sUN "B") Placeholder True] ++
242 pimp (sUN "B") Placeholder True] ++
228 [pexp l, pexp r]) o
243 [pexp l, pexp r]) o
229 otherPats o@(PDPair fc hls p t _ v)
244 otherPats o@(PDPair fc hls p t _ v)
230− = ops fc sigmaCon
245+ = ph $ ops fc sigmaCon
231 ([pimp (sUN "a") Placeholder True,
246 ([pimp (sUN "a") Placeholder True,
232 pimp (sUN "P") Placeholder True] ++
247 pimp (sUN "P") Placeholder True] ++
233 [pexp t,pexp v]) o
248 [pexp t,pexp v]) o
234− otherPats o@(PConstant _ c) = inventConsts [o] -- return o
249+ otherPats o@(PConstant _ c) = ph $ inventConsts [o] -- return o
235 otherPats arg = return Placeholder
250 otherPats arg = return Placeholder
236
251
237 ops fc n xs o
252 ops fc n xs o
src/Idris/Elab/Clause.hs+4−2
@@ -165,9 +165,12 @@ elabClauses info' fc opts n_in cs =
165 cov <- coverage
165 cov <- coverage
166 pmissing <-
166 pmissing <-
167 if cov && not (hasDefault pats_raw)
167 if cov && not (hasDefault pats_raw)
168+ then do -- Generate clauses from the given possible cases
168− then do missing <- genClauses fc n (map getLHS pdef) cs_full
169+ missing <- genClauses fc n (map getLHS pdef) cs_full
169 -- missing <- genMissing n scargs sc
170 -- missing <- genMissing n scargs sc
170 missing' <- filterM (checkPossible info fc True n) missing
171 missing' <- filterM (checkPossible info fc True n) missing
172+ -- Filter out the ones which match one of the
173+ -- given cases (including impossible ones)
171 let clhs = map getLHS pdef
174 let clhs = map getLHS pdef
172 logElab 2 $ "Must be unreachable:\n" ++
175 logElab 2 $ "Must be unreachable:\n" ++
173 showSep "\n" (map showTmImpls missing') ++
176 showSep "\n" (map showTmImpls missing') ++
@@ -312,7 +315,6 @@ elabClauses info' fc opts n_in cs =
312 , (f, args) <- unApply tm = all (isPatVar pvs) args
315 , (f, args) <- unApply tm = all (isPatVar pvs) args
313 hasDefault _ = False
316 hasDefault _ = False
314
317
315−
316 getLHS (_, l, _) = l
318 getLHS (_, l, _) = l
317
319
318 simple_lhs ctxt (Right (x, y)) = Right (normalise ctxt [] x, y)
320 simple_lhs ctxt (Right (x, y)) = Right (normalise ctxt [] x, y)
test/totality011/expectednew file+2
@@ -0,0 +1,2 @@
1+totality011.lidr:22:1:
2+Main.weCanOnlyGetOlder is not total as there are missing cases
test/totality011/runnew file+3
@@ -0,0 +1,3 @@
1+#!/usr/bin/env bash
2+${IDRIS:-idris} $@ totality011.lidr --check
3+rm -f *.ibc
test/totality011/totality011.lidrnew file+31
@@ -0,0 +1,31 @@
1+> %default total
2+
3+> X : Nat -> Type
4+> Y : (t : Nat) -> X t -> Type
5+> step : (t : Nat) -> (x : X t) -> Y t x -> X (S t)
6+
7+> Pred : X t -> X (S t) -> Type
8+> Pred {t} x x' = Subset (Y t x) (\ y => (x' = step t x y))
9+
10+> ReachableFrom : X t'' -> X t -> Type
11+> ReachableFrom {t'' = Z } {t} x'' x =
12+> (Z = t , x'' = x)
13+> ReachableFrom {t'' = S t'} {t} x'' x =
14+> Either (S t' = t , x'' = x)
15+> (Subset (X t') (\ x' => (x' `ReachableFrom` x , x' `Pred` x'')))
16+
17+> weCanOnlyGetOlder : (x'' : X t'') ->
18+> (x : X t) ->
19+> x'' `ReachableFrom` x ->
20+> t'' `GTE` t
21+
22+> weCanOnlyGetOlder {t'' = Z} {t = Z} _ _ _ = LTEZero
23+> weCanOnlyGetOlder {t'' = Z} {t = S m} _ _ (Zeqt , _) =
24+> void (uninhabited u) where
25+> u : Z = S m
26+> u = trans Zeqt Refl
27+
28+> weCanOnlyGetOlder {t'' = S _} {t = S _} _ _ _ = ?foo
29+
30+-- > weCanOnlyGetOlder {t'' = S _} {t = S _} _ _ (_, _) = ?foo
31+