on master help sign in
Fix ordering of run time case trees

Fixes #3254

commit45bf2b648d5a082a2c4494e954af3079dcd23be0 authorEdwin Brady <ecb10@st-andrews.ac.uk> dateSat 9 Jul 2016, 11:48 (10 years ago) parentcfe4aa2
5 files changed+53−28
src/Idris/Core/CaseTree.hs+34−22 src/Idris/Core/Evaluate.hs+13−3 src/Idris/Elab/Clause.hs+2−1 src/Idris/Elab/Term.hs+3−1 src/Idris/IBC.hs+1−1
src/Idris/Core/CaseTree.hs+34−22
@@ -251,7 +251,8 @@ data Phase = CompileTime | RunTime
251251-- Work Right to Left
252252
253253simpleCase :: Bool -> SC -> Bool ->
254− Phase -> FC -> [Int] -> [Type] ->
254+ Phase -> FC -> [Int] ->
255+ [(Type, Bool)] -> -- ^ (Argument type, whether it's canonical)
255256 [([Name], Term, Term)] ->
256257 ErasureInfo ->
257258 TC CaseDef
@@ -273,7 +274,7 @@ simpleCase tc defcase reflect phase fc inacc argtys cs erInfo
273274 OK pats ->
274275 let numargs = length (fst (head pats))
275276 ns = take numargs args
276− (ns', ps') = order [(n, i `elem` inacc) | (i,n) <- zip [0..] ns] pats
277+ (ns', ps') = order phase [(n, i `elem` inacc) | (i,n) <- zip [0..] ns] pats (map snd argtys)
277278 (tree, st) = runCaseBuilder erInfo
278279 (match ns' ps' defcase)
279280 ([], numargs, [])
@@ -431,28 +432,38 @@ partition xs = error $ "Partition " ++ show xs
431432--
432433-- The first argument means [(Name, IsInaccessible)].
433434
434−order :: [(Name, Bool)] -> [Clause] -> ([Name], [Clause])
435−order [] cs = ([], cs)
436−order ns' [] = (map fst ns', [])
437−order ns' cs = let patnames = transpose (map (zip ns') (map fst cs))
438− -- only sort the arguments where there is no clash in
439− -- constructor tags between families, and no constructor/constant
440− -- clash, because otherwise we can't reliable make the
441− -- case distinction on evaluation
442− (patnames_ord, patnames_rest)
443− = Data.List.partition (noClash . map snd) patnames
444− -- note: sortBy . reverse is not nonsense because sortBy is stable
445− pats' = transpose (sortBy moreDistinct (reverse patnames_ord)
446− ++ patnames_rest) in
447− (getNOrder pats', zipWith rebuild pats' cs)
435+order :: Phase -> [(Name, Bool)] -> [Clause] -> [Bool] -> ([Name], [Clause])
436+-- do nothing at compile time: FIXME (EB): Put this in after checking
437+-- implications for Franck's reflection work... see issue 3233
438+-- order CompileTime ns cs _ = (map fst ns, cs)
439+order _ [] cs cans = ([], cs)
440+order _ ns' [] cans = (map fst ns', [])
441+order phase ns' cs cans
442+ = let patnames = transpose (map (zip ns') (map (zip cans) (map fst cs)))
443+ -- only sort the arguments where there is no clash in
444+ -- constructor tags between families, the argument type is canonical,
445+ -- and no constructor/constant
446+ -- clash, because otherwise we can't reliable make the
447+ -- case distinction on evaluation
448+ (patnames_ord, patnames_rest)
449+ = Data.List.partition (noClash . map snd) patnames
450+ patnames_ord' = case phase of
451+ CompileTime -> patnames_ord
452+ -- reversing tends to make better case trees
453+ -- and helps erasure
454+ RunTime -> reverse patnames_ord
455+ pats' = transpose (sortBy moreDistinct patnames_ord'
456+ ++ patnames_rest) in
457+ (getNOrder pats', zipWith rebuild pats' cs)
448458 where
449459 getNOrder [] = error $ "Failed order on " ++ show (map fst ns', cs)
450460 getNOrder (c : _) = map (fst . fst) c
451461
452− rebuild patnames clause = (map snd patnames, snd clause)
462+ rebuild patnames clause = (map (snd . snd) patnames, snd clause)
453463
454464 noClash [] = True
455− noClash (p : ps) = not (any (clashPat p) ps) && noClash ps
465+ noClash ((can, p) : ps) = can && not (any (clashPat p) (map snd ps))
466+ && noClash ps
456467
457468 clashPat (PCon _ _ _ _) (PConst _) = True
458469 clashPat (PConst _) (PCon _ _ _ _) = True
@@ -462,12 +473,13 @@ order ns' cs = let patnames = transpose (map (zip ns') (map fst cs))
462473 clashPat _ _ = False
463474
464475 -- this compares (+isInaccessible, -numberOfCases)
465− moreDistinct xs ys = compare (snd . fst . head $ xs, numNames [] (map snd ys))
466− (snd . fst . head $ ys, numNames [] (map snd xs))
476+ moreDistinct xs ys
477+ = compare (snd . fst . head $ xs, numNames [] (map snd ys))
478+ (snd . fst . head $ ys, numNames [] (map snd xs))
467479
468− numNames xs (PCon _ n _ _ : ps)
480+ numNames xs ((_, PCon _ n _ _) : ps)
469481 | not (Left n `elem` xs) = numNames (Left n : xs) ps
470− numNames xs (PConst c : ps)
482+ numNames xs ((_, PConst c) : ps)
471483 | not (Right c `elem` xs) = numNames (Right c : xs) ps
472484 numNames xs (_ : ps) = numNames xs ps
473485 numNames xs [] = length xs
src/Idris/Core/Evaluate.hs+13−3
@@ -21,7 +21,8 @@ module Idris.Core.Evaluate(normalise, normaliseTrace, normaliseC,
2121 lookupP, lookupP_all, lookupDef, lookupNameDef, lookupDefExact, lookupDefAcc, lookupDefAccExact, lookupVal,
2222 mapDefCtxt,
2323 lookupTotal, lookupTotalExact, lookupInjectiveExact,
24− lookupNameTotal, lookupMetaInformation, lookupTyEnv, isTCDict, isDConName, canBeDConName, isTConName, isConName, isFnName,
24+ lookupNameTotal, lookupMetaInformation, lookupTyEnv, isTCDict,
25+ isCanonical, isDConName, canBeDConName, isTConName, isConName, isFnName,
2526 Value(..), Quote(..), initEval, uniqueNameCtxt, uniqueBindersCtxt, definitions,
2627 isUniverse) where
2728
@@ -697,7 +698,7 @@ data Def = Function !Type !Term
697698 | Operator Type Int ([Value] -> Maybe Value)
698699 | CaseOp CaseInfo
699700 !Type
700− ![Type] -- argument types
701+ ![(Type, Bool)] -- argument types, whether canonical
701702 ![Either Term (Term, Term)] -- original definition
702703 ![([Name], Term, Term)] -- simplified for totality check definition
703704 !CaseDefs
@@ -915,7 +916,7 @@ addDatatype (Data n tag ty unique cons) uctxt
915916addCasedef :: Name -> ErasureInfo -> CaseInfo ->
916917 Bool -> SC -> -- default case
917918 Bool -> Bool ->
918− [Type] -> -- argument types
919+ [(Type, Bool)] -> -- argument types, whether canonical
919920 [Int] -> -- inaccessible arguments
920921 [Either Term (Term, Term)] ->
921922 [([Name], Term, Term)] -> -- totality
@@ -1019,6 +1020,15 @@ lookupTy n ctxt = map snd (lookupTyName n ctxt)
10191020lookupTyExact :: Name -> Context -> Maybe Type
10201021lookupTyExact n ctxt = fmap snd (lookupTyNameExact n ctxt)
10211022
1023+-- | Return true if the given type is a concrete type familyor primitive
1024+-- False it it's a function to compute a type or a variable
1025+isCanonical :: Type -> Context -> Bool
1026+isCanonical t ctxt
1027+ = case unApply t of
1028+ (P _ n _, _) -> isConName n ctxt
1029+ (Constant _, _) -> True
1030+ _ -> False
1031+
10221032isConName :: Name -> Context -> Bool
10231033isConName n ctxt = isTConName n ctxt || isDConName n ctxt
10241034
src/Idris/Elab/Clause.hs+2−1
@@ -84,7 +84,8 @@ elabClauses info' fc opts n_in cs =
8484 -- question: CAFs in where blocks?
8585 tclift $ tfail $ At fc (NoTypeDecl n)
8686 [ty] -> return ty
87− let atys = map snd (getArgTys fty)
87+ let atys_in = map snd (getArgTys (normalise ctxt [] fty))
88+ let atys = map (\x -> (x, isCanonical x ctxt)) atys_in
8889 cs_elab <- mapM (elabClause info opts)
8990 (zip [0..] cs)
9091 ctxt <- getContext
src/Idris/Elab/Term.hs+3−1
@@ -1926,11 +1926,13 @@ runElabAction info ist fc env tm ns = do tm' <- eval tm
19261926 in (ns, lhs', Impossible))
19271927 clauses'
19281928 let clauses''' = map (\(ns, lhs, rhs) -> (map fst ns, lhs, rhs)) clauses''
1929+ let argtys = map (\x -> (x, isCanonical x ctxt))
1930+ (map snd (getArgTys (normalise ctxt [] ty)))
19291931 ctxt'<- lift $
19301932 addCasedef n (const [])
19311933 info False (STerm Erased)
19321934 True False -- TODO what are these?
1933− (map snd $ getArgTys ty) [] -- TODO inaccessible types
1935+ argtys [] -- TODO inaccessible types
19341936 clauses'
19351937 clauses'''
19361938 clauses'''
src/Idris/IBC.hs+1−1
@@ -49,7 +49,7 @@ import Codec.Archive.Zip
4949import Debug.Trace
5050
5151ibcVersion :: Word16
52−ibcVersion = 144
52+ibcVersion = 145
5353
5454-- | When IBC is being loaded - we'll load different things (and omit
5555-- different structures/definitions) depending on which phase we're in.