liquidhaskell 0.5.0.1 → 0.6.0.0
raw patch · 233 files changed
+16744/−25269 lines, 233 filesdep +cerealdep +daemonsdep +located-basedep −ansi-terminaldep −filemanipdep −interndep ~Diffdep ~aesondep ~arraysetup-changednew-component:exe:lhi
Dependencies added: cereal, daemons, located-base, network, tasty-ant-xml, temporary, unix
Dependencies removed: ansi-terminal, filemanip, intern
Dependency ranges changed: Diff, aeson, array, base, bifunctors, bytestring, cmdargs, containers, cpphs, data-default, deepseq, directory, filepath, fingertree, ghc, ghc-paths, hashable, hpc, hscolour, liquid-fixpoint, mtl, optparse-applicative, parsec, pretty, process, stm, syb, tagged, template-haskell, text, time, transformers, unordered-containers, vector
Files
- Liquid.hs +0/−113
- Setup.hs +1/−0
- include/708/Control/Monad.spec +0/−3
- include/CoreToLogic.lg +1/−0
- include/Data/Set.spec +1/−0
- include/Data/Vector.spec +5/−0
- include/GHC/Real.spec +9/−3
- include/GHC/Types.spec +1/−0
- include/Language/Haskell/Liquid/Foreign.hs +4/−4
- include/Language/Haskell/Liquid/List.hs +0/−2
- include/Prelude.hquals +6/−2
- liquidhaskell.cabal +171/−189
- src/LHi.hs +35/−0
- src/Language/Haskell/Liquid/ACSS.hs +0/−264
- src/Language/Haskell/Liquid/ANFTransform.hs +0/−265
- src/Language/Haskell/Liquid/Annotate.hs +0/−425
- src/Language/Haskell/Liquid/Bare.hs +1/−2
- src/Language/Haskell/Liquid/Bare/Axiom.hs +232/−0
- src/Language/Haskell/Liquid/Bare/Check.hs +110/−62
- src/Language/Haskell/Liquid/Bare/DataType.hs +73/−25
- src/Language/Haskell/Liquid/Bare/Env.hs +17/−10
- src/Language/Haskell/Liquid/Bare/Existential.hs +9/−9
- src/Language/Haskell/Liquid/Bare/Expand.hs +58/−74
- src/Language/Haskell/Liquid/Bare/GhcSpec.hs +153/−70
- src/Language/Haskell/Liquid/Bare/Lookup.hs +9/−8
- src/Language/Haskell/Liquid/Bare/Measure.hs +85/−77
- src/Language/Haskell/Liquid/Bare/Misc.hs +43/−38
- src/Language/Haskell/Liquid/Bare/OfType.hs +28/−31
- src/Language/Haskell/Liquid/Bare/Plugged.hs +30/−20
- src/Language/Haskell/Liquid/Bare/RTEnv.hs +34/−50
- src/Language/Haskell/Liquid/Bare/RefToLogic.hs +60/−49
- src/Language/Haskell/Liquid/Bare/Resolve.hs +49/−38
- src/Language/Haskell/Liquid/Bare/Spec.hs +27/−27
- src/Language/Haskell/Liquid/Bare/SymSort.hs +44/−36
- src/Language/Haskell/Liquid/Bounds.hs +0/−161
- src/Language/Haskell/Liquid/CTags.hs +0/−74
- src/Language/Haskell/Liquid/Cabal.hs +0/−254
- src/Language/Haskell/Liquid/CmdLine.hs +0/−370
- src/Language/Haskell/Liquid/Constraint/Axioms.hs +569/−0
- src/Language/Haskell/Liquid/Constraint/Constraint.hs +30/−25
- src/Language/Haskell/Liquid/Constraint/Env.hs +286/−0
- src/Language/Haskell/Liquid/Constraint/Fresh.hs +142/−0
- src/Language/Haskell/Liquid/Constraint/Generate.hs +1392/−1924
- src/Language/Haskell/Liquid/Constraint/Monad.hs +154/−0
- src/Language/Haskell/Liquid/Constraint/ProofToCore.hs +185/−0
- src/Language/Haskell/Liquid/Constraint/Qualifier.hs +159/−0
- src/Language/Haskell/Liquid/Constraint/Split.hs +496/−0
- src/Language/Haskell/Liquid/Constraint/ToFixpoint.hs +25/−29
- src/Language/Haskell/Liquid/Constraint/Types.hs +185/−111
- src/Language/Haskell/Liquid/CoreToLogic.hs +0/−409
- src/Language/Haskell/Liquid/Desugar/Check.lhs +0/−765
- src/Language/Haskell/Liquid/Desugar/Coverage.lhs +0/−1240
- src/Language/Haskell/Liquid/Desugar/Desugar.lhs +0/−440
- src/Language/Haskell/Liquid/Desugar/DsArrows.lhs +0/−1202
- src/Language/Haskell/Liquid/Desugar/DsBinds.lhs +0/−900
- src/Language/Haskell/Liquid/Desugar/DsExpr.lhs +0/−867
- src/Language/Haskell/Liquid/Desugar/DsExpr.lhs-boot +0/−11
- src/Language/Haskell/Liquid/Desugar/DsForeign.lhs +0/−807
- src/Language/Haskell/Liquid/Desugar/DsGRHSs.lhs +0/−160
- src/Language/Haskell/Liquid/Desugar/DsListComp.lhs +0/−879
- src/Language/Haskell/Liquid/Desugar/DsMeta.hs +0/−2816
- src/Language/Haskell/Liquid/Desugar/DsUtils.lhs +0/−835
- src/Language/Haskell/Liquid/Desugar/HscMain.hs +0/−95
- src/Language/Haskell/Liquid/Desugar/Match.lhs +0/−1050
- src/Language/Haskell/Liquid/Desugar/Match.lhs-boot +0/−35
- src/Language/Haskell/Liquid/Desugar/MatchCon.lhs +0/−293
- src/Language/Haskell/Liquid/Desugar/MatchLit.lhs +0/−468
- src/Language/Haskell/Liquid/Desugar710/Check.hs +1/−0
- src/Language/Haskell/Liquid/Desugar710/Coverage.hs +1/−0
- src/Language/Haskell/Liquid/Desugar710/Desugar.hs +2/−1
- src/Language/Haskell/Liquid/Desugar710/DsArrows.hs +2/−1
- src/Language/Haskell/Liquid/Desugar710/DsBinds.hs +1/−0
- src/Language/Haskell/Liquid/Desugar710/DsCCall.hs +1/−2
- src/Language/Haskell/Liquid/Desugar710/DsExpr.hs +5/−4
- src/Language/Haskell/Liquid/Desugar710/DsForeign.hs +1/−1
- src/Language/Haskell/Liquid/Desugar710/DsGRHSs.hs +1/−1
- src/Language/Haskell/Liquid/Desugar710/DsListComp.hs +3/−1
- src/Language/Haskell/Liquid/Desugar710/DsMeta.hs +2/−2
- src/Language/Haskell/Liquid/Desugar710/DsUtils.hs +3/−1
- src/Language/Haskell/Liquid/Desugar710/HscMain.hs +3/−3
- src/Language/Haskell/Liquid/Desugar710/Match.hs +1/−1
- src/Language/Haskell/Liquid/Desugar710/MatchCon.hs +1/−1
- src/Language/Haskell/Liquid/Desugar710/MatchLit.hs +1/−1
- src/Language/Haskell/Liquid/Dictionaries.hs +0/−65
- src/Language/Haskell/Liquid/DiffCheck.hs +0/−459
- src/Language/Haskell/Liquid/Errors.hs +0/−304
- src/Language/Haskell/Liquid/Fresh.hs +0/−140
- src/Language/Haskell/Liquid/GHC/Interface.hs +402/−0
- src/Language/Haskell/Liquid/GHC/Misc.hs +542/−0
- src/Language/Haskell/Liquid/GHC/Play.hs +86/−0
- src/Language/Haskell/Liquid/GHC/SpanStack.hs +75/−0
- src/Language/Haskell/Liquid/GhcInterface.hs +0/−387
- src/Language/Haskell/Liquid/GhcMisc.hs +0/−520
- src/Language/Haskell/Liquid/GhcPlay.hs +0/−84
- src/Language/Haskell/Liquid/Interactive/Handler.hs +30/−0
- src/Language/Haskell/Liquid/Interactive/Types.hs +57/−0
- src/Language/Haskell/Liquid/Liquid.hs +204/−0
- src/Language/Haskell/Liquid/Literals.hs +0/−52
- src/Language/Haskell/Liquid/Measure.hs +158/−157
- src/Language/Haskell/Liquid/Misc.hs +92/−43
- src/Language/Haskell/Liquid/Names.hs +0/−6
- src/Language/Haskell/Liquid/Parse.hs +97/−82
- src/Language/Haskell/Liquid/PredType.hs +0/−334
- src/Language/Haskell/Liquid/PrettyPrint.hs +0/−337
- src/Language/Haskell/Liquid/Prover/Constants.hs +25/−0
- src/Language/Haskell/Liquid/Prover/Misc.hs +38/−0
- src/Language/Haskell/Liquid/Prover/Names.hs +8/−0
- src/Language/Haskell/Liquid/Prover/Parser.hs +100/−0
- src/Language/Haskell/Liquid/Prover/Pretty.hs +64/−0
- src/Language/Haskell/Liquid/Prover/SMTInterface.hs +14/−0
- src/Language/Haskell/Liquid/Prover/Solve.hs +304/−0
- src/Language/Haskell/Liquid/Prover/Types.hs +129/−0
- src/Language/Haskell/Liquid/Qualifier.hs +0/−133
- src/Language/Haskell/Liquid/RefSplit.hs +0/−123
- src/Language/Haskell/Liquid/RefType.hs +0/−1143
- src/Language/Haskell/Liquid/Simplify.hs +0/−42
- src/Language/Haskell/Liquid/Strata.hs +0/−70
- src/Language/Haskell/Liquid/Tidy.hs +0/−141
- src/Language/Haskell/Liquid/TransformRec.hs +0/−245
- src/Language/Haskell/Liquid/Transforms/ANF.hs +313/−0
- src/Language/Haskell/Liquid/Transforms/CoreToLogic.hs +456/−0
- src/Language/Haskell/Liquid/Transforms/Rec.hs +246/−0
- src/Language/Haskell/Liquid/Transforms/RefSplit.hs +107/−0
- src/Language/Haskell/Liquid/Transforms/Simplify.hs +43/−0
- src/Language/Haskell/Liquid/Types.hs +1659/−1854
- src/Language/Haskell/Liquid/Types/Bounds.hs +162/−0
- src/Language/Haskell/Liquid/Types/Dictionaries.hs +65/−0
- src/Language/Haskell/Liquid/Types/Errors.hs +674/−0
- src/Language/Haskell/Liquid/Types/Literals.hs +58/−0
- src/Language/Haskell/Liquid/Types/Meet.hs +28/−0
- src/Language/Haskell/Liquid/Types/Names.hs +6/−0
- src/Language/Haskell/Liquid/Types/PredType.hs +355/−0
- src/Language/Haskell/Liquid/Types/PrettyPrint.hs +331/−0
- src/Language/Haskell/Liquid/Types/RefType.hs +1145/−0
- src/Language/Haskell/Liquid/Types/Specifications.hs +10/−0
- src/Language/Haskell/Liquid/Types/Strata.hs +69/−0
- src/Language/Haskell/Liquid/Types/Variance.hs +16/−0
- src/Language/Haskell/Liquid/Types/Visitors.hs +143/−0
- src/Language/Haskell/Liquid/UX/ACSS.hs +267/−0
- src/Language/Haskell/Liquid/UX/Annotate.hs +451/−0
- src/Language/Haskell/Liquid/UX/CTags.hs +73/−0
- src/Language/Haskell/Liquid/UX/CmdLine.hs +433/−0
- src/Language/Haskell/Liquid/UX/Config.hs +75/−0
- src/Language/Haskell/Liquid/UX/DiffCheck.hs +488/−0
- src/Language/Haskell/Liquid/UX/Errors.hs +108/−0
- src/Language/Haskell/Liquid/UX/Tidy.hs +228/−0
- src/Language/Haskell/Liquid/Variance.hs +0/−11
- src/Language/Haskell/Liquid/Visitors.hs +0/−143
- src/Language/Haskell/Liquid/WiredIn.hs +70/−28
- src/Language/Haskell/Liquid/World.hs +0/−23
- src/Liquid.hs +5/−0
- tests/crash/Assume.hs +5/−0
- tests/crash/Assume1.hs +15/−0
- tests/crash/Ast.hs +61/−0
- tests/crash/CyclicExprAlias2.hs +1/−1
- tests/crash/Qualif.hs +10/−0
- tests/crash/T649.hs +34/−0
- tests/crash/errmsg-dc-num.hs +6/−0
- tests/crash/errmsg-dc-type.hs +5/−0
- tests/crash/errmsg-mismatch.hs +5/−0
- tests/crash/issue594.hs +7/−0
- tests/crash/predparams.hs +10/−0
- tests/neg/AbsApp.hs +16/−0
- tests/neg/Ast.hs +54/−0
- tests/neg/BadHMeas.hs +5/−0
- tests/neg/BigNum.hs +7/−0
- tests/neg/Books.hs +62/−0
- tests/neg/FunSoundness.hs +9/−0
- tests/neg/GADTs.hs +21/−0
- tests/neg/Gradual.hs +15/−0
- tests/neg/PairMeasure0.hs +0/−20
- tests/neg/Propability.hs +0/−2
- tests/neg/Propability0.hs +0/−2
- tests/neg/StateConstraints.hs +1/−1
- tests/neg/T602.hs +22/−0
- tests/neg/TermReal.hs +5/−0
- tests/neg/Variance1.hs +11/−0
- tests/neg/listne.hs +7/−0
- tests/pos/Abs.hs +2/−2
- tests/pos/Avg.hs +0/−3
- tests/pos/Bar.hs +5/−0
- tests/pos/BinarySearch.hs +43/−0
- tests/pos/Books.hs +50/−0
- tests/pos/Class.hs +29/−20
- tests/pos/CountMonad.hs +70/−0
- tests/pos/DB00.hs +21/−0
- tests/pos/Even.hs +5/−7
- tests/pos/GADTs.hs +21/−0
- tests/pos/GhcSort1.hs +8/−10
- tests/pos/GoodHMeas.hs +10/−0
- tests/pos/Gradual.hs +13/−0
- tests/pos/LambdaDeBruijn.hs +87/−0
- tests/pos/LambdaEval.hs +4/−3
- tests/pos/ListQSort-LType.hs +14/−13
- tests/pos/Merge1.hs +14/−0
- tests/pos/OrdList.hs +4/−3
- tests/pos/PairMeasure0.hs +17/−2
- tests/pos/Product.hs +0/−1
- tests/pos/Propability.hs +0/−2
- tests/pos/RBTree-col-height.hs +2/−2
- tests/pos/RBTree-color.hs +1/−1
- tests/pos/RBTree-height.hs +1/−1
- tests/pos/RBTree.hs +2/−2
- tests/pos/RealProps.hs +2/−3
- tests/pos/RealProps1.hs +2/−2
- tests/pos/ResolvePred.hs +1/−1
- tests/pos/StructRec.hs +18/−0
- tests/pos/T531.hs +6/−0
- tests/pos/T595.hs +29/−0
- tests/pos/T595a.hs +12/−0
- tests/pos/T598.hs +10/−0
- tests/pos/Words.hs +5/−0
- tests/pos/Words1.hs +3/−0
- tests/pos/anish1.hs +13/−0
- tests/pos/csgordon_issue_296.hs +6/−0
- tests/pos/dropwhile.hs +84/−0
- tests/pos/gadtEval.hs +5/−5
- tests/pos/gimme.hs +2/−1
- tests/pos/hole-fun.hs +10/−0
- tests/pos/idNat.hs +5/−0
- tests/pos/idNat0.hs +8/−0
- tests/pos/listqual.hs +10/−0
- tests/pos/nats.hs +5/−0
- tests/pos/pair00.hs +16/−7
- tests/pos/recursion0.hs +7/−0
- tests/pos/repeatHigherOrder.hs +24/−0
- tests/pos/scanr.hs +2/−2
- tests/pos/test00-int.hs +0/−4
- tests/pos/test00.hs +0/−4
- tests/pos/testRec.hs +16/−21
- tests/pos/zipper0.hs +6/−25
- tests/pos/zipper000.hs +68/−0
- tests/test.hs +95/−34
− Liquid.hs
@@ -1,113 +0,0 @@-{-# LANGUAGE TupleSections #-}-{-# LANGUAGE CPP #-}--{-@ LIQUID "--cabaldir" @-}-{-@ LIQUID "--diff" @-}--#if __GLASGOW_HASKELL__ < 710-import Data.Monoid (mconcat, mempty)-import Control.Applicative ((<$>))-#endif--import Data.Maybe-import System.Exit-import Control.DeepSeq-import Text.PrettyPrint.HughesPJ-import CoreSyn-import Var-import System.Console.CmdArgs.Verbosity (whenLoud)-import System.Console.CmdArgs.Default--import qualified Language.Fixpoint.Config as FC-import qualified Language.Haskell.Liquid.DiffCheck as DC-import Language.Fixpoint.Misc-import Language.Fixpoint.Interface-import Language.Fixpoint.Types (sinfo, Result (..))-import Language.Haskell.Liquid.Types-import Language.Haskell.Liquid.Errors-import Language.Haskell.Liquid.CmdLine-import Language.Haskell.Liquid.GhcInterface-import Language.Haskell.Liquid.Constraint.Generate-import Language.Haskell.Liquid.Constraint.ToFixpoint-import Language.Haskell.Liquid.Constraint.Types-import Language.Haskell.Liquid.TransformRec-import Language.Haskell.Liquid.Annotate (mkOutput)----main :: IO b-main = do cfg0 <- getOpts- res <- mconcat <$> mapM (checkOne cfg0) (files cfg0)- let ecode = resultExit $ {- traceShow "RESULT" $ -} o_result res- -- putStrLn $ "ExitCode: " ++ show ecode- exitWith ecode--checkOne :: Config -> FilePath -> IO (Output Doc)-checkOne cfg0 t = getGhcInfo cfg0 t >>= either errOut (liquidOne t)- where- errOut r = exitWithResult cfg0 t $ mempty { o_result = r}--liquidOne :: FilePath -> GhcInfo -> IO (Output Doc)-liquidOne target info =- do donePhase Loud "Extracted Core using GHC"- let cfg = config $ spec info- whenLoud $ do putStrLn "**** Config **************************************************"- print cfg- whenLoud $ do putStrLn $ showpp info- putStrLn "*************** Original CoreBinds ***************************"- putStrLn $ showpp (cbs info)- let cbs' = transformScope (cbs info)- whenLoud $ do donePhase Loud "transformRecExpr"- putStrLn "*************** Transform Rec Expr CoreBinds *****************"- putStrLn $ showpp cbs'- putStrLn "*************** Slicing Out Unchanged CoreBinds *****************"- dc <- prune cfg cbs' target info- let cbs'' = maybe cbs' DC.newBinds dc- let info' = maybe info (\z -> info {spec = DC.newSpec z}) dc- let cgi = {-# SCC "generateConstraints" #-} generateConstraints $! info' {cbs = cbs''}- cgi `deepseq` donePhase Loud "generateConstraints"- out <- solveCs cfg target cgi info' dc- donePhase Loud "solve"- let out' = mconcat [maybe mempty DC.oldOutput dc, out]- DC.saveResult target out'- exitWithResult cfg target out'--checkedNames :: Maybe DC.DiffCheck -> Maybe [String]-checkedNames dc = concatMap names . DC.newBinds <$> dc- where- names (NonRec v _ ) = [showpp $ shvar v]- names (Rec xs) = map (shvar . fst) xs- shvar = showpp . varName--prune :: Config -> [CoreBind] -> FilePath -> GhcInfo -> IO (Maybe DC.DiffCheck)-prune cfg cbinds target info- | not (null vs) = return . Just $ DC.DC (DC.thin cbinds vs) mempty sp- | diffcheck cfg = DC.slice target cbinds sp- | otherwise = return Nothing- where- vs = tgtVars sp- sp = spec info--solveCs :: Config -> FilePath -> CGInfo -> GhcInfo -> Maybe DC.DiffCheck -> IO (Output Doc)-solveCs cfg target cgi info dc- = do finfo <- cgInfoFInfo info cgi- Result r sol <- solve fx finfo- let names = checkedNames dc- let warns = logErrors cgi- let annm = annotMap cgi- let res = ferr sol r- let out0 = mkOutput cfg res sol annm- return $ out0 { o_vars = names } { o_errors = warns} { o_result = res }- where- fx = def { FC.solver = fromJust (smtsolver cfg)- , FC.real = real cfg- , FC.native = native cfg- , FC.srcFile = target- -- , FC.stats = True- }- ferr s r = fmap (tidyError s) $ result $ sinfo <$> r----- writeCGI tgt cgi = {-# SCC "ConsWrite" #-} writeFile (extFileName Cgi tgt) str--- where--- str = {-# SCC "PPcgi" #-} showpp cgi
Setup.hs view
@@ -1,5 +1,6 @@ import Distribution.Simple + main = defaultMain -- main = defaultMainWithHooks fixpointHooks
− include/708/Control/Monad.spec
@@ -1,3 +0,0 @@-module spec Control.Monad where--Control.Monad.sequence :: GHC.Base.Monad m => xs:[m a] -> m {v:[a] | (len v) = (len xs)}
include/CoreToLogic.lg view
@@ -3,6 +3,7 @@ define Data.Set.Base.intersection x y = (Set_cap x y) define Data.Set.Base.difference x y = (Set_dif x y) define Data.Set.Base.empty = (Set_empty 0)+define Data.Set.Base.null x = (Set_emp x) define Data.Set.Base.member x xs = (Set_mem x xs) define Data.Set.Base.isSubsetOf x y = (Set_sub x y) define Data.Set.Base.elems xs = (listElts xs)
include/Data/Set.spec view
@@ -37,6 +37,7 @@ isSubsetOf :: (GHC.Classes.Ord a) => x:(Data.Set.Set a) -> y:(Data.Set.Set a) -> {v:Bool | ((Prop v) <=> (Set_sub x y))} member :: (GHC.Classes.Ord a) => x:a -> xs:(Data.Set.Set a) -> {v:Bool | ((Prop v) <=> (Set_mem x xs))}+null :: (GHC.Classes.Ord a) => xs:(Data.Set.Set a) -> {v:Bool | ((Prop v) <=> (Set_emp xs))} empty :: {v:(Data.Set.Set a) | (Set_emp v)} singleton :: x:a -> {v:(Data.Set.Set a) | v = (Set_sng x)}
include/Data/Vector.spec view
@@ -2,6 +2,9 @@ import GHC.Base +data variance Vector covariant++ measure vlen :: forall a. (Data.Vector.Vector a) -> Int invariant {v: Data.Vector.Vector a | 0 <= vlen v } @@ -13,3 +16,5 @@ assume length :: forall a. x:(Data.Vector.Vector a) -> {v : Nat | v = vlen x } assume replicate :: n:Nat -> a -> {v:Data.Vector.Vector a | vlen v = n} ++assume imap :: (Nat -> a -> b) -> x:(Data.Vector.Vector a) -> {y:Data.Vector.Vector b | vlen y = vlen x }
include/GHC/Real.spec view
@@ -8,8 +8,10 @@ GHC.Real.fromRational :: GHC.Real.Rational -> a class (GHC.Real.Real a, GHC.Enum.Enum a) => GHC.Real.Integral a where- GHC.Real.quot :: a -> {v:a | v /= 0} -> a- GHC.Real.rem :: a -> {v:a | v /= 0} -> a+ GHC.Real.quot :: x:a -> y:{v:a | v /= 0} -> {v:a | (v = (x / y)) &&+ ((x >= 0 && y >= 0) => v >= 0) &&+ ((x >= 0 && y >= 1) => v <= x) }+ GHC.Real.rem :: x:a -> y:{v:a | v /= 0} -> {v:a | ((v >= 0) && (v < y))} GHC.Real.mod :: x:a -> y:{v:a | v /= 0} -> {v:a | v = x mod y && ((0 <= x && 0 < y) => (0 <= v && v < y))} GHC.Real.div :: x:a -> y:{v:a | v /= 0} -> {v:a | (v = (x / y)) && ((x >= 0 && y >= 0) => v >= 0) &&@@ -18,7 +20,11 @@ ((x >= 0 && y >= 0) => v >= 0) && ((x >= 0 && y >= 1) => v <= x)} , {v:a | ((v >= 0) && (v < y))})- GHC.Real.divMod :: a -> {v:a | v /= 0} -> (a, a)+ GHC.Real.divMod :: x:a -> y:{v:a | v /= 0} -> ( {v:a | (v = (x / y)) &&+ ((x >= 0 && y >= 0) => v >= 0) &&+ ((x >= 0 && y >= 1) => v <= x) }+ , {v:a | v = x mod y && ((0 <= x && 0 < y) => (0 <= v && v < y))}+ ) GHC.Real.toInteger :: x:a -> {v:GHC.Integer.Type.Integer | v = x} // fixpoint can't handle (x mod y), only (x mod c) so we need to be more clever here
include/GHC/Types.spec view
@@ -18,6 +18,7 @@ GHC.Types.isTrue# :: n:_ -> {v:GHC.Types.Bool | ((n = 1) <=> (Prop(v)))} +GHC.Types.W# :: w:_ -> {v:GHC.Types.Word | v == w }
include/Language/Haskell/Liquid/Foreign.hs view
@@ -11,7 +11,7 @@ import GHC.Base -- TODO: shouldn't have to re-import these (tests/pos/imp0.hs)-{- import Foreign.C.Types -} +{- import Foreign.C.Types -} {- import Foreign.Ptr -} {- import Foreign.ForeignPtr -} {- import GHC.Base -}@@ -23,17 +23,17 @@ {-# NOINLINE intCSize #-} {-@ assume intCSize :: x:Int -> {v: CSize | v = x } @-} intCSize :: Int -> CSize-intCSize = fromIntegral +intCSize = fromIntegral {-# NOINLINE cSizeInt #-} {-@ assume cSizeInt :: x:CSize -> {v: Int | v = x } @-} cSizeInt :: CSize -> Int-cSizeInt = fromIntegral +cSizeInt = fromIntegral {-@ assume mkPtr :: x:GHC.Prim.Addr# -> {v: (Ptr b) | ((plen v) = (addrLen x) && ((plen v) >= 0)) } @-} mkPtr :: Addr# -> Ptr b-mkPtr = undefined -- Ptr x +mkPtr = undefined -- Ptr x {-@ isNullPtr :: p:(Ptr a) -> {v:Bool | ((Prop v) <=> (isNullPtr p)) } @-}
include/Language/Haskell/Liquid/List.hs view
@@ -4,5 +4,3 @@ transpose _ [] = [] transpose n ([] : xss) = transpose n xss transpose n ((x:xs) : xss) = (x : [h | (h:_) <- xss]) : transpose (n - 1) (xs : [ t | (_:t) <- xss])--
include/Prelude.hquals view
@@ -32,11 +32,11 @@ qualif False1(v:GHC.Types.Bool) : (~ Prop(v)) -qualif Papp(v:a,p:Pred a) : (papp1(p, v)) constant papp1 : func(1, [Pred @(0); @(0); bool])+qualif Papp(v:a,p:Pred a) : (papp1(p, v)) -qualif Papp2(v:a,x:b,p:Pred a b) : (papp2(p, v, x)) constant papp2 : func(4, [Pred @(0) @(1); @(2); @(3); bool])+qualif Papp2(v:a,x:b,p:Pred a b) : (papp2(p, v, x)) qualif Papp3(v:a,x:b, y:c, p:Pred a b c) : (papp3(p, v, x, y)) constant papp3 : func(6, [Pred @(0) @(1) @(2); @(3); @(4); @(5); bool])@@ -46,3 +46,7 @@ constant Prop : func(0, [GHC.Types.Bool; bool])+constant runFun : func(2, [Arrow @(0) @(1); @(0); @(1)])+++
liquidhaskell.cabal view
@@ -1,8 +1,8 @@ Name: liquidhaskell-Version: 0.5.0.1+Version: 0.6.0.0 Copyright: 2010-15 Ranjit Jhala, University of California, San Diego. build-type: Simple-Synopsis: Liquid Types for Haskell +Synopsis: Liquid Types for Haskell Description: Liquid Types for Haskell. Homepage: http://goto.ucsd.edu/liquidhaskell License: BSD3@@ -13,6 +13,7 @@ Build-Type: Simple Cabal-version: >=1.18 + data-files: include/*.hquals , include/*.hs , include/*.spec@@ -32,7 +33,6 @@ , include/Language/Haskell/Liquid/*.hs , include/Language/Haskell/Liquid/*.pred , include/System/*.spec- , include/708/Control/*.spec , include/710/Data/*.spec , syntax/liquid.css @@ -47,6 +47,11 @@ Type: git Location: https://github.com/ucsd-progsys/liquidhaskell/ +Flag devel+ Description: turn on stricter error reporting for development+ Default: False+ Manual: True+ Flag include Description: use in-tree include directory Default: False@@ -55,199 +60,171 @@ default-language: Haskell98 Build-Depends: base >= 4 && < 5 , ghc- , ansi-terminal- , template-haskell- , time- , array- , hpc- , bifunctors , cmdargs- , containers- , cpphs- , data-default , deepseq- , directory- , Diff- , filemanip- , filepath- , ghc-paths- , hscolour- , mtl- , parsec , pretty , process- , syb- , text- , vector , liquid-fixpoint- , hashable- , unordered-containers- , aeson- , bytestring- , fingertree+ , located-base+ -- , prover , liquidhaskell - Main-is: Liquid.hs- ghc-options: -W -fno-warn-unused-imports -fno-warn-dodgy-imports -fno-warn-deprecated-flags -fno-warn-deprecations+ Main-is: src/Liquid.hs+ ghc-options: -W -threaded+ if flag(devel)+ ghc-options: -Werror Default-Extensions: PatternGuards --- Executable liquid-count-binders--- Build-Depends: base >= 4 && < 5--- , ghc==7.6.3--- , ansi-terminal--- , bifunctors--- , cmdargs--- , containers--- , cpphs--- , deepseq--- , directory--- , Diff--- , filemanip--- , filepath--- , ghc-paths--- , hscolour--- , mtl--- , parsec--- , pretty--- , process--- , syb--- , text--- , vector--- , liquid-fixpoint--- , hashable--- , unordered-containers--- , aeson--- , bytestring--- , fingertree--- , liquidhaskell--- --- Main-is: CountBinders.hs--- --ghc-options: -O -W--- Extensions: PatternGuards-+Executable lhi+ default-language: Haskell98+ Build-Depends: base >= 4 && < 5+ , ghc+ , cmdargs+ , deepseq+ , pretty+ , liquid-fixpoint+ , located-base+ -- , prover+ , liquidhaskell+ , network+ , directory+ , unix+ , daemons+ , bytestring+ , data-default+ , unordered-containers+ , cereal+ , process+ Main-is: src/LHi.hs+ ghc-options: -W -threaded+ if flag(devel)+ ghc-options: -Werror+ Default-Extensions: PatternGuards Library Default-Language: Haskell98- Build-Depends: base- , ghc == 7.8.3 || == 7.8.4 || == 7.10.2- , ansi-terminal- , template-haskell- , time- , array- , hpc- , bifunctors- , cmdargs- , containers- , cpphs- , data-default- , deepseq- , directory- , Diff- , filemanip- , filepath- , ghc-paths- , hscolour- , mtl- , parsec- , pretty+ Build-Depends: base >= 4 && < 5+ , ghc >= 7.10.2 && < 7.11+ , template-haskell >= 2.9+ , time >= 1.4+ , array >= 0.5+ , hpc >= 0.6+ , cmdargs >= 0.10+ , containers >= 0.5+ , cpphs >= 1.19+ , data-default >= 0.5+ , deepseq >= 1.3+ , directory >= 1.2+ , Diff >= 0.3+ , filepath >= 1.3+ , ghc-paths >= 0.1+ , hscolour >= 1.22+ , mtl >= 2.1+ , parsec >= 3.1+ , pretty >= 1.1 , process >= 1.2- , syb- , text- , intern- , vector- , hashable- , unordered-containers- , liquid-fixpoint >= 0.4- , aeson- , bytestring- , fingertree+ , syb >= 0.4.4+ , text >= 1.2+ , vector >= 0.10+ , hashable >= 1.2+ , unordered-containers >= 0.2+ , liquid-fixpoint >= 0.5 && < 0.6+ , located-base+ -- , prover+ , aeson >= 0.10+ , bytestring >= 0.10+ , fingertree >= 0.1 , Cabal >= 1.18- + , bifunctors >= 5.1+ , cereal+ , temporary >= 1.2+ hs-source-dirs: src, include- + Exposed-Modules: Language.Haskell.Liquid.Prelude,- Language.Haskell.Liquid.Foreign, - Language.Haskell.Liquid.List, - Language.Haskell.Liquid.PrettyPrint, + Language.Haskell.Liquid.Foreign,+ Language.Haskell.Liquid.List, Language.Haskell.Liquid.Bare,- Language.Haskell.Liquid.Constraint.Constraint, - Language.Haskell.Liquid.Constraint.Types, - Language.Haskell.Liquid.Constraint.Generate, - Language.Haskell.Liquid.Constraint.ToFixpoint, - Language.Haskell.Liquid.Measure, - Language.Haskell.Liquid.Parse, - Language.Haskell.Liquid.GhcInterface, - Language.Haskell.Liquid.World, - Language.Haskell.Liquid.RefType, - Language.Haskell.Liquid.RefSplit, - Language.Haskell.Liquid.Errors, - Language.Haskell.Liquid.PredType, - Language.Haskell.Liquid.ACSS, - Language.Haskell.Liquid.DiffCheck, - Language.Haskell.Liquid.ANFTransform, - Language.Haskell.Liquid.Annotate, - Language.Haskell.Liquid.CTags,- Language.Haskell.Liquid.CmdLine, - Language.Haskell.Liquid.Cabal, - Language.Haskell.Liquid.GhcMisc, - Language.Haskell.Liquid.GhcPlay, - Language.Haskell.Liquid.Misc, - Language.Haskell.Liquid.CoreToLogic,- Language.Haskell.Liquid.Variance,- Language.Haskell.Liquid.Bounds,- Language.Haskell.Liquid.Dictionaries,- Language.Haskell.Liquid.Qualifier, - Language.Haskell.Liquid.TransformRec, - Language.Haskell.Liquid.Tidy, + Language.Haskell.Liquid.Constraint.Constraint,+ Language.Haskell.Liquid.Constraint.Monad,+ Language.Haskell.Liquid.Constraint.Env,+ Language.Haskell.Liquid.Constraint.Types,+ Language.Haskell.Liquid.Constraint.Split,+ Language.Haskell.Liquid.Constraint.Axioms,+ Language.Haskell.Liquid.Constraint.ProofToCore,+ Language.Haskell.Liquid.Constraint.Generate,+ Language.Haskell.Liquid.Constraint.ToFixpoint,+ Language.Haskell.Liquid.Measure,+ Language.Haskell.Liquid.Parse,+ Language.Haskell.Liquid.GHC.Interface,+ Language.Haskell.Liquid.GHC.SpanStack,+ Language.Haskell.Liquid.Types.RefType,+ Language.Haskell.Liquid.Types.Errors,+ Language.Haskell.Liquid.Types.PrettyPrint,+ Language.Haskell.Liquid.Types.Specifications,+ Language.Haskell.Liquid.Types.PredType,+ Language.Haskell.Liquid.Types.Meet,+ Language.Haskell.Liquid.UX.ACSS,+ Language.Haskell.Liquid.UX.DiffCheck,+ Language.Haskell.Liquid.Transforms.ANF,+ Language.Haskell.Liquid.Transforms.RefSplit,+ Language.Haskell.Liquid.Transforms.CoreToLogic,+ Language.Haskell.Liquid.Transforms.Rec,+ Language.Haskell.Liquid.Transforms.Simplify,+ Language.Haskell.Liquid.UX.Errors,+ Language.Haskell.Liquid.UX.Annotate,+ Language.Haskell.Liquid.UX.CTags,+ Language.Haskell.Liquid.UX.Config,+ Language.Haskell.Liquid.UX.CmdLine,+ Language.Haskell.Liquid.GHC.Misc,+ Language.Haskell.Liquid.GHC.Play,+ Language.Haskell.Liquid.Misc,+ Language.Haskell.Liquid.Types.Variance,+ Language.Haskell.Liquid.Types.Bounds,+ Language.Haskell.Liquid.Types.Dictionaries,+ Language.Haskell.Liquid.Constraint.Qualifier,+ Language.Haskell.Liquid.UX.Tidy, Language.Haskell.Liquid.Types,- Language.Haskell.Liquid.Simplify,- Language.Haskell.Liquid.Literals,- Language.Haskell.Liquid.Strata,- Language.Haskell.Liquid.Fresh,- Language.Haskell.Liquid.Visitors,+ Language.Haskell.Liquid.Types.Literals,+ Language.Haskell.Liquid.Types.Strata,+ Language.Haskell.Liquid.Constraint.Fresh,+ Language.Haskell.Liquid.Types.Visitors, Language.Haskell.Liquid.WiredIn,- Language.Haskell.Liquid.Names,+ Language.Haskell.Liquid.Types.Names,+ Language.Haskell.Liquid.Liquid, Paths_liquidhaskell, -- FIXME: These shouldn't really be exposed, but the linker complains otherwise...- Language.Haskell.Liquid.Bare.RefToLogic- Language.Haskell.Liquid.Bare.Check- Language.Haskell.Liquid.Bare.DataType- Language.Haskell.Liquid.Bare.Env- Language.Haskell.Liquid.Bare.Expand- Language.Haskell.Liquid.Bare.Existential- Language.Haskell.Liquid.Bare.GhcSpec- Language.Haskell.Liquid.Bare.Lookup- Language.Haskell.Liquid.Bare.Measure- Language.Haskell.Liquid.Bare.Misc- Language.Haskell.Liquid.Bare.OfType- Language.Haskell.Liquid.Bare.Plugged- Language.Haskell.Liquid.Bare.Resolve- Language.Haskell.Liquid.Bare.RTEnv- Language.Haskell.Liquid.Bare.SymSort- Language.Haskell.Liquid.Bare.Spec+ Language.Haskell.Liquid.Bare.RefToLogic,+ Language.Haskell.Liquid.Bare.Check,+ Language.Haskell.Liquid.Bare.DataType,+ Language.Haskell.Liquid.Bare.Env,+ Language.Haskell.Liquid.Bare.Expand,+ Language.Haskell.Liquid.Bare.Existential,+ Language.Haskell.Liquid.Bare.GhcSpec,+ Language.Haskell.Liquid.Bare.Lookup,+ Language.Haskell.Liquid.Bare.Axiom,+ Language.Haskell.Liquid.Bare.Measure,+ Language.Haskell.Liquid.Bare.Misc,+ Language.Haskell.Liquid.Bare.OfType,+ Language.Haskell.Liquid.Bare.Plugged,+ Language.Haskell.Liquid.Bare.Resolve,+ Language.Haskell.Liquid.Bare.RTEnv,+ Language.Haskell.Liquid.Bare.SymSort,+ Language.Haskell.Liquid.Bare.Spec,+ Language.Haskell.Liquid.Interactive.Types,+ Language.Haskell.Liquid.Interactive.Handler, - if impl(ghc < 7.10)- exposed-modules:- --NOTE: these need to be exposed so GHC generates .dyn_o files for them..- Language.Haskell.Liquid.Desugar.Check,- Language.Haskell.Liquid.Desugar.Coverage,- Language.Haskell.Liquid.Desugar.Desugar,- Language.Haskell.Liquid.Desugar.DsArrows,- Language.Haskell.Liquid.Desugar.DsBinds,- Language.Haskell.Liquid.Desugar.DsExpr,- Language.Haskell.Liquid.Desugar.DsForeign,- Language.Haskell.Liquid.Desugar.DsGRHSs,- Language.Haskell.Liquid.Desugar.DsListComp,- Language.Haskell.Liquid.Desugar.DsMeta,- Language.Haskell.Liquid.Desugar.DsUtils,- Language.Haskell.Liquid.Desugar.HscMain,- Language.Haskell.Liquid.Desugar.Match,- Language.Haskell.Liquid.Desugar.MatchCon,- Language.Haskell.Liquid.Desugar.MatchLit- else- exposed-modules:- --NOTE: these need to be exposed so GHC generates .dyn_o files for them..+ Language.Haskell.Liquid.Prover.Constants,+ Language.Haskell.Liquid.Prover.Misc,+ Language.Haskell.Liquid.Prover.Parser,+ Language.Haskell.Liquid.Prover.Pretty,+ Language.Haskell.Liquid.Prover.SMTInterface,+ Language.Haskell.Liquid.Prover.Solve,+ Language.Haskell.Liquid.Prover.Types,+ Language.Haskell.Liquid.Prover.Names,++ -- NOTE: these need to be exposed so GHC generates .dyn_o files for them.. Language.Haskell.Liquid.Desugar710.Check, Language.Haskell.Liquid.Desugar710.Coverage, Language.Haskell.Liquid.Desugar710.Desugar,@@ -264,28 +241,33 @@ Language.Haskell.Liquid.Desugar710.Match, Language.Haskell.Liquid.Desugar710.MatchCon, Language.Haskell.Liquid.Desugar710.MatchLit- ghc-options: -W -fno-warn-unused-imports -fno-warn-dodgy-imports -fno-warn-deprecated-flags -fno-warn-deprecations+ ghc-options: -W if flag(include) hs-source-dirs: devel+ if flag(devel)+ ghc-options: -Werror+ ghc-prof-options: -fprof-auto Default-Extensions: PatternGuards test-suite test default-language: Haskell98 type: exitcode-stdio-1.0 hs-source-dirs: tests- ghc-options: -O2 -threaded+ ghc-options: -W -threaded+ if flag(devel)+ ghc-options: -Werror main-is: test.hs- build-depends: base,- liquidhaskell,- containers,- directory,- filepath,- mtl,- process,- optparse-applicative == 0.11.*,- stm,- tagged,- tasty >= 0.10,- tasty-hunit >= 0.9,- tasty-rerun >= 1.1,- transformers+ build-depends: base >= 4 && < 5+ , containers >= 0.5+ , directory >= 1.2+ , filepath >= 1.3+ , mtl >= 2.1+ , process >= 1.2+ , optparse-applicative >= 0.11+ , stm >= 2.4+ , tagged >= 0.7.3+ , tasty >= 0.10+ , tasty-ant-xml+ , tasty-hunit >= 0.9+ , tasty-rerun >= 1.1+ , transformers >= 0.3
+ src/LHi.hs view
@@ -0,0 +1,35 @@+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE OverloadedStrings #-}++import System.Environment (getArgs)+import System.Daemon+import Control.Concurrent.MVar ( newMVar )+import Data.Default ( def )+import Language.Haskell.Liquid.Interactive.Types+import qualified Language.Haskell.Liquid.Interactive.Handler as H+import Language.Haskell.Liquid.UX.CmdLine (getOpts)+import Language.Haskell.Liquid.UX.Config (port)++daemonName :: String+daemonName = "lhi0"++main :: IO ()+main = do+ st <- newMVar H.initial+ cmd <- command+ ensureDaemonRunning daemonName (options cmd) (H.handler st)+ res <- client cmd+ print res++options :: Command -> DaemonOptions+options cmd = def { daemonPort = port cmd }++client :: Command -> IO (Maybe Response)+client cmd = runClient "localhost" (port cmd) cmd++---------------------------------------------------------------------------------+-- | Parsing Command Line -------------------------------------------------------+---------------------------------------------------------------------------------+command :: IO Command+-------------------------------------------------------------------------------+command = getOpts =<< getArgs
− src/Language/Haskell/Liquid/ACSS.hs
@@ -1,264 +0,0 @@--- | Formats Haskell source code as HTML with CSS and Mouseover Type Annotations-module Language.Haskell.Liquid.ACSS (- hscolour- , hsannot- , AnnMap (..)- , breakS- , srcModuleName- , Status (..)- ) where--import Language.Haskell.HsColour.Anchors-import Language.Haskell.HsColour.Classify as Classify-import Language.Haskell.HsColour.HTML (renderAnchors, escape)-import qualified Language.Haskell.HsColour.CSS as CSS--import Data.Either (partitionEithers)-import Data.Maybe (fromMaybe)-import qualified Data.HashMap.Strict as M-import Data.List (find, isPrefixOf, findIndex, elemIndices, intercalate)-import Data.Char (isSpace)-import Text.Printf-import Language.Haskell.Liquid.GhcMisc--data AnnMap = Ann {- types :: M.HashMap Loc (String, String) -- ^ Loc -> (Var, Type)- , errors :: [(Loc, Loc, String)] -- ^ List of error intervals- , status :: !Status- }--data Status = Safe | Unsafe | Error | Crash- deriving (Eq, Ord, Show)--data Annotation = A {- typ :: Maybe String -- ^ type string- , err :: Maybe String -- ^ error string- , lin :: Maybe (Int, Int) -- ^ line number, total width of lines i.e. max (length (show lineNum))- } deriving (Show)----- | Formats Haskell source code using HTML and mouse-over annotations-hscolour :: Bool -- ^ Whether to include anchors.- -> Bool -- ^ Whether input document is literate haskell or not- -> String -- ^ Haskell source code, Annotations as comments at end- -> String -- ^ Coloured Haskell source code.--hscolour anchor lhs = hsannot anchor Nothing lhs . splitSrcAndAnns--type CommentTransform = Maybe (String -> [(TokenType, String)])---- | Formats Haskell source code using HTML and mouse-over annotations-hsannot :: Bool -- ^ Whether to include anchors.- -> CommentTransform -- ^ Function to refine comment tokens- -> Bool -- ^ Whether input document is literate haskell or not- -> (String, AnnMap) -- ^ Haskell Source, Annotations- -> String -- ^ Coloured Haskell source code.--hsannot anchor tx False z = hsannot' Nothing anchor tx z-hsannot anchor tx True (s, m) = concatMap chunk $ litSpans $ joinL $ classify $ inlines s- where chunk (Code c, l) = hsannot' (Just l) anchor tx (c, m)- chunk (Lit c , _) = c--litSpans :: [Lit] -> [(Lit, Loc)]-litSpans lits = zip lits $ spans lits- where spans = tokenSpans Nothing . map unL--hsannot' baseLoc anchor tx =- CSS.pre- . (if anchor then concatMap (renderAnchors renderAnnotToken)- . insertAnnotAnchors- else concatMap renderAnnotToken)- . annotTokenise baseLoc tx---- | annotTokenise is absurdly slow: O(#tokens x #errors)--annotTokenise :: Maybe Loc -> CommentTransform -> (String, AnnMap) -> [(TokenType, String, Annotation)]-annotTokenise baseLoc tx (src, annm) = zipWith (\(x,y) z -> (x,y,z)) toks annots- where- toks = tokeniseWithCommentTransform tx src- spans = tokenSpans baseLoc $ map snd toks- annots = fmap (spanAnnot linWidth annm) spans- linWidth = length $ show $ length $ lines src--spanAnnot w (Ann ts es _) span = A t e b- where- t = fmap snd (M.lookup span ts)- e = fmap (\_ -> "ERROR") $ find (span `inRange`) [(x,y) | (x,y,_) <- es]- b = spanLine w span--spanLine w (L (l, c))- | c == 1 = Just (l, w)- | otherwise = Nothing--inRange (L (l0, c0)) (L (l, c), L (l', c'))- = l <= l0 && c <= c0 && l0 <= l' && c0 < c'--tokeniseWithCommentTransform :: Maybe (String -> [(TokenType, String)]) -> String -> [(TokenType, String)]-tokeniseWithCommentTransform Nothing = tokenise-tokeniseWithCommentTransform (Just f) = concatMap (expand f) . tokenise- where expand f (Comment, s) = f s- expand _ z = [z]--tokenSpans :: Maybe Loc -> [String] -> [Loc]-tokenSpans = scanl plusLoc . fromMaybe (L (1, 1))--plusLoc :: Loc -> String -> Loc-plusLoc (L (l, c)) s- = case '\n' `elemIndices` s of- [] -> L (l, (c + n))- is -> L ((l + length is), (n - maximum is))- where n = length s--renderAnnotToken :: (TokenType, String, Annotation) -> String-renderAnnotToken (x, y, a) = renderLinAnnot (lin a)- $ renderErrAnnot (err a)- $ renderTypAnnot (typ a)- $ CSS.renderToken (x, y)----renderTypAnnot (Just ann) s = printf "<a class=annot href=\"#\"><span class=annottext>%s</span>%s</a>" (escape ann) s-renderTypAnnot Nothing s = s--renderErrAnnot (Just _) s = printf "<span class=hs-error>%s</span>" s-renderErrAnnot Nothing s = s--renderLinAnnot (Just d) s = printf "<span class=hs-linenum>%s: </span>%s" (lineString d) s-renderLinAnnot Nothing s = s--lineString (i, w) = (replicate (w - (length is)) ' ') ++ is- where is = show i--{- Example Annotation:-<a class=annot href="#"><span class=annottext>x#agV:Int -> {VV_int:Int | (0 <= VV_int),(x#agV <= VV_int)}</span>-<span class='hs-definition'>NOWTRYTHIS</span></a>--}---insertAnnotAnchors :: [(TokenType, String, a)] -> [Either String (TokenType, String, a)]-insertAnnotAnchors toks- = stitch (zip toks' toks) $ insertAnchors toks'- where toks' = [(x,y) | (x,y,_) <- toks]--stitch :: Eq b => [(b, c)] -> [Either a b] -> [Either a c]-stitch xys ((Left a) : rest)- = (Left a) : stitch xys rest-stitch ((x,y):xys) ((Right x'):rest)- | x == x'- = (Right y) : stitch xys rest- | otherwise- = error "stitch"-stitch _ []- = []-stitch _ _- = error "stitch: cannot happen"--splitSrcAndAnns :: String -> (String, AnnMap)-splitSrcAndAnns s =- let ls = lines s in- case findIndex (breakS ==) ls of- Nothing -> (s, Ann M.empty [] Safe)- Just i -> (src, ann)- where (codes, _:mname:annots) = splitAt i ls- ann = annotParse mname $ dropWhile isSpace $ unlines annots- src = unlines codes--srcModuleName :: String -> String-srcModuleName = fromMaybe "Main" . tokenModule . tokenise--tokenModule toks- = do i <- findIndex ((Keyword, "module") ==) toks- let (_, toks') = splitAt (i+2) toks- j <- findIndex ((Space ==) . fst) toks'- let (toks'', _) = splitAt j toks'- return $ concatMap snd toks''--breakS = "MOUSEOVER ANNOTATIONS"--annotParse :: String -> String -> AnnMap-annotParse mname s = Ann (M.fromList ts) [(x,y,"") | (x,y) <- es] Safe- where- (ts, es) = partitionEithers $ parseLines mname 0 $ lines s---parseLines _ _ []- = []--parseLines mname i ("":ls)- = parseLines mname (i+1) ls--parseLines mname i (_:_:l:c:"0":l':c':rest')- = Right (L (line, col), L (line', col')) : parseLines mname (i + 7) rest'- where line = (read l) :: Int- col = (read c) :: Int- line' = (read l') :: Int- col' = (read c') :: Int--parseLines mname i (x:f:l:c:n:rest)- | f /= mname- = parseLines mname (i + 5 + num) rest'- | otherwise- = Left (L (line, col), (x, anns)) : parseLines mname (i + 5 + num) rest'- where line = (read l) :: Int- col = (read c) :: Int- num = (read n) :: Int- anns = intercalate "\n" $ take num rest- rest' = drop num rest--parseLines _ i _- = error $ "Error Parsing Annot Input on Line: " ++ show i--instance Show AnnMap where- show (Ann ts es _ ) = "\n\n" ++ (concatMap ppAnnotTyp $ M.toList ts)- ++ (concatMap ppAnnotErr [(x,y) | (x,y,_) <- es])--ppAnnotTyp (L (l, c), (x, s)) = printf "%s\n%d\n%d\n%d\n%s\n\n\n" x l c (length $ lines s) s-ppAnnotErr (L (l, c), L (l', c')) = printf " \n%d\n%d\n0\n%d\n%d\n\n\n\n" l c l' c'----------------------------------------------------------------------------------------- Code for Dealing With LHS, stolen from Language.Haskell.HsColour.HsColour ---------------------------------------------------------------------------------------- | Separating literate files into code\/comment chunks.-data Lit = Code {unL :: String} | Lit {unL :: String} deriving (Show)---- Re-implementation of 'lines', for better efficiency (but decreased laziness).--- Also, importantly, accepts non-standard DOS and Mac line ending characters.--- And retains the trailing '\n' character in each resultant string.-inlines :: String -> [String]-inlines s = lines' s id- where- lines' [] acc = [acc []]- lines' ('\^M':'\n':s) acc = acc ['\n'] : lines' s id -- DOS- lines' ('\n':s) acc = acc ['\n'] : lines' s id -- Unix- lines' (c:s) acc = lines' s (acc . (c:))----- | The code for classify is largely stolen from Language.Preprocessor.Unlit.-classify :: [String] -> [Lit]-classify [] = []-classify (x:xs) | "\\begin{code}"`isPrefixOf`x- = Lit x: allProg "code" xs-classify (x:xs) | "\\begin{spec}"`isPrefixOf`x- = Lit x: allProg "spec" xs-classify (('>':x):xs) = Code ('>':x) : classify xs-classify (x:xs) = Lit x: classify xs---allProg name = go- where- end = "\\end{" ++ name ++ "}"- go [] = [] -- Should give an error message,- -- but I have no good position information.- go (x:xs) | end `isPrefixOf `x- = Lit x: classify xs- go (x:xs) = Code x: go xs----- | Join up chunks of code\/comment that are next to each other.-joinL :: [Lit] -> [Lit]-joinL [] = []-joinL (Code c:Code c2:xs) = joinL (Code (c++c2):xs)-joinL (Lit c :Lit c2 :xs) = joinL (Lit (c++c2):xs)-joinL (any:xs) = any: joinL xs
− src/Language/Haskell/Liquid/ANFTransform.hs
@@ -1,265 +0,0 @@-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE NoMonomorphismRestriction #-}-{-# LANGUAGE TupleSections #-}-{-# LANGUAGE TypeSynonymInstances #-}-{-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE OverloadedStrings #-}---------------------------------------------------------------------------------------------------- Code to convert Core to Administrative Normal Form -------------------------------------------------------------------------------------------------------------module Language.Haskell.Liquid.ANFTransform (anormalize) where-import CoreSyn-import CoreUtils (exprType)-import qualified DsMonad-import DsMonad (initDs)-import GHC hiding (exprType)-import HscTypes-import Id (mkSysLocalM)-import Literal-import MkCore (mkCoreLets)-import Outputable (trace)-import Var (varType, setVarType)-import TypeRep-import Type (mkForAllTys, substTy, mkForAllTys, mkTopTvSubst, isTyVar)-import TyCon (tyConDataCons_maybe)-import DataCon (dataConInstArgTys)-import FamInstEnv (emptyFamInstEnv)-import VarEnv (VarEnv, emptyVarEnv, extendVarEnv, lookupWithDefaultVarEnv)-import Control.Monad.State.Lazy-import UniqSupply (MonadUnique)-import Language.Fixpoint.Types (anfPrefix)-import Language.Haskell.Liquid.GhcMisc (MGIModGuts(..), showPpr, symbolFastString)-import Language.Haskell.Liquid.TransformRec-import Language.Fixpoint.Misc (fst3, errorstar)-import Data.Maybe (fromMaybe)-import Data.List (sortBy, (\\))-import Control.Applicative--anormalize :: Bool -> HscEnv -> MGIModGuts -> IO [CoreBind]-anormalize expandFlag hscEnv modGuts- = do -- putStrLn "***************************** GHC CoreBinds ***************************" - -- putStrLn $ showPpr orig_cbs- liftM (fromMaybe err . snd) $ initDs hscEnv m grEnv tEnv emptyFamInstEnv act- where m = mgi_module modGuts- grEnv = mgi_rdr_env modGuts- tEnv = modGutsTypeEnv modGuts- act = liftM concat $ mapM (normalizeTopBind expandFlag emptyVarEnv) orig_cbs- orig_cbs = transformRecExpr $ mgi_binds modGuts- err = errorstar "anormalize fails!"--modGutsTypeEnv mg = typeEnvFromEntities ids tcs fis- where ids = bindersOfBinds (mgi_binds mg)- tcs = mgi_tcs mg- fis = mgi_fam_insts mg-------------------------------------------------------------------------------------- Actual Normalizing Functions ------------------------------------------------------------------------------------------ Can't make the below default for normalizeBind as it --- fails tests/pos/lets.hs due to GHCs odd let-bindings--normalizeTopBind :: Bool -> VarEnv Id -> Bind CoreBndr -> DsMonad.DsM [CoreBind]-normalizeTopBind expandFlag γ (NonRec x e)- = do e' <- runDsM $ evalStateT (stitch γ e) (DsST expandFlag [])- return [normalizeTyVars $ NonRec x e']--normalizeTopBind expandFlag γ (Rec xes)- = do xes' <- runDsM $ execStateT (normalizeBind γ (Rec xes)) (DsST expandFlag [])- return $ map normalizeTyVars (st_binds xes')--normalizeTyVars (NonRec x e) = NonRec (setVarType x t') $ normalizeForAllTys e- where t' = subst msg as as' bt- msg = "WARNING unable to renameVars on " ++ showPpr x- as' = fst $ splitForAllTys $ exprType e- (as, bt) = splitForAllTys (varType x)-normalizeTyVars (Rec xes) = Rec xes'- where nrec = normalizeTyVars <$> ((\(x, e) -> NonRec x e) <$> xes)- xes' = (\(NonRec x e) -> (x, e)) <$> nrec--subst msg as as' bt- | length as == length as'- = mkForAllTys as' $ substTy su bt- | otherwise- = trace msg $ mkForAllTys as bt- where su = mkTopTvSubst $ zip as (mkTyVarTys as')---- | eta-expand CoreBinds with quantified types-normalizeForAllTys :: CoreExpr -> CoreExpr-normalizeForAllTys e = case e of- Lam b _ | isTyVar b- -> e- _ -> mkLams tvs (mkTyApps e (map mkTyVarTy tvs))- where- (tvs, _) = splitForAllTys (exprType e)---newtype DsM a = DsM {runDsM :: DsMonad.DsM a}- deriving (Functor, Monad, MonadUnique, Applicative)--data DsST = DsST { st_expandflag :: Bool- , st_binds :: [CoreBind]- }--type DsMW = StateT DsST DsM---------------------------------------------------------------------normalizeBind :: VarEnv Id -> CoreBind -> DsMW ()---------------------------------------------------------------------normalizeBind γ (NonRec x e)- = do e' <- normalize γ e- add [NonRec x e']--normalizeBind γ (Rec xes)- = do es' <- mapM (stitch γ) es- add [Rec (zip xs es')]- where (xs, es) = unzip xes-----------------------------------------------------------------------normalizeName :: VarEnv Id -> CoreExpr -> DsMW CoreExpr------------------------------------------------------------------------- normalizeNameDebug γ e --- = liftM (tracePpr ("normalizeName" ++ showPpr e)) $ normalizeName γ e--normalizeName _ e@(Lit l)- | shouldNormalize l- = normalizeLiteral e- | otherwise- = return e--normalizeName γ (Var x)- = return $ Var (lookupWithDefaultVarEnv γ x x)--normalizeName _ e@(Type _)- = return e--normalizeName _ e@(Coercion _)- = do x <- lift $ freshNormalVar $ exprType e- add [NonRec x e]- return $ Var x--normalizeName γ (Tick n e)- = do e' <- normalizeName γ e- return $ Tick n e'--normalizeName γ e- = do e' <- normalize γ e- x <- lift $ freshNormalVar $ exprType e- add [NonRec x e']- return $ Var x--shouldNormalize l = case l of- LitInteger _ _ -> True- MachStr _ -> True- _ -> False--add :: [CoreBind] -> DsMW ()-add w = modify $ \s -> s{st_binds = st_binds s++w}------------------------------------------------------------------------normalizeLiteral :: CoreExpr -> DsMW CoreExpr------------------------------------------------------------------------normalizeLiteral e =- do x <- lift $ freshNormalVar (exprType e)- add [NonRec x e]- return $ Var x--freshNormalVar :: Type -> DsM Id-freshNormalVar = mkSysLocalM (symbolFastString anfPrefix)------------------------------------------------------------------------normalize :: VarEnv Id -> CoreExpr -> DsMW CoreExpr------------------------------------------------------------------------normalize γ (Lam x e)- = do e' <- stitch γ e- return $ Lam x e'--normalize γ (Let b e)- = do normalizeBind γ b- normalize γ e- -- Need to float bindings all the way up to the top - -- Due to GHCs odd let-bindings (see tests/pos/lets.hs) --normalize γ (Case e x t as)- = do n <- normalizeName γ e- x' <- lift $ freshNormalVar τx -- rename "wild" to avoid shadowing- let γ' = extendVarEnv γ x x'- as' <- forM as $ \(c, xs, e') -> liftM (c, xs,) (stitch γ' e')- flag <- st_expandflag <$> get- as'' <- lift $ expandDefaultCase flag τx as' - return $ Case n x' t as''- where τx = varType x--normalize γ (Var x)- = return $ Var (lookupWithDefaultVarEnv γ x x)--normalize _ e@(Lit _)- = return e--normalize _ e@(Type _)- = return e--normalize γ (Cast e τ)- = do e' <- normalizeName γ e- return $ Cast e' τ--normalize γ (App e1 e2)- = do e1' <- normalize γ e1- n2 <- normalizeName γ e2- return $ App e1' n2--normalize γ (Tick n e)- = do e' <- normalize γ e- return $ Tick n e'--normalize _ (Coercion c) - = return $ Coercion c--stitch :: VarEnv Id -> CoreExpr -> DsMW CoreExpr -stitch γ e- = do bs' <- get- modify $ \s -> s {st_binds = []}- e' <- normalize γ e- bs <- st_binds <$> get- put bs'- return $ mkCoreLets bs e'-------------------------------------------------------------------------------------expandDefaultCase :: Bool -> Type -> [(AltCon, [Id], CoreExpr)] -> DsM [(AltCon, [Id], CoreExpr)]-------------------------------------------------------------------------------------expandDefaultCase flag tyapp zs@((DEFAULT, _ ,_) : _) | flag- = expandDefaultCase' tyapp zs--expandDefaultCase _ tyapp@(TyConApp tc _) z@((DEFAULT, _ ,_):dcs)- = case tyConDataCons_maybe tc of- Just ds -> do let ds' = ds \\ [ d | (DataAlt d, _ , _) <- dcs] - if (length ds') == 1 - then expandDefaultCase' tyapp z - else return z- Nothing -> return z ----expandDefaultCase _ _ z- = return z--expandDefaultCase' (TyConApp tc argτs) z@((DEFAULT, _ ,e) : dcs)- = case tyConDataCons_maybe tc of- Just ds -> do let ds' = ds \\ [ d | (DataAlt d, _ , _) <- dcs] - dcs' <- forM ds' $ cloneCase argτs e- return $ sortCases $ dcs' ++ dcs- Nothing -> return z ---expandDefaultCase' _ z- = return z--cloneCase argτs e d - = do xs <- mapM freshNormalVar $ dataConInstArgTys d argτs- return (DataAlt d, xs, e)--sortCases = sortBy (\x y -> cmpAltCon (fst3 x) (fst3 y))-
− src/Language/Haskell/Liquid/Annotate.hs
@@ -1,425 +0,0 @@-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE TupleSections #-}-{-# LANGUAGE NoMonomorphismRestriction #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE TypeSynonymInstances #-}-{-# LANGUAGE FlexibleInstances #-}-------------------------------------------------------------------------------- | This module contains the code that uses the inferred types to generate--- 1. HTMLized source with Inferred Types in mouseover annotations.--- 2. Annotations files (e.g. for vim/emacs)--- 3. JSON files for the web-demo etc.------------------------------------------------------------------------------module Language.Haskell.Liquid.Annotate (mkOutput, annotate) where--import GHC ( SrcSpan (..)- , srcSpanStartCol- , srcSpanEndCol- , srcSpanStartLine- , srcSpanEndLine)-import Text.PrettyPrint.HughesPJ hiding (first)-import GHC.Exts (groupWith, sortWith)--import Data.Char (isSpace)-import Data.Function (on)-import Data.List (sortBy)-import Data.Maybe (mapMaybe)--import Data.Aeson-import Control.Arrow hiding ((<+>))-import Control.Applicative ((<$>))-import Control.Monad (when, forM_)--import System.FilePath (takeFileName, dropFileName, (</>))-import System.Directory (findExecutable, copyFile)-import Text.Printf (printf)-import qualified Data.List as L-import qualified Data.Vector as V-import qualified Data.ByteString.Lazy as B-import qualified Data.Text as T-import qualified Data.HashMap.Strict as M-import qualified Language.Haskell.Liquid.ACSS as ACSS-import Language.Haskell.HsColour.Classify-import Language.Fixpoint.Files-import Language.Fixpoint.Names hiding (encode)-import Language.Fixpoint.Misc-import Language.Haskell.Liquid.GhcMisc-import Language.Fixpoint.Types hiding (Def (..), Constant (..), Located (..))-import Language.Haskell.Liquid.Misc-import Language.Haskell.Liquid.PrettyPrint-import Language.Haskell.Liquid.RefType-import Language.Haskell.Liquid.Errors ()-import Language.Haskell.Liquid.Tidy-import Language.Haskell.Liquid.Types hiding (Located(..), Def(..))---- | @output@ creates the pretty printed output----------------------------------------------------------------------------------------------mkOutput :: Config -> FixResult Error -> FixSolution -> AnnInfo (Annot SpecType) -> Output Doc----------------------------------------------------------------------------------------------mkOutput cfg res sol anna- = O { o_vars = Nothing- , o_errors = []- , o_types = toDoc <$> annTy- , o_templs = toDoc <$> annTmpl- , o_bots = mkBots annTy- , o_result = res- }- where- annTmpl = closeAnnots anna- annTy = tidySpecType Lossy <$> applySolution sol annTmpl- toDoc = rtypeDoc tidy- tidy = if shortNames cfg then Lossy else Full---- | @annotate@ actually renders the output to files---------------------------------------------------------------------annotate :: Config -> FilePath -> Output Doc -> IO ()---------------------------------------------------------------------annotate cfg srcF out- = do generateHtml srcF tpHtmlF tplAnnMap- generateHtml srcF tyHtmlF typAnnMap- writeFile vimF $ vimAnnot cfg annTyp- B.writeFile jsonF $ encode typAnnMap- when showWarns $ forM_ bots (printf "WARNING: Found false in %s\n" . showPpr)- where- tplAnnMap = mkAnnMap cfg result annTpl- typAnnMap = mkAnnMap cfg result annTyp- annTpl = o_templs out- annTyp = o_types out- result = o_result out- bots = o_bots out- tyHtmlF = extFileName Html srcF- tpHtmlF = extFileName Html $ extFileName Cst srcF- _annF = extFileName Annot srcF- jsonF = extFileName Json srcF- vimF = extFileName Vim srcF- showWarns = not $ nowarnings cfg--mkBots (AI m) = [ src | (src, (Just _, t) : _) <- sortBy (compare `on` fst) $ M.toList m- , isFalse (rTypeReft t) ]--writeFilesOrStrings :: FilePath -> [Either FilePath String] -> IO ()-writeFilesOrStrings tgtFile = mapM_ $ either (`copyFile` tgtFile) (tgtFile `appendFile`)--generateHtml srcF htmlF annm- = do src <- readFile srcF- let lhs = isExtFile LHs srcF- let body = {-# SCC "hsannot" #-} ACSS.hsannot False (Just tokAnnot) lhs (src, annm)- cssFile <- getCssPath- copyFile cssFile (dropFileName htmlF </> takeFileName cssFile)- renderHtml lhs htmlF srcF (takeFileName cssFile) body--renderHtml True = renderPandoc-renderHtml False = renderDirect------------------------------------------------------------------------------ | Pandoc HTML Rendering (for lhs + markdown source) ----------------------------------------------------------------------------------------------renderPandoc htmlFile srcFile css body- = do renderFn <- maybe renderDirect renderPandoc' <$> findExecutable "pandoc"- renderFn htmlFile srcFile css body--renderPandoc' pandocPath htmlFile srcFile css body- = do _ <- writeFile mdFile $ pandocPreProc body- ec <- executeShellCommand "pandoc" cmd- writeFilesOrStrings htmlFile [Right (cssHTML css)]- checkExitCode cmd ec- where mdFile = extFileName Mkdn srcFile- cmd = pandocCmd pandocPath mdFile htmlFile--pandocCmd pandocPath mdFile htmlFile- = printf "%s -f markdown -t html %s > %s" pandocPath mdFile htmlFile--pandocPreProc = T.unpack- . strip beg code- . strip end code- . strip beg spec- . strip end spec- . T.pack- where- beg, end, code, spec :: String- beg = "begin"- end = "end"- code = "code"- spec = "spec"- strip x y = T.replace (T.pack $ printf "\\%s{%s}" x y) T.empty- -- stripBcode = T.replace (T.pack "\\begin{code}") T.empty- -- stripEcode = T.replace (T.pack "\\end{code}") T.empty- -- stripBspec = T.replace (T.pack "\\begin{code}") T.empty- -- stripEspec = T.replace (T.pack "\\end{code}") T.empty--------------------------------------------------------------------------------- | Direct HTML Rendering (for non-lhs/markdown source) ---------------------------------------------------------------------------------------------- More or less taken from hscolour--renderDirect htmlFile srcFile css body- = writeFile htmlFile $! (top'n'tail full srcFile css $! body)- where full = True -- False -- TODO: command-line-option---- | @top'n'tail True@ is used for standalone HTML,--- @top'n'tail False@ for embedded HTML--top'n'tail True title css = (htmlHeader title css ++) . (++ htmlClose)-top'n'tail False _ _ = id---- Use this for standalone HTML--htmlHeader title css = unlines- [ "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\">"- , "<html>"- , "<head>"- , "<title>" ++ title ++ "</title>"- , "</head>"- , cssHTML css- , "<body>"- , "<hr>"- , "Put mouse over identifiers to see inferred types"- ]--htmlClose = "\n</body>\n</html>"--cssHTML css = unlines- [ "<head>"- , "<link type='text/css' rel='stylesheet' href='"++ css ++ "' />"- , "</head>"- ]----------------------------------------------------------------------------------- | Building Annotation Maps ----------------------------------------------------------------------------------------------------------------------------------- | This function converts our annotation information into that which--- is required by `Language.Haskell.Liquid.ACSS` to generate mouseover--- annotations.--mkAnnMap :: Config -> FixResult Error -> AnnInfo Doc -> ACSS.AnnMap-mkAnnMap cfg res ann = ACSS.Ann (mkAnnMapTyp cfg ann) (mkAnnMapErr res) (mkStatus res)--mkStatus (Safe) = ACSS.Safe-mkStatus (Unsafe _) = ACSS.Unsafe-mkStatus (Crash _ _) = ACSS.Error-mkStatus _ = ACSS.Crash--mkAnnMapErr (Unsafe ls) = mapMaybe cinfoErr ls-mkAnnMapErr (Crash ls _) = mapMaybe cinfoErr ls-mkAnnMapErr _ = []--cinfoErr e = case pos e of- RealSrcSpan l -> Just (srcSpanStartLoc l, srcSpanEndLoc l, showpp e)- _ -> Nothing---- cinfoErr (Ci (RealSrcSpan l) e) =--- cinfoErr _ = Nothing----- mkAnnMapTyp :: (RefTypable a c tv r, RefTypable a c tv (), PPrint tv, PPrint a) =>Config-> AnnInfo (RType a c tv r) -> M.HashMap Loc (String, String)-mkAnnMapTyp cfg z = M.fromList $ map (first srcSpanStartLoc) $ mkAnnMapBinders cfg z--mkAnnMapBinders cfg (AI m)- = map (second bindStr . head . sortWith (srcSpanEndCol . fst))- $ groupWith (lineCol . fst)- [ (l, x) | (RealSrcSpan l, x:_) <- M.toList m, oneLine l]- where- bindStr (x, v) = (maybe "_" (symbolString . shorten . symbol) x, render v)- shorten = if shortNames cfg then dropModuleNames else id--closeAnnots :: AnnInfo (Annot SpecType) -> AnnInfo SpecType-closeAnnots = closeA . filterA . collapseA--closeA a@(AI m) = cf <$> a- where- cf (AnnLoc l) = case m `mlookup` l of- [(_, AnnUse t)] -> t- [(_, AnnDef t)] -> t- [(_, AnnRDf t)] -> t- _ -> errorstar $ "malformed AnnInfo: " ++ showPpr l- cf (AnnUse t) = t- cf (AnnDef t) = t- cf (AnnRDf t) = t--filterA (AI m) = AI (M.filter ff m)- where- ff [(_, AnnLoc l)] = l `M.member` m- ff _ = True--collapseA (AI m) = AI (fmap pickOneA m)--pickOneA xas = case (rs, ds, ls, us) of- (x:_, _, _, _) -> [x]- (_, x:_, _, _) -> [x]- (_, _, x:_, _) -> [x]- (_, _, _, x:_) -> [x]- (_, _, _, _ ) -> [ ]- where- rs = [x | x@(_, AnnRDf _) <- xas]- ds = [x | x@(_, AnnDef _) <- xas]- ls = [x | x@(_, AnnLoc _) <- xas]- us = [x | x@(_, AnnUse _) <- xas]----------------------------------------------------------------------------------- | Tokenizing Refinement Type Annotations in @-blocks --------------------------------------------------------------------------------------------------------- | The token used for refinement symbols inside the highlighted types in @-blocks.-refToken = Keyword---- | The top-level function for tokenizing @-block annotations. Used to--- tokenize comments by ACSS.-tokAnnot s- = case trimLiquidAnnot s of- Just (l, body, r) -> [(refToken, l)] ++ tokBody body ++ [(refToken, r)]- Nothing -> [(Comment, s)]--trimLiquidAnnot ('{':'-':'@':ss)- | drop (length ss - 3) ss == "@-}"- = Just (liquidBegin, take (length ss - 3) ss, liquidEnd)-trimLiquidAnnot _- = Nothing--tokBody s- | isData s = tokenise s- | isType s = tokenise s- | isIncl s = tokenise s- | isMeas s = tokenise s- | otherwise = tokeniseSpec s--isMeas = spacePrefix "measure"-isData = spacePrefix "data"-isType = spacePrefix "type"-isIncl = spacePrefix "include"--spacePrefix str s@(c:cs)- | isSpace c = spacePrefix str cs- | otherwise = take (length str) s == str-spacePrefix _ _ = False---tokeniseSpec :: String -> [(TokenType, String)]-tokeniseSpec str = {- traceShow ("tokeniseSpec: " ++ str) $ -} tokeniseSpec' str--tokeniseSpec' = tokAlt . chopAltDBG -- [('{', ':'), ('|', '}')]- where- tokAlt (s:ss) = tokenise s ++ tokAlt' ss- tokAlt _ = []- tokAlt' (s:ss) = (refToken, s) : tokAlt ss- tokAlt' _ = []--chopAltDBG y = {- traceShow ("chopAlts: " ++ y) $ -}- filter (/= "") $ concatMap (chopAlts [("{", ":"), ("|", "}")])- $ chopAlts [("<{", "}>"), ("{", "}")] y-------------------------------------------------------------------------------- | JSON: Annotation Data Types ------------------------------------------------------------------------------------------------------------------data Assoc k a = Asc (M.HashMap k a)-type AnnTypes = Assoc Int (Assoc Int Annot1)-type AnnErrors = [(Loc, Loc, String)]-data Annot1 = A1 { ident :: String- , ann :: String- , row :: Int- , col :: Int- }----------------------------------------------------------------------------- | Creating Vim Annotations ---------------------------------------------------------------------------------------------------------------------vimAnnot :: Config -> AnnInfo Doc -> String-vimAnnot cfg = L.intercalate "\n" . map vimBind . mkAnnMapBinders cfg--vimBind (sp, (v, ann)) = printf "%d:%d-%d:%d::%s" l1 c1 l2 c2 (v ++ " :: " ++ show ann)- where- l1 = srcSpanStartLine sp- c1 = srcSpanStartCol sp- l2 = srcSpanEndLine sp- c2 = srcSpanEndCol sp----------------------------------------------------------------------------- | JSON Instances -------------------------------------------------------------------------------------------------------------------------------instance ToJSON ACSS.Status where- toJSON ACSS.Safe = "safe"- toJSON ACSS.Unsafe = "unsafe"- toJSON ACSS.Error = "error"- toJSON ACSS.Crash = "crash"--instance ToJSON Annot1 where- toJSON (A1 i a r c) = object [ "ident" .= i- , "ann" .= a- , "row" .= r- , "col" .= c- ]--instance ToJSON Loc where- toJSON (L (l, c)) = object [ "line" .= toJSON l- , "column" .= toJSON c ]--instance ToJSON AnnErrors where- toJSON errs = Array $ V.fromList $ fmap toJ errs- where- toJ (l,l',s) = object [ "start" .= toJSON l- , "stop" .= toJSON l'- , "message" .= toJSON s ]--instance (Show k, ToJSON a) => ToJSON (Assoc k a) where- toJSON (Asc kas) = object [ tshow k .= toJSON a | (k, a) <- M.toList kas ]- where- tshow = T.pack . show--instance ToJSON ACSS.AnnMap where- toJSON a = object [ "types" .= toJSON (annTypes a)- , "errors" .= toJSON (ACSS.errors a)- , "status" .= toJSON (ACSS.status a)- ]--annTypes :: ACSS.AnnMap -> AnnTypes-annTypes a = grp [(l, c, ann1 l c x s) | (l, c, x, s) <- binders]- where- ann1 l c x s = A1 x s l c- grp = L.foldl' (\m (r,c,x) -> ins r c x m) (Asc M.empty)- binders = [(l, c, x, s) | (L (l, c), (x, s)) <- M.toList $ ACSS.types a]--ins r c x (Asc m) = Asc (M.insert r (Asc (M.insert c x rm)) m)- where- Asc rm = M.lookupDefault (Asc M.empty) r m--------------------------------------------------------------------------------------- | A Little Unit Test -------------------------------------------------------------------------------------------------------------------------------------------_anns :: AnnTypes-_anns = i [(5, i [( 14, A1 { ident = "foo"- , ann = "int -> int"- , row = 5- , col = 14- })- ]- )- ,(9, i [( 22, A1 { ident = "map"- , ann = "(a -> b) -> [a] -> [b]"- , row = 9- , col = 22- })- ,( 28, A1 { ident = "xs"- , ann = "[b]"- , row = 9- , col = 28- })- ])- ]--i = Asc . M.fromList
src/Language/Haskell/Liquid/Bare.hs view
@@ -1,4 +1,4 @@--- | This module contains the functions that convert /from/ descriptions of +-- | This module contains the functions that convert /from/ descriptions of -- symbols, names and types (over freshly parsed /bare/ Strings), -- /to/ representations connected to GHC vars, names, and types. -- The actual /representations/ of bare and real (refinement) types are all@@ -10,4 +10,3 @@ ) where import Language.Haskell.Liquid.Bare.GhcSpec-
+ src/Language/Haskell/Liquid/Bare/Axiom.hs view
@@ -0,0 +1,232 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE TypeSynonymInstances #-}+{-# LANGUAGE FlexibleInstances #-}++module Language.Haskell.Liquid.Bare.Axiom (makeAxiom) where++import Prelude hiding (error)+import CoreSyn+import TyCon+import Id+import Name+import Type hiding (isFunTy)+import Var++import TypeRep++import Prelude hiding (mapM)+++import Control.Monad hiding (forM, mapM)+import Control.Monad.Except hiding (forM, mapM)+import Control.Monad.State hiding (forM, mapM)+import Data.Bifunctor+++++import Text.PrettyPrint.HughesPJ (text)+++import qualified Data.List as L+++import Language.Fixpoint.Misc+import Language.Fixpoint.Types (Symbol, symbol, symbolString)++import qualified Language.Fixpoint.Types as F+import Language.Haskell.Liquid.Types.RefType+import Language.Haskell.Liquid.Transforms.CoreToLogic++import Language.Haskell.Liquid.GHC.Misc (showPpr, sourcePosSrcSpan, dropModuleNames)+-- import Language.Haskell.Liquid.Types.RefType (generalize, ofType, uRType, typeSort)++import Language.Haskell.Liquid.Types hiding (binders)+++import qualified Language.Haskell.Liquid.Measure as Ms++import Language.Haskell.Liquid.Bare.Env++++++++++++makeAxiom :: F.TCEmb TyCon -> LogicMap -> [CoreBind] -> GhcSpec -> Ms.BareSpec -> LocSymbol+ -> BareM ((Symbol, Located SpecType), [(Var, Located SpecType)], [HAxiom])+makeAxiom tce lmap cbs _ _ x+ = case filter ((val x `elem`) . map (dropModuleNames . simplesymbol) . binders) cbs of+ (NonRec v def:_) -> do vts <- zipWithM (makeAxiomType tce lmap x) (reverse $ findAxiomNames x cbs) (defAxioms v def)+ insertAxiom v (val x)+ updateLMap lmap x x v+ updateLMap lmap (x{val = (symbol . showPpr . getName) v}) x v+ return ((val x, makeType v),+ (v, makeAssumeType v):vts, defAxioms v def)+ (Rec [(v, def)]:_) -> do vts <- zipWithM (makeAxiomType tce lmap x) (reverse $ findAxiomNames x cbs) (defAxioms v def)+ insertAxiom v (val x)+ updateLMap lmap x x v -- (reverse $ findAxiomNames x cbs) (defAxioms v def)+ updateLMap lmap (x{val = (symbol . showPpr . getName) v}) x v+ return ((val x, makeType v),+ ((v, makeAssumeType v): vts),+ defAxioms v def)+ _ -> throwError $ mkError "Cannot extract measure from haskell function"+ where++ --coreToDef' x v def = case runToLogic lmap mkError $ coreToDef x v def of+ -- Left l -> l :: [Def (RRType ()) DataCon] -- return l+ -- Right _ -> error $ "ERROR" -- throwError e++ mkError :: String -> Error+ mkError str = ErrHMeas (sourcePosSrcSpan $ loc x) (pprint $ val x) (text str)++ makeType v = x{val = ufType $ varType v}+ makeAssumeType v = x{val = axiomType x $ varType v}++++binders (NonRec x _) = [x]+binders (Rec xes) = fst <$> xes++updateLMap :: LogicMap -> LocSymbol -> LocSymbol -> Var -> BareM ()+updateLMap _ _ _ v | not (isFun $ varType v)+ = return ()+ where+ isFun (FunTy _ _) = True+ isFun (ForAllTy _ t) = isFun t+ isFun _ = False++updateLMap _ x y vv -- v axm@(Axiom (vv, _) xs _ lhs rhs)+ = insertLogicEnv (val x) ys (F.eApps (F.EVar $ val y) (F.EVar <$> ys))+ where+ nargs = dropWhile isClassType $ ty_args $ toRTypeRep $ ((ofType $ varType vv) :: RRType ())++ ys = zipWith (\i _ -> symbol (("x" ++ show i) :: String)) [1..] nargs++makeAxiomType :: F.TCEmb TyCon -> LogicMap -> LocSymbol -> Var -> HAxiom -> BareM (Var, Located SpecType)+makeAxiomType tce lmap x v (Axiom _ xs _ lhs rhs)+ = do foldM (\lm x -> (updateLMap lm (dummyLoc $ F.symbol x) (dummyLoc $ F.symbol x) x >> (logicEnv <$> get))) lmap xs+ return (v, x{val = t})+ where+ t = fromRTypeRep $ tr{ty_res = res, ty_binds = symbol <$> xs}+ tt = ofType $ varType v+ tr = toRTypeRep tt+ res = ty_res tr `strengthen` MkUReft ref mempty mempty++ llhs = case runToLogic tce lmap' mkErr (coreToLogic lhs) of+ Left e -> e+ Right e -> panic Nothing $ show e+ lrhs = case runToLogic tce lmap' mkErr (coreToLogic rhs) of+ Left e -> e+ Right e -> panic Nothing $ show e+ ref = F.Reft (F.vv_, F.PAtom F.Eq llhs lrhs)++ -- nargs = dropWhile isClassType $ ty_args $ toRTypeRep $ ((ofType $ varType vv) :: RRType ())+++ lmap' = lmap -- M.insert v' (LMap v' ys runFun) lmap++ mkErr s = ErrHMeas (sourcePosSrcSpan $ loc x) (pprint $ val x) (text s)++ --mkBinds (_:xs) (v:vs) = v:mkBinds xs vs+ --mkBinds _ _ = []++ -- v' = val x -- symbol $ showPpr $ getName vv+++++findAxiomNames x (NonRec v _ :cbs) | isAxiomName x v = v:findAxiomNames x cbs+findAxiomNames x (Rec [(v,_)]:cbs) | isAxiomName x v = v:findAxiomNames x cbs+findAxiomNames x (_:cbs) = findAxiomNames x cbs+findAxiomNames _ [] = []++isAxiomName x v =+ (("axiom_" ++ symbolString (val x)) `L.isPrefixOf`) (symbolString $ dropModuleNames $ simplesymbol v)++defAxioms :: Var -> CoreExpr -> [Axiom Var Kind (Expr Var)]+defAxioms v e = go [] $ simplify e+ where+ go bs (Tick _ e) = go bs e+ go bs (Lam x e) | isTyVar x = go bs e+ go bs (Lam x e) | isClassPred (varType x) = go bs e+ go bs (Lam x e) = go (bs++[x]) e+ go bs (Case (Var x) _ _ alts) = goalt x bs <$> alts+ go bs e = [Axiom (v, Nothing) bs (varType <$> bs) (foldl App (Var v) (Var <$> bs)) e]++ goalt x bs (DataAlt c, ys, e) = let vs = [b | b<- bs , b /= x] ++ ys in+ Axiom (v, Just c) vs (varType <$> vs) (mkApp bs x c ys) $ simplify e+ goalt _ _ (LitAlt _, _, _) = todo Nothing "defAxioms: goalt Lit"+ goalt _ _ (DEFAULT, _, _) = todo Nothing "defAxioms: goalt Def"++ mkApp bs x c ys = foldl App (Var v) ((\y -> if y == x then (mkConApp c (Var <$> ys)) else Var y)<$> bs)+++class Simplifiable a where+ simplify :: a -> a++instance Simplifiable CoreExpr where+ simplify (Tick _ e) = simplify e+ simplify (Lam x e) | isTyVar x = simplify e+ simplify (Lam x e) | isClassPred (varType x) = simplify e+ simplify (Lam x e) = Lam x $ simplify e+ simplify (Let b e) = unANF (simplify b) (simplify e)+ simplify (Case e v t alts) = Case e v t alts+ simplify (Cast e _) = simplify e+ simplify (App e (Type _)) = simplify e+ simplify (App e (Var x)) | isClassPred (varType x) = simplify e+ simplify (App f e) = App (simplify f) (simplify e)+ simplify e@(Var _) = e+ simplify e = todo Nothing ("simplify" ++ showPpr e)++unANF (NonRec x ex) e | L.isPrefixOf "lq_anf" (show x)+ = subst (x, ex) e+unANF b e = Let b e++instance Simplifiable CoreBind where+ simplify (NonRec x e) = NonRec x $ simplify e+ simplify (Rec xes) = Rec (second simplify <$> xes)+++class Subable a where+ subst :: (Var, CoreExpr) -> a -> a++instance Subable CoreExpr where+ subst (x, ex) (Var y) | x == y = ex+ | otherwise = Var y+ subst su (App f e) = App (subst su f) (subst su e)+ subst su (Lam x e) = Lam x (subst su e)+ subst _ _ = todo Nothing "Subable"++-- | Specification for Haskell function+axiomType :: LocSymbol -> Type -> SpecType+axiomType s τ = fromRTypeRep $ t{ty_res = res, ty_binds = xs}+ where+ t = toRTypeRep $ ofType τ+ ys = dropWhile isClassType $ ty_args t+ xs = (\i -> symbol ("x" ++ show i)) <$> [1..(length ys)]+ x = F.vv_++ res = ty_res t `strengthen` MkUReft ref mempty mempty++ ref = F.Reft (x, F.PAtom F.Eq (F.EVar x) (mkApp xs))++ mkApp = F.mkEApp s . map F.EVar+++-- | Type for uninterpreted function that approximated Haskell function into logic+ufType :: (F.Reftable r) => Type -> RRType r+ufType τ = fromRTypeRep $ t{ty_args = args, ty_binds = xs, ty_refts = rs}+ where+ t = toRTypeRep $ ofType τ+ (args, xs, rs) = unzip3 $ dropWhile (isClassType . fst3) $ zip3 (ty_args t) (ty_binds t) (ty_refts t)+++simplesymbol :: CoreBndr -> Symbol+simplesymbol = symbol . getName
src/Language/Haskell/Liquid/Bare/Check.hs view
@@ -11,31 +11,38 @@ import Debug.Trace ++import Prelude hiding (error) import DataCon import Name (getSrcSpan) import TyCon+import Id import Var -import Control.Applicative ((<$>), (<|>))+import Control.Applicative ((<|>)) import Control.Arrow ((&&&))-import Control.Monad.Writer+ import Data.Maybe+import Data.Function (on) import Text.PrettyPrint.HughesPJ import qualified Data.List as L import qualified Data.HashMap.Strict as M -import Language.Fixpoint.Misc (applyNonNull, group, mapSnd, errorstar, safeHead)-import Language.Fixpoint.Sort (checkSorted, checkSortedReftFull, checkSortFull)-import Language.Fixpoint.Types hiding (R)+import Language.Fixpoint.Misc (applyNonNull, group, safeHead)+import Language.Fixpoint.SortCheck (checkSorted, checkSortedReftFull, checkSortFull)+import Language.Fixpoint.Types hiding (Error, R) -import Language.Haskell.Liquid.GhcMisc (realTcArity, showPpr, sourcePosSrcSpan)-import Language.Haskell.Liquid.Misc (firstDuplicate, snd4)-import Language.Haskell.Liquid.PredType (pvarRType, wiredSortedSyms)-import Language.Haskell.Liquid.PrettyPrint (pprintSymbol)-import Language.Haskell.Liquid.RefType (classBinds, ofType, rTypeSort, rTypeSortedReft, subsTyVars_meet, toType)+import Language.Haskell.Liquid.GHC.Misc (realTcArity, showPpr, fSrcSpan, sourcePosSrcSpan)+import Language.Haskell.Liquid.Misc (snd4, mapSnd)+import Language.Haskell.Liquid.Types.PredType (pvarRType)+import Language.Haskell.Liquid.Types.PrettyPrint (pprintSymbol)+import Language.Haskell.Liquid.Types.RefType (classBinds, ofType, rTypeSort, rTypeSortedReft, subsTyVars_meet, toType) import Language.Haskell.Liquid.Types+import Language.Haskell.Liquid.WiredIn ++ import qualified Language.Haskell.Liquid.Measure as Ms import Language.Haskell.Liquid.Bare.DataType (dataConSpec)@@ -53,33 +60,47 @@ checkGhcSpec specs env sp = applyNonNull (Right sp) Left errors where- errors = mapMaybe (checkBind "constructor" emb tcEnv env) (dcons sp)- ++ mapMaybe (checkBind "measure" emb tcEnv env) (meas sp)+ errors = mapMaybe (checkBind "constructor" emb tcEnv env) (dcons sp)+ ++ mapMaybe (checkBind "measure" emb tcEnv env) (meas sp)+ ++ mapMaybe (checkBind "assumed type" emb tcEnv env) (asmSigs sp)+ ++ mapMaybe (checkBind "class method" emb tcEnv env) (clsSigs sp) ++ mapMaybe (checkInv emb tcEnv env) (invariants sp)- ++ (checkIAl emb tcEnv env) (ialiases sp)+ ++ checkIAl emb tcEnv env (ialiases sp) ++ checkMeasures emb env ms+ ++ checkClassMeasures (measures sp) ++ mapMaybe checkMismatch sigs ++ checkDuplicate (tySigs sp)+ ++ checkQualifiers env (qualifiers sp) ++ checkDuplicate (asmSigs sp) ++ checkDupIntersect (tySigs sp) (asmSigs sp) ++ checkRTAliases "Type Alias" env tAliases- ++ checkRTAliases "Pred Alias" env pAliases+ ++ checkRTAliases "Pred Alias" env eAliases ++ checkDuplicateFieldNames (dconsP sp) ++ checkRefinedClasses (concatMap (Ms.classes . snd) specs) (concatMap (Ms.rinstance . snd) specs) tAliases = concat [Ms.aliases sp | (_, sp) <- specs]- pAliases = concat [Ms.paliases sp | (_, sp) <- specs]- dcons spec = [(v, Loc l l' t) | (v,t) <- dataConSpec (dconsP spec)- | (_,dcp) <- dconsP spec- , let l = dc_loc dcp- , let l' = dc_locE dcp+ eAliases = concat [Ms.ealiases sp | (_, sp) <- specs]+ dcons spec = [(v, Loc l l' t) | (v, t) <- dataConSpec (dconsP spec)+ | (_, dcp) <- dconsP spec+ , let l = dc_loc dcp+ , let l' = dc_locE dcp ] emb = tcEmbeds sp tcEnv = tyconEnv sp ms = measures sp+ clsSigs sp = [ (v, t) | (v, t) <- tySigs sp, isJust (isClassOpId_maybe v) ] sigs = tySigs sp ++ asmSigs sp ++checkQualifiers :: SEnv SortedReft -> [Qualifier] -> [Error]+checkQualifiers = mapMaybe . checkQualifier++checkQualifier :: SEnv SortedReft -> Qualifier -> Maybe Error+checkQualifier env q = mkE <$> checkSortFull γ boolSort (q_body q)+ where γ = foldl (\e (x, s) -> insertSEnv x (RR s mempty) e) env (q_params q ++ wiredSortedSyms)+ mkE = ErrBadQual (sourcePosSrcSpan $ q_pos q) (pprint $ q_name q)+ checkRefinedClasses :: [RClass BareType] -> [RInstance BareType] -> [Error] checkRefinedClasses definitions instances = mkError <$> duplicates@@ -101,17 +122,24 @@ = sourcePosSrcSpan . loc . riclass &&& pprint . ritype checkDuplicateFieldNames :: [(DataCon, DataConP)] -> [Error]-checkDuplicateFieldNames = catMaybes . map go+checkDuplicateFieldNames = mapMaybe go where- go (d, dts) = checkNoDups (dc_loc dts) d (fst <$> tyArgs dts)- checkNoDups l d xs = mkErr l d <$> firstDuplicate xs+ go (d, dts) = checkNoDups (dc_loc dts) d (fst <$> tyArgs dts)+ checkNoDups l d xs = mkErr l d <$> firstDuplicate xs mkErr l d x = ErrBadData (sourcePosSrcSpan l) (pprint d) (text "Multiple declarations of record selector" <+> pprintSymbol x) +firstDuplicate :: Ord a => [a] -> Maybe a+firstDuplicate = go . L.sort+ where+ go (y:x:xs) | x == y = Just x+ | otherwise = go (x:xs)+ go _ = Nothing+ checkInv :: TCEmb TyCon -> TCEnv -> SEnv SortedReft -> Located SpecType -> Maybe Error-checkInv emb tcEnv env t = checkTy err emb tcEnv env (val t)+checkInv emb tcEnv env t = checkTy err emb tcEnv env t where err = ErrInvt (sourcePosSrcSpan $ loc t) (val t) @@ -120,13 +148,13 @@ checkIAlOne emb tcEnv env (t1, t2) = checkEq : (tcheck <$> [t1, t2]) where- tcheck t = checkTy (err t) emb tcEnv env (val t)+ tcheck t = checkTy (err t) emb tcEnv env t err t = ErrIAl (sourcePosSrcSpan $ loc t) (val t) t1' :: RSort t1' = toRSort $ val t1 t2' :: RSort t2' = toRSort $ val t2- checkEq = if (t1' == t2') then Nothing else Just errmis+ checkEq = if t1' == t2' then Nothing else Just errmis errmis = ErrIAlMis (sourcePosSrcSpan $ loc t1) (val t1) (val t2) emsg emsg = pprint t1 <+> text "does not match with" <+> pprint t2 @@ -137,9 +165,9 @@ err1s = checkDuplicateRTAlias msg as checkBind :: (PPrint v) => String -> TCEmb TyCon -> TCEnv -> SEnv SortedReft -> (v, Located SpecType) -> Maybe Error-checkBind s emb tcEnv env (v, Loc l _ t) = checkTy msg emb tcEnv env' t+checkBind s emb tcEnv env (v, t) = checkTy msg emb tcEnv env' t where- msg = ErrTySpec (sourcePosSrcSpan l) (text s <+> pprint v) t+ msg = ErrTySpec (fSrcSpan t) (text s <+> pprint v) (val t) env' = foldl (\e (x, s) -> insertSEnv x (RR s mempty) e) env wiredSortedSyms checkTerminationExpr :: (Eq v, PPrint v) => TCEmb TyCon -> SEnv SortedReft -> (v, Located SpecType, [Expr])-> Maybe Error@@ -154,20 +182,20 @@ xts = concatMap mkClass $ zip (ty_binds trep) (ty_args trep) trep = toRTypeRep t - mkClass (_, (RApp c ts _ _)) | isClass c = classBinds (rRCls c ts)- mkClass (x, t) = [(x, rSort t)]+ mkClass (_, RApp c ts _ _) | isClass c = classBinds (rRCls c ts)+ mkClass (x, t) = [(x, rSort t)] rSort = rTypeSortedReft emb cmpZero = PAtom Le $ expr (0 :: Int) -- zero -checkTy :: (Doc -> Error) -> TCEmb TyCon -> TCEnv -> SEnv SortedReft -> SpecType -> Maybe Error-checkTy mkE emb tcEnv env t = mkE <$> checkRType emb env (txRefSort tcEnv emb t)+checkTy :: (Doc -> Error) -> TCEmb TyCon -> TCEnv -> SEnv SortedReft -> Located SpecType -> Maybe Error+checkTy mkE emb tcEnv env t = mkE <$> checkRType emb env (val $ txRefSort tcEnv emb t) checkDupIntersect :: [(Var, Located SpecType)] -> [(Var, Located SpecType)] -> [Error] checkDupIntersect xts mxts = concatMap mkWrn dups where mkWrn (x, t) = pprWrn x (sourcePosSrcSpan $ loc t)- dups = L.intersectBy (\x y -> (fst x == fst y)) mxts xts+ dups = L.intersectBy ((==) `on` fst) mxts xts pprWrn v l = trace ("WARNING: Assume Overwrites Specifications for "++ show v ++ " : " ++ showPpr l) [] checkDuplicate :: [(Var, Located SpecType)] -> [Error]@@ -183,9 +211,8 @@ (text s) (pprint $ rtName x) (sourcePosSrcSpan . rtPos <$> xs)- mkErr [] = error "mkError: called on empty list"- dups = [z | z@(_:_:_) <- L.groupBy (\x y -> rtName x == rtName y) tas]-+ mkErr [] = panic Nothing "mkError: called on empty list"+ dups = [z | z@(_:_:_) <- L.groupBy ((==) `on` rtName) tas] checkMismatch :: (Var, Located SpecType) -> Maybe Error@@ -200,7 +227,12 @@ rhs :: RSort = ofType $ varType x errTypeMismatch :: Var -> Located SpecType -> Error-errTypeMismatch x t = ErrMismatch (sourcePosSrcSpan $ loc t) (pprint x) (varType x) (toType $ val t)+errTypeMismatch x t = ErrMismatch lqSp (pprint x) d1 d2 hsSp+ where+ d1 = pprint $ varType x+ d2 = pprint $ toType $ val t+ lqSp = sourcePosSrcSpan $ loc t+ hsSp = getSrcSpan x ------------------------------------------------------------------------------------------------ -- | @checkRType@ determines if a type is malformed in a given environment ---------------------@@ -208,15 +240,16 @@ checkRType :: (PPrint r, Reftable r) => TCEmb TyCon -> SEnv SortedReft -> RRType (UReft r) -> Maybe Doc ------------------------------------------------------------------------------------------------ -checkRType emb env t = checkAppTys t <|> checkFunRefs t <|> checkAbstractRefs t <|> efoldReft cb (rTypeSortedReft emb) f insertPEnv env Nothing t+checkRType emb env t = checkAppTys t+ <|> checkAbstractRefs t+ <|> efoldReft cb (rTypeSortedReft emb) f insertPEnv env Nothing t where- cb c ts = classBinds (rRCls c ts)- f env me r err = err <|> checkReft env emb me r- insertPEnv p γ = insertsSEnv γ (mapSnd (rTypeSortedReft emb) <$> pbinds p)- pbinds p = (pname p, pvarRType p :: RSort)- : [(x, t) | (t, x, _) <- pargs p]+ cb c ts = classBinds (rRCls c ts)+ f env me r err = err <|> checkReft env emb me r+ insertPEnv p γ = insertsSEnv γ (mapSnd (rTypeSortedReft emb) <$> pbinds p)+ pbinds p = (pname p, pvarRType p :: RSort) : [(x, tx) | (tx, x, _) <- pargs p] -checkAppTys t = go t+checkAppTys = go where go (RAllT _ t) = go t go (RAllP _ t) = go t@@ -241,9 +274,10 @@ <+> text "arguments" | otherwise = Nothing- where expectedArity = realTcArity tc-+ where+ expectedArity = realTcArity tc +{- checkFunRefs t = go t where go (RAllT _ t) = go t@@ -258,10 +292,9 @@ go (RExprArg _) = Nothing go (RHole _) = Nothing go (RFun _ t1 t2 r)- | isTauto r- = go t1 <|> go t2- | otherwise- = Just $ text "Function types cannot have refinements:" <+> (pprint r)+ | isTauto r = go t1 <|> go t2+ | otherwise = Just $ text "Function types cannot have refinements:" <+> (pprint r)+-} checkAbstractRefs t = go t where@@ -282,27 +315,27 @@ go' c rs = foldl (\acc (x, y) -> acc <|> checkOne' x y) Nothing (zip rs (rTyConPVs c)) - checkOne' (RProp xs t) p- | pvType p /= toRSort t- = Just $ text "Unexpected Sort in" <+> pprint p+ checkOne' (RProp xs (RHole _)) p | or [s1 /= s2 | ((_, s1), (s2, _, _)) <- zip xs (pargs p)] = Just $ text "Wrong Arguments in" <+> pprint p | length xs /= length (pargs p) = Just $ text "Wrong Number of Arguments in" <+> pprint p | otherwise- = go t- checkOne' (RPropP xs _) p+ = Nothing+ checkOne' (RProp xs t) p+ | pvType p /= toRSort t+ = Just $ text "Unexpected Sort in" <+> pprint p | or [s1 /= s2 | ((_, s1), (s2, _, _)) <- zip xs (pargs p)] = Just $ text "Wrong Arguments in" <+> pprint p | length xs /= length (pargs p) = Just $ text "Wrong Number of Arguments in" <+> pprint p | otherwise- = Nothing- checkOne' _ _ = errorstar "This cannot happen"+ = go t + efold f = foldl (\acc x -> acc <|> f x) Nothing - check s (U _ (Pr ps) _) = foldl (\acc pp -> acc <|> checkOne s pp) Nothing ps+ check s (MkUReft _ (Pr ps) _) = foldl (\acc pp -> acc <|> checkOne s pp) Nothing ps checkOne s p | pvType' p /= s = Just $ text "Incorrect Sort:\n\t"@@ -355,15 +388,15 @@ checkMeasure emb γ (M name@(Loc src _ n) sort body) = [txerror e | Just e <- checkMBody γ emb name sort <$> body] where- txerror = ErrMeas (sourcePosSrcSpan src) n+ txerror = ErrMeas (sourcePosSrcSpan src) (pprint n) checkMBody γ emb _ sort (Def _ as c _ bs body) = checkMBody' emb sort γ' body- where + where γ' = L.foldl' (\γ (x, t) -> insertSEnv x t γ) γ (ats ++ xts) ats = (mapSnd (rTypeSortedReft emb) <$> as) xts = zip (fst <$> bs) $ rTypeSortedReft emb . subsTyVars_meet su <$> ty_args trep trep = toRTypeRep ct- su = checkMBodyUnify (ty_res trep) (last txs) + su = checkMBodyUnify (ty_res trep) (last txs) txs = snd4 $ bkArrowDeep sort ct = ofType $ dataConUserType c :: SpecType @@ -375,9 +408,24 @@ checkMBody' emb sort γ body = case body of E e -> checkSortFull γ (rTypeSort emb sort') e- P p -> checkSortFull γ propSort p- R s p -> checkSortFull (insertSEnv s sty γ) propSort p+ P p -> checkSortFull γ boolSort p+ R s p -> checkSortFull (insertSEnv s sty γ) boolSort p where -- psort = FApp propFTyCon [] sty = rTypeSortedReft emb sort' sort' = ty_res $ toRTypeRep sort++checkClassMeasures :: [Measure SpecType DataCon] -> [Error]+checkClassMeasures ms = mapMaybe checkOne byTyCon+ where+ byName = L.groupBy ((==) `on` (val.name)) ms++ byTyCon = concatMap (L.groupBy ((==) `on` (dataConTyCon . ctor . head . eqns)))+ byName++ checkOne [] = impossible Nothing "checkClassMeasures.checkOne on empty measure group"+ checkOne [_] = Nothing+ checkOne (m:ms) = Just (ErrDupMeas (sourcePosSrcSpan (loc (name m)))+ (pprint (val (name m)))+ (pprint ((dataConTyCon . ctor . head . eqns) m))+ (map (sourcePosSrcSpan.loc.name) (m:ms)))
src/Language/Haskell/Liquid/Bare/DataType.hs view
@@ -1,33 +1,37 @@-{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE TupleSections #-} module Language.Haskell.Liquid.Bare.DataType ( makeConTypes , makeTyConEmbeds-+ , makeRecordSelectorSigs , dataConSpec , meetDataConSpec ) where +import Prelude hiding (error) import DataCon import TyCon import Var+import SrcLoc (SrcSpan)+import Name (getSrcSpan) -import Control.Applicative ((<$>)) import Data.Maybe-import Data.Monoid + import qualified Data.List as L import qualified Data.HashMap.Strict as M -import Language.Fixpoint.Misc (errorstar, mapSnd)-import Language.Fixpoint.Types (Symbol, TCEmb, meet)+import Language.Fixpoint.Types (Symbol, TCEmb, mkSubst, Expr(..), Brel(..), subst) -import Language.Haskell.Liquid.GhcMisc (symbolTyVar)-import Language.Haskell.Liquid.PredType (dataConPSpecType)-import Language.Haskell.Liquid.RefType (mkDataConIdsTy, ofType, rApp, rVar, uPVar)+import Language.Haskell.Liquid.GHC.Misc (sourcePos2SrcSpan, symbolTyVar)+import Language.Haskell.Liquid.Types.PredType (dataConPSpecType)+import Language.Haskell.Liquid.Types.RefType (mkDataConIdsTy, ofType, rApp, rVar, strengthen, uPVar, uReft) import Language.Haskell.Liquid.Types-import Language.Haskell.Liquid.Variance+import Language.Haskell.Liquid.Types.Meet+import Language.Haskell.Liquid.Misc (mapSnd)+import Language.Haskell.Liquid.Types.Variance import Language.Haskell.Liquid.WiredIn import qualified Language.Haskell.Liquid.Measure as Ms@@ -36,6 +40,8 @@ import Language.Haskell.Liquid.Bare.Lookup import Language.Haskell.Liquid.Bare.OfType +-- import Debug.Trace+ ----------------------------------------------------------------------- -- Bare Predicate: DataCon Definitions -------------------------------- -----------------------------------------------------------------------@@ -54,17 +60,29 @@ merge [] vs = ((Nothing,) . Just) <$> vs merge ds [] = ((,Nothing) . Just) <$> ds -+dataConSpec :: [(DataCon, DataConP)] -> [(Var, SpecType)]+dataConSpec x = [ (v, t) | (v, (_, t)) <- dataConSpec' x ] -dataConSpec :: [(DataCon, DataConP)]-> [(Var, (RType RTyCon RTyVar RReft))]-dataConSpec dcs = concatMap mkDataConIdsTy [(dc, dataConPSpecType dc t) | (dc, t) <- dcs]+dataConSpec' :: [(DataCon, DataConP)] -> [(Var, (SrcSpan, SpecType))]+dataConSpec' dcs = concatMap tx dcs+ where+ tx (a, b) = [ (x, (sspan b, t)) | (x, t) <- mkDataConIdsTy (a, dataConPSpecType a b) ]+ sspan z = sourcePos2SrcSpan (dc_loc z) (dc_locE z) -meetDataConSpec xts dcs = M.toList $ L.foldl' upd dcm xts+meetDataConSpec :: [(Var, SpecType)] -> [(DataCon, DataConP)] -> [(Var, SpecType)]+meetDataConSpec xts dcs = M.toList $ snd <$> L.foldl' upd dcm0 xts where- dcm = M.fromList $ dataConSpec dcs- upd dcm (x, t) = M.insert x (maybe t (meet t) (M.lookup x dcm)) dcm+ dcm0 = M.fromList $ dataConSpec' dcs+ meetX x t (sp', t') = meetVarTypes (pprint x) (getSrcSpan x, t) (sp', t')+ upd dcm (x, t) = M.insert x (getSrcSpan x, tx') dcm+ where+ tx' = maybe t (meetX x t) (M.lookup x dcm) -ofBDataDecl :: Maybe DataDecl -> (Maybe (LocSymbol, [Variance])) -> BareM ((TyCon, TyConP), [(DataCon, Located DataConP)])++-- FIXME: ES: why the maybes?+ofBDataDecl :: Maybe DataDecl+ -> (Maybe (LocSymbol, [Variance]))+ -> BareM ((TyCon, TyConP), [(DataCon, Located DataConP)]) ofBDataDecl (Just (D tc as ps ls cts _ sfun)) maybe_invariance_info = do πs <- mapM ofBPVar ps tc' <- lookupGhcTyCon tc@@ -97,7 +115,7 @@ (tcov, tcontr) = (is, []) ofBDataDecl Nothing Nothing- = errorstar $ "Bare.DataType.ofBDataDecl called on invalid inputs"+ = panic Nothing "Bare.DataType.ofBDataDecl called on invalid inputs" getPsSig m pos (RAllT _ t) = getPsSig m pos t@@ -113,21 +131,20 @@ getPsSig m pos (RHole r) = addps m pos r getPsSig _ _ z- = error $ "getPsSig" ++ show z+ = panic Nothing $ "getPsSig" ++ show z -getPsSigPs m pos (RPropP _ r) = addps m pos r-getPsSigPs m pos (RProp _ t) = getPsSig m pos t-getPsSigPs _ _ (RHProp _ _) = errorstar "TODO:EFFECTS:getPsSigPs"+getPsSigPs m pos (RProp _ (RHole r)) = addps m pos r+getPsSigPs m pos (RProp _ t) = getPsSig m pos t -addps m pos (U _ ps _) = (flip (,)) pos . f <$> pvars ps- where f = fromMaybe (error "Bare.addPs: notfound") . (`L.lookup` m) . uPVar+addps m pos (MkUReft _ ps _) = (flip (,)) pos . f <$> pvars ps+ where f = fromMaybe (panic Nothing "Bare.addPs: notfound") . (`L.lookup` m) . uPVar -- TODO:EFFECTS:ofBDataCon ofBDataCon l l' tc αs ps ls πs (c, xts) = do c' <- lookupGhcDataCon c ts' <- mapM (mkSpecType' l ps) ts let cs = map ofType (dataConStupidTheta c')- let t0 = rApp tc rs (RPropP [] . pdVarReft <$> πs) mempty+ let t0 = rApp tc rs (rPropP [] . pdVarReft <$> πs) mempty return $ (c', DataConP l αs πs ls cs (reverse (zip xs ts')) t0 l') where (xs, ts) = unzip xts@@ -141,3 +158,34 @@ makeTyConEmbeds' z = M.fromList <$> mapM tx (M.toList z) where tx (c, y) = (, y) <$> lookupGhcTyCon c++makeRecordSelectorSigs :: [(DataCon, Located DataConP)] -> BareM [(Var, Located SpecType)]+makeRecordSelectorSigs dcs = concat <$> mapM makeOne dcs+ where+ makeOne (dc, Loc l l' dcp)+ | null (dataConFieldLabels dc)+ = return []+ | otherwise = do+ fs <- mapM lookupGhcVar (dataConFieldLabels dc)+ return (fs `zip` ts)+ where+ ts = [ Loc l l' (mkArrow (freeTyVars dcp) [] (freeLabels dcp)+ [(z, res, mempty)]+ (dropPreds (subst su t `strengthen` mt)))+ | (x, t) <- reverse args -- NOTE: the reverse here is correct+ , not (isFunTy t) -- NOTE: we only have measures for non-function fields+ , let vv = rTypeValueVar t+ -- the measure singleton refinement, eg `v = getBar foo`+ , let mt = uReft (vv, PAtom Eq (EVar vv) (EApp (EVar x) (EVar z)))+ ]++ su = mkSubst $ [ (x, EApp (EVar x) (EVar z)) | x <- xs ]+ args = tyArgs dcp+ xs = map fst args+ z = "lq$recSel"+ res = dropPreds (tyRes dcp)++ -- FIXME: this is clearly imprecise, but the preds in the DataConP seem+ -- to be malformed. If we leave them in, tests/pos/kmp.hs fails with+ -- a malformed predicate application. Niki, help!!+ dropPreds = fmap (\(MkUReft r _ps ss) -> MkUReft r mempty ss)
src/Language/Haskell/Liquid/Bare/Env.hs view
@@ -13,28 +13,32 @@ , withVArgs , setRTAlias- , setRPAlias , setREAlias , execBare++ , insertLogicEnv+ , insertAxiom ) where +import Prelude hiding (error) import HscTypes import TyCon import Var -import Control.Monad.Error hiding (Error)+import Control.Monad.Except import Control.Monad.State import Control.Monad.Writer import qualified Control.Exception as Ex import qualified Data.HashMap.Strict as M -import Language.Fixpoint.Types (Expr(..), Symbol, symbol, Pred) -import Language.Haskell.Liquid.Errors ()+import Language.Fixpoint.Types (Expr(..), Symbol, symbol)++import Language.Haskell.Liquid.UX.Errors () import Language.Haskell.Liquid.Types-import Language.Haskell.Liquid.Bounds+import Language.Haskell.Liquid.Types.Bounds -----------------------------------------------------------------------------------@@ -42,7 +46,7 @@ ----------------------------------------------------------------------------------- -- FIXME: don't use WriterT [], very slow-type BareM = WriterT [Warn] (ErrorT Error (StateT BareEnv IO))+type BareM = WriterT [Warn] (ExceptT Error (StateT BareEnv IO)) type Warn = String @@ -51,7 +55,7 @@ type InlnEnv = M.HashMap Symbol TInline data TInline = TI { tiargs :: [Symbol]- , tibody :: Either Pred Expr+ , tibody :: Expr } deriving (Show) @@ -68,7 +72,12 @@ +insertLogicEnv x ys e+ = modify $ \be -> be {logicEnv = (logicEnv be) {logic_map = M.insert x (LMap x ys e) $ logic_map $ logicEnv be}} +insertAxiom x s+ = modify $ \be -> be {logicEnv = (logicEnv be){axiom_map = M.insert x s $ axiom_map $ logicEnv be}}+ setModule m b = b { modName = m } inModule m act = do@@ -91,8 +100,6 @@ setRTAlias s a = modify $ \b -> b { rtEnv = mapRT (M.insert s a) $ rtEnv b } -setRPAlias s a =- modify $ \b -> b { rtEnv = mapRP (M.insert s a) $ rtEnv b } setREAlias s a = modify $ \b -> b { rtEnv = mapRE (M.insert s a) $ rtEnv b }@@ -101,7 +108,7 @@ execBare :: BareM a -> BareEnv -> IO (Either Error a) ------------------------------------------------------------------ execBare act benv =- do z <- evalStateT (runErrorT (runWriterT act)) benv `Ex.catch` (return . Left)+ do z <- evalStateT (runExceptT (runWriterT act)) benv `Ex.catch` (return . Left) case z of Left s -> return $ Left s Right (x, ws) -> do forM_ ws $ putStrLn . ("WARNING: " ++)
src/Language/Haskell/Liquid/Bare/Existential.hs view
@@ -2,17 +2,17 @@ txExpToBind ) where -import Control.Applicative ((<$>)) import Control.Monad.State import Data.Char import qualified Data.HashMap.Strict as M -import Language.Fixpoint.Misc (errorstar, fst3)-import Language.Fixpoint.Names (headSym)+import Prelude hiding (error)+import Language.Fixpoint.Misc (fst3)+import Language.Fixpoint.Types.Names (headSym) import Language.Fixpoint.Types (Expr(..), Symbol, symbol, exprReft) -import Language.Haskell.Liquid.RefType (strengthen, uTop)+import Language.Haskell.Liquid.Types.RefType (strengthen, uTop) import Language.Haskell.Liquid.Types -------------------------------------------------------------------------------@@ -63,10 +63,10 @@ = return t expToBindReft :: SpecProp -> State ExSt SpecProp+expToBindReft (RProp s (RHole r)) = rPropP s <$> expToBindRef r expToBindReft (RProp s t) = RProp s <$> expToBindT t-expToBindReft (RPropP s r) = RPropP s <$> expToBindRef r-expToBindReft (RHProp _ _) = errorstar "TODO:EFFECTS:expToBindReft" + getBinds :: State ExSt (M.HashMap Symbol (RSort, Expr)) getBinds = do bds <- emap <$> get@@ -77,11 +77,11 @@ addExist t x (tx, e) = REx x t' t where t' = (ofRSort tx) `strengthen` uTop r- r = exprReft e + r = exprReft e expToBindRef :: UReft r -> State ExSt (UReft r)-expToBindRef (U r (Pr p) l)- = mapM expToBind p >>= return . (\p -> U r p l). Pr+expToBindRef (MkUReft r (Pr p) l)+ = mapM expToBind p >>= return . (\p -> MkUReft r p l). Pr expToBind :: UsedPVar -> State ExSt UsedPVar expToBind p
src/Language/Haskell/Liquid/Bare/Expand.hs view
@@ -2,21 +2,21 @@ module Language.Haskell.Liquid.Bare.Expand ( expandReft- , expandPred , expandExpr ) where -import Control.Applicative ((<$>), (<*>))-import Control.Monad.Reader hiding (forM)+import Prelude hiding (error)+ import Control.Monad.State hiding (forM) import qualified Data.HashMap.Strict as M -import Language.Fixpoint.Types (Expr(..), Pred(..), Refa(..), Reft(..), mkSubst, subst)+import Language.Fixpoint.Types (Expr(..), Reft(..), mkSubst, subst, eApps, splitEApp) import Language.Haskell.Liquid.Misc (safeZipWithError) import Language.Haskell.Liquid.Types + import Language.Haskell.Liquid.Bare.Env --------------------------------------------------------------------------------@@ -24,107 +24,91 @@ -------------------------------------------------------------------------------- expandReft :: RReft -> BareM RReft-expandReft = txPredReft expandPred expandExpr--txPredReft :: (Pred -> BareM Pred) -> (Expr -> BareM Expr) -> RReft -> BareM RReft-txPredReft f fe u = (\r -> u {ur_reft = r}) <$> txPredReft' (ur_reft u)- where- txPredReft' (Reft (v, ra)) = Reft . (v,) <$> txPredRefa ra- txPredRefa (Refa p) = Refa <$> (f <=< mapPredM fe) p+expandReft = txPredReft expandExpr -mapPredM :: (Expr -> BareM Expr) -> Pred -> BareM Pred-mapPredM f = go+txPredReft :: (Expr -> BareM Expr) -> RReft -> BareM RReft+txPredReft f u = (\r -> u {ur_reft = r}) <$> txPredReft' (ur_reft u) where- go PTrue = return PTrue- go PFalse = return PFalse- go p@(PKVar _ _) = return p- go (PAnd ps) = PAnd <$> mapM go ps- go (POr ps) = POr <$> mapM go ps- go (PNot p) = PNot <$> go p- go (PImp p q) = PImp <$> go p <*> go q- go (PIff p q) = PIff <$> go p <*> go q- go (PBexp e) = PBexp <$> f e- go (PAtom b e1 e2) = PAtom b <$> f e1 <*> f e2- go (PAll xs p) = PAll xs <$> go p- -- go (PExist xs p) = PExist xs <$> go p- go PTop = return PTop+ txPredReft' (Reft (v, ra)) = Reft . (v,) <$> f ra ----------------------------------------------------------------------------------- Expand Preds ----------------------------------------------------------------+-- Expand Exprs ---------------------------------------------------------------- -------------------------------------------------------------------------------- -expandPred :: Pred -> BareM Pred -expandPred p@(PBexp (EApp (Loc l _ f') es))- = do env <- gets (predAliases.rtEnv)- return $- case M.lookup f' env of- Just rp ->- expandApp l rp es- Nothing ->- p-expandPred p@(PBexp _)- = return p-expandPred (PAnd ps)- = PAnd <$> mapM expandPred ps-expandPred (POr ps)- = POr <$> mapM expandPred ps-expandPred (PNot p)- = PNot <$> expandPred p-expandPred (PImp p q)- = PImp <$> expandPred p <*> expandPred q-expandPred (PIff p q)- = PIff <$> expandPred p <*> expandPred q-expandPred (PAll xs p)- = PAll xs <$> expandPred p--- expandPred (PExist xs p)--- = PExist xs <$> expandPred p-expandPred p- = return p ------------------------------------------------------------------------------------ Expand Exprs -------------------------------------------------------------------------------------------------------------------------------------------------- expandExpr :: Expr -> BareM Expr -expandExpr (EApp f@(Loc l _ f') es)- = do env <- gets (exprAliases.rtEnv)- case M.lookup f' env of- Just re ->- expandApp l re <$> mapM expandExpr es- Nothing ->- EApp f <$> mapM expandExpr es+expandExpr e@(EApp _ _)+ = expandEApp $ splitEApp e expandExpr (ENeg e) = ENeg <$> expandExpr e expandExpr (EBin op e1 e2) = EBin op <$> expandExpr e1 <*> expandExpr e2 expandExpr (EIte p e1 e2)- = EIte p <$> expandExpr e1 <*> expandExpr e2+ = EIte <$> expandExpr p <*> expandExpr e1 <*> expandExpr e2 expandExpr (ECst e s) = (`ECst` s) <$> expandExpr e +expandExpr e@(EVar _)+ = return e expandExpr e@(ESym _) = return e expandExpr e@(ECon _) = return e-expandExpr e@(EVar _)- = return e-expandExpr e@(ELit _ _)- = return e -expandExpr EBot- = return EBot+expandExpr (PAnd ps)+ = PAnd <$> mapM expandExpr ps+expandExpr (POr ps)+ = POr <$> mapM expandExpr ps+expandExpr (PNot p)+ = PNot <$> expandExpr p+expandExpr (PImp p q)+ = PImp <$> expandExpr p <*> expandExpr q+expandExpr (PIff p q)+ = PIff <$> expandExpr p <*> expandExpr q+expandExpr (PAll xs p)+ = PAll xs <$> expandExpr p+expandExpr (ELam xt e)+ = ELam xt <$> expandExpr e +expandExpr (ETApp e s)+ = (`ETApp` s) <$> expandExpr e +expandExpr (ETAbs e s)+ = (`ETAbs` s) <$> expandExpr e ++expandExpr (PAtom b e1 e2)+ = PAtom b <$> expandExpr e1 <*> expandExpr e2 ++expandExpr (PKVar k s)+ = return $ PKVar k s ++expandExpr PGrad+ = return PGrad++expandExpr (PExist s e)+ = PExist s <$> expandExpr e +++expandEApp (EVar f, es)+ = do env <- gets (exprAliases.rtEnv)+ case M.lookup f env of+ Just re ->+ expandApp re <$> mapM expandExpr es + Nothing ->+ eApps (EVar f) <$> mapM expandExpr es +expandEApp (f, es)+ = return $ eApps f es + -------------------------------------------------------------------------------- -- Expand Alias Application ---------------------------------------------------- -------------------------------------------------------------------------------- -expandApp l re es+expandApp re es = subst su $ rtBody re where su = mkSubst $ safeZipWithError msg (rtVArgs re) es- msg = "Malformed alias application at " ++ show l ++ "\n\t"+ msg = "Malformed alias application" ++ "\n\t" ++ show (rtName re) ++ " defined at " ++ show (rtPos re) ++ "\n\texpects " ++ show (length $ rtVArgs re)
src/Language/Haskell/Liquid/Bare/GhcSpec.hs view
@@ -8,39 +8,47 @@ , makeGhcSpec ) where +-- import Debug.Trace (trace)+import Prelude hiding (error) import CoreSyn hiding (Expr) import HscTypes import Id import NameSet+import Name import TyCon import Var import TysWiredIn -import Control.Applicative ((<$>))+import DataCon (DataCon)+ import Control.Monad.Reader import Control.Monad.State import Data.Bifunctor import Data.Maybe-import Data.Monoid ++import Control.Monad.Except (catchError)+import TypeRep (Type(TyConApp))+ import qualified Control.Exception as Ex import qualified Data.List as L import qualified Data.HashMap.Strict as M import qualified Data.HashSet as S -import Language.Fixpoint.Misc-import Language.Fixpoint.Names (takeWhileSym, nilName, consName)-import Language.Fixpoint.Types+import Language.Fixpoint.Misc (thd3) -import Language.Haskell.Liquid.Dictionaries-import Language.Haskell.Liquid.GhcMisc (getSourcePosE, getSourcePos, sourcePosSrcSpan)-import Language.Haskell.Liquid.PredType (makeTyConInfo)-import Language.Haskell.Liquid.RefType+import Language.Fixpoint.Types hiding (Error)++import Language.Haskell.Liquid.Types.Dictionaries+import Language.Haskell.Liquid.GHC.Misc (showPpr, getSourcePosE, getSourcePos, sourcePosSrcSpan, isDataConId)+import Language.Haskell.Liquid.Types.PredType (makeTyConInfo)+import Language.Haskell.Liquid.Types.RefType import Language.Haskell.Liquid.Types+import Language.Haskell.Liquid.Misc (mapSnd) import Language.Haskell.Liquid.WiredIn-import Language.Haskell.Liquid.Visitors-import Language.Haskell.Liquid.CoreToLogic ++ import qualified Language.Haskell.Liquid.Measure as Ms import Language.Haskell.Liquid.Bare.Check@@ -48,6 +56,7 @@ import Language.Haskell.Liquid.Bare.Env import Language.Haskell.Liquid.Bare.Existential import Language.Haskell.Liquid.Bare.Measure+import Language.Haskell.Liquid.Bare.Axiom import Language.Haskell.Liquid.Bare.Misc (makeSymbols, mkVarExpr) import Language.Haskell.Liquid.Bare.Plugged import Language.Haskell.Liquid.Bare.RTEnv@@ -56,18 +65,23 @@ import Language.Haskell.Liquid.Bare.RefToLogic import Language.Haskell.Liquid.Bare.Lookup (lookupGhcTyCon) ------------------------------------------------------------------------------ Top Level Output -----------------------------------------------------------------------------------------------------------makeGhcSpec :: Config -> ModName -> [CoreBind] -> [Var] -> [Var] -> NameSet -> HscEnv -> Either Error LogicMap+--------------------------------------------------------------------------------+makeGhcSpec :: Config+ -> ModName+ -> [CoreBind]+ -> [Var]+ -> [Var]+ -> NameSet+ -> HscEnv+ -> Either Error LogicMap -> [(ModName,Ms.BareSpec)] -> IO GhcSpec+-------------------------------------------------------------------------------- makeGhcSpec cfg name cbs vars defVars exports env lmap specs = do sp <- throwLeft =<< execBare act initEnv- let renv = ghcSpecEnv sp cbs- throwLeft $ checkGhcSpec specs renv $ postProcess cbs renv sp+ let renv = ghcSpecEnv sp+ throwLeft . checkGhcSpec specs renv $ postProcess cbs renv sp where act = makeGhcSpec' cfg cbs vars defVars exports specs throwLeft = either Ex.throw return@@ -80,58 +94,114 @@ where x = symbol "x" xs = symbol "xs"- hNil = EApp (dummyLoc $ symbol nilDataCon ) []- hCons = EApp (dummyLoc $ symbol consDataCon) + hNil = mkEApp (dummyLoc $ symbol nilDataCon ) []+ hCons = mkEApp (dummyLoc $ symbol consDataCon) postProcess :: [CoreBind] -> SEnv SortedReft -> GhcSpec -> GhcSpec-postProcess cbs specEnv sp@(SP {..}) = sp { tySigs = tySigs', texprs = ts, asmSigs = asmSigs', dicts = dicts' }- -- HEREHEREHEREHERE (addTyConInfo stuff)+postProcess cbs specEnv sp@(SP {..})+ = sp { tySigs = tySigs', texprs = ts, asmSigs = asmSigs', dicts = dicts', invariants = invs', meas = meas', inSigs = inSigs' } where- (sigs, ts) = replaceLocalBinds tcEmbeds tyconEnv tySigs texprs specEnv cbs- tySigs' = mapSnd (addTyConInfo tcEmbeds tyconEnv <$>) <$> sigs- asmSigs' = mapSnd (addTyConInfo tcEmbeds tyconEnv <$>) <$> asmSigs- dicts' = dmapty (addTyConInfo tcEmbeds tyconEnv) dicts+ (sigs, ts') = replaceLocalBinds tcEmbeds tyconEnv tySigs texprs specEnv cbs+ (assms, ts'') = replaceLocalBinds tcEmbeds tyconEnv asmSigs ts' specEnv cbs+ (insigs, ts) = replaceLocalBinds tcEmbeds tyconEnv inSigs ts'' specEnv cbs+ tySigs' = mapSnd (addTyConInfo tcEmbeds tyconEnv <$>) <$> sigs+ asmSigs' = mapSnd (addTyConInfo tcEmbeds tyconEnv <$>) <$> assms+ inSigs' = mapSnd (addTyConInfo tcEmbeds tyconEnv <$>) <$> insigs+ dicts' = dmapty (addTyConInfo tcEmbeds tyconEnv) dicts+ invs' = (addTyConInfo tcEmbeds tyconEnv <$>) <$> invariants+ meas' = mapSnd (fmap (addTyConInfo tcEmbeds tyconEnv) . txRefSort tyconEnv tcEmbeds) <$> meas -ghcSpecEnv sp cbs = fromListSEnv binds+ghcSpecEnv :: GhcSpec -> SEnv SortedReft+ghcSpecEnv sp = fromListSEnv binds where emb = tcEmbeds sp binds = [(x, rSort t) | (x, Loc _ _ t) <- meas sp] ++ [(symbol v, rSort t) | (v, Loc _ _ t) <- ctors sp] ++ [(x, vSort v) | (x, v) <- freeSyms sp, isConLikeId v]- ++ [(val x , rSort stringrSort) | Just (ELit x s) <- mkLit <$> lconsts, isString s]+ -- ++ [(val x , rSort stringrSort) | Just (ELit x s) <- mkLit <$> lconsts, isString s] rSort = rTypeSortedReft emb vSort = rSort . varRSort varRSort :: Var -> RSort varRSort = ofType . varType- lconsts = literals cbs- stringrSort :: RSort- stringrSort = ofType stringTy- isString s = rTypeSort emb stringrSort == s+ --lconsts = literals cbs+ --stringrSort :: RSort+ --stringrSort = ofType stringTy+ --isString s = rTypeSort emb stringrSort == s ------------------------------------------------------------------------------------------------ makeGhcSpec' :: Config -> [CoreBind] -> [Var] -> [Var] -> NameSet -> [(ModName, Ms.BareSpec)] -> BareM GhcSpec ------------------------------------------------------------------------------------------------ makeGhcSpec' cfg cbs vars defVars exports specs = do name <- modName <$> get- makeBounds name defVars cbs specs makeRTEnv specs- (tycons, datacons, dcSs, tyi, embs) <- makeGhcSpecCHOP1 specs+ (tycons, datacons, dcSs, recSs, tyi, embs) <- makeGhcSpecCHOP1 specs+ makeBounds embs name defVars cbs specs modify $ \be -> be { tcEnv = tyi } (cls, mts) <- second mconcat . unzip . mconcat <$> mapM (makeClasses name cfg vars) specs (measures, cms', ms', cs', xs') <- makeGhcSpecCHOP2 cbs specs dcSs datacons cls embs (invs, ialias, sigs, asms) <- makeGhcSpecCHOP3 cfg vars defVars specs name mts embs- syms <- makeSymbols (vars ++ map fst cs') xs' (sigs ++ asms ++ cs') ms' (invs ++ (snd <$> ialias))+ syms <- makeSymbols (varInModule name) (vars ++ map fst cs') xs' (sigs ++ asms ++ cs') ms' (invs ++ (snd <$> ialias)) let su = mkSubst [ (x, mkVarExpr v) | (x, v) <- syms]- return (emptySpec cfg)- >>= makeGhcSpec0 cfg defVars exports name- >>= makeGhcSpec1 vars embs tyi exports name sigs asms cs' ms' cms' su+ makeGhcSpec0 cfg defVars exports name (emptySpec cfg)+ >>= makeGhcSpec1 vars defVars embs tyi exports name sigs (recSs ++ asms) cs' ms' cms' su >>= makeGhcSpec2 invs ialias measures su- >>= makeGhcSpec3 datacons tycons embs syms- >>= makeGhcSpec4 defVars specs name su+ >>= makeGhcSpec3 (datacons ++ cls) tycons embs syms >>= makeSpecDictionaries embs vars specs+ >>= makeGhcAxioms embs cbs name specs+ >>= makeExactDataCons name (exactDC cfg) (snd <$> syms)+ -- This step need the updated logic map, ie should happen after makeGhcAxioms+ >>= makeGhcSpec4 defVars specs name su+ >>= addProofType ++addProofType :: GhcSpec -> BareM GhcSpec+addProofType spec+ = do tycon <- (Just <$> (lookupGhcTyCon $ dummyLoc proofTyConName)) `catchError` (\_ -> return Nothing)+ return $ spec {proofType = (`TyConApp` []) <$> tycon}+++makeExactDataCons :: ModName -> Bool -> [Var] -> GhcSpec -> BareM GhcSpec+makeExactDataCons n flag vs spec+ | flag = return $ spec {tySigs = (tySigs spec) ++ xts}+ | otherwise = return spec+ where+ xts = makeExact <$> (filter isDataConId $ filter (varInModule n) vs)++varInModule n v = L.isPrefixOf (show n) $ show v++makeExact :: Var -> (Var, Located SpecType)+makeExact x = (x, dummyLoc . fromRTypeRep $ trep{ty_res = res, ty_binds = xs})+ where+ t :: SpecType+ t = ofType $ varType x+ trep = toRTypeRep t+ xs = zipWith (\_ i -> (symbol ("x" ++ show i))) (ty_args trep) [1..]++ res = ty_res trep `strengthen` MkUReft ref mempty mempty+ vv = vv_+ x' = symbol x -- simpleSymbolVar x+ ref = Reft (vv, PAtom Eq (EVar vv) eq)+ eq | null (ty_vars trep) && null xs = EVar x'+ | otherwise = mkEApp (dummyLoc x') (EVar <$> xs)+++makeGhcAxioms :: TCEmb TyCon -> [CoreBind] -> ModName -> [(ModName, Ms.BareSpec)] -> GhcSpec -> BareM GhcSpec+makeGhcAxioms tce cbs name bspecs sp = makeAxioms tce cbs sp spec+ where+ spec = fromMaybe mempty $ lookup name bspecs++makeAxioms :: TCEmb TyCon -> [CoreBind] -> GhcSpec -> Ms.BareSpec -> BareM GhcSpec+makeAxioms tce cbs spec sp+ = do lmap <- logicEnv <$> get+ (ms, tys, as) <- unzip3 <$> mapM (makeAxiom tce lmap cbs spec sp) (S.toList $ Ms.axioms sp)+ lmap' <- logicEnv <$> get+ return $ spec { meas = ms ++ meas spec+ , asmSigs = concat tys ++ asmSigs spec+ , axioms = concat as ++ axioms spec+ , logicMap = lmap' }+ emptySpec :: Config -> GhcSpec-emptySpec cfg = SP [] [] [] [] [] [] [] [] [] mempty [] [] [] [] mempty mempty mempty cfg mempty [] mempty mempty+emptySpec cfg = SP [] [] [] [] [] [] [] [] [] [] mempty [] [] [] [] mempty mempty mempty cfg mempty [] mempty mempty [] mempty Nothing makeGhcSpec0 cfg defVars exports name sp@@ -140,20 +210,21 @@ , exports = exports , tgtVars = targetVars } -makeGhcSpec1 vars embs tyi exports name sigs asms cs' ms' cms' su sp+makeGhcSpec1 vars defVars embs tyi exports name sigs asms cs' ms' cms' su sp = do tySigs <- makePluggedSigs name embs tyi exports $ tx sigs asmSigs <- makePluggedAsmSigs embs tyi $ tx asms ctors <- makePluggedAsmSigs embs tyi $ tx cs' lmap <- logicEnv <$> get inlmap <- inlines <$> get let ctors' = [ (x, txRefToLogic lmap inlmap <$> t) | (x, t) <- ctors ]- return $ sp { tySigs = tySigs- , asmSigs = asmSigs- , ctors = ctors'+ return $ sp { tySigs = filter (\(v,_) -> v `elem` vs) tySigs+ , asmSigs = filter (\(v,_) -> v `elem` vs) asmSigs+ , ctors = filter (\(v,_) -> v `elem` vs) ctors' , meas = tx' $ tx $ ms' ++ varMeasures vars ++ cms' } where tx = fmap . mapSnd . subst $ su tx' = fmap (mapSnd $ fmap uRType)+ vs = vars ++ defVars makeGhcSpec2 invs ialias measures su sp = return $ sp { invariants = subst su invs@@ -163,8 +234,9 @@ ++ Ms.imeas measures } +makeGhcSpec3 :: [(DataCon, DataConP)] -> [(TyCon, TyConP)] -> TCEmb TyCon -> [(t, Var)] -> GhcSpec -> BareM GhcSpec makeGhcSpec3 datacons tycons embs syms sp- = do tcEnv <- gets tcEnv+ = do tcEnv <- tcEnv <$> get lmap <- logicEnv <$> get inlmap <- inlines <$> get let dcons' = mapSnd (txRefToLogic lmap inlmap) <$> datacons@@ -179,10 +251,10 @@ texprs' <- mconcat <$> mapM (makeTExpr defVars . snd) specs lazies <- mkThing makeLazy lvars' <- mkThing makeLVar- asize' <- S.fromList <$> makeASize + asize' <- S.fromList <$> makeASize hmeas <- mkThing makeHIMeas quals <- mconcat <$> mapM makeQualifiers specs- let sigs = strengthenHaskellMeasures hmeas ++ tySigs sp+ let msgs = strengthenHaskellMeasures hmeas lmap <- logicEnv <$> get inlmap <- inlines <$> get let tx = mapSnd (fmap $ txRefToLogic lmap inlmap)@@ -193,9 +265,10 @@ , lvars = lvars' , autosize = asize' , lazy = lazies- , tySigs = tx <$> sigs- , asmSigs = tx <$> (asmSigs sp)- , measures = mtx <$> (measures sp)+ , tySigs = tx <$> tySigs sp + , asmSigs = tx <$> asmSigs sp+ , measures = mtx <$> measures sp+ , inSigs = tx <$> msgs } where mkThing mk = S.fromList . mconcat <$> sequence [ mk defVars s | (m, s) <- specs, m == name ]@@ -207,8 +280,9 @@ let tyi = makeTyConInfo tycons embs <- mconcat <$> mapM makeTyConEmbeds specs datacons <- makePluggedDataCons embs tyi (concat dcs ++ wiredDataCons)- let dcSelectors = concat $ map makeMeasureSelectors datacons- return $ (tycons, second val <$> datacons, dcSelectors, tyi, embs)+ let dcSelectors = concatMap makeMeasureSelectors datacons+ recSels <- makeRecordSelectorSigs datacons+ return (tycons, second val <$> datacons, dcSelectors, recSels, tyi, embs) makeGhcSpecCHOP3 cfg vars defVars specs name mts embs = do sigs' <- mconcat <$> mapM (makeAssertSpec name cfg vars defVars) specs@@ -217,26 +291,30 @@ ialias <- mconcat <$> mapM makeIAliases specs let dms = makeDefaultMethods vars mts tyi <- gets tcEnv- let sigs = [ (x, txRefSort tyi embs . txExpToBind <$> t) | (_, x, t) <- sigs' ++ mts ++ dms ]- let asms = [ (x, txRefSort tyi embs . txExpToBind <$> t) | (_, x, t) <- asms' ]+ let sigs = [ (x, txRefSort tyi embs $ fmap txExpToBind t) | (_, x, t) <- sigs' ++ mts ++ dms ]+ let asms = [ (x, txRefSort tyi embs $ fmap txExpToBind t) | (_, x, t) <- asms' ] return (invs, ialias, sigs, asms) + makeGhcSpecCHOP2 cbs specs dcSelectors datacons cls embs- = do measures' <- mconcat <$> mapM makeMeasureSpec specs- tyi <- gets tcEnv- name <- gets modName- mapM_ (makeHaskellInlines cbs name) specs- hmeans <- mapM (makeHaskellMeasures cbs name) specs- let measures = mconcat (Ms.wiredInMeasures:measures':Ms.mkMSpec' dcSelectors:hmeans)- let (cs, ms) = makeMeasureSpec' measures- let cms = makeClassMeasureSpec measures- let cms' = [ (x, Loc l l' $ cSort t) | (Loc l l' x, t) <- cms ]- let ms' = [ (x, Loc l l' t) | (Loc l l' x, t) <- ms, isNothing $ lookup x cms' ]- let cs' = [ (v, Loc (getSourcePos v) (getSourcePosE v) (txRefSort tyi embs t)) | (v, t) <- meetDataConSpec cs (datacons ++ cls)]- let xs' = val . fst <$> ms+ = do measures' <- mconcat <$> mapM makeMeasureSpec specs+ tyi <- gets tcEnv+ name <- gets modName+ mapM_ (makeHaskellInlines embs cbs name) specs+ hmeans <- mapM (makeHaskellMeasures embs cbs name) specs+ let measures = mconcat (Ms.wiredInMeasures:measures':Ms.mkMSpec' dcSelectors:hmeans)+ let (cs, ms) = makeMeasureSpec' measures+ let cms = makeClassMeasureSpec measures+ let cms' = [ (x, Loc l l' $ cSort t) | (Loc l l' x, t) <- cms ]+ let ms' = [ (x, Loc l l' t) | (Loc l l' x, t) <- ms, isNothing $ lookup x cms' ]+ let cs' = [ (v, txRefSort' v tyi embs t) | (v, t) <- meetDataConSpec cs (datacons ++ cls)]+ let xs' = val . fst <$> ms return (measures, cms', ms', cs', xs') +txRefSort' v tyi embs t = txRefSort tyi embs (atLoc' v t) +atLoc' v = Loc (getSourcePos v) (getSourcePosE v)+ data ReplaceEnv = RE { _re_env :: M.HashMap Symbol Symbol , _re_fenv :: SEnv SortedReft , _re_emb :: TCEmb TyCon@@ -282,14 +360,19 @@ mapM_ traverseExprs (rhssOfBind b) k +-- RJ: this function is incomprehensible, what does it do?! withExtendedEnv vs k = do RE env' fenv' emb tyi <- ask- let env = L.foldl' (\m v -> M.insert (takeWhileSym (/='#') $ symbol v) (symbol v) m) env' vs+ let env = L.foldl' (\m v -> M.insert (varShortSymbol v) (symbol v) m) env' vs fenv = L.foldl' (\m v -> insertSEnv (symbol v) (rTypeSortedReft emb (ofType $ varType v :: RSort)) m) fenv' vs withReaderT (const (RE env fenv emb tyi)) $ do mapM_ replaceLocalBindsOne vs k +varShortSymbol :: Var -> Symbol+varShortSymbol = symbol . takeWhile (/= '#') . showPpr . getName++-- RJ: this function is incomprehensible replaceLocalBindsOne :: Var -> ReplaceM () replaceLocalBindsOne v = do mt <- gets (M.lookup v . fst)@@ -298,12 +381,12 @@ Just (Loc l l' (toRTypeRep -> t@(RTypeRep {..}))) -> do (RE env' fenv emb tyi) <- ask let f m k = M.lookupDefault k k m- let (env,args) = L.mapAccumL (\e (v,t) -> (M.insert v v e, substa (f e) t))+ let (env,args) = L.mapAccumL (\e (v, t) -> (M.insert v v e, substa (f e) t)) env' (zip ty_binds ty_args) let res = substa (f env) ty_res let t' = fromRTypeRep $ t { ty_args = args, ty_res = res } let msg = ErrTySpec (sourcePosSrcSpan l) (pprint v) t'- case checkTy msg emb tyi fenv t' of+ case checkTy msg emb tyi fenv (Loc l l' t') of Just err -> Ex.throw err Nothing -> modify (first $ M.insert v (Loc l l' t')) mes <- gets (M.lookup v . snd)
src/Language/Haskell/Liquid/Bare/Lookup.hs view
@@ -12,6 +12,7 @@ , lookupGhcDataCon ) where +import Prelude hiding (error) import BasicTypes import ConLike import DataCon@@ -27,7 +28,7 @@ import TysWiredIn import Var -import Control.Monad.Error (catchError, throwError)+import Control.Monad.Except (catchError, throwError) import Control.Monad.State import Data.Maybe import Text.PrettyPrint.HughesPJ (text)@@ -35,10 +36,10 @@ import qualified Data.List as L import qualified Data.HashMap.Strict as M -import Language.Fixpoint.Names (hpropConName, isPrefixOfSym, lengthSym, propConName, symbolString)+import Language.Fixpoint.Types.Names (hpropConName, isPrefixOfSym, lengthSym, propConName, symbolString) import Language.Fixpoint.Types (Symbol, Symbolic(..)) -import Language.Haskell.Liquid.GhcMisc (lookupRdrName, sourcePosSrcSpan, tcRnLookupRdrName)+import Language.Haskell.Liquid.GHC.Misc (lookupRdrName, sourcePosSrcSpan, tcRnLookupRdrName) import Language.Haskell.Liquid.Types import Language.Haskell.Liquid.WiredIn @@ -61,6 +62,7 @@ srcSpan = nameSrcSpan + -- lookupGhcThing :: (GhcLookup a) => String -> (TyThing -> Maybe b) -> a -> BareM b lookupGhcThing name f x = do zs <- lookupGhcThing' name f x@@ -87,7 +89,7 @@ = symbolLookupEnv env mod k wiredIn :: M.HashMap Symbol Name-wiredIn = M.fromList $ special ++ wiredIns +wiredIn = M.fromList $ special ++ wiredIns where wiredIns = [ (symbol n, n) | thing <- wiredInThings, let n = getName thing ] special = [ ("GHC.Integer.smallInteger", smallIntegerName)@@ -131,11 +133,11 @@ lookupGhcTyCon :: GhcLookup a => a -> BareM TyCon lookupGhcTyCon s = (lookupGhcThing "type constructor or class" ftc s) `catchError` (tryPropTyCon s)- where + where ftc (ATyCon x) = Just x ftc _ = Nothing -tryPropTyCon s e +tryPropTyCon s e | sx == propConName = return propTyCon | sx == hpropConName = return hpropTyCon | otherwise = throwError e@@ -159,7 +161,6 @@ = Nothing lookupGhcDataCon' = lookupGhcThing "data constructor" fdc- where + where fdc (AConLike (RealDataCon x)) = Just x fdc _ = Nothing-
src/Language/Haskell/Liquid/Bare/Measure.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE TupleSections #-} @@ -6,34 +6,31 @@ makeHaskellMeasures , makeHaskellInlines , makeHaskellBounds- , makeMeasureSpec , makeMeasureSpec'- , makeClassMeasureSpec , makeMeasureSelectors- , strengthenHaskellMeasures- , varMeasures ) where import CoreSyn import DataCon+import TyCon import Id import Name import Type hiding (isFunTy) import Var -import Prelude hiding (mapM)-import Control.Applicative ((<$>), (<*>))+import Prelude hiding (mapM, error)+import Control.Arrow ((&&&)) import Control.Monad hiding (forM, mapM)-import Control.Monad.Error hiding (Error, forM, mapM)+import Control.Monad.Except hiding (forM, mapM) import Control.Monad.State hiding (forM, mapM) import Data.Bifunctor import Data.Maybe import Data.Char (toUpper)-import Data.Monoid+ import Data.Traversable (forM, mapM) import Text.PrettyPrint.HughesPJ (text) import Text.Parsec.Pos (SourcePos)@@ -43,17 +40,18 @@ import qualified Data.HashMap.Strict as M import qualified Data.HashSet as S -import Language.Fixpoint.Misc-import Language.Fixpoint.Names-import Language.Fixpoint.Types (Expr(..))+import Language.Fixpoint.Misc (mlookup, sortNub)+import Language.Fixpoint.Types (Symbol, dummySymbol, symbolString, symbol, Expr(..))+import Language.Fixpoint.SortCheck (isFirstOrder)+ import qualified Language.Fixpoint.Types as F -import Language.Haskell.Liquid.CoreToLogic-import Language.Haskell.Liquid.Misc (mapSndM)-import Language.Haskell.Liquid.GhcMisc (getSourcePos, getSourcePosE, sourcePosSrcSpan, isDataConId)-import Language.Haskell.Liquid.RefType (dataConSymbol, generalize, ofType, uRType)+import Language.Haskell.Liquid.Transforms.CoreToLogic+import Language.Haskell.Liquid.Misc+import Language.Haskell.Liquid.GHC.Misc (dropModuleNames, getSourcePos, getSourcePosE, sourcePosSrcSpan, isDataConId)+import Language.Haskell.Liquid.Types.RefType (generalize, ofType, uRType, typeSort) import Language.Haskell.Liquid.Types-import Language.Haskell.Liquid.Bounds+import Language.Haskell.Liquid.Types.Bounds import qualified Language.Haskell.Liquid.Measure as Ms @@ -65,88 +63,91 @@ import Language.Haskell.Liquid.Bare.Resolve import Language.Haskell.Liquid.Bare.RefToLogic -makeHaskellMeasures :: [CoreBind] -> ModName -> (ModName, Ms.BareSpec) -> BareM (Ms.MSpec SpecType DataCon)-makeHaskellMeasures _ name' (name, _ ) | name /= name'+makeHaskellMeasures :: F.TCEmb TyCon -> [CoreBind] -> ModName -> (ModName, Ms.BareSpec) -> BareM (Ms.MSpec SpecType DataCon)+makeHaskellMeasures _ _ name' (name, _ ) | name /= name' = return mempty-makeHaskellMeasures cbs _ (_ , spec)+makeHaskellMeasures tce cbs _ (_ , spec) = do lmap <- gets logicEnv- Ms.mkMSpec' <$> mapM (makeMeasureDefinition lmap cbs') (S.toList $ Ms.hmeas spec)+ Ms.mkMSpec' <$> mapM (makeMeasureDefinition tce lmap cbs') (S.toList $ Ms.hmeas spec) where cbs' = concatMap unrec cbs unrec cb@(NonRec _ _) = [cb] unrec (Rec xes) = [NonRec x e | (x, e) <- xes] --makeHaskellInlines :: [CoreBind] -> ModName -> (ModName, Ms.BareSpec) -> BareM ()-makeHaskellInlines _ name' (name, _ ) | name /= name'+makeHaskellInlines :: F.TCEmb TyCon -> [CoreBind] -> ModName -> (ModName, Ms.BareSpec) -> BareM ()+makeHaskellInlines _ _ name' (name, _ ) | name /= name' = return mempty-makeHaskellInlines cbs _ (_ , spec)+makeHaskellInlines tce cbs _ (_ , spec) = do lmap <- gets logicEnv- mapM_ (makeMeasureInline lmap cbs') (S.toList $ Ms.inlines spec)+ mapM_ (makeMeasureInline tce lmap cbs') (S.toList $ Ms.inlines spec) where cbs' = concatMap unrec cbs unrec cb@(NonRec _ _) = [cb] unrec (Rec xes) = [NonRec x e | (x, e) <- xes] --makeMeasureInline :: LogicMap -> [CoreBind] -> LocSymbol -> BareM ()-makeMeasureInline lmap cbs x- = case (filter ((val x `elem`) . (map (dropModuleNames . simplesymbol)) . binders) cbs) of- (NonRec v def:_) -> do {e <- coreToFun' x v def; updateInlines x e}- (Rec [(v, def)]:_) -> do {e <- coreToFun' x v def; updateInlines x e}+makeMeasureInline :: F.TCEmb TyCon -> LogicMap -> [CoreBind] -> LocSymbol -> BareM ()+makeMeasureInline tce lmap cbs x+ = case filter ((val x `elem`) . map (dropModuleNames . simplesymbol) . binders) cbs of+ (NonRec v def:_) -> do {e <- coreToFun' tce x v def; updateInlines x e}+ (Rec [(v, def)]:_) -> do {e <- coreToFun' tce x v def; updateInlines x e} _ -> throwError $ mkError "Cannot inline haskell function" where- binders (NonRec x _) = [x]+ binders (NonRec z _) = [z] binders (Rec xes) = fst <$> xes - coreToFun' x v def = case (runToLogic lmap mkError $ coreToFun x v def) of- Left (xs, e) -> return (TI (symbol <$> xs) e)+ coreToFun' tce x v def = case runToLogic tce lmap mkError $ coreToFun x v def of+ Left (xs, e) -> return (TI (symbol <$> xs) (fromLR e)) Right e -> throwError e - mkError :: String -> Error- mkError str = ErrHMeas (sourcePosSrcSpan $ loc x) (val x) (text str)+ fromLR (Left l) = l + fromLR (Right r) = r + mkError :: String -> Error+ mkError str = ErrHMeas (sourcePosSrcSpan $ loc x) (pprint $ val x) (text str) updateInlines x v = modify $ \s -> let iold = M.insert (val x) v (inlines s) in s{inlines = M.map (f iold) iold }- where f imap = txRefToLogic mempty imap-+ where+ f = txRefToLogic mempty -makeMeasureDefinition :: LogicMap -> [CoreBind] -> LocSymbol -> BareM (Measure SpecType DataCon)-makeMeasureDefinition lmap cbs x- = case (filter ((val x `elem`) . (map (dropModuleNames . simplesymbol)) . binders) cbs) of- (NonRec v def:_) -> (Ms.mkM x (logicType $ varType v)) <$> coreToDef' x v def- (Rec [(v, def)]:_) -> (Ms.mkM x (logicType $ varType v)) <$> coreToDef' x v def+makeMeasureDefinition :: F.TCEmb TyCon -> LogicMap -> [CoreBind] -> LocSymbol -> BareM (Measure SpecType DataCon)+makeMeasureDefinition tce lmap cbs x+ = case filter ((val x `elem`) . map (dropModuleNames . simplesymbol) . binders) cbs of+ (NonRec v def:_) -> Ms.mkM x (logicType $ varType v) <$> coreToDef' x v def+ (Rec [(v, def)]:_) -> Ms.mkM x (logicType $ varType v) <$> coreToDef' x v def _ -> throwError $ mkError "Cannot extract measure from haskell function" where binders (NonRec x _) = [x] binders (Rec xes) = fst <$> xes - coreToDef' x v def = case (runToLogic lmap mkError $ coreToDef x v def) of+ coreToDef' x v def = case runToLogic tce lmap mkError $ coreToDef x v def of Left l -> return l Right e -> throwError e mkError :: String -> Error- mkError str = ErrHMeas (sourcePosSrcSpan $ loc x) (val x) (text str)+ mkError str = ErrHMeas (sourcePosSrcSpan $ loc x) (pprint $ val x) (text str) +simplesymbol :: CoreBndr -> Symbol simplesymbol = symbol . getName strengthenHaskellMeasures :: S.HashSet (Located Var) -> [(Var, Located SpecType)]-strengthenHaskellMeasures hmeas = (\v -> (val v, fmap strengthenResult v)) <$> (S.toList hmeas)+strengthenHaskellMeasures hmeas+ = (val &&& fmap strengthenResult) <$> S.toList hmeas makeMeasureSelectors :: (DataCon, Located DataConP) -> [Measure SpecType DataCon]-makeMeasureSelectors (dc, (Loc l l' (DataConP _ vs _ _ _ xts r _))) = catMaybes (go <$> zip (reverse xts) [1..])+makeMeasureSelectors (dc, Loc l l' (DataConP _ vs _ _ _ xts r _))+ = catMaybes (go <$> zip (reverse xts) [1..]) where go ((x,t), i) | isFunTy t = Nothing- | True = Just $ makeMeasureSelector (Loc l l' x) (dty t) dc n i+ | otherwise = Just $ makeMeasureSelector (Loc l l' x) (dty t) dc n i dty t = foldr RAllT (RFun dummySymbol r (fmap mempty t) mempty) vs n = length xts makeMeasureSelector x s dc n i = M {name = x, sort = s, eqns = [eqn]}- where eqn = Def x [] dc Nothing (((, Nothing) . mkx) <$> [1 .. n]) (E (EVar $ mkx i)) + where eqn = Def x [] dc Nothing (((, Nothing) . mkx) <$> [1 .. n]) (E (EVar $ mkx i)) mkx j = symbol ("xx" ++ show j) @@ -154,9 +155,9 @@ makeMeasureSpec (mod,spec) = inModule mod mkSpec where mkSpec = mkMeasureDCon =<< mkMeasureSort =<< m- m = Ms.mkMSpec <$> (mapM expandMeasure $ Ms.measures spec)+ m = Ms.mkMSpec <$> mapM expandMeasure (Ms.measures spec) <*> return (Ms.cmeasures spec)- <*> (mapM expandMeasure $ Ms.imeasures spec)+ <*> mapM expandMeasure (Ms.imeasures spec) makeMeasureSpec' = mapFst (mapSnd uRType <$>) . Ms.dataConTypes . first (mapReft ur_reft) @@ -167,16 +168,16 @@ mkMeasureDCon :: Ms.MSpec t LocSymbol -> BareM (Ms.MSpec t DataCon)-mkMeasureDCon m = (forM (measureCtors m) $ \n -> (val n,) <$> lookupGhcDataCon n)- >>= (return . mkMeasureDCon_ m)+mkMeasureDCon m+ = mkMeasureDCon_ m <$> forM (measureCtors m)+ (\n -> (val n,) <$> lookupGhcDataCon n) mkMeasureDCon_ :: Ms.MSpec t LocSymbol -> [(Symbol, DataCon)] -> Ms.MSpec t DataCon mkMeasureDCon_ m ndcs = m' {Ms.ctorMap = cm'} where m' = fmap (tx.val) m- cm' = hashMapMapKeys (tx' . tx) $ Ms.ctorMap m'+ cm' = hashMapMapKeys (symbol . tx) $ Ms.ctorMap m' tx = mlookup (M.fromList ndcs)- tx' = dataConSymbol measureCtors :: Ms.MSpec t LocSymbol -> [LocSymbol] measureCtors = sortNub . fmap ctor . concat . M.elems . Ms.ctorMap@@ -186,51 +187,58 @@ = Ms.MSpec <$> forM c (mapM txDef) <*> forM mm tx <*> forM cm tx <*> forM im tx where tx :: Measure BareType ctor -> BareM (Measure SpecType ctor)- tx (M n s eqs) = M n <$> (ofMeaSort s) <*> (mapM txDef eqs)+ tx (M n s eqs) = M n <$> ofMeaSort s <*> mapM txDef eqs txDef :: Def BareType ctor -> BareM (Def SpecType ctor)- txDef def = liftM3 (\xs t bds-> def{ dparams = xs, dsort = t, binds = bds}) + txDef def = liftM3 (\xs t bds-> def{ dparams = xs, dsort = t, binds = bds}) (mapM (mapSndM ofMeaSort) (dparams def)) (mapM ofMeaSort $ dsort def) (mapM (mapSndM $ mapM ofMeaSort) (binds def)) -varMeasures vars = [ (symbol v, varSpecType v) | v <- vars, isDataConId v, isSimpleType $ varType v ]+varMeasures :: (Monoid r) => [Var] -> [(Symbol, Located (RRType r))]+varMeasures vars = [ (symbol v, varSpecType v) | v <- vars+ , isDataConId v+ , isSimpleType $ varType v ] -isSimpleType t = null tvs && isNothing (splitFunTy_maybe tb)- where- (tvs, tb) = splitForAllTys t+isSimpleType :: Type -> Bool+isSimpleType = isFirstOrder . typeSort M.empty +-- OLD isSimpleType t = null tvs && isNothing (splitFunTy_maybe tb)+-- OLD where+-- OLD (tvs, tb) = splitForAllTys t++varSpecType :: (Monoid r) => Var -> Located (RRType r) varSpecType v = Loc l l' (ofType $ varType v) where l = getSourcePos v l' = getSourcePosE v -makeHaskellBounds :: CoreProgram -> S.HashSet (Var, LocSymbol) -> BareM RBEnv-makeHaskellBounds cbs xs+makeHaskellBounds :: F.TCEmb TyCon -> CoreProgram -> S.HashSet (Var, LocSymbol) -> BareM RBEnv+makeHaskellBounds tce cbs xs = do lmap <- gets logicEnv- M.fromList <$> mapM (makeHaskellBound lmap cbs) (S.toList xs)+ M.fromList <$> mapM (makeHaskellBound tce lmap cbs) (S.toList xs) -makeHaskellBound lmap cbs (v, x) = case filter ((v `elem`) . binders) cbs of- (NonRec v def:_) -> do {e <- coreToFun' x v def; return $ toBound v x e}- (Rec [(v, def)]:_) -> do {e <- coreToFun' x v def; return $ toBound v x e}+makeHaskellBound tce lmap cbs (v, x) = case filter ((v `elem`) . binders) cbs of+ (NonRec v def:_) -> do {e <- coreToFun' tce x v def; return $ toBound v x e}+ (Rec [(v, def)]:_) -> do {e <- coreToFun' tce x v def; return $ toBound v x e} _ -> throwError $ mkError "Cannot make bound of haskell function" where binders (NonRec x _) = [x] binders (Rec xes) = fst <$> xes - coreToFun' x v def = case (runToLogic lmap mkError $ coreToFun x v def) of+ coreToFun' tce x v def = case runToLogic tce lmap mkError $ coreToFun x v def of Left (xs, e) -> return (xs, e) Right e -> throwError e mkError :: String -> Error- mkError str = ErrHMeas (sourcePosSrcSpan $ loc x) (val x) (text str)+ mkError str = ErrHMeas (sourcePosSrcSpan $ loc x) (pprint $ val x) (text str) -toBound :: Var -> LocSymbol -> ([Var], Either F.Pred F.Expr) -> (LocSymbol, RBound)+toBound :: Var -> LocSymbol -> ([Var], Either F.Expr F.Expr) -> (LocSymbol, RBound) toBound v x (vs, Left p) = (x', Bound x' fvs ps xs p) where x' = capitalizeBound x@@ -238,9 +246,9 @@ (ps , xs) = (txp <$> ps', txx <$> xs') txp v = (dummyLoc $ simpleSymbolVar v, ofType $ varType v) txx v = (dummyLoc $ symbol v, ofType $ varType v)- fvs = (((`RVar` mempty) . RTV) <$> (fst $ splitForAllTys $ varType v)) :: [RSort]+ fvs = (((`RVar` mempty) . RTV) <$> fst (splitForAllTys $ varType v)) :: [RSort] -toBound v x (vs, Right e) = toBound v x (vs, Left $ F.PBexp e)+toBound v x (vs, Right e) = toBound v x (vs, Left e) capitalizeBound = fmap (symbol . toUpperHead . symbolString) where@@ -248,11 +256,11 @@ toUpperHead (x:xs) = toUpper x:xs ----------------------------------------------------------------------------------- Expand Measures -------------------------------------------------------------+-- | Expand Measures ----------------------------------------------------------- -------------------------------------------------------------------------------- expandMeasure m- = do eqns <- sequence $ expandMeasureDef <$> (eqns m)+ = do eqns <- sequence $ expandMeasureDef <$> eqns m return $ m { sort = generalize (sort m) , eqns = eqns } @@ -262,6 +270,6 @@ return $ d { body = body } expandMeasureBody :: SourcePos -> Body -> BareM Body-expandMeasureBody l (P p) = P <$> (resolve l =<< expandPred p)-expandMeasureBody l (R x p) = R x <$> (resolve l =<< expandPred p)+expandMeasureBody l (P p) = P <$> (resolve l =<< expandExpr p)+expandMeasureBody l (R x p) = R x <$> (resolve l =<< expandExpr p) expandMeasureBody l (E e) = E <$> resolve l e
src/Language/Haskell/Liquid/Bare/Misc.hs view
@@ -17,7 +17,7 @@ , hasBoolResult ) where -+import Prelude hiding (error) import TysWiredIn import Name @@ -26,47 +26,53 @@ import TypeRep import Var -import Control.Applicative ((<$>))-import Control.Monad.Error (throwError)+import Control.Monad.Except (throwError) import Control.Monad.State import Data.Maybe (isNothing) import qualified Data.List as L -import Language.Fixpoint.Names (dropModuleNames)-import Language.Fixpoint.Misc (sortDiff, sortNub)-import Language.Fixpoint.Types (Symbol, Expr(..), Reft(..), Reftable(..), emptySEnv, memberSEnv, symbol, syms, toReft)+import Language.Fixpoint.Misc (sortNub)+import Language.Fixpoint.Types (Symbol, Expr(..), Reft(..), Reftable(..), mkEApp, emptySEnv, memberSEnv, symbol, syms, toReft) -import Language.Haskell.Liquid.GhcMisc-import Language.Haskell.Liquid.RefType+import Language.Haskell.Liquid.GHC.Misc+import Language.Haskell.Liquid.Types.RefType import Language.Haskell.Liquid.Types+import Language.Haskell.Liquid.Misc (sortDiff) import Language.Haskell.Liquid.Bare.Env + -- TODO: This is where unsorted stuff is for now. Find proper places for what follows. -- WTF does this function do?-makeSymbols vs xs' xts yts ivs+makeSymbols f vs xs' xts yts ivs = do svs <- gets varEnv- return [ (x,v') | (x,v) <- svs, x `elem` xs, let (v',_,_) = joinVar vs (v,x,x)]+ return $ L.nub ([ (x,v') | (x,v) <- svs, x `elem` xs, let (v',_,_) = joinVar vs (v,x,x)]+ ++ [ (symbol v, v) | v <- vs, f v, isDataConId v, hasBasicArgs $ varType v ]) where xs = sortNub $ zs ++ zs' ++ zs'' zs = concatMap freeSymbols (snd <$> xts) `sortDiff` xs' zs' = concatMap freeSymbols (snd <$> yts) `sortDiff` xs' zs'' = concatMap freeSymbols ivs `sortDiff` xs'- -freeSymbols ty = sortNub $ concat $ efoldReft (\_ _ -> []) (\ _ -> ()) f (\_ -> id) emptySEnv [] (val ty)- where - f γ _ r xs = let Reft (v, _) = toReft r in - [ x | x <- syms r, x /= v, not (x `memberSEnv` γ)] : xs + -- arguments should be basic so that autogenerated singleton types are well formed+ hasBasicArgs (ForAllTy _ t) = hasBasicArgs t+ hasBasicArgs (FunTy tx t) = isBaseTy tx && hasBasicArgs t+ hasBasicArgs _ = True ++freeSymbols ty = sortNub $ concat $ efoldReft (\_ _ -> []) (const ()) f (const id) emptySEnv [] (val ty)+ where+ f γ _ r xs = let Reft (v, _) = toReft r in+ [ x | x <- syms r, x /= v, not (x `memberSEnv` γ)] : xs+ ------------------------------------------------------------------------------- -- Renaming Type Variables in Haskell Signatures ------------------------------ ------------------------------------------------------------------------------- data MapTyVarST = MTVST { vmap :: [(Var, RTyVar)]- , errmsg :: Error + , errmsg :: Error } initMapSt = MTVST []@@ -74,36 +80,36 @@ -- TODO: Maybe don't expose this; instead, roll this in with mapTyVar and export a -- single "clean" function as the API. runMapTyVars :: StateT MapTyVarST (Either Error) () -> MapTyVarST -> Either Error MapTyVarST-runMapTyVars x s = execStateT x s+runMapTyVars = execStateT mapTyVars :: (PPrint r, Reftable r) => Type -> RRType r -> StateT MapTyVarST (Either Error) ()-mapTyVars τ (RAllT _ t) +mapTyVars τ (RAllT _ t) = mapTyVars τ t-mapTyVars (ForAllTy _ τ) t +mapTyVars (ForAllTy _ τ) t = mapTyVars τ t-mapTyVars (FunTy τ τ') (RFun _ t t' _) +mapTyVars (FunTy τ τ') (RFun _ t t' _) = mapTyVars τ t >> mapTyVars τ' t'-mapTyVars (TyConApp _ τs) (RApp _ ts _ _) +mapTyVars (TyConApp _ τs) (RApp _ ts _ _) = zipWithM_ mapTyVars τs ts-mapTyVars (TyVarTy α) (RVar a _) +mapTyVars (TyVarTy α) (RVar a _) = do s <- get s' <- mapTyRVar α a s put s'-mapTyVars τ (RAllP _ t) - = mapTyVars τ t -mapTyVars τ (RAllS _ t) - = mapTyVars τ t -mapTyVars τ (RAllE _ _ t) - = mapTyVars τ t +mapTyVars τ (RAllP _ t)+ = mapTyVars τ t+mapTyVars τ (RAllS _ t)+ = mapTyVars τ t+mapTyVars τ (RAllE _ _ t)+ = mapTyVars τ t mapTyVars τ (RRTy _ _ _ t) = mapTyVars τ t mapTyVars τ (REx _ _ t)- = mapTyVars τ t + = mapTyVars τ t mapTyVars _ (RExprArg _) = return ()-mapTyVars (AppTy τ τ') (RAppTy t t' _) - = do mapTyVars τ t - mapTyVars τ' t' +mapTyVars (AppTy τ τ') (RAppTy t t' _)+ = do mapTyVars τ t+ mapTyVars τ' t' mapTyVars _ (RHole _) = return () mapTyVars _ _@@ -118,15 +124,15 @@ -mkVarExpr v - | isFunVar v = EApp (varFunSymbol v) []+mkVarExpr v+ | isFunVar v = mkEApp (varFunSymbol v) [] | otherwise = EVar (symbol v) -varFunSymbol = dummyLoc . dataConSymbol . idDataCon +varFunSymbol = dummyLoc . symbol . idDataCon isFunVar v = isDataConId v && not (null αs) && isNothing tf where- (αs, t) = splitForAllTys $ varType v + (αs, t) = splitForAllTys $ varType v tf = splitFunTy_maybe t -- the Vars we lookup in GHC don't always have the same tyvars as the Vars@@ -142,7 +148,6 @@ simpleSymbolVar = dropModuleNames . symbol . showPpr . getName hasBoolResult (ForAllTy _ t) = hasBoolResult t-hasBoolResult (FunTy _ t) | eqType boolTy t = True +hasBoolResult (FunTy _ t) | eqType boolTy t = True hasBoolResult (FunTy _ t) = hasBoolResult t hasBoolResult _ = False-
src/Language/Haskell/Liquid/Bare/OfType.hs view
@@ -12,17 +12,18 @@ , mkSpecType' ) where +import Prelude hiding (error) import BasicTypes import Name import TyCon hiding (synTyConRhs_maybe) import Type (expandTypeSynonyms) import TysWiredIn -import Control.Applicative+ import Control.Monad.Reader hiding (forM) import Control.Monad.State hiding (forM) import Data.Maybe (fromMaybe)-import Data.Monoid+ import Data.Traversable (forM) import Text.Parsec.Pos import Text.Printf@@ -30,14 +31,13 @@ import qualified Control.Exception as Ex import qualified Data.HashMap.Strict as M -import Language.Fixpoint.Misc (errorstar)-import Language.Fixpoint.Types (Expr(..), Reftable, Symbol, meet, mkSubst, subst, symbol)+import Language.Fixpoint.Types (Expr(..), Reftable, Symbol, meet, mkSubst, subst, symbol, mkEApp) -import Language.Haskell.Liquid.GhcMisc +import Language.Haskell.Liquid.GHC.Misc import Language.Haskell.Liquid.Misc (secondM)-import Language.Haskell.Liquid.RefType+import Language.Haskell.Liquid.Types.RefType import Language.Haskell.Liquid.Types-import Language.Haskell.Liquid.Bounds+import Language.Haskell.Liquid.Types.Bounds import Language.Haskell.Liquid.Bare.Env import Language.Haskell.Liquid.Bare.Expand@@ -63,10 +63,10 @@ ofBPVar :: BPVar -> BareM RPVar ofBPVar- = mapM_pvar ofBSort+ = mapMPvar ofBSort -mapM_pvar :: (Monad m) => (a -> m b) -> PVar a -> m (PVar b)-mapM_pvar f (PV x t v txys)+mapMPvar :: (Monad m) => (a -> m b) -> PVar a -> m (PVar b)+mapMPvar f (PV x t v txys) = do t' <- forM t f txys' <- mapM (\(t, x, y) -> liftM (, x, y) (f t)) txys return $ PV x t' v txys'@@ -82,16 +82,16 @@ = ofBRType expandRTAliasApp resolveReft t where resolveReft- = (resolve l <=< expandReft) . txParam subvUReft (uPVar <$> πs) t+ = (resolve l <=< expandReft) . txParam l subvUReft (uPVar <$> πs) t -txParam f πs t = f (txPvar (predMap πs t))+txParam l f πs t = f (txPvar l (predMap πs t)) -txPvar :: M.HashMap Symbol UsedPVar -> UsedPVar -> UsedPVar-txPvar m π = π { pargs = args' }+txPvar :: SourcePos -> M.HashMap Symbol UsedPVar -> UsedPVar -> UsedPVar+txPvar l m π = π { pargs = args' } where args' | not (null (pargs π)) = zipWith (\(_,x ,_) (t,_,y) -> (t, x, y)) (pargs π') (pargs π) | otherwise = pargs π'- π' = fromMaybe (errorstar err) $ M.lookup (pname π) m+ π' = fromMaybe (panic (Just $ sourcePosSrcSpan l) err) $ M.lookup (pname π) m err = "Bare.replaceParams Unbound Predicate Variable: " ++ show π predMap πs t = M.fromList [(pname π, π) | π <- πs ++ rtypePredBinds t]@@ -135,13 +135,12 @@ go (RExprArg (Loc l l' e)) = RExprArg . Loc l l' <$> resolve l e - go_ref (RPropP ss r)- = RPropP <$> mapM go_syms ss <*> resolveReft r+ go_ref (RProp ss (RHole r))+ = rPropP <$> mapM go_syms ss <*> resolveReft r go_ref (RProp ss t) = RProp <$> mapM go_syms ss <*> go t- go_ref (RHProp _ _)- = errorstar "TODO:EFFECTS:ofBRType" + go_syms = secondM ofBSort @@ -161,7 +160,7 @@ rs' <- mapM go_ref rs ts' <- mapM go ts bareTCApp r' lc' rs' ts'- goRApp _ _ = errorstar "This cannot happen"+ goRApp _ _ = impossible Nothing "goRApp failed through to final case" matchTyCon :: LocSymbol -> Int -> BareM TyCon@@ -186,18 +185,16 @@ expandRTAliasApp :: SourcePos -> RTAlias RTyVar SpecType -> [BareType] -> RReft -> BareM SpecType expandRTAliasApp l rta args r | length args == length αs + length εs- = do args' <- mapM (ofBareType l) args- let ts = take (length αs) args'- αts = zipWith (\α t -> (α, toRSort t, t)) αs ts- return $ subst su . (`strengthen` r) . subsTyVars_meet αts $ rtBody rta+ = do ts <- mapM (ofBareType l) $ take (length αs) args+ es <- mapM (resolve l . exprArg (show err)) $ drop (length αs) args+ let tsu = zipWith (\α t -> (α, toRSort t, t)) αs ts+ let esu = mkSubst $ zip (symbol <$> εs) es+ return $ subst esu . (`strengthen` r) . subsTyVars_meet tsu $ rtBody rta | otherwise = Ex.throw err where- su = mkSubst $ zip (symbol <$> εs) es αs = rtTArgs rta εs = rtVArgs rta- es_ = drop (length αs) args- es = map (exprArg $ show err) es_ err :: Error err = ErrAliasApp (sourcePosSrcSpan l) (length args) (pprint $ rtName rta) (sourcePosSrcSpan $ rtPos rta) (length αs + length εs) @@ -212,11 +209,11 @@ exprArg _ (RApp x [] [] _) = EVar (symbol x) exprArg msg (RApp f ts [] _)- = EApp (symbol <$> f) (exprArg msg <$> ts)+ = mkEApp (symbol <$> f) (exprArg msg <$> ts) exprArg msg (RAppTy (RVar f _) t _)- = EApp (dummyLoc $ symbol f) [exprArg msg t]+ = mkEApp (dummyLoc $ symbol f) [exprArg msg t] exprArg msg z- = errorstar $ printf "Unexpected expression parameter: %s in %s" (show z) msg+ = panic Nothing $ printf "Unexpected expression parameter: %s in %s" (show z) msg -------------------------------------------------------------------------------- @@ -241,7 +238,7 @@ tyApp (RApp c ts rs r) ts' rs' r' = RApp c (ts ++ ts') (rs ++ rs') (r `meet` r') tyApp t [] [] r = t `strengthen` r-tyApp _ _ _ _ = errorstar $ "Bare.Type.tyApp on invalid inputs"+tyApp _ _ _ _ = panic Nothing $ "Bare.Type.tyApp on invalid inputs" expandRTypeSynonyms :: (PPrint r, Reftable r) => RRType r -> RRType r expandRTypeSynonyms = ofType . expandTypeSynonyms . toType
src/Language/Haskell/Liquid/Bare/Plugged.hs view
@@ -7,6 +7,7 @@ , makePluggedDataCons ) where +import Prelude hiding (error) import DataCon import Module import Name@@ -15,23 +16,25 @@ import Type (expandTypeSynonyms) import Var -import Control.Applicative ((<$>), (<*>))+ import Control.Monad-import Control.Monad.Error+import Control.Monad.Except import Data.Generics.Aliases (mkT) import Data.Generics.Schemes (everywhere)-import Data.Monoid + import qualified Data.HashMap.Strict as M -import Language.Fixpoint.Names (dummySymbol)-import Language.Fixpoint.Types (mapPredReft, pAnd, conjuncts, Refa (..), TCEmb)+import Language.Fixpoint.Types.Names (dummySymbol)+import Language.Fixpoint.Types (mapPredReft, pAnd, conjuncts, TCEmb) -- import Language.Fixpoint.Types (traceFix, showFix) -import Language.Haskell.Liquid.GhcMisc (sourcePosSrcSpan)-import Language.Haskell.Liquid.RefType (addTyConInfo, ofType, rVar, rTyVar, subts, toType, uReft)+import Language.Haskell.Liquid.GHC.Misc (sourcePos2SrcSpan)+import Language.Haskell.Liquid.Types.RefType (addTyConInfo, ofType, rVar, rTyVar, subts, toType, uReft) import Language.Haskell.Liquid.Types +import Language.Haskell.Liquid.Misc (zipWithDefM)+ import Language.Haskell.Liquid.Bare.Env import Language.Haskell.Liquid.Bare.Misc @@ -44,22 +47,21 @@ makePluggedAsmSigs embs tcEnv sigs = forM sigs $ \(x,t) -> do let τ = expandTypeSynonyms $ varType x- let r = killHoles+ let r = const killHoles (x,) <$> plugHoles embs tcEnv x r τ t makePluggedDataCons embs tcEnv dcs = forM dcs $ \(dc, Loc l l' dcp) -> do let (das, _, dts, dt) = dataConSig dc tyArgs <- zipWithM (\t1 (x,t2) ->- (x,) . val <$> plugHoles embs tcEnv (dataConName dc) killHoles t1 (Loc l l' t2))+ (x,) . val <$> plugHoles embs tcEnv (dataConName dc) (const killHoles) t1 (Loc l l' t2)) dts (reverse $ tyArgs dcp)- tyRes <- val <$> plugHoles embs tcEnv (dataConName dc) killHoles dt (Loc l l' (tyRes dcp))+ tyRes <- val <$> plugHoles embs tcEnv (dataConName dc) (const killHoles) dt (Loc l l' (tyRes dcp)) return (dc, Loc l l' dcp { freeTyVars = map rTyVar das , freePred = map (subts (zip (freeTyVars dcp) (map (rVar :: TyVar -> RSort) das))) (freePred dcp) , tyArgs = reverse tyArgs , tyRes = tyRes}) - plugHoles tce tyi x f t (Loc l l' st) = do tyvsmap <- case runMapTyVars (mapTyVars (toType rt') st'') initvmap of Left e -> throwError e@@ -76,13 +78,21 @@ (_, ps, ls2, st') = bkUniv st (_, st'') = bkClass st' cs' = [(dummySymbol, RApp c t [] mempty) | (c,t) <- cs]- initvmap = initMapSt $ ErrMismatch (sourcePosSrcSpan l) (pprint x) t (toType st)+ initvmap = initMapSt $ ErrMismatch lqSp (pprint x) (pprint t) (pprint $ toType st) hsSp+ hsSp = getSrcSpan x+ lqSp = sourcePos2SrcSpan l l' go :: SpecType -> SpecType -> BareM SpecType- go t (RHole r) = return $ (addHoles t') { rt_reft = f r }+ go t (RHole r) = return $ (addHoles t') { rt_reft = f t r } where t' = everywhere (mkT $ addRefs tce tyi) t- addHoles = fmap (const $ f $ uReft ("v", Refa hole))+ addHoles = everywhere (mkT $ addHole)+ -- NOTE: make sure we only add holes to RVar and RApp (NOT RFun)+ addHole :: SpecType -> SpecType+ addHole t@(RVar v _) = RVar v (f t (uReft ("v", hole)))+ addHole t@(RApp c ts ps _) = RApp c ts ps (f t (uReft ("v", hole)))+ addHole t = t+ go (RVar _ _) v@(RVar _ _) = return v go (RFun _ i o _) (RFun x i' o' r) = RFun x <$> go i i' <*> go o o' <*> return r go (RAllT _ t) (RAllT a t') = RAllT a <$> go t t'@@ -93,7 +103,9 @@ go t (REx b x t') = REx b x <$> go t t' go t (RRTy e r o t') = RRTy e r o <$> go t t' go (RAppTy t1 t2 _) (RAppTy t1' t2' r) = RAppTy <$> go t1 t1' <*> go t2 t2' <*> return r- go (RApp _ t _ _) (RApp c t' p r) = RApp c <$> (zipWithM go t t') <*> return p <*> return r+ -- zipWithDefM: if ts and ts' have different length then the liquid and haskell types are different.+ -- keep different types for now, as a pretty error message will be created at Bare.Check+ go (RApp _ ts _ _) (RApp c ts' p r) = RApp c <$> (zipWithDefM go ts ts') <*> return p <*> return r -- If we reach the default case, there's probably an error, but we defer -- throwing it as checkGhcSpec does a much better job of reporting the -- problem to the user.@@ -111,9 +123,9 @@ addRefs _ _ t = t -maybeTrue :: NamedThing a => a -> ModName -> NameSet -> RReft -> RReft-maybeTrue x target exports r- | isInternalName name || inTarget && notExported+maybeTrue :: NamedThing a => a -> ModName -> NameSet -> SpecType -> RReft -> RReft+maybeTrue x target exports t r+ | not (isFunTy t) && (isInternalName name || inTarget && notExported) = r | otherwise = killHoles r@@ -128,5 +140,3 @@ where tx r = {- traceFix ("killholes: r = " ++ showFix r) $ -} mapPredReft dropHoles r dropHoles = pAnd . filter (not . isHole) . conjuncts--
src/Language/Haskell/Liquid/Bare/RTEnv.hs view
@@ -4,21 +4,23 @@ makeRTEnv ) where -import Control.Applicative ((<$>))+import Prelude hiding (error)+ import Data.Graph hiding (Graph) import Data.Maybe import qualified Control.Exception as Ex import qualified Data.HashMap.Strict as M+import qualified Data.List as L -import Language.Fixpoint.Misc (errorstar, fst3)-import Language.Fixpoint.Types (Expr(..), Pred(..), Symbol)+import Language.Fixpoint.Misc (fst3)+import Language.Fixpoint.Types (Expr(..), Symbol) -import Language.Haskell.Liquid.GhcMisc (sourcePosSrcSpan)-import Language.Haskell.Liquid.Misc (ordNub)-import Language.Haskell.Liquid.RefType (symbolRTyVar)+import Language.Haskell.Liquid.GHC.Misc (sourcePosSrcSpan)+import Language.Haskell.Liquid.Types.RefType (symbolRTyVar) import Language.Haskell.Liquid.Types + import qualified Language.Haskell.Liquid.Measure as Ms import Language.Haskell.Liquid.Bare.Env@@ -30,11 +32,9 @@ makeRTEnv specs = do makeREAliases ets- makeRPAliases pts makeRTAliases rts where rts = (concat [(m,) <$> Ms.aliases s | (m, s) <- specs])- pts = (concat [(m,) <$> Ms.paliases s | (m, s) <- specs]) ets = (concat [(m,) <$> Ms.ealiases s | (m, s) <- specs]) @@ -48,16 +48,6 @@ body <- withVArgs l l' (rtVArgs xt) $ ofBareType l $ rtBody xt setRTAlias (rtName xt) $ mapRTAVars symbolRTyVar $ xt { rtBody = body} -makeRPAliases- = graphExpand buildPredEdges expBody- where- expBody (mod, xt)- = inModule mod $- do let l = rtPos xt- let l' = rtPosE xt- body <- withVArgs l l' (rtVArgs xt) $ resolve l =<< (expandPred $ rtBody xt)- setRPAlias (rtName xt) $ xt { rtBody = body }- makeREAliases = graphExpand buildExprEdges expBody where@@ -88,7 +78,7 @@ fromAliasSymbol table sym = fromMaybe err $ M.lookup sym table where- err = errorstar $ "fromAliasSymbol: Dangling alias symbol: " ++ show sym+ err = panic Nothing $ "fromAliasSymbol: Dangling alias symbol: " ++ show sym type Graph t = [Node t]@@ -122,7 +112,7 @@ , acycle = map locate scc } err []- = errorstar "Bare.RTEnv.checkCyclicAliases: No type aliases in reported cycle"+ = panic Nothing "Bare.RTEnv.checkCyclicAliases: No type aliases in reported cycle" locate sym = ( sourcePosSrcSpan $ rtPos $ snd $ fromAliasSymbol table sym@@ -141,6 +131,9 @@ -------------------------------------------------------------------------------- +ordNub :: Ord a => [a] -> [a]+ordNub = map head . L.group . L.sort+ buildTypeEdges :: AliasTable BareType -> BareType -> [Symbol] buildTypeEdges table = ordNub . go where@@ -162,46 +155,37 @@ -- Just _ -> [c] -- Nothing -> [ ] - go_ref (RPropP _ _) = Nothing+ go_ref (RProp _ (RHole _)) = Nothing go_ref (RProp _ t) = Just t- go_ref (RHProp _ _) = errorstar "TODO:EFFECTS:buildTypeEdges" -buildPredEdges :: AliasTable Pred -> Pred -> [Symbol]-buildPredEdges table = ordNub . go- where- go :: Pred -> [Symbol]- go (PBexp (EApp lf _)) = [ f | let f = val lf, M.member f table]- go (PAnd ps) = concatMap go ps- go (POr ps) = concatMap go ps- go (PNot p) = go p- go (PImp p q) = go p ++ go q- go (PIff p q) = go p ++ go q- go (PAll _ p) = go p- go _ = [] - -- go (PBexp _) = []- -- go (PAtom _ _ _) = []- -- go PTrue = []- -- go PFalse = []- -- go PTop = []- buildExprEdges table = ordNub . go where go :: Expr -> [Symbol]- go (EApp lf es) = go_alias (val lf) ++ concatMap go es+ go (EApp e1 e2) = go e1 ++ go e2 go (ENeg e) = go e go (EBin _ e1 e2) = go e1 ++ go e2 go (EIte _ e1 e2) = go e1 ++ go e2 go (ECst e _) = go e- go _ = [] - -- go (ELit _ _) = []- -- go (ESym _) = []- -- go (ECon _) = []- -- go (EVar _) = []- -- go EBot = []+ go (ESym _) = []+ go (ECon _) = []+ go (EVar v) = go_alias v + go (PAnd ps) = concatMap go ps+ go (POr ps) = concatMap go ps+ go (PNot p) = go p+ go (PImp p q) = go p ++ go q+ go (PIff p q) = go p ++ go q+ go (PAll _ p) = go p+ go (ELam _ e) = go e ++ go (PAtom _ e1 e2) = go e1 ++ go e2 ++ go (ETApp e _) = go e + go (ETAbs e _) = go e + go (PKVar _ _) = []+ go (PExist _ e) = go e + go PGrad = [] + go_alias f = [f | M.member f table ]- -- = case M.lookup f table of- -- Just _ -> [f]- -- Nothing -> [ ]
src/Language/Haskell/Liquid/Bare/RefToLogic.hs view
@@ -7,27 +7,33 @@ ) where +import Prelude hiding (error)+ import Language.Haskell.Liquid.Types+import Language.Haskell.Liquid.Misc (mapSnd) import Language.Haskell.Liquid.Bare.Env -import Language.Fixpoint.Types hiding (Def, R)-import Language.Fixpoint.Misc-import Language.Fixpoint.Names+import Language.Fixpoint.Types hiding (R) ++import Language.Haskell.Liquid.GHC.Misc (dropModuleUnique)+++ import qualified Data.HashMap.Strict as M -import Control.Applicative ((<$>)) + txRefToLogic :: (Transformable r) => LogicMap -> InlnEnv -> r -> r txRefToLogic = tx' class Transformable a where- tx :: Symbol -> (Either LMap TInline) -> a -> a+ tx :: Symbol -> Either LMap TInline -> a -> a tx' :: LogicMap -> InlnEnv -> a -> a tx' lmap imap x = M.foldrWithKey tx x limap where- limap = M.fromList ((mapSnd Left <$> M.toList lmap) ++ (mapSnd Right <$> M.toList imap))+ limap = M.fromList ((mapSnd Left <$> (M.toList $ logic_map lmap)) ++ (mapSnd Right <$> M.toList imap)) instance (Transformable a) => (Transformable [a]) where@@ -35,7 +41,7 @@ instance Transformable DataConP where tx s m x = x { tyConsts = tx s m (tyConsts x)- , tyArgs = mapSnd (tx s m) <$> (tyArgs x)+ , tyArgs = mapSnd (tx s m) <$> tyArgs x , tyRes = tx s m (tyRes x) } @@ -49,9 +55,9 @@ tx s m = fmap (tx s m) instance Transformable Reft where- tx s m (Reft (v, Refa p)) = if v == s- then errorstar "Transformable: this should not happen"- else Reft(v, Refa $ tx s m p)+ tx s m (Reft (v, p)) = if v == s+ then impossible Nothing "Transformable: v != s"+ else Reft(v, tx s m p) -- OLD instance Transformable Refa where -- OLD tx s m (RConc p) = RConc $ tx s m p@@ -61,41 +67,44 @@ tx s m (Left x) = Left (tx s m x) tx s m (Right x) = Right (tx s m x) -instance Transformable Pred where- tx _ _ PTrue = PTrue- tx _ _ PFalse = PFalse- tx _ _ PTop = PTop- tx s m (PAnd ps) = PAnd (tx s m <$> ps)- tx s m (POr ps) = POr (tx s m <$> ps)- tx s m (PNot p) = PNot (tx s m p)- tx s m (PImp p1 p2) = PImp (tx s m p1) (tx s m p2)- tx s m (PIff p1 p2) = PIff (tx s m p1) (tx s m p2)- tx s m (PBexp (EApp f es)) = txPApp (s, m) f (tx s m <$> es)- tx s m (PBexp e) = PBexp (tx s m e)- tx s m (PAtom r e1 e2) = PAtom r (tx s m e1) (tx s m e2)- tx s m (PAll xss p) = PAll xss $ txQuant xss s m p- -- tx s m (PExist xss p) = PExist xss $ txQuant xss s m p- tx _ _ p@(PKVar _ _) = p txQuant xss s m p- | s `elem` (fst <$> xss) = errorstar "Transformable.tx on Pred: this should not happen"+ | s `elem` (fst <$> xss) = impossible Nothing "Transformable.tx on Pred" | otherwise = tx s m p instance Transformable Expr where tx s m (EVar s')- | cmpSymbol s s' = mexpr m+ | cmpSymbol s s' = mexpr s' m | otherwise = EVar s'- tx s m (EApp f es) = txEApp (s, m) f (tx s m <$> es)+ tx s m e@(EApp _ _) = txEApp (s, m) e -- f (tx s m es) tx _ _ (ESym c) = ESym c tx _ _ (ECon c) = ECon c- tx _ _ (ELit l s') = ELit l s'+ --tx _ _ (ELit l s') = ELit l s' tx s m (ENeg e) = ENeg (tx s m e) tx s m (EBin o e1 e2) = EBin o (tx s m e1) (tx s m e2) tx s m (EIte p e1 e2) = EIte (tx s m p) (tx s m e1) (tx s m e2) tx s m (ECst e s') = ECst (tx s m e) s' tx _ _ EBot = EBot+ tx _ _ PTrue = PTrue+ tx _ _ PFalse = PFalse+ tx _ _ PTop = PTop+ tx s m (PAnd ps) = PAnd (tx s m <$> ps)+ tx s m (POr ps) = POr (tx s m <$> ps)+ tx s m (PNot p) = PNot (tx s m p)+ tx s m (PImp p1 p2) = PImp (tx s m p1) (tx s m p2)+ tx s m (PIff p1 p2) = PIff (tx s m p1) (tx s m p2)+ tx s m (PAtom r e1 e2) = PAtom r (tx s m e1) (tx s m e2)+ tx s m (ELam (x,t) e) = ELam (x,t) $ txQuant [(x,t)] s m e+ tx s m (PAll xss p) = PAll xss $ txQuant xss s m p+ tx _ _ (PExist _ _) = panic Nothing "tx: PExist is for fixpoint internals only"+ -- tx s m (PExist xss p) = PExist xss $ txQuant xss s m p+ tx _ _ p@(PKVar _ _) = p+ tx _ _ p@(ETApp _ _) = p+ tx _ _ p@(ETAbs _ _) = p+ tx _ _ p@PGrad = p + instance Transformable (Measure t c) where tx s m x = x{eqns = tx s m <$> (eqns x)} @@ -107,40 +116,42 @@ tx s m (P p) = P $ tx s m p tx s m (R v p) = R v $ tx s m p -mexpr (Left (LMap _ _ e)) = e-mexpr (Right (TI _ (Right e))) = e-mexpr _ = errorstar "mexpr"+mexpr _ (Left (LMap _ [] e)) = e+mexpr s (Left (LMap _ _ _)) = EVar s+mexpr _ (Right (TI _ e)) = e+-- mexpr s s' = panic Nothing ("mexpr on " ++ show s ++ "\t" ++ show s') -txEApp (s, (Left (LMap _ xs e))) f es- | cmpSymbol s (val f)- = subst (mkSubst $ zip xs es) e- | otherwise- = EApp f es+txEApp (s,m) e = go f+ where+ (f, es) = splitEApp e + go (EVar x) = txEApp' (s,m) x (tx s m <$> es) + go f = eApps (tx s m f) (tx s m <$> es) -txEApp (s, (Right (TI xs (Right e)))) f es- | cmpSymbol s (val f)+txEApp' (s, (Left (LMap _ xs e))) f es+ | cmpSymbol s f && length xs == length es = subst (mkSubst $ zip xs es) e | otherwise- = EApp f es-+ = mkEApp (dummyLoc f) es -txEApp (s, (Right (TI _ (Left _)))) f es- | cmpSymbol s (val f)- = errorstar "txEApp: deep internal error"+txEApp' (s, (Right (TI xs e))) f es+ | cmpSymbol s f && length xs == length es+ = subst (mkSubst $ zip xs es) e | otherwise- = EApp f es+ = mkEApp (dummyLoc f) es -txPApp (s, (Right (TI xs (Left e)))) f es+{-+txPApp (s, (Right (TI xs e))) f es | cmpSymbol s (val f) = subst (mkSubst $ zip xs es) e | otherwise- = PBexp $ EApp f es+ = EApp f es -txPApp (s, m) f es = PBexp $ txEApp (s, m) f es+txPApp (s, m) f es = txEApp (s, m) f es+-} cmpSymbol s1 {- symbol in Core -} s2 {- logical Symbol-}- = (dropModuleNamesAndUnique s1) == (dropModuleNamesAndUnique s2)+ = dropModuleNamesAndUnique s1 == dropModuleNamesAndUnique s2 dropModuleNamesAndUnique = dropModuleUnique {- . dropModuleNames -}
src/Language/Haskell/Liquid/Bare/Resolve.hs view
@@ -7,17 +7,26 @@ Resolvable(..) ) where -import Control.Applicative ((<$>), (<*>))++import Prelude hiding (error)+ import Control.Monad.State import Data.Char (isUpper) import Text.Parsec.Pos import qualified Data.List as L-import qualified Data.Text as T+ import qualified Data.HashMap.Strict as M -import Language.Fixpoint.Names (prims)-import Language.Fixpoint.Types (Expr(..), Pred(..), Qualifier(..), Refa(..), Reft(..), Sort(..), Symbol, fTyconSymbol, symbol, symbolFTycon, symbolText)+import Language.Fixpoint.Types.Names (prims, unconsSym)+import Language.Fixpoint.Types (Expr(..),+ Qualifier(..),+ Reft(..),+ Sort(..),+ Symbol,+ fTyconSymbol,+ symbol,+ symbolFTycon) import Language.Haskell.Liquid.Misc (secondM, third3M) import Language.Haskell.Liquid.Types@@ -34,26 +43,29 @@ instance Resolvable Qualifier where resolve _ (Q n ps b l) = Q n <$> mapM (secondM (resolve l)) ps <*> resolve l b <*> return l -instance Resolvable Pred where++instance Resolvable Expr where+ resolve l (EVar s) = EVar <$> resolve l s+ resolve l (EApp s es) = EApp <$> resolve l s <*> resolve l es+ resolve l (ENeg e) = ENeg <$> resolve l e+ resolve l (EBin o e1 e2) = EBin o <$> resolve l e1 <*> resolve l e2+ resolve l (EIte p e1 e2) = EIte <$> resolve l p <*> resolve l e1 <*> resolve l e2+ resolve l (ECst x s) = ECst <$> resolve l x <*> resolve l s resolve l (PAnd ps) = PAnd <$> resolve l ps resolve l (POr ps) = POr <$> resolve l ps resolve l (PNot p) = PNot <$> resolve l p resolve l (PImp p q) = PImp <$> resolve l p <*> resolve l q resolve l (PIff p q) = PIff <$> resolve l p <*> resolve l q- resolve l (PBexp b) = PBexp <$> resolve l b resolve l (PAtom r e1 e2) = PAtom r <$> resolve l e1 <*> resolve l e2+ resolve l (ELam (x,t) e) = ELam <$> ((,) <$> resolve l x <*> resolve l t) <*> resolve l e resolve l (PAll vs p) = PAll <$> mapM (secondM (resolve l)) vs <*> resolve l p- -- resolve l (PExist vs p) = PExist <$> mapM (secondM (resolve l)) vs <*> resolve l p- resolve _ p = return p--instance Resolvable Expr where- resolve l (EVar s) = EVar <$> resolve l s- resolve l (EApp s es) = EApp <$> resolve l s <*> resolve l es- resolve l (ENeg e) = ENeg <$> resolve l e- resolve l (EBin o e1 e2) = EBin o <$> resolve l e1 <*> resolve l e2- resolve l (EIte p e1 e2) = EIte <$> resolve l p <*> resolve l e1 <*> resolve l e2- resolve l (ECst x s) = ECst <$> resolve l x <*> resolve l s- resolve _ x = return x+ resolve l (ETApp e s) = ETApp <$> resolve l e <*> resolve l s + resolve l (ETAbs e s) = ETAbs <$> resolve l e <*> resolve l s + resolve _ (PKVar k s) = return $ PKVar k s + resolve l (PExist ss e) = PExist ss <$> resolve l e+ resolve _ (ESym s) = return $ ESym s + resolve _ (ECon c) = return $ ECon c + resolve _ PGrad = return PGrad instance Resolvable LocSymbol where resolve _ ls@(Loc l l' s)@@ -68,37 +80,36 @@ return $ Loc l l' qs _ -> return ls -addSym x = modify $ \be -> be { varEnv = (varEnv be) `L.union` [x] }+addSym x = modify $ \be -> be { varEnv = varEnv be `L.union` [x] } -isCon c- | Just (c,_) <- T.uncons $ symbolText c = isUpper c- | otherwise = False+isCon s+ | Just (c,_) <- unconsSym s = isUpper c+ | otherwise = False instance Resolvable Symbol where resolve l x = fmap val $ resolve l $ Loc l l x instance Resolvable Sort where- resolve _ FInt = return FInt- resolve _ FReal = return FReal- resolve _ FNum = return FNum- resolve _ FFrac = return FFrac- resolve _ s@(FObj _) = return s --FObj . S <$> lookupName env m s- resolve _ s@(FVar _) = return s- resolve l (FFunc i ss) = FFunc i <$> resolve l ss- resolve _ (FApp tc ss)- | tcs' `elem` prims = FApp tc <$> ss'- | otherwise = FApp <$> (symbolFTycon . Loc l l' . symbol <$> lookupGhcTyCon tcs) <*> ss'- where- tcs@(Loc l l' tcs') = fTyconSymbol tc- ss' = resolve l ss+ resolve _ FInt = return FInt+ resolve _ FReal = return FReal+ resolve _ FNum = return FNum+ resolve _ FFrac = return FFrac+ resolve _ s@(FObj _) = return s --FObj . S <$> lookupName env m s+ resolve _ s@(FVar _) = return s+ resolve l (FAbs i s) = FAbs i <$> (resolve l s)+ resolve l (FFunc s1 s2) = FFunc <$> (resolve l s1) <*> (resolve l s2)+ resolve _ (FTC c)+ | tcs' `elem` prims = FTC <$> return c+ | otherwise = FTC <$> (symbolFTycon . Loc l l' . symbol <$> lookupGhcTyCon tcs)+ where+ tcs@(Loc l l' tcs') = fTyconSymbol c+ resolve l (FApp t1 t2) = FApp <$> resolve l t1 <*> resolve l t2 instance Resolvable (UReft Reft) where- resolve l (U r p s) = U <$> resolve l r <*> resolve l p <*> return s+ resolve l (MkUReft r p s) = MkUReft <$> resolve l r <*> resolve l p <*> return s instance Resolvable Reft where- resolve l (Reft (s, ra)) = Reft . (s,) <$> resolveRefa ra- where- resolveRefa (Refa p) = Refa <$> resolve l p+ resolve l (Reft (s, ra)) = Reft . (s,) <$> resolve l ra instance Resolvable Predicate where resolve l (Pr pvs) = Pr <$> resolve l pvs
src/Language/Haskell/Liquid/Bare/Spec.hs view
@@ -22,30 +22,30 @@ , makeHBounds ) where +import Prelude hiding (error) import MonadUtils (mapMaybeM) import TyCon import Var -import Control.Applicative ((<$>))-import Control.Monad.Error++import Control.Monad.Except import Control.Monad.State import Data.Maybe-import Data.Monoid + import qualified Data.List as L import qualified Data.HashSet as S import qualified Data.HashMap.Strict as M -import Language.Fixpoint.Misc (concatMapM, group, mapFst, snd3)-import Language.Fixpoint.Names (dropModuleNames, dropSym, isPrefixOfSym, qualifySymbol, symbolString, takeModuleNames)-import Language.Fixpoint.Types (Qualifier(..), symbol)--import Language.Haskell.Liquid.Dictionaries-import Language.Haskell.Liquid.GhcMisc (getSourcePos, showPpr, symbolTyVar)-import Language.Haskell.Liquid.Misc (addFst3, fourth4)-import Language.Haskell.Liquid.RefType (generalize, rVar, symbolRTyVar)+import Language.Fixpoint.Misc (group, snd3)+import Language.Fixpoint.Types.Names (dropSym, isPrefixOfSym, symbolString)+import Language.Fixpoint.Types (Qualifier(..), symbol, atLoc)+import Language.Haskell.Liquid.Types.Dictionaries+import Language.Haskell.Liquid.GHC.Misc ( dropModuleNames, qualifySymbol, takeModuleNames, getSourcePos, showPpr, symbolTyVar)+import Language.Haskell.Liquid.Misc (addFst3, fourth4, mapFst, concatMapM)+import Language.Haskell.Liquid.Types.RefType (generalize, rVar, symbolRTyVar) import Language.Haskell.Liquid.Types-import Language.Haskell.Liquid.Bounds+import Language.Haskell.Liquid.Types.Bounds import qualified Language.Haskell.Liquid.Measure as Ms @@ -147,12 +147,12 @@ makeDefaultMethods :: [Var] -> [(ModName,Var,Located SpecType)]- -> [(ModName,Var,Located SpecType)]+ -> [(ModName, Var ,Located SpecType)] makeDefaultMethods defVs sigs = [ (m,dmv,t) | dmv <- defVs , let dm = symbol $ showPpr dmv- , "$dm" `isPrefixOfSym` (dropModuleNames dm)+ , "$dm" `isPrefixOfSym` dropModuleNames dm , let mod = takeModuleNames dm , let method = qualifySymbol mod $ dropSym 3 (dropModuleNames dm) , let mb = L.find ((method `isPrefixOfSym`) . symbol . snd3) sigs@@ -205,18 +205,18 @@ = inModule mod $ makeIAliases' $ Ms.ialiases spec makeIAliases' :: [(Located BareType, Located BareType)] -> BareM [(Located SpecType, Located SpecType)]-makeIAliases' ts = mapM mkIA ts+makeIAliases' = mapM mkIA where- mkIA (t1, t2) = liftM2 (,) (mkI t1) (mkI t2)- mkI (Loc l l' t) = (Loc l l') . generalize <$> mkSpecType l t+ mkIA (t1, t2) = (,) <$> mkI t1 <*> mkI t2+ mkI (Loc l l' t) = Loc l l' . generalize <$> mkSpecType l t makeInvariants (mod,spec) = inModule mod $ makeInvariants' $ Ms.invariants spec makeInvariants' :: [Located BareType] -> BareM [Located SpecType]-makeInvariants' ts = mapM mkI ts+makeInvariants' = mapM mkI where- mkI (Loc l l' t) = (Loc l l') . generalize <$> mkSpecType l t+ mkI (Loc l l' t) = Loc l l' . generalize <$> mkSpecType l t makeSpecDictionaries embs vars specs sp@@ -229,26 +229,26 @@ makeSpecDictionaryOne embs vars (RI x t xts) = do t' <- mkTy t tyi <- gets tcEnv- ts' <- (map (txRefSort tyi embs . txExpToBind)) <$> mapM mkTy' ts- let (d, dts) = makeDictionary $ RI x t' $ zip xs ts'+ ts' <- map (val . txRefSort tyi embs . fmap txExpToBind) <$> mapM mkTy' ts+ let (d, dts) = makeDictionary $ RI x (val t') $ zip xs ts' let v = lookupName d return ((, dts) <$> v) where- mkTy t = mkSpecType (loc x) t- mkTy' t = generalize <$> mkTy t+ mkTy t = atLoc x <$> mkSpecType (loc x) t+ mkTy' t = fmap generalize <$> mkTy t (xs, ts) = unzip xts lookupName x = case filter ((==x) . fst) ((\x -> (dropModuleNames $ symbol $ show x, x)) <$> vars) of [(_, x)] -> Just x _ -> Nothing -makeBounds name defVars cbs specs+makeBounds tce name defVars cbs specs = do bnames <- mkThing makeHBounds- hbounds <- makeHaskellBounds cbs bnames- bnds <- M.fromList <$> (mapM go (concatMap (M.toList . Ms.bounds . snd ) specs))+ hbounds <- makeHaskellBounds tce cbs bnames+ bnds <- M.fromList <$> mapM go (concatMap (M.toList . Ms.bounds . snd ) specs) modify $ \env -> env{ bounds = hbounds `mappend` bnds } where- go (x,bound) = (x,) <$> (mkBound bound)+ go (x,bound) = (x,) <$> mkBound bound mkThing mk = S.fromList . mconcat <$> sequence [ mk defVars s | (m, s) <- specs, m == name]
src/Language/Haskell/Liquid/Bare/SymSort.hs view
@@ -1,70 +1,78 @@+{-# LANGUAGE FlexibleContexts #-}+ module Language.Haskell.Liquid.Bare.SymSort ( txRefSort ) where -import Control.Applicative ((<$>))+import Prelude hiding (error) import qualified Data.List as L--import Language.Fixpoint.Misc (errorstar, safeZip, fst3, snd3)-import Language.Fixpoint.Types (meet)+import Data.Maybe (fromMaybe)+import TyCon (TyCon)+import Language.Fixpoint.Misc (fst3, snd3)+import Language.Fixpoint.Types (atLoc, meet, TCEmb) -import Language.Haskell.Liquid.RefType (appRTyCon, strengthen)+import Language.Haskell.Liquid.Types.RefType (appRTyCon, strengthen) import Language.Haskell.Liquid.Types-import Language.Haskell.Liquid.Misc (safeZipWithError, intToString)+import Language.Haskell.Liquid.GHC.Misc (fSrcSpan)+import Language.Haskell.Liquid.Misc (safeZipWithError)+import Language.Haskell.Liquid.Bare.Env --- TODO: Rename, "Sort" isn't a good name for this module -- EFFECTS: TODO is this the SAME as addTyConInfo? No. `txRefSort` -- (1) adds the _real_ sorts to RProp, -- (2) gathers _extra_ RProp at turnst them into refinements, -- e.g. tests/pos/multi-pred-app-00.hs-txRefSort tyi tce = mapBot (addSymSort tce tyi) -addSymSort tce tyi (RApp rc@(RTyCon _ _ _) ts rs r) - = RApp rc ts (zipWith3 (addSymSortRef rc) pvs rargs [1..]) r'+txRefSort :: TCEnv -> TCEmb TyCon -> Located SpecType -> Located SpecType+txRefSort tyi tce t = atLoc t $ mapBot (addSymSort (fSrcSpan t) tce tyi) (val t)++addSymSort sp tce tyi (RApp rc@(RTyCon _ _ _) ts rs r)+ = RApp rc ts (zipWith3 (addSymSortRef sp rc) pvs rargs [1..]) r' where rc' = appRTyCon tce tyi rc ts- pvs = rTyConPVs rc' + pvs = rTyConPVs rc' (rargs, rrest) = splitAt (length pvs) rs r' = L.foldl' go r rrest- go r (RPropP _ r') = r' `meet` r- go r (RProp _ _ ) = r -- is this correct?- go _ (RHProp _ _ ) = errorstar "TODO:EFFECTS:addSymSort"+ go r (RProp _ (RHole r')) = r' `meet` r+ go r (RProp _ t' ) = let r' = fromMaybe mempty (stripRTypeBase t') in r `meet` r' -addSymSort _ _ t +addSymSort _ _ _ t = t -addSymSortRef _ _ (RHProp _ _) _ = errorstar "TODO:EFFECTS:addSymSortRef"-addSymSortRef rc p r i | isPropPV p = addSymSortRef' rc i p r - | otherwise = errorstar "addSymSortRef: malformed ref application"-+addSymSortRef sp rc p r i+ | isPropPV p+ = addSymSortRef' sp rc i p r+ | otherwise+ = panic Nothing "addSymSortRef: malformed ref application" -addSymSortRef' _ _ p (RProp s (RVar v r)) | isDummy v+addSymSortRef' _ _ _ p (RProp s (RVar v r)) | isDummy v = RProp xs t where t = ofRSort (pvType p) `strengthen` r xs = spliceArgs "addSymSortRef 1" s p -addSymSortRef' _ _ p (RProp s t) - = RProp xs t- where- xs = spliceArgs "addSymSortRef 2" s p--addSymSortRef' rc i p (RPropP _ r@(U _ (Pr [up]) _)) - = RPropP xts r -- (ofRSort (pvType p) `strengthen` r)+addSymSortRef' sp rc i p (RProp _ (RHole r@(MkUReft _ (Pr [up]) _)))+ | length xs == length ts+ = RProp xts (RHole r)+ | otherwise+ = uError $ ErrPartPred sp (pprint rc) (pprint $ pname up) i (length xs) (length ts) where- xts = safeZipWithError msg xs ts+ xts = safeZipWithError "addSymSortRef'" xs ts xs = snd3 <$> pargs up ts = fst3 <$> pargs p- msg = intToString i ++ " argument of " ++ show rc ++ " is " ++ show (pname up) - ++ " that expects " ++ show (length ts) ++ " arguments, but it has " ++ show (length xs) -addSymSortRef' _ _ _ (RPropP s r)- = RPropP s r -- (ofRSort (pvType p) `strengthen` r)--addSymSortRef' _ _ _ _- = errorstar "TODO:EFFECTS:addSymSortRef'"+addSymSortRef' _ _ _ _ (RProp s (RHole r))+ = RProp s (RHole r) -spliceArgs msg s p = safeZip msg (fst <$> s) (fst3 <$> pargs p) +addSymSortRef' _ _ _ p (RProp s t)+ = RProp xs t+ where+ xs = spliceArgs "addSymSortRef 2" s p +spliceArgs msg s p = go (fst <$> s) (pargs p)+ where+ go [] [] = []+ go [] ((s,x,_):as) = (x, s):go [] as+ go (x:xs) ((s,_,_):as) = (x,s):go xs as+ go xs [] = panic Nothing $ "spliceArgs: " ++ msg ++ "on XS=" ++ show xs
− src/Language/Haskell/Liquid/Bounds.hs
@@ -1,161 +0,0 @@-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE TupleSections #-}--module Language.Haskell.Liquid.Bounds (-- Bound(..),-- RBound, RRBound,-- RBEnv, RRBEnv,-- makeBound,- envToSub-- ) where--import Text.PrettyPrint.HughesPJ--import Data.List (partition)-import Data.Maybe-import Data.Hashable-import Data.Monoid-import Data.Bifunctor--import qualified Data.HashMap.Strict as M-import Control.Applicative ((<$>))--import Language.Fixpoint.Types-import Language.Fixpoint.Misc--import Language.Haskell.Liquid.Types-import Language.Haskell.Liquid.RefType---data Bound t e- = Bound { bname :: LocSymbol -- ^ The name of the bound- , tyvars :: [t] -- ^ Type variables that appear in the bounds- , bparams :: [(LocSymbol, t)] -- ^ These are abstract refinements, for now- , bargs :: [(LocSymbol, t)] -- ^ These are value variables- , bbody :: e -- ^ The body of the bound- }--type RBound = RRBound RSort-type RRBound tv = Bound tv Pred--type RBEnv = M.HashMap LocSymbol RBound-type RRBEnv tv = M.HashMap LocSymbol (RRBound tv)---instance Hashable (Bound t e) where- hashWithSalt i = hashWithSalt i . bname--instance Eq (Bound t e) where- b1 == b2 = (bname b1) == (bname b2)--instance (PPrint e, PPrint t) => (Show (Bound t e)) where- show = showpp---instance (PPrint e, PPrint t) => (PPrint (Bound t e)) where- pprint (Bound s vs ps xs e) = text "bound" <+> pprint s <+>- text "forall" <+> pprint vs <+> text "." <+>- pprint (fst <$> ps) <+> text "=" <+>- pprint_bsyms (fst <$> xs) <+> pprint e--pprint_bsyms [] = text ""-pprint_bsyms xs = text "\\" <+> pprint xs <+> text "->"--instance Bifunctor Bound where- first f (Bound s vs ps xs e) = Bound s (f <$> vs) (mapSnd f <$> ps) (mapSnd f <$> xs) e- second f (Bound s vs ps xs e) = Bound s vs ps xs (f e)---makeBound :: (PPrint r, UReftable r)- => RRBound RSort -> [RRType r] -> [Symbol] -> (RRType r) -> (RRType r)-makeBound (Bound _ vs ps xs p) ts qs t- = RRTy cts mempty OCons t- where- cts = (\(x, t) -> (x, foldr subsTyVar_meet t su)) <$> cts'-- cts' = makeBoundType penv rs xs-- penv = zip (val . fst <$> ps) qs- rs = bkImp [] p-- bkImp acc (PImp p q) = bkImp (p:acc) q- bkImp acc p = p:acc-- su = [(α, toRSort t, t) | (RVar α _, t) <- zip vs ts ]--makeBoundType :: (PPrint r, UReftable r)- => [(Symbol, Symbol)]- -> [Pred]- -> [(LocSymbol, RSort)]- -> [(Symbol, RRType r)]-makeBoundType penv (q:qs) xts = go xts- where- -- NV TODO: Turn this into a proper error- go [] = errorstar "Bound with empty symbols"-- go [(x, t)] = [(dummySymbol, tp t x), (dummySymbol, tq t x)]- go ((x, t):xtss) = (val x, mkt t x):(go xtss)-- mkt t x = ofRSort t `strengthen` ofUReft (U (Reft (val x, mempty))- (Pr $ M.lookupDefault [] (val x) ps) mempty)- tp t x = ofRSort t `strengthen` ofUReft (U (Reft (val x, refa rs))- (Pr $ M.lookupDefault [] (val x) ps) mempty)- tq t x = ofRSort t `strengthen` makeRef penv x q-- (ps, rs) = partitionPs penv qs----- NV TODO: Turn this into a proper error-makeBoundType _ _ _ = errorstar "Bound with empty predicates"---partitionPs :: [(Symbol, Symbol)] -> [Pred] -> (M.HashMap Symbol [UsedPVar], [Pred])-partitionPs penv qs = mapFst makeAR $ partition (isPApp penv) qs- where- makeAR ps = M.fromListWith (++) $ map (toUsedPVars penv) ps--isPApp penv (PBexp (EApp p _)) = isJust $ lookup (val p) penv-isPApp _ _ = False--toUsedPVars penv q@(PBexp (EApp _ es)) = (x, [toUsedPVar penv q])- where- -- NV : TODO make this a better error- x = (\(EVar x) -> x) $ last es-toUsedPVars _ _ = error "This cannot happen"--toUsedPVar penv (PBexp (EApp p es))- = PV q (PVProp ()) e (((), dummySymbol,) <$> es')- where- EVar e = last es- es' = init es- Just q = lookup (val p) penv--toUsedPVar _ _ = error "This cannot happen"--envToSub = go []- where- go _ [] = error "This cannot happen: envToSub on 0 elems"- go _ [(_,_)] = error "This cannot happen: envToSub on 1 elem"- go ack [(_,l), (_, r)] = (reverse ack, l, r)- go ack (x:xs) = go (x:ack) xs---- `makeRef` is used to make the refinement of the last implication,--- thus it can contain both concrete and abstract refinements--makeRef :: (UReftable r) => [(Symbol, Symbol)] -> LocSymbol -> Pred -> r-makeRef penv v (PAnd rs) = ofUReft (U (Reft (val v, refa rrs)) r mempty)- where- r = Pr (toUsedPVar penv <$> pps)- (pps, rrs) = partition (isPApp penv) rs--makeRef penv v rr- | isPApp penv rr = ofUReft (U (Reft(val v, mempty)) r mempty)- where- r = Pr [toUsedPVar penv rr]--makeRef _ v p = ofReft (Reft(val v, Refa p))
− src/Language/Haskell/Liquid/CTags.hs
@@ -1,74 +0,0 @@-{-# LANGUAGE TupleSections #-}--- | This module contains the code for generating "tags" for constraints--- based on their source, i.e. the top-level binders under which the--- constraint was generated. These tags are used by fixpoint to --- prioritize constraints by the "source-level" function.--module Language.Haskell.Liquid.CTags (- -- * Type for constraint tags- TagKey, TagEnv- - -- * Default tag value- , defaultTag- - -- * Constructing @TagEnv@- , makeTagEnv- - -- * Accessing @TagEnv@- , getTag, memTagEnv--) where--import Var-import CoreSyn--import qualified Data.HashSet as S-import qualified Data.HashMap.Strict as M-import qualified Data.Graph as G--import Language.Fixpoint.Misc (mapSnd)-import Language.Fixpoint.Types (Tag)-import Language.Haskell.Liquid.Visitors (freeVars)---- | The @TagKey@ is the top-level binder, and @Tag@ is a singleton Int list--type TagKey = Var-type TagEnv = M.HashMap TagKey Tag---- TODO: use the "callgraph" SCC to do this numbering.--defaultTag :: Tag-defaultTag = [0]--memTagEnv :: TagKey -> TagEnv -> Bool-memTagEnv = M.member--makeTagEnv :: [CoreBind] -> TagEnv -makeTagEnv = M.map (:[]) . callGraphRanks . makeCallGraph ---- makeTagEnv = M.fromList . (`zip` (map (:[]) [1..])). L.sort . map fst . concatMap bindEqns--getTag :: TagKey -> TagEnv -> Tag-getTag = M.lookupDefault defaultTag----------------------------------------------------------------------------------------------------------type CallGraph = [(Var, [Var])] -- caller-callee pairs--callGraphRanks :: CallGraph -> M.HashMap Var Int--- callGraphRanks cg = traceShow ("CallGraph Ranks: " ++ show cg) $ callGraphRanks' cg--callGraphRanks = M.fromList . concat . index . mkScc- where mkScc cg = G.stronglyConnComp [(u, u, vs) | (u, vs) <- cg]- index = zipWith (\i -> map (, i) . G.flattenSCC) [1..] --makeCallGraph :: [CoreBind] -> CallGraph-makeCallGraph cbs = mapSnd calls `fmap` xes - where xes = concatMap bindEqns cbs- xs = S.fromList $ map fst xes- calls = filter (`S.member` xs) . freeVars S.empty--bindEqns (NonRec x e) = [(x, e)]-bindEqns (Rec xes) = xes --
− src/Language/Haskell/Liquid/Cabal.hs
@@ -1,254 +0,0 @@--- | This module contains a single function that extracts the cabal information about a target file, if any.--- This information can be used to extend the source-directories that are searched to find modules that are--- imported by the target file.--{-@ LIQUID "--no-termination" @-}-{-@ LIQUID "--diff" @-}-{-@ LIQUID "--short-names" @-}-{-@ LIQUID "--cabaldir" @-}--{-# LANGUAGE TypeSynonymInstances #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE CPP #-}--module Language.Haskell.Liquid.Cabal (cabalInfo, Info(..)) where--import Control.Applicative ((<$>))-import Data.Bits ( shiftL, shiftR, xor )-import Data.Char ( ord )-import Data.List-import Data.Maybe-import qualified Data.Text as T-import qualified Data.Text.IO as TIO-import Data.Word ( Word32 )-import Distribution.Compiler-import Distribution.Package-import Distribution.PackageDescription-import Distribution.PackageDescription.Configuration-import Distribution.PackageDescription.Parse-import Distribution.Simple.BuildPaths-import Distribution.System-import Distribution.Verbosity-import Language.Haskell.Extension-import Numeric ( showHex )-import System.Console.CmdArgs-import System.Environment-import System.Exit-import System.FilePath-import System.Directory-import System.Info-import Language.Haskell.Liquid.Errors---- To use in ghci:--- exitWithPanic = undefined--------------------------------------------------------------------------------------------------cabalInfo :: FilePath -> IO (Maybe Info)-------------------------------------------------------------------------------------------------cabalInfo f = do- f <- canonicalizePath f- cf <- findCabalFile f- case cf of- Just f -> Just <$> processCabalFile f- Nothing -> return Nothing--processCabalFile :: FilePath -> IO Info-processCabalFile f = do- let sandboxDir = sandboxBuildDir (takeDirectory f </> ".cabal-sandbox")- b <- doesDirectoryExist sandboxDir- let distDir = if b then sandboxDir else "dist"- i <- cabalConfiguration f distDir <$> readPackageDescription silent f- i <- addPackageDbs =<< canonicalizePaths i- whenLoud $ putStrLn $ "Cabal Info: " ++ show i- return i--------------------------------------------------------------------------------------------------findCabalFile :: FilePath -> IO (Maybe FilePath)-------------------------------------------------------------------------------------------------findCabalFile = fmap listToMaybe . findInPath isCabal- where- isCabal = (".cabal" ==) . takeExtension--findInPath :: (FilePath -> Bool) -> FilePath -> IO [FilePath]-findInPath p f = concat <$> mapM (findInDir p) (ancestorDirs f)--ancestorDirs :: FilePath -> [FilePath]-ancestorDirs = go . takeDirectory- where- go f- | f == f' = [f]- | otherwise = f : go f'- where- f' = takeDirectory f--findInDir :: (FilePath -> Bool) -> FilePath -> IO [FilePath]-findInDir p dir = do- files <- getDirectoryContents dir- return [ dir </> f | f <- files, p f ]------------------------------------------------------------------------------------------------------ INVARIANT: all FilePaths must be absolute-data Info = Info { cabalFile :: FilePath- , buildDirs :: [FilePath]- , sourceDirs :: [FilePath]- , exts :: [Extension]- , otherOptions :: [String]- , packageDbs :: [String]- , packageDeps :: [String]- , macroPath :: FilePath- } deriving (Show)---addPackageDbs :: Info -> IO Info-addPackageDbs i = maybe i addDB <$> getSandboxDB i- where- addDB db = i { packageDbs = T.unpack db : packageDbs i}--getSandboxDB :: Info -> IO (Maybe T.Text)-getSandboxDB i = do- tM <- maybeReadFile $ sandBoxFile i- case tM of- Just t -> return $ Just $ parsePackageDb t- Nothing -> return Nothing- -- fmap <$> maybeReadFile (sandBoxFile i)--parsePackageDb :: T.Text -> T.Text-parsePackageDb t = case dbs of- [db] -> T.strip db- _ -> exitWithPanic $ "Malformed package-db in sandbox: " ++ show dbs- where- dbs = mapMaybe (T.stripPrefix pfx) $ T.lines t- pfx = "package-db:"- -- /Users/rjhala/research/liquid/liquidhaskell/.cabal-sandbox/x86_64-osx-ghc-7.8.3-packages.conf.d--maybeReadFile :: FilePath -> IO (Maybe T.Text)-maybeReadFile f = do- b <- doesFileExist f- if b then Just <$> TIO.readFile f- else return Nothing----sandBoxFile :: Info -> FilePath-sandBoxFile i = dir </> "cabal.sandbox.config"- where- dir = takeDirectory $ cabalFile i---dumpPackageDescription :: PackageDescription -> FilePath -> FilePath -> Info-dumpPackageDescription pkgDesc file distDir = Info {- cabalFile = file- , buildDirs = nub (map normalise buildDirs)- , sourceDirs = nub (normalise <$> getSourceDirectories buildInfo dir)- , exts = nub (concatMap usedExtensions buildInfo)- , otherOptions = nub (filter isAllowedOption (concatMap (hcOptions GHC) buildInfo))- , packageDbs = []- , packageDeps = nub [ unPackName n | Dependency n _ <- buildDepends pkgDesc, n /= thisPackage ]- , macroPath = macroPath- }- where- (buildDirs, macroPath) = getBuildDirectories pkgDesc distDir- buildInfo = allBuildInfo pkgDesc- dir = dropFileName file- thisPackage = (pkgName . package) pkgDesc--unPackName :: PackageName -> String-unPackName (PackageName s) = s---getSourceDirectories :: [BuildInfo] -> FilePath -> [String]-getSourceDirectories buildInfo cabalDir = map (cabalDir </>) (concatMap hsSourceDirs buildInfo)--allowedOptions :: [String]-allowedOptions =- ["-W"- ,"-w"- ,"-Wall"- ,"-fglasgow-exts"- ,"-fpackage-trust"- ,"-fhelpful-errors"- ,"-F"- ,"-cpp"]--allowedOptionPrefixes :: [String]-allowedOptionPrefixes =- ["-fwarn-"- ,"-fno-warn-"- ,"-fcontext-stack="- ,"-firrefutable-tuples"- ,"-D"- ,"-U"- ,"-I"- ,"-fplugin="- ,"-fplugin-opt="- ,"-pgm"- ,"-opt"]---getBuildDirectories :: PackageDescription -> FilePath -> ([String], FilePath)-getBuildDirectories pkgDesc distDir =- (case library pkgDesc of- Just _ -> buildDir : buildDirs- Nothing -> buildDirs- ,autogenDir </> cppHeaderName)- where- buildDir = distDir </> "build"- autogenDir = buildDir </> "autogen"- execBuildDir e = buildDir </> exeName e </> (exeName e ++ "-tmp")- buildDirs = autogenDir : map execBuildDir (executables pkgDesc)----- See https://github.com/haskell/cabal/blob/master/cabal-install/Distribution/Client/Sandbox.hs#L137-L158-sandboxBuildDir :: FilePath -> FilePath-sandboxBuildDir sandboxDir = "dist/dist-sandbox-" ++ showHex sandboxDirHash ""- where- sandboxDirHash = jenkins sandboxDir-- -- See http://en.wikipedia.org/wiki/Jenkins_hash_function- jenkins :: String -> Word32- jenkins str = loop_finish $ foldl' loop 0 str- where- loop :: Word32 -> Char -> Word32- loop hash key_i' = hash'''- where- key_i = toEnum . ord $ key_i'- hash' = hash + key_i- hash'' = hash' + (shiftL hash' 10)- hash''' = hash'' `xor` (shiftR hash'' 6)-- loop_finish :: Word32 -> Word32- loop_finish hash = hash'''- where- hash' = hash + (shiftL hash 3)- hash'' = hash' `xor` (shiftR hash' 11)- hash''' = hash'' + (shiftL hash'' 15)--isAllowedOption :: String -> Bool-isAllowedOption opt = elem opt allowedOptions || any (`isPrefixOf` opt) allowedOptionPrefixes--buildCompiler :: CompilerId-buildCompiler = CompilerId buildCompilerFlavor compilerVersion--cabalConfiguration :: FilePath -> FilePath -> GenericPackageDescription -> Info-cabalConfiguration cabalFile distDir desc =- case finalizePackageDescription []- (const True)- buildPlatform-#if MIN_VERSION_Cabal(1,22,0)- (unknownCompilerInfo buildCompiler NoAbiTag)-#else- buildCompiler-#endif- []- desc of- Right (pkgDesc,_) -> dumpPackageDescription pkgDesc cabalFile distDir- Left e -> exitWithPanic $ "Issue with package configuration\n" ++ show e--canonicalizePaths :: Info -> IO Info-canonicalizePaths i = do- buildDirs <- mapM canonicalizePath (buildDirs i)- macroPath <- canonicalizePath (macroPath i)- return (i { buildDirs = buildDirs, macroPath = macroPath })
− src/Language/Haskell/Liquid/CmdLine.hs
@@ -1,370 +0,0 @@-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE NoMonomorphismRestriction #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TupleSections #-}-{-# LANGUAGE TypeSynonymInstances #-}-{-# OPTIONS_GHC -fno-cse #-}--{-@ LIQUID "--cabaldir" @-}-{-@ LIQUID "--diff" @-}---- | This module contains all the code needed to output the result which--- is either: `SAFE` or `WARNING` with some reasonable error message when--- something goes wrong. All forms of errors/exceptions should go through--- here. The idea should be to report the error, the source position that--- causes it, generate a suitable .json file and then exit.---module Language.Haskell.Liquid.CmdLine (- -- * Get Command Line Configuration- getOpts, mkOpts-- -- * Update Configuration With Pragma- , withPragmas- , withCabal-- -- * Exit Function- , exitWithResult-- -- * Diff check mode- , diffcheck-) where--import Control.Applicative ((<$>))-import Control.Monad-import Data.Maybe-import System.Directory-import System.Exit-import System.Environment--import System.Console.CmdArgs.Explicit-import System.Console.CmdArgs.Implicit hiding (Loud)-import System.Console.CmdArgs.Text--import Data.List (intercalate, nub)-import Data.Monoid--import System.FilePath (dropFileName, isAbsolute,- takeDirectory, (</>))--import Language.Fixpoint.Config hiding (Config, real, native, getOpts)-import Language.Fixpoint.Files-import Language.Fixpoint.Misc-import Language.Fixpoint.Names (dropModuleNames)-import Language.Fixpoint.Types hiding (Result)-import Language.Haskell.Liquid.Annotate-import Language.Haskell.Liquid.GhcMisc-import Language.Haskell.Liquid.Misc-import Language.Haskell.Liquid.PrettyPrint-import Language.Haskell.Liquid.Types hiding (config, name, typ)-import Language.Haskell.Liquid.Errors-import Language.Haskell.Liquid.Cabal--import Text.Parsec.Pos (newPos)-import Text.PrettyPrint.HughesPJ hiding (Mode)--------------------------------------------------------------------------------------- Parsing Command Line----------------------------------------------------------------------------------------------------------------------------------------------config = cmdArgsMode $ Config {- files- = def &= typ "TARGET"- &= args- &= typFile-- , idirs- = def &= typDir- &= help "Paths to Spec Include Directory "-- , fullcheck- = def- &= help "Full Checking: check all binders (DEFAULT)"-- , diffcheck- = def- &= help "Incremental Checking: only check changed binders"-- , real- = def- &= help "Supports real number arithmetic"- , native- = def &= help "Use native (Haskell) fixpoint constraint solver"-- , binders- = def &= help "Check a specific set of binders"-- , noPrune- = def &= help "Disable prunning unsorted Predicates"- &= name "no-prune-unsorted"-- , notermination- = def &= help "Disable Termination Check"- &= name "no-termination-check"-- , nowarnings- = def &= help "Don't display warnings, only show errors"- &= name "no-warnings"-- , trustinternals- = def &= help "Trust all ghc auto generated code"- &= name "trust-interals"-- , nocaseexpand- = def &= help "Disable Termination Check"- &= name "no-case-expand"- , strata- = def &= help "Enable Strata Analysis"-- , notruetypes- = def &= help "Disable Trueing Top Level Types"- &= name "no-true-types"-- , totality- = def &= help "Check totality"-- , smtsolver- = def &= help "Name of SMT-Solver"-- , noCheckUnknown- = def &= explicit- &= name "no-check-unknown"- &= help "Don't complain about specifications for unexported and unused values "-- , maxParams- = 2 &= help "Restrict qualifier mining to those taking at most `m' parameters (2 by default)"-- , shortNames- = def &= name "short-names"- &= help "Print shortened names, i.e. drop all module qualifiers."-- , shortErrors- = def &= name "short-errors"- &= help "Don't show long error messages, just line numbers."-- , cabalDir- = def &= name "cabal-dir"- &= help "Find and use .cabal to add paths to sources for imported files"-- , ghcOptions- = def &= name "ghc-option"- &= typ "OPTION"- &= help "Pass this option to GHC"-- , cFiles- = def &= name "c-files"- &= typ "OPTION"- &= help "Tell GHC to compile and link against these files"-- } &= verbosity- &= program "liquid"- &= help "Refinement Types for Haskell"- &= summary copyright- &= details [ "LiquidHaskell is a Refinement Type based verifier for Haskell"- , ""- , "To check a Haskell file foo.hs, type:"- , " liquid foo.hs "- ]--getOpts :: IO Config-getOpts = do- cfg0 <- envCfg- cfg1 <- mkOpts =<< cmdArgsRun' config- cfg <- fixConfig $ mconcat [cfg0, cfg1]- whenNormal $ putStrLn copyright- case smtsolver cfg of- Just _ -> return cfg- Nothing -> do smts <- mapM findSmtSolver [Z3, Cvc4, Mathsat]- case catMaybes smts of- (s:_) -> return (cfg {smtsolver = Just s})- _ -> exitWithPanic noSmtError- where- noSmtError = "LiquidHaskell requires an SMT Solver, i.e. z3, cvc4, or mathsat to be installed."--cmdArgsRun' :: Mode (CmdArgs a) -> IO a-cmdArgsRun' mode- = do parseResult <- process mode <$> getArgs- case parseResult of- Left err ->- putStrLn (help err) >> exitFailure- Right args ->- cmdArgsApply args- where- help err = showText defaultWrap $ helpText [err] HelpFormatDefault mode--findSmtSolver :: SMTSolver -> IO (Maybe SMTSolver)-findSmtSolver smt = maybe Nothing (const $ Just smt) <$> findExecutable (show smt)--fixConfig :: Config -> IO Config-fixConfig cfg = do- pwd <- getCurrentDirectory- cfg <- canonicalizePaths pwd cfg- -- cfg <- withCabal cfg- return $ fixDiffCheck cfg---- | Attempt to canonicalize all `FilePath's in the `Config' so we don't have--- to worry about relative paths.-canonicalizePaths :: FilePath -> Config -> IO Config-canonicalizePaths pwd cfg = do- tgt <- canonicalizePath pwd- isdir <- doesDirectoryExist tgt- is <- mapM (canonicalize tgt isdir) $ idirs cfg- cs <- mapM (canonicalize tgt isdir) $ cFiles cfg- return $ cfg { idirs = is, cFiles = cs }--canonicalize :: FilePath -> Bool -> FilePath -> IO FilePath-canonicalize tgt isdir f- | isAbsolute f = return f- | isdir = canonicalizePath (tgt </> f)- | otherwise = canonicalizePath (takeDirectory tgt </> f)--fixDiffCheck :: Config -> Config-fixDiffCheck cfg = cfg { diffcheck = diffcheck cfg && not (fullcheck cfg) }--envCfg = do so <- lookupEnv "LIQUIDHASKELL_OPTS"- case so of- Nothing -> return mempty- Just s -> parsePragma $ envLoc s- where- envLoc = Loc l l- l = newPos "ENVIRONMENT" 0 0--copyright = "LiquidHaskell Copyright 2009-15 Regents of the University of California. All Rights Reserved.\n"--mkOpts :: Config -> IO Config-mkOpts cfg- = do let files' = sortNub $ files cfg- id0 <- getIncludeDir- return $ cfg { files = files' }- { idirs = (dropFileName <$> files') ++ [id0 </> gHC_VERSION, id0] ++ idirs cfg }- -- tests fail if you flip order of idirs'-------------------------------------------------------------------------------------------- | Updating options----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------withPragmas :: Config -> FilePath -> [Located String] -> IO Config-----------------------------------------------------------------------------------------withPragmas cfg fp ps = foldM withPragma cfg ps >>= canonicalizePaths fp--withPragma :: Config -> Located String -> IO Config-withPragma c s = (c `mappend`) <$> parsePragma s--parsePragma :: Located String -> IO Config-parsePragma s = withArgs [val s] $ cmdArgsRun config------------------------------------------------------------------------------------------withCabal :: Config -> IO Config-----------------------------------------------------------------------------------------withCabal cfg- | cabalDir cfg = withCabal' cfg- | otherwise = return cfg--withCabal' cfg = do- whenLoud $ putStrLn $ "addCabalDirs: " ++ tgt- io <- cabalInfo tgt- case io of- Just i -> return $ fixCabalDirs' cfg i- Nothing -> exitWithPanic "Cannot find .cabal information!"- where- tgt = case files cfg of- f:_ -> f- _ -> exitWithPanic "Please provide a target file to verify."---fixCabalDirs' :: Config -> Info -> Config-fixCabalDirs' cfg i = cfg { idirs = nub $ idirs cfg ++ sourceDirs i ++ buildDirs i }- { ghcOptions = ghcOptions cfg ++ dbOpts ++ pkOpts- ++ ["-optP-include", "-optP" ++ macroPath i]}- where- dbOpts = ["-package-db " ++ db | db <- packageDbs i]- pkOpts = ["-package " ++ n | n <- packageDeps i] -- SPEED HIT for smaller benchmarks---------------------------------------------------------------------------------------------- | Monoid instances for updating options-------------------------------------------------------------------------------------------instance Monoid Config where- mempty = Config def def def def def def def def def def def def def def def def 2 def def def def def def- mappend c1 c2 = Config { files = sortNub $ files c1 ++ files c2- , idirs = sortNub $ idirs c1 ++ idirs c2- , fullcheck = fullcheck c1 || fullcheck c2- , real = real c1 || real c2- , diffcheck = diffcheck c1 || diffcheck c2- , native = native c1 || native c2- , binders = sortNub $ binders c1 ++ binders c2- , noCheckUnknown = noCheckUnknown c1 || noCheckUnknown c2- , notermination = notermination c1 || notermination c2- , nowarnings = nowarnings c1 || nowarnings c2- , trustinternals = trustinternals c1 || trustinternals c2- , nocaseexpand = nocaseexpand c1 || nocaseexpand c2- , strata = strata c1 || strata c2- , notruetypes = notruetypes c1 || notruetypes c2- , totality = totality c1 || totality c2- , noPrune = noPrune c1 || noPrune c2- , maxParams = maxParams c1 `max` maxParams c2- , smtsolver = smtsolver c1 `mappend` smtsolver c2- , shortNames = shortNames c1 || shortNames c2- , shortErrors = shortErrors c1 || shortErrors c2- , cabalDir = cabalDir c1 || cabalDir c2- , ghcOptions = ghcOptions c1 ++ ghcOptions c2- , cFiles = cFiles c1 ++ cFiles c2- }--instance Monoid SMTSolver where- mempty = def- mappend s1 s2- | s1 == s2 = s1- | s2 == def = s1- | otherwise = s2------------------------------------------------------------------------------ | Exit Function ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------exitWithResult :: Config -> FilePath -> Output Doc -> IO (Output Doc)--------------------------------------------------------------------------exitWithResult cfg target out- = do {-# SCC "annotate" #-} annotate cfg target out- donePhase Loud "annotate"- writeCheckVars $ o_vars out- writeResult cfg (colorResult r) r- writeFile (extFileName Result target) (showFix r)- return $ out { o_result = r }- where- r = o_result out `addErrors` o_errors out---writeCheckVars Nothing = return ()-writeCheckVars (Just []) = colorPhaseLn Loud "Checked Binders: None" ""-writeCheckVars (Just ns) = colorPhaseLn Loud "Checked Binders:" "" >> forM_ ns (putStrLn . symbolString . dropModuleNames . symbol)--writeResult cfg c = mapM_ (writeDoc c) . zip [0..] . resDocs tidy- where- tidy = if shortErrors cfg then Lossy else Full- writeDoc c (i, d) = writeBlock c i $ lines $ render d- writeBlock _ _ [] = return ()- writeBlock c 0 ss = forM_ ss (colorPhaseLn c "")- writeBlock _ _ ss = forM_ ("\n" : ss) putStrLn--resDocs _ Safe = [text "SAFE"]-resDocs k (Crash xs s) = text ("ERROR: " ++ s) : pprManyOrdered k "" (errToFCrash <$> xs)-resDocs k (Unsafe xs) = text "UNSAFE" : pprManyOrdered k "" (nub xs)-resDocs _ (UnknownError d) = [text $ "PANIC: Unexpected Error: " ++ d, reportUrl]--reportUrl = text "Please submit a bug report at: https://github.com/ucsd-progsys/liquidhaskell"---addErrors r [] = r-addErrors Safe errs = Unsafe errs-addErrors (Unsafe xs) errs = Unsafe (xs ++ errs)-addErrors r _ = r-instance Fixpoint (FixResult Error) where- toFix = vcat . resDocs Full
+ src/Language/Haskell/Liquid/Constraint/Axioms.hs view
@@ -0,0 +1,569 @@+{-# LANGUAGE DeriveFoldable #-}+{-# LANGUAGE DeriveTraversable #-}+{-# LANGUAGE StandaloneDeriving #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE NoMonomorphismRestriction #-}+{-# LANGUAGE TypeSynonymInstances #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE TupleSections #-}+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE PatternGuards #-}+{-# LANGUAGE DeriveFunctor #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}++module Language.Haskell.Liquid.Constraint.Axioms (++ expandProofs++ -- * Combining proofs+ , makeCombineType+ , makeCombineVar++ ) where+++import Prelude hiding (error)++import Literal++import Coercion+import DataCon+import CoreSyn+import Type+import TyCon+import TypeRep+import Var+import Name+import NameSet++import Text.PrettyPrint.HughesPJ hiding (first, sep)+import Control.Monad.State+import qualified Data.List as L+import qualified Data.HashMap.Strict as M+import Data.Maybe (fromJust)+import Language.Fixpoint.Types.Names+import Language.Fixpoint.Utils.Files++import qualified Language.Fixpoint.Types as F++import Language.Haskell.Liquid.UX.Tidy (panicError)+import Language.Haskell.Liquid.Types.Visitors (freeVars)+import Language.Haskell.Liquid.Types hiding (binds, Loc, loc, freeTyVars, Def, HAxiom)+import qualified Language.Haskell.Liquid.Types as T+import Language.Haskell.Liquid.WiredIn+import Language.Haskell.Liquid.Types.RefType+import Language.Haskell.Liquid.Types.Visitors hiding (freeVars)+import Language.Haskell.Liquid.GHC.Misc+import Language.Haskell.Liquid.GHC.SpanStack (showSpan)+import Language.Fixpoint.Misc hiding (errorstar)+import Language.Haskell.Liquid.Constraint.ProofToCore+import Language.Haskell.Liquid.Transforms.CoreToLogic+import Language.Haskell.Liquid.Constraint.Types++import System.IO.Unsafe++import Language.Haskell.Liquid.Prover.Types (Axiom(..), Query(..))+import qualified Language.Haskell.Liquid.Prover.Types as P+import Language.Haskell.Liquid.Prover.Solve (solve)+++import qualified Data.HashSet as S++++class Provable a where++ expandProofs :: GhcInfo -> [(F.Symbol, SpecType)] -> a -> CG a+ expandProofs info sigs x =+ do (x, s) <- runState (expProofs x) <$> initAEEnv info sigs+ modify $ \st -> st {freshIndex = ae_index s}+ return x++ expProofs :: a -> Pr a+ expProofs = return+++instance Provable CoreBind where+ -- expProofs (NonRec x e) | returnsProof x = (\e -> Rec [(traceShow ("\n\nMake it Rec\n\n" ++ show (F.symbol x)) x,e)]) <$> (addRec (x,e) >> expProofs e)+ expProofs (NonRec x e) =+ do e' <- addRec (x,e) >> expProofs e+ if x `elem` freeVars S.empty e'+ then return $ Rec [(x, e')]+ else return $ NonRec x e'+ expProofs (Rec xes) = Rec <$> (addRecs xes >> mapSndM expProofs xes)+++instance Provable CoreExpr where+ expProofs ee@(App (App (Tick _ (Var f)) i) e) | isAuto f = grapInt i >>= expandAutoProof ee e+ expProofs ee@(App (App (Var f) i) e) | isAuto f = grapInt i >>= expandAutoProof ee e+ expProofs ee@(App (Tick _ (App (Tick _ (Var f)) i)) e) | isAuto f = grapInt i >>= expandAutoProof ee e+ expProofs ee@(App (Tick _ (App (Var f) i)) e) | isAuto f = grapInt i >>= expandAutoProof ee e+++ expProofs ee@(App (App (Tick _ (Var f)) i) e) | isCases f = grapInt i >>= expandCasesProof ee e+ expProofs ee@(App (App (Var f) i) e) | isCases f = grapInt i >>= expandCasesProof ee e+ expProofs ee@(App (Tick _ (App (Tick _ (Var f)) i)) e) | isCases f = grapInt i >>= expandCasesProof ee e+ expProofs ee@(App (Tick _ (App (Var f) i)) e) | isCases f = grapInt i >>= expandCasesProof ee e++ expProofs (App e1 e2) = liftM2 App (expProofs e1) (expProofs e2)+ expProofs (Lam x e) = addVar x >> liftM (Lam x) (expProofs e)+ expProofs (Let b e) = do b' <- expProofs b+ addBind b'+ liftM (Let b') (expProofs e)+ expProofs (Case e v t alts) = liftM2 (\e -> Case e v t) (expProofs e) (mapM (expProofsCase e) alts)+ expProofs (Cast e c) = liftM (`Cast` c) (expProofs e)+ expProofs (Tick t e) = liftM (Tick t) (expProofs e)++ expProofs (Var v) = return $ Var v+ expProofs (Lit l) = return $ Lit l+ expProofs (Type t) = return $ Type t+ expProofs (Coercion c) = return $ Coercion c++++expProofsCase :: CoreExpr -> CoreAlt -> Pr CoreAlt+expProofsCase (Var x) (DataAlt c, xs, e)+ = do addVars xs+ t <- L.lookup (symbol c) . ae_sigs <$> get+ addAssert $ makeRefinement t (x:xs)+ res <- liftM (DataAlt c,xs,) (expProofs e)+ rmAssert+ return res++expProofsCase _ (c, xs, e)+ = addVars xs >> liftM (c,xs,) (expProofs e)+++instance Provable CoreAlt where+ expProofs (c, xs, e) = addVars xs >> liftM (c,xs,) (expProofs e)++expandCasesProof :: CoreExpr -> CoreExpr -> Integer -> Pr CoreExpr+expandCasesProof inite e it+ = do vs <- reverse . ae_vars <$> get+ case L.find (isAlgType . varType) vs of+ Nothing -> return inite+ Just v -> makeCases v inite e it++makeDataCons v = data_cons $ algTyConRhs tc+ where+ t = varType v+ tc = fst $ splitTyConApp t++makeCases v inite e it = Case (Var v) v (varType v) <$> (mapM go $ makeDataCons v)+ where+ go c = do xs <- makeDataConArgs v c+ addVars xs+ t <- L.lookup (symbol c) . ae_sigs <$> get+ addAssert $ makeRefinement t (v:xs)+ proof <- expandAutoProof inite (e) it+ rmAssert+ return (DataAlt c, xs, proof)++makeDataConArgs v dc = mapM freshVar ts+ where+ ts = dataConInstOrigArgTys dc ats+ ats = snd $ splitTyConApp $ varType v+++expandAutoProof :: CoreExpr -> CoreExpr -> Integer -> Pr CoreExpr+expandAutoProof inite e it+ = do ams <- ae_axioms <$> get+ vs' <- ae_vars <$> get+ cts <- ae_consts <$> get+ ds <- ae_assert <$> get+ cmb <- ae_cmb <$> get+ lmap <- ae_lmap <$> get+ isHO <- ae_isHO <$> get + e' <- unANFExpr e++ foldM (\lm x -> (updateLMap lm (dummyLoc $ F.symbol x) x >> (ae_lmap <$> get))) lmap vs'++ let (vs, vlits) = L.partition (`elem` readVars e') $ nub' vs'+ let allvs = nub' ((fst . aname <$> ams) ++ cts ++ vs')+ let (cts', vcts) = L.partition (isFunctionType . varType) allvs+ let usedVs = nub' (vs++vcts)++ env <- makeEnvironment ((L.\\) allvs usedVs) ((L.\\) vlits usedVs)+ ctors <- mapM makeCtor cts'+ pvs <- mapM makeVar usedVs+ le <- makeGoalPredicate e'+ fn <- freshFilePath+ axioms <- makeAxioms+ let sol = unsafePerformIO (solve $ makeQuery fn it isHO le axioms ctors ds env pvs)+ return $ {-+ traceShow (+ "\n\nTo prove\n" ++ show (showpp le) +++ "\n\nWe need \n" ++ show sol +++ "\n\nExpr = \n" ++ show (toCore cmb inite sol) +++ "\n\n"+ ) $ -}+ traceShow "\nexpandedExpr\n" $ toCore cmb inite sol++nub' = L.nubBy (\v1 v2 -> F.symbol v1 == F.symbol v2)++-- TODO: merge this with the Bare.Axiom.hs+updateLMap :: LogicMap -> LocSymbol -> Var -> Pr ()+updateLMap _ _ v | not (isFun $ varType v)+ = return ()+ where+ isFun (FunTy _ _) = True+ isFun (ForAllTy _ t) = isFun t+ isFun _ = False++updateLMap _ x vv+ = insertLogicEnv x' ys (F.eApps (F.EVar $ val x) (F.EVar <$> ys))+ where+ nargs = dropWhile isClassType $ ty_args $ toRTypeRep $ ((ofType $ varType vv) :: RRType ())++ ys = zipWith (\i _ -> symbol (("x" ++ show i) :: String)) [1..] nargs+ x' = simpleSymbolVar vv++insertLogicEnv x ys e+ = modify $ \be -> be {ae_lmap = (ae_lmap be) {logic_map = M.insert x (LMap x ys e) $ logic_map $ ae_lmap be}}++simpleSymbolVar x = dropModuleNames $ symbol $ showPpr $ getName x++-------------------------------------------------------------------------------+---------------- From Haskell to Prover ------------------------------------+-------------------------------------------------------------------------------++++++makeEnvironment :: [Var] -> [Var] -> Pr [P.LVar]+makeEnvironment avs vs+ = do lits <- ae_lits <$> get+ let lts' = filter (\(x,_) -> not (x `elem` (F.symbol <$> avs))) (normalize lits)+ let lts1 = [P.Var x s () | (x, s) <- lts']+ lts2 <- mapM makeLVar vs+ return (lts1 ++ lts2)++++makeQuery :: FilePath -> Integer -> Bool -> F.Expr -> [HAxiom] -> [HVarCtor] -> [F.Expr] -> [P.LVar] -> [HVar] -> HQuery+makeQuery fn i isHO p axioms cts ds env vs + = Query { q_depth = fromInteger i+ , q_goal = P.Pred p++ , q_vars = checkVar <$> vs -- local variables+ , q_ctors = cts -- constructors: globals with function type+ , q_env = checkEnv <$> env -- environment: anything else that can appear in the logic++ , q_fname = fn+ , q_axioms = axioms+ , q_decls = (P.Pred <$> ds)+ , q_isHO = isHO + }++checkEnv pv@(P.Var x s _)+ | isBaseSort s = pv+ | otherwise = panic Nothing ("\nEnv:\nNon Basic " ++ show x ++ " :: " ++ show s)++checkVar pv@(P.Var x s _)+ | isBaseSort s = pv+ | otherwise = panic Nothing ("\nVar:\nNon Basic " ++ show x ++ " :: " ++ show s)++makeAxioms =+ do recs <- ae_recs <$> get+ tce <- ae_emb <$> get+ sigs <- ae_sigs <$> get+ gs <- ae_globals <$> get+ let (rgs, gs') = L.partition (`elem` (fst <$> recs)) $ filter returnsProof gs+ let as1 = varToPAxiom tce sigs <$> gs'+ let as2 = varToPAxiomWithGuard tce sigs recs <$> rgs+ return (as1 ++ as2)++unANFExpr e = (foldl (flip Let) e . ae_binds) <$> get++makeGoalPredicate e =+ do lm <- ae_lmap <$> get+ tce <- ae_emb <$> get+ case runToLogic tce lm (ErrOther (showSpan "makeGoalPredicate") . text) (coreToPred e) of+ Left p -> return p+ Right err -> panicError err++makeRefinement :: Maybe SpecType -> [Var] -> F.Expr+makeRefinement Nothing _ = F.PTrue+makeRefinement (Just t) xs = rr+ where trep = toRTypeRep t+ ys = [x | (x, t') <- zip (ty_binds trep) (ty_args trep), not (isClassType t')]+ rr = case stripRTypeBase $ ty_res trep of+ Nothing -> F.PTrue+ Just ref -> let F.Reft(v, r) = F.toReft ref+ su = F.mkSubst $ zip (v:ys) (F.EVar . F.symbol <$> xs)+ in F.subst su r++++makeCtor :: Var -> Pr HVarCtor+makeCtor c+ = do tce <- ae_emb <$> get+ sigs <- ae_sigs <$> get+ lmap <- ae_lmap <$> get+ lvs <- ae_vars <$> get+ return $ makeCtor' tce lmap sigs (c `elem` lvs) c++makeCtor' :: F.TCEmb TyCon -> LogicMap -> [(F.Symbol, SpecType)] -> Bool -> Var -> HVarCtor+makeCtor' tce _ _ islocal v | islocal+ = P.VarCtor (P.Var (F.symbol v) (typeSort tce $ varType v) v) [] (P.Pred F.PTrue)++makeCtor' tce lmap sigs _ v+ = case M.lookup v (axiom_map lmap) of+ Nothing -> P.VarCtor (P.Var (F.symbol v) (typeSort tce $ varType v) v) vs r+ Just x -> P.VarCtor (P.Var x (typeSort tce $ varType v) v) [] (P.Pred F.PTrue)++ where+ x = F.symbol v+ (vs, r) = case L.lookup x sigs of+ Nothing -> ([], P.Pred F.PTrue)+ Just t -> let trep = toRTypeRep t+ in case stripRTypeBase $ ty_res trep of+ Nothing -> ([], P.Pred F.PTrue)+ Just r -> let (F.Reft(v, p)) = F.toReft r+ xts = [(x,t) | (x, t) <- zip (ty_binds trep) (ty_args trep), not $ isClassType t]+ e = F.mkEApp (dummyLoc x) (F.EVar . fst <$> xts)+ in ([P.Var x (rTypeSort tce t) () | (x, t) <- xts], P.Pred $ F.subst1 p (v, e))++makeVar :: Var -> Pr HVar+makeVar v = do {tce <- ae_emb <$> get; return $ makeVar' tce v}++makeVar' tce v = P.Var (F.symbol v) (typeSort tce $ varType v) v++makeLVar :: Var -> Pr P.LVar+makeLVar v = do {tce <- ae_emb <$> get; return $ makeLVar' tce v}++makeLVar' tce v = P.Var (F.symbol v) (typeSort tce $ varType v) ()++++varToPAxiomWithGuard :: F.TCEmb TyCon -> [(Symbol, SpecType)] -> [(Var, [Var])] -> Var -> HAxiom+varToPAxiomWithGuard tce sigs recs v+ = P.Axiom { axiom_name = makeVar' tce v+ , axiom_vars = vs+ , axiom_body = P.Pred $ F.PImp q bd+ }+ where+ q = makeGuard $ zip (symbol <$> args) xts+ args = fromJust $ L.lookup v recs+ x = F.symbol v+ (vs, xts, bd) = case L.lookup x sigs of+ Nothing -> panic Nothing ("haxiomToPAxiom: " ++ show x ++ " not found")+ Just t -> let trep = toRTypeRep t+ bd' = case stripRTypeBase $ ty_res trep of+ Nothing -> F.PTrue+ Just r -> let (F.Reft(_, p)) = F.toReft r in p+ xts = filter (not . isClassType . snd) $ zip (ty_binds trep) (ty_args trep)+ vs' = [P.Var x (rTypeSort tce t) () | (x, t) <- xts]+ in (vs', xts, bd')++makeGuard :: [(F.Symbol, (F.Symbol, SpecType))] -> F.Expr+makeGuard xs = F.POr $ go [] xs+ where+ go _ []+ = []+ go acc ((x, (x', RApp c _ _ _)):xxs)+ | Just f <- sizeFunction $ rtc_info c+ = (F.PAnd (F.PAtom F.Lt (f x') (f x):acc)) : go (F.PAtom F.Le (f x') (f x):acc) xxs+ go acc (_:xxs)+ = go acc xxs+++varToPAxiom :: F.TCEmb TyCon -> [(Symbol, SpecType)] -> Var -> HAxiom+varToPAxiom tce sigs v+ = P.Axiom { axiom_name = makeVar' tce v+ , axiom_vars = vs+ , axiom_body = P.Pred bd+ }+ where+ x = F.symbol v+ (vs, bd) = case L.lookup x sigs of+ Nothing -> panic Nothing ("haxiomToPAxiom: " ++ show x ++ " not found")+ Just t -> let trep = toRTypeRep t+ bd' = case stripRTypeBase $ ty_res trep of+ Nothing -> F.PTrue+ Just r -> let (F.Reft(_, p)) = F.toReft r in p+ vs' = [P.Var x (rTypeSort tce t) () | (x, t) <- zip (ty_binds trep) (ty_args trep), not $ isClassType t]+ in (vs', bd')+++-------------------------------------------------------------------------------+------------- Proof State Environment ----------------------------------------+-------------------------------------------------------------------------------++type Pr = State AEnv++data AEnv = AE { ae_axioms :: [T.HAxiom] -- axiomatized functions+ , ae_binds :: [CoreBind] -- local bindings, tracked st they are expanded in logic+ , ae_lmap :: LogicMap -- logical mapping+ , ae_consts :: [Var] -- Data constructors and imported variables+ , ae_globals :: [Var] -- Global definitions, like axioms+ , ae_vars :: [Var] -- local variables in scope+ , ae_emb :: F.TCEmb TyCon -- type constructor information+ , ae_lits :: [(Symbol, F.Sort)] -- literals+ , ae_index :: Integer -- unique integer+ , ae_sigs :: [(Symbol, SpecType)] -- Refined type signatures+ , ae_target :: FilePath -- file name of target source coude+ , ae_recs :: [(Var, [Var])] -- axioms that are used recursively:+ -- these axioms are guarded to used only with "smaller" arguments+ , ae_assert :: [F.Expr] --+ , ae_cmb :: CoreExpr -> CoreExpr -> CoreExpr -- how to combine proofs+ , ae_isHO :: Bool -- allow higher order binders + }+++initAEEnv info sigs+ = do tce <- tyConEmbed <$> get+ lts <- lits <$> get+ i <- freshIndex <$> get+ modify $ \s -> s{freshIndex = i + 1}+ return $ AE { ae_axioms = axioms spc+ , ae_binds = []+ , ae_lmap = logicMap spc+ , ae_consts = L.nub vs+ , ae_globals = L.nub tp+ , ae_vars = []+ , ae_emb = tce+ , ae_lits = wiredSortedSyms ++ lts+ , ae_index = i+ , ae_sigs = sigs+ , ae_target = target info+ , ae_recs = []+ , ae_assert = []+ , ae_cmb = \x y -> (App (App (Var by) x) y)+ , ae_isHO = higherorder $ config spc + }+ where+ spc = spec info+ vs = filter validVar (snd <$> freeSyms spc)+ tp = filter validExp (defVars info)++ isExported = flip elemNameSet (exports $ spec info) . getName+ validVar = not . canIgnore+ validExp x = validVar x && isExported x+ by = makeCombineVar $ makeCombineType τProof+ τProof = proofType $ spec info+++++addBind b = modify $ \ae -> ae{ae_binds = b:ae_binds ae}+addAssert p = modify $ \ae -> ae{ae_assert = p:ae_assert ae}+rmAssert = modify $ \ae -> ae{ae_assert = tail $ ae_assert ae}+addRec (x,e) = modify $ \ae -> ae{ae_recs = (x, grapArgs e):ae_recs ae}+addRecs xes = modify $ \ae -> ae{ae_recs = [(x, grapArgs e) | (x, e) <- xes] ++ ae_recs ae}++addVar x | canIgnore x = return ()+ | otherwise = modify $ \ae -> ae{ae_vars = x:ae_vars ae}+++addVars x = modify $ \ae -> ae{ae_vars = x' ++ ae_vars ae}+ where+ x' = filter (not . canIgnore) x++getUniq :: Pr Integer+getUniq+ = do modify (\s -> s{ae_index = 1 + (ae_index s)})+ ae_index <$> get+++freshVar :: Type -> Pr Var+freshVar t =+ do n <- getUniq+ return $ stringVar ("x" ++ show n) t++freshFilePath :: Pr FilePath+freshFilePath =+ do fn <- ae_target <$> get+ n <- getUniq+ return $ (extFileName (Auto $ fromInteger n) fn)+++-------------------------------------------------------------------------------+-------------- Playing with Fixpoint ----------------------------------------+-------------------------------------------------------------------------------+++isBaseSort _ = True ++++-------------------------------------------------------------------------------+-------------- Playing with GHC Core ----------------------------------------+-------------------------------------------------------------------------------++-- hasBaseType = isBaseTy . varType++isFunctionType (FunTy _ _) = True+isFunctionType (ForAllTy _ t) = isFunctionType t+isFunctionType _ = False+++resultType (ForAllTy _ t) = resultType t+resultType (FunTy _ t) = resultType t+resultType t = t+++grapArgs (Lam x e) | isTyVar x = grapArgs e+grapArgs (Lam x e) | isClassPred $ varType x = grapArgs e+grapArgs (Lam x e) = x : grapArgs e+grapArgs (Let _ e) = grapArgs e+grapArgs _ = []++++grapInt (Var v)+ = do bs <- ae_binds <$> get+ let (e:_) = [ex | NonRec x ex <- bs, x == v]+ return $ go e+ where+ go (Tick _ e) = go e+ go (App _ l) = go l+ go (Lit l) = litToInt l+ go e = panic Nothing $ ("grapInt called with wrong argument " ++ showPpr e)++ litToInt (MachInt i) = i+ litToInt (MachInt64 i) = i+ litToInt _ = panic Nothing "litToInt: non integer literal"++grapInt (Tick _ e) = grapInt e+grapInt _ = return 2+++-------------------------------------------------------------------------------+-------------------- Combine Proofs ----------------------------------------+-------------------------------------------------------------------------------++makeCombineType Nothing+ = panic Nothing "proofType not found"+makeCombineType (Just τ)+ = FunTy τ (FunTy τ τ)+++makeCombineVar τ = stringVar combineProofsName τ+-------------------------------------------------------------------------------+------------------- Helper Functions ----------------------------------------+-------------------------------------------------------------------------------++canIgnore v = isInternal v || isTyVar v+isAuto v = isPrefixOfSym "auto" $ dropModuleNames $ F.symbol v+isCases v = isPrefixOfSym "cases" $ dropModuleNames $ F.symbol v+isProof v = isPrefixOfSym "Proof" $ dropModuleNames $ F.symbol v+++returnsProof :: Var -> Bool+returnsProof = isProof' . resultType . varType+ where+ isProof' (TyConApp tc _) = isProof tc+ isProof' _ = False+++normalize xts = filter hasBaseSort $ L.nub xts+ where+ hasBaseSort = isBaseSort . snd+++mapSndM act xys = mapM (\(x, y) -> (x,) <$> act y) xys
src/Language/Haskell/Liquid/Constraint/Constraint.hs view
@@ -1,49 +1,54 @@ {-# LANGUAGE TypeSynonymInstances #-} {-# LANGUAGE FlexibleInstances #-} -module Language.Haskell.Liquid.Constraint.Constraint where+-- TODO: what exactly is the purpose of this module? What do these functions do? -import Data.Monoid-import Data.Maybe-import Control.Applicative+module Language.Haskell.Liquid.Constraint.Constraint (+ constraintToLogic+, addConstraints+) where +import Prelude hiding (error)+import Data.Maybe import Language.Haskell.Liquid.Types import Language.Haskell.Liquid.Constraint.Types-+import Language.Haskell.Liquid.Constraint.Env import Language.Fixpoint.Types -instance Monoid LConstraint where- mempty = LC []- mappend (LC cs1) (LC cs2) = LC (cs1 ++ cs2)--typeToConstraint t = LC [t]--addConstraints t γ = γ {lcs = mappend (typeToConstraint t) (lcs γ)}+--------------------------------------------------------------------------------+addConstraints :: CGEnv -> [(Symbol, SpecType)] -> CGEnv+--------------------------------------------------------------------------------+addConstraints γ t = γ {lcs = mappend (t2c t) (lcs γ)}+ where+ t2c z = LC [z] -constraintToLogic γ (LC ts) = pAnd (constraintToLogicOne γ <$> ts)+--------------------------------------------------------------------------------+constraintToLogic :: REnv -> LConstraint -> Expr+--------------------------------------------------------------------------------+constraintToLogic γ (LC ts) = pAnd (constraintToLogicOne γ <$> ts) -constraintToLogicOne γ env- = pAnd [subConstraintToLogicOne- (zip xs xts)- (last xs,- (last $ (fst <$> xts), r))+-- RJ: The code below is atrocious. Please fix it!+constraintToLogicOne :: (Reftable r) => REnv -> [(Symbol, RRType r)] -> Expr+constraintToLogicOne γ binds+ = pAnd [subConstraintToLogicOne+ (zip xs xts)+ (last xs,+ (last (fst <$> xts), r)) | xts <- xss] where- xts = init env+ xts = init binds (xs, ts) = unzip xts- r = snd $ last env- xss = combinations ((\t -> [(x, t) | x <- grapBindsWithType t γ]) <$> ts)+ r = snd $ last binds+ xss = combinations ((\t -> [(x, t) | x <- localBindsOfType t γ]) <$> ts) subConstraintToLogicOne xts (x', (x, t)) = PImp (pAnd rs) r where (rs , su) = foldl go ([], []) xts ([r], _ ) = go ([], su) (x', (x, t))- go (acc, su) (x', (x, t)) = let (Reft(v, Refa p)) = toReft (fromMaybe mempty (stripRTypeBase t))- su' = (x', EVar x):(v, EVar x) : su+ go (acc, su) (x', (x, t)) = let (Reft(v, p)) = toReft (fromMaybe mempty (stripRTypeBase t))+ su' = (x', EVar x):(v, EVar x) : su in (subst (mkSubst su') p : acc, su')-- combinations :: [[a]] -> [[a]] combinations [] = [[]]
+ src/Language/Haskell/Liquid/Constraint/Env.hs view
@@ -0,0 +1,286 @@++{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE NoMonomorphismRestriction #-}+{-# LANGUAGE TypeSynonymInstances #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE TupleSections #-}+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE PatternGuards #-}+{-# LANGUAGE DeriveFunctor #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE ImplicitParams #-}+{-# LANGUAGE PartialTypeSignatures #-}++-- | This module defines the representation for Environments needed+-- during constraint generation.++module Language.Haskell.Liquid.Constraint.Env (++ -- * Insert+ (+++=)+ , (++=)+ , (+=)+ , extendEnvWithVV+ , addBinders+ , addSEnv+ , (-=)+ , globalize++ -- * Construction+ , fromListREnv+ , toListREnv+ , insertREnv -- TODO: remove this ASAP+ + -- * Query+ , localBindsOfType+ , lookupREnv+ , (?=)++ -- * Pruning refinements (TODO: move!)+ , rTypeSortedReft'++ -- * Extend CGEnv+ , setLocation, setBind, setRecs, setTRec++ -- * Lookup CGEnv+ , getLocation++) where+++-- import Name (getSrcSpan)+import Prelude hiding (error)+import CoreSyn (CoreExpr)+import SrcLoc+import Var+-- import Outputable+-- import FastString (fsLit)+import Control.Monad.State++-- import GHC.Err.Located hiding (error)+import GHC.Stack++import Control.Arrow (first)+import Data.Maybe -- (fromMaybe)+import qualified Data.List as L+import qualified Data.HashSet as S+import qualified Data.HashMap.Strict as M+import qualified Language.Fixpoint.Types as F+++import Language.Fixpoint.SortCheck (pruneUnsortedReft)++++import Language.Haskell.Liquid.Types.RefType+import qualified Language.Haskell.Liquid.GHC.SpanStack as Sp+import Language.Haskell.Liquid.Types hiding (binds, Loc, loc, freeTyVars, Def)+import Language.Haskell.Liquid.Constraint.Types+import Language.Haskell.Liquid.Constraint.Fresh+import Language.Haskell.Liquid.Transforms.RefSplit+import qualified Language.Haskell.Liquid.UX.CTags as Tg++-- import Debug.Trace (trace)++instance Freshable CG Integer where+ fresh = do s <- get+ let n = freshIndex s+ put $ s { freshIndex = n + 1 }+ return n++--------------------------------------------------------------------------------+-- | Refinement Type Environments ----------------------------------------------+--------------------------------------------------------------------------------++-- updREnvLocal :: REnv -> (_ -> _) -> REnv+updREnvLocal rE f = rE { reLocal = f (reLocal rE) }++-- RJ: REnv-Split-Bug?+filterREnv :: (SpecType -> Bool) -> REnv -> REnv+filterREnv f rE = rE `updREnvLocal` (M.filter f)++fromListREnv :: [(F.Symbol, SpecType)] -> [(F.Symbol, SpecType)] -> REnv+fromListREnv gXts lXts = REnv+ { reGlobal = M.fromList gXts+ , reLocal = M.fromList lXts+ }++-- RJ: REnv-Split-Bug?+deleteREnv :: F.Symbol -> REnv -> REnv+deleteREnv x rE = rE `updREnvLocal` (M.delete x)++insertREnv :: F.Symbol -> SpecType -> REnv -> REnv+insertREnv x y rE = {- trace ("insertREnv: " ++ show x) $ -} rE `updREnvLocal` (M.insert x y)++lookupREnv :: F.Symbol -> REnv -> Maybe SpecType+lookupREnv x rE = msum $ M.lookup x <$> renvMaps rE++memberREnv :: F.Symbol -> REnv -> Bool+memberREnv x rE = or $ M.member x <$> renvMaps rE++globalREnv :: REnv -> REnv+globalREnv (REnv gM lM) = REnv gM' M.empty+ where+ gM' = M.unionWith (\_ t -> t) gM lM++renvMaps rE = [reLocal rE, reGlobal rE]++--------------------------------------------------------------------------------+localBindsOfType :: RRType r -> REnv -> [F.Symbol]+--------------------------------------------------------------------------------+localBindsOfType tx γ = fst <$> localsREnv (filterREnv ((== toRSort tx) . toRSort) γ)++-- RJ: REnv-Split-Bug?+localsREnv :: REnv -> [(F.Symbol, SpecType)]+localsREnv = M.toList . reLocal++globalsREnv :: REnv -> [(F.Symbol, SpecType)]+globalsREnv = M.toList . reGlobal++toListREnv :: REnv -> [(F.Symbol, SpecType)]+toListREnv re = globalsREnv re ++ localsREnv re++--------------------------------------------------------------------------------+extendEnvWithVV :: CGEnv -> SpecType -> CG CGEnv+--------------------------------------------------------------------------------+extendEnvWithVV γ t+ | F.isNontrivialVV vv && not (vv `memberREnv` (renv γ))+ = (γ, "extVV") += (vv, t)+ | otherwise+ = return γ+ where+ vv = rTypeValueVar t++addBinders :: CGEnv -> F.Symbol -> [(F.Symbol, SpecType)] -> CG CGEnv+addBinders γ0 x' cbs = foldM (++=) (γ0 -= x') [("addBinders", x, t) | (x, t) <- cbs]++addBind :: SrcSpan -> F.Symbol -> F.SortedReft -> CG ((F.Symbol, F.Sort), F.BindId)+addBind l x r = do+ st <- get+ let (i, bs') = F.insertBindEnv x r (binds st)+ put $ st { binds = bs' } { bindSpans = M.insert i l (bindSpans st) }+ return ((x, F.sr_sort r), i) -- traceShow ("addBind: " ++ showpp x) i++addClassBind :: SrcSpan -> SpecType -> CG [((F.Symbol, F.Sort), F.BindId)]+addClassBind l = mapM (uncurry (addBind l)) . classBinds++{- see tests/pos/polyfun for why you need everything in fixenv -}+addCGEnv :: (SpecType -> SpecType) -> CGEnv -> (String, F.Symbol, SpecType) -> CG CGEnv+addCGEnv tx γ (eMsg, x, REx y tyy tyx)+ = do y' <- fresh+ γ' <- addCGEnv tx γ (eMsg, y', tyy)+ addCGEnv tx γ' (eMsg, x, tyx `F.subst1` (y, F.EVar y'))++addCGEnv tx γ (eMsg, x, RAllE yy tyy tyx)+ = addCGEnv tx γ (eMsg, x, t)+ where+ xs = localBindsOfType tyy (renv γ)+ t = L.foldl' F.meet ttrue [ tyx' `F.subst1` (yy, F.EVar x) | x <- xs]+ (tyx', ttrue) = splitXRelatedRefs yy tyx++addCGEnv tx γ (_, x, t') = do+ idx <- fresh+ allowHOBinders <- allowHO <$> get + let t = tx $ normalize idx t'+ let l = getLocation γ+ let γ' = γ { renv = insertREnv x t (renv γ) }+ pflag <- pruneRefs <$> get+ is <- if allowHOBinders || isBase t + then (:) <$> addBind l x (rTypeSortedReft' pflag γ' t) <*> addClassBind l t + else return []+ return $ γ' { fenv = insertsFEnv (fenv γ) is }++rTypeSortedReft' pflag γ+ | pflag = pruneUnsortedReft (feEnv $ fenv γ) . f+ | otherwise = f+ where+ f = rTypeSortedReft (emb γ)++normalize idx = normalizeVV idx . normalizePds++normalizeVV idx t@(RApp _ _ _ _)+ | not (F.isNontrivialVV (rTypeValueVar t))+ = shiftVV t (F.vv $ Just idx)++normalizeVV _ t+ = t+++--------------------------------------------------------------------------------+(+=) :: (CGEnv, String) -> (F.Symbol, SpecType) -> CG CGEnv+--------------------------------------------------------------------------------+(γ, eMsg) += (x, r)+ | x == F.dummySymbol+ = return γ+ | x `memberREnv` (renv γ)+ = err+ | otherwise+ = γ ++= (eMsg, x, r)+ where err = panic Nothing $ eMsg ++ " Duplicate binding for "+ ++ F.symbolString x+ ++ "\n New: " ++ showpp r+ ++ "\n Old: " ++ showpp (x `lookupREnv` (renv γ))+++--------------------------------------------------------------------------------+globalize :: CGEnv -> CGEnv+--------------------------------------------------------------------------------+globalize γ = γ {renv = globalREnv (renv γ)}+++--------------------------------------------------------------------------------+(++=) :: CGEnv -> (String, F.Symbol, SpecType) -> CG CGEnv+--------------------------------------------------------------------------------+(++=) γ (eMsg, x, t)+ = -- trace ("++= " ++ show x) $+ addCGEnv (addRTyConInv (M.unionWith mappend (invs γ) (ial γ))) γ (eMsg, x, t)++--------------------------------------------------------------------------------+addSEnv :: CGEnv -> (String, F.Symbol, SpecType) -> CG CGEnv+--------------------------------------------------------------------------------+addSEnv γ = addCGEnv (addRTyConInv (invs γ)) γ++(+++=) :: (CGEnv, String) -> (F.Symbol, CoreExpr, SpecType) -> CG CGEnv+(γ, _) +++= (x, e, t) = (γ {lcb = M.insert x e (lcb γ) }, "+++=") += (x, t)++γ -= x = γ {renv = deleteREnv x (renv γ), lcb = M.delete x (lcb γ)}++(?=) :: (?callStack :: CallStack) => CGEnv -> F.Symbol -> Maybe SpecType+γ ?= x = lookupREnv x (renv γ)++------------------------------------------------------------------------+setLocation :: CGEnv -> Sp.Span -> CGEnv+------------------------------------------------------------------------+setLocation γ p = γ { cgLoc = Sp.push p $ cgLoc γ }++------------------------------------------------------------------------+setBind :: CGEnv -> Var -> CGEnv+------------------------------------------------------------------------+setBind γ x = γ `setLocation` Sp.Var x `setBind'` x++setBind' :: CGEnv -> Tg.TagKey -> CGEnv+setBind' γ k+ | Tg.memTagEnv k (tgEnv γ) = γ { tgKey = Just k }+ | otherwise = γ++------------------------------------------------------------------------+setRecs :: CGEnv -> [Var] -> CGEnv+------------------------------------------------------------------------+setRecs γ xs = γ { recs = L.foldl' (flip S.insert) (recs γ) xs }++------------------------------------------------------------------------+setTRec :: CGEnv -> [(Var, SpecType)] -> CGEnv+------------------------------------------------------------------------+setTRec γ xts = γ' {trec = Just $ M.fromList xts' `M.union` trec'}+ where+ γ' = γ `setRecs` (fst <$> xts)+ trec' = fromMaybe M.empty $ trec γ+ xts' = first F.symbol <$> xts++------------------------------------------------------------------------+getLocation :: CGEnv -> SrcSpan+------------------------------------------------------------------------+getLocation = Sp.srcSpan . cgLoc
+ src/Language/Haskell/Liquid/Constraint/Fresh.hs view
@@ -0,0 +1,142 @@+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TupleSections #-}+{-# LANGUAGE TypeSynonymInstances #-}+{-# LANGUAGE UndecidableInstances #-}++module Language.Haskell.Liquid.Constraint.Fresh (Freshable(..)) where++import Prelude hiding (error)+++import Language.Fixpoint.Types+import Language.Haskell.Liquid.Misc (single)+import Language.Haskell.Liquid.Types++class (Applicative m, Monad m) => Freshable m a where+ fresh :: m a+ true :: a -> m a+ true = return . id+ refresh :: a -> m a+ refresh = return . id++instance Freshable m Integer => Freshable m Symbol where+ fresh = tempSymbol "x" <$> fresh++instance Freshable m Integer => Freshable m Expr where+ fresh = kv <$> fresh+ where+ kv = (`PKVar` mempty) . intKvar++instance Freshable m Integer => Freshable m [Expr] where+ fresh = single <$> fresh++instance Freshable m Integer => Freshable m Reft where+ fresh = panic Nothing "fresh Reft"+ true (Reft (v,_)) = return $ Reft (v, mempty)+ refresh (Reft (_,_)) = (Reft .) . (,) <$> freshVV <*> fresh+ where+ freshVV = vv . Just <$> fresh++instance Freshable m Integer => Freshable m RReft where+ fresh = panic Nothing "fresh RReft"+ true (MkUReft r _ s) = MkUReft <$> true r <*> return mempty <*> true s+ refresh (MkUReft r _ s) = MkUReft <$> refresh r <*> return mempty <*> refresh s++instance Freshable m Integer => Freshable m Strata where+ fresh = (:[]) . SVar <$> fresh+ true [] = fresh+ true s = return s+ refresh [] = fresh+ refresh s = return s++instance (Freshable m Integer, Freshable m r, Reftable r, RefTypable RTyCon RTyVar r) => Freshable m (RRType r) where+ fresh = panic Nothing "fresh RefType"+ refresh = refreshRefType+ true = trueRefType++-----------------------------------------------------------------------------------------------+trueRefType :: (Freshable m Integer, Freshable m r, Reftable r, RefTypable RTyCon RTyVar r) => RRType r -> m (RRType r)+-----------------------------------------------------------------------------------------------+trueRefType (RAllT α t)+ = RAllT α <$> true t++trueRefType (RAllP π t)+ = RAllP π <$> true t++trueRefType (RFun _ t t' _)+ = rFun <$> fresh <*> true t <*> true t'++trueRefType (RApp c ts _ _) | isClass c+ = rRCls c <$> mapM true ts++trueRefType (RApp c ts rs r)+ = RApp c <$> mapM true ts <*> mapM trueRef rs <*> true r++trueRefType (RAppTy t t' _)+ = RAppTy <$> true t <*> true t' <*> return mempty++trueRefType (RVar a r)+ = RVar a <$> true r++trueRefType (RAllE y ty tx)+ = do y' <- fresh+ ty' <- true ty+ tx' <- true tx+ return $ RAllE y' ty' (tx' `subst1` (y, EVar y'))++trueRefType (RRTy e o r t)+ = RRTy e o r <$> trueRefType t++trueRefType t+ = return t++trueRef (RProp _ (RHole _)) = panic Nothing "trueRef: unexpected RProp _ (RHole _))"+trueRef (RProp s t) = RProp s <$> trueRefType t++++-----------------------------------------------------------------------------------------------+refreshRefType :: (Freshable m Integer, Freshable m r, Reftable r, RefTypable RTyCon RTyVar r) => RRType r -> m (RRType r)+-----------------------------------------------------------------------------------------------+refreshRefType (RAllT α t)+ = RAllT α <$> refresh t++refreshRefType (RAllP π t)+ = RAllP π <$> refresh t++refreshRefType (RFun b t t' _)+ | b == dummySymbol = rFun <$> fresh <*> refresh t <*> refresh t'+ | otherwise = rFun b <$> refresh t <*> refresh t'++refreshRefType (RApp rc ts _ _) | isClass rc+ = return $ rRCls rc ts++refreshRefType (RApp rc ts rs r)+ = RApp rc <$> mapM refresh ts <*> mapM refreshRef rs <*> refresh r++refreshRefType (RVar a r)+ = RVar a <$> refresh r++refreshRefType (RAppTy t t' r)+ = RAppTy <$> refresh t <*> refresh t' <*> refresh r++refreshRefType (RAllE y ty tx)+ = do y' <- fresh+ ty' <- refresh ty+ tx' <- refresh tx+ return $ RAllE y' ty' (tx' `subst1` (y, EVar y'))++refreshRefType (RRTy e o r t)+ = RRTy e o r <$> refreshRefType t++refreshRefType t+ = return t++refreshRef (RProp _ (RHole _)) = panic Nothing "refreshRef: unexpected (RProp _ (RHole _))"+refreshRef (RProp s t) = RProp <$> mapM freshSym s <*> refreshRefType t++freshSym (_, t) = (, t) <$> fresh
src/Language/Haskell/Liquid/Constraint/Generate.hs view
@@ -12,1927 +12,1395 @@ {-# LANGUAGE DeriveFunctor #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE OverloadedStrings #-}---- | This module defines the representation of Subtyping and WF Constraints, and--- the code for syntax-directed constraint generation.--module Language.Haskell.Liquid.Constraint.Generate (-- generateConstraints-- ) where--import CoreUtils (exprType)-import MkCore-import Coercion-import DataCon-import Pair-import CoreSyn-import SrcLoc-import Type-import TyCon-import PrelNames-import TypeRep-import Class (Class, className)-import Var-import Id-import IdInfo-import Name-import NameSet-import Text.PrettyPrint.HughesPJ hiding (first)--import Control.Monad.State--import Control.Applicative ((<$>), (<*>))--import Data.Monoid (mconcat, mempty, mappend)-import Data.Maybe (fromMaybe, catMaybes, fromJust, isJust)-import qualified Data.HashMap.Strict as M-import qualified Data.HashSet as S-import qualified Data.List as L-import qualified Data.Text as T-import Data.Bifunctor-import Data.List (foldl')-import qualified Data.Foldable as F-import qualified Data.Traversable as T--import Text.Printf--import qualified Language.Haskell.Liquid.CTags as Tg-import Language.Fixpoint.Sort (pruneUnsortedReft)-import Language.Fixpoint.Visitor--import Language.Haskell.Liquid.Fresh--import qualified Language.Fixpoint.Types as F--import Language.Haskell.Liquid.Names-import Language.Haskell.Liquid.Dictionaries-import Language.Haskell.Liquid.Variance-import Language.Haskell.Liquid.Types hiding (binds, Loc, loc, freeTyVars, Def)-import Language.Haskell.Liquid.Strata-import Language.Haskell.Liquid.Bounds-import Language.Haskell.Liquid.RefType-import Language.Haskell.Liquid.Visitors-import Language.Haskell.Liquid.PredType hiding (freeTyVars)-import Language.Haskell.Liquid.GhcMisc ( isInternal, collectArguments, tickSrcSpan- , hasBaseTypeVar, showPpr, isDataConId)-import Language.Haskell.Liquid.Misc-import Language.Fixpoint.Misc-import Language.Haskell.Liquid.Literals-import Language.Haskell.Liquid.RefSplit-import Control.DeepSeq--import Language.Haskell.Liquid.Constraint.Types-import Language.Haskell.Liquid.Constraint.Constraint---- import Debug.Trace (trace)--------------------------------------------------------------------------------------- Constraint Generation: Toplevel ---------------------------------------------------------------------------------------------------generateConstraints :: GhcInfo -> CGInfo-generateConstraints info = {-# SCC "ConsGen" #-} execState act $ initCGI cfg info- where- act = consAct info- cfg = config $ spec info---consAct info- = do γ <- initEnv info- sflag <- scheck <$> get- tflag <- trustghc <$> get- let trustBinding x = tflag && (x `elem` derVars info || isInternal x)- foldM_ (consCBTop trustBinding) γ (cbs info)- hcs <- hsCs <$> get- hws <- hsWfs <$> get- scss <- sCs <$> get- annot <- annotMap <$> get- scs <- if sflag then concat <$> mapM splitS (hcs ++ scss)- else return []- let smap = if sflag then solveStrata scs else []- let hcs' = if sflag then subsS smap hcs else hcs- fcs <- concat <$> mapM splitC (subsS smap hcs')- fws <- concat <$> mapM splitW hws- let annot' = if sflag then subsS smap <$> annot else annot- modify $ \st -> st { fixCs = fcs } { fixWfs = fws } {annotMap = annot'}---------------------------------------------------------------------------------------initEnv :: GhcInfo -> CG CGEnv--------------------------------------------------------------------------------------initEnv info- = do let tce = tcEmbeds sp- let fVars = impVars info- let dcs = filter isConLikeId ((snd <$> freeSyms sp))- let dcs' = filter isConLikeId fVars- defaults <- forM fVars $ \x -> liftM (x,) (trueTy $ varType x)- dcsty <- forM dcs $ \x -> liftM (x,) (trueTy $ varType x)- dcsty' <- forM dcs' $ \x -> liftM (x,) (trueTy $ varType x)- (hs,f0) <- refreshHoles $ grty info -- asserted refinements (for defined vars)- f0'' <- refreshArgs' =<< grtyTop info -- default TOP reftype (for exported vars without spec)- let f0' = if notruetypes $ config sp then [] else f0''- f1 <- refreshArgs' defaults -- default TOP reftype (for all vars)- f1' <- refreshArgs' $ makedcs dcsty- f2 <- refreshArgs' $ assm info -- assumed refinements (for imported vars)- f3 <- refreshArgs' $ vals asmSigs sp -- assumed refinedments (with `assume`)- f40 <- refreshArgs' $ vals ctors sp -- constructor refinements (for measures)- (invs1, f41) <- mapSndM refreshArgs' $ makeAutoDecrDataCons dcsty (autosize sp) dcs- (invs2, f42) <- mapSndM refreshArgs' $ makeAutoDecrDataCons dcsty' (autosize sp) dcs'- let f4 = mergeDataConTypes f40 (f41 ++ f42)- sflag <- scheck <$> get- let senv = if sflag then f2 else []- let tx = mapFst F.symbol . addRInv ialias . strataUnify senv . predsUnify sp- let bs = (tx <$> ) <$> [f0 ++ f0', f1 ++ f1', f2, f3, f4]- lts <- lits <$> get- let tcb = mapSnd (rTypeSort tce) <$> concat bs- let γ0 = measEnv sp (head bs) (cbs info) (tcb ++ lts) (bs!!3) hs (invs1 ++ invs2)- foldM (++=) γ0 [("initEnv", x, y) | (x, y) <- concat $ tail bs]- where- sp = spec info- ialias = mkRTyConIAl $ ialiases sp- vals f = map (mapSnd val) . f- mapSndM f (x,y) = (x,) <$> f y- makedcs = map strengthenDataConType--makeAutoDecrDataCons dcts specenv dcs- = (simplify invs, tys)- where- (invs, tys) = unzip $ concatMap go tycons- tycons = L.nub $ catMaybes $ map idTyCon dcs-- go tycon- | S.member tycon specenv = zipWith (makeSizedDataCons dcts) (tyConDataCons tycon) [0..]- go _- = []- idTyCon x = dataConTyCon <$> case idDetails x of {DataConWorkId d -> Just d; DataConWrapId d -> Just d; _ -> Nothing}-- simplify invs = dummyLoc . (`strengthen` invariant) . fmap (\_ -> mempty) <$> L.nub invs- invariant = U (F.Reft (F.vv_, F.Refa $ F.PAtom F.Ge (lenOf F.vv_) (F.ECon $ F.I 0)) ) mempty mempty--lenOf x = F.EApp lenLocSymbol [F.EVar x]--makeSizedDataCons dcts x' n = (toRSort $ ty_res trep, (x, fromRTypeRep trep{ty_res = tres}))- where- x = dataConWorkId x'- t = fromMaybe (errorstar "makeSizedDataCons: this should never happen") $ L.lookup x dcts- trep = toRTypeRep t- tres = ty_res trep `strengthen` U (F.Reft (F.vv_, F.Refa- $ F.PAtom F.Eq (lenOf F.vv_) computelen)) mempty mempty-- recarguments = filter (\(t,_) -> (toRSort t == toRSort tres)) (zip (ty_args trep) (ty_binds trep))- computelen = foldr (F.EBin F.Plus) (F.ECon $ F.I n) (lenOf . snd <$> recarguments)---mergeDataConTypes xts yts = merge (L.sortBy f xts) (L.sortBy f yts)- where- f (x,_) (y,_) = compare x y- merge [] ys = ys- merge xs [] = xs- merge (xt@(x, tx):xs) (yt@(y, ty):ys)- | x == y = (x, tx `F.meet` ty):merge xs ys- | x < y = xt:merge xs (yt:ys)- | otherwise = yt:merge (xt:xs) ys--refreshHoles vts = first catMaybes . unzip . map extract <$> mapM refreshHoles' vts-refreshHoles' (x,t)- | noHoles t = return (Nothing,x,t)- | otherwise = (Just $ F.symbol x,x,) <$> mapReftM tx t- where- tx r | hasHole r = refresh r- | otherwise = return r-extract (a,b,c) = (a,(b,c))--refreshArgs' = mapM (mapSndM refreshArgs)--strataUnify :: [(Var, SpecType)] -> (Var, SpecType) -> (Var, SpecType)-strataUnify senv (x, t) = (x, maybe t (mappend t) pt)- where- pt = fmap (\(U _ _ l) -> U mempty mempty l) <$> L.lookup x senv----- | TODO: All this *should* happen inside @Bare@ but appears--- to happen after certain are signatures are @fresh@-ed,--- which is why they are here.---- NV : still some sigs do not get TyConInfo--predsUnify :: GhcSpec -> (Var, RRType RReft) -> (Var, RRType RReft)-predsUnify sp = second (addTyConInfo tce tyi) -- needed to eliminate some @RPropH@-- where- tce = tcEmbeds sp- tyi = tyconEnv sp-- ---------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------- -----------------------------------------------------------------------------------------measEnv sp xts cbs lts asms hs autosizes- = CGE { loc = noSrcSpan- , renv = fromListREnv $ second val <$> meas sp- , syenv = F.fromListSEnv $ freeSyms sp- , fenv = initFEnv $ lts ++ (second (rTypeSort tce . val) <$> meas sp)- , denv = dicts sp- , recs = S.empty- , invs = mkRTyConInv $ (invariants sp ++ autosizes)- , ial = mkRTyConIAl $ ialiases sp- , grtys = fromListREnv xts- , assms = fromListREnv asms- , emb = tce- , tgEnv = Tg.makeTagEnv cbs- , tgKey = Nothing- , trec = Nothing- , lcb = M.empty- , holes = fromListHEnv hs- , lcs = mempty- }- where- tce = tcEmbeds sp--assm = assmGrty impVars-grty = assmGrty defVars--assmGrty f info = [ (x, val t) | (x, t) <- sigs, x `S.member` xs ]- where- xs = S.fromList $ f info- sigs = tySigs $ spec info--grtyTop info = forM topVs $ \v -> (v,) <$> trueTy (varType v)- where- topVs = filter isTop $ defVars info- isTop v = isExportedId v && not (v `S.member` sigVs)- isExportedId = flip elemNameSet (exports $ spec info) . getName- sigVs = S.fromList [v | (v,_) <- tySigs (spec info) ++ asmSigs (spec info)]------------------------------------------------------------------------------ | Helpers: Reading/Extending Environment Bindings ------------------------------------------------------------------------------------------------getTag :: CGEnv -> F.Tag-getTag γ = maybe Tg.defaultTag (`Tg.getTag` tgEnv γ) (tgKey γ)--setLoc :: CGEnv -> SrcSpan -> CGEnv-γ `setLoc` src- | isGoodSrcSpan src = γ { loc = src }- | otherwise = γ--withRecs :: CGEnv -> [Var] -> CGEnv-withRecs γ xs = γ { recs = foldl' (flip S.insert) (recs γ) xs }--withTRec γ xts = γ' {trec = Just $ M.fromList xts' `M.union` trec'}- where γ' = γ `withRecs` (fst <$> xts)- trec' = fromMaybe M.empty $ trec γ- xts' = mapFst F.symbol <$> xts--setBind :: CGEnv -> Tg.TagKey -> CGEnv-setBind γ k- | Tg.memTagEnv k (tgEnv γ) = γ { tgKey = Just k }- | otherwise = γ---isGeneric :: RTyVar -> SpecType -> Bool-isGeneric α t = all (\(c, α') -> (α'/=α) || isOrd c || isEq c ) (classConstrs t)- where classConstrs t = [(c, α') | (c, ts) <- tyClasses t- , t' <- ts- , α' <- freeTyVars t']- isOrd = (ordClassName ==) . className- isEq = (eqClassName ==) . className----------------------------------------------------------------------------------- Constraint Splitting ----------------------------------------------------------------------------------splitW :: WfC -> CG [FixWfC]--splitW (WfC γ t@(RFun x t1 t2 _))- = do ws <- bsplitW γ t- ws' <- splitW (WfC γ t1)- γ' <- (γ, "splitW") += (x, t1)- ws'' <- splitW (WfC γ' t2)- return $ ws ++ ws' ++ ws''--splitW (WfC γ t@(RAppTy t1 t2 _))- = do ws <- bsplitW γ t- ws' <- splitW (WfC γ t1)- ws'' <- splitW (WfC γ t2)- return $ ws ++ ws' ++ ws''--splitW (WfC γ (RAllT _ r))- = splitW (WfC γ r)--splitW (WfC γ (RAllP _ r))- = splitW (WfC γ r)--splitW (WfC γ t@(RVar _ _))- = bsplitW γ t--splitW (WfC γ t@(RApp _ ts rs _))- = do ws <- bsplitW γ t- γ' <- γ `extendEnvWithVV` t- ws' <- concat <$> mapM (splitW . WfC γ') ts- ws'' <- concat <$> mapM (rsplitW γ) rs- return $ ws ++ ws' ++ ws''--splitW (WfC γ (RAllE x tx t))- = do ws <- splitW (WfC γ tx)- γ' <- (γ, "splitW") += (x, tx)- ws' <- splitW (WfC γ' t)- return $ ws ++ ws'--splitW (WfC γ (REx x tx t))- = do ws <- splitW (WfC γ tx)- γ' <- (γ, "splitW") += (x, tx)- ws' <- splitW (WfC γ' t)- return $ ws ++ ws'--splitW (WfC _ t)- = errorstar $ "splitW cannot handle: " ++ showpp t--rsplitW _ (RPropP _ _)- = errorstar "Constrains: rsplitW for RPropP"-rsplitW γ (RProp ss t0)- = do γ' <- foldM (++=) γ [("rsplitC", x, ofRSort s) | (x, s) <- ss]- splitW $ WfC γ' t0-rsplitW _ (RHProp _ _)- = errorstar "TODO: EFFECTS"--bsplitW :: CGEnv -> SpecType -> CG [FixWfC]-bsplitW γ t = bsplitW' γ t . pruneRefs <$> get--bsplitW' γ t pflag- | F.isNonTrivial r' = [F.wfC (fe_binds $ fenv γ) r' Nothing ci]- | otherwise = []- where- r' = rTypeSortedReft' pflag γ t- ci = Ci (loc γ) Nothing---------------------------------------------------------------splitS :: SubC -> CG [([Stratum], [Stratum])]-bsplitS :: SpecType -> SpecType -> CG [([Stratum], [Stratum])]---------------------------------------------------------------splitS (SubC γ (REx x _ t1) (REx x2 _ t2)) | x == x2- = splitS (SubC γ t1 t2)--splitS (SubC γ t1 (REx _ _ t2))- = splitS (SubC γ t1 t2)--splitS (SubC γ (REx _ _ t1) t2)- = splitS (SubC γ t1 t2)--splitS (SubC γ (RAllE x _ t1) (RAllE x2 _ t2)) | x == x2- = splitS (SubC γ t1 t2)--splitS (SubC γ (RAllE _ _ t1) t2)- = splitS (SubC γ t1 t2)--splitS (SubC γ t1 (RAllE _ _ t2))- = splitS (SubC γ t1 t2)--splitS (SubC γ (RRTy _ _ _ t1) t2)- = splitS (SubC γ t1 t2)--splitS (SubC γ t1 (RRTy _ _ _ t2))- = splitS (SubC γ t1 t2)--splitS (SubC γ t1@(RFun x1 r1 r1' _) t2@(RFun x2 r2 r2' _))- = do cs <- bsplitS t1 t2- cs' <- splitS (SubC γ r2 r1)- γ' <- (γ, "splitC") += (x2, r2)- let r1x2' = r1' `F.subst1` (x1, F.EVar x2)- cs'' <- splitS (SubC γ' r1x2' r2')- return $ cs ++ cs' ++ cs''--splitS (SubC γ t1@(RAppTy r1 r1' _) t2@(RAppTy r2 r2' _))- = do cs <- bsplitS t1 t2- cs' <- splitS (SubC γ r1 r2)- cs'' <- splitS (SubC γ r1' r2')- cs''' <- splitS (SubC γ r2' r1')- return $ cs ++ cs' ++ cs'' ++ cs'''--splitS (SubC γ t1 (RAllP p t))- = splitS $ SubC γ t1 t'- where- t' = fmap (replacePredsWithRefs su) t- su = (uPVar p, pVartoRConc p)--splitS (SubC _ t1@(RAllP _ _) t2)- = errorstar $ "Predicate in lhs of constrain:" ++ showpp t1 ++ "\n<:\n" ++ showpp t2--splitS (SubC γ (RAllT α1 t1) (RAllT α2 t2))- | α1 == α2- = splitS $ SubC γ t1 t2- | otherwise- = splitS $ SubC γ t1 t2'- where t2' = subsTyVar_meet' (α2, RVar α1 mempty) t2--splitS (SubC _ (RApp c1 _ _ _) (RApp c2 _ _ _)) | isClass c1 && c1 == c2- = return []---splitS (SubC γ t1@(RApp {}) t2@(RApp {}))- = do (t1',t2') <- unifyVV t1 t2- cs <- bsplitS t1' t2'- γ' <- γ `extendEnvWithVV` t1'- let RApp c t1s r1s _ = t1'- let RApp _ t2s r2s _ = t2'- let isapplied = tyConArity (rtc_tc c) == length t1s- let tyInfo = rtc_info c- csvar <- splitsSWithVariance γ' t1s t2s $ varianceTyArgs tyInfo- csvar' <- rsplitsSWithVariance isapplied γ' r1s r2s $ variancePsArgs tyInfo- return $ cs ++ csvar ++ csvar'--splitS (SubC _ t1@(RVar a1 _) t2@(RVar a2 _))- | a1 == a2- = bsplitS t1 t2--splitS (SubC _ t1 t2)- = errorstar $ "(Another Broken Test1!!!) splitS unexpected: " ++ showpp t1 ++ "\n\n" ++ showpp t2--splitS (SubR _ _ _)- = return []--splitsSWithVariance γ t1s t2s variants- = concatMapM (\(t1, t2, v) -> splitfWithVariance (\s1 s2 -> splitS (SubC γ s1 s2)) t1 t2 v) (zip3 t1s t2s variants)--rsplitsSWithVariance False _ _ _ _ - = return [] --rsplitsSWithVariance _ γ t1s t2s variants- = concatMapM (\(t1, t2, v) -> splitfWithVariance (rsplitS γ) t1 t2 v) (zip3 t1s t2s variants)--bsplitS t1 t2- = return $ [(s1, s2)]- where [s1, s2] = getStrata <$> [t1, t2]--rsplitS γ (RProp s1 r1) (RProp s2 r2)- = splitS (SubC γ (F.subst su r1) r2)- where su = F.mkSubst [(x, F.EVar y) | ((x,_), (y,_)) <- zip s1 s2]--rsplitS _ _ _- = errorstar "rspliS Rpoly - RPropP"----splitfWithVariance f t1 t2 Invariant = liftM2 (++) (f t1 t2) (f t2 t1) -- return []-splitfWithVariance f t1 t2 Bivariant = liftM2 (++) (f t1 t2) (f t2 t1)-splitfWithVariance f t1 t2 Covariant = f t1 t2-splitfWithVariance f t1 t2 Contravariant = f t2 t1----------------------------------------------------------------splitC :: SubC -> CG [FixSubC]---------------------------------------------------------------splitC (SubC γ (REx x tx t1) (REx x2 _ t2)) | x == x2- = do γ' <- (γ, "addExBind 0") += (x, forallExprRefType γ tx)- splitC (SubC γ' t1 t2)--splitC (SubC γ t1 (REx x tx t2))- = do y <- fresh - γ' <- (γ, "addExBind 1") += (y, forallExprRefType γ tx)- splitC (SubC γ' t1 (F.subst1 t2 (x, F.EVar y)))---- existential at the left hand side is treated like forall-splitC (SubC γ (REx x tx t1) t2)- = do -- let tx' = traceShow ("splitC: " ++ showpp z) tx- y <- fresh - γ' <- (γ, "addExBind 2") += (y, forallExprRefType γ tx)- splitC (SubC γ' (F.subst1 t1 (x, F.EVar y)) t2)--splitC (SubC γ (RAllE x tx t1) (RAllE x2 _ t2)) | x == x2- = do γ' <- (γ, "addAllBind 0") += (x, forallExprRefType γ tx)- splitC (SubC γ' t1 t2)--splitC (SubC γ (RAllE x tx t1) t2)- = do y <- fresh - γ' <- (γ, "addAABind 1") += (y, forallExprRefType γ tx)- splitC (SubC γ' (t1 `F.subst1` (x, F.EVar y)) t2)--splitC (SubC γ t1 (RAllE x tx t2))- = do y <- fresh - γ' <- (γ, "addAllBind 2") += (y, forallExprRefType γ tx)- splitC (SubC γ' t1 (F.subst1 t2 (x, F.EVar y)))--splitC (SubC γ (RRTy env _ OCons t1) t2)- = do γ' <- foldM (\γ (x, t) -> γ `addSEnv` ("splitS", x,t)) γ xts- c1 <- splitC (SubC γ' t1' t2')- c2 <- splitC (SubC γ t1 t2 )- return $ c1 ++ c2- where- (xts, t1', t2') = envToSub env--splitC (SubC γ (RRTy e r o t1) t2)- = do γ' <- foldM (\γ (x, t) -> γ `addSEnv` ("splitS", x,t)) γ e- c1 <- splitC (SubR γ' o r )- c2 <- splitC (SubC γ t1 t2)- return $ c1 ++ c2--splitC (SubC γ t1@(RFun x1 r1 r1' _) t2@(RFun x2 r2 r2' _))- = do cs <- bsplitC γ t1 t2- cs' <- splitC (SubC γ r2 r1)- γ' <- (γ, "splitC") += (x2, r2)- let r1x2' = r1' `F.subst1` (x1, F.EVar x2)- cs'' <- splitC (SubC γ' r1x2' r2')- return $ cs ++ cs' ++ cs''--splitC (SubC γ t1@(RAppTy r1 r1' _) t2@(RAppTy r2 r2' _))- = do cs <- bsplitC γ t1 t2- cs' <- splitC (SubC γ r1 r2)- cs'' <- splitC (SubC γ r1' r2')- cs''' <- splitC (SubC γ r2' r1')- return $ cs ++ cs' ++ cs'' ++ cs'''--splitC (SubC γ t1 (RAllP p t))- = splitC $ SubC γ t1 t'- where- t' = fmap (replacePredsWithRefs su) t- su = (uPVar p, pVartoRConc p)--splitC (SubC _ t1@(RAllP _ _) t2)- = errorstar $ "Predicate in lhs of constraint:" ++ showpp t1 ++ "\n<:\n" ++ showpp t2--splitC (SubC γ (RAllT α1 t1) (RAllT α2 t2))- | α1 == α2- = splitC $ SubC γ t1 t2- | otherwise- = splitC $ SubC γ t1 t2'- where t2' = subsTyVar_meet' (α2, RVar α1 mempty) t2---splitC (SubC _ (RApp c1 _ _ _) (RApp c2 _ _ _)) | isClass c1 && c1 == c2- = return []--splitC (SubC γ t1@(RApp _ _ _ _) t2@(RApp _ _ _ _))- = do (t1',t2') <- unifyVV t1 t2- cs <- bsplitC γ t1' t2'- γ' <- γ `extendEnvWithVV` t1'- let RApp c t1s r1s _ = t1'- let RApp _ t2s r2s _ = t2'- let isapplied = tyConArity (rtc_tc c) == length t1s- let tyInfo = rtc_info c- csvar <- splitsCWithVariance γ' t1s t2s $ varianceTyArgs tyInfo- csvar' <- rsplitsCWithVariance isapplied γ' r1s r2s $ variancePsArgs tyInfo- return $ cs ++ csvar ++ csvar'--splitC (SubC γ t1@(RVar a1 _) t2@(RVar a2 _))- | a1 == a2- = bsplitC γ t1 t2--splitC (SubC _ t1 t2)- = errorstar $ "(Another Broken Test!!!) splitc unexpected:\n" ++ showpp t1 ++ "\n\n" ++ showpp t2--splitC (SubR γ o r)- = do fg <- pruneRefs <$> get- let r1' = if fg then pruneUnsortedReft γ'' r1 else r1- return $ F.subC γ' F.PTrue r1' r2 Nothing tag ci- where- γ'' = fe_env $ fenv γ- γ' = fe_binds $ fenv γ- r1 = F.RR F.boolSort $ F.toReft r- r2 = F.RR F.boolSort $ F.Reft (vv, F.Refa $ F.PBexp $ F.EVar vv)- vv = "vvRec"- -- s = boolSort -- F.FApp F.boolFTyCon []- ci = Ci src err- err = Just $ ErrAssType src o (text $ show o ++ "type error") r- tag = getTag γ- src = loc γ---splitsCWithVariance γ t1s t2s variants- = concatMapM (\(t1, t2, v) -> splitfWithVariance (\s1 s2 -> (splitC (SubC γ s1 s2))) t1 t2 v) (zip3 t1s t2s variants)--rsplitsCWithVariance False _ _ _ _ - = return [] --rsplitsCWithVariance _ γ t1s t2s variants- = concatMapM (\(t1, t2, v) -> splitfWithVariance (rsplitC γ) t1 t2 v) (zip3 t1s t2s variants)----bsplitC γ t1 t2- = do checkStratum γ t1 t2- pflag <- pruneRefs <$> get- γ' <- γ ++= ("bsplitC", v, t1)- let r = (mempty :: UReft F.Reft){ur_reft = F.Reft (F.dummySymbol, F.Refa $ constraintToLogic γ' (lcs γ'))}- let t1' = addRTyConInv (invs γ') t1 `strengthen` r- return $ bsplitC' γ' t1' t2 pflag- where- F.Reft(v, _) = ur_reft (fromMaybe mempty (stripRTypeBase t1))--checkStratum γ t1 t2- | s1 <:= s2 = return ()- | otherwise = addWarning wrn- where- [s1, s2] = getStrata <$> [t1, t2]- wrn = ErrOther (loc γ) (text $ "Stratum Error : " ++ show s1 ++ " > " ++ show s2)--bsplitC' γ t1 t2 pflag- | F.isFunctionSortedReft r1' && F.isNonTrivial r2'- = F.subC γ' grd (r1' {F.sr_reft = mempty}) r2' Nothing tag ci- | F.isNonTrivial r2'- = F.subC γ' grd r1' r2' Nothing tag ci- | otherwise- = []- where- γ' = fe_binds $ fenv γ- r1' = rTypeSortedReft' pflag γ t1- r2' = rTypeSortedReft' pflag γ t2- ci = Ci src err- tag = getTag γ- err = Just $ ErrSubType src (text "subtype") g t1 t2- src = loc γ- REnv g = renv γ- grd = F.PTrue----unifyVV t1@(RApp _ _ _ _) t2@(RApp _ _ _ _)- = do vv <- (F.vv . Just) <$> fresh- return $ (shiftVV t1 vv, (shiftVV t2 vv) ) -- {rt_pargs = r2s'})--unifyVV _ _- = errorstar $ "Constraint.Generate.unifyVV called on invalid inputs"--rsplitC _ (RPropP _ _) (RPropP _ _)- = errorstar "RefTypes.rsplitC on RPropP"--rsplitC γ (RProp s1 r1) (RProp s2 r2)- = do γ' <- foldM (++=) γ [("rsplitC1", x, ofRSort s) | (x, s) <- s2]- splitC (SubC γ' (F.subst su r1) r2)- where su = F.mkSubst [(x, F.EVar y) | ((x,_), (y,_)) <- zip s1 s2]--rsplitC _ _ _- = errorstar "rsplit Rpoly - RPropP"---type CG = State CGInfo--initCGI cfg info = CGInfo {- hsCs = []- , sCs = []- , hsWfs = []- , fixCs = []- , isBind = []- , fixWfs = []- , freshIndex = 0- , binds = F.emptyBindEnv- , annotMap = AI M.empty- , tyConInfo = tyi- , tyConEmbed = tce- , kuts = F.ksEmpty- , lits = coreBindLits tce info- , termExprs = M.fromList $ texprs spc- , specDecr = decr spc- , specLVars = lvars spc- , specLazy = lazy spc- , tcheck = not $ notermination cfg- , scheck = strata cfg- , trustghc = trustinternals cfg- , pruneRefs = not $ noPrune cfg- , logErrors = []- , kvProf = emptyKVProf- , recCount = 0- , bindSpans = M.empty- , autoSize = autosize spc- }- where- tce = tcEmbeds spc- spc = spec info- tyi = tyconEnv spc -- EFFECTS HEREHEREHERE makeTyConInfo (tconsP spc)--coreBindLits tce info- = sortNub $ [ (val x, so) | (_, Just (F.ELit x so)) <- lconsts ]- ++ [(F.symbol x, F.strSort) | (_, Just (F.ESym x)) <- lconsts ]- ++ [ (dconToSym dc, dconToSort dc) | dc <- dcons ]- where- lconsts = literalConst tce <$> literals (cbs info)- dcons = filter isDCon $ impVars info ++ (snd <$> freeSyms (spec info))- dconToSort = typeSort tce . expandTypeSynonyms . varType- dconToSym = dataConSymbol . idDataCon- isDCon x = isDataConId x && not (hasBaseTypeVar x)--extendEnvWithVV γ t- | F.isNontrivialVV vv- = (γ, "extVV") += (vv, t)- | otherwise- = return γ- where vv = rTypeValueVar t--{- see tests/pos/polyfun for why you need everything in fixenv -}-addCGEnv :: (SpecType -> SpecType) -> CGEnv -> (String, F.Symbol, SpecType) -> CG CGEnv-addCGEnv tx γ (msg, x, REx y tyy tyx)- = do y' <- fresh- γ' <- addCGEnv tx γ (msg, y', tyy)- addCGEnv tx γ' (msg, x, tyx `F.subst1` (y, F.EVar y'))--addCGEnv tx γ (msg, x, RAllE yy tyy tyx)- = addCGEnv tx γ (msg, x, t)- where- xs = grapBindsWithType tyy γ- t = foldl F.meet ttrue [ tyx' `F.subst1` (yy, F.EVar x) | x <- xs]-- (tyx', ttrue) = splitXRelatedRefs yy tyx--addCGEnv tx γ (_, x, t')- = do idx <- fresh- let t = tx $ normalize {-x-} idx t'- let l = loc γ- let γ' = γ { renv = insertREnv x t (renv γ) }- pflag <- pruneRefs <$> get- is <- if isBase t- then (:) <$> addBind l x (rTypeSortedReft' pflag γ' t) <*> addClassBind l t- else return []- return $ γ' { fenv = insertsFEnv (fenv γ) is }--(++=) :: CGEnv -> (String, F.Symbol, SpecType) -> CG CGEnv-(++=) γ = addCGEnv (addRTyConInv (M.unionWith mappend (invs γ) (ial γ))) γ--addSEnv :: CGEnv -> (String, F.Symbol, SpecType) -> CG CGEnv-addSEnv γ = addCGEnv (addRTyConInv (invs γ)) γ--rTypeSortedReft' pflag γ- | pflag- = pruneUnsortedReft (fe_env $ fenv γ) . f- | otherwise- = f- where- f = rTypeSortedReft (emb γ)--(+++=) :: (CGEnv, String) -> (F.Symbol, CoreExpr, SpecType) -> CG CGEnv--(γ, _) +++= (x, e, t) = (γ{lcb = M.insert x e (lcb γ)}, "+++=") += (x, t)--(+=) :: (CGEnv, String) -> (F.Symbol, SpecType) -> CG CGEnv-(γ, msg) += (x, r)- | x == F.dummySymbol- = return γ- | x `memberREnv` (renv γ)- = err- | otherwise- = γ ++= (msg, x, r)- where err = errorstar $ msg ++ " Duplicate binding for "- ++ F.symbolString x- ++ "\n New: " ++ showpp r- ++ "\n Old: " ++ showpp (x `lookupREnv` (renv γ))--γ -= x = γ {renv = deleteREnv x (renv γ), lcb = M.delete x (lcb γ)}--(??=) :: CGEnv -> F.Symbol -> CG SpecType-γ ??= x- = case M.lookup x (lcb γ) of- Just e -> consE (γ-=x) e- Nothing -> refreshTy $ γ ?= x--(?=) :: CGEnv -> F.Symbol -> SpecType-γ ?= x = fromMaybe err $ lookupREnv x (renv γ)- where err = errorstar $ "EnvLookup: unknown "- ++ showpp x- ++ " in renv\n"- ++ showpp (renv γ)--normalize idx- = normalizeVV idx- . normalizePds--normalizeVV idx t@(RApp _ _ _ _)- | not (F.isNontrivialVV (rTypeValueVar t))- = shiftVV t (F.vv $ Just idx)--normalizeVV _ t- = t---addBind :: SrcSpan -> F.Symbol -> F.SortedReft -> CG ((F.Symbol, F.Sort), F.BindId)-addBind l x r- = do st <- get- let (i, bs') = F.insertBindEnv x r (binds st)- put $ st { binds = bs' } { bindSpans = M.insert i l (bindSpans st) }- return ((x, F.sr_sort r), i) -- traceShow ("addBind: " ++ showpp x) i--addClassBind :: SrcSpan -> SpecType -> CG [((F.Symbol, F.Sort), F.BindId)]-addClassBind l = mapM (uncurry (addBind l)) . classBinds---- RJ: What is this `isBind` business?-pushConsBind act- = do modify $ \s -> s { isBind = False : isBind s }- z <- act- modify $ \s -> s { isBind = tail (isBind s) }- return z--addC :: SubC -> String -> CG ()-addC !c@(SubC γ t1 t2) _msg- = do -- trace ("addC at " ++ show (loc γ) ++ _msg++ showpp t1 ++ "\n <: \n" ++ showpp t2 ) $- modify $ \s -> s { hsCs = c : (hsCs s) }- bflag <- headDefault True . isBind <$> get- sflag <- scheck <$> get- if bflag && sflag- then modify $ \s -> s {sCs = (SubC γ t2 t1) : (sCs s) }- else return ()- where- headDefault a [] = a- headDefault _ (x:_) = x---addC !c _msg- = modify $ \s -> s { hsCs = c : (hsCs s) }--addPost γ (RRTy e r OInv t)- = do γ' <- foldM (\γ (x, t) -> γ `addSEnv` ("addPost", x,t)) γ e- addC (SubR γ' OInv r) "precondition" >> return t--addPost γ (RRTy e r OTerm t)- = do γ' <- foldM (\γ (x, t) -> γ ++= ("addPost", x,t)) γ e- addC (SubR γ' OTerm r) "precondition" >> return t--addPost _ (RRTy _ _ OCons t)- = return t--addPost _ t- = return t--addW :: WfC -> CG ()-addW !w = modify $ \s -> s { hsWfs = w : (hsWfs s) }--addWarning :: TError SpecType -> CG ()-addWarning w = modify $ \s -> s { logErrors = w : (logErrors s) }---- | Used for annotation binders (i.e. at binder sites)--addIdA :: Var -> Annot SpecType -> CG ()-addIdA !x !t = modify $ \s -> s { annotMap = upd $ annotMap s }- where- loc = getSrcSpan x- upd m@(AI _) = if boundRecVar loc m then m else addA loc (Just x) t m--boundRecVar l (AI m) = not $ null [t | (_, AnnRDf t) <- M.lookupDefault [] l m]----- | Used for annotating reads (i.e. at Var x sites)--addLocA :: Maybe Var -> SrcSpan -> Annot SpecType -> CG ()-addLocA !xo !l !t- = modify $ \s -> s { annotMap = addA l xo t $ annotMap s }---- | Used to update annotations for a location, due to (ghost) predicate applications--updateLocA (_:_) (Just l) t = addLocA Nothing l (AnnUse t)-updateLocA _ _ _ = return ()--addA !l xo@(Just _) !t (AI m)- | isGoodSrcSpan l- = AI $ inserts l (T.pack . showPpr <$> xo, t) m-addA !l xo@Nothing !t (AI m)- | l `M.member` m -- only spans known to be variables- = AI $ inserts l (T.pack . showPpr <$> xo, t) m-addA _ _ _ !a- = a---------------------------------------------------------------------------------------------- Generation: Freshness -------------------------------------------------------------------------------------------- | Right now, we generate NO new pvars. Rather than clutter code--- with `uRType` calls, put it in one place where the above--- invariant is /obviously/ enforced.--- Constraint generation should ONLY use @freshTy_type@ and @freshTy_expr@--freshTy_type :: KVKind -> CoreExpr -> Type -> CG SpecType-freshTy_type k _ τ = freshTy_reftype k $ ofType τ--freshTy_expr :: KVKind -> CoreExpr -> Type -> CG SpecType-freshTy_expr k e _ = freshTy_reftype k $ exprRefType e--freshTy_reftype :: KVKind -> SpecType -> CG SpecType--- freshTy_reftype k t = do t <- refresh =<< fixTy t--- addKVars k t--- return t--freshTy_reftype k t = (fixTy t >>= refresh) =>> addKVars k---- | Used to generate "cut" kvars for fixpoint. Typically, KVars for recursive--- definitions, and also to update the KVar profile.--addKVars :: KVKind -> SpecType -> CG ()-addKVars !k !t = do when (True) $ modify $ \s -> s { kvProf = updKVProf k kvars (kvProf s) }- when (isKut k) $ modify $ \s -> s { kuts = F.ksUnion kvars (kuts s) }- where- kvars = sortNub $ specTypeKVars t--isKut :: KVKind -> Bool-isKut RecBindE = True-isKut _ = False--specTypeKVars :: SpecType -> [F.KVar]-specTypeKVars = foldReft ((++) . (kvars . ur_reft)) []--trueTy :: Type -> CG SpecType-trueTy = ofType' >=> true--ofType' :: Type -> CG SpecType-ofType' = fixTy . ofType--fixTy :: SpecType -> CG SpecType-fixTy t = do tyi <- tyConInfo <$> get- tce <- tyConEmbed <$> get- return $ addTyConInfo tce tyi t--refreshArgsTop :: (Var, SpecType) -> CG SpecType-refreshArgsTop (x, t)- = do (t', su) <- refreshArgsSub t- modify $ \s -> s {termExprs = M.adjust (F.subst su <$>) x $ termExprs s}- return t'--refreshArgs :: SpecType -> CG SpecType-refreshArgs t- = fst <$> refreshArgsSub t----- NV TODO: this does not refreshes args if they are wrapped in an RRTy-refreshArgsSub :: SpecType -> CG (SpecType, F.Subst)-refreshArgsSub t- = do ts <- mapM refreshArgs ts_u- xs' <- mapM (\_ -> fresh) xs- let sus = F.mkSubst <$> (L.inits $ zip xs (F.EVar <$> xs'))- let su = last sus- let ts' = zipWith F.subst sus ts- let t' = fromRTypeRep $ trep {ty_binds = xs', ty_args = ts', ty_res = F.subst su tbd}- return (t', su)- where- trep = toRTypeRep t- xs = ty_binds trep- ts_u = ty_args trep- tbd = ty_res trep--instance Freshable CG Integer where- fresh = do s <- get- let n = freshIndex s- put $ s { freshIndex = n + 1 }- return n---------------------------------------------------------------------------------------------------------- TERMINATION TYPE ------------------------------------------------------------------------------------------------------------------------makeDecrIndex :: (Var, Template SpecType)-> CG [Int]-makeDecrIndex (x, Assumed t)- = do dindex <- makeDecrIndexTy x t- case dindex of- Left _ -> return []- Right i -> return i-makeDecrIndex (x, Asserted t)- = do dindex <- makeDecrIndexTy x t- case dindex of- Left msg -> addWarning msg >> return []- Right i -> return i-makeDecrIndex _ = return []--makeDecrIndexTy x t- = do spDecr <- specDecr <$> get- autosz <- autoSize <$> get- hint <- checkHint' autosz (L.lookup x $ spDecr)- case dindex autosz of- Nothing -> return $ Left msg -- addWarning msg >> return []- Just i -> return $ Right $ fromMaybe [i] hint- where- ts = ty_args trep- checkHint' = \autosz -> checkHint x ts (isDecreasing autosz cenv)- dindex = \autosz -> L.findIndex (isDecreasing autosz cenv) ts- msg = ErrTermin [x] (getSrcSpan x) (text "No decreasing parameter")- cenv = makeNumEnv ts- trep = toRTypeRep $ unOCons t---recType _ ((_, []), (_, [], t))- = t--recType autoenv ((vs, indexc), (_, index, t))- = makeRecType autoenv t v dxt index- where v = (vs !!) <$> indexc- dxt = (xts !!) <$> index- xts = zip (ty_binds trep) (ty_args trep)- trep = toRTypeRep $ unOCons t--checkIndex (x, vs, t, index)- = do mapM_ (safeLogIndex msg' vs) index- mapM (safeLogIndex msg ts) index- where- loc = getSrcSpan x- ts = ty_args $ toRTypeRep $ unOCons $ unTemplate t- msg' = ErrTermin [x] loc (text $ "No decreasing " ++ show index ++ "-th argument on " ++ (showPpr x) ++ " with " ++ (showPpr vs))- msg = ErrTermin [x] loc (text "No decreasing parameter")--makeRecType autoenv t vs dxs is- = mergecondition t $ fromRTypeRep $ trep {ty_binds = xs', ty_args = ts'}- where- (xs', ts') = unzip $ replaceN (last is) (makeDecrType autoenv vdxs) xts- vdxs = zip vs dxs- xts = zip (ty_binds trep) (ty_args trep)- trep = toRTypeRep $ unOCons t--unOCons (RAllT v t) = RAllT v $ unOCons t-unOCons (RAllP p t) = RAllP p $ unOCons t-unOCons (RFun x tx t r) = RFun x (unOCons tx) (unOCons t) r-unOCons (RRTy _ _ OCons t) = unOCons t-unOCons t = t---mergecondition (RAllT _ t1) (RAllT v t2)- = RAllT v $ mergecondition t1 t2-mergecondition (RAllP _ t1) (RAllP p t2)- = RAllP p $ mergecondition t1 t2-mergecondition (RRTy xts r OCons t1) t2- = RRTy xts r OCons (mergecondition t1 t2)-mergecondition (RFun _ t11 t12 _) (RFun x2 t21 t22 r2)- = RFun x2 (mergecondition t11 t21) (mergecondition t12 t22) r2-mergecondition _ t- = t--safeLogIndex err ls n- | n >= length ls = addWarning err >> return Nothing- | otherwise = return $ Just $ ls !! n--checkHint _ _ _ Nothing- = return Nothing--checkHint x _ _ (Just ns) | L.sort ns /= ns- = addWarning (ErrTermin [x] loc (text "The hints should be increasing")) >> return Nothing- where loc = getSrcSpan x--checkHint x ts f (Just ns)- = (mapM (checkValidHint x ts f) ns) >>= (return . Just . catMaybes)--checkValidHint x ts f n- | n < 0 || n >= length ts = addWarning err >> return Nothing- | f (ts L.!! n) = return $ Just n- | otherwise = addWarning err >> return Nothing- where err = ErrTermin [x] loc (text $ "Invalid Hint " ++ show (n+1) ++ " for " ++ (showPpr x) ++ "\nin\n" ++ show (ts))- loc = getSrcSpan x------------------------------------------------------------------------------------------ Generation: Corebind ----------------------------------------------------------------------------------------------consCBTop :: (Var -> Bool) -> CGEnv -> CoreBind -> CG CGEnv-consCBLet :: CGEnv -> CoreBind -> CG CGEnv----------------------------------------------------------------------consCBLet γ cb- = do oldtcheck <- tcheck <$> get- strict <- specLazy <$> get- let tflag = oldtcheck- let isStr = tcond cb strict- modify $ \s -> s{tcheck = tflag && isStr}- γ' <- consCB (tflag && isStr) isStr γ cb- modify $ \s -> s{tcheck = oldtcheck}- return γ'--consCBTop trustBinding γ cb | all trustBinding xs- = do ts <- mapM trueTy (varType <$> xs)- foldM (\γ xt -> (γ, "derived") += xt) γ (zip xs' ts)- where xs = bindersOf cb- xs' = F.symbol <$> xs--consCBTop _ γ cb- = do oldtcheck <- tcheck <$> get- strict <- specLazy <$> get- let tflag = oldtcheck- let isStr = tcond cb strict- modify $ \s -> s{tcheck = tflag && isStr}- γ' <- consCB (tflag && isStr) isStr γ cb- modify $ \s -> s{tcheck = oldtcheck}- return γ'--tcond cb strict- = not $ any (\x -> S.member x strict || isInternal x) (binds cb)- where binds (NonRec x _) = [x]- binds (Rec xes) = fst $ unzip xes----------------------------------------------------------------------consCB :: Bool -> Bool -> CGEnv -> CoreBind -> CG CGEnv----------------------------------------------------------------------consCBSizedTys γ xes- = do xets'' <- forM xes $ \(x, e) -> liftM (x, e,) (varTemplate γ (x, Just e))- sflag <- scheck <$> get- autoenv <- autoSize <$> get- let cmakeFinType = if sflag then makeFinType else id- let cmakeFinTy = if sflag then makeFinTy else snd- let xets = mapThd3 (fmap cmakeFinType) <$> xets''- ts' <- mapM (T.mapM refreshArgs) $ (thd3 <$> xets)- let vs = zipWith collectArgs ts' es- is <- mapM makeDecrIndex (zip xs ts') >>= checkSameLens- let ts = cmakeFinTy <$> zip is ts'- let xeets = (\vis -> [(vis, x) | x <- zip3 xs is $ map unTemplate ts]) <$> (zip vs is)- (L.transpose <$> mapM checkIndex (zip4 xs vs ts is)) >>= checkEqTypes- let rts = (recType autoenv <$>) <$> xeets- let xts = zip xs ts- γ' <- foldM extender γ xts- let γs = [γ' `withTRec` (zip xs rts') | rts' <- rts]- let xets' = zip3 xs es ts- mapM_ (uncurry $ consBind True) (zip γs xets')- return γ'- where- (xs, es) = unzip xes- collectArgs = collectArguments . length . ty_binds . toRTypeRep . unOCons . unTemplate- checkEqTypes :: [[Maybe SpecType]] -> CG [[SpecType]]- checkEqTypes x = mapM (checkAll err1 toRSort) (catMaybes <$> x)- checkSameLens = checkAll err2 length- err1 = ErrTermin xs loc $ text "The decreasing parameters should be of same type"- err2 = ErrTermin xs loc $ text "All Recursive functions should have the same number of decreasing parameters"- loc = getSrcSpan (head xs)-- checkAll _ _ [] = return []- checkAll err f (x:xs)- | all (==(f x)) (f <$> xs) = return (x:xs)- | otherwise = addWarning err >> return []--consCBWithExprs γ xes- = do xets' <- forM xes $ \(x, e) -> liftM (x, e,) (varTemplate γ (x, Just e))- texprs <- termExprs <$> get- let xtes = catMaybes $ (`lookup` texprs) <$> xs- sflag <- scheck <$> get- let cmakeFinType = if sflag then makeFinType else id- let xets = mapThd3 (fmap cmakeFinType) <$> xets'- let ts = safeFromAsserted err . thd3 <$> xets- ts' <- mapM refreshArgs ts- let xts = zip xs (Asserted <$> ts')- γ' <- foldM extender γ xts- let γs = makeTermEnvs γ' xtes xes ts ts'- let xets' = zip3 xs es (Asserted <$> ts')- mapM_ (uncurry $ consBind True) (zip γs xets')- return γ'- where (xs, es) = unzip xes- lookup k m | Just x <- M.lookup k m = Just (k, x)- | otherwise = Nothing- err = "Constant: consCBWithExprs"--makeFinTy (ns, t) = fmap go t- where- go t = fromRTypeRep $ trep {ty_args = args'}- where- trep = toRTypeRep t- args' = mapNs ns makeFinType $ ty_args trep---makeTermEnvs γ xtes xes ts ts' = withTRec γ . zip xs <$> rts- where- vs = zipWith collectArgs ts es- ys = (fst4 . bkArrowDeep) <$> ts- ys' = (fst4 . bkArrowDeep) <$> ts'- sus' = zipWith mkSub ys ys'- sus = zipWith mkSub ys ((F.symbol <$>) <$> vs)- ess = (\x -> (safeFromJust (err x) $ (x `L.lookup` xtes))) <$> xs- tes = zipWith (\su es -> F.subst su <$> es) sus ess- tes' = zipWith (\su es -> F.subst su <$> es) sus' ess- rss = zipWith makeLexRefa tes' <$> (repeat <$> tes)- rts = zipWith addTermCond ts' <$> rss- (xs, es) = unzip xes- mkSub ys ys' = F.mkSubst [(x, F.EVar y) | (x, y) <- zip ys ys']- collectArgs = collectArguments . length . ty_binds . toRTypeRep- err x = "Constant: makeTermEnvs: no terminating expression for " ++ showPpr x--consCB tflag _ γ (Rec xes) | tflag- = do texprs <- termExprs <$> get- modify $ \i -> i { recCount = recCount i + length xes }- let xxes = catMaybes $ (`lookup` texprs) <$> xs- if null xxes- then consCBSizedTys γ xes- else check xxes <$> consCBWithExprs γ xes- where xs = fst $ unzip xes- check ys r | length ys == length xs = r- | otherwise = errorstar err- err = printf "%s: Termination expressions should be provided for ALL mutual recursive functions" loc- loc = showPpr $ getSrcSpan (head xs)- lookup k m | Just x <- M.lookup k m = Just (k, x)- | otherwise = Nothing--consCB _ str γ (Rec xes) | not str- = do xets' <- forM xes $ \(x, e) -> liftM (x, e,) (varTemplate γ (x, Just e))- sflag <- scheck <$> get- let cmakeDivType = if sflag then makeDivType else id- let xets = mapThd3 (fmap cmakeDivType) <$> xets'- modify $ \i -> i { recCount = recCount i + length xes }- let xts = [(x, to) | (x, _, to) <- xets]- γ' <- foldM extender (γ `withRecs` (fst <$> xts)) xts- mapM_ (consBind True γ') xets- return γ'--consCB _ _ γ (Rec xes)- = do xets <- forM xes $ \(x, e) -> liftM (x, e,) (varTemplate γ (x, Just e))- modify $ \i -> i { recCount = recCount i + length xes }- let xts = [(x, to) | (x, _, to) <- xets]- γ' <- foldM extender (γ `withRecs` (fst <$> xts)) xts- mapM_ (consBind True γ') xets- return γ'---- | NV: Dictionaries are not checked, because--- | class methods' preconditions are not satisfied-consCB _ _ γ (NonRec x _) | isDictionary x- = do t <- trueTy (varType x)- extender γ (x, Assumed t)- where- isDictionary = isJust . dlookup (denv γ)---consCB _ _ γ (NonRec x (App (Var w) (Type τ))) | isDictionary w- = do t <- trueTy τ- addW $ WfC γ t- let xts = dmap (f t) $ safeFromJust (show w ++ "Not a dictionary" ) $ dlookup (denv γ) w- let γ' = γ{denv = dinsert (denv γ) x xts }- t <- trueTy (varType x)- extender γ' (x, Assumed t)- where f t' (RAllT α te) = subsTyVar_meet' (α, t') te- f _ _ = error "consCB on Dictionary: this should not happen"- isDictionary = isJust . dlookup (denv γ)----consCB _ _ γ (NonRec x e)- = do to <- varTemplate γ (x, Nothing)- to' <- consBind False γ (x, e, to) >>= (addPostTemplate γ)- extender γ (x, to')--consBind isRec γ (x, e, Asserted spect)- = do let γ' = (γ `setLoc` getSrcSpan x) `setBind` x- (_,πs,_,_) = bkUniv spect- γπ <- foldM addPToEnv γ' πs- cconsE γπ e spect- when (F.symbol x `elemHEnv` holes γ) $- -- have to add the wf constraint here for HOLEs so we have the proper env- addW $ WfC γπ $ fmap killSubst spect- addIdA x (defAnn isRec spect)- return $ Asserted spect -- Nothing--consBind isRec γ (x, e, Assumed spect)- = do let γ' = (γ `setLoc` getSrcSpan x) `setBind` x- γπ <- foldM addPToEnv γ' πs- cconsE γπ e =<< true spect- addIdA x (defAnn isRec spect)- return $ Asserted spect -- Nothing- where πs = ty_preds $ toRTypeRep spect--consBind isRec γ (x, e, Unknown)- = do t <- consE (γ `setBind` x) e- addIdA x (defAnn isRec t)- return $ Asserted t--noHoles = and . foldReft (\r bs -> not (hasHole r) : bs) []--killSubst :: RReft -> RReft-killSubst = fmap killSubstReft--killSubstReft :: F.Reft -> F.Reft-killSubstReft = trans kv () ()- where- kv = defaultVisitor { txPred = ks }- ks _ (F.PKVar k _) = F.PKVar k mempty- ks _ p = p-- -- tx (F.Reft (s, rs)) = F.Reft (s, map f rs)- -- f (F.RKvar k _) = F.RKvar k mempty- -- f (F.RConc p) = F.RConc p--defAnn True = AnnRDf-defAnn False = AnnDef--addPToEnv γ π- = do γπ <- γ ++= ("addSpec1", pname π, pvarRType π)- foldM (++=) γπ [("addSpec2", x, ofRSort t) | (t, x, _) <- pargs π]--extender γ (x, Asserted t) = γ ++= ("extender", F.symbol x, t)-extender γ (x, Assumed t) = γ ++= ("extender", F.symbol x, t)-extender γ _ = return γ--addBinders γ0 x' cbs = foldM (++=) (γ0 -= x') [("addBinders", x, t) | (x, t) <- cbs]--data Template a = Asserted a | Assumed a | Unknown deriving (Functor, F.Foldable, T.Traversable)--deriving instance (Show a) => (Show (Template a))--unTemplate (Asserted t) = t-unTemplate (Assumed t) = t-unTemplate _ = errorstar "Constraint.Generate.unTemplate called on `Unknown`"--addPostTemplate γ (Asserted t) = Asserted <$> addPost γ t-addPostTemplate γ (Assumed t) = Assumed <$> addPost γ t-addPostTemplate _ Unknown = return Unknown--safeFromAsserted _ (Asserted t) = t-safeFromAsserted msg _ = errorstar $ "safeFromAsserted:" ++ msg---- | @varTemplate@ is only called with a `Just e` argument when the `e`--- corresponds to the body of a @Rec@ binder.-varTemplate :: CGEnv -> (Var, Maybe CoreExpr) -> CG (Template SpecType)-varTemplate γ (x, eo)- = case (eo, lookupREnv (F.symbol x) (grtys γ), lookupREnv (F.symbol x) (assms γ)) of- (_, Just t, _) -> Asserted <$> refreshArgsTop (x, t)- (_, _, Just t) -> Assumed <$> refreshArgsTop (x, t)- (Just e, _, _) -> do t <- freshTy_expr RecBindE e (exprType e)- addW (WfC γ t)- Asserted <$> refreshArgsTop (x, t)- (_, _, _) -> return Unknown------------------------------------------------------------------------------------------ Generation: Expression -------------------------------------------------------------------------------------------------------------------- Type Checking ------------------------------cconsE :: CGEnv -> Expr Var -> SpecType -> CG ()---------------------------------------------------------------------cconsE γ e@(Let b@(NonRec x _) ee) t- = do sp <- specLVars <$> get- if (x `S.member` sp) || isDefLazyVar x- then cconsLazyLet γ e t- else do γ' <- consCBLet γ b- cconsE γ' ee t- where- isDefLazyVar = L.isPrefixOf "fail" . showPpr--cconsE γ e (RAllP p t)- = cconsE γ' e t''- where- t' = replacePredsWithRefs su <$> t- su = (uPVar p, pVartoRConc p)- (css, t'') = splitConstraints t'- γ' = foldl (flip addConstraints) γ css--cconsE γ (Let b e) t- = do γ' <- consCBLet γ b- cconsE γ' e t--cconsE γ (Case e x _ cases) t- = do γ' <- consCBLet γ (NonRec x e)- forM_ cases $ cconsCase γ' x t nonDefAlts- where- nonDefAlts = [a | (a, _, _) <- cases, a /= DEFAULT]--cconsE γ (Lam α e) (RAllT α' t) | isTyVar α- = cconsE γ e $ subsTyVar_meet' (α', rVar α) t--cconsE γ (Lam x e) (RFun y ty t _)- | not (isTyVar x)- = do γ' <- (γ, "cconsE") += (F.symbol x, ty)- cconsE γ' e (t `F.subst1` (y, F.EVar $ F.symbol x))- addIdA x (AnnDef ty)--cconsE γ (Tick tt e) t- = cconsE (γ `setLoc` tickSrcSpan tt) e t---- GHC 7.10 encodes type classes with a single method as newtypes and--- `cast`s between the method and class type instead of applying the--- class constructor. Just rewrite the core to what we're used to--- seeing..-cconsE γ (Cast e co) t- | Pair _t1 t2 <- coercionKind co- , isClassPred t2- , (tc,ts) <- splitTyConApp t2- , [dc] <- tyConDataCons tc- = cconsE γ (mkCoreConApps dc $ map Type ts ++ [e]) t--cconsE γ e@(Cast e' _) t- = do t' <- castTy γ (exprType e) e'- addC (SubC γ t' t) ("cconsE Cast" ++ showPpr e)--cconsE γ e t- = do te <- consE γ e- te' <- instantiatePreds γ e te >>= addPost γ- addC (SubC γ te' t) ("cconsE" ++ showPpr e)---splitConstraints (RRTy cs _ OCons t)- = let (css, t') = splitConstraints t in (cs:css, t')-splitConstraints (RFun x tx@(RApp c _ _ _) t r) | isClass c- = let (css, t') = splitConstraints t in (css, RFun x tx t' r)-splitConstraints t- = ([], t)----------------------------------------------------------------------- | @instantiatePreds@ peels away the universally quantified @PVars@--- of a @RType@, generates fresh @Ref@ for them and substitutes them--- in the body.--instantiatePreds γ e (RAllP π t)- = do r <- freshPredRef γ e π- instantiatePreds γ e $ replacePreds "consE" t [(π, r)]--instantiatePreds _ _ t0- = return t0------------------------------------------------------------------------ | @instantiateStrata@ generates fresh @Strata@ vars and substitutes--- them inside the body of the type.--instantiateStrata ls t = substStrata t ls <$> mapM (\_ -> fresh) ls--substStrata t ls ls' = F.substa f t- where- f x = fromMaybe x $ L.lookup x su- su = zip ls ls'-----------------------------------------------------------------------cconsLazyLet γ (Let (NonRec x ex) e) t- = do tx <- trueTy (varType x)- γ' <- (γ, "Let NonRec") +++= (x', ex, tx)- cconsE γ' e t- where- x' = F.symbol x--cconsLazyLet _ _ _- = errorstar "Constraint.Generate.cconsLazyLet called on invalid inputs"------------------------------------------------------------------------ | Type Synthesis --------------------------------------------------------------------------------------------------------------------consE :: CGEnv -> Expr Var -> CG SpecType----------------------------------------------------------------------consE γ (Var x)- = do t <- varRefType γ x- addLocA (Just x) (loc γ) (varAnn γ x t)- return t--consE _ (Lit c)- = refreshVV $ uRType $ literalFRefType c--consE γ e'@(App e (Type τ))- = do RAllT α te <- checkAll ("Non-all TyApp with expr", e) <$> consE γ e- t <- if isGeneric α te then freshTy_type TypeInstE e τ else trueTy τ- addW $ WfC γ t- t' <- refreshVV t- instantiatePreds γ e' $ subsTyVar_meet' (α, t') te--consE γ e'@(App e a) | isDictionary a- = if isJust tt- then return $ fromJust tt- else do ([], πs, ls, te) <- bkUniv <$> consE γ e- te0 <- instantiatePreds γ e' $ foldr RAllP te πs- te' <- instantiateStrata ls te0- (γ', te''') <- dropExists γ te'- te'' <- dropConstraints γ te'''- updateLocA πs (exprLoc e) te''- let RFun x tx t _ = checkFun ("Non-fun App with caller ", e') te''- pushConsBind $ cconsE γ' a tx- addPost γ' $ maybe (checkUnbound γ' e' x t a) (F.subst1 t . (x,)) (argExpr γ a)- where- grepfunname (App x (Type _)) = grepfunname x- grepfunname (Var x) = x- grepfunname e = errorstar $ "grepfunname on \t" ++ showPpr e- mdict w = case w of- Var x -> case dlookup (denv γ) x of {Just _ -> Just x; Nothing -> Nothing}- Tick _ e -> mdict e- _ -> Nothing- isDictionary _ = isJust (mdict a)- d = fromJust (mdict a)- dinfo = dlookup (denv γ) d- tt = dhasinfo dinfo $ grepfunname e--consE γ e'@(App e a)- = do ([], πs, ls, te) <- bkUniv <$> consE γ e- te0 <- instantiatePreds γ e' $ foldr RAllP te πs- te' <- instantiateStrata ls te0- (γ', te''') <- dropExists γ te'- te'' <- dropConstraints γ te'''- updateLocA πs (exprLoc e) te''- let RFun x tx t _ = checkFun ("Non-fun App with caller ", e') te''- pushConsBind $ cconsE γ' a tx- addPost γ' $ maybe (checkUnbound γ' e' x t a) (F.subst1 t . (x,)) (argExpr γ a)--consE γ (Lam α e) | isTyVar α- = liftM (RAllT (rTyVar α)) (consE γ e)--consE γ e@(Lam x e1)- = do tx <- freshTy_type LamE (Var x) τx- γ' <- ((γ, "consE") += (F.symbol x, tx))- t1 <- consE γ' e1- addIdA x $ AnnDef tx- addW $ WfC γ tx- return $ rFun (F.symbol x) tx t1- where- FunTy τx _ = exprType e---- EXISTS-BASED CONSTRAINTS HEREHEREHEREHERE--- Currently suppressed because they break all sorts of invariants,--- e.g. for `unfoldR`...--- consE γ e@(Let b@(NonRec x _) e')--- = do γ' <- consCBLet γ b--- consElimE γ' [F.symbol x] e'------ consE γ (Case e x _ [(ac, ys, ce)])--- = do γ' <- consCBLet γ (NonRec x e)--- γ'' <- caseEnv γ' x [] ac ys--- consElimE γ'' (F.symbol <$> (x:ys)) ce--consE γ e@(Let _ _)- = cconsFreshE LetE γ e--consE γ e@(Case _ _ _ _)- = cconsFreshE CaseE γ e--consE γ (Tick tt e)- = do t <- consE (γ `setLoc` l) e- addLocA Nothing l (AnnUse t)- return t- where l = tickSrcSpan tt---- GHC 7.10 encodes type classes with a single method as newtypes and--- `cast`s between the method and class type instead of applying the--- class constructor. Just rewrite the core to what we're used to--- seeing..-consE γ (Cast e co)- | Pair _t1 t2 <- coercionKind co- , isClassPred t2- , (tc,ts) <- splitTyConApp t2- , [dc] <- tyConDataCons tc- = consE γ (mkCoreConApps dc $ map Type ts ++ [e])--consE γ e@(Cast e' _)- = castTy γ (exprType e) e'--consE _ e@(Coercion _)- = trueTy $ exprType e--consE _ e@(Type t)- = errorstar $ "consE cannot handle type " ++ showPpr (e, t)--castTy _ τ (Var x)- = do t <- trueTy τ- return $ t `strengthen` (uTop $ F.uexprReft $ F.expr x)--castTy g t (Tick _ e)- = castTy g t e--castTy _ _ e- = errorstar $ "castTy cannot handle expr " ++ showPpr e---- castTy γ τ e--- = do t <- trueTy (exprType e)--- cconsE γ e t--- trueTy τ--singletonReft = uTop . F.symbolReft . F.symbol---- | @consElimE@ is used to *synthesize* types by **existential elimination**--- instead of *checking* via a fresh template. That is, assuming--- γ |- e1 ~> t1--- we have--- γ |- let x = e1 in e2 ~> Ex x t1 t2--- where--- γ, x:t1 |- e2 ~> t2--- instead of the earlier case where we generate a fresh template `t` and check--- γ, x:t1 |- e <~ t---- consElimE γ xs e--- = do t <- consE γ e--- xts <- forM xs $ \x -> (x,) <$> (γ ??= x)--- return $ rEx xts t---- | @consFreshE@ is used to *synthesize* types with a **fresh template** when--- the above existential elimination is not easy (e.g. at joins, recursive binders)--cconsFreshE kvkind γ e- = do t <- freshTy_type kvkind e $ exprType e- addW $ WfC γ t- cconsE γ e t- return t--checkUnbound γ e x t a- | x `notElem` (F.syms t)- = t- | otherwise- = errorstar $ "checkUnbound: " ++ show x ++ " is elem of syms of " ++ show t- ++ "\nIn\t" ++ showPpr e ++ " at " ++ showPpr (loc γ) ++ "\nArg = \n" ++ show a--dropExists γ (REx x tx t) = liftM (, t) $ (γ, "dropExists") += (x, tx)-dropExists γ t = return (γ, t)--dropConstraints :: CGEnv -> SpecType -> CG SpecType-dropConstraints γ (RFun x tx@(RApp c _ _ _) t r) | isClass c- = (flip (RFun x tx)) r <$> dropConstraints γ t-dropConstraints γ (RRTy cts _ OCons t)- = do γ' <- foldM (\γ (x, t) -> γ `addSEnv` ("splitS", x,t)) γ xts- addC (SubC γ' t1 t2) "dropConstraints"- dropConstraints γ t- where- (xts, t1, t2) = envToSub cts--dropConstraints _ t = return t----------------------------------------------------------------------------------------cconsCase :: CGEnv -> Var -> SpecType -> [AltCon] -> (AltCon, [Var], CoreExpr) -> CG ()---------------------------------------------------------------------------------------cconsCase γ x t acs (ac, ys, ce)- = do cγ <- caseEnv γ x acs ac ys- cconsE cγ ce t--refreshTy t = refreshVV t >>= refreshArgs--refreshVV (RAllT a t) = liftM (RAllT a) (refreshVV t)-refreshVV (RAllP p t) = liftM (RAllP p) (refreshVV t)--refreshVV (REx x t1 t2)- = do [t1', t2'] <- mapM refreshVV [t1, t2]- liftM (shiftVV (REx x t1' t2')) fresh--refreshVV (RFun x t1 t2 r)- = do [t1', t2'] <- mapM refreshVV [t1, t2]- liftM (shiftVV (RFun x t1' t2' r)) fresh--refreshVV (RAppTy t1 t2 r)- = do [t1', t2'] <- mapM refreshVV [t1, t2]- liftM (shiftVV (RAppTy t1' t2' r)) fresh--refreshVV (RApp c ts rs r)- = do ts' <- mapM refreshVV ts- rs' <- mapM refreshVVRef rs- liftM (shiftVV (RApp c ts' rs' r)) fresh--refreshVV t- = return t---refreshVVRef (RProp ss t)- = do xs <- mapM (\_ -> fresh) (fst <$> ss)- let su = F.mkSubst $ zip (fst <$> ss) (F.EVar <$> xs)- liftM (RProp (zip xs (snd <$> ss)) . F.subst su) (refreshVV t)--refreshVVRef (RPropP ss r)- = return $ RPropP ss r--refreshVVRef (RHProp _ _)- = errorstar "TODO: EFFECTS refreshVVRef"-----------------------------------------------------------------------------------------caseEnv :: CGEnv -> Var -> [AltCon] -> AltCon -> [Var] -> CG CGEnv---------------------------------------------------------------------------------------caseEnv γ x _ (DataAlt c) ys- = do let (x' : ys') = F.symbol <$> (x:ys)- xt0 <- checkTyCon ("checkTycon cconsCase", x) <$> γ ??= x'- tdc <- γ ??= (dataConSymbol c) >>= refreshVV- let (rtd, yts, _) = unfoldR tdc (shiftVV xt0 x') ys- let r1 = dataConReft c ys'- let r2 = dataConMsReft rtd ys'- let xt = (xt0 `F.meet` rtd) `strengthen` (uTop (r1 `F.meet` r2))- let cbs = safeZip "cconsCase" (x':ys') (xt0:yts)- cγ' <- addBinders γ x' cbs- cγ <- addBinders cγ' x' [(x', xt)]- return cγ--caseEnv γ x acs a _- = do let x' = F.symbol x- xt' <- (`strengthen` uTop (altReft γ acs a)) <$> (γ ??= x')- cγ <- addBinders γ x' [(x', xt')]- return cγ--altReft _ _ (LitAlt l) = literalFReft l-altReft γ acs DEFAULT = mconcat [notLiteralReft l | LitAlt l <- acs]- where notLiteralReft = maybe mempty F.notExprReft . snd . literalConst (emb γ)-altReft _ _ _ = error "Constraint : altReft"--unfoldR td (RApp _ ts rs _) ys = (t3, tvys ++ yts, ignoreOblig rt)- where- tbody = instantiatePvs (instantiateTys td ts) $ reverse rs- (ys0, yts', _, rt) = safeBkArrow $ instantiateTys tbody tvs'- yts'' = zipWith F.subst sus (yts'++[rt])- (t3,yts) = (last yts'', init yts'')- sus = F.mkSubst <$> (L.inits [(x, F.EVar y) | (x, y) <- zip ys0 ys'])- (αs, ys') = mapSnd (F.symbol <$>) $ L.partition isTyVar ys- tvs' = rVar <$> αs- tvys = ofType . varType <$> αs--unfoldR _ _ _ = error "Constraint.hs : unfoldR"--instantiateTys = foldl' go- where go (RAllT α tbody) t = subsTyVar_meet' (α, t) tbody- go _ _ = errorstar "Constraint.instanctiateTy"--instantiatePvs = foldl' go- where go (RAllP p tbody) r = replacePreds "instantiatePv" tbody [(p, r)]- go _ _ = errorstar "Constraint.instanctiatePv"--checkTyCon _ t@(RApp _ _ _ _) = t-checkTyCon x t = checkErr x t --errorstar $ showPpr x ++ "type: " ++ showPpr t--checkFun _ t@(RFun _ _ _ _) = t-checkFun x t = checkErr x t--checkAll _ t@(RAllT _ _) = t-checkAll x t = checkErr x t--checkErr (msg, e) t = errorstar $ msg ++ showPpr e ++ ", type: " ++ showpp t--varAnn γ x t- | x `S.member` recs γ- = AnnLoc (getSrcSpan' x)- | otherwise- = AnnUse t--getSrcSpan' x- | loc == noSrcSpan- = loc- | otherwise- = loc- where loc = getSrcSpan x---------------------------------------------------------------------------- | Helpers: Creating Fresh Refinement ---------------------------------------------------------------------------------------------------------freshPredRef :: CGEnv -> CoreExpr -> PVar RSort -> CG SpecProp-freshPredRef γ e (PV _ (PVProp τ) _ as)- = do t <- freshTy_type PredInstE e (toType τ)- args <- mapM (\_ -> fresh) as- let targs = [(x, s) | (x, (s, y, z)) <- zip args as, (F.EVar y) == z ]- γ' <- foldM (++=) γ [("freshPredRef", x, ofRSort τ) | (x, τ) <- targs]- addW $ WfC γ' t- return $ RProp targs t--freshPredRef _ _ (PV _ PVHProp _ _)- = errorstar "TODO:EFFECTS:freshPredRef"------------------------------------------------------------------------------------ Helpers: Creating Refinement Types For Various Things --------------------------------------------------------------------------------argExpr :: CGEnv -> CoreExpr -> Maybe F.Expr-argExpr _ (Var vy) = Just $ F.eVar vy-argExpr γ (Lit c) = snd $ literalConst (emb γ) c-argExpr γ (Tick _ e) = argExpr γ e-argExpr _ e = errorstar $ "argExpr: " ++ showPpr e--varRefType :: CGEnv -> Var -> CG SpecType-varRefType γ x = varRefType' γ x <$> (γ ??= F.symbol x)--varRefType' :: CGEnv -> Var -> SpecType -> SpecType-varRefType' γ x t'- | Just tys <- trec γ, Just tr <- M.lookup x' tys- = tr `strengthenS` xr- | otherwise- = t' `strengthenS` xr- where- xr = singletonReft x- x' = F.symbol x----- | RJ: `nomeet` replaces `strengthenS` for `strengthen` in the definition--- of `varRefType`. Why does `tests/neg/strata.hs` fail EVEN if I just replace--- the `otherwise` case? The fq file holds no answers, both are sat.-strengthenS :: (F.Reftable r) => RType c tv r -> r -> RType c tv r-strengthenS (RApp c ts rs r) r' = RApp c ts rs $ topMeet r r'-strengthenS (RVar a r) r' = RVar a $ topMeet r r'-strengthenS (RFun b t1 t2 r) r' = RFun b t1 t2 $ topMeet r r'-strengthenS (RAppTy t1 t2 r) r' = RAppTy t1 t2 $ topMeet r r'-strengthenS t _ = t-topMeet r r' = F.top r `F.meet` r'---- TODO: should only expose/use subt. Not subsTyVar_meet-subsTyVar_meet' (α, t) = subsTyVar_meet (α, toRSort t, t)----------------------------------------------------------------------------------------- Forcing Strictness --------------------------------------------------------------------------------------------------------------instance NFData CGEnv where- rnf (CGE x1 x2 x3 _ x5 x6 x7 x8 x9 _ _ x10 _ _ _ _ _)- = x1 `seq` rnf x2 `seq` seq x3 `seq` rnf x5 `seq`- rnf x6 `seq` x7 `seq` rnf x8 `seq` rnf x9 `seq` rnf x10--instance NFData FEnv where- rnf (FE x1 _) = rnf x1--instance NFData SubC where- rnf (SubC x1 x2 x3)- = rnf x1 `seq` rnf x2 `seq` rnf x3- rnf (SubR x1 _ x2)- = rnf x1 `seq` rnf x2--instance NFData Class where- rnf _ = ()--instance NFData RTyCon where- rnf _ = ()--instance NFData Type where- rnf _ = ()--instance NFData WfC where- rnf (WfC x1 x2)- = rnf x1 `seq` rnf x2--instance NFData CGInfo where- rnf x = ({-# SCC "CGIrnf1" #-} rnf (hsCs x)) `seq`- ({-# SCC "CGIrnf2" #-} rnf (hsWfs x)) `seq`- ({-# SCC "CGIrnf3" #-} rnf (fixCs x)) `seq`- ({-# SCC "CGIrnf4" #-} rnf (fixWfs x)) `seq`- ({-# SCC "CGIrnf6" #-} rnf (freshIndex x)) `seq`- ({-# SCC "CGIrnf7" #-} rnf (binds x)) `seq`- ({-# SCC "CGIrnf8" #-} rnf (annotMap x)) `seq`- ({-# SCC "CGIrnf10" #-} rnf (kuts x)) `seq`- ({-# SCC "CGIrnf10" #-} rnf (lits x)) `seq`- ({-# SCC "CGIrnf10" #-} rnf (kvProf x))------------------------------------------------------------------------------------------------------- Reftypes from F.Fixpoint Expressions --------------------------------------------------------------------------------------------------------forallExprRefType :: CGEnv -> SpecType -> SpecType-forallExprRefType γ t = t `strengthen` (uTop r')- where- r' = fromMaybe mempty $ forallExprReft γ r- r = F.sr_reft $ rTypeSortedReft (emb γ) t--forallExprReft :: CGEnv -> F.Reft -> Maybe F.Reft-forallExprReft γ r = F.isSingletonReft r >>= forallExprReft_ γ---- = do e <- F.isSingletonReft r--- r' <- forallExprReft_ γ e--- return r'--forallExprReft_ :: CGEnv -> F.Expr -> Maybe F.Reft-forallExprReft_ γ (F.EApp f es)- = case forallExprReftLookup γ (val f) of- Just (xs,_,_,t) -> let su = F.mkSubst $ safeZip "fExprRefType" xs es in- Just $ F.subst su $ F.sr_reft $ rTypeSortedReft (emb γ) t- Nothing -> Nothing -- F.exprReft e--forallExprReft_ γ (F.EVar x)- = case forallExprReftLookup γ x of- Just (_,_,_,t) -> Just $ F.sr_reft $ rTypeSortedReft (emb γ) t- Nothing -> Nothing -- F.exprReft e--forallExprReft_ _ _ = Nothing -- F.exprReft e--forallExprReftLookup γ x = snap <$> F.lookupSEnv x (syenv γ)- where- snap = mapFourth4 ignoreOblig . bkArrow . fourth4 . bkUniv . (γ ?=) . F.symbol--{--splitExistsCases z xs tx- = fmap $ fmap (exrefAddEq z xs tx)--exrefAddEq z xs t (F.Reft (s, F.Refa rs))- = F.Reft(s, F.Refa (F.POr [ pand x | x <- xs]))- where- tref = fromMaybe mempty $ stripRTypeBase t- pand x = substzx x rs `mappend` exrefToPred x tref- substzx x = F.subst (F.mkSubst [(z, F.EVar x)])--exrefToPred x u = F.subst (F.mkSubst [(v, F.EVar x)]) p- where- F.Reft (v, F.Refa p) = ur_reft u--}------------------------------------------------------------------------------------------------------ Cleaner Signatures For Rec-bindings --------------------------------------------------------------------------------------------------------exprLoc :: CoreExpr -> Maybe SrcSpan--exprLoc (Tick tt _) = Just $ tickSrcSpan tt-exprLoc (App e a) | isType a = exprLoc e-exprLoc _ = Nothing--isType (Type _) = True-isType a = eqType (exprType a) predType---exprRefType :: CoreExpr -> SpecType-exprRefType = exprRefType_ M.empty--exprRefType_ :: M.HashMap Var SpecType -> CoreExpr -> SpecType-exprRefType_ γ (Let b e)- = exprRefType_ (bindRefType_ γ b) e--exprRefType_ γ (Lam α e) | isTyVar α- = RAllT (rTyVar α) (exprRefType_ γ e)--exprRefType_ γ (Lam x e)- = rFun (F.symbol x) (ofType $ varType x) (exprRefType_ γ e)--exprRefType_ γ (Tick _ e)- = exprRefType_ γ e--exprRefType_ γ (Var x)- = M.lookupDefault (ofType $ varType x) x γ--exprRefType_ _ e- = ofType $ exprType e--bindRefType_ γ (Rec xes)- = extendγ γ [(x, exprRefType_ γ e) | (x,e) <- xes]--bindRefType_ γ (NonRec x e)- = extendγ γ [(x, exprRefType_ γ e)]--extendγ γ xts- = foldr (\(x,t) m -> M.insert x t m) γ xts---instance NFData REnv where- rnf (REnv _) = () -- rnf m+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE ImplicitParams #-}++-- | This module defines the representation of Subtyping and WF Constraints, and+-- the code for syntax-directed constraint generation.++module Language.Haskell.Liquid.Constraint.Generate ( generateConstraints ) where++import Prelude hiding (error, undefined)++import GHC.Stack+import CoreUtils (exprType)+import MkCore+import Coercion+import DataCon+import Pair+import CoreSyn+import SrcLoc+import Type+import TyCon+import PrelNames+import TypeRep+import Class (className)+import Var+import Kind+import Id+import IdInfo+import Name+import NameSet+import Unify+import VarSet+-- import Unique+++import Text.PrettyPrint.HughesPJ hiding (first)+import Control.Monad.State+-- import Control.Applicative ((<$>), (<*>), Applicative)+-- import Data.Monoid (mconcat, mempty, mappend)+import Data.Maybe (fromMaybe, catMaybes, fromJust, isJust)+import qualified Data.HashMap.Strict as M+import qualified Data.HashSet as S+import qualified Data.List as L++import Data.Bifunctor+import qualified Data.Foldable as F+import qualified Data.Traversable as T++++++import qualified Language.Haskell.Liquid.UX.CTags as Tg++++import Language.Fixpoint.Types.Visitor++import Language.Haskell.Liquid.Constraint.Fresh+import Language.Haskell.Liquid.Constraint.Env+import Language.Haskell.Liquid.Constraint.Monad+import Language.Haskell.Liquid.Constraint.Split++import qualified Language.Fixpoint.Types as F++import Language.Haskell.Liquid.WiredIn (dictionaryVar)+import Language.Haskell.Liquid.Types.Dictionaries++import qualified Language.Haskell.Liquid.GHC.SpanStack as Sp+import Language.Haskell.Liquid.Types hiding (binds, Loc, loc, freeTyVars, Def)+import Language.Haskell.Liquid.Types.Strata+import Language.Haskell.Liquid.Types.Names++import Language.Haskell.Liquid.Types.RefType+import Language.Haskell.Liquid.Types.Visitors hiding (freeVars)+import Language.Haskell.Liquid.Types.PredType hiding (freeTyVars)+import Language.Haskell.Liquid.Types.Meet+import Language.Haskell.Liquid.GHC.Misc ( isInternal, collectArguments, tickSrcSpan+ , hasBaseTypeVar, showPpr, isDataConId)+import Language.Haskell.Liquid.Misc+import Language.Fixpoint.Misc+import Language.Haskell.Liquid.Types.Literals++import Language.Haskell.Liquid.Constraint.Axioms+import Language.Haskell.Liquid.Constraint.Types+import Language.Haskell.Liquid.Constraint.Constraint++-- import Debug.Trace (trace)++-----------------------------------------------------------------------+------------- Constraint Generation: Toplevel -------------------------+-----------------------------------------------------------------------++generateConstraints :: GhcInfo -> CGInfo+generateConstraints info = {-# SCC "ConsGen" #-} execState act $ initCGI cfg info+ where+ act = consAct info+ cfg = config $ spec info++consAct :: GhcInfo -> CG ()+consAct info+ = do γ' <- initEnv info+ sflag <- scheck <$> get+ tflag <- trustghc <$> get+ γ <- if expandProofsMode then addCombine τProof γ' else return γ'+ cbs' <- if expandProofsMode then mapM (expandProofs info (mkSigs γ)) $ cbs info else return $ cbs info+ let trustBinding x = tflag && (x `elem` derVars info || isInternal x)+ foldM_ (consCBTop trustBinding) γ cbs'+ hcs <- hsCs <$> get+ hws <- hsWfs <$> get+ scss <- sCs <$> get+ annot <- annotMap <$> get+ scs <- if sflag then concat <$> mapM splitS (hcs ++ scss)+ else return []+ let smap = if sflag then solveStrata scs else []+ let hcs' = if sflag then subsS smap hcs else hcs+ fcs <- concat <$> mapM splitC (subsS smap hcs')+ fws <- concat <$> mapM splitW hws+ let annot' = if sflag then subsS smap <$> annot else annot+ modify $ \st -> st { fEnv = fixEnv γ, fixCs = fcs , fixWfs = fws , annotMap = annot'}+ where+ expandProofsMode = autoproofs $ config $ spec info+ τProof = proofType $ spec info+ fixEnv = feEnv . fenv+ mkSigs γ = toListREnv (renv γ) +++ toListREnv (assms γ) +++ toListREnv (intys γ) +++ toListREnv (grtys γ)++addCombine τ γ+ = do t <- trueTy combineType+ γ ++= ("combineProofs", combineSymbol, t)+ where+ combineType = makeCombineType τ+ combineVar = makeCombineVar combineType+ combineSymbol = F.symbol combineVar++------------------------------------------------------------------------------------+initEnv :: GhcInfo -> CG CGEnv+------------------------------------------------------------------------------------+initEnv info+ = do let tce = tcEmbeds sp+ let fVars = impVars info+ let dcs = filter isConLikeId ((snd <$> freeSyms sp))+ let dcs' = filter isConLikeId fVars+ defaults <- forM fVars $ \x -> liftM (x,) (trueTy $ varType x)+ dcsty <- forM dcs $ makeDataConTypes+ dcsty' <- forM dcs' $ makeDataConTypes+ (hs,f0) <- refreshHoles $ grty info -- asserted refinements (for defined vars)+ f0'' <- refreshArgs' =<< grtyTop info -- default TOP reftype (for exported vars without spec)+ let f0' = if notruetypes $ config sp then [] else f0''+ f1 <- refreshArgs' defaults -- default TOP reftype (for all vars)+ f1' <- refreshArgs' $ makedcs dcsty+ f2 <- refreshArgs' $ assm info -- assumed refinements (for imported vars)+ f3 <- refreshArgs' $ vals asmSigs sp -- assumed refinedments (with `assume`)+ f40 <- refreshArgs' $ vals ctors sp -- constructor refinements (for measures)+ f5 <- refreshArgs' $ vals inSigs sp -- internal refinements (from Haskell measures)+ (invs1, f41) <- mapSndM refreshArgs' $ makeAutoDecrDataCons dcsty (autosize sp) dcs+ (invs2, f42) <- mapSndM refreshArgs' $ makeAutoDecrDataCons dcsty' (autosize sp) dcs'+ let f4 = mergeDataConTypes (mergeDataConTypes f40 (f41 ++ f42)) (filter (isDataConId . fst) f2)+ sflag <- scheck <$> get+ let senv = if sflag then f2 else []+ let tx = mapFst F.symbol . addRInv ialias . strataUnify senv . predsUnify sp+ let bs = (tx <$> ) <$> [f0 ++ f0', f1 ++ f1', f2, f3, f4, f5]+ lts <- lits <$> get+ let tcb = mapSnd (rTypeSort tce) <$> concat bs+ let γ0 = measEnv sp (head bs) (cbs info) (tcb ++ lts) (bs!!3) (bs!!5) hs (invs1 ++ invs2)+ globalize <$> foldM (++=) γ0 [("initEnv", x, y) | (x, y) <- concat $ tail bs]+ where+ sp = spec info+ ialias = mkRTyConIAl $ ialiases sp+ vals f = map (mapSnd val) . f+ mapSndM f (x,y) = (x,) <$> f y+ makedcs = map strengthenDataConType++makeDataConTypes x = (x,) <$> (trueTy $ varType x)++makeAutoDecrDataCons dcts specenv dcs+ = (simplify invs, tys)+ where+ (invs, tys) = unzip $ concatMap go tycons+ tycons = L.nub $ catMaybes $ map idTyCon dcs++ go tycon+ | S.member tycon specenv = zipWith (makeSizedDataCons dcts) (tyConDataCons tycon) [0..]+ go _+ = []+ idTyCon x = dataConTyCon <$> case idDetails x of {DataConWorkId d -> Just d; DataConWrapId d -> Just d; _ -> Nothing}++ simplify invs = dummyLoc . (`strengthen` invariant) . fmap (\_ -> mempty) <$> L.nub invs+ invariant = MkUReft (F.Reft (F.vv_, F.PAtom F.Ge (lenOf F.vv_) (F.ECon $ F.I 0)) ) mempty mempty++lenOf x = F.mkEApp lenLocSymbol [F.EVar x]++makeSizedDataCons dcts x' n = (toRSort $ ty_res trep, (x, fromRTypeRep trep{ty_res = tres}))+ where+ x = dataConWorkId x'+ t = fromMaybe (impossible Nothing "makeSizedDataCons: this should never happen") $ L.lookup x dcts+ trep = toRTypeRep t+ tres = ty_res trep `strengthen` MkUReft (F.Reft (F.vv_, F.PAtom F.Eq (lenOf F.vv_) computelen)) mempty mempty++ recarguments = filter (\(t,_) -> (toRSort t == toRSort tres)) (zip (ty_args trep) (ty_binds trep))+ computelen = foldr (F.EBin F.Plus) (F.ECon $ F.I n) (lenOf . snd <$> recarguments)++mergeDataConTypes :: [(Var, SpecType)] -> [(Var, SpecType)] -> [(Var, SpecType)]+mergeDataConTypes xts yts = merge (L.sortBy f xts) (L.sortBy f yts)+ where+ f (x,_) (y,_) = compare x y+ merge [] ys = ys+ merge xs [] = xs+ merge (xt@(x, tx):xs) (yt@(y, ty):ys)+ | x == y = (x, mXY x tx y ty) : merge xs ys+ | x < y = xt : merge xs (yt : ys)+ | otherwise = yt : merge (xt : xs) ys+ mXY x tx y ty = meetVarTypes (pprint x) (getSrcSpan x, tx) (getSrcSpan y, ty)++refreshHoles vts = first catMaybes . unzip . map extract <$> mapM refreshHoles' vts+refreshHoles' (x,t)+ | noHoles t = return (Nothing, x, t)+ | otherwise = (Just $ F.symbol x,x,) <$> mapReftM tx t+ where+ tx r | hasHole r = refresh r+ | otherwise = return r+extract (a,b,c) = (a,(b,c))++refreshArgs' = mapM (mapSndM refreshArgs)++strataUnify :: [(Var, SpecType)] -> (Var, SpecType) -> (Var, SpecType)+strataUnify senv (x, t) = (x, maybe t (mappend t) pt)+ where+ pt = fmap (\(MkUReft _ _ l) -> MkUReft mempty mempty l) <$> L.lookup x senv+++-- | TODO: All this *should* happen inside @Bare@ but appears+-- to happen after certain are signatures are @fresh@-ed,+-- which is why they are here.++-- NV : still some sigs do not get TyConInfo++predsUnify :: GhcSpec -> (Var, RRType RReft) -> (Var, RRType RReft)+predsUnify sp = second (addTyConInfo tce tyi) -- needed to eliminate some @RPropH@+ where+ tce = tcEmbeds sp+ tyi = tyconEnv sp++-------------------------------------------------------------------------------+-------------------------------------------------------------------------------+-------------------------------------------------------------------------------++measEnv sp xts cbs lts asms itys hs autosizes+ = CGE { cgLoc = Sp.empty+ , renv = fromListREnv (second val <$> meas sp) []+ , syenv = F.fromListSEnv $ freeSyms sp+ , fenv = initFEnv $ lts ++ (second (rTypeSort tce . val) <$> meas sp)+ , denv = dicts sp+ , recs = S.empty+ , invs = mkRTyConInv $ (invariants sp ++ autosizes)+ , ial = mkRTyConIAl $ ialiases sp+ , grtys = fromListREnv xts []+ , assms = fromListREnv asms []+ , intys = fromListREnv itys []+ , emb = tce+ , tgEnv = Tg.makeTagEnv cbs+ , tgKey = Nothing+ , trec = Nothing+ , lcb = M.empty+ , holes = fromListHEnv hs+ , lcs = mempty+ , aenv = axiom_map $ logicMap sp+ , cerr = Nothing + }+ where+ tce = tcEmbeds sp++assm = assmGrty impVars+grty = assmGrty defVars++assmGrty f info = [ (x, val t) | (x, t) <- sigs, x `S.member` xs ]+ where+ xs = S.fromList $ f info+ sigs = tySigs $ spec info++grtyTop info = forM topVs $ \v -> (v,) <$> trueTy (varType v)+ where+ topVs = filter isTop $ defVars info+ isTop v = isExportedId v && not (v `S.member` sigVs)+ isExportedId = flip elemNameSet (exports $ spec info) . getName+ sigVs = S.fromList [v | (v,_) <- tySigs (spec info) ++ asmSigs (spec info) ++ inSigs (spec info)]++initCGI cfg info = CGInfo {+ fEnv = F.emptySEnv+ , hsCs = []+ , sCs = []+ , hsWfs = []+ , fixCs = []+ , isBind = []+ , fixWfs = []+ , freshIndex = 0+ , binds = F.emptyBindEnv+ , annotMap = AI M.empty+ , tyConInfo = tyi+ , tyConEmbed = tce+ , kuts = mempty -- F.ksEmpty+ , lits = coreBindLits tce info ++ (map (mapSnd F.sr_sort) $ map mkSort $ meas spc)+ , termExprs = M.fromList $ texprs spc+ , specDecr = decr spc+ , specLVars = lvars spc+ , specLazy = dictionaryVar `S.insert` lazy spc+ , tcheck = not $ notermination cfg+ , scheck = strata cfg+ , trustghc = trustinternals cfg+ , pruneRefs = not $ noPrune cfg+ , logErrors = []+ , kvProf = emptyKVProf+ , recCount = 0+ , bindSpans = M.empty+ , autoSize = autosize spc+ , allowHO = higherorder cfg + }+ where+ tce = tcEmbeds spc+ spc = spec info+ tyi = tyconEnv spc+ mkSort = mapSnd (rTypeSortedReft tce . val)++coreBindLits :: F.TCEmb TyCon -> GhcInfo -> [(F.Symbol, F.Sort)]+coreBindLits tce info+ = sortNub $ [ (F.symbol x, F.strSort) | (_, Just (F.ESym x)) <- lconsts ] -- strings+ ++ [ (dconToSym dc, dconToSort dc) | dc <- dcons ] -- data constructors+ where+ lconsts = literalConst tce <$> literals (cbs info)+ dcons = filter isDCon freeVs+ freeVs = impVars info ++ (snd <$> freeSyms (spec info))+ dconToSort = typeSort tce . expandTypeSynonyms . varType+ dconToSym = F.symbol . idDataCon+ isDCon x = isDataConId x && not (hasBaseTypeVar x)++-------------------------------------------------------------------+-- | Generation: Freshness ---------------------------------------+-------------------------------------------------------------------++-- | Right now, we generate NO new pvars. Rather than clutter code+-- with `uRType` calls, put it in one place where the above+-- invariant is /obviously/ enforced.+-- Constraint generation should ONLY use @freshTy_type@ and @freshTy_expr@++freshTy_type :: KVKind -> CoreExpr -> Type -> CG SpecType+freshTy_type k _ τ = freshTy_reftype k $ ofType τ++freshTy_expr :: KVKind -> CoreExpr -> Type -> CG SpecType+freshTy_expr k e _ = freshTy_reftype k $ exprRefType e++freshTy_reftype :: KVKind -> SpecType -> CG SpecType+freshTy_reftype k t = (fixTy t >>= refresh) =>> addKVars k++-- | Used to generate "cut" kvars for fixpoint. Typically, KVars for recursive+-- definitions, and also to update the KVar profile.+addKVars :: KVKind -> SpecType -> CG ()+addKVars !k !t = do when (True) $ modify $ \s -> s { kvProf = updKVProf k kvars (kvProf s) }+ when (isKut k) $ modify $ \s -> s { kuts = mappend kvars (kuts s) }+ where+ kvars = F.KS $ S.fromList $ specTypeKVars t++isKut :: KVKind -> Bool+isKut RecBindE = True+isKut _ = False++specTypeKVars :: SpecType -> [F.KVar]+specTypeKVars = foldReft (\ _ r ks -> (kvars $ ur_reft r) ++ ks) []++trueTy :: Type -> CG SpecType+trueTy = ofType' >=> true++ofType' :: Type -> CG SpecType+ofType' = fixTy . ofType++fixTy :: SpecType -> CG SpecType+fixTy t = do tyi <- tyConInfo <$> get+ tce <- tyConEmbed <$> get+ return $ addTyConInfo tce tyi t++refreshArgsTop :: (Var, SpecType) -> CG SpecType+refreshArgsTop (x, t)+ = do (t', su) <- refreshArgsSub t+ modify $ \s -> s {termExprs = M.adjust (F.subst su <$>) x $ termExprs s}+ return t'++refreshArgs :: SpecType -> CG SpecType+refreshArgs t+ = fst <$> refreshArgsSub t+++-- NV TODO: this does not refresh args if they are wrapped in an RRTy+refreshArgsSub :: SpecType -> CG (SpecType, F.Subst)+refreshArgsSub t+ = do ts <- mapM refreshArgs ts_u+ xs' <- mapM (\_ -> fresh) xs+ let sus = F.mkSubst <$> (L.inits $ zip xs (F.EVar <$> xs'))+ let su = last sus+ let ts' = zipWith F.subst sus ts+ let t' = fromRTypeRep $ trep {ty_binds = xs', ty_args = ts', ty_res = F.subst su tbd}+ return (t', su)+ where+ trep = toRTypeRep t+ xs = ty_binds trep+ ts_u = ty_args trep+ tbd = ty_res trep++-------------------------------------------------------------------------------+-- | TERMINATION TYPE --------------------------------------+-------------------------------------------------------------------------------++makeDecrIndex :: (Var, Template SpecType)-> CG [Int]+makeDecrIndex (x, Assumed t)+ = do dindex <- makeDecrIndexTy x t+ case dindex of+ Left _ -> return []+ Right i -> return i+makeDecrIndex (x, Asserted t)+ = do dindex <- makeDecrIndexTy x t+ case dindex of+ Left msg -> addWarning msg >> return []+ Right i -> return i+makeDecrIndex _ = return []++makeDecrIndexTy x t+ = do spDecr <- specDecr <$> get+ autosz <- autoSize <$> get+ hint <- checkHint' autosz (L.lookup x $ spDecr)+ case dindex autosz of+ Nothing -> return $ Left msg+ Just i -> return $ Right $ fromMaybe [i] hint+ where+ ts = ty_args trep+ checkHint' = \autosz -> checkHint x ts (isDecreasing autosz cenv)+ dindex = \autosz -> L.findIndex (isDecreasing autosz cenv) ts+ msg = ErrTermin (getSrcSpan x) [pprint x] (text "No decreasing parameter")+ cenv = makeNumEnv ts+ trep = toRTypeRep $ unOCons t+++recType _ ((_, []), (_, [], t))+ = t++recType autoenv ((vs, indexc), (_, index, t))+ = makeRecType autoenv t v dxt index+ where v = (vs !!) <$> indexc+ dxt = (xts !!) <$> index+ xts = zip (ty_binds trep) (ty_args trep)+ trep = toRTypeRep $ unOCons t++-- checkIndex :: (Var, _, _ , _) -> _+checkIndex (x, vs, t, index)+ = do mapM_ (safeLogIndex msg1 vs) index+ mapM (safeLogIndex msg2 ts) index+ where+ loc = getSrcSpan x+ ts = ty_args $ toRTypeRep $ unOCons $ unTemplate t+ msg1 = ErrTermin loc [xd] ("No decreasing" <+> pprint index <> "-th argument on" <+> xd <+> "with" <+> (pprint vs))+ msg2 = ErrTermin loc [xd] "No decreasing parameter"+ xd = pprint x++makeRecType autoenv t vs dxs is+ = mergecondition t $ fromRTypeRep $ trep {ty_binds = xs', ty_args = ts'}+ where+ (xs', ts') = unzip $ replaceN (last is) (makeDecrType autoenv vdxs) xts+ vdxs = zip vs dxs+ xts = zip (ty_binds trep) (ty_args trep)+ trep = toRTypeRep $ unOCons t++unOCons (RAllT v t) = RAllT v $ unOCons t+unOCons (RAllP p t) = RAllP p $ unOCons t+unOCons (RFun x tx t r) = RFun x (unOCons tx) (unOCons t) r+unOCons (RRTy _ _ OCons t) = unOCons t+unOCons t = t+++mergecondition (RAllT _ t1) (RAllT v t2)+ = RAllT v $ mergecondition t1 t2+mergecondition (RAllP _ t1) (RAllP p t2)+ = RAllP p $ mergecondition t1 t2+mergecondition (RRTy xts r OCons t1) t2+ = RRTy xts r OCons (mergecondition t1 t2)+mergecondition (RFun _ t11 t12 _) (RFun x2 t21 t22 r2)+ = RFun x2 (mergecondition t11 t21) (mergecondition t12 t22) r2+mergecondition _ t+ = t++safeLogIndex err ls n+ | n >= length ls = addWarning err >> return Nothing+ | otherwise = return $ Just $ ls !! n++checkHint _ _ _ Nothing+ = return Nothing++checkHint x _ _ (Just ns) | L.sort ns /= ns+ = addWarning (ErrTermin loc [dx] (text "The hints should be increasing")) >> return Nothing+ where+ loc = getSrcSpan x+ dx = pprint x++checkHint x ts f (Just ns)+ = (mapM (checkValidHint x ts f) ns) >>= (return . Just . catMaybes)++checkValidHint x ts f n+ | n < 0 || n >= length ts = addWarning err >> return Nothing+ | f (ts L.!! n) = return $ Just n+ | otherwise = addWarning err >> return Nothing+ where+ err = ErrTermin loc [xd] (vcat [ "Invalid Hint" <+> pprint (n+1) <+> "for" <+> xd+ , "in"+ , pprint ts ])+ loc = getSrcSpan x+ xd = pprint x++--------------------------------------------------------------------------------+consCBLet :: CGEnv -> CoreBind -> CG CGEnv+--------------------------------------------------------------------------------+consCBLet γ cb+ = do oldtcheck <- tcheck <$> get+ strict <- specLazy <$> get+ let tflag = oldtcheck+ let isStr = tcond cb strict+ -- TODO: yuck.+ modify $ \s -> s { tcheck = tflag && isStr }+ γ' <- consCB (tflag && isStr) isStr γ cb+ modify $ \s -> s{tcheck = oldtcheck}+ return γ'++--------------------------------------------------------------------------------+-- | Constraint Generation: Corebind -------------------------------------------+--------------------------------------------------------------------------------+consCBTop :: (Var -> Bool) -> CGEnv -> CoreBind -> CG CGEnv+--------------------------------------------------------------------------------+consCBTop trustBinding γ cb | all trustBinding xs+ = do ts <- mapM trueTy (varType <$> xs)+ foldM (\γ xt -> (γ, "derived") += xt) γ (zip xs' ts)+ where+ xs = bindersOf cb+ xs' = F.symbol <$> xs++consCBTop _ γ cb+ = do oldtcheck <- tcheck <$> get+ strict <- specLazy <$> get+ let tflag = oldtcheck+ let isStr = tcond cb strict+ modify $ \s -> s { tcheck = tflag && isStr}+ γ' <- consCB (tflag && isStr) isStr γ cb+ modify $ \s -> s { tcheck = oldtcheck}+ return γ'++tcond cb strict+ = not $ any (\x -> S.member x strict || isInternal x) (binds cb)+ where+ binds (NonRec x _) = [x]+ binds (Rec xes) = fst $ unzip xes++--------------------------------------------------------------------------------+consCB :: Bool -> Bool -> CGEnv -> CoreBind -> CG CGEnv+--------------------------------------------------------------------------------++-- RJ: AAAAAAARGHHH!!!!!! THIS CODE IS HORRIBLE!!!!!!!!!+consCBSizedTys γ xes+ = do xets'' <- forM xes $ \(x, e) -> liftM (x, e,) (varTemplate γ (x, Just e))+ sflag <- scheck <$> get+ autoenv <- autoSize <$> get+ let cmakeFinType = if sflag then makeFinType else id+ let cmakeFinTy = if sflag then makeFinTy else snd+ let xets = mapThd3 (fmap cmakeFinType) <$> xets''+ ts' <- mapM (T.mapM refreshArgs) $ (thd3 <$> xets)+ let vs = zipWith collectArgs ts' es+ is <- mapM makeDecrIndex (zip xs ts') >>= checkSameLens+ let ts = cmakeFinTy <$> zip is ts'+ let xeets = (\vis -> [(vis, x) | x <- zip3 xs is $ map unTemplate ts]) <$> (zip vs is)+ (L.transpose <$> mapM checkIndex (zip4 xs vs ts is)) >>= checkEqTypes+ let rts = (recType autoenv <$>) <$> xeets+ let xts = zip xs ts+ γ' <- foldM extender γ xts+ let γs = [γ' `setTRec` (zip xs rts') | rts' <- rts]+ let xets' = zip3 xs es ts+ mapM_ (uncurry $ consBind True) (zip γs xets')+ return γ'+ where+ (xs, es) = unzip xes+ dxs = pprint <$> xs+ collectArgs = collectArguments . length . ty_binds . toRTypeRep . unOCons . unTemplate+ checkEqTypes :: [[Maybe SpecType]] -> CG [[SpecType]]+ checkEqTypes x = mapM (checkAll err1 toRSort) (catMaybes <$> x)+ checkSameLens = checkAll err2 length+ err1 = ErrTermin loc dxs $ text "The decreasing parameters should be of same type"+ err2 = ErrTermin loc dxs $ text "All Recursive functions should have the same number of decreasing parameters"+ loc = getSrcSpan (head xs)++ checkAll _ _ [] = return []+ checkAll err f (x:xs)+ | all (==(f x)) (f <$> xs) = return (x:xs)+ | otherwise = addWarning err >> return []++consCBWithExprs γ xes+ = do xets' <- forM xes $ \(x, e) -> liftM (x, e,) (varTemplate γ (x, Just e))+ texprs <- termExprs <$> get+ let xtes = catMaybes $ (`lookup` texprs) <$> xs+ sflag <- scheck <$> get+ let cmakeFinType = if sflag then makeFinType else id+ let xets = mapThd3 (fmap cmakeFinType) <$> xets'+ let ts = safeFromAsserted err . thd3 <$> xets+ ts' <- mapM refreshArgs ts+ let xts = zip xs (Asserted <$> ts')+ γ' <- foldM extender γ xts+ let γs = makeTermEnvs γ' xtes xes ts ts'+ let xets' = zip3 xs es (Asserted <$> ts')+ mapM_ (uncurry $ consBind True) (zip γs xets')+ return γ'+ where (xs, es) = unzip xes+ lookup k m | Just x <- M.lookup k m = Just (k, x)+ | otherwise = Nothing+ err = "Constant: consCBWithExprs"++makeFinTy (ns, t) = fmap go t+ where+ go t = fromRTypeRep $ trep {ty_args = args'}+ where+ trep = toRTypeRep t+ args' = mapNs ns makeFinType $ ty_args trep++makeTermEnvs γ xtes xes ts ts' = setTRec γ . zip xs <$> rts+ where+ vs = zipWith collectArgs ts es+ ys = (fst4 . bkArrowDeep) <$> ts+ ys' = (fst4 . bkArrowDeep) <$> ts'+ sus' = zipWith mkSub ys ys'+ sus = zipWith mkSub ys ((F.symbol <$>) <$> vs)+ ess = (\x -> (safeFromJust (err x) $ (x `L.lookup` xtes))) <$> xs+ tes = zipWith (\su es -> F.subst su <$> es) sus ess+ tes' = zipWith (\su es -> F.subst su <$> es) sus' ess+ rss = zipWith makeLexRefa tes' <$> (repeat <$> tes)+ rts = zipWith (addObligation OTerm) ts' <$> rss+ (xs, es) = unzip xes+ mkSub ys ys' = F.mkSubst [(x, F.EVar y) | (x, y) <- zip ys ys']+ collectArgs = collectArguments . length . ty_binds . toRTypeRep+ err x = "Constant: makeTermEnvs: no terminating expression for " ++ showPpr x++addObligation :: Oblig -> SpecType -> RReft -> SpecType+addObligation o t r = mkArrow αs πs ls xts $ RRTy [] r o t2+ where+ (αs, πs, ls, t1) = bkUniv t+ (xs, ts, rs, t2) = bkArrow t1+ xts = zip3 xs ts rs+++consCB tflag _ γ (Rec xes) | tflag+ = do texprs <- termExprs <$> get+ modify $ \i -> i { recCount = recCount i + length xes }+ let xxes = catMaybes $ (`lookup` texprs) <$> xs+ if null xxes+ then consCBSizedTys γ xes+ else check xxes <$> consCBWithExprs γ xes+ where+ xs = fst $ unzip xes+ check ys r | length ys == length xs = r+ | otherwise = panic (Just loc) $ msg+ msg = "Termination expressions must be provided for all mutually recursive binders"+ loc = getSrcSpan (head xs)+ lookup k m = (k,) <$> M.lookup k m++consCB _ str γ (Rec xes) | not str+ = do xets' <- forM xes $ \(x, e) -> liftM (x, e,) (varTemplate γ (x, Just e))+ sflag <- scheck <$> get+ let cmakeDivType = if sflag then makeDivType else id+ let xets = mapThd3 (fmap cmakeDivType) <$> xets'+ modify $ \i -> i { recCount = recCount i + length xes }+ let xts = [(x, to) | (x, _, to) <- xets]+ γ' <- foldM extender (γ `setRecs` (fst <$> xts)) xts+ mapM_ (consBind True γ') xets+ return γ'++consCB _ _ γ (Rec xes)+ = do xets <- forM xes $ \(x, e) -> liftM (x, e,) (varTemplate γ (x, Just e))+ modify $ \i -> i { recCount = recCount i + length xes }+ let xts = [(x, to) | (x, _, to) <- xets]+ γ' <- foldM extender (γ `setRecs` (fst <$> xts)) xts+ mapM_ (consBind True γ') xets+ return γ'++-- | NV: Dictionaries are not checked, because+-- | class methods' preconditions are not satisfied+consCB _ _ γ (NonRec x _) | isDictionary x+ = do t <- trueTy (varType x)+ extender γ (x, Assumed t)+ where+ isDictionary = isJust . dlookup (denv γ)+++consCB _ _ γ (NonRec x (App (Var w) (Type τ)))+ | Just d <- dlookup (denv γ) w+ = do t <- trueTy τ+ addW $ WfC γ t+ let xts = dmap (f t) d+ let γ' = γ{denv = dinsert (denv γ) x xts }+ t <- trueTy (varType x)+ extender γ' (x, Assumed t)+ where+ f t' (RAllT α te) = subsTyVar_meet' (α, t') te+ f _ _ = impossible Nothing "consCB on Dictionary: this should not happen"++consCB _ _ γ (NonRec x e)+ = do to <- varTemplate γ (x, Nothing)+ to' <- consBind False γ (x, e, to) >>= (addPostTemplate γ)+ extender γ (x, to')++--------------------------------------------------------------------------------+consBind :: Bool+ -> CGEnv+ -> (Var, CoreExpr ,Template SpecType)+ -> CG (Template SpecType)+--------------------------------------------------------------------------------+consBind _ _ (x, _, t)+ | RecSelId {} <- idDetails x -- don't check record selectors+ = return t++consBind isRec γ (x, e, Asserted spect)+ = do let γ' = γ `setBind` x+ (_,πs,_,_) = bkUniv spect+ γπ <- foldM addPToEnv γ' πs+ cconsE γπ e spect+ when (F.symbol x `elemHEnv` holes γ) $+ -- have to add the wf constraint here for HOLEs so we have the proper env+ addW $ WfC γπ $ fmap killSubst spect+ addIdA x (defAnn isRec spect)+ return $ Asserted spect -- Nothing++consBind isRec γ (x, e, Internal spect)+ = do let γ' = γ `setBind` x+ (_,πs,_,_) = bkUniv spect+ γπ <- foldM addPToEnv γ' πs+ let γπ' = γπ {cerr = Just $ ErrHMeas (getLocation γπ) (pprint x) (text explanation)}+ cconsE γπ' e spect+ when (F.symbol x `elemHEnv` holes γ) $+ -- have to add the wf constraint here for HOLEs so we have the proper env+ addW $ WfC γπ $ fmap killSubst spect+ addIdA x (defAnn isRec spect)+ return $ Internal spect -- Nothing+ where+ explanation = "Cannot give singleton type to the function definition."+++consBind isRec γ (x, e, Assumed spect)+ = do let γ' = γ `setBind` x+ γπ <- foldM addPToEnv γ' πs+ cconsE γπ e =<< true spect+ addIdA x (defAnn isRec spect)+ return $ Asserted spect -- Nothing+ where πs = ty_preds $ toRTypeRep spect++consBind isRec γ (x, e, Unknown)+ = do t <- consE (γ `setBind` x) e+ addIdA x (defAnn isRec t)+ return $ Asserted t+++noHoles = and . foldReft (\_ r bs -> not (hasHole r) : bs) []++killSubst :: RReft -> RReft+killSubst = fmap killSubstReft++killSubstReft :: F.Reft -> F.Reft+killSubstReft = trans kv () ()+ where+ kv = defaultVisitor { txExpr = ks }+ ks _ (F.PKVar k _) = F.PKVar k mempty+ ks _ p = p++ -- tx (F.Reft (s, rs)) = F.Reft (s, map f rs)+ -- f (F.RKvar k _) = F.RKvar k mempty+ -- f (F.RConc p) = F.RConc p++defAnn True = AnnRDf+defAnn False = AnnDef++addPToEnv γ π+ = do γπ <- γ ++= ("addSpec1", pname π, pvarRType π)+ foldM (++=) γπ [("addSpec2", x, ofRSort t) | (t, x, _) <- pargs π]++extender γ (x, Asserted t) = γ ++= ("extender", F.symbol x, t)+extender γ (x, Assumed t) = γ ++= ("extender", F.symbol x, t)+extender γ _ = return γ+++data Template a = Asserted a | Assumed a | Internal a | Unknown deriving (Functor, F.Foldable, T.Traversable)++deriving instance (Show a) => (Show (Template a))++unTemplate (Asserted t) = t+unTemplate (Assumed t) = t+unTemplate (Internal t) = t +unTemplate _ = panic Nothing "Constraint.Generate.unTemplate called on `Unknown`"++addPostTemplate γ (Asserted t) = Asserted <$> addPost γ t+addPostTemplate γ (Assumed t) = Assumed <$> addPost γ t+addPostTemplate γ (Internal t) = Internal <$> addPost γ t+addPostTemplate _ Unknown = return Unknown++safeFromAsserted _ (Asserted t) = t+safeFromAsserted msg _ = panic Nothing $ "safeFromAsserted:" ++ msg++-- | @varTemplate@ is only called with a `Just e` argument when the `e`+-- corresponds to the body of a @Rec@ binder.+varTemplate :: CGEnv -> (Var, Maybe CoreExpr) -> CG (Template SpecType)+varTemplate γ (x, eo)+ = case (eo, lookupREnv (F.symbol x) (grtys γ), lookupREnv (F.symbol x) (assms γ), lookupREnv (F.symbol x) (intys γ)) of+ (_, Just t, _, _) -> Asserted <$> refreshArgsTop (x, t)+ (_, _, _, Just t) -> Internal <$> refreshArgsTop (x, t)+ (_, _, Just t, _) -> Assumed <$> refreshArgsTop (x, t)+ (Just e, _, _, _) -> do t <- freshTy_expr RecBindE e (exprType e)+ addW (WfC γ t)+ Asserted <$> refreshArgsTop (x, t)+ (_, _, _, _) -> return Unknown++--------------------------------------------------------------------------------+-- | Constraint Generation: Checking -------------------------------------------+--------------------------------------------------------------------------------+cconsE :: CGEnv -> Expr Var -> SpecType -> CG ()+--------------------------------------------------------------------------------+cconsE g e t = do+ -- Note: tracing goes here+ -- traceM $ printf "cconsE:\n expr = %s\n exprType = %s\n lqType = %s\n" (showPpr e) (showPpr (exprType e)) (showpp t)+ cconsE' g e t++cconsE' :: CGEnv -> Expr Var -> SpecType -> CG ()+cconsE' γ e@(Let b@(NonRec x _) ee) t+ = do sp <- specLVars <$> get+ if (x `S.member` sp) || isDefLazyVar x+ then cconsLazyLet γ e t+ else do γ' <- consCBLet γ b+ cconsE γ' ee t+ where+ isDefLazyVar = L.isPrefixOf "fail" . showPpr++cconsE' γ e (RAllP p t)+ = cconsE γ' e t''+ where+ t' = replacePredsWithRefs su <$> t+ su = (uPVar p, pVartoRConc p)+ (css, t'') = splitConstraints t'+ γ' = L.foldl' addConstraints γ css++cconsE' γ (Let b e) t+ = do γ' <- consCBLet γ b+ cconsE γ' e t++cconsE' γ (Case e x _ cases) t+ = do γ' <- consCBLet γ (NonRec x e)+ forM_ cases $ cconsCase γ' x t nonDefAlts+ where+ nonDefAlts = [a | (a, _, _) <- cases, a /= DEFAULT]++cconsE' γ (Lam α e) (RAllT _ t) | isKindVar α+ = cconsE γ e t++cconsE' γ (Lam α e) (RAllT α' t) | isTyVar α+ = cconsE γ e $ subsTyVar_meet' (α', rVar α) t++cconsE' γ (Lam x e) (RFun y ty t _)+ | not (isTyVar x)+ = do γ' <- (γ, "cconsE") += (F.symbol x, ty)+ cconsE γ' e (t `F.subst1` (y, F.EVar $ F.symbol x))+ addIdA x (AnnDef ty)++cconsE' γ (Tick tt e) t+ = cconsE (γ `setLocation` (Sp.Tick tt)) e t++cconsE' γ (Cast e co) t+ -- See Note [Type classes with a single method]+ | Just f <- isClassConCo co+ = cconsE γ (f e) t++cconsE' γ e@(Cast e' _) t+ = do t' <- castTy γ (exprType e) e'+ addC (SubC γ t' t) ("cconsE Cast: " ++ showPpr e)++cconsE' γ e t+ = do te <- consE γ e+ te' <- instantiatePreds γ e te >>= addPost γ+ addC (SubC γ te' t) ("cconsE: " ++ showPpr e)+++splitConstraints (RRTy cs _ OCons t)+ = let (css, t') = splitConstraints t in (cs:css, t')+splitConstraints (RFun x tx@(RApp c _ _ _) t r) | isClass c+ = let (css, t') = splitConstraints t in (css, RFun x tx t' r)+splitConstraints t+ = ([], t)++-------------------------------------------------------------------+-- | @instantiatePreds@ peels away the universally quantified @PVars@+-- of a @RType@, generates fresh @Ref@ for them and substitutes them+-- in the body.+-------------------------------------------------------------------+instantiatePreds γ e (RAllP π t)+ = do r <- freshPredRef γ e π+ instantiatePreds γ e $ replacePreds "consE" t [(π, r)]++instantiatePreds _ _ t0+ = return t0++-------------------------------------------------------------------+-- | @instantiateStrata@ generates fresh @Strata@ vars and substitutes+-- them inside the body of the type.+-------------------------------------------------------------------++instantiateStrata ls t = substStrata t ls <$> mapM (\_ -> fresh) ls++substStrata t ls ls' = F.substa f t+ where+ f x = fromMaybe x $ L.lookup x su+ su = zip ls ls'++-------------------------------------------------------------------+cconsLazyLet γ (Let (NonRec x ex) e) t+ = do tx <- trueTy (varType x)+ γ' <- (γ, "Let NonRec") +++= (x', ex, tx)+ cconsE γ' e t+ where+ x' = F.symbol x++cconsLazyLet _ _ _+ = panic Nothing "Constraint.Generate.cconsLazyLet called on invalid inputs"++--------------------------------------------------------------------------------+-- | Type Synthesis ------------------------------------------------------------+--------------------------------------------------------------------------------+consE :: CGEnv -> Expr Var -> CG SpecType+--------------------------------------------------------------------------------++-- NV this is a hack to type polymorphic axiomatized functions+-- no need to check this code with flag, the axioms environment withh +-- be empty if there is no axiomatization++consE γ e'@(App e@(Var x) (Type τ)) | (M.member x $ aenv γ)+ = do RAllT α te <- checkAll ("Non-all TyApp with expr", e) <$> consE γ e+ t <- if isGeneric α te then freshTy_type TypeInstE e τ else trueTy τ+ addW $ WfC γ t+ t' <- refreshVV t+ tt <- instantiatePreds γ e' $ subsTyVar_meet' (α, t') te+ return $ strengthenS tt (singletonReft (M.lookup x $ aenv γ) x)++{-+consE γ (Lam β (e'@(App e@(Var x) (Type τ)))) | (M.member x $ aenv γ) && isTyVar β + = do RAllT α te <- checkAll ("Non-all TyApp with expr", e) <$> consE γ e+ t <- if isGeneric α te then freshTy_type TypeInstE e τ else trueTy τ+ addW $ WfC γ t+ t' <- refreshVV t+ tt <- instantiatePreds γ e' $ subsTyVar_meet' (α, t') te+ return $ RAllT (rTyVar β) + $ strengthenS tt (singletonReft (M.lookup x $ aenv γ) x)+-}+-- NV END HACK ++consE γ (Var x)+ = do t <- varRefType γ x+ addLocA (Just x) (getLocation γ) (varAnn γ x t)+ return t++consE _ (Lit c)+ = refreshVV $ uRType $ literalFRefType c++consE γ (App e (Type τ)) | isKind τ+ = consE γ e+++consE γ e'@(App e (Type τ))+ = do RAllT α te <- checkAll ("Non-all TyApp with expr", e) <$> consE γ e+ t <- if isGeneric α te then freshTy_type TypeInstE e τ else trueTy τ+ addW $ WfC γ t+ t' <- refreshVV t+ instantiatePreds γ e' $ subsTyVar_meet' (α, t') te++-- RJ: The snippet below is *too long*. Please pull stuff from the where-clause+-- out to the top-level.+consE γ e'@(App e a) | isDictionary a+ = if isJust tt+ then return $ fromJust tt+ else do ([], πs, ls, te) <- bkUniv <$> consE γ e+ te0 <- instantiatePreds γ e' $ foldr RAllP te πs+ te' <- instantiateStrata ls te0+ (γ', te''') <- dropExists γ te'+ te'' <- dropConstraints γ te'''+ updateLocA {- πs -} (exprLoc e) te''+ let RFun x tx t _ = checkFun ("Non-fun App with caller ", e') te''+ pushConsBind $ cconsE γ' a tx+ addPost γ' $ maybe (checkUnbound γ' e' x t a) (F.subst1 t . (x,)) (argExpr γ a)+ where+ grepfunname (App x (Type _)) = grepfunname x+ grepfunname (Var x) = x+ grepfunname e = panic Nothing $ "grepfunname on \t" ++ showPpr e+ mdict w = case w of+ Var x -> case dlookup (denv γ) x of {Just _ -> Just x; Nothing -> Nothing}+ Tick _ e -> mdict e+ _ -> Nothing+ isDictionary _ = isJust (mdict a)+ d = fromJust (mdict a)+ dinfo = dlookup (denv γ) d+ tt = dhasinfo dinfo $ grepfunname e++consE γ e'@(App e a)+ = do ([], πs, ls, te) <- bkUniv <$> consE γ e+ te0 <- instantiatePreds γ e' $ foldr RAllP te πs+ te' <- instantiateStrata ls te0+ (γ', te''') <- dropExists γ te'+ te'' <- dropConstraints γ te'''+ updateLocA {- πs -} (exprLoc e) te''+ let RFun x tx t _ = checkFun ("Non-fun App with caller ", e') te''+ pushConsBind $ cconsE γ' a tx+ addPost γ' $ maybe (checkUnbound γ' e' x t a) (F.subst1 t . (x,)) (argExpr γ a)+ {- + tt <- addPost γ' $ maybe (checkUnbound γ' e' x t a) (F.subst1 t . (x,)) (argExpr γ a)+ let rr = case (argExpr γ e, argExpr γ a) of + (Just e', Just a') -> uTop $ F.Reft (F.vv_, F.PAtom F.Eq (F.EVar F.vv_) (F.EApp e' a'))+ _ -> mempty+ return $ tt `strengthen` rr + -}+++consE γ (Lam α e) | isTyVar α+ = liftM (RAllT (rTyVar α)) (consE γ e)++consE γ e@(Lam x e1)+ = do tx <- freshTy_type LamE (Var x) τx+ γ' <- ((γ, "consE") += (F.symbol x, tx))+ t1 <- consE γ' e1+ addIdA x $ AnnDef tx+ addW $ WfC γ tx+ return $ rFun (F.symbol x) tx t1+ where+ FunTy τx _ = exprType e++consE γ e@(Let _ _)+ = cconsFreshE LetE γ e++consE γ e@(Case _ _ _ _)+ = cconsFreshE CaseE γ e++consE γ (Tick tt e)+ = do t <- consE (setLocation γ (Sp.Tick tt)) e+ addLocA Nothing (tickSrcSpan tt) (AnnUse t)+ return t++consE γ (Cast e co)+ -- See Note [Type classes with a single method]+ | Just f <- isClassConCo co+ = consE γ (f e)++consE γ e@(Cast e' _)+ = castTy γ (exprType e) e'++consE _ e@(Coercion _)+ = trueTy $ exprType e++consE _ e@(Type t)+ = panic Nothing $ "consE cannot handle type " ++ showPpr (e, t)++castTy _ τ (Var x)+ = do t <- trueTy τ+ return $ t `strengthen` (uTop $ F.uexprReft $ F.expr x)++castTy g t (Tick _ e)+ = castTy g t e++castTy _ _ e+ = panic Nothing $ "castTy cannot handle expr " ++ showPpr e++isClassConCo :: Coercion -> Maybe (Expr Var -> Expr Var)+-- See Note [Type classes with a single method]+isClassConCo co+ --- | trace ("isClassConCo: " ++ showPpr (coercionKind co)) False+ --- = undefined++ | Pair t1 t2 <- coercionKind co+ , isClassPred t2+ , (tc,ts) <- splitTyConApp t2+ , [dc] <- tyConDataCons tc+ , [tm] <- dataConOrigArgTys dc+ -- tcMatchTy because we have to instantiate the class tyvars+ , Just _ <- tcMatchTy (mkVarSet $ tyConTyVars tc) tm t1+ = Just (\e -> mkCoreConApps dc $ map Type ts ++ [e])++ | otherwise+ = Nothing++----------------------------------------------------------------------+-- Note [Type classes with a single method]+----------------------------------------------------------------------+-- GHC 7.10 encodes type classes with a single method as newtypes and+-- `cast`s between the method and class type instead of applying the+-- class constructor. Just rewrite the core to what we're used to+-- seeing..+--+-- specifically, we want to rewrite+--+-- e `cast` ((a -> b) ~ C)+--+-- to+--+-- D:C e+--+-- but only when+--+-- D:C :: (a -> b) -> C++-- | @consElimE@ is used to *synthesize* types by **existential elimination**+-- instead of *checking* via a fresh template. That is, assuming+-- γ |- e1 ~> t1+-- we have+-- γ |- let x = e1 in e2 ~> Ex x t1 t2+-- where+-- γ, x:t1 |- e2 ~> t2+-- instead of the earlier case where we generate a fresh template `t` and check+-- γ, x:t1 |- e <~ t++-- consElimE γ xs e+-- = do t <- consE γ e+-- xts <- forM xs $ \x -> (x,) <$> (γ ??= x)+-- return $ rEx xts t++-- | @consFreshE@ is used to *synthesize* types with a **fresh template** when+-- the above existential elimination is not easy (e.g. at joins, recursive binders)++cconsFreshE kvkind γ e+ = do t <- freshTy_type kvkind e $ exprType e+ addW $ WfC γ t+ cconsE γ e t+ return t++checkUnbound γ e x t a+ | x `notElem` (F.syms t) = t+ | otherwise = panic (Just $ getLocation γ) msg+ where+ msg = unlines [ "checkUnbound: " ++ show x ++ " is elem of syms of " ++ show t+ , "In", showPpr e, "Arg = " , show a ]+++dropExists γ (REx x tx t) = liftM (, t) $ (γ, "dropExists") += (x, tx)+dropExists γ t = return (γ, t)++dropConstraints :: CGEnv -> SpecType -> CG SpecType+dropConstraints γ (RFun x tx@(RApp c _ _ _) t r) | isClass c+ = (flip (RFun x tx)) r <$> dropConstraints γ t+dropConstraints γ (RRTy cts _ OCons t)+ = do γ' <- foldM (\γ (x, t) -> γ `addSEnv` ("splitS", x,t)) γ xts+ addC (SubC γ' t1 t2) "dropConstraints"+ dropConstraints γ t+ where+ (xts, t1, t2) = envToSub cts++dropConstraints _ t = return t++-------------------------------------------------------------------------------------+cconsCase :: CGEnv -> Var -> SpecType -> [AltCon] -> (AltCon, [Var], CoreExpr) -> CG ()+-------------------------------------------------------------------------------------+cconsCase γ x t acs (ac, ys, ce)+ = do cγ <- caseEnv γ x acs ac ys+ cconsE cγ ce t++--------------------------------------------------------------------------------+refreshTy :: SpecType -> CG SpecType+--------------------------------------------------------------------------------+refreshTy t = refreshVV t >>= refreshArgs++refreshVV (RAllT a t) = liftM (RAllT a) (refreshVV t)+refreshVV (RAllP p t) = liftM (RAllP p) (refreshVV t)++refreshVV (REx x t1 t2)+ = do [t1', t2'] <- mapM refreshVV [t1, t2]+ liftM (shiftVV (REx x t1' t2')) fresh++refreshVV (RFun x t1 t2 r)+ = do [t1', t2'] <- mapM refreshVV [t1, t2]+ liftM (shiftVV (RFun x t1' t2' r)) fresh++refreshVV (RAppTy t1 t2 r)+ = do [t1', t2'] <- mapM refreshVV [t1, t2]+ liftM (shiftVV (RAppTy t1' t2' r)) fresh++refreshVV (RApp c ts rs r)+ = do ts' <- mapM refreshVV ts+ rs' <- mapM refreshVVRef rs+ liftM (shiftVV (RApp c ts' rs' r)) fresh++refreshVV t+ = return t++refreshVVRef (RProp ss (RHole r))+ = return $ RProp ss (RHole r)++refreshVVRef (RProp ss t)+ = do xs <- mapM (\_ -> fresh) (fst <$> ss)+ let su = F.mkSubst $ zip (fst <$> ss) (F.EVar <$> xs)+ liftM (RProp (zip xs (snd <$> ss)) . F.subst su) (refreshVV t)+++++-------------------------------------------------------------------------------------+caseEnv :: CGEnv -> Var -> [AltCon] -> AltCon -> [Var] -> CG CGEnv+-------------------------------------------------------------------------------------+caseEnv γ x _ (DataAlt c) ys+ = do let (x' : ys') = F.symbol <$> (x:ys)+ xt0 <- checkTyCon ("checkTycon cconsCase", x) <$> γ ??= x+ let xt = shiftVV xt0 x'+ tdc <- γ ??= ({- F.symbol -} dataConWorkId c) >>= refreshVV+ let (rtd, yts, _) = unfoldR tdc xt ys+ let r1 = dataConReft c ys'+ let r2 = dataConMsReft rtd ys'+ let xt = (xt0 `F.meet` rtd) `strengthen` (uTop (r1 `F.meet` r2))+ let cbs = safeZip "cconsCase" (x':ys') (xt0:yts)+ cγ' <- addBinders γ x' cbs+ cγ <- addBinders cγ' x' [(x', xt)]+ return cγ++caseEnv γ x acs a _+ = do let x' = F.symbol x+ xt' <- (`strengthen` uTop (altReft γ acs a)) <$> (γ ??= x)+ cγ <- addBinders γ x' [(x', xt')]+ return cγ++altReft _ _ (LitAlt l) = literalFReft l+altReft γ acs DEFAULT = mconcat [notLiteralReft l | LitAlt l <- acs]+ where notLiteralReft = maybe mempty F.notExprReft . snd . literalConst (emb γ)+altReft _ _ _ = panic Nothing "Constraint : altReft"++unfoldR td (RApp _ ts rs _) ys = (t3, tvys ++ yts, ignoreOblig rt)+ where+ tbody = instantiatePvs (instantiateTys td ts) $ reverse rs+ (ys0, yts', _, rt) = safeBkArrow $ instantiateTys tbody tvs'+ yts'' = zipWith F.subst sus (yts'++[rt])+ (t3,yts) = (last yts'', init yts'')+ sus = F.mkSubst <$> (L.inits [(x, F.EVar y) | (x, y) <- zip ys0 ys'])+ (αs, ys') = mapSnd (F.symbol <$>) $ L.partition isTyVar ys+ tvs' = rVar <$> αs+ tvys = ofType . varType <$> αs++unfoldR _ _ _ = panic Nothing "Constraint.hs : unfoldR"++instantiateTys = L.foldl' go+ where go (RAllT α tbody) t = subsTyVar_meet' (α, t) tbody+ go _ _ = panic Nothing "Constraint.instanctiateTy"++instantiatePvs = L.foldl' go+ where go (RAllP p tbody) r = replacePreds "instantiatePv" tbody [(p, r)]+ go _ _ = panic Nothing "Constraint.instanctiatePv"++checkTyCon _ t@(RApp _ _ _ _) = t+checkTyCon x t = checkErr x t++checkFun _ t@(RFun _ _ _ _) = t+checkFun x t = checkErr x t++checkAll _ t@(RAllT _ _) = t+checkAll x t = checkErr x t++checkErr (msg, e) t = panic Nothing $ msg ++ showPpr e ++ ", type: " ++ showpp t++varAnn γ x t+ | x `S.member` recs γ = AnnLoc (getSrcSpan x)+ | otherwise = AnnUse t++-----------------------------------------------------------------------+-- | Helpers: Creating Fresh Refinement -------------------------------+-----------------------------------------------------------------------++freshPredRef :: CGEnv -> CoreExpr -> PVar RSort -> CG SpecProp+freshPredRef γ e (PV _ (PVProp τ) _ as)+ = do t <- freshTy_type PredInstE e (toType τ)+ args <- mapM (\_ -> fresh) as+ let targs = [(x, s) | (x, (s, y, z)) <- zip args as, (F.EVar y) == z ]+ γ' <- foldM (++=) γ [("freshPredRef", x, ofRSort τ) | (x, τ) <- targs]+ addW $ WfC γ' t+ return $ RProp targs t++freshPredRef _ _ (PV _ PVHProp _ _)+ = todo Nothing "EFFECTS:freshPredRef"++--------------------------------------------------------------------------------+-- | Helpers: Creating Refinement Types For Various Things ---------------------+--------------------------------------------------------------------------------++argExpr :: CGEnv -> CoreExpr -> Maybe F.Expr+argExpr _ (Var vy) = Just $ F.eVar vy+argExpr γ (Lit c) = snd $ literalConst (emb γ) c+argExpr γ (Tick _ e) = argExpr γ e+argExpr _ _ = Nothing+++--------------------------------------------------------------------------------+(??=) :: (?callStack :: CallStack) => CGEnv -> Var -> CG SpecType+--------------------------------------------------------------------------------+γ ??= x = case M.lookup x' (lcb γ) of+ Just e -> consE (γ -= x') e+ Nothing -> refreshTy tx+ where+ x' = F.symbol x+ tx = fromMaybe tt (γ ?= x')+ tt = ofType $ varType x+++--------------------------------------------------------------------------------+varRefType :: (?callStack :: CallStack) => CGEnv -> Var -> CG SpecType+--------------------------------------------------------------------------------+varRefType γ x = do+ xt <- varRefType' γ x <$> (γ ??= x)+ return xt -- F.tracepp (printf "varRefType x = [%s]" (showpp x))++varRefType' :: CGEnv -> Var -> SpecType -> SpecType+varRefType' γ x t'+ | Just tys <- trec γ, Just tr <- M.lookup x' tys+ = tr `strengthenS` xr+ | otherwise+ = t' `strengthenS` xr+ where+ xr = singletonReft (M.lookup x $ aenv γ) x+ x' = F.symbol x++singletonReft (Just x) _ = uTop $ F.symbolReft x+singletonReft Nothing v = uTop $ F.symbolReft $ F.symbol v++-- | RJ: `nomeet` replaces `strengthenS` for `strengthen` in the definition+-- of `varRefType`. Why does `tests/neg/strata.hs` fail EVEN if I just replace+-- the `otherwise` case? The fq file holds no answers, both are sat.+strengthenS :: (PPrint r, F.Reftable r) => RType c tv r -> r -> RType c tv r+strengthenS (RApp c ts rs r) r' = RApp c ts rs $ topMeet r r'+strengthenS (RVar a r) r' = RVar a $ topMeet r r'+strengthenS (RFun b t1 t2 r) r' = RFun b t1 t2 $ topMeet r r'+strengthenS (RAppTy t1 t2 r) r' = RAppTy t1 t2 $ topMeet r r'+strengthenS t _ = t++topMeet :: (PPrint r, F.Reftable r) => r -> r -> r+topMeet r r' = {- F.tracepp msg $ -} F.top r `F.meet` r'+ -- where+ -- msg = printf "topMeet r = [%s] r' = [%s]" (showpp r) (showpp r')++ -- traceM $ printf "cconsE:\n expr = %s\n exprType = %s\n lqType = %s\n" (showPpr e) (showPpr (exprType e)) (showpp t)+--------------------------------------------------------------------------------+-- | Cleaner Signatures For Rec-bindings ---------------------------------------+--------------------------------------------------------------------------------++exprLoc :: CoreExpr -> Maybe SrcSpan++exprLoc (Tick tt _) = Just $ tickSrcSpan tt+exprLoc (App e a) | isType a = exprLoc e+exprLoc _ = Nothing++isType (Type _) = True+isType a = eqType (exprType a) predType+++exprRefType :: CoreExpr -> SpecType+exprRefType = exprRefType_ M.empty++exprRefType_ :: M.HashMap Var SpecType -> CoreExpr -> SpecType+exprRefType_ γ (Let b e)+ = exprRefType_ (bindRefType_ γ b) e++exprRefType_ γ (Lam α e) | isTyVar α+ = RAllT (rTyVar α) (exprRefType_ γ e)++exprRefType_ γ (Lam x e)+ = rFun (F.symbol x) (ofType $ varType x) (exprRefType_ γ e)++exprRefType_ γ (Tick _ e)+ = exprRefType_ γ e++exprRefType_ γ (Var x)+ = M.lookupDefault (ofType $ varType x) x γ++exprRefType_ _ e+ = ofType $ exprType e++bindRefType_ γ (Rec xes)+ = extendγ γ [(x, exprRefType_ γ e) | (x,e) <- xes]++bindRefType_ γ (NonRec x e)+ = extendγ γ [(x, exprRefType_ γ e)]++extendγ γ xts+ = foldr (\(x,t) m -> M.insert x t m) γ xts++isGeneric :: RTyVar -> SpecType -> Bool+isGeneric α t = all (\(c, α') -> (α'/=α) || isOrd c || isEq c ) (classConstrs t)+ where classConstrs t = [(c, α') | (c, ts) <- tyClasses t+ , t' <- ts+ , α' <- freeTyVars t']+ isOrd = (ordClassName ==) . className+ isEq = (eqClassName ==) . className
+ src/Language/Haskell/Liquid/Constraint/Monad.hs view
@@ -0,0 +1,154 @@+-- | This module contains various functions that add/update in the CG monad.++{-# LANGUAGE TupleSections #-}+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE PatternGuards #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE ImplicitParams #-}+{-# LANGUAGE FlexibleContexts #-}++module Language.Haskell.Liquid.Constraint.Monad where+++-- import Text.PrettyPrint.HughesPJ hiding (first)+import Prelude hiding (error)+-- import qualified TyCon as TC+import Var+import Name (getSrcSpan)+import SrcLoc -- (SrcSpan)+import Outputable hiding (showPpr, panic) -- (SrcSpan)++++import qualified Data.HashMap.Strict as M+-- import qualified Data.HashSet as S+import qualified Data.Text as T+-- import qualified Data.List as L++-- import Data.Maybe (fromMaybe) -- catMaybes, fromJust, isJust)+import Control.Monad+import Control.Monad.State (get, modify)+-- import qualified Language.Fixpoint.Types as F+import Language.Haskell.Liquid.Types hiding (loc)+-- import Language.Haskell.Liquid.Types.Variance++-- import Language.Haskell.Liquid.Types.Strata+import Language.Haskell.Liquid.Constraint.Types+import Language.Haskell.Liquid.Constraint.Env+-- import Language.Haskell.Liquid.Constraint.Fresh+-- import Language.Haskell.Liquid.Types.PredType hiding (freeTyVars)+-- import Language.Haskell.Liquid.Types.RefType+import Language.Fixpoint.Misc hiding (errorstar)+-- import Language.Haskell.Liquid.Misc -- (concatMapM)+import Language.Haskell.Liquid.GHC.Misc -- (concatMapM)+import Language.Haskell.Liquid.Types.RefType++++++--------------------------------------------------------------------------------+-- RJ: What is this `isBind` business?+--------------------------------------------------------------------------------+pushConsBind :: CG a -> CG a+--------------------------------------------------------------------------------+pushConsBind act+ = do modify $ \s -> s { isBind = False : isBind s }+ z <- act+ modify $ \s -> s { isBind = tail (isBind s) }+ return z++--------------------------------------------------------------------------------+-- | `addC` adds a subtyping constraint into the global pool.+--------------------------------------------------------------------------------+addC :: SubC -> String -> CG ()+--------------------------------------------------------------------------------+addC c@(SubC γ t1 t2) _msg+ | toType t1 /= toType t2+ = panic Nothing $ "addC: malformed constraint:\n" ++ showpp t1 ++ "\n <: \n" ++ showpp t2+ | otherwise+ = do modify $ \s -> s { hsCs = c : (hsCs s) }+ bflag <- headDefault True . isBind <$> get+ sflag <- scheck <$> get+ if bflag && sflag+ then modify $ \s -> s {sCs = (SubC γ t2 t1) : (sCs s) }+ else return ()+ where+ headDefault a [] = a+ headDefault _ (x:_) = x++addC c _msg+ = modify $ \s -> s { hsCs = c : hsCs s }+++--------------------------------------------------------------------------------+-- | addPost: RJ: what DOES this function do?+--------------------------------------------------------------------------------+addPost :: CGEnv -> SpecType -> CG SpecType+--------------------------------------------------------------------------------+addPost γ (RRTy e r OInv t)+ = do γ' <- foldM (\γ (x, t) -> γ `addSEnv` ("addPost", x,t)) γ e+ addC (SubR γ' OInv r) "precondition" >> return t++addPost γ (RRTy e r OTerm t)+ = do γ' <- foldM (\γ (x, t) -> γ ++= ("addPost", x,t)) γ e+ addC (SubR γ' OTerm r) "precondition" >> return t++addPost _ (RRTy _ _ OCons t)+ = return t++addPost _ t+ = return t++--------------------------------------------------------------------------------+-- | Add Well formedness Constraint+--------------------------------------------------------------------------------+addW :: WfC -> CG ()+--------------------------------------------------------------------------------+addW !w = modify $ \s -> s { hsWfs = w : (hsWfs s) }++--------------------------------------------------------------------------------+-- | Add a warning+--------------------------------------------------------------------------------+addWarning :: Error -> CG ()+--------------------------------------------------------------------------------+addWarning w = modify $ \s -> s { logErrors = w : logErrors s }++-- | Add Identifier Annotations, used for annotation binders (i.e. at binder sites)+addIdA :: Var -> Annot SpecType -> CG ()+addIdA !x !t = modify $ \s -> s { annotMap = upd $ annotMap s }+ where+ l = getSrcSpan x+ upd m@(AI _) = if boundRecVar l m then m else addA l (Just x) t m++boundRecVar :: SrcSpan -> AnnInfo (Annot a) -> Bool+boundRecVar l (AI m) = not $ null [t | (_, AnnRDf t) <- M.lookupDefault [] l m]+++-- | Used for annotating reads (i.e. at Var x sites)++addLocA :: Maybe Var -> SrcSpan -> Annot SpecType -> CG ()+addLocA !xo !l !t+ = modify $ \s -> s { annotMap = addA l xo t $ annotMap s }+++--------------------------------------------------------------------------------+-- | Update annotations for a location, due to (ghost) predicate applications+--------------------------------------------------------------------------------+updateLocA :: Maybe SrcSpan -> SpecType -> CG ()+--------------------------------------------------------------------------------+updateLocA (Just l) t = addLocA Nothing l (AnnUse t)+updateLocA _ _ = return ()+--------------------------------------------------------------------------------++--------------------------------------------------------------------------------+addA :: (Outputable a) => SrcSpan -> Maybe a -> b -> AnnInfo b -> AnnInfo b+--------------------------------------------------------------------------------+addA !l xo@(Just _) !t (AI m)+ | isGoodSrcSpan l+ = AI $ inserts l (T.pack . showPpr <$> xo, t) m+addA !l xo@Nothing !t (AI m)+ | l `M.member` m -- only spans known to be variables+ = AI $ inserts l (T.pack . showPpr <$> xo, t) m+addA _ _ _ !a+ = a
+ src/Language/Haskell/Liquid/Constraint/ProofToCore.hs view
@@ -0,0 +1,185 @@+{-# LANGUAGE TypeSynonymInstances #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE FlexibleContexts #-}++module Language.Haskell.Liquid.Constraint.ProofToCore where++import Prelude hiding (error)+import CoreSyn hiding (Expr, Var)+import qualified CoreSyn as H+import Language.Haskell.Liquid.Types.Errors++import Var hiding (Var)++import CoreUtils++import Type hiding (Var)+import TypeRep++import Language.Haskell.Liquid.GHC.Misc+import Language.Haskell.Liquid.WiredIn++++import Language.Haskell.Liquid.Prover.Types+import Language.Haskell.Liquid.Transforms.CoreToLogic ()+import qualified Data.List as L+import Data.Maybe (fromMaybe)++type HId = Id+type HVar = Var HId+type HAxiom = Axiom HId+type HCtor = Ctor HId+type HVarCtor = VarCtor HId+type HQuery = Query HId+type HInstance = Instance HId+type HProof = Proof HId+type HExpr = Expr HId++type CmbExpr = CoreExpr -> CoreExpr -> CoreExpr++class ToCore a where+ toCore :: CmbExpr -> CoreExpr -> a -> CoreExpr++instance ToCore HInstance where+ toCore c e i = makeApp (toCore c e $ inst_axiom i) (toCore c e <$> inst_args i)++instance ToCore HProof where+ toCore _ e Invalid = e+ toCore c e p = combineProofs c e $ (toCore c e <$> p_evidence p)++instance ToCore HAxiom where+ toCore c e a = toCore c e $ axiom_name a++instance ToCore HExpr where+ toCore c e (EVar v) = toCore c e v+ toCore c' e (EApp c es) = makeApp (toCore c' e c) (toCore c' e <$> es)++instance ToCore HCtor where+ toCore c' e c = toCore c' e $ ctor_expr c++instance ToCore HVar where+ toCore _ _ v = H.Var $ var_info v+++-------------------------------------------------------------------------------+---------------- Combining Proofs --------------------------------------------+-------------------------------------------------------------------------------++-- | combineProofs :: combinator -> default expressions -> list of proofs+-- | -> combined result++combineProofs :: CmbExpr -> CoreExpr -> [CoreExpr] -> CoreExpr+combineProofs _ e [] = e+combineProofs c _ es = foldl (flip Let) (combine [1..] c (H.Var v) (H.Var <$> vs)) (bs ++ [dictionaryBind])+ where+ (v:vs, bs) = unzip [let v = (varANF i (exprType e)) in (v, NonRec v e)+ | (e, i) <- zip es [1..] ]++combine _ _ e [] = e+combine _ c e' [e] = c e' e+combine (i:uniq) c e' (e:es) = Let (NonRec v (c e' e)) (combine uniq c (H.Var v) es)+ where+ v = varCombine i (exprType $ c e' e)+combine _ _ _ _ = impossible Nothing err -- TODO: Does this case have a+ where -- sane implementation?+ err = "Language.Haskell.Liquid.Constraint.ProofToCore.combine called with"+ ++ " empty first argument and non-empty fourth argument. This should"+ ++ " never happen!"+++-------------------------------------------------------------------------------+---------------- make Application --------------------------------------------+-------------------------------------------------------------------------------++++-- | To make application we need to instantiate expressions irrelevant to logic+-- | type application and dictionaries.+-- | Then, ANF the final expression++makeApp :: CoreExpr -> [CoreExpr] -> CoreExpr+makeApp f es = foldl (flip Let) (foldl App f' (reverse es')) (reverse bs)+ where+ vts = resolveVs as $ zip (dropWhile isClassPred ts) (exprType <$> es)+ (as, ts) = bkArrow (exprType f)+ f' = instantiateVars vts f+ ds = makeDictionaries dictionaryVar f'+ (bs, es', _) = foldl anf ([], [], [1..]) (ds ++ (instantiateVars vts <$> es))+++instance Show Type where+ show (TyVarTy v) = show $ tvId v+ show t = showPpr t++-- | ANF+anf :: ([CoreBind], [CoreExpr], [Int]) -> CoreExpr -> ([CoreBind], [CoreExpr], [Int])+anf (bs, es, i:uniq) (App f e) = ((NonRec v (App f e')):(bs++bs'), H.Var v:es, uniq')+ where v = varANFPr i (exprType $ App f e)+ (bs', [e'], uniq') = anf ([], [], uniq) e++anf (bs, es, uniq) e = (bs, e:es, uniq)++-- | Filling up dictionaries+makeDictionaries dname e = go (exprType e)+ where+ go (ForAllTy _ t) = go t+ go (FunTy tx t ) | isClassPred tx = (makeDictionary dname tx):go t+ go _ = []++makeDictionary dname t = App (H.Var dname) (Type t)++-- | Filling up types+instantiateVars vts e = go e (exprType e)+ where+ go e (ForAllTy a t) = go (App e (Type $ fromMaybe (TyVarTy a) $ L.lookup a vts)) t+ go e _ = e++resolveVs :: [Id] -> [(Type, Type)] -> [(Id, Type)]+resolveVs as ts = go as ts+ where+ go _ [] = []+ go fvs ((ForAllTy v t1, t2):ts) = go (v:fvs) ((t1, t2):ts)+ go fvs ((t1, ForAllTy v t2):ts) = go (v:fvs) ((t1, t2):ts)+ go fvs ((FunTy t1 t2, FunTy t1' t2'):ts) = go fvs ((t1, t1'):(t2, t2'):ts)+ go fvs ((AppTy t1 t2, AppTy t1' t2'):ts) = go fvs ((t1, t1'):(t2, t2'):ts)+ go fvs ((TyVarTy a, TyVarTy a'):ts) | a == a' = go fvs ts+ go fvs ((TyVarTy a, t):ts) | a `elem` fvs = let vts = (go fvs (substTyV (a, t) <$> ts)) in (a, resolveVar a t vts) : vts+ go fvs ((t, TyVarTy a):ts) | a `elem` fvs = let vts = (go fvs (substTyV (a, t) <$> ts)) in (a, resolveVar a t vts) : vts+ go fvs ((TyConApp _ cts,TyConApp _ cts'):ts) = go fvs (zip cts cts' ++ ts)+ go fvs ((LitTy _, LitTy _):ts) = go fvs ts+ go _ (tt:_) = panic Nothing $ ("cannot resolve " ++ show tt ++ (" for ") ++ show ts)++resolveVar _ t [] = t+resolveVar a t ((a', t'):ats)+ | a == a' = resolveVar a' t' ats+ | TyVarTy a'' <- t' = resolveVar a'' t' ats+ | otherwise = resolveVar a t ats+++substTyV :: (Id, Type) -> (Type, Type) -> (Type, Type)+substTyV (a, at) (t1, t2) = (go t1, go t2)+ where+ go (ForAllTy a' t) | a == a' = ForAllTy a' t+ | otherwise = ForAllTy a' (go t)+ go (FunTy t1 t2) = FunTy (go t1) (go t2)+ go (AppTy t1 t2) = AppTy (go t1) (go t2)+ go (TyConApp c ts) = TyConApp c (go <$> ts)+ go (LitTy l) = LitTy l+ go (TyVarTy v) | v == a = at+ | otherwise = TyVarTy v+++-------------------------------------------------------------------------------+------------------------- HELPERS --------------------------------------------+-------------------------------------------------------------------------------++varCombine i = stringVar ("proof_anf_cmb" ++ show i)+varANF i = stringVar ("proof_anf_bind" ++ show i)+varANFPr i = stringVar ("proof_anf_bind_pr" ++ show i)++bkArrow = go [] []+ where+ go vs ts (ForAllTy v t) = go (v:vs) ts t+ go vs ts (FunTy tx t) = go vs (tx:ts) t+ go vs ts _ = (reverse vs, reverse ts)
+ src/Language/Haskell/Liquid/Constraint/Qualifier.hs view
@@ -0,0 +1,159 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE ViewPatterns #-}+{-# LANGUAGE PartialTypeSignatures #-}++module Language.Haskell.Liquid.Constraint.Qualifier (+ specificationQualifiers+ ) where++import TyCon++import Prelude hiding (error)++import Language.Haskell.Liquid.Bare+import Language.Haskell.Liquid.Types.RefType+import Language.Haskell.Liquid.GHC.Misc (getSourcePos)+import Language.Haskell.Liquid.Types.PredType+import Language.Haskell.Liquid.Types+import Language.Fixpoint.Types++++-- import Control.Applicative ((<$>))+import Data.List (delete, nub)+import Data.Maybe (catMaybes, fromMaybe)+import qualified Data.HashSet as S+-- import Data.Bifunctor (second)+import Debug.Trace++-----------------------------------------------------------------------------------+specificationQualifiers :: Int -> GhcInfo -> SEnv Sort -> [Qualifier]+-----------------------------------------------------------------------------------+specificationQualifiers k info lEnv+ = [ q | (x, t) <- (tySigs $ spec info) ++ (asmSigs $ spec info) ++ (inSigs $ spec info) ++ (ctors $ spec info)+ , x `S.member` (S.fromList $ defVars info +++ -- NOTE: this mines extra, useful qualifiers but causes+ -- a significant increase in running time, so we hide it+ -- behind `--scrape-imports` and `--scrape-used-imports`+ if info `hasOpt` scrapeUsedImports+ then useVars info+ else if info `hasOpt` scrapeImports+ then impVars info+ else [])+ , q <- refTypeQuals lEnv (getSourcePos x) (tcEmbeds $ spec info) (val t)+ -- NOTE: large qualifiers are VERY expensive, so we only mine+ -- qualifiers up to a given size, controlled with --max-params+ , length (q_params q) <= k + 1+ ]+ -- where lEnv = trace ("Literals: " ++ show lEnv') lEnv'++-- GRAVEYARD: scraping quals from imports kills the system with too much crap+-- specificationQualifiers info = {- filter okQual -} qs+-- where+-- qs = concatMap refTypeQualifiers ts+-- refTypeQualifiers = refTypeQuals $ tcEmbeds spc+-- ts = val <$> t1s ++ t2s+-- t1s = [t | (x, t) <- tySigs spc, x `S.member` definedVars]+-- t2s = [] -- [t | (_, t) <- ctor spc ]+-- definedVars = S.fromList $ defVars info+-- spc = spec info+--+-- okQual = not . any isPred . map snd . q_params+-- where+-- isPred (FApp tc _) = tc == stringFTycon "Pred"+-- isPred _ = False+++-- TODO: rewrite using foldReft'+-- refTypeQuals :: SpecType -> [Qualifier]+refTypeQuals :: SEnv Sort -> SourcePos -> TCEmb TyCon -> SpecType -> [Qualifier]+refTypeQuals lEnv l tce t0 = go emptySEnv t0+ where+ scrape = refTopQuals lEnv l tce t0+ add x t γ = insertSEnv x (rTypeSort tce t) γ+ goBind x t γ t' = go (add x t γ) t'+ go γ t@(RVar _ _) = scrape γ t+ go γ (RAllT _ t) = go γ t+ go γ (RAllP p t) = go (insertSEnv (pname p) (rTypeSort tce $ (pvarRType p :: RSort)) γ) t+ go γ t@(RAppTy t1 t2 _) = go γ t1 ++ go γ t2 ++ scrape γ t+ go γ (RFun x t t' _) = go γ t ++ goBind x t γ t'+ go γ t@(RApp c ts rs _) = scrape γ t ++ concatMap (go γ') ts ++ goRefs c γ' rs+ where γ' = add (rTypeValueVar t) t γ+ go γ (RAllE x t t') = go γ t ++ goBind x t γ t'+ go γ (REx x t t') = go γ t ++ goBind x t γ t'+ go _ _ = []+ goRefs c g rs = concat $ zipWith (goRef g) rs (rTyConPVs c)+ goRef _ (RProp _ (RHole _)) _ = []+ goRef g (RProp s t) _ = go (insertsSEnv g s) t+ insertsSEnv = foldr (\(x, t) γ -> insertSEnv x (rTypeSort tce t) γ)++refTopQuals lEnv l tce t0 γ t+ = [ mkQ v so pa | let (RR so (Reft (v, ra))) = rTypeSortedReft tce t+ , pa <- conjuncts ra+ , not $ isHole pa+ ]+ +++ [ mkP s e | let (MkUReft _ (Pr ps) _) = fromMaybe (msg t) $ stripRTypeBase t+ , p <- findPVar (ty_preds $ toRTypeRep t0) <$> ps+ , (s, _, e) <- pargs p+ ]+ where+ mkQ = mkQual lEnv l t0 γ+ mkP = mkPQual lEnv l tce t0 γ+ msg t = panic Nothing $ "Qualifier.refTopQuals: no typebase" ++ showpp t++mkPQual lEnv l tce t0 γ t e = mkQual lEnv l t0 γ' v so pa+ where+ v = "vv"+ so = rTypeSort tce t+ γ' = insertSEnv v so γ+ pa = PAtom Eq (EVar v) e++mkQual = mkQualNEW++mkQualNEW lEnv l _ γ v so p = Q "Auto" ((v, so) : xts) p l+ where+ xs = delete v $ nub $ syms p+ xts = catMaybes $ zipWith (envSort l lEnv γ) xs [0..]+ -- xts = Language.Fixpoint.Misc.traceShow msg $ xts'+ -- msg = "Free Vars in: " ++ showFix p ++ " in " ++ show t0++-- OLD+{-+ TODO: If it's so OLD, do we need to keep it? Never called, etc...+mkQualOLD lEnv l t0 γ v so p = Q "Auto" ((v, so) : yts) p' l+ where+ yts = [(y, lookupSort l γ i x) | (x, i, y) <- xys ]+ p' = subst su p+ su = mkSubst [(x, EVar y) | (x, _, y) <- xys]+ xys = zipWith (\x i -> (x, i, symbol ("~A" ++ show i))) xs [0..]+ -- xs = delete v $ orderedFreeVars γ p+ xs = {- Language.Fixpoint.Misc.traceShow msg $ -} delete v $ orderedFreeVarsOLD γ p+ msg = "Free Vars in: " ++ showFix p ++ " in " ++ show t0++orderedFreeVarsOLD :: SEnv Sort -> Pred -> [Symbol]+orderedFreeVarsOLD γ = nub . filter (`memberSEnv` γ) . syms+-}++{-+ TODO: Never used, do I need to exist?+orderedFreeVars :: SEnv Sort -> Pred -> [Symbol]+orderedFreeVars lEnv = nub . filter (not . (`memberSEnv` lEnv)) . syms+-}++envSort :: SourcePos -> SEnv Sort -> SEnv Sort -> Symbol -> Integer -> Maybe (Symbol, Sort)+envSort l lEnv tEnv x i+ | Just t <- lookupSEnv x tEnv = Just (x, t)+ | Just _ <- lookupSEnv x lEnv = Nothing+ | otherwise = Just (x, ai)+ where+ ai = trace msg $ fObj $ Loc l l $ tempSymbol "LHTV" i+ msg = "unknown symbol in qualifier: " ++ show x++{-+ TODO: Never used, do I need to exist?+lookupSort l γ i x = fromMaybe ai $ lookupSEnv x γ+ where+ ai = trace msg $ fObj $ Loc l l $ tempSymbol "LHTV" i+ msg = "unknown symbol in qualifier: " ++ show x+-}
+ src/Language/Haskell/Liquid/Constraint/Split.hs view
@@ -0,0 +1,496 @@+{-# LANGUAGE ImplicitParams #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE PartialTypeSignatures #-}++--------------------------------------------------------------------------------+-- | Constraint Splitting ------------------------------------------------------+--------------------------------------------------------------------------------++module Language.Haskell.Liquid.Constraint.Split (++ -- * Split Subtyping Constraints+ splitC++ -- * Split Well-formedness Constraints+ , splitW++ -- * Split Strata Constraints+ , splitS++ -- * ???+ , envToSub++ -- * Panic+ , panicUnbound+ ) where++import Prelude hiding (error)++++import Text.PrettyPrint.HughesPJ hiding (first)+import qualified TyCon as TC++import Data.Maybe (fromMaybe) -- catMaybes, fromJust, isJust)+import Control.Monad+import Control.Monad.State (get)+import qualified Control.Exception as Ex++import qualified Language.Fixpoint.Types as F+import Language.Fixpoint.Misc hiding (errorstar)+import Language.Fixpoint.SortCheck (pruneUnsortedReft)++import Language.Haskell.Liquid.Misc -- (concatMapM)+import qualified Language.Haskell.Liquid.UX.CTags as Tg+import Language.Haskell.Liquid.UX.Errors () -- CTags as Tg+import Language.Haskell.Liquid.Types hiding (loc)++import Language.Haskell.Liquid.Types.Variance+import Language.Haskell.Liquid.Types.Strata+import Language.Haskell.Liquid.Types.PredType hiding (freeTyVars)+import Language.Haskell.Liquid.Types.RefType++import Language.Haskell.Liquid.Constraint.Types+import Language.Haskell.Liquid.Constraint.Env+import Language.Haskell.Liquid.Constraint.Fresh+import Language.Haskell.Liquid.Constraint.Monad+import Language.Haskell.Liquid.Constraint.Constraint++--------------------------------------------------------------------------------+splitW :: WfC -> CG [FixWfC]+--------------------------------------------------------------------------------+splitW (WfC γ t@(RFun x t1 t2 _))+ = do ws <- bsplitW γ t+ ws' <- splitW (WfC γ t1)+ γ' <- (γ, "splitW") += (x, t1)+ ws'' <- splitW (WfC γ' t2)+ return $ ws ++ ws' ++ ws''++splitW (WfC γ t@(RAppTy t1 t2 _))+ = do ws <- bsplitW γ t+ ws' <- splitW (WfC γ t1)+ ws'' <- splitW (WfC γ t2)+ return $ ws ++ ws' ++ ws''++splitW (WfC γ (RAllT _ r))+ = splitW (WfC γ r)++splitW (WfC γ (RAllP _ r))+ = splitW (WfC γ r)++splitW (WfC γ t@(RVar _ _))+ = bsplitW γ t++splitW (WfC γ t@(RApp _ ts rs _))+ = do ws <- bsplitW γ t+ γ' <- γ `extendEnvWithVV` t+ ws' <- concat <$> mapM (splitW . WfC γ') ts+ ws'' <- concat <$> mapM (rsplitW γ) rs+ return $ ws ++ ws' ++ ws''++splitW (WfC γ (RAllE x tx t))+ = do ws <- splitW (WfC γ tx)+ γ' <- (γ, "splitW") += (x, tx)+ ws' <- splitW (WfC γ' t)+ return $ ws ++ ws'++splitW (WfC γ (REx x tx t))+ = do ws <- splitW (WfC γ tx)+ γ' <- (γ, "splitW") += (x, tx)+ ws' <- splitW (WfC γ' t)+ return $ ws ++ ws'++splitW (WfC _ t)+ = panic Nothing $ "splitW cannot handle: " ++ showpp t++rsplitW _ (RProp _ (RHole _))+ = panic Nothing "Constrains: rsplitW for RProp _ (RHole _)"+rsplitW γ (RProp ss t0)+ = do γ' <- foldM (++=) γ [("rsplitW", x, ofRSort s) | (x, s) <- ss]+ splitW $ WfC γ' t0++bsplitW :: CGEnv -> SpecType -> CG [FixWfC]+bsplitW γ t =+ do pflag <- pruneRefs <$> get+ isHO <- allowHO <$> get+ return $ bsplitW' γ t pflag isHO++bsplitW' γ t pflag isHO+ | isHO || F.isNonTrivial r'+ = F.wfC (feBinds $ fenv γ) r' ci+ | otherwise+ = []+ where+ r' = rTypeSortedReft' pflag γ t+ ci = Ci (getLocation γ) Nothing++--------------------------------------------------------------------------------+splitS :: SubC -> CG [([Stratum], [Stratum])]+bsplitS :: SpecType -> SpecType -> CG [([Stratum], [Stratum])]+--------------------------------------------------------------------------------+splitS (SubC γ (REx x _ t1) (REx x2 _ t2)) | x == x2+ = splitS (SubC γ t1 t2)++splitS (SubC γ t1 (REx _ _ t2))+ = splitS (SubC γ t1 t2)++splitS (SubC γ (REx _ _ t1) t2)+ = splitS (SubC γ t1 t2)++splitS (SubC γ (RAllE x _ t1) (RAllE x2 _ t2)) | x == x2+ = splitS (SubC γ t1 t2)++splitS (SubC γ (RAllE _ _ t1) t2)+ = splitS (SubC γ t1 t2)++splitS (SubC γ t1 (RAllE _ _ t2))+ = splitS (SubC γ t1 t2)++splitS (SubC γ (RRTy _ _ _ t1) t2)+ = splitS (SubC γ t1 t2)++splitS (SubC γ t1 (RRTy _ _ _ t2))+ = splitS (SubC γ t1 t2)++splitS (SubC γ t1@(RFun x1 r1 r1' _) t2@(RFun x2 r2 r2' _))+ = do cs <- bsplitS t1 t2+ cs' <- splitS (SubC γ r2 r1)+ γ' <- (γ, "splitS") += (x2, r2)+ let r1x2' = r1' `F.subst1` (x1, F.EVar x2)+ cs'' <- splitS (SubC γ' r1x2' r2')+ return $ cs ++ cs' ++ cs''++splitS (SubC γ t1@(RAppTy r1 r1' _) t2@(RAppTy r2 r2' _))+ = do cs <- bsplitS t1 t2+ cs' <- splitS (SubC γ r1 r2)+ cs'' <- splitS (SubC γ r1' r2')+ cs''' <- splitS (SubC γ r2' r1')+ return $ cs ++ cs' ++ cs'' ++ cs'''++splitS (SubC γ t1 (RAllP p t))+ = splitS $ SubC γ t1 t'+ where+ t' = fmap (replacePredsWithRefs su) t+ su = (uPVar p, pVartoRConc p)++splitS (SubC _ t1@(RAllP _ _) t2)+ = panic Nothing $ "Predicate in lhs of constrain:" ++ showpp t1 ++ "\n<:\n" ++ showpp t2++splitS (SubC γ (RAllT α1 t1) (RAllT α2 t2))+ | α1 == α2+ = splitS $ SubC γ t1 t2+ | otherwise+ = splitS $ SubC γ t1 t2'+ where t2' = subsTyVar_meet' (α2, RVar α1 mempty) t2++splitS (SubC _ (RApp c1 _ _ _) (RApp c2 _ _ _)) | isClass c1 && c1 == c2+ = return []+++splitS (SubC γ t1@(RApp {}) t2@(RApp {}))+ = do (t1',t2') <- unifyVV t1 t2+ cs <- bsplitS t1' t2'+ γ' <- γ `extendEnvWithVV` t1'+ let RApp c t1s r1s _ = t1'+ let RApp _ t2s r2s _ = t2'+ let isapplied = TC.tyConArity (rtc_tc c) == length t1s+ let tyInfo = rtc_info c+ csvar <- splitsSWithVariance γ' t1s t2s $ varianceTyArgs tyInfo+ csvar' <- rsplitsSWithVariance isapplied γ' r1s r2s $ variancePsArgs tyInfo+ return $ cs ++ csvar ++ csvar'++splitS (SubC _ t1@(RVar a1 _) t2@(RVar a2 _))+ | a1 == a2+ = bsplitS t1 t2++splitS (SubC _ t1 t2)+ = panic Nothing $ "(Another Broken Test1!!!) splitS unexpected: " ++ showpp t1 ++ "\n\n" ++ showpp t2++splitS (SubR _ _ _)+ = return []++splitsSWithVariance γ t1s t2s variants+ = concatMapM (\(t1, t2, v) -> splitfWithVariance (\s1 s2 -> splitS (SubC γ s1 s2)) t1 t2 v) (zip3 t1s t2s variants)++rsplitsSWithVariance False _ _ _ _+ = return []++rsplitsSWithVariance _ γ t1s t2s variants+ = concatMapM (\(t1, t2, v) -> splitfWithVariance (rsplitS γ) t1 t2 v) (zip3 t1s t2s variants)++bsplitS t1 t2+ = return $ [(s1, s2)]+ where [s1, s2] = getStrata <$> [t1, t2]++rsplitS _ (RProp _ (RHole _)) _+ = panic Nothing "rsplitS RProp _ (RHole _)"++rsplitS _ _ (RProp _ (RHole _))+ = panic Nothing "rsplitS RProp _ (RHole _)"++rsplitS γ (RProp s1 r1) (RProp s2 r2)+ = splitS (SubC γ (F.subst su r1) r2)+ where su = F.mkSubst [(x, F.EVar y) | ((x,_), (y,_)) <- zip s1 s2]++splitfWithVariance f t1 t2 Invariant = (++) <$> f t1 t2 <*> f t2 t1+splitfWithVariance f t1 t2 Bivariant = (++) <$> f t1 t2 <*> f t2 t1+splitfWithVariance f t1 t2 Covariant = f t1 t2+splitfWithVariance f t1 t2 Contravariant = f t2 t1+++------------------------------------------------------------+splitC :: SubC -> CG [FixSubC]+------------------------------------------------------------++splitC (SubC γ (REx x tx t1) (REx x2 _ t2)) | x == x2+ = do γ' <- (γ, "addExBind 0") += (x, forallExprRefType γ tx)+ splitC (SubC γ' t1 t2)++splitC (SubC γ t1 (REx x tx t2))+ = do y <- fresh+ γ' <- (γ, "addExBind 1") += (y, forallExprRefType γ tx)+ splitC (SubC γ' t1 (F.subst1 t2 (x, F.EVar y)))++-- existential at the left hand side is treated like forall+splitC (SubC γ (REx x tx t1) t2)+ = do -- let tx' = traceShow ("splitC: " ++ showpp z) tx+ y <- fresh+ γ' <- (γ, "addExBind 2") += (y, forallExprRefType γ tx)+ splitC (SubC γ' (F.subst1 t1 (x, F.EVar y)) t2)++splitC (SubC γ (RAllE x tx t1) (RAllE x2 _ t2)) | x == x2+ = do γ' <- (γ, "addAllBind 0") += (x, forallExprRefType γ tx)+ splitC (SubC γ' t1 t2)++splitC (SubC γ (RAllE x tx t1) t2)+ = do y <- fresh+ γ' <- (γ, "addAABind 1") += (y, forallExprRefType γ tx)+ splitC (SubC γ' (t1 `F.subst1` (x, F.EVar y)) t2)++splitC (SubC γ t1 (RAllE x tx t2))+ = do y <- fresh+ γ' <- (γ, "addAllBind 2") += (y, forallExprRefType γ tx)+ splitC (SubC γ' t1 (F.subst1 t2 (x, F.EVar y)))++splitC (SubC γ (RRTy env _ OCons t1) t2)+ = do γ' <- foldM (\γ (x, t) -> γ `addSEnv` ("splitS", x,t)) γ xts+ c1 <- splitC (SubC γ' t1' t2')+ c2 <- splitC (SubC γ t1 t2 )+ return $ c1 ++ c2+ where+ (xts, t1', t2') = envToSub env++splitC (SubC γ (RRTy e r o t1) t2)+ = do γ' <- foldM (\γ (x, t) -> γ `addSEnv` ("splitS", x,t)) γ e+ c1 <- splitC (SubR γ' o r)+ c2 <- splitC (SubC γ t1 t2)+ return $ c1 ++ c2++splitC (SubC γ t1@(RFun x1 r1 r1' _) t2@(RFun x2 r2 r2' _))+ = do cs <- bsplitC γ t1 t2+ cs' <- splitC (SubC γ r2 r1)+ γ' <- (γ, "splitC") += (x2, r2)+ let r1x2' = r1' `F.subst1` (x1, F.EVar x2)+ cs'' <- splitC (SubC γ' r1x2' r2')+ return $ cs ++ cs' ++ cs''++splitC (SubC γ t1@(RAppTy r1 r1' _) t2@(RAppTy r2 r2' _))+ = do cs <- bsplitC γ t1 t2+ cs' <- splitC (SubC γ r1 r2)+ cs'' <- splitC (SubC γ r1' r2')+ cs''' <- splitC (SubC γ r2' r1')+ return $ cs ++ cs' ++ cs'' ++ cs'''++splitC (SubC γ t1 (RAllP p t))+ = splitC $ SubC γ t1 t'+ where+ t' = fmap (replacePredsWithRefs su) t+ su = (uPVar p, pVartoRConc p)++splitC (SubC γ t1@(RAllP _ _) t2)+ = panic (Just $ getLocation γ) $ "Predicate in lhs of constraint:" ++ showpp t1 ++ "\n<:\n" ++ showpp t2++splitC (SubC γ (RAllT α1 t1) (RAllT α2 t2))+ | α1 == α2+ = splitC $ SubC γ t1 t2+ | otherwise+ = splitC $ SubC γ t1 t2'+ where t2' = subsTyVar_meet' (α2, RVar α1 mempty) t2+++splitC (SubC _ (RApp c1 _ _ _) (RApp c2 _ _ _)) | isClass c1 && c1 == c2+ = return []++splitC (SubC γ t1@(RApp _ _ _ _) t2@(RApp _ _ _ _))+ = do (t1',t2') <- unifyVV t1 t2+ cs <- bsplitC γ t1' t2'+ γ' <- γ `extendEnvWithVV` t1'+ let RApp c t1s r1s _ = t1'+ let RApp _ t2s r2s _ = t2'+ let isapplied = True -- TC.tyConArity (rtc_tc c) == length t1s+ let tyInfo = rtc_info c+ csvar <- splitsCWithVariance γ' t1s t2s $ varianceTyArgs tyInfo+ csvar' <- rsplitsCWithVariance isapplied γ' r1s r2s $ variancePsArgs tyInfo+ return $ cs ++ csvar ++ csvar'++splitC (SubC γ t1@(RVar a1 _) t2@(RVar a2 _))+ | a1 == a2+ = bsplitC γ t1 t2++splitC (SubC _ t1 t2)+ = panic Nothing $ "(Another Broken Test!!!) splitc unexpected:\n" ++ showpp t1 ++ "\n <:\n" ++ showpp t2++splitC (SubR γ o r)+ = do fg <- pruneRefs <$> get+ let r1' = if fg then pruneUnsortedReft γ'' r1 else r1+ return $ F.subC γ' r1' r2 Nothing tag ci+ where+ γ'' = feEnv $ fenv γ+ γ' = feBinds $ fenv γ+ r1 = F.RR F.boolSort rr+ r2 = F.RR F.boolSort $ F.Reft (vv, F.EVar vv)+ vv = "vvRec"+ ci = Ci src err+ err = Just $ ErrAssType src o (text $ show o ++ "type error") g (rHole rr)+ rr = F.toReft r+ tag = getTag γ+ src = getLocation γ+ g = reLocal $ renv γ++rHole :: F.Reft -> SpecType+rHole = RHole . uTop+++splitsCWithVariance γ t1s t2s variants+ = concatMapM (\(t1, t2, v) -> splitfWithVariance (\s1 s2 -> (splitC (SubC γ s1 s2))) t1 t2 v) (zip3 t1s t2s variants)++rsplitsCWithVariance False _ _ _ _+ = return []++rsplitsCWithVariance _ γ t1s t2s variants+ = concatMapM (\(t1, t2, v) -> splitfWithVariance (rsplitC γ) t1 t2 v) (zip3 t1s t2s variants)++bsplitC γ t1 t2 = do+ checkStratum γ t1 t2+ pflag <- pruneRefs <$> get+ isHO <- allowHO <$> get+ let t1' = addLhsInv γ t1+ return $ bsplitC' γ t1' t2 pflag isHO++addLhsInv :: CGEnv -> SpecType -> SpecType+addLhsInv γ t = addRTyConInv (invs γ) t `strengthen` r+ where+ r = (mempty :: UReft F.Reft) { ur_reft = F.Reft (F.dummySymbol, p) }+ p = constraintToLogic rE' (lcs γ)+ rE' = insertREnv v t (renv γ)+ v = rTypeValueVar t++ -- γ' <- γ ++= ("bsplitC", v, t1)+ -- let r = (mempty :: UReft F.Reft){ur_reft = F.Reft (F.dummySymbol, constraintToLogic γ' (lcs γ'))}+ -- let t1' = addRTyConInv (invs γ') t1 `strengthen` r+ -- let F.Reft(v, _) = ur_reft (fromMaybe mempty (stripRTypeBase t1))++checkStratum γ t1 t2+ | s1 <:= s2 = return ()+ | otherwise = addWarning wrn+ where+ [s1, s2] = getStrata <$> [t1, t2]+ wrn = ErrOther (getLocation γ) (text $ "Stratum Error : " ++ show s1 ++ " > " ++ show s2)++bsplitC' γ t1 t2 pflag isHO+ | isHO+ = F.subC γ' r1' r2' Nothing tag ci+ | F.isFunctionSortedReft r1' && F.isNonTrivial r2'+ = F.subC γ' (r1' {F.sr_reft = mempty}) r2' Nothing tag ci+ | F.isNonTrivial r2'+ = F.subC γ' r1' r2' Nothing tag ci+ | otherwise+ = []+ where+ γ' = feBinds $ fenv γ+ r1' = rTypeSortedReft' pflag γ t1+ r2' = rTypeSortedReft' pflag γ t2+ ci = Ci src err+ tag = getTag γ+ err = Just $ fromMaybe (ErrSubType src (text "subtype") g t1 t2) (cerr γ)+ src = getLocation γ+ g = reLocal $ renv γ++unifyVV :: SpecType -> SpecType -> CG (SpecType, SpecType)+unifyVV t1@(RApp _ _ _ _) t2@(RApp _ _ _ _)+ = do vv <- (F.vv . Just) <$> fresh+ return $ (shiftVV t1 vv, (shiftVV t2 vv) )++unifyVV _ _+ = panic Nothing $ "Constraint.Generate.unifyVV called on invalid inputs"++rsplitC _ _ (RProp _ (RHole _))+ = panic Nothing "RefTypes.rsplitC on RProp _ (RHole _)"++rsplitC _ (RProp _ (RHole _)) _+ = panic Nothing "RefTypes.rsplitC on RProp _ (RHole _)"++rsplitC γ (RProp s1 r1) (RProp s2 r2)+ = do γ' <- foldM (++=) γ [("rsplitC1", x, ofRSort s) | (x, s) <- s2]+ splitC (SubC γ' (F.subst su r1) r2)+ where su = F.mkSubst [(x, F.EVar y) | ((x,_), (y,_)) <- zip s1 s2]+++--------------------------------------------------------------------------------+-- | Reftypes from F.Fixpoint Expressions --------------------------------------+--------------------------------------------------------------------------------+forallExprRefType :: CGEnv -> SpecType -> SpecType+forallExprRefType γ t = t `strengthen` (uTop r')+ where+ r' = fromMaybe mempty $ forallExprReft γ r+ r = F.sr_reft $ rTypeSortedReft (emb γ) t++forallExprReft :: CGEnv -> F.Reft -> Maybe F.Reft+forallExprReft γ r =+ do e <- F.isSingletonReft r+ forallExprReft_ γ $ F.splitEApp e++forallExprReft_ :: CGEnv -> (F.Expr, [F.Expr]) -> Maybe F.Reft+forallExprReft_ γ (F.EVar x, [])+ = case forallExprReftLookup γ x of+ Just (_,_,_,t) -> Just $ F.sr_reft $ rTypeSortedReft (emb γ) t+ Nothing -> Nothing++forallExprReft_ γ (F.EVar f, es)+ = case forallExprReftLookup γ f of+ Just (xs,_,_,t) -> let su = F.mkSubst $ safeZip "fExprRefType" xs es in+ Just $ F.subst su $ F.sr_reft $ rTypeSortedReft (emb γ) t+ Nothing -> Nothing++forallExprReft_ _ _+ = Nothing++-- forallExprReftLookup :: CGEnv -> F.Symbol -> Int+forallExprReftLookup γ x = snap <$> F.lookupSEnv x (syenv γ)+ where+ snap = mapFourth4 ignoreOblig . bkArrow . fourth4 . bkUniv . lookup+ lookup z = fromMaybe (panicUnbound γ z) (γ ?= F.symbol z)+++--------------------------------------------------------------------------------+getTag :: CGEnv -> F.Tag+--------------------------------------------------------------------------------+getTag γ = maybe Tg.defaultTag (`Tg.getTag` tgEnv γ) (tgKey γ)+++--------------------------------------------------------------------------------+{-@ envToSub :: {v:[(a, b)] | 2 <= len v} -> ([(a, b)], b, b) @-}+envToSub :: [(a, b)] -> ([(a, b)], b, b)+--------------------------------------------------------------------------------+envToSub = go []+ where+ go _ [] = impossible Nothing "This cannot happen: envToSub on 0 elems"+ go _ [(_,_)] = impossible Nothing "This cannot happen: envToSub on 1 elem"+ go ack [(_,l), (_, r)] = (reverse ack, l, r)+ go ack (x:xs) = go (x:ack) xs++--------------------------------------------------------------------------------+-- | Constraint Generation Panic -----------------------------------------------+--------------------------------------------------------------------------------+panicUnbound :: (PPrint x) => CGEnv -> x -> a+panicUnbound γ x = Ex.throw $ (ErrUnbound (getLocation γ) (pprint x) :: Error)
src/Language/Haskell/Liquid/Constraint/ToFixpoint.hs view
@@ -3,48 +3,44 @@ cgInfoFInfo ) where-+import Prelude hiding (error) import qualified Language.Fixpoint.Types as F import Language.Haskell.Liquid.Constraint.Types import Language.Haskell.Liquid.Types hiding ( binds )-import Language.Fixpoint.Misc ( mapSnd )-import Language.Fixpoint.Interface ( parseFInfo ) -import Control.Applicative ((<$>))-import qualified Data.HashMap.Strict as M+import Language.Fixpoint.Solver ( parseFInfo )+++ import Data.Monoid -import Language.Haskell.Liquid.Qualifier-import Language.Haskell.Liquid.RefType ( rTypeSortedReft )+import Language.Haskell.Liquid.Constraint.Qualifier -cgInfoFInfo :: GhcInfo -> CGInfo -> IO (F.FInfo Cinfo)-cgInfoFInfo info cgi = do- let tgtFI = targetFInfo info cgi++cgInfoFInfo :: GhcInfo -> CGInfo -> FilePath -> IO (F.FInfo Cinfo)+cgInfoFInfo info cgi fi = do+ let tgtFI = targetFInfo info cgi fi impFI <- parseFInfo $ hqFiles info return $ tgtFI <> impFI -targetFInfo :: GhcInfo -> CGInfo -> F.FInfo Cinfo-targetFInfo info cgi- = F.FI { F.cm = M.fromList $ F.addIds $ fixCs cgi- , F.ws = fixWfs cgi- , F.bs = binds cgi- , F.gs = F.fromListSEnv . map mkSort $ meas spc- , F.lits = lits cgi- , F.kuts = kuts cgi- , F.quals = targetQuals info- , F.bindInfo = (`Ci` Nothing) <$> bindSpans cgi- -- , F.fileName = error "FIX THIS" :: FilePath- }- where- spc = spec info- tce = tcEmbeds spc- mkSort = mapSnd (rTypeSortedReft tce . val)+targetFInfo :: GhcInfo -> CGInfo -> FilePath -> F.FInfo Cinfo+targetFInfo info cgi fn = F.fi cs ws bs ls ks qs bi fn aHO + where+ cs = fixCs cgi+ ws = fixWfs cgi+ bs = binds cgi+ ls = fEnv cgi+ ks = kuts cgi+ qs = targetQuals info cgi+ bi = (`Ci` Nothing) <$> bindSpans cgi+ aHO = allowHO cgi -targetQuals :: GhcInfo -> [F.Qualifier]-targetQuals info = spcQs ++ genQs+targetQuals :: GhcInfo -> CGInfo -> [F.Qualifier]+targetQuals info cgi = spcQs ++ genQs where spcQs = qualifiers spc- genQs = specificationQualifiers n info+ genQs = specificationQualifiers n info (fEnv cgi) n = maxParams $ config spc spc = spec info+ -- lEnv = F.fromListSEnv $ lits cgi
src/Language/Haskell/Liquid/Constraint/Types.hs view
@@ -1,5 +1,50 @@-module Language.Haskell.Liquid.Constraint.Types where +{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE OverloadedStrings #-}++module Language.Haskell.Liquid.Constraint.Types+ ( -- * Constraint Generation Monad+ CG++ -- * Constraint information+ , CGInfo (..)++ -- * Constraint Generation Environment+ , CGEnv (..)++ -- * Logical constraints (FIXME: related to bounds?)+ , LConstraint (..)++ -- * Fixpoint environment+ , FEnv (..)+ , initFEnv+ , insertsFEnv++ -- * Hole Environment+ , HEnv+ , fromListHEnv+ , elemHEnv++ -- * Subtyping Constraints+ , SubC (..)+ , FixSubC++ -- * Well-formedness Constraints+ , WfC (..)+ , FixWfC++ -- * Invariants+ , RTyConInv+ , mkRTyConInv+ , addRTyConInv+ , addRInv++ -- * Aliases?+ , RTyConIAl+ , mkRTyConIAl+ ) where++import Prelude hiding (error) import CoreSyn import SrcLoc @@ -13,60 +58,76 @@ import qualified Data.HashSet as S import qualified Data.List as L -import Control.Applicative ((<$>))-import Data.Monoid (mconcat)+import Control.DeepSeq+-- import Data.Monoid (mconcat) import Data.Maybe (catMaybes)+import Control.Monad.State + import Var -import Language.Haskell.Liquid.Types-import Language.Haskell.Liquid.Strata-import Language.Haskell.Liquid.Misc (fourth4)-import Language.Haskell.Liquid.RefType (shiftVV)-import Language.Haskell.Liquid.PredType (wiredSortedSyms)+++++import Language.Haskell.Liquid.GHC.SpanStack+import Language.Haskell.Liquid.Types hiding (binds)+import Language.Haskell.Liquid.Types.Strata+import Language.Haskell.Liquid.Misc (fourth4)+import Language.Haskell.Liquid.Types.RefType (shiftVV)+import Language.Haskell.Liquid.WiredIn (wiredSortedSyms) import qualified Language.Fixpoint.Types as F import Language.Fixpoint.Misc -import qualified Language.Haskell.Liquid.CTags as Tg+import qualified Language.Haskell.Liquid.UX.CTags as Tg +type CG = State CGInfo+ data CGEnv- = CGE { loc :: !SrcSpan -- ^ Location in original source file- , renv :: !REnv -- ^ SpecTypes for Bindings in scope- , syenv :: !(F.SEnv Var) -- ^ Map from free Symbols (e.g. datacons) to Var- -- , penv :: !(F.SEnv PrType) -- ^ PrTypes for top-level bindings (merge with renv)- , denv :: !RDEnv -- ^ Dictionary Environment- , fenv :: !FEnv -- ^ Fixpoint Environment- , recs :: !(S.HashSet Var) -- ^ recursive defs being processed (for annotations)- , invs :: !RTyConInv -- ^ Datatype invariants- , ial :: !RTyConIAl -- ^ Datatype checkable invariants- , grtys :: !REnv -- ^ Top-level variables with (assert)-guarantees to verify- , assms :: !REnv -- ^ Top-level variables with assumed types- , emb :: F.TCEmb TC.TyCon -- ^ How to embed GHC Tycons into fixpoint sorts+ = CGE { cgLoc :: !SpanStack -- ^ Location in original source file+ , renv :: !REnv -- ^ SpecTypes for Bindings in scope+ , syenv :: !(F.SEnv Var) -- ^ Map from free Symbols (e.g. datacons) to Var+ , denv :: !RDEnv -- ^ Dictionary Environment+ , fenv :: !FEnv -- ^ Fixpoint Environment+ , recs :: !(S.HashSet Var) -- ^ recursive defs being processed (for annotations)+ , invs :: !RTyConInv -- ^ Datatype invariants+ , ial :: !RTyConIAl -- ^ Datatype checkable invariants+ , grtys :: !REnv -- ^ Top-level variables with (assert)-guarantees to verify+ , assms :: !REnv -- ^ Top-level variables with assumed types+ , intys :: !REnv -- ^ Top-level variables with auto generated internal types+ , emb :: F.TCEmb TC.TyCon -- ^ How to embed GHC Tycons into fixpoint sorts , tgEnv :: !Tg.TagEnv -- ^ Map from top-level binders to fixpoint tag- , tgKey :: !(Maybe Tg.TagKey) -- ^ Current top-level binder+ , tgKey :: !(Maybe Tg.TagKey) -- ^ Current top-level binder , trec :: !(Maybe (M.HashMap F.Symbol SpecType)) -- ^ Type of recursive function with decreasing constraints- , lcb :: !(M.HashMap F.Symbol CoreExpr) -- ^ Let binding that have not been checked- , holes :: !HEnv -- ^ Types with holes, will need refreshing- , lcs :: !LConstraint -- ^ Logical Constraints+ , lcb :: !(M.HashMap F.Symbol CoreExpr) -- ^ Let binding that have not been checked (c.f. LAZYVARs)+ , holes :: !HEnv -- ^ Types with holes, will need refreshing+ , lcs :: !LConstraint -- ^ Logical Constraints+ , aenv :: !(M.HashMap Var F.Symbol) -- ^ axiom environment maps axiomatized Haskell functions to the logical functions+ , cerr :: !(Maybe (TError SpecType)) -- ^ error that should be reported at the user } -- deriving (Data, Typeable) - data LConstraint = LC [[(F.Symbol, SpecType)]] +instance Monoid LConstraint where+ mempty = LC []+ mappend (LC cs1) (LC cs2) = LC (cs1 ++ cs2) + instance PPrint CGEnv where- pprint = pprint . renv+ pprintTidy k = pprintTidy k . renv instance Show CGEnv where show = showpp -------------------------------------------------------------------------------------- Constraints: Types --------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------+-- | Subtyping Constraints -----------------------------------------------------+-------------------------------------------------------------------------------- +-- RJ: what is the difference between these two?+ data SubC = SubC { senv :: !CGEnv , lhs :: !SpecType , rhs :: !SpecType@@ -83,55 +144,63 @@ type FixWfC = F.WfC Cinfo instance PPrint SubC where- pprint c = pprint (senv c)- $+$ (text " |- " <+> (pprint (lhs c) $+$- text "<:" $+$- pprint (rhs c)))+ -- pprint c = pprint (senv c)+ -- $+$ (text " |- " <+> (pprint (lhs c) $+$+ -- text "<:" $+$+ -- pprint (rhs c)))+ pprintTidy k c@(SubC {}) = pprintTidy k (senv c)+ $+$ ("||-" <+> vcat [ pprintTidy k (lhs c)+ , "<:"+ , pprintTidy k (rhs c) ] )+ pprintTidy k c@(SubR {}) = pprintTidy k (senv c)+ $+$ ("||-" <+> vcat [ pprintTidy k (ref c)+ , parens (pprintTidy k (oblig c))]) + instance PPrint WfC where- pprint (WfC w r) = pprint w <> text " |- " <> pprint r+ pprintTidy k (WfC _ r) = {- pprintTidy k w <> text -} "<...> |-" <+> pprintTidy k r instance SubStratum SubC where subS su (SubC γ t1 t2) = SubC γ (subS su t1) (subS su t2) subS _ c = c ------------------------------------------------------------------------------------ Generation: Types --------------------------------------------------------------------------------+--------------------------------------------------------------------------------+-- | Generation: Types ---------------------------------------------------------+-------------------------------------------------------------------------------- -data CGInfo = CGInfo { hsCs :: ![SubC] -- ^ subtyping constraints over RType- , hsWfs :: ![WfC] -- ^ wellformedness constraints over RType- , sCs :: ![SubC] -- ^ additional stratum constrains for let bindings- , fixCs :: ![FixSubC] -- ^ subtyping over Sort (post-splitting)- , isBind :: ![Bool] -- ^ tracks constraints that come from let-bindings- , fixWfs :: ![FixWfC] -- ^ wellformedness constraints over Sort (post-splitting)- , freshIndex :: !Integer -- ^ counter for generating fresh KVars- , binds :: !F.BindEnv -- ^ set of environment binders- , annotMap :: !(AnnInfo (Annot SpecType)) -- ^ source-position annotation map- , tyConInfo :: !(M.HashMap TC.TyCon RTyCon) -- ^ information about type-constructors- , specDecr :: ![(Var, [Int])] -- ^ ? FIX THIS- , termExprs :: !(M.HashMap Var [F.Expr]) -- ^ Terminating Metrics for Recursive functions- , specLVars :: !(S.HashSet Var) -- ^ Set of variables to ignore for termination checking- , specLazy :: !(S.HashSet Var) -- ^ ? FIX THIS- , autoSize :: !(S.HashSet TC.TyCon) -- ^ ? FIX THIS- , tyConEmbed :: !(F.TCEmb TC.TyCon) -- ^ primitive Sorts into which TyCons should be embedded- , kuts :: !(F.Kuts) -- ^ Fixpoint Kut variables (denoting "back-edges"/recursive KVars)- , lits :: ![(F.Symbol, F.Sort)] -- ^ ? FIX THIS- , tcheck :: !Bool -- ^ Check Termination (?)- , scheck :: !Bool -- ^ Check Strata (?)- , trustghc :: !Bool -- ^ Trust ghc auto generated bindings- , pruneRefs :: !Bool -- ^ prune unsorted refinements- , logErrors :: ![TError SpecType] -- ^ Errors during constraint generation- , kvProf :: !KVProf -- ^ Profiling distribution of KVars- , recCount :: !Int -- ^ number of recursive functions seen (for benchmarks)- , bindSpans :: M.HashMap F.BindId SrcSpan -- ^ Source Span associated with Fixpoint Binder- }+data CGInfo = CGInfo {+ fEnv :: !(F.SEnv F.Sort) -- ^ top-level fixpoint env+ , hsCs :: ![SubC] -- ^ subtyping constraints over RType+ , hsWfs :: ![WfC] -- ^ wellformedness constraints over RType+ , sCs :: ![SubC] -- ^ additional stratum constrains for let bindings+ , fixCs :: ![FixSubC] -- ^ subtyping over Sort (post-splitting)+ , isBind :: ![Bool] -- ^ tracks constraints that come from let-bindings+ , fixWfs :: ![FixWfC] -- ^ wellformedness constraints over Sort (post-splitting)+ , freshIndex :: !Integer -- ^ counter for generating fresh KVars+ , binds :: !F.BindEnv -- ^ set of environment binders+ , annotMap :: !(AnnInfo (Annot SpecType)) -- ^ source-position annotation map+ , tyConInfo :: !(M.HashMap TC.TyCon RTyCon) -- ^ information about type-constructors+ , specDecr :: ![(Var, [Int])] -- ^ ? FIX THIS+ , termExprs :: !(M.HashMap Var [F.Expr]) -- ^ Terminating Metrics for Recursive functions+ , specLVars :: !(S.HashSet Var) -- ^ Set of variables to ignore for termination checking+ , specLazy :: !(S.HashSet Var) -- ^ ? FIX THIS+ , autoSize :: !(S.HashSet TC.TyCon) -- ^ ? FIX THIS+ , tyConEmbed :: !(F.TCEmb TC.TyCon) -- ^ primitive Sorts into which TyCons should be embedded+ , kuts :: !F.Kuts -- ^ Fixpoint Kut variables (denoting "back-edges"/recursive KVars)+ , lits :: ![(F.Symbol, F.Sort)] -- ^ ? FIX THIS+ , tcheck :: !Bool -- ^ Check Termination (?)+ , scheck :: !Bool -- ^ Check Strata (?)+ , trustghc :: !Bool -- ^ Trust ghc auto generated bindings+ , pruneRefs :: !Bool -- ^ prune unsorted refinements+ , logErrors :: ![Error] -- ^ Errors during constraint generation+ , kvProf :: !KVProf -- ^ Profiling distribution of KVars+ , recCount :: !Int -- ^ number of recursive functions seen (for benchmarks)+ , bindSpans :: M.HashMap F.BindId SrcSpan -- ^ Source Span associated with Fixpoint Binder+ , allowHO :: !Bool + } instance PPrint CGInfo where- pprint cgi = {-# SCC "ppr_CGI" #-} pprCGInfo cgi+ pprintTidy _ cgi = {-# SCC "ppr_CGI" #-} pprCGInfo cgi pprCGInfo _cgi = text "*********** Constraint Information ***********"@@ -152,30 +221,25 @@ -- -$$ (text "Recursive binders:" <+> pprint (recCount cgi)) -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Helper Types: HEnv --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------+-- | Helper Types: HEnv --------------------------------------------------------+-------------------------------------------------------------------------------- newtype HEnv = HEnv (S.HashSet F.Symbol) fromListHEnv = HEnv . S.fromList elemHEnv x (HEnv s) = x `S.member` s ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ Helper Types: Invariants -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------+-- | Helper Types: Invariants --------------------------------------------------+-------------------------------------------------------------------------------- type RTyConInv = M.HashMap RTyCon [SpecType] type RTyConIAl = M.HashMap RTyCon [SpecType] +-------------------------------------------------------------------------------- mkRTyConInv :: [F.Located SpecType] -> RTyConInv+-------------------------------------------------------------------------------- mkRTyConInv ts = group [ (c, t) | t@(RApp c _ _ _) <- strip <$> ts] where strip = fourth4 . bkUniv . val@@ -218,42 +282,52 @@ conjoinInvariant t _ = t ---grapBindsWithType tx γ- = fst <$> toListREnv (filterREnv ((== toRSort tx) . toRSort) (renv γ))----------------------------------------------------------------------- Refinement Type Environments ---------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------+-- | Fixpoint Environment ------------------------------------------------------+-------------------------------------------------------------------------------- +data FEnv = FE { feBinds :: !F.IBindEnv -- ^ Integer Keys for Fixpoint Environment+ , feEnv :: !(F.SEnv F.Sort) -- ^ Fixpoint Environment+ } -toListREnv (REnv env) = M.toList env-filterREnv f (REnv env) = REnv $ M.filter f env-fromListREnv = REnv . M.fromList-deleteREnv x (REnv env) = REnv (M.delete x env)-insertREnv x y (REnv env) = REnv (M.insert x y env)-lookupREnv x (REnv env) = M.lookup x env-memberREnv x (REnv env) = M.member x env+insertFEnv (FE benv env) ((x, t), i)+ = FE (F.insertsIBindEnv [i] benv) (F.insertSEnv x t env) +insertsFEnv :: FEnv -> [((F.Symbol, F.Sort), F.BindId)] -> FEnv+insertsFEnv = L.foldl' insertFEnv +initFEnv xts = FE F.emptyIBindEnv $ F.fromListSEnv (wiredSortedSyms ++ xts) --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Fixpoint Environment ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------+-- | Forcing Strictness --------------------------------------------------------+-------------------------------------------------------------------------------- +instance NFData CGEnv where+ rnf (CGE x1 _ x3 _ x5 x6 x7 x8 x9 _ _ _ x10 _ _ _ _ _ _ _)+ = x1 `seq` {- rnf x2 `seq` -} seq x3 `seq` rnf x5 `seq`+ rnf x6 `seq` x7 `seq` rnf x8 `seq` rnf x9 `seq` rnf x10 -data FEnv = FE { fe_binds :: !F.IBindEnv -- ^ Integer Keys for Fixpoint Environment- , fe_env :: !(F.SEnv F.Sort) -- ^ Fixpoint Environment- }+instance NFData FEnv where+ rnf (FE x1 _) = rnf x1 -insertFEnv (FE benv env) ((x, t), i)- = FE (F.insertsIBindEnv [i] benv) (F.insertSEnv x t env)+instance NFData SubC where+ rnf (SubC x1 x2 x3)+ = rnf x1 `seq` rnf x2 `seq` rnf x3+ rnf (SubR x1 _ x2)+ = rnf x1 `seq` rnf x2 -insertsFEnv :: FEnv -> [((F.Symbol, F.Sort), F.BindId)] -> FEnv-insertsFEnv = L.foldl' insertFEnv+instance NFData WfC where+ rnf (WfC x1 x2)+ = rnf x1 `seq` rnf x2 -initFEnv init = FE F.emptyIBindEnv $ F.fromListSEnv (wiredSortedSyms ++ init)+instance NFData CGInfo where+ rnf x = ({-# SCC "CGIrnf1" #-} rnf (hsCs x)) `seq`+ ({-# SCC "CGIrnf2" #-} rnf (hsWfs x)) `seq`+ ({-# SCC "CGIrnf3" #-} rnf (fixCs x)) `seq`+ ({-# SCC "CGIrnf4" #-} rnf (fixWfs x)) `seq`+ ({-# SCC "CGIrnf6" #-} rnf (freshIndex x)) `seq`+ ({-# SCC "CGIrnf7" #-} rnf (binds x)) `seq`+ ({-# SCC "CGIrnf8" #-} rnf (annotMap x)) `seq`+ ({-# SCC "CGIrnf10" #-} rnf (kuts x)) `seq`+ ({-# SCC "CGIrnf10" #-} rnf (lits x)) `seq`+ ({-# SCC "CGIrnf10" #-} rnf (kvProf x))
− src/Language/Haskell/Liquid/CoreToLogic.hs
@@ -1,409 +0,0 @@-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE FlexibleContexts #-} -{-# LANGUAGE UndecidableInstances #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE TupleSections #-}-{-# LANGUAGE EmptyDataDecls #-}--module Language.Haskell.Liquid.CoreToLogic ( -- coreToDef , coreToFun- , mkLit, runToLogic,- logicType, - strengthenResult-- ) where--import GHC hiding (Located)-import Var -import Type --import qualified CoreSyn as C-import Literal-import IdInfo--import Data.Text.Encoding--import TysWiredIn --import Control.Applicative --import Language.Fixpoint.Misc-import Language.Fixpoint.Names (dropModuleNames, propConName, isPrefixOfSym)-import Language.Fixpoint.Types hiding (Def, R, simplify)-import qualified Language.Fixpoint.Types as F-import Language.Haskell.Liquid.GhcMisc-import Language.Haskell.Liquid.GhcPlay-import Language.Haskell.Liquid.Types hiding (GhcInfo(..), GhcSpec (..))-import Language.Haskell.Liquid.WiredIn-import Language.Haskell.Liquid.RefType---import qualified Data.HashMap.Strict as M--import Data.Monoid---logicType :: (Reftable r) => Type -> RRType r-logicType τ = fromRTypeRep $ t{ty_res = res, ty_binds = binds, ty_args = args, ty_refts = refts}- where - t = toRTypeRep $ ofType τ - res = mkResType $ ty_res t- (binds, args, refts) = unzip3 $ dropWhile (isClassType.snd3) $ zip3 (ty_binds t) (ty_args t) (ty_refts t)- -- mkResType t - | isBool t = propType- | otherwise = t--isBool (RApp (RTyCon{rtc_tc = c}) _ _ _) = c == boolTyCon-isBool _ = False--{- strengthenResult type: the refinement depends on whether the result type is a Bool or not:--CASE1: measure f@logic :: X -> Prop <=> f@haskell :: x:X -> {v:Bool | (Prop v) <=> (f@logic x)} --CASE2: measure f@logic :: X -> Y <=> f@haskell :: x:X -> {v:Y | v = (f@logic x)} --}--strengthenResult :: Var -> SpecType-strengthenResult v- | isBool res- = -- traceShow ("Type for " ++ showPpr v ++ "\t OF \t" ++ show (ty_binds rep)) $ - fromRTypeRep $ rep{ty_res = res `strengthen` r, ty_binds = xs}- | otherwise- = -- traceShow ("Type for " ++ showPpr v ++ "\t OF \t" ++ show (ty_binds rep)) $ - fromRTypeRep $ rep{ty_res = res `strengthen` r', ty_binds = xs}- where rep = toRTypeRep t- res = ty_res rep- xs = intSymbol (symbol ("x" :: String)) <$> [1..length $ ty_binds rep]- r' = U (exprReft (EApp f (mkA <$> vxs))) mempty mempty- r = U (propReft (PBexp $ EApp f (mkA <$> vxs))) mempty mempty- vxs = dropWhile (isClassType.snd) $ zip xs (ty_args rep)- f = dummyLoc $ dropModuleNames $ simplesymbol v- t = (ofType $ varType v) :: SpecType- mkA = \(x, _) -> EVar x -- if isBool t then EApp (dummyLoc propConName) [(EVar x)] else EVar x---simplesymbol = symbol . getName--newtype LogicM a = LM {runM :: LState -> Either a Error}--data LState = LState { symbolMap :: LogicMap - , mkError :: String -> Error- }---instance Monad LogicM where- return = LM . const . Left- (LM m) >>= f - = LM $ \s -> case m s of - (Left x) -> (runM (f x)) s - (Right x) -> Right x--instance Functor LogicM where- fmap f (LM m) = LM $ \s -> case m s of - (Left x) -> Left $ f x- (Right x) -> Right x--instance Applicative LogicM where- pure = LM . const . Left- (LM f) <*> (LM m) - = LM $ \s -> case (f s, m s) of - (Left f , Left x ) -> Left $ f x- (Right f, Left _ ) -> Right f- (Left _ , Right x) -> Right x- (Right _, Right x) -> Right x--throw :: String -> LogicM a-throw str = LM $ \s -> Right $ (mkError s) str--getState :: LogicM LState-getState = LM $ Left --runToLogic lmap ferror (LM m) - = m $ LState {symbolMap = lmap, mkError = ferror}--coreToDef :: Reftable r => LocSymbol -> Var -> C.CoreExpr -> LogicM [Def (RRType r) DataCon]-coreToDef x _ e = go [] $ inline_preds $ simplify e- where- go args (C.Lam x e) = go (x:args) e- go args (C.Tick _ e) = go args e- go args (C.Case _ _ t alts) - | eqType t boolTy = mapM (goalt_prop (reverse $ tail args) (head args)) alts- | otherwise = mapM (goalt (reverse $ tail args) (head args)) alts- go _ _ = throw "Measure Functions should have a case at top level"-- goalt args dx ((C.DataAlt d), xs, e) - = ((Def x (toArgs id args) d (Just $ ofType $ varType dx) (toArgs Just xs)) . E) - <$> coreToLogic e- goalt _ _ alt- = throw $ "Bad alternative" ++ showPpr alt-- goalt_prop args dx ((C.DataAlt d), xs, e) - = ((Def x (toArgs id args) d (Just $ ofType $ varType dx) (toArgs Just xs)) . P) - <$> coreToPred e- goalt_prop _ _ alt - = throw $ "Bad alternative" ++ showPpr alt-- toArgs f args = [(symbol x, f $ ofType $ varType x) | x <- args]-- inline_preds = inline (eqType boolTy . varType)--coreToFun :: LocSymbol -> Var -> C.CoreExpr -> LogicM ([Var], Either Pred Expr)-coreToFun _ v e = go [] $ inline_preds $ simplify e- where- go acc (C.Lam x e) | isTyVar x = go acc e- go acc (C.Lam x e) | isErasable x = go acc e- go acc (C.Lam x e) = go (x:acc) e- go acc (C.Tick _ e) = go acc e- go acc e | eqType rty boolTy - = (reverse acc,) . Left <$> coreToPred e - | otherwise - = (reverse acc,) . Right <$> coreToLogic e-- inline_preds = inline (eqType boolTy . varType)-- rty = snd $ splitFunTys $ snd $ splitForAllTys $ varType v--instance Show C.CoreExpr where- show = showPpr--coreToPred :: C.CoreExpr -> LogicM Pred-coreToPred (C.Let b p) = subst1 <$> coreToPred p <*> makesub b-coreToPred (C.Tick _ p) = coreToPred p-coreToPred (C.App (C.Var v) e) | ignoreVar v = coreToPred e-coreToPred (C.Var x)- | x == falseDataConId- = return PFalse- | x == trueDataConId- = return PTrue- | eqType boolTy (varType x)- = return $ PBexp $ EApp (dummyLoc propConName) [(EVar $ symbol x)]-coreToPred p@(C.App _ _) = toPredApp p -coreToPred e- = PBexp <$> coreToLogic e --- coreToPred e --- = throw ("Cannot transform to Logical Predicate:\t" ++ showPpr e)---coreToLogic :: C.CoreExpr -> LogicM Expr-coreToLogic (C.Let b e) = subst1 <$> coreToLogic e <*> makesub b-coreToLogic (C.Tick _ e) = coreToLogic e-coreToLogic (C.App (C.Var v) e) | ignoreVar v = coreToLogic e-coreToLogic (C.Lit l) - = case mkLit l of - Nothing -> throw $ "Bad Literal in measure definition" ++ showPpr l- Just i -> return i-coreToLogic (C.Var x) = (symbolMap <$> getState) >>= eVarWithMap x-coreToLogic e@(C.App _ _) = toLogicApp e -coreToLogic (C.Case e b _ alts) | eqType (varType b) boolTy- = checkBoolAlts alts >>= coreToIte e -coreToLogic e = throw ("Cannot transform to Logic:\t" ++ showPpr e)--checkBoolAlts :: [C.CoreAlt] -> LogicM (C.CoreExpr, C.CoreExpr)-checkBoolAlts [(C.DataAlt false, [], efalse), (C.DataAlt true, [], etrue)]- | false == falseDataCon, true == trueDataCon- = return (efalse, etrue)-checkBoolAlts [(C.DataAlt true, [], etrue), (C.DataAlt false, [], efalse)]- | false == falseDataCon, true == trueDataCon- = return (efalse, etrue)-checkBoolAlts alts- = throw ("checkBoolAlts failed on " ++ showPpr alts) --coreToIte e (efalse, etrue)- = do p <- coreToPred e- e1 <- coreToLogic efalse - e2 <- coreToLogic etrue- return $ EIte p e2 e1--toPredApp :: C.CoreExpr -> LogicM Pred-toPredApp p - = do let (f, es) = splitArgs p- f' <- tosymbol f- go f' es- where- go f [e1, e2]- | Just rel <- M.lookup (val f) brels - = PAtom rel <$> (coreToLogic e1) <*> (coreToLogic e2)- go f [e]- | val f == symbol ("not" :: String)- = PNot <$> coreToPred e- go f [e1, e2]- | val f == symbol ("||" :: String)- = POr <$> mapM coreToPred [e1, e2]- | val f == symbol ("&&" :: String)- = PAnd <$> mapM coreToPred [e1, e2]- | val f == symbol ("==>" :: String)- = PImp <$> coreToPred e1 <*> coreToPred e2- go f es- | val f == symbol ("or" :: String)- = POr <$> mapM coreToPred es- | val f == symbol ("and" :: String)- = PAnd <$> mapM coreToPred es- | otherwise- = PBexp <$> toLogicApp p--toLogicApp :: C.CoreExpr -> LogicM Expr-toLogicApp e - = do let (f, es) = splitArgs e- args <- mapM coreToLogic es- lmap <- symbolMap <$> getState- def <- (`EApp` args) <$> tosymbol f- (\x -> makeApp def lmap x args) <$> tosymbol' f--makeApp :: Expr -> LogicMap -> Located Symbol-> [Expr] -> Expr-makeApp _ _ f [e] | val f == symbol ("GHC.Num.negate" :: String)- = ENeg e--makeApp _ _ f [e1, e2] | Just op <- M.lookup (val f) bops- = EBin op e1 e2--makeApp def lmap f es - = eAppWithMap lmap f es def--eVarWithMap :: Id -> LogicMap -> LogicM Expr-eVarWithMap x lmap - = do f' <- tosymbol' (C.Var x :: C.CoreExpr)- return $ eAppWithMap lmap f' [] (EVar $ symbol x)--brels :: M.HashMap Symbol Brel-brels = M.fromList [ (symbol ("==" :: String), Eq)- , (symbol ("/=" :: String), Ne)- , (symbol (">=" :: String), Ge)- , (symbol (">" :: String) , Gt)- , (symbol ("<=" :: String), Le)- , (symbol ("<" :: String) , Lt)- ]--bops :: M.HashMap Symbol Bop-bops = M.fromList [ (numSymbol "+", Plus)- , (numSymbol "-", Minus)- , (numSymbol "*", Times)- , (numSymbol "/", Div)- , (numSymbol "%", Mod)- ] - where- numSymbol :: String -> Symbol- numSymbol = symbol . (++) "GHC.Num."--splitArgs e = (f, reverse es)- where- (f, es) = go e-- go (C.App (C.Var i) e) | ignoreVar i = go e- go (C.App f (C.Var v)) | isErasable v = go f- go (C.App f e) = (f', e:es) where (f', es) = go f- go f = (f, [])--tosymbol (C.Var c) | isDataConId c = return $ dummyLoc $ symbol c -tosymbol (C.Var x) = return $ dummyLoc $ simpleSymbolVar x-tosymbol e = throw ("Bad Measure Definition:\n" ++ showPpr e ++ "\t cannot be applied")--tosymbol' (C.Var x) = return $ dummyLoc $ simpleSymbolVar' x-tosymbol' e = throw ("Bad Measure Definition:\n" ++ showPpr e ++ "\t cannot be applied")--makesub (C.NonRec x e) = (symbol x,) <$> coreToLogic e-makesub _ = throw "Cannot make Logical Substitution of Recursive Definitions"--mkLit :: Literal -> Maybe Expr-mkLit (MachInt n) = mkI n-mkLit (MachInt64 n) = mkI n-mkLit (MachWord n) = mkI n-mkLit (MachWord64 n) = mkI n-mkLit (MachFloat n) = mkR n-mkLit (MachDouble n) = mkR n-mkLit (LitInteger n _) = mkI n-mkLit (MachStr s) = mkS s -mkLit _ = Nothing -- ELit sym sort--mkI = Just . ECon . I -mkR = Just . ECon . F.R . fromRational-mkS = Just . ESym . SL . decodeUtf8--ignoreVar i = simpleSymbolVar i `elem` ["I#"]---simpleSymbolVar = dropModuleNames . symbol . showPpr . getName-simpleSymbolVar' = symbol . showPpr . getName--isErasable v = isPrefixOfSym (symbol ("$" :: String)) (simpleSymbolVar v)--isDead = isDeadOcc . occInfo . idInfo--class Simplify a where- simplify :: a -> a - inline :: (Id -> Bool) -> a -> a--instance Simplify C.CoreExpr where- simplify e@(C.Var _) - = e- simplify e@(C.Lit _) - = e- simplify (C.App e (C.Type _)) - = simplify e- simplify (C.App e (C.Var dict)) | isErasable dict - = simplify e- simplify (C.App (C.Lam x e) _) | isDead x - = simplify e- simplify (C.App e1 e2) - = C.App (simplify e1) (simplify e2)- simplify (C.Lam x e) | isTyVar x - = simplify e- simplify (C.Lam x e) | isErasable x - = simplify e- simplify (C.Lam x e) - = C.Lam x (simplify e)- simplify (C.Let (C.NonRec x _) e) | isErasable x- = simplify e - simplify (C.Let (C.Rec xes) e) | all (isErasable . fst) xes- = simplify e - simplify (C.Let xes e) - = C.Let (simplify xes) (simplify e)- simplify (C.Case e x t alts) - = C.Case (simplify e) x t (filter (not . isUndefined) (simplify <$> alts))- simplify (C.Cast e _) - = simplify e- simplify (C.Tick _ e) - = simplify e- simplify (C.Coercion c)- = C.Coercion c- simplify (C.Type t)- = C.Type t -- inline p (C.Let (C.NonRec x ex) e) | p x- = sub (M.singleton x (inline p ex)) (inline p e)- inline p (C.Let xes e) = C.Let (inline p xes) (inline p e) - inline p (C.App e1 e2) = C.App (inline p e1) (inline p e2)- inline p (C.Lam x e) = C.Lam x (inline p e)- inline p (C.Case e x t alts) = C.Case (inline p e) x t (inline p <$> alts)- inline p (C.Cast e c) = C.Cast (inline p e) c- inline p (C.Tick t e) = C.Tick t (inline p e)- inline _ (C.Var x) = C.Var x- inline _ (C.Lit l) = C.Lit l- inline _ (C.Coercion c) = C.Coercion c- inline _ (C.Type t) = C.Type t--isUndefined (_, _, e) = isUndefinedExpr e- where - -- auto generated undefined case: (\_ -> (patError @type "error message")) void- isUndefinedExpr (C.App (C.Var x) _) | (show x) `elem` perrors = True- isUndefinedExpr (C.Let _ e) = isUndefinedExpr e- -- otherwise - isUndefinedExpr _ = False -- perrors = ["Control.Exception.Base.patError"]---instance Simplify C.CoreBind where- simplify (C.NonRec x e) = C.NonRec x (simplify e)- simplify (C.Rec xes) = C.Rec (mapSnd simplify <$> xes )-- inline p (C.NonRec x e) = C.NonRec x (inline p e)- inline p (C.Rec xes) = C.Rec (mapSnd (inline p) <$> xes)--instance Simplify C.CoreAlt where- simplify (c, xs, e) = (c, xs, simplify e) -- inline p (c, xs, e) = (c, xs, inline p e)-
− src/Language/Haskell/Liquid/Desugar/Check.lhs
@@ -1,765 +0,0 @@-%-% (c) The University of Glasgow 2006-% (c) The GRASP/AQUA Project, Glasgow University, 1997-1998-%-% Author: Juan J. Quintela <quintela@krilin.dc.fi.udc.es>--\begin{code}-module Language.Haskell.Liquid.Desugar.Check ( check , ExhaustivePat ) where---- #include "HsVersions.h"--import HsSyn-import TcHsSyn-import Language.Haskell.Liquid.Desugar.DsUtils-import Language.Haskell.Liquid.Desugar.MatchLit-import Id-import ConLike-import DataCon-import PatSyn-import Name-import TysWiredIn-import PrelNames-import TyCon-import SrcLoc-import UniqSet-import Util-import BasicTypes-import Outputable-import FastString-\end{code}--This module performs checks about if one list of equations are:-\begin{itemize}-\item Overlapped-\item Non exhaustive-\end{itemize}-To discover that we go through the list of equations in a tree-like fashion.--If you like theory, a similar algorithm is described in:-\begin{quotation}- {\em Two Techniques for Compiling Lazy Pattern Matching},- Luc Maranguet,- INRIA Rocquencourt (RR-2385, 1994)-\end{quotation}-The algorithm is based on the first technique, but there are some differences:-\begin{itemize}-\item We don't generate code-\item We have constructors and literals (not only literals as in the- article)-\item We don't use directions, we must select the columns from- left-to-right-\end{itemize}-(By the way the second technique is really similar to the one used in- @Match.lhs@ to generate code)--This function takes the equations of a pattern and returns:-\begin{itemize}-\item The patterns that are not recognized-\item The equations that are not overlapped-\end{itemize}-It simplify the patterns and then call @check'@ (the same semantics), and it-needs to reconstruct the patterns again ....--The problem appear with things like:-\begin{verbatim}- f [x,y] = ....- f (x:xs) = .....-\end{verbatim}-We want to put the two patterns with the same syntax, (prefix form) and-then all the constructors are equal:-\begin{verbatim}- f (: x (: y [])) = ....- f (: x xs) = .....-\end{verbatim}-(more about that in @tidy_eqns@)--We would prefer to have a @WarningPat@ of type @String@, but Strings and the-Pretty Printer are not friends.--We use @InPat@ in @WarningPat@ instead of @OutPat@-because we need to print the-warning messages in the same way they are introduced, i.e. if the user-wrote:-\begin{verbatim}- f [x,y] = ..-\end{verbatim}-He don't want a warning message written:-\begin{verbatim}- f (: x (: y [])) ........-\end{verbatim}-Then we need to use InPats.-\begin{quotation}- Juan Quintela 5 JUL 1998\\- User-friendliness and compiler writers are no friends.-\end{quotation}--\begin{code}-type WarningPat = InPat Name-type ExhaustivePat = ([WarningPat], [(Name, [HsLit])])-type EqnNo = Int-type EqnSet = UniqSet EqnNo---check :: [EquationInfo] -> ([ExhaustivePat], [EquationInfo])- -- Second result is the shadowed equations- -- if there are view patterns, just give up - don't know what the function is-check qs = (untidy_warns, shadowed_eqns)- where- tidy_qs = map tidy_eqn qs- (warns, used_nos) = check' ([1..] `zip` tidy_qs)- untidy_warns = map untidy_exhaustive warns- shadowed_eqns = [eqn | (eqn,i) <- qs `zip` [1..],- not (i `elementOfUniqSet` used_nos)]--untidy_exhaustive :: ExhaustivePat -> ExhaustivePat-untidy_exhaustive ([pat], messages) =- ([untidy_no_pars pat], map untidy_message messages)-untidy_exhaustive (pats, messages) =- (map untidy_pars pats, map untidy_message messages)--untidy_message :: (Name, [HsLit]) -> (Name, [HsLit])-untidy_message (string, lits) = (string, map untidy_lit lits)-\end{code}--The function @untidy@ does the reverse work of the @tidy_pat@ funcion.--\begin{code}--type NeedPars = Bool--untidy_no_pars :: WarningPat -> WarningPat-untidy_no_pars p = untidy False p--untidy_pars :: WarningPat -> WarningPat-untidy_pars p = untidy True p--untidy :: NeedPars -> WarningPat -> WarningPat-untidy b (L loc p) = L loc (untidy' b p)- where- untidy' _ p@(WildPat _) = p- untidy' _ p@(VarPat _) = p- untidy' _ (LitPat lit) = LitPat (untidy_lit lit)- untidy' _ p@(ConPatIn _ (PrefixCon [])) = p- untidy' b (ConPatIn name ps) = pars b (L loc (ConPatIn name (untidy_con ps)))- untidy' _ (ListPat pats ty Nothing) = ListPat (map untidy_no_pars pats) ty Nothing - untidy' _ (TuplePat pats box tys) = TuplePat (map untidy_no_pars pats) box tys- untidy' _ (ListPat _ _ (Just _)) = panic "Check.untidy: Overloaded ListPat" - untidy' _ (PArrPat _ _) = panic "Check.untidy: Shouldn't get a parallel array here!"- untidy' _ (SigPatIn _ _) = panic "Check.untidy: SigPat"- untidy' _ (LazyPat {}) = panic "Check.untidy: LazyPat"- untidy' _ (AsPat {}) = panic "Check.untidy: AsPat"- untidy' _ (ParPat {}) = panic "Check.untidy: ParPat"- untidy' _ (BangPat {}) = panic "Check.untidy: BangPat"- untidy' _ (ConPatOut {}) = panic "Check.untidy: ConPatOut"- untidy' _ (ViewPat {}) = panic "Check.untidy: ViewPat"- untidy' _ (SplicePat {}) = panic "Check.untidy: SplicePat"- untidy' _ (QuasiQuotePat {}) = panic "Check.untidy: QuasiQuotePat"- untidy' _ (NPat {}) = panic "Check.untidy: NPat"- untidy' _ (NPlusKPat {}) = panic "Check.untidy: NPlusKPat"- untidy' _ (SigPatOut {}) = panic "Check.untidy: SigPatOut"- untidy' _ (CoPat {}) = panic "Check.untidy: CoPat"--untidy_con :: HsConPatDetails Name -> HsConPatDetails Name-untidy_con (PrefixCon pats) = PrefixCon (map untidy_pars pats)-untidy_con (InfixCon p1 p2) = InfixCon (untidy_pars p1) (untidy_pars p2)-untidy_con (RecCon (HsRecFields flds dd))- = RecCon (HsRecFields [ fld { hsRecFieldArg = untidy_pars (hsRecFieldArg fld) }- | fld <- flds ] dd)--pars :: NeedPars -> WarningPat -> Pat Name-pars True p = ParPat p-pars _ p = unLoc p--untidy_lit :: HsLit -> HsLit-untidy_lit (HsCharPrim c) = HsChar c-untidy_lit lit = lit-\end{code}--This equation is the same that check, the only difference is that the-boring work is done, that work needs to be done only once, this is-the reason top have two functions, check is the external interface,-@check'@ is called recursively.--There are several cases:--\begin{itemize}-\item There are no equations: Everything is OK.-\item There are only one equation, that can fail, and all the patterns are- variables. Then that equation is used and the same equation is- non-exhaustive.-\item All the patterns are variables, and the match can fail, there are- more equations then the results is the result of the rest of equations- and this equation is used also.--\item The general case, if all the patterns are variables (here the match- can't fail) then the result is that this equation is used and this- equation doesn't generate non-exhaustive cases.--\item In the general case, there can exist literals ,constructors or only- vars in the first column, we actuate in consequence.--\end{itemize}---\begin{code}--check' :: [(EqnNo, EquationInfo)]- -> ([ExhaustivePat], -- Pattern scheme that might not be matched at all- EqnSet) -- Eqns that are used (others are overlapped)--check' [] = ([],emptyUniqSet)- -- Was ([([],[])], emptyUniqSet)- -- But that (a) seems weird, and (b) triggered Trac #7669 - -- So now I'm just doing the simple obvious thing--check' ((n, EqnInfo { eqn_pats = ps, eqn_rhs = MatchResult can_fail _ }) : rs)- | first_eqn_all_vars && case can_fail of { CantFail -> True; CanFail -> False }- = ([], unitUniqSet n) -- One eqn, which can't fail-- | first_eqn_all_vars && null rs -- One eqn, but it can fail- = ([(takeList ps (repeat nlWildPat),[])], unitUniqSet n)-- | first_eqn_all_vars -- Several eqns, first can fail- = (pats, addOneToUniqSet indexs n)- where- first_eqn_all_vars = all_vars ps- (pats,indexs) = check' rs--check' qs- | some_literals = split_by_literals qs- | some_constructors = split_by_constructor qs- | only_vars = first_column_only_vars qs- | otherwise = pprPanic "Check.check': Not implemented :-(" (ppr first_pats)- -- Shouldn't happen- where- -- Note: RecPats will have been simplified to ConPats- -- at this stage.- first_pats = {- ASSERT2( okGroup qs, pprGroup qs ) -} map firstPatN qs- some_constructors = any is_con first_pats- some_literals = any is_lit first_pats- only_vars = all is_var first_pats-\end{code}--Here begins the code to deal with literals, we need to split the matrix-in different matrix beginning by each literal and a last matrix with the-rest of values.--\begin{code}-split_by_literals :: [(EqnNo, EquationInfo)] -> ([ExhaustivePat], EqnSet)-split_by_literals qs = process_literals used_lits qs- where- used_lits = get_used_lits qs-\end{code}--@process_explicit_literals@ is a function that process each literal that appears-in the column of the matrix.--\begin{code}-process_explicit_literals :: [HsLit] -> [(EqnNo, EquationInfo)] -> ([ExhaustivePat],EqnSet)-process_explicit_literals lits qs = (concat pats, unionManyUniqSets indexs)- where- pats_indexs = map (\x -> construct_literal_matrix x qs) lits- (pats,indexs) = unzip pats_indexs-\end{code}---@process_literals@ calls @process_explicit_literals@ to deal with the literals-that appears in the matrix and deal also with the rest of the cases. It-must be one Variable to be complete.--\begin{code}--process_literals :: [HsLit] -> [(EqnNo, EquationInfo)] -> ([ExhaustivePat],EqnSet)-process_literals used_lits qs- | null default_eqns = {- ASSERT( not (null qs) ) -} ([make_row_vars used_lits (head qs)] ++ pats,indexs)- | otherwise = (pats_default,indexs_default)- where- (pats,indexs) = process_explicit_literals used_lits qs- default_eqns = -- ASSERT2( okGroup qs, pprGroup qs )- [remove_var q | q <- qs, is_var (firstPatN q)]- (pats',indexs') = check' default_eqns- pats_default = [(nlWildPat:ps,constraints) | (ps,constraints) <- (pats')] ++ pats- indexs_default = unionUniqSets indexs' indexs-\end{code}--Here we have selected the literal and we will select all the equations that-begins for that literal and create a new matrix.--\begin{code}-construct_literal_matrix :: HsLit -> [(EqnNo, EquationInfo)] -> ([ExhaustivePat],EqnSet)-construct_literal_matrix lit qs =- (map (\ (xs,ys) -> (new_lit:xs,ys)) pats,indexs)- where- (pats,indexs) = (check' (remove_first_column_lit lit qs))- new_lit = nlLitPat lit--remove_first_column_lit :: HsLit- -> [(EqnNo, EquationInfo)]- -> [(EqnNo, EquationInfo)]-remove_first_column_lit lit qs- = -- ASSERT2( okGroup qs, pprGroup qs )- [(n, shift_pat eqn) | q@(n,eqn) <- qs, is_var_lit lit (firstPatN q)]- where- shift_pat eqn@(EqnInfo { eqn_pats = _:ps}) = eqn { eqn_pats = ps }- shift_pat _ = panic "Check.shift_var: no patterns"-\end{code}--This function splits the equations @qs@ in groups that deal with the-same constructor.--\begin{code}-split_by_constructor :: [(EqnNo, EquationInfo)] -> ([ExhaustivePat], EqnSet)-split_by_constructor qs- | null used_cons = ([], mkUniqSet $ map fst qs)- | notNull unused_cons = need_default_case used_cons unused_cons qs- | otherwise = no_need_default_case used_cons qs- where- used_cons = get_used_cons qs- unused_cons = get_unused_cons used_cons-\end{code}--The first column of the patterns matrix only have vars, then there is-nothing to do.--\begin{code}-first_column_only_vars :: [(EqnNo, EquationInfo)] -> ([ExhaustivePat],EqnSet)-first_column_only_vars qs = (map (\ (xs,ys) -> (nlWildPat:xs,ys)) pats,indexs)- where- (pats, indexs) = check' (map remove_var qs)-\end{code}--This equation takes a matrix of patterns and split the equations by-constructor, using all the constructors that appears in the first column-of the pattern matching.--We can need a default clause or not ...., it depends if we used all the-constructors or not explicitly. The reasoning is similar to @process_literals@,-the difference is that here the default case is not always needed.--\begin{code}-no_need_default_case :: [Pat Id] -> [(EqnNo, EquationInfo)] -> ([ExhaustivePat],EqnSet)-no_need_default_case cons qs = (concat pats, unionManyUniqSets indexs)- where- pats_indexs = map (\x -> construct_matrix x qs) cons- (pats,indexs) = unzip pats_indexs--need_default_case :: [Pat Id] -> [DataCon] -> [(EqnNo, EquationInfo)] -> ([ExhaustivePat],EqnSet)-need_default_case used_cons unused_cons qs- | null default_eqns = (pats_default_no_eqns,indexs)- | otherwise = (pats_default,indexs_default)- where- (pats,indexs) = no_need_default_case used_cons qs- default_eqns = -- ASSERT2( okGroup qs, pprGroup qs )- [remove_var q | q <- qs, is_var (firstPatN q)]- (pats',indexs') = check' default_eqns- pats_default = [(make_whole_con c:ps,constraints) |- c <- unused_cons, (ps,constraints) <- pats'] ++ pats- new_wilds = {- ASSERT( not (null qs) ) -} make_row_vars_for_constructor (head qs)- pats_default_no_eqns = [(make_whole_con c:new_wilds,[]) | c <- unused_cons] ++ pats- indexs_default = unionUniqSets indexs' indexs--construct_matrix :: Pat Id -> [(EqnNo, EquationInfo)] -> ([ExhaustivePat],EqnSet)-construct_matrix con qs =- (map (make_con con) pats,indexs)- where- (pats,indexs) = (check' (remove_first_column con qs))-\end{code}--Here remove first column is more difficult that with literals due to the fact-that constructors can have arguments.--For instance, the matrix-\begin{verbatim}- (: x xs) y- z y-\end{verbatim}-is transformed in:-\begin{verbatim}- x xs y- _ _ y-\end{verbatim}--\begin{code}-remove_first_column :: Pat Id -- Constructor- -> [(EqnNo, EquationInfo)]- -> [(EqnNo, EquationInfo)]-remove_first_column (ConPatOut{ pat_con = L _ con, pat_args = PrefixCon con_pats }) qs- = -- ASSERT2( okGroup qs, pprGroup qs )- [(n, shift_var eqn) | q@(n, eqn) <- qs, is_var_con con (firstPatN q)]- where- new_wilds = [WildPat (hsLPatType arg_pat) | arg_pat <- con_pats]- shift_var eqn@(EqnInfo { eqn_pats = ConPatOut{ pat_args = PrefixCon ps' } : ps})- = eqn { eqn_pats = map unLoc ps' ++ ps }- shift_var eqn@(EqnInfo { eqn_pats = WildPat _ : ps })- = eqn { eqn_pats = new_wilds ++ ps }- shift_var _ = panic "Check.Shift_var:No done"-remove_first_column _ _ = panic "Check.remove_first_column: Not ConPatOut"--make_row_vars :: [HsLit] -> (EqnNo, EquationInfo) -> ExhaustivePat-make_row_vars used_lits (_, EqnInfo { eqn_pats = pats})- = (nlVarPat new_var:takeList (tail pats) (repeat nlWildPat),[(new_var,used_lits)])- where- new_var = hash_x--hash_x :: Name-hash_x = mkInternalName unboundKey {- doesn't matter much -}- (mkVarOccFS (fsLit "#x"))- noSrcSpan--make_row_vars_for_constructor :: (EqnNo, EquationInfo) -> [WarningPat]-make_row_vars_for_constructor (_, EqnInfo { eqn_pats = pats})- = takeList (tail pats) (repeat nlWildPat)--compare_cons :: Pat Id -> Pat Id -> Bool-compare_cons (ConPatOut{ pat_con = L _ con1 }) (ConPatOut{ pat_con = L _ con2 })- = case (con1, con2) of- (RealDataCon id1, RealDataCon id2) -> id1 == id2- _ -> False-compare_cons _ _ = panic "Check.compare_cons: Not ConPatOut with RealDataCon"--remove_dups :: [Pat Id] -> [Pat Id]-remove_dups [] = []-remove_dups (x:xs) | or (map (\y -> compare_cons x y) xs) = remove_dups xs- | otherwise = x : remove_dups xs--get_used_cons :: [(EqnNo, EquationInfo)] -> [Pat Id]-get_used_cons qs = remove_dups [pat | q <- qs, let pat = firstPatN q,- isConPatOut pat]--isConPatOut :: Pat Id -> Bool-isConPatOut ConPatOut{ pat_con = L _ RealDataCon{} } = True-isConPatOut _ = False--remove_dups' :: [HsLit] -> [HsLit]-remove_dups' [] = []-remove_dups' (x:xs) | x `elem` xs = remove_dups' xs- | otherwise = x : remove_dups' xs---get_used_lits :: [(EqnNo, EquationInfo)] -> [HsLit]-get_used_lits qs = remove_dups' all_literals- where- all_literals = get_used_lits' qs--get_used_lits' :: [(EqnNo, EquationInfo)] -> [HsLit]-get_used_lits' [] = []-get_used_lits' (q:qs)- | Just lit <- get_lit (firstPatN q) = lit : get_used_lits' qs- | otherwise = get_used_lits qs--get_lit :: Pat id -> Maybe HsLit--- Get a representative HsLit to stand for the OverLit--- It doesn't matter which one, because they will only be compared--- with other HsLits gotten in the same way-get_lit (LitPat lit) = Just lit-get_lit (NPat (OverLit { ol_val = HsIntegral i}) mb _) = Just (HsIntPrim (mb_neg negate mb i))-get_lit (NPat (OverLit { ol_val = HsFractional f }) mb _) = Just (HsFloatPrim (mb_neg negateFractionalLit mb f))-get_lit (NPat (OverLit { ol_val = HsIsString s }) _ _) = Just (HsStringPrim (fastStringToByteString s))-get_lit _ = Nothing--mb_neg :: (a -> a) -> Maybe b -> a -> a-mb_neg _ Nothing v = v-mb_neg negate (Just _) v = negate v--get_unused_cons :: [Pat Id] -> [DataCon]-get_unused_cons used_cons = {- ASSERT( not (null used_cons) ) -} unused_cons- where- used_set :: UniqSet DataCon- used_set = mkUniqSet [d | ConPatOut{ pat_con = L _ (RealDataCon d) } <- used_cons]- (ConPatOut { pat_con = L _ (RealDataCon con1), pat_arg_tys = inst_tys }) = head used_cons- ty_con = dataConTyCon con1- unused_cons = filterOut is_used (tyConDataCons ty_con)- is_used con = con `elementOfUniqSet` used_set- || dataConCannotMatch inst_tys con--all_vars :: [Pat Id] -> Bool-all_vars [] = True-all_vars (WildPat _:ps) = all_vars ps-all_vars _ = False--remove_var :: (EqnNo, EquationInfo) -> (EqnNo, EquationInfo)-remove_var (n, eqn@(EqnInfo { eqn_pats = WildPat _ : ps})) = (n, eqn { eqn_pats = ps })-remove_var _ = panic "Check.remove_var: equation does not begin with a variable"--------------------------{--eqnPats :: (EqnNo, EquationInfo) -> [Pat Id]-eqnPats (_, eqn) = eqn_pats eqn-okGroup :: [(EqnNo, EquationInfo)] -> Bool--- True if all equations have at least one pattern, and--- all have the same number of patterns-okGroup [] = True-okGroup (e:es) = n_pats > 0 && and [length (eqnPats e) == n_pats | e <- es]- where- n_pats = length (eqnPats e)--}--- Half-baked print--- pprGroup :: [(EqnNo, EquationInfo)] -> SDoc--- pprEqnInfo :: (EqnNo, EquationInfo) -> SDoc--- pprGroup es = vcat (map pprEqnInfo es)--- pprEqnInfo e = ppr (eqnPats e)---firstPatN :: (EqnNo, EquationInfo) -> Pat Id-firstPatN (_, eqn) = firstPat eqn--is_con :: Pat Id -> Bool-is_con (ConPatOut {}) = True-is_con _ = False--is_lit :: Pat Id -> Bool-is_lit (LitPat _) = True-is_lit (NPat _ _ _) = True-is_lit _ = False--is_var :: Pat Id -> Bool-is_var (WildPat _) = True-is_var _ = False--is_var_con :: ConLike -> Pat Id -> Bool-is_var_con _ (WildPat _) = True-is_var_con con (ConPatOut{ pat_con = L _ id }) = id == con-is_var_con _ _ = False--is_var_lit :: HsLit -> Pat Id -> Bool-is_var_lit _ (WildPat _) = True-is_var_lit lit pat- | Just lit' <- get_lit pat = lit == lit'- | otherwise = False-\end{code}--The difference beteewn @make_con@ and @make_whole_con@ is that-@make_wole_con@ creates a new constructor with all their arguments, and-@make_con@ takes a list of argumntes, creates the contructor getting their-arguments from the list. See where \fbox{\ ???\ } are used for details.--We need to reconstruct the patterns (make the constructors infix and-similar) at the same time that we create the constructors.--You can tell tuple constructors using-\begin{verbatim}- Id.isTupleDataCon-\end{verbatim}-You can see if one constructor is infix with this clearer code :-))))))))))-\begin{verbatim}- Lex.isLexConSym (Name.occNameString (Name.getOccName con))-\end{verbatim}-- Rather clumsy but it works. (Simon Peyton Jones)---We don't mind the @nilDataCon@ because it doesn't change the way to-print the message, we are searching only for things like: @[1,2,3]@,-not @x:xs@ ....--In @reconstruct_pat@ we want to ``undo'' the work-that we have done in @tidy_pat@.-In particular:-\begin{tabular}{lll}- @((,) x y)@ & returns to be & @(x, y)@-\\ @((:) x xs)@ & returns to be & @(x:xs)@-\\ @(x:(...:[])@ & returns to be & @[x,...]@-\end{tabular}-%-The difficult case is the third one becouse we need to follow all the-contructors until the @[]@ to know that we need to use the second case,-not the second. \fbox{\ ???\ }-%-\begin{code}-isInfixCon :: DataCon -> Bool-isInfixCon con = isDataSymOcc (getOccName con)--is_nil :: Pat Name -> Bool-is_nil (ConPatIn con (PrefixCon [])) = unLoc con == getName nilDataCon-is_nil _ = False--is_list :: Pat Name -> Bool-is_list (ListPat _ _ Nothing) = True-is_list _ = False--return_list :: DataCon -> Pat Name -> Bool-return_list id q = id == consDataCon && (is_nil q || is_list q)--make_list :: LPat Name -> Pat Name -> Pat Name-make_list p q | is_nil q = ListPat [p] placeHolderType Nothing-make_list p (ListPat ps ty Nothing) = ListPat (p:ps) ty Nothing-make_list _ _ = panic "Check.make_list: Invalid argument"--make_con :: Pat Id -> ExhaustivePat -> ExhaustivePat-make_con (ConPatOut{ pat_con = L _ (RealDataCon id) }) (lp:lq:ps, constraints)- | return_list id q = (noLoc (make_list lp q) : ps, constraints)- | isInfixCon id = (nlInfixConPat (getName id) lp lq : ps, constraints)- where q = unLoc lq--make_con (ConPatOut{ pat_con = L _ (RealDataCon id), pat_args = PrefixCon pats, pat_arg_tys = tys }) (ps, constraints)- | isTupleTyCon tc = (noLoc (TuplePat pats_con (tupleTyConBoxity tc) tys) : rest_pats, constraints)- | isPArrFakeCon id = (noLoc (PArrPat pats_con placeHolderType) : rest_pats, constraints)- | otherwise = (nlConPat name pats_con : rest_pats, constraints)- where- name = getName id- (pats_con, rest_pats) = splitAtList pats ps- tc = dataConTyCon id--make_con _ _ = panic "Check.make_con: Not ConPatOut"---- reconstruct parallel array pattern------ * don't check for the type only; we need to make sure that we are really--- dealing with one of the fake constructors and not with the real--- representation--make_whole_con :: DataCon -> WarningPat-make_whole_con con | isInfixCon con = nlInfixConPat name nlWildPat nlWildPat- | otherwise = nlConPat name pats- where- name = getName con- pats = [nlWildPat | _ <- dataConOrigArgTys con]-\end{code}--------------------------------------------------------------------------- Tidying equations---------------------------------------------------------------------------tidy_eqn does more or less the same thing as @tidy@ in @Match.lhs@;-that is, it removes syntactic sugar, reducing the number of cases that-must be handled by the main checking algorithm. One difference is-that here we can do *all* the tidying at once (recursively), rather-than doing it incrementally.--\begin{code}-tidy_eqn :: EquationInfo -> EquationInfo-tidy_eqn eqn = eqn { eqn_pats = map tidy_pat (eqn_pats eqn),- eqn_rhs = tidy_rhs (eqn_rhs eqn) }- where- -- Horrible hack. The tidy_pat stuff converts "might-fail" patterns to- -- WildPats which of course loses the info that they can fail to match.- -- So we stick in a CanFail as if it were a guard.- tidy_rhs (MatchResult can_fail body)- | any might_fail_pat (eqn_pats eqn) = MatchResult CanFail body- | otherwise = MatchResult can_fail body-----------------might_fail_pat :: Pat Id -> Bool--- Returns True of patterns that might fail (i.e. fall through) in a way--- that is not covered by the checking algorithm. Specifically:--- NPlusKPat--- ViewPat (if refutable)--- ConPatOut of a PatSynCon---- First the two special cases-might_fail_pat (NPlusKPat {}) = True-might_fail_pat (ViewPat _ p _) = not (isIrrefutableHsPat p)---- Now the recursive stuff-might_fail_pat (ParPat p) = might_fail_lpat p-might_fail_pat (AsPat _ p) = might_fail_lpat p-might_fail_pat (SigPatOut p _ ) = might_fail_lpat p-might_fail_pat (ListPat ps _ Nothing) = any might_fail_lpat ps-might_fail_pat (ListPat _ _ (Just _)) = True-might_fail_pat (TuplePat ps _ _) = any might_fail_lpat ps-might_fail_pat (PArrPat ps _) = any might_fail_lpat ps-might_fail_pat (BangPat p) = might_fail_lpat p-might_fail_pat (ConPatOut { pat_con = con, pat_args = ps })- = case unLoc con of- RealDataCon _dcon -> any might_fail_lpat (hsConPatArgs ps)- PatSynCon _psyn -> True---- Finally the ones that are sure to succeed, or which are covered by the checking algorithm-might_fail_pat (LazyPat _) = False -- Always succeeds-might_fail_pat _ = False -- VarPat, WildPat, LitPat, NPat-----------------might_fail_lpat :: LPat Id -> Bool-might_fail_lpat (L _ p) = might_fail_pat p-----------------tidy_lpat :: LPat Id -> LPat Id-tidy_lpat p = fmap tidy_pat p-----------------tidy_pat :: Pat Id -> Pat Id-tidy_pat pat@(WildPat _) = pat-tidy_pat (VarPat id) = WildPat (idType id)-tidy_pat (ParPat p) = tidy_pat (unLoc p)-tidy_pat (LazyPat p) = WildPat (hsLPatType p) -- For overlap and exhaustiveness checking- -- purposes, a ~pat is like a wildcard-tidy_pat (BangPat p) = tidy_pat (unLoc p)-tidy_pat (AsPat _ p) = tidy_pat (unLoc p)-tidy_pat (SigPatOut p _) = tidy_pat (unLoc p)-tidy_pat (CoPat _ pat _) = tidy_pat pat---- These two are might_fail patterns, so we map them to--- WildPats. The might_fail_pat stuff arranges that the--- guard says "this equation might fall through".-tidy_pat (NPlusKPat id _ _ _) = WildPat (idType (unLoc id))-tidy_pat (ViewPat _ _ ty) = WildPat ty-tidy_pat (ListPat _ _ (Just (ty,_))) = WildPat ty-tidy_pat (ConPatOut { pat_con = L _ (PatSynCon syn), pat_arg_tys = tys })- = WildPat (patSynInstResTy syn tys)--tidy_pat pat@(ConPatOut { pat_con = L _ con, pat_args = ps })- = pat { pat_args = tidy_con con ps }--tidy_pat (ListPat ps ty Nothing)- = unLoc $ foldr (\ x y -> mkPrefixConPat consDataCon [x,y] [ty])- (mkNilPat ty)- (map tidy_lpat ps)---- introduce fake parallel array constructors to be able to handle parallel--- arrays with the existing machinery for constructor pattern----tidy_pat (PArrPat ps ty)- = unLoc $ mkPrefixConPat (parrFakeCon (length ps))- (map tidy_lpat ps)- [ty]--tidy_pat (TuplePat ps boxity tys)- = unLoc $ mkPrefixConPat (tupleCon (boxityNormalTupleSort boxity) arity)- (map tidy_lpat ps) tys- where- arity = length ps--tidy_pat (NPat lit mb_neg eq) = tidyNPat tidy_lit_pat lit mb_neg eq-tidy_pat (LitPat lit) = tidy_lit_pat lit--tidy_pat (ConPatIn {}) = panic "Check.tidy_pat: ConPatIn"-tidy_pat (SplicePat {}) = panic "Check.tidy_pat: SplicePat"-tidy_pat (QuasiQuotePat {}) = panic "Check.tidy_pat: QuasiQuotePat"-tidy_pat (SigPatIn {}) = panic "Check.tidy_pat: SigPatIn"--tidy_lit_pat :: HsLit -> Pat Id--- Unpack string patterns fully, so we can see when they--- overlap with each other, or even explicit lists of Chars.-tidy_lit_pat lit- | HsString s <- lit- = unLoc $ foldr (\c pat -> mkPrefixConPat consDataCon [mkCharLitPat c, pat] [charTy])- (mkPrefixConPat nilDataCon [] [charTy]) (unpackFS s)- | otherwise- = tidyLitPat lit--------------------tidy_con :: ConLike -> HsConPatDetails Id -> HsConPatDetails Id-tidy_con _ (PrefixCon ps) = PrefixCon (map tidy_lpat ps)-tidy_con _ (InfixCon p1 p2) = PrefixCon [tidy_lpat p1, tidy_lpat p2]-tidy_con con (RecCon (HsRecFields fs _))- | null fs = PrefixCon (replicate arity nlWildPat)- -- Special case for null patterns; maybe not a record at all- | otherwise = PrefixCon (map (tidy_lpat.snd) all_pats)- where- arity = case con of- RealDataCon dcon -> dataConSourceArity dcon- PatSynCon psyn -> patSynArity psyn-- -- pad out all the missing fields with WildPats.- field_pats = case con of- RealDataCon dc -> map (\ f -> (f, nlWildPat)) (dataConFieldLabels dc)- PatSynCon{} -> panic "Check.tidy_con: pattern synonym with record syntax"- all_pats = foldr (\(HsRecField id p _) acc -> insertNm (getName (unLoc id)) p acc)- field_pats fs-- insertNm nm p [] = [(nm,p)]- insertNm nm p (x@(n,_):xs)- | nm == n = (nm,p):xs- | otherwise = x : insertNm nm p xs-\end{code}
− src/Language/Haskell/Liquid/Desugar/Coverage.lhs
@@ -1,1240 +0,0 @@-%-% (c) Galois, 2006-% (c) University of Glasgow, 2007-%-\begin{code}-module Language.Haskell.Liquid.Desugar.Coverage (addTicksToBinds, hpcInitCode) where--import Type-import HsSyn-import Module-import Outputable-import DynFlags-import Control.Monad-import SrcLoc-import ErrUtils-import NameSet hiding (FreeVars)-import Name-import Bag-import CostCentre-import CoreSyn-import Id-import VarSet-import Data.List-import FastString-import HscTypes-import TyCon-import Unique-import BasicTypes-import MonadUtils-import Maybes-import CLabel-import Util--import Data.Array-import Data.Time-import System.Directory--import Trace.Hpc.Mix-import Trace.Hpc.Util--import BreakArray-import Data.Map (Map)-import qualified Data.Map as Map-\end{code}---%************************************************************************-%* *-%* The main function: addTicksToBinds-%* *-%************************************************************************--\begin{code}-addTicksToBinds- :: DynFlags- -> Module- -> ModLocation -- ... off the current module- -> NameSet -- Exported Ids. When we call addTicksToBinds,- -- isExportedId doesn't work yet (the desugarer- -- hasn't set it), so we have to work from this set.- -> [TyCon] -- Type constructor in this module- -> LHsBinds Id- -> IO (LHsBinds Id, HpcInfo, ModBreaks)--addTicksToBinds dflags mod mod_loc exports tyCons binds =-- case ml_hs_file mod_loc of- Nothing -> return (binds, emptyHpcInfo False, emptyModBreaks)- Just orig_file -> do-- if "boot" `isSuffixOf` orig_file- then return (binds, emptyHpcInfo False, emptyModBreaks)- else do-- let orig_file2 = guessSourceFile binds orig_file-- (binds1,_,st)- = unTM (addTickLHsBinds binds)- (TTE- { fileName = mkFastString orig_file2- , declPath = []- , tte_dflags = dflags- , exports = exports- , inlines = emptyVarSet- , inScope = emptyVarSet- , blackList = Map.fromList- [ (getSrcSpan (tyConName tyCon),())- | tyCon <- tyCons ]- , density = mkDensity dflags- , this_mod = mod- , tickishType = case hscTarget dflags of- HscInterpreted -> Breakpoints- _ | gopt Opt_Hpc dflags -> HpcTicks- | gopt Opt_SccProfilingOn dflags- -> ProfNotes- | otherwise -> error "addTicksToBinds: No way to annotate!"- })- (TT- { tickBoxCount = 0- , mixEntries = []- })-- let entries = reverse $ mixEntries st-- let count = tickBoxCount st- hashNo <- writeMixEntries dflags mod count entries orig_file2- modBreaks <- mkModBreaks dflags count entries-- when (dopt Opt_D_dump_ticked dflags) $- log_action dflags dflags SevDump noSrcSpan defaultDumpStyle- (pprLHsBinds binds1)-- return (binds1, HpcInfo count hashNo, modBreaks)---guessSourceFile :: LHsBinds Id -> FilePath -> FilePath-guessSourceFile binds orig_file =- -- Try look for a file generated from a .hsc file to a- -- .hs file, by peeking ahead.- let top_pos = catMaybes $ foldrBag (\ (L pos _) rest ->- srcSpanFileName_maybe pos : rest) [] binds- in- case top_pos of- (file_name:_) | ".hsc" `isSuffixOf` unpackFS file_name- -> unpackFS file_name- _ -> orig_file---mkModBreaks :: DynFlags -> Int -> [MixEntry_] -> IO ModBreaks-mkModBreaks dflags count entries = do- breakArray <- newBreakArray dflags $ length entries- let- locsTicks = listArray (0,count-1) [ span | (span,_,_,_) <- entries ]- varsTicks = listArray (0,count-1) [ vars | (_,_,vars,_) <- entries ]- declsTicks= listArray (0,count-1) [ decls | (_,decls,_,_) <- entries ]- modBreaks = emptyModBreaks- { modBreaks_flags = breakArray- , modBreaks_locs = locsTicks- , modBreaks_vars = varsTicks- , modBreaks_decls = declsTicks- }- --- return modBreaks---writeMixEntries :: DynFlags -> Module -> Int -> [MixEntry_] -> FilePath -> IO Int-writeMixEntries dflags mod count entries filename- | not (gopt Opt_Hpc dflags) = return 0- | otherwise = do- let- hpc_dir = hpcDir dflags- mod_name = moduleNameString (moduleName mod)-- hpc_mod_dir- | modulePackageId mod == mainPackageId = hpc_dir- | otherwise = hpc_dir ++ "/" ++ packageIdString (modulePackageId mod)-- tabStop = 8 -- <tab> counts as a normal char in GHC's location ranges.-- createDirectoryIfMissing True hpc_mod_dir- modTime <- getModificationUTCTime filename- let entries' = [ (hpcPos, box)- | (span,_,_,box) <- entries, hpcPos <- [mkHpcPos span] ]- when (length entries' /= count) $ do- panic "the number of .mix entries are inconsistent"- let hashNo = mixHash filename modTime tabStop entries'- mixCreate hpc_mod_dir mod_name- $ Mix filename modTime (toHash hashNo) tabStop entries'- return hashNo----- -------------------------------------------------------------------------------- TickDensity: where to insert ticks--data TickDensity- = TickForCoverage -- for Hpc- | TickForBreakPoints -- for GHCi- | TickAllFunctions -- for -prof-auto-all- | TickTopFunctions -- for -prof-auto-top- | TickExportedFunctions -- for -prof-auto-exported- | TickCallSites -- for stack tracing- deriving Eq--mkDensity :: DynFlags -> TickDensity-mkDensity dflags- | gopt Opt_Hpc dflags = TickForCoverage- | HscInterpreted <- hscTarget dflags = TickForBreakPoints- | ProfAutoAll <- profAuto dflags = TickAllFunctions- | ProfAutoTop <- profAuto dflags = TickTopFunctions- | ProfAutoExports <- profAuto dflags = TickExportedFunctions- | ProfAutoCalls <- profAuto dflags = TickCallSites- | otherwise = panic "desnity"- -- ToDo: -fhpc is taking priority over -fprof-auto here. It seems- -- that coverage works perfectly well with profiling, but you don't- -- get any auto-generated SCCs. It would make perfect sense to- -- allow both of them, and indeed to combine some of the other flags- -- (-fprof-auto-calls -fprof-auto-top, for example)---- | Decide whether to add a tick to a binding or not.-shouldTickBind :: TickDensity- -> Bool -- top level?- -> Bool -- exported?- -> Bool -- simple pat bind?- -> Bool -- INLINE pragma?- -> Bool--shouldTickBind density top_lev exported simple_pat inline- = case density of- TickForBreakPoints -> not simple_pat- -- we never add breakpoints to simple pattern bindings- -- (there's always a tick on the rhs anyway).- TickAllFunctions -> not inline- TickTopFunctions -> top_lev && not inline- TickExportedFunctions -> exported && not inline- TickForCoverage -> True- TickCallSites -> False--shouldTickPatBind :: TickDensity -> Bool -> Bool-shouldTickPatBind density top_lev- = case density of- TickForBreakPoints -> False- TickAllFunctions -> True- TickTopFunctions -> top_lev- TickExportedFunctions -> False- TickForCoverage -> False- TickCallSites -> False---- -------------------------------------------------------------------------------- Adding ticks to bindings--addTickLHsBinds :: LHsBinds Id -> TM (LHsBinds Id)-addTickLHsBinds = mapBagM addTickLHsBind--addTickLHsBind :: LHsBind Id -> TM (LHsBind Id)-addTickLHsBind (L pos bind@(AbsBinds { abs_binds = binds,- abs_exports = abs_exports })) = do- withEnv add_exports $ do- withEnv add_inlines $ do- binds' <- addTickLHsBinds binds- return $ L pos $ bind { abs_binds = binds' }- where- -- in AbsBinds, the Id on each binding is not the actual top-level- -- Id that we are defining, they are related by the abs_exports- -- field of AbsBinds. So if we're doing TickExportedFunctions we need- -- to add the local Ids to the set of exported Names so that we know to- -- tick the right bindings.- add_exports env =- env{ exports = exports env `addListToNameSet`- [ idName mid- | ABE{ abe_poly = pid, abe_mono = mid } <- abs_exports- , idName pid `elemNameSet` (exports env) ] }-- add_inlines env =- env{ inlines = inlines env `extendVarSetList`- [ mid- | ABE{ abe_poly = pid, abe_mono = mid } <- abs_exports- , isAnyInlinePragma (idInlinePragma pid) ] }---addTickLHsBind (L pos (funBind@(FunBind { fun_id = (L _ id) }))) = do- env <- getEnv- let dflags = tte_dflags env- let name = getOccString id- decl_path <- getPathEntry- density <- getDensity-- inline_ids <- liftM inlines getEnv- let inline = isAnyInlinePragma (idInlinePragma id)- || id `elemVarSet` inline_ids-- -- See Note [inline sccs]- if inline && gopt Opt_SccProfilingOn dflags then return (L pos funBind) else do-- (fvs, mg@(MG { mg_alts = matches' })) <-- getFreeVars $- addPathEntry name $- addTickMatchGroup False (fun_matches funBind)-- blackListed <- isBlackListed pos- exported_names <- liftM exports getEnv-- -- We don't want to generate code for blacklisted positions- -- We don't want redundant ticks on simple pattern bindings- -- We don't want to tick non-exported bindings in TickExportedFunctions- let simple = isSimplePatBind funBind- toplev = null decl_path- exported = idName id `elemNameSet` exported_names-- tick <- if not blackListed &&- shouldTickBind density toplev exported simple inline- then- bindTick density name pos fvs- else- return Nothing-- return $ L pos $ funBind { fun_matches = mg { mg_alts = matches' }- , fun_tick = tick }-- where- -- a binding is a simple pattern binding if it is a funbind with zero patterns- isSimplePatBind :: HsBind a -> Bool- isSimplePatBind funBind = matchGroupArity (fun_matches funBind) == 0---- TODO: Revisit this-addTickLHsBind (L pos (pat@(PatBind { pat_lhs = lhs, pat_rhs = rhs }))) = do- let name = "(...)"- (fvs, rhs') <- getFreeVars $ addPathEntry name $ addTickGRHSs False False rhs-- density <- getDensity- decl_path <- getPathEntry- let top_lev = null decl_path- let add_ticks = shouldTickPatBind density top_lev-- tickish <- if add_ticks- then bindTick density name pos fvs- else return Nothing-- let patvars = map getOccString (collectPatBinders lhs)- patvar_ticks <- if add_ticks- then mapM (\v -> bindTick density v pos fvs) patvars- else return []-- return $ L pos $ pat { pat_rhs = rhs',- pat_ticks = (tickish, patvar_ticks)}---- Only internal stuff, not from source, uses VarBind, so we ignore it.-addTickLHsBind var_bind@(L _ (VarBind {})) = return var_bind-addTickLHsBind patsyn_bind@(L _ (PatSynBind {})) = return patsyn_bind---bindTick :: TickDensity -> String -> SrcSpan -> FreeVars -> TM (Maybe (Tickish Id))-bindTick density name pos fvs = do- decl_path <- getPathEntry- let- toplev = null decl_path- count_entries = toplev || density == TickAllFunctions- top_only = density /= TickAllFunctions- box_label = if toplev then TopLevelBox [name]- else LocalBox (decl_path ++ [name])- --- allocATickBox box_label count_entries top_only pos fvs----- Note [inline sccs]------ It should be reasonable to add ticks to INLINE functions; however--- currently this tickles a bug later on because the SCCfinal pass--- does not look inside unfoldings to find CostCentres. It would be--- difficult to fix that, because SCCfinal currently works on STG and--- not Core (and since it also generates CostCentres for CAFs,--- changing this would be difficult too).------ Another reason not to add ticks to INLINE functions is that this--- sometimes handy for avoiding adding a tick to a particular function--- (see #6131)------ So for now we do not add any ticks to INLINE functions at all.---- -------------------------------------------------------------------------------- Decorate an LHsExpr with ticks---- selectively add ticks to interesting expressions-addTickLHsExpr :: LHsExpr Id -> TM (LHsExpr Id)-addTickLHsExpr e@(L pos e0) = do- d <- getDensity- case d of- TickForBreakPoints | isGoodBreakExpr e0 -> tick_it- TickForCoverage -> tick_it- TickCallSites | isCallSite e0 -> tick_it- _other -> dont_tick_it- where- tick_it = allocTickBox (ExpBox False) False False pos $ addTickHsExpr e0- dont_tick_it = addTickLHsExprNever e---- Add a tick to an expression which is the RHS of an equation or a binding.--- We always consider these to be breakpoints, unless the expression is a 'let'--- (because the body will definitely have a tick somewhere). ToDo: perhaps--- we should treat 'case' and 'if' the same way?-addTickLHsExprRHS :: LHsExpr Id -> TM (LHsExpr Id)-addTickLHsExprRHS e@(L pos e0) = do- d <- getDensity- case d of- TickForBreakPoints | HsLet{} <- e0 -> dont_tick_it- | otherwise -> tick_it- TickForCoverage -> tick_it- TickCallSites | isCallSite e0 -> tick_it- _other -> dont_tick_it- where- tick_it = allocTickBox (ExpBox False) False False pos $ addTickHsExpr e0- dont_tick_it = addTickLHsExprNever e---- The inner expression of an evaluation context:--- let binds in [], ( [] )--- we never tick these if we're doing HPC, but otherwise--- we treat it like an ordinary expression.-addTickLHsExprEvalInner :: LHsExpr Id -> TM (LHsExpr Id)-addTickLHsExprEvalInner e = do- d <- getDensity- case d of- TickForCoverage -> addTickLHsExprNever e- _otherwise -> addTickLHsExpr e---- | A let body is treated differently from addTickLHsExprEvalInner--- above with TickForBreakPoints, because for breakpoints we always--- want to tick the body, even if it is not a redex. See test--- break012. This gives the user the opportunity to inspect the--- values of the let-bound variables.-addTickLHsExprLetBody :: LHsExpr Id -> TM (LHsExpr Id)-addTickLHsExprLetBody e@(L pos e0) = do- d <- getDensity- case d of- TickForBreakPoints | HsLet{} <- e0 -> dont_tick_it- | otherwise -> tick_it- _other -> addTickLHsExprEvalInner e- where- tick_it = allocTickBox (ExpBox False) False False pos $ addTickHsExpr e0- dont_tick_it = addTickLHsExprNever e---- version of addTick that does not actually add a tick,--- because the scope of this tick is completely subsumed by--- another.-addTickLHsExprNever :: LHsExpr Id -> TM (LHsExpr Id)-addTickLHsExprNever (L pos e0) = do- e1 <- addTickHsExpr e0- return $ L pos e1---- general heuristic: expressions which do not denote values are good break points-isGoodBreakExpr :: HsExpr Id -> Bool-isGoodBreakExpr (HsApp {}) = True-isGoodBreakExpr (OpApp {}) = True-isGoodBreakExpr (NegApp {}) = True-isGoodBreakExpr (HsIf {}) = True-isGoodBreakExpr (HsMultiIf {}) = True-isGoodBreakExpr (HsCase {}) = True-isGoodBreakExpr (RecordCon {}) = True-isGoodBreakExpr (RecordUpd {}) = True-isGoodBreakExpr (ArithSeq {}) = True-isGoodBreakExpr (PArrSeq {}) = True-isGoodBreakExpr _other = False--isCallSite :: HsExpr Id -> Bool-isCallSite HsApp{} = True-isCallSite OpApp{} = True-isCallSite _ = False--addTickLHsExprOptAlt :: Bool -> LHsExpr Id -> TM (LHsExpr Id)-addTickLHsExprOptAlt oneOfMany (L pos e0)- = ifDensity TickForCoverage- (allocTickBox (ExpBox oneOfMany) False False pos $ addTickHsExpr e0)- (addTickLHsExpr (L pos e0))--addBinTickLHsExpr :: (Bool -> BoxLabel) -> LHsExpr Id -> TM (LHsExpr Id)-addBinTickLHsExpr boxLabel (L pos e0)- = ifDensity TickForCoverage- (allocBinTickBox boxLabel pos $ addTickHsExpr e0)- (addTickLHsExpr (L pos e0))----- -------------------------------------------------------------------------------- Decoarate an HsExpr with ticks--addTickHsExpr :: HsExpr Id -> TM (HsExpr Id)-addTickHsExpr e@(HsVar id) = do freeVar id; return e-addTickHsExpr e@(HsIPVar _) = return e-addTickHsExpr e@(HsOverLit _) = return e-addTickHsExpr e@(HsLit _) = return e-addTickHsExpr (HsLam matchgroup) =- liftM HsLam (addTickMatchGroup True matchgroup)-addTickHsExpr (HsLamCase ty mgs) =- liftM (HsLamCase ty) (addTickMatchGroup True mgs)-addTickHsExpr (HsApp e1 e2) =- liftM2 HsApp (addTickLHsExprNever e1) (addTickLHsExpr e2)-addTickHsExpr (OpApp e1 e2 fix e3) =- liftM4 OpApp- (addTickLHsExpr e1)- (addTickLHsExprNever e2)- (return fix)- (addTickLHsExpr e3)-addTickHsExpr (NegApp e neg) =- liftM2 NegApp- (addTickLHsExpr e)- (addTickSyntaxExpr hpcSrcSpan neg)-addTickHsExpr (HsPar e) =- liftM HsPar (addTickLHsExprEvalInner e)-addTickHsExpr (SectionL e1 e2) =- liftM2 SectionL- (addTickLHsExpr e1)- (addTickLHsExprNever e2)-addTickHsExpr (SectionR e1 e2) =- liftM2 SectionR- (addTickLHsExprNever e1)- (addTickLHsExpr e2)-addTickHsExpr (ExplicitTuple es boxity) =- liftM2 ExplicitTuple- (mapM addTickTupArg es)- (return boxity)-addTickHsExpr (HsCase e mgs) =- liftM2 HsCase- (addTickLHsExpr e) -- not an EvalInner; e might not necessarily- -- be evaluated.- (addTickMatchGroup False mgs)-addTickHsExpr (HsIf cnd e1 e2 e3) =- liftM3 (HsIf cnd)- (addBinTickLHsExpr (BinBox CondBinBox) e1)- (addTickLHsExprOptAlt True e2)- (addTickLHsExprOptAlt True e3)-addTickHsExpr (HsMultiIf ty alts)- = do { let isOneOfMany = case alts of [_] -> False; _ -> True- ; alts' <- mapM (liftL $ addTickGRHS isOneOfMany False) alts- ; return $ HsMultiIf ty alts' }-addTickHsExpr (HsLet binds e) =- bindLocals (collectLocalBinders binds) $- liftM2 HsLet- (addTickHsLocalBinds binds) -- to think about: !patterns.- (addTickLHsExprLetBody e)-addTickHsExpr (HsDo cxt stmts srcloc)- = do { (stmts', _) <- addTickLStmts' forQual stmts (return ())- ; return (HsDo cxt stmts' srcloc) }- where- forQual = case cxt of- ListComp -> Just $ BinBox QualBinBox- _ -> Nothing-addTickHsExpr (ExplicitList ty wit es) =- liftM3 ExplicitList- (return ty)- (addTickWit wit)- (mapM (addTickLHsExpr) es) - where addTickWit Nothing = return Nothing- addTickWit (Just fln) = do fln' <- addTickHsExpr fln- return (Just fln')-addTickHsExpr (ExplicitPArr ty es) =- liftM2 ExplicitPArr- (return ty)- (mapM (addTickLHsExpr) es)-addTickHsExpr (RecordCon id ty rec_binds) =- liftM3 RecordCon- (return id)- (return ty)- (addTickHsRecordBinds rec_binds)-addTickHsExpr (RecordUpd e rec_binds cons tys1 tys2) =- liftM5 RecordUpd- (addTickLHsExpr e)- (addTickHsRecordBinds rec_binds)- (return cons) (return tys1) (return tys2)--addTickHsExpr (ExprWithTySigOut e ty) =- liftM2 ExprWithTySigOut- (addTickLHsExprNever e) -- No need to tick the inner expression- -- for expressions with signatures- (return ty)-addTickHsExpr (ArithSeq ty wit arith_seq) =- liftM3 ArithSeq- (return ty)- (addTickWit wit)- (addTickArithSeqInfo arith_seq)- where addTickWit Nothing = return Nothing- addTickWit (Just fl) = do fl' <- addTickHsExpr fl- return (Just fl')-addTickHsExpr (HsTickPragma _ (L pos e0)) = do- e2 <- allocTickBox (ExpBox False) False False pos $- addTickHsExpr e0- return $ unLoc e2-addTickHsExpr (PArrSeq ty arith_seq) =- liftM2 PArrSeq- (return ty)- (addTickArithSeqInfo arith_seq)-addTickHsExpr (HsSCC nm e) =- liftM2 HsSCC- (return nm)- (addTickLHsExpr e)-addTickHsExpr (HsCoreAnn nm e) =- liftM2 HsCoreAnn- (return nm)- (addTickLHsExpr e)-addTickHsExpr e@(HsBracket {}) = return e-addTickHsExpr e@(HsTcBracketOut {}) = return e-addTickHsExpr e@(HsRnBracketOut {}) = return e-addTickHsExpr e@(HsSpliceE {}) = return e-addTickHsExpr (HsProc pat cmdtop) =- liftM2 HsProc- (addTickLPat pat)- (liftL (addTickHsCmdTop) cmdtop)-addTickHsExpr (HsWrap w e) =- liftM2 HsWrap- (return w)- (addTickHsExpr e) -- explicitly no tick on inside--addTickHsExpr e@(HsType _) = return e-addTickHsExpr (HsUnboundVar {}) = panic "addTickHsExpr.HsUnboundVar"---- Others dhould never happen in expression content.-addTickHsExpr e = pprPanic "addTickHsExpr" (ppr e)--addTickTupArg :: HsTupArg Id -> TM (HsTupArg Id)-addTickTupArg (Present e) = do { e' <- addTickLHsExpr e; return (Present e') }-addTickTupArg (Missing ty) = return (Missing ty)--addTickMatchGroup :: Bool{-is lambda-} -> MatchGroup Id (LHsExpr Id) -> TM (MatchGroup Id (LHsExpr Id))-addTickMatchGroup is_lam mg@(MG { mg_alts = matches }) = do- let isOneOfMany = matchesOneOfMany matches- matches' <- mapM (liftL (addTickMatch isOneOfMany is_lam)) matches- return $ mg { mg_alts = matches' }--addTickMatch :: Bool -> Bool -> Match Id (LHsExpr Id) -> TM (Match Id (LHsExpr Id))-addTickMatch isOneOfMany isLambda (Match pats opSig gRHSs) =- bindLocals (collectPatsBinders pats) $ do- gRHSs' <- addTickGRHSs isOneOfMany isLambda gRHSs- return $ Match pats opSig gRHSs'--addTickGRHSs :: Bool -> Bool -> GRHSs Id (LHsExpr Id) -> TM (GRHSs Id (LHsExpr Id))-addTickGRHSs isOneOfMany isLambda (GRHSs guarded local_binds) = do- bindLocals binders $ do- local_binds' <- addTickHsLocalBinds local_binds- guarded' <- mapM (liftL (addTickGRHS isOneOfMany isLambda)) guarded- return $ GRHSs guarded' local_binds'- where- binders = collectLocalBinders local_binds--addTickGRHS :: Bool -> Bool -> GRHS Id (LHsExpr Id) -> TM (GRHS Id (LHsExpr Id))-addTickGRHS isOneOfMany isLambda (GRHS stmts expr) = do- (stmts',expr') <- addTickLStmts' (Just $ BinBox $ GuardBinBox) stmts- (addTickGRHSBody isOneOfMany isLambda expr)- return $ GRHS stmts' expr'--addTickGRHSBody :: Bool -> Bool -> LHsExpr Id -> TM (LHsExpr Id)-addTickGRHSBody isOneOfMany isLambda expr@(L pos e0) = do- d <- getDensity- case d of- TickForCoverage -> addTickLHsExprOptAlt isOneOfMany expr- TickAllFunctions | isLambda ->- addPathEntry "\\" $- allocTickBox (ExpBox False) True{-count-} False{-not top-} pos $- addTickHsExpr e0- _otherwise ->- addTickLHsExprRHS expr--addTickLStmts :: (Maybe (Bool -> BoxLabel)) -> [ExprLStmt Id] -> TM [ExprLStmt Id]-addTickLStmts isGuard stmts = do- (stmts, _) <- addTickLStmts' isGuard stmts (return ())- return stmts--addTickLStmts' :: (Maybe (Bool -> BoxLabel)) -> [ExprLStmt Id] -> TM a- -> TM ([ExprLStmt Id], a)-addTickLStmts' isGuard lstmts res- = bindLocals (collectLStmtsBinders lstmts) $- do { lstmts' <- mapM (liftL (addTickStmt isGuard)) lstmts- ; a <- res- ; return (lstmts', a) }--addTickStmt :: (Maybe (Bool -> BoxLabel)) -> Stmt Id (LHsExpr Id) -> TM (Stmt Id (LHsExpr Id))-addTickStmt _isGuard (LastStmt e ret) = do- liftM2 LastStmt- (addTickLHsExpr e)- (addTickSyntaxExpr hpcSrcSpan ret)-addTickStmt _isGuard (BindStmt pat e bind fail) = do- liftM4 BindStmt- (addTickLPat pat)- (addTickLHsExprRHS e)- (addTickSyntaxExpr hpcSrcSpan bind)- (addTickSyntaxExpr hpcSrcSpan fail)-addTickStmt isGuard (BodyStmt e bind' guard' ty) = do- liftM4 BodyStmt- (addTick isGuard e)- (addTickSyntaxExpr hpcSrcSpan bind')- (addTickSyntaxExpr hpcSrcSpan guard')- (return ty)-addTickStmt _isGuard (LetStmt binds) = do- liftM LetStmt- (addTickHsLocalBinds binds)-addTickStmt isGuard (ParStmt pairs mzipExpr bindExpr) = do- liftM3 ParStmt- (mapM (addTickStmtAndBinders isGuard) pairs)- (addTickSyntaxExpr hpcSrcSpan mzipExpr)- (addTickSyntaxExpr hpcSrcSpan bindExpr)--addTickStmt isGuard stmt@(TransStmt { trS_stmts = stmts- , trS_by = by, trS_using = using- , trS_ret = returnExpr, trS_bind = bindExpr- , trS_fmap = liftMExpr }) = do- t_s <- addTickLStmts isGuard stmts- t_y <- fmapMaybeM addTickLHsExprRHS by- t_u <- addTickLHsExprRHS using- t_f <- addTickSyntaxExpr hpcSrcSpan returnExpr- t_b <- addTickSyntaxExpr hpcSrcSpan bindExpr- t_m <- addTickSyntaxExpr hpcSrcSpan liftMExpr- return $ stmt { trS_stmts = t_s, trS_by = t_y, trS_using = t_u- , trS_ret = t_f, trS_bind = t_b, trS_fmap = t_m }--addTickStmt isGuard stmt@(RecStmt {})- = do { stmts' <- addTickLStmts isGuard (recS_stmts stmt)- ; ret' <- addTickSyntaxExpr hpcSrcSpan (recS_ret_fn stmt)- ; mfix' <- addTickSyntaxExpr hpcSrcSpan (recS_mfix_fn stmt)- ; bind' <- addTickSyntaxExpr hpcSrcSpan (recS_bind_fn stmt)- ; return (stmt { recS_stmts = stmts', recS_ret_fn = ret'- , recS_mfix_fn = mfix', recS_bind_fn = bind' }) }--addTick :: Maybe (Bool -> BoxLabel) -> LHsExpr Id -> TM (LHsExpr Id)-addTick isGuard e | Just fn <- isGuard = addBinTickLHsExpr fn e- | otherwise = addTickLHsExprRHS e--addTickStmtAndBinders :: Maybe (Bool -> BoxLabel) -> ParStmtBlock Id Id- -> TM (ParStmtBlock Id Id)-addTickStmtAndBinders isGuard (ParStmtBlock stmts ids returnExpr) =- liftM3 ParStmtBlock- (addTickLStmts isGuard stmts)- (return ids)- (addTickSyntaxExpr hpcSrcSpan returnExpr)--addTickHsLocalBinds :: HsLocalBinds Id -> TM (HsLocalBinds Id)-addTickHsLocalBinds (HsValBinds binds) =- liftM HsValBinds- (addTickHsValBinds binds)-addTickHsLocalBinds (HsIPBinds binds) =- liftM HsIPBinds- (addTickHsIPBinds binds)-addTickHsLocalBinds (EmptyLocalBinds) = return EmptyLocalBinds--addTickHsValBinds :: HsValBindsLR Id a -> TM (HsValBindsLR Id b)-addTickHsValBinds (ValBindsOut binds sigs) =- liftM2 ValBindsOut- (mapM (\ (rec,binds') ->- liftM2 (,)- (return rec)- (addTickLHsBinds binds'))- binds)- (return sigs)-addTickHsValBinds _ = panic "addTickHsValBinds"--addTickHsIPBinds :: HsIPBinds Id -> TM (HsIPBinds Id)-addTickHsIPBinds (IPBinds ipbinds dictbinds) =- liftM2 IPBinds- (mapM (liftL (addTickIPBind)) ipbinds)- (return dictbinds)--addTickIPBind :: IPBind Id -> TM (IPBind Id)-addTickIPBind (IPBind nm e) =- liftM2 IPBind- (return nm)- (addTickLHsExpr e)---- There is no location here, so we might need to use a context location??-addTickSyntaxExpr :: SrcSpan -> SyntaxExpr Id -> TM (SyntaxExpr Id)-addTickSyntaxExpr pos x = do- L _ x' <- addTickLHsExpr (L pos x)- return $ x'--- we do not walk into patterns.-addTickLPat :: LPat Id -> TM (LPat Id)-addTickLPat pat = return pat--addTickHsCmdTop :: HsCmdTop Id -> TM (HsCmdTop Id)-addTickHsCmdTop (HsCmdTop cmd tys ty syntaxtable) =- liftM4 HsCmdTop- (addTickLHsCmd cmd)- (return tys)- (return ty)- (return syntaxtable)--addTickLHsCmd :: LHsCmd Id -> TM (LHsCmd Id)-addTickLHsCmd (L pos c0) = do- c1 <- addTickHsCmd c0- return $ L pos c1--addTickHsCmd :: HsCmd Id -> TM (HsCmd Id)-addTickHsCmd (HsCmdLam matchgroup) =- liftM HsCmdLam (addTickCmdMatchGroup matchgroup)-addTickHsCmd (HsCmdApp c e) =- liftM2 HsCmdApp (addTickLHsCmd c) (addTickLHsExpr e)-{--addTickHsCmd (OpApp e1 c2 fix c3) =- liftM4 OpApp- (addTickLHsExpr e1)- (addTickLHsCmd c2)- (return fix)- (addTickLHsCmd c3)--}-addTickHsCmd (HsCmdPar e) = liftM HsCmdPar (addTickLHsCmd e)-addTickHsCmd (HsCmdCase e mgs) =- liftM2 HsCmdCase- (addTickLHsExpr e)- (addTickCmdMatchGroup mgs)-addTickHsCmd (HsCmdIf cnd e1 c2 c3) =- liftM3 (HsCmdIf cnd)- (addBinTickLHsExpr (BinBox CondBinBox) e1)- (addTickLHsCmd c2)- (addTickLHsCmd c3)-addTickHsCmd (HsCmdLet binds c) =- bindLocals (collectLocalBinders binds) $- liftM2 HsCmdLet- (addTickHsLocalBinds binds) -- to think about: !patterns.- (addTickLHsCmd c)-addTickHsCmd (HsCmdDo stmts srcloc)- = do { (stmts', _) <- addTickLCmdStmts' stmts (return ())- ; return (HsCmdDo stmts' srcloc) }--addTickHsCmd (HsCmdArrApp e1 e2 ty1 arr_ty lr) =- liftM5 HsCmdArrApp- (addTickLHsExpr e1)- (addTickLHsExpr e2)- (return ty1)- (return arr_ty)- (return lr)-addTickHsCmd (HsCmdArrForm e fix cmdtop) =- liftM3 HsCmdArrForm- (addTickLHsExpr e)- (return fix)- (mapM (liftL (addTickHsCmdTop)) cmdtop)--addTickHsCmd (HsCmdCast co cmd) - = liftM2 HsCmdCast (return co) (addTickHsCmd cmd)---- Others should never happen in a command context.---addTickHsCmd e = pprPanic "addTickHsCmd" (ppr e)--addTickCmdMatchGroup :: MatchGroup Id (LHsCmd Id) -> TM (MatchGroup Id (LHsCmd Id))-addTickCmdMatchGroup mg@(MG { mg_alts = matches }) = do- matches' <- mapM (liftL addTickCmdMatch) matches- return $ mg { mg_alts = matches' }--addTickCmdMatch :: Match Id (LHsCmd Id) -> TM (Match Id (LHsCmd Id))-addTickCmdMatch (Match pats opSig gRHSs) =- bindLocals (collectPatsBinders pats) $ do- gRHSs' <- addTickCmdGRHSs gRHSs- return $ Match pats opSig gRHSs'--addTickCmdGRHSs :: GRHSs Id (LHsCmd Id) -> TM (GRHSs Id (LHsCmd Id))-addTickCmdGRHSs (GRHSs guarded local_binds) = do- bindLocals binders $ do- local_binds' <- addTickHsLocalBinds local_binds- guarded' <- mapM (liftL addTickCmdGRHS) guarded- return $ GRHSs guarded' local_binds'- where- binders = collectLocalBinders local_binds--addTickCmdGRHS :: GRHS Id (LHsCmd Id) -> TM (GRHS Id (LHsCmd Id))--- The *guards* are *not* Cmds, although the body is--- C.f. addTickGRHS for the BinBox stuff-addTickCmdGRHS (GRHS stmts cmd)- = do { (stmts',expr') <- addTickLStmts' (Just $ BinBox $ GuardBinBox)- stmts (addTickLHsCmd cmd)- ; return $ GRHS stmts' expr' }--addTickLCmdStmts :: [LStmt Id (LHsCmd Id)] -> TM [LStmt Id (LHsCmd Id)]-addTickLCmdStmts stmts = do- (stmts, _) <- addTickLCmdStmts' stmts (return ())- return stmts--addTickLCmdStmts' :: [LStmt Id (LHsCmd Id)] -> TM a -> TM ([LStmt Id (LHsCmd Id)], a)-addTickLCmdStmts' lstmts res- = bindLocals binders $ do- lstmts' <- mapM (liftL addTickCmdStmt) lstmts- a <- res- return (lstmts', a)- where- binders = collectLStmtsBinders lstmts--addTickCmdStmt :: Stmt Id (LHsCmd Id) -> TM (Stmt Id (LHsCmd Id))-addTickCmdStmt (BindStmt pat c bind fail) = do- liftM4 BindStmt- (addTickLPat pat)- (addTickLHsCmd c)- (return bind)- (return fail)-addTickCmdStmt (LastStmt c ret) = do- liftM2 LastStmt- (addTickLHsCmd c)- (addTickSyntaxExpr hpcSrcSpan ret)-addTickCmdStmt (BodyStmt c bind' guard' ty) = do- liftM4 BodyStmt- (addTickLHsCmd c)- (addTickSyntaxExpr hpcSrcSpan bind')- (addTickSyntaxExpr hpcSrcSpan guard')- (return ty)-addTickCmdStmt (LetStmt binds) = do- liftM LetStmt- (addTickHsLocalBinds binds)-addTickCmdStmt stmt@(RecStmt {})- = do { stmts' <- addTickLCmdStmts (recS_stmts stmt)- ; ret' <- addTickSyntaxExpr hpcSrcSpan (recS_ret_fn stmt)- ; mfix' <- addTickSyntaxExpr hpcSrcSpan (recS_mfix_fn stmt)- ; bind' <- addTickSyntaxExpr hpcSrcSpan (recS_bind_fn stmt)- ; return (stmt { recS_stmts = stmts', recS_ret_fn = ret'- , recS_mfix_fn = mfix', recS_bind_fn = bind' }) }---- Others should never happen in a command context.-addTickCmdStmt stmt = pprPanic "addTickHsCmd" (ppr stmt)--addTickHsRecordBinds :: HsRecordBinds Id -> TM (HsRecordBinds Id)-addTickHsRecordBinds (HsRecFields fields dd)- = do { fields' <- mapM process fields- ; return (HsRecFields fields' dd) }- where- process (HsRecField ids expr doc)- = do { expr' <- addTickLHsExpr expr- ; return (HsRecField ids expr' doc) }--addTickArithSeqInfo :: ArithSeqInfo Id -> TM (ArithSeqInfo Id)-addTickArithSeqInfo (From e1) =- liftM From- (addTickLHsExpr e1)-addTickArithSeqInfo (FromThen e1 e2) =- liftM2 FromThen- (addTickLHsExpr e1)- (addTickLHsExpr e2)-addTickArithSeqInfo (FromTo e1 e2) =- liftM2 FromTo- (addTickLHsExpr e1)- (addTickLHsExpr e2)-addTickArithSeqInfo (FromThenTo e1 e2 e3) =- liftM3 FromThenTo- (addTickLHsExpr e1)- (addTickLHsExpr e2)- (addTickLHsExpr e3)--liftL :: (Monad m) => (a -> m a) -> Located a -> m (Located a)-liftL f (L loc a) = do- a' <- f a- return $ L loc a'-\end{code}--\begin{code}-data TickTransState = TT { tickBoxCount:: Int- , mixEntries :: [MixEntry_]- }--data TickTransEnv = TTE { fileName :: FastString- , density :: TickDensity- , tte_dflags :: DynFlags- , exports :: NameSet- , inlines :: VarSet- , declPath :: [String]- , inScope :: VarSet- , blackList :: Map SrcSpan ()- , this_mod :: Module- , tickishType :: TickishType- }---- deriving Show--data TickishType = ProfNotes | HpcTicks | Breakpoints----- | Tickishs that only make sense when their source code location--- refers to the current file. This might not always be true due to--- LINE pragmas in the code - which would confuse at least HPC.-tickSameFileOnly :: TickishType -> Bool-tickSameFileOnly HpcTicks = True-tickSameFileOnly _other = False--type FreeVars = OccEnv Id-noFVs :: FreeVars-noFVs = emptyOccEnv---- Note [freevars]--- For breakpoints we want to collect the free variables of an--- expression for pinning on the HsTick. We don't want to collect--- *all* free variables though: in particular there's no point pinning--- on free variables that are will otherwise be in scope at the GHCi--- prompt, which means all top-level bindings. Unfortunately detecting--- top-level bindings isn't easy (collectHsBindsBinders on the top-level--- bindings doesn't do it), so we keep track of a set of "in-scope"--- variables in addition to the free variables, and the former is used--- to filter additions to the latter. This gives us complete control--- over what free variables we track.--data TM a = TM { unTM :: TickTransEnv -> TickTransState -> (a,FreeVars,TickTransState) }- -- a combination of a state monad (TickTransState) and a writer- -- monad (FreeVars).--instance Functor TM where- fmap = liftM--instance Applicative TM where- pure = return- (<*>) = ap--instance Monad TM where- return a = TM $ \ _env st -> (a,noFVs,st)- (TM m) >>= k = TM $ \ env st ->- case m env st of- (r1,fv1,st1) ->- case unTM (k r1) env st1 of- (r2,fv2,st2) ->- (r2, fv1 `plusOccEnv` fv2, st2)---- getState :: TM TickTransState--- getState = TM $ \ env st -> (st, noFVs, st)---- setState :: (TickTransState -> TickTransState) -> TM ()--- setState f = TM $ \ env st -> ((), noFVs, f st)--getEnv :: TM TickTransEnv-getEnv = TM $ \ env st -> (env, noFVs, st)--withEnv :: (TickTransEnv -> TickTransEnv) -> TM a -> TM a-withEnv f (TM m) = TM $ \ env st ->- case m (f env) st of- (a, fvs, st') -> (a, fvs, st')--getDensity :: TM TickDensity-getDensity = TM $ \env st -> (density env, noFVs, st)--ifDensity :: TickDensity -> TM a -> TM a -> TM a-ifDensity d th el = do d0 <- getDensity; if d == d0 then th else el--getFreeVars :: TM a -> TM (FreeVars, a)-getFreeVars (TM m)- = TM $ \ env st -> case m env st of (a, fv, st') -> ((fv,a), fv, st')--freeVar :: Id -> TM ()-freeVar id = TM $ \ env st ->- if id `elemVarSet` inScope env- then ((), unitOccEnv (nameOccName (idName id)) id, st)- else ((), noFVs, st)--addPathEntry :: String -> TM a -> TM a-addPathEntry nm = withEnv (\ env -> env { declPath = declPath env ++ [nm] })--getPathEntry :: TM [String]-getPathEntry = declPath `liftM` getEnv--getFileName :: TM FastString-getFileName = fileName `liftM` getEnv--isGoodSrcSpan' :: SrcSpan -> Bool-isGoodSrcSpan' pos@(RealSrcSpan _) = srcSpanStart pos /= srcSpanEnd pos-isGoodSrcSpan' (UnhelpfulSpan _) = False--isGoodTickSrcSpan :: SrcSpan -> TM Bool-isGoodTickSrcSpan pos = do- file_name <- getFileName- tickish <- tickishType `liftM` getEnv- let need_same_file = tickSameFileOnly tickish- same_file = Just file_name == srcSpanFileName_maybe pos- return (isGoodSrcSpan' pos && (not need_same_file || same_file))--ifGoodTickSrcSpan :: SrcSpan -> TM a -> TM a -> TM a-ifGoodTickSrcSpan pos then_code else_code = do- good <- isGoodTickSrcSpan pos- if good then then_code else else_code--bindLocals :: [Id] -> TM a -> TM a-bindLocals new_ids (TM m)- = TM $ \ env st ->- case m env{ inScope = inScope env `extendVarSetList` new_ids } st of- (r, fv, st') -> (r, fv `delListFromOccEnv` occs, st')- where occs = [ nameOccName (idName id) | id <- new_ids ]--isBlackListed :: SrcSpan -> TM Bool-isBlackListed pos = TM $ \ env st ->- case Map.lookup pos (blackList env) of- Nothing -> (False,noFVs,st)- Just () -> (True,noFVs,st)---- the tick application inherits the source position of its--- expression argument to support nested box allocations-allocTickBox :: BoxLabel -> Bool -> Bool -> SrcSpan -> TM (HsExpr Id)- -> TM (LHsExpr Id)-allocTickBox boxLabel countEntries topOnly pos m =- ifGoodTickSrcSpan pos (do- (fvs, e) <- getFreeVars m- env <- getEnv- tickish <- mkTickish boxLabel countEntries topOnly pos fvs (declPath env)- return (L pos (HsTick tickish (L pos e)))- ) (do- e <- m- return (L pos e)- )---- the tick application inherits the source position of its--- expression argument to support nested box allocations-allocATickBox :: BoxLabel -> Bool -> Bool -> SrcSpan -> FreeVars- -> TM (Maybe (Tickish Id))-allocATickBox boxLabel countEntries topOnly pos fvs =- ifGoodTickSrcSpan pos (do- let- mydecl_path = case boxLabel of- TopLevelBox x -> x- LocalBox xs -> xs- _ -> panic "allocATickBox"- tickish <- mkTickish boxLabel countEntries topOnly pos fvs mydecl_path- return (Just tickish)- ) (return Nothing)---mkTickish :: BoxLabel -> Bool -> Bool -> SrcSpan -> OccEnv Id -> [String]- -> TM (Tickish Id)-mkTickish boxLabel countEntries topOnly pos fvs decl_path =- TM $ \ env st ->- let c = tickBoxCount st- ids = filter (not . isUnLiftedType . idType) $ occEnvElts fvs- -- unlifted types cause two problems here:- -- * we can't bind them at the GHCi prompt- -- (bindLocalsAtBreakpoint already fliters them out),- -- * the simplifier might try to substitute a literal for- -- the Id, and we can't handle that.-- mes = mixEntries st- me = (pos, decl_path, map (nameOccName.idName) ids, boxLabel)-- cc_name | topOnly = head decl_path- | otherwise = concat (intersperse "." decl_path)-- cc = mkUserCC (mkFastString cc_name) (this_mod env) pos (mkCostCentreUnique c)-- dflags = tte_dflags env-- count = countEntries && gopt Opt_ProfCountEntries dflags-- tickish = case tickishType env of- HpcTicks -> HpcTick (this_mod env) c- ProfNotes -> ProfNote cc count True{-scopes-}- Breakpoints -> Breakpoint c ids- in- ( tickish- , fvs- , st {tickBoxCount=c+1,mixEntries=me:mes}- )---allocBinTickBox :: (Bool -> BoxLabel) -> SrcSpan -> TM (HsExpr Id)- -> TM (LHsExpr Id)-allocBinTickBox boxLabel pos m = do- env <- getEnv- case tickishType env of- HpcTicks -> do e <- liftM (L pos) m- ifGoodTickSrcSpan pos- (mkBinTickBoxHpc boxLabel pos e)- (return e)- _other -> allocTickBox (ExpBox False) False False pos m--mkBinTickBoxHpc :: (Bool -> BoxLabel) -> SrcSpan -> LHsExpr Id- -> TM (LHsExpr Id)-mkBinTickBoxHpc boxLabel pos e =- TM $ \ env st ->- let meT = (pos,declPath env, [],boxLabel True)- meF = (pos,declPath env, [],boxLabel False)- meE = (pos,declPath env, [],ExpBox False)- c = tickBoxCount st- mes = mixEntries st- in- ( L pos $ HsTick (HpcTick (this_mod env) c) $ L pos $ HsBinTick (c+1) (c+2) e- -- notice that F and T are reversed,- -- because we are building the list in- -- reverse...- , noFVs- , st {tickBoxCount=c+3 , mixEntries=meF:meT:meE:mes}- )--mkHpcPos :: SrcSpan -> HpcPos-mkHpcPos pos@(RealSrcSpan s)- | isGoodSrcSpan' pos = toHpcPos (srcSpanStartLine s,- srcSpanStartCol s,- srcSpanEndLine s,- srcSpanEndCol s - 1)- -- the end column of a SrcSpan is one- -- greater than the last column of the- -- span (see SrcLoc), whereas HPC- -- expects to the column range to be- -- inclusive, hence we subtract one above.-mkHpcPos _ = panic "bad source span; expected such spans to be filtered out"--hpcSrcSpan :: SrcSpan-hpcSrcSpan = mkGeneralSrcSpan (fsLit "Haskell Program Coverage internals")-\end{code}---\begin{code}-matchesOneOfMany :: [LMatch Id body] -> Bool-matchesOneOfMany lmatches = sum (map matchCount lmatches) > 1- where- matchCount (L _ (Match _pats _ty (GRHSs grhss _binds))) = length grhss-\end{code}---\begin{code}-type MixEntry_ = (SrcSpan, [String], [OccName], BoxLabel)---- For the hash value, we hash everything: the file name,--- the timestamp of the original source file, the tab stop,--- and the mix entries. We cheat, and hash the show'd string.--- This hash only has to be hashed at Mix creation time,--- and is for sanity checking only.--mixHash :: FilePath -> UTCTime -> Int -> [MixEntry] -> Int-mixHash file tm tabstop entries = fromIntegral $ hashString- (show $ Mix file tm 0 tabstop entries)-\end{code}--%************************************************************************-%* *-%* initialisation-%* *-%************************************************************************--Each module compiled with -fhpc declares an initialisation function of-the form `hpc_init_<module>()`, which is emitted into the _stub.c file-and annotated with __attribute__((constructor)) so that it gets-executed at startup time.--The function's purpose is to call hs_hpc_module to register this-module with the RTS, and it looks something like this:--static void hpc_init_Main(void) __attribute__((constructor));-static void hpc_init_Main(void)-{extern StgWord64 _hpc_tickboxes_Main_hpc[];- hs_hpc_module("Main",8,1150288664,_hpc_tickboxes_Main_hpc);}--\begin{code}-hpcInitCode :: Module -> HpcInfo -> SDoc-hpcInitCode _ (NoHpcInfo {}) = empty-hpcInitCode this_mod (HpcInfo tickCount hashNo)- = vcat- [ text "static void hpc_init_" <> ppr this_mod- <> text "(void) __attribute__((constructor));"- , text "static void hpc_init_" <> ppr this_mod <> text "(void)"- , braces (vcat [- ptext (sLit "extern StgWord64 ") <> tickboxes <>- ptext (sLit "[]") <> semi,- ptext (sLit "hs_hpc_module") <>- parens (hcat (punctuate comma [- doubleQuotes full_name_str,- int tickCount, -- really StgWord32- int hashNo, -- really StgWord32- tickboxes- ])) <> semi- ])- ]- where- tickboxes = ppr (mkHpcTicksLabel $ this_mod)-- module_name = hcat (map (text.charToC) $- bytesFS (moduleNameFS (Module.moduleName this_mod)))- package_name = hcat (map (text.charToC) $- bytesFS (packageIdFS (modulePackageId this_mod)))- full_name_str- | modulePackageId this_mod == mainPackageId- = module_name- | otherwise- = package_name <> char '/' <> module_name-\end{code}
− src/Language/Haskell/Liquid/Desugar/Desugar.lhs
@@ -1,440 +0,0 @@-%-% (c) The University of Glasgow 2006-% (c) The GRASP/AQUA Project, Glasgow University, 1992-1998-%--The Desugarer: turning HsSyn into Core.--\begin{code}-module Language.Haskell.Liquid.Desugar.Desugar ( deSugarWithLoc, deSugar, deSugarExpr ) where--import DynFlags-import HscTypes-import HsSyn-import TcRnTypes-import TcRnMonad ( finalSafeMode )-import MkIface-import Id-import Name-import Type-import FamInstEnv-import InstEnv-import Class-import Avail-import PatSyn-import CoreSyn-import CoreSubst-import PprCore-import DsMonad-import Language.Haskell.Liquid.Desugar.DsExpr-import Language.Haskell.Liquid.Desugar.DsBinds-import Language.Haskell.Liquid.Desugar.DsForeign-import Module-import NameSet-import NameEnv-import Rules-import BasicTypes ( Activation(.. ) )-import CoreMonad ( endPass, CoreToDo(..) )-import FastString-import ErrUtils-import Outputable-import SrcLoc-import Coverage-import Util-import MonadUtils-import OrdList-import Data.List-import Data.IORef-import Control.Monad( when )-\end{code}--%************************************************************************-%* *-%* The main function: deSugar-%* *-%************************************************************************--\begin{code}--- | Main entry point to the desugarer.-deSugarWithLoc, deSugar :: HscEnv -> ModLocation -> TcGblEnv -> IO (Messages, Maybe ModGuts)--- Can modify PCS by faulting in more declarations--deSugarWithLoc = deSugar --deSugar hsc_env- mod_loc- tcg_env@(TcGblEnv { tcg_mod = mod,- tcg_src = hsc_src,- tcg_type_env = type_env,- tcg_imports = imports,- tcg_exports = exports,- tcg_keep = keep_var,- tcg_th_splice_used = tc_splice_used,- tcg_rdr_env = rdr_env,- tcg_fix_env = fix_env,- tcg_inst_env = inst_env,- tcg_fam_inst_env = fam_inst_env,- tcg_warns = warns,- tcg_anns = anns,- tcg_binds = binds,- tcg_imp_specs = imp_specs,- tcg_dependent_files = dependent_files,- tcg_ev_binds = ev_binds,- tcg_fords = fords,- tcg_rules = rules,- tcg_vects = vects,- tcg_patsyns = patsyns,- tcg_tcs = tcs,- tcg_insts = insts,- tcg_fam_insts = fam_insts,- tcg_hpc = other_hpc_info })-- = do { let dflags = hsc_dflags hsc_env- ; showPass dflags "Desugar"-- -- Desugar the program- ; let export_set = availsToNameSet exports- target = hscTarget dflags- hpcInfo = emptyHpcInfo other_hpc_info- want_ticks = gopt Opt_Hpc dflags- || target == HscInterpreted- || (gopt Opt_SccProfilingOn dflags- && case profAuto dflags of- NoProfAuto -> False- _ -> True)-- ; (binds_cvr, ds_hpc_info, modBreaks)- <- if want_ticks && not (isHsBoot hsc_src)- then addTicksToBinds dflags mod mod_loc export_set- (typeEnvTyCons type_env) binds- else return (binds, hpcInfo, emptyModBreaks)-- ; (msgs, mb_res) <- initDs hsc_env mod rdr_env type_env fam_inst_env $- do { ds_ev_binds <- dsEvBinds ev_binds- ; core_prs <- dsTopLHsBinds binds_cvr- ; (spec_prs, spec_rules) <- dsImpSpecs imp_specs- ; (ds_fords, foreign_prs) <- dsForeigns fords- ; ds_rules <- mapMaybeM dsRule rules- ; ds_vects <- mapM dsVect vects- ; let hpc_init- | gopt Opt_Hpc dflags = hpcInitCode mod ds_hpc_info- | otherwise = empty- ; return ( ds_ev_binds- , foreign_prs `appOL` core_prs `appOL` spec_prs- , spec_rules ++ ds_rules, ds_vects- , ds_fords `appendStubC` hpc_init) }-- ; case mb_res of {- Nothing -> return (msgs, Nothing) ;- Just (ds_ev_binds, all_prs, all_rules, vects0, ds_fords) -> do-- do { -- Add export flags to bindings- keep_alive <- readIORef keep_var- ; let (rules_for_locals, rules_for_imps) = partition isLocalRule all_rules- final_prs = addExportFlagsAndRules target export_set keep_alive- rules_for_locals (fromOL all_prs)-- final_pgm = combineEvBinds ds_ev_binds final_prs- -- Notice that we put the whole lot in a big Rec, even the foreign binds- -- When compiling PrelFloat, which defines data Float = F# Float#- -- we want F# to be in scope in the foreign marshalling code!- -- You might think it doesn't matter, but the simplifier brings all top-level- -- things into the in-scope set before simplifying; so we get no unfolding for F#!-- ; (ds_binds, ds_rules_for_imps, ds_vects)- <- simpleOptPgm dflags mod final_pgm rules_for_imps vects0- -- The simpleOptPgm gets rid of type- -- bindings plus any stupid dead code-- ; endPass hsc_env CoreDesugarOpt ds_binds ds_rules_for_imps-- ; let used_names = mkUsedNames tcg_env- ; deps <- mkDependencies tcg_env-- ; used_th <- readIORef tc_splice_used- ; dep_files <- readIORef dependent_files- ; safe_mode <- finalSafeMode dflags tcg_env-- ; let mod_guts = ModGuts {- mg_module = mod,- mg_boot = isHsBoot hsc_src,- mg_exports = exports,- mg_deps = deps,- mg_used_names = used_names,- mg_used_th = used_th,- mg_dir_imps = imp_mods imports,- mg_rdr_env = rdr_env,- mg_fix_env = fix_env,- mg_warns = warns,- mg_anns = anns,- mg_tcs = tcs,- mg_insts = insts,- mg_fam_insts = fam_insts,- mg_inst_env = inst_env,- mg_fam_inst_env = fam_inst_env,- mg_patsyns = filter ((`elemNameSet` export_set) . patSynName) patsyns,- mg_rules = ds_rules_for_imps,- mg_binds = ds_binds,- mg_foreign = ds_fords,- mg_hpc_info = ds_hpc_info,- mg_modBreaks = modBreaks,- mg_vect_decls = ds_vects,- mg_vect_info = noVectInfo,- mg_safe_haskell = safe_mode,- mg_trust_pkg = imp_trust_own_pkg imports,- mg_dependent_files = dep_files- }- ; return (msgs, Just mod_guts)- }}}--dsImpSpecs :: [LTcSpecPrag] -> DsM (OrdList (Id,CoreExpr), [CoreRule])-dsImpSpecs imp_specs- = do { spec_prs <- mapMaybeM (dsSpec Nothing) imp_specs- ; let (spec_binds, spec_rules) = unzip spec_prs- ; return (concatOL spec_binds, spec_rules) }--combineEvBinds :: [CoreBind] -> [(Id,CoreExpr)] -> [CoreBind]--- Top-level bindings can include coercion bindings, but not via superclasses--- See Note [Top-level evidence]-combineEvBinds [] val_prs- = [Rec val_prs]-combineEvBinds (NonRec b r : bs) val_prs- | isId b = combineEvBinds bs ((b,r):val_prs)- | otherwise = NonRec b r : combineEvBinds bs val_prs-combineEvBinds (Rec prs : bs) val_prs- = combineEvBinds bs (prs ++ val_prs)-\end{code}--Note [Top-level evidence]-~~~~~~~~~~~~~~~~~~~~~~~~~-Top-level evidence bindings may be mutually recursive with the top-level value-bindings, so we must put those in a Rec. But we can't put them *all* in a Rec-because the occurrence analyser doesn't teke account of type/coercion variables-when computing dependencies.--So we pull out the type/coercion variables (which are in dependency order),-and Rec the rest.---\begin{code}-deSugarExpr :: HscEnv -> LHsExpr Id -> IO (Messages, Maybe CoreExpr)--deSugarExpr hsc_env tc_expr- = do { let dflags = hsc_dflags hsc_env- icntxt = hsc_IC hsc_env- rdr_env = ic_rn_gbl_env icntxt- type_env = mkTypeEnvWithImplicits (ic_tythings icntxt)- fam_insts = snd (ic_instances icntxt)- fam_inst_env = extendFamInstEnvList emptyFamInstEnv fam_insts- -- This stuff is a half baked version of TcRnDriver.setInteractiveContext-- ; showPass dflags "Desugar"-- -- Do desugaring- ; (msgs, mb_core_expr) <- initDs hsc_env (icInteractiveModule icntxt) rdr_env- type_env fam_inst_env $- dsLExpr tc_expr-- ; case mb_core_expr of- Nothing -> return ()- Just expr -> dumpIfSet_dyn dflags Opt_D_dump_ds "Desugared" (pprCoreExpr expr)-- ; return (msgs, mb_core_expr) }-\end{code}--%************************************************************************-%* *-%* Add rules and export flags to binders-%* *-%************************************************************************--\begin{code}-addExportFlagsAndRules- :: HscTarget -> NameSet -> NameSet -> [CoreRule]- -> [(Id, t)] -> [(Id, t)]-addExportFlagsAndRules target exports keep_alive rules prs- = mapFst add_one prs- where- add_one bndr = add_rules name (add_export name bndr)- where- name = idName bndr-- ---------- Rules --------- -- See Note [Attach rules to local ids]- -- NB: the binder might have some existing rules,- -- arising from specialisation pragmas- add_rules name bndr- | Just rules <- lookupNameEnv rule_base name- = bndr `addIdSpecialisations` rules- | otherwise- = bndr- rule_base = extendRuleBaseList emptyRuleBase rules-- ---------- Export flag --------- -- See Note [Adding export flags]- add_export name bndr- | dont_discard name = setIdExported bndr- | otherwise = bndr-- dont_discard :: Name -> Bool- dont_discard name = is_exported name- || name `elemNameSet` keep_alive-- -- In interactive mode, we don't want to discard any top-level- -- entities at all (eg. do not inline them away during- -- simplification), and retain them all in the TypeEnv so they are- -- available from the command line.- --- -- isExternalName separates the user-defined top-level names from those- -- introduced by the type checker.- is_exported :: Name -> Bool- is_exported | targetRetainsAllBindings target = isExternalName- | otherwise = (`elemNameSet` exports)-\end{code}---Note [Adding export flags]-~~~~~~~~~~~~~~~~~~~~~~~~~~-Set the no-discard flag if either- a) the Id is exported- b) it's mentioned in the RHS of an orphan rule- c) it's in the keep-alive set--It means that the binding won't be discarded EVEN if the binding-ends up being trivial (v = w) -- the simplifier would usually just-substitute w for v throughout, but we don't apply the substitution to-the rules (maybe we should?), so this substitution would make the rule-bogus.--You might wonder why exported Ids aren't already marked as such;-it's just because the type checker is rather busy already and-I didn't want to pass in yet another mapping.--Note [Attach rules to local ids]-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~-Find the rules for locally-defined Ids; then we can attach them-to the binders in the top-level bindings--Reason- - It makes the rules easier to look up- - It means that transformation rules and specialisations for- locally defined Ids are handled uniformly- - It keeps alive things that are referred to only from a rule- (the occurrence analyser knows about rules attached to Ids)- - It makes sure that, when we apply a rule, the free vars- of the RHS are more likely to be in scope- - The imported rules are carried in the in-scope set- which is extended on each iteration by the new wave of- local binders; any rules which aren't on the binding will- thereby get dropped---%************************************************************************-%* *-%* Desugaring transformation rules-%* *-%************************************************************************--\begin{code}-dsRule :: LRuleDecl Id -> DsM (Maybe CoreRule)-dsRule (L loc (HsRule name act vars lhs _tv_lhs rhs _fv_rhs))- = putSrcSpanDs loc $- do { let bndrs' = [var | RuleBndr (L _ var) <- vars]-- ; lhs' <- unsetGOptM Opt_EnableRewriteRules $- unsetWOptM Opt_WarnIdentities $- dsLExpr lhs -- Note [Desugaring RULE left hand sides]-- ; rhs' <- dsLExpr rhs- ; dflags <- getDynFlags-- -- Substitute the dict bindings eagerly,- -- and take the body apart into a (f args) form- ; case decomposeRuleLhs bndrs' lhs' of {- Left msg -> do { warnDs msg; return Nothing } ;- Right (final_bndrs, fn_id, args) -> do-- { let is_local = isLocalId fn_id- -- NB: isLocalId is False of implicit Ids. This is good because- -- we don't want to attach rules to the bindings of implicit Ids,- -- because they don't show up in the bindings until just before code gen- fn_name = idName fn_id- final_rhs = simpleOptExpr rhs' -- De-crap it- rule = mkRule False {- Not auto -} is_local- name act fn_name final_bndrs args final_rhs-- inline_shadows_rule -- Function can be inlined before rule fires- | wopt Opt_WarnInlineRuleShadowing dflags- , isLocalId fn_id || hasSomeUnfolding (idUnfolding fn_id) - -- If imported with no unfolding, no worries- = case (idInlineActivation fn_id, act) of- (NeverActive, _) -> False- (AlwaysActive, _) -> True- (ActiveBefore {}, _) -> True- (ActiveAfter {}, NeverActive) -> True- (ActiveAfter n, ActiveAfter r) -> r < n -- Rule active strictly first- (ActiveAfter {}, AlwaysActive) -> False- (ActiveAfter {}, ActiveBefore {}) -> False- | otherwise = False-- ; when inline_shadows_rule $- warnDs (vcat [ hang (ptext (sLit "Rule") <+> doubleQuotes (ftext name)- <+> ptext (sLit "may never fire"))- 2 (ptext (sLit "because") <+> quotes (ppr fn_id)- <+> ptext (sLit "might inline first"))- , ptext (sLit "Probable fix: add an INLINE[n] or NOINLINE[n] pragma on")- <+> quotes (ppr fn_id) ])-- ; return (Just rule)- } } }-\end{code}--Note [Desugaring RULE left hand sides]-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~-For the LHS of a RULE we do *not* want to desugar- [x] to build (\cn. x `c` n)-We want to leave explicit lists simply as chains-of cons's. We can achieve that slightly indirectly by-switching off EnableRewriteRules. See DsExpr.dsExplicitList.--That keeps the desugaring of list comprehensions simple too.----Nor do we want to warn of conversion identities on the LHS;-the rule is precisly to optimise them:- {-# RULES "fromRational/id" fromRational = id :: Rational -> Rational #-}---%************************************************************************-%* *-%* Desugaring vectorisation declarations-%* *-%************************************************************************--\begin{code}-dsVect :: LVectDecl Id -> DsM CoreVect-dsVect (L loc (HsVect (L _ v) rhs))- = putSrcSpanDs loc $- do { rhs' <- dsLExpr rhs- ; return $ Vect v rhs'- }-dsVect (L _loc (HsNoVect (L _ v)))- = return $ NoVect v-dsVect (L _loc (HsVectTypeOut isScalar tycon rhs_tycon))- = return $ VectType isScalar tycon' rhs_tycon- where- tycon' | Just ty <- coreView $ mkTyConTy tycon- , (tycon', []) <- splitTyConApp ty = tycon'- | otherwise = tycon-dsVect vd@(L _ (HsVectTypeIn _ _ _))- = pprPanic "Desugar.dsVect: unexpected 'HsVectTypeIn'" (ppr vd)-dsVect (L _loc (HsVectClassOut cls))- = return $ VectClass (classTyCon cls)-dsVect vc@(L _ (HsVectClassIn _))- = pprPanic "Desugar.dsVect: unexpected 'HsVectClassIn'" (ppr vc)-dsVect (L _loc (HsVectInstOut inst))- = return $ VectInst (instanceDFunId inst)-dsVect vi@(L _ (HsVectInstIn _))- = pprPanic "Desugar.dsVect: unexpected 'HsVectInstIn'" (ppr vi)-\end{code}
− src/Language/Haskell/Liquid/Desugar/DsArrows.lhs
@@ -1,1202 +0,0 @@-%-% (c) The University of Glasgow 2006-% (c) The GRASP/AQUA Project, Glasgow University, 1992-1998-%--Desugaring arrow commands--\begin{code}-{-# OPTIONS -fno-warn-tabs #-}--- The above warning supression flag is a temporary kludge.--- While working on this module you are encouraged to remove it and--- detab the module (please do the detabbing in a separate patch). See--- http://ghc.haskell.org/trac/ghc/wiki/Commentary/CodingStyle#TabsvsSpaces--- for details--module Language.Haskell.Liquid.Desugar.DsArrows ( dsProcExpr ) where---- #include "HsVersions.h"--import Language.Haskell.Liquid.Desugar.Match-import Language.Haskell.Liquid.Desugar.DsUtils-import DsMonad--import HsSyn hiding (collectPatBinders, collectPatsBinders, collectLStmtsBinders, collectLStmtBinders, collectStmtBinders )-import TcHsSyn---- NB: The desugarer, which straddles the source and Core worlds, sometimes--- needs to see source types (newtypes etc), and sometimes not--- So WATCH OUT; check each use of split*Ty functions.--- Sigh. This is a pain.--import {-# SOURCE #-} Language.Haskell.Liquid.Desugar.DsExpr ( dsExpr, dsLExpr, dsLocalBinds )--import TcType-import TcEvidence-import CoreSyn-import CoreFVs-import CoreUtils-import MkCore-import Language.Haskell.Liquid.Desugar.DsBinds (dsHsWrapper)--import Name-import Var-import Id-import DataCon-import TysWiredIn-import BasicTypes-import PrelNames-import Outputable-import Bag-import VarSet-import SrcLoc-import ListSetOps( assocDefault )-import FastString-import Data.List-\end{code}--\begin{code}-data DsCmdEnv = DsCmdEnv {- arr_id, compose_id, first_id, app_id, choice_id, loop_id :: CoreExpr- }--mkCmdEnv :: CmdSyntaxTable Id -> DsM ([CoreBind], DsCmdEnv)--- See Note [CmdSyntaxTable] in HsExpr-mkCmdEnv tc_meths- = do { (meth_binds, prs) <- mapAndUnzipM mk_bind tc_meths- ; return (meth_binds, DsCmdEnv {- arr_id = Var (find_meth prs arrAName),- compose_id = Var (find_meth prs composeAName),- first_id = Var (find_meth prs firstAName),- app_id = Var (find_meth prs appAName),- choice_id = Var (find_meth prs choiceAName),- loop_id = Var (find_meth prs loopAName)- }) }- where- mk_bind (std_name, expr)- = do { rhs <- dsExpr expr- ; id <- newSysLocalDs (exprType rhs)- ; return (NonRec id rhs, (std_name, id)) }- - find_meth prs std_name- = assocDefault (mk_panic std_name) prs std_name- mk_panic std_name = pprPanic "mkCmdEnv" (ptext (sLit "Not found:") <+> ppr std_name)---- arr :: forall b c. (b -> c) -> a b c-do_arr :: DsCmdEnv -> Type -> Type -> CoreExpr -> CoreExpr-do_arr ids b_ty c_ty f = mkApps (arr_id ids) [Type b_ty, Type c_ty, f]---- (>>>) :: forall b c d. a b c -> a c d -> a b d-do_compose :: DsCmdEnv -> Type -> Type -> Type ->- CoreExpr -> CoreExpr -> CoreExpr-do_compose ids b_ty c_ty d_ty f g- = mkApps (compose_id ids) [Type b_ty, Type c_ty, Type d_ty, f, g]---- first :: forall b c d. a b c -> a (b,d) (c,d)-do_first :: DsCmdEnv -> Type -> Type -> Type -> CoreExpr -> CoreExpr-do_first ids b_ty c_ty d_ty f- = mkApps (first_id ids) [Type b_ty, Type c_ty, Type d_ty, f]---- app :: forall b c. a (a b c, b) c-do_app :: DsCmdEnv -> Type -> Type -> CoreExpr-do_app ids b_ty c_ty = mkApps (app_id ids) [Type b_ty, Type c_ty]---- (|||) :: forall b d c. a b d -> a c d -> a (Either b c) d--- note the swapping of d and c-do_choice :: DsCmdEnv -> Type -> Type -> Type ->- CoreExpr -> CoreExpr -> CoreExpr-do_choice ids b_ty c_ty d_ty f g- = mkApps (choice_id ids) [Type b_ty, Type d_ty, Type c_ty, f, g]---- loop :: forall b d c. a (b,d) (c,d) -> a b c--- note the swapping of d and c-do_loop :: DsCmdEnv -> Type -> Type -> Type -> CoreExpr -> CoreExpr-do_loop ids b_ty c_ty d_ty f- = mkApps (loop_id ids) [Type b_ty, Type d_ty, Type c_ty, f]---- premap :: forall b c d. (b -> c) -> a c d -> a b d--- premap f g = arr f >>> g-do_premap :: DsCmdEnv -> Type -> Type -> Type ->- CoreExpr -> CoreExpr -> CoreExpr-do_premap ids b_ty c_ty d_ty f g- = do_compose ids b_ty c_ty d_ty (do_arr ids b_ty c_ty f) g--mkFailExpr :: HsMatchContext Id -> Type -> DsM CoreExpr-mkFailExpr ctxt ty- = mkErrorAppDs pAT_ERROR_ID ty (matchContextErrString ctxt)---- construct CoreExpr for \ (a :: a_ty, b :: b_ty) -> a-mkFstExpr :: Type -> Type -> DsM CoreExpr-mkFstExpr a_ty b_ty = do- a_var <- newSysLocalDs a_ty- b_var <- newSysLocalDs b_ty- pair_var <- newSysLocalDs (mkCorePairTy a_ty b_ty)- return (Lam pair_var- (coreCasePair pair_var a_var b_var (Var a_var)))---- construct CoreExpr for \ (a :: a_ty, b :: b_ty) -> b-mkSndExpr :: Type -> Type -> DsM CoreExpr-mkSndExpr a_ty b_ty = do- a_var <- newSysLocalDs a_ty- b_var <- newSysLocalDs b_ty- pair_var <- newSysLocalDs (mkCorePairTy a_ty b_ty)- return (Lam pair_var- (coreCasePair pair_var a_var b_var (Var b_var)))-\end{code}--Build case analysis of a tuple. This cannot be done in the DsM monad,-because the list of variables is typically not yet defined.--\begin{code}--- coreCaseTuple [u1..] v [x1..xn] body--- = case v of v { (x1, .., xn) -> body }--- But the matching may be nested if the tuple is very big--coreCaseTuple :: UniqSupply -> Id -> [Id] -> CoreExpr -> CoreExpr-coreCaseTuple uniqs scrut_var vars body- = mkTupleCase uniqs vars body scrut_var (Var scrut_var)--coreCasePair :: Id -> Id -> Id -> CoreExpr -> CoreExpr-coreCasePair scrut_var var1 var2 body- = Case (Var scrut_var) scrut_var (exprType body)- [(DataAlt (tupleCon BoxedTuple 2), [var1, var2], body)]-\end{code}--\begin{code}-mkCorePairTy :: Type -> Type -> Type-mkCorePairTy t1 t2 = mkBoxedTupleTy [t1, t2]--mkCorePairExpr :: CoreExpr -> CoreExpr -> CoreExpr-mkCorePairExpr e1 e2 = mkCoreTup [e1, e2]--mkCoreUnitExpr :: CoreExpr-mkCoreUnitExpr = mkCoreTup []-\end{code}--The input is divided into a local environment, which is a flat tuple-(unless it's too big), and a stack, which is a right-nested pair.-In general, the input has the form-- ((x1,...,xn), (s1,...(sk,())...))--where xi are the environment values, and si the ones on the stack,-with s1 being the "top", the first one to be matched with a lambda.--\begin{code}-envStackType :: [Id] -> Type -> Type-envStackType ids stack_ty = mkCorePairTy (mkBigCoreVarTupTy ids) stack_ty---- splitTypeAt n (t1,... (tn,t)...) = ([t1, ..., tn], t)-splitTypeAt :: Int -> Type -> ([Type], Type)-splitTypeAt n ty- | n == 0 = ([], ty)- | otherwise = case tcTyConAppArgs ty of- [t, ty'] -> let (ts, ty_r) = splitTypeAt (n-1) ty' in (t:ts, ty_r)- _ -> pprPanic "splitTypeAt" (ppr ty)--------------------------------------------------- buildEnvStack------ ((x1,...,xn),stk)--buildEnvStack :: [Id] -> Id -> CoreExpr-buildEnvStack env_ids stack_id- = mkCorePairExpr (mkBigCoreVarTup env_ids) (Var stack_id)--------------------------------------------------- matchEnvStack------ \ ((x1,...,xn),stk) -> body--- =>--- \ pair ->--- case pair of (tup,stk) ->--- case tup of (x1,...,xn) ->--- body--matchEnvStack :: [Id] -- x1..xn- -> Id -- stk- -> CoreExpr -- e- -> DsM CoreExpr-matchEnvStack env_ids stack_id body = do- uniqs <- newUniqueSupply- tup_var <- newSysLocalDs (mkBigCoreVarTupTy env_ids)- let match_env = coreCaseTuple uniqs tup_var env_ids body- pair_id <- newSysLocalDs (mkCorePairTy (idType tup_var) (idType stack_id))- return (Lam pair_id (coreCasePair pair_id tup_var stack_id match_env))--------------------------------------------------- matchEnv------ \ (x1,...,xn) -> body--- =>--- \ tup ->--- case tup of (x1,...,xn) ->--- body--matchEnv :: [Id] -- x1..xn- -> CoreExpr -- e- -> DsM CoreExpr-matchEnv env_ids body = do- uniqs <- newUniqueSupply- tup_id <- newSysLocalDs (mkBigCoreVarTupTy env_ids)- return (Lam tup_id (coreCaseTuple uniqs tup_id env_ids body))--------------------------------------------------- matchVarStack------ case (x1, ...(xn, s)...) -> e--- =>--- case z0 of (x1,z1) ->--- case zn-1 of (xn,s) ->--- e-matchVarStack :: [Id] -> Id -> CoreExpr -> DsM (Id, CoreExpr)-matchVarStack [] stack_id body = return (stack_id, body)-matchVarStack (param_id:param_ids) stack_id body = do- (tail_id, tail_code) <- matchVarStack param_ids stack_id body- pair_id <- newSysLocalDs (mkCorePairTy (idType param_id) (idType tail_id))- return (pair_id, coreCasePair pair_id param_id tail_id tail_code)-\end{code}--\begin{code}-mkHsEnvStackExpr :: [Id] -> Id -> LHsExpr Id-mkHsEnvStackExpr env_ids stack_id- = mkLHsTupleExpr [mkLHsVarTuple env_ids, nlHsVar stack_id]-\end{code}--Translation of arrow abstraction--\begin{code}---- D; xs |-a c : () --> t' ---> c'--- ----------------------------- D |- proc p -> c :: a t t' ---> premap (\ p -> ((xs),())) c'------ where (xs) is the tuple of variables bound by p--dsProcExpr- :: LPat Id- -> LHsCmdTop Id- -> DsM CoreExpr-dsProcExpr pat (L _ (HsCmdTop cmd _unitTy cmd_ty ids)) = do- (meth_binds, meth_ids) <- mkCmdEnv ids- let locals = mkVarSet (collectPatBinders pat)- (core_cmd, _free_vars, env_ids) <- dsfixCmd meth_ids locals unitTy cmd_ty cmd- let env_ty = mkBigCoreVarTupTy env_ids- let env_stk_ty = mkCorePairTy env_ty unitTy- let env_stk_expr = mkCorePairExpr (mkBigCoreVarTup env_ids) mkCoreUnitExpr- fail_expr <- mkFailExpr ProcExpr env_stk_ty- var <- selectSimpleMatchVarL pat- match_code <- matchSimply (Var var) ProcExpr pat env_stk_expr fail_expr- let pat_ty = hsLPatType pat- proc_code = do_premap meth_ids pat_ty env_stk_ty cmd_ty- (Lam var match_code)- core_cmd- return (mkLets meth_binds proc_code)-\end{code}--Translation of a command judgement of the form-- D; xs |-a c : stk --> t--to an expression e such that-- D |- e :: a (xs, stk) t--\begin{code}-dsLCmd :: DsCmdEnv -> IdSet -> Type -> Type -> LHsCmd Id -> [Id]- -> DsM (CoreExpr, IdSet)-dsLCmd ids local_vars stk_ty res_ty cmd env_ids- = dsCmd ids local_vars stk_ty res_ty (unLoc cmd) env_ids--dsCmd :: DsCmdEnv -- arrow combinators- -> IdSet -- set of local vars available to this command- -> Type -- type of the stack (right-nested tuple)- -> Type -- return type of the command- -> HsCmd Id -- command to desugar- -> [Id] -- list of vars in the input to this command- -- This is typically fed back,- -- so don't pull on it too early- -> DsM (CoreExpr, -- desugared expression- IdSet) -- subset of local vars that occur free---- D |- fun :: a t1 t2--- D, xs |- arg :: t1--- -------------------------------- D; xs |-a fun -< arg : stk --> t2------ ---> premap (\ ((xs), _stk) -> arg) fun--dsCmd ids local_vars stack_ty res_ty- (HsCmdArrApp arrow arg arrow_ty HsFirstOrderApp _)- env_ids = do- let- (a_arg_ty, _res_ty') = tcSplitAppTy arrow_ty- (_a_ty, arg_ty) = tcSplitAppTy a_arg_ty- core_arrow <- dsLExpr arrow- core_arg <- dsLExpr arg- stack_id <- newSysLocalDs stack_ty- core_make_arg <- matchEnvStack env_ids stack_id core_arg- return (do_premap ids- (envStackType env_ids stack_ty)- arg_ty- res_ty- core_make_arg- core_arrow,- exprFreeIds core_arg `intersectVarSet` local_vars)---- D, xs |- fun :: a t1 t2--- D, xs |- arg :: t1--- --------------------------------- D; xs |-a fun -<< arg : stk --> t2------ ---> premap (\ ((xs), _stk) -> (fun, arg)) app--dsCmd ids local_vars stack_ty res_ty- (HsCmdArrApp arrow arg arrow_ty HsHigherOrderApp _)- env_ids = do- let- (a_arg_ty, _res_ty') = tcSplitAppTy arrow_ty- (_a_ty, arg_ty) = tcSplitAppTy a_arg_ty- - core_arrow <- dsLExpr arrow- core_arg <- dsLExpr arg- stack_id <- newSysLocalDs stack_ty- core_make_pair <- matchEnvStack env_ids stack_id- (mkCorePairExpr core_arrow core_arg)-- return (do_premap ids- (envStackType env_ids stack_ty)- (mkCorePairTy arrow_ty arg_ty)- res_ty- core_make_pair- (do_app ids arg_ty res_ty),- (exprFreeIds core_arrow `unionVarSet` exprFreeIds core_arg)- `intersectVarSet` local_vars)---- D; ys |-a cmd : (t,stk) --> t'--- D, xs |- exp :: t--- --------------------------- D; xs |-a cmd exp : stk --> t'------ ---> premap (\ ((xs),stk) -> ((ys),(e,stk))) cmd--dsCmd ids local_vars stack_ty res_ty (HsCmdApp cmd arg) env_ids = do- core_arg <- dsLExpr arg- let- arg_ty = exprType core_arg- stack_ty' = mkCorePairTy arg_ty stack_ty- (core_cmd, free_vars, env_ids')- <- dsfixCmd ids local_vars stack_ty' res_ty cmd- stack_id <- newSysLocalDs stack_ty- arg_id <- newSysLocalDs arg_ty- -- push the argument expression onto the stack- let- stack' = mkCorePairExpr (Var arg_id) (Var stack_id)- core_body = bindNonRec arg_id core_arg- (mkCorePairExpr (mkBigCoreVarTup env_ids') stack')-- -- match the environment and stack against the input- core_map <- matchEnvStack env_ids stack_id core_body- return (do_premap ids- (envStackType env_ids stack_ty)- (envStackType env_ids' stack_ty')- res_ty- core_map- core_cmd,- free_vars `unionVarSet`- (exprFreeIds core_arg `intersectVarSet` local_vars))---- D; ys |-a cmd : stk t'--- -------------------------------------------------- D; xs |-a \ p1 ... pk -> cmd : (t1,...(tk,stk)...) t'------ ---> premap (\ ((xs), (p1, ... (pk,stk)...)) -> ((ys),stk)) cmd--dsCmd ids local_vars stack_ty res_ty- (HsCmdLam (MG { mg_alts = [L _ (Match pats _ (GRHSs [L _ (GRHS [] body)] _ ))] }))- env_ids = do- let- pat_vars = mkVarSet (collectPatsBinders pats)- local_vars' = pat_vars `unionVarSet` local_vars- (pat_tys, stack_ty') = splitTypeAt (length pats) stack_ty- (core_body, free_vars, env_ids') <- dsfixCmd ids local_vars' stack_ty' res_ty body- param_ids <- mapM newSysLocalDs pat_tys- stack_id' <- newSysLocalDs stack_ty'-- -- the expression is built from the inside out, so the actions- -- are presented in reverse order-- let- -- build a new environment, plus what's left of the stack- core_expr = buildEnvStack env_ids' stack_id'- in_ty = envStackType env_ids stack_ty- in_ty' = envStackType env_ids' stack_ty'- - fail_expr <- mkFailExpr LambdaExpr in_ty'- -- match the patterns against the parameters- match_code <- matchSimplys (map Var param_ids) LambdaExpr pats core_expr fail_expr- -- match the parameters against the top of the old stack- (stack_id, param_code) <- matchVarStack param_ids stack_id' match_code- -- match the old environment and stack against the input- select_code <- matchEnvStack env_ids stack_id param_code- return (do_premap ids in_ty in_ty' res_ty select_code core_body,- free_vars `minusVarSet` pat_vars)--dsCmd ids local_vars stack_ty res_ty (HsCmdPar cmd) env_ids- = dsLCmd ids local_vars stack_ty res_ty cmd env_ids---- D, xs |- e :: Bool--- D; xs1 |-a c1 : stk --> t--- D; xs2 |-a c2 : stk --> t--- ------------------------------------------- D; xs |-a if e then c1 else c2 : stk --> t------ ---> premap (\ ((xs),stk) ->--- if e then Left ((xs1),stk) else Right ((xs2),stk))--- (c1 ||| c2)--dsCmd ids local_vars stack_ty res_ty (HsCmdIf mb_fun cond then_cmd else_cmd)- env_ids = do- core_cond <- dsLExpr cond- (core_then, fvs_then, then_ids) <- dsfixCmd ids local_vars stack_ty res_ty then_cmd- (core_else, fvs_else, else_ids) <- dsfixCmd ids local_vars stack_ty res_ty else_cmd- stack_id <- newSysLocalDs stack_ty- either_con <- dsLookupTyCon eitherTyConName- left_con <- dsLookupDataCon leftDataConName- right_con <- dsLookupDataCon rightDataConName-- let mk_left_expr ty1 ty2 e = mkConApp left_con [Type ty1, Type ty2, e]- mk_right_expr ty1 ty2 e = mkConApp right_con [Type ty1, Type ty2, e]-- in_ty = envStackType env_ids stack_ty- then_ty = envStackType then_ids stack_ty- else_ty = envStackType else_ids stack_ty- sum_ty = mkTyConApp either_con [then_ty, else_ty]- fvs_cond = exprFreeIds core_cond `intersectVarSet` local_vars- - core_left = mk_left_expr then_ty else_ty (buildEnvStack then_ids stack_id)- core_right = mk_right_expr then_ty else_ty (buildEnvStack else_ids stack_id)-- core_if <- case mb_fun of - Just fun -> do { core_fun <- dsExpr fun- ; matchEnvStack env_ids stack_id $- mkCoreApps core_fun [core_cond, core_left, core_right] }- Nothing -> matchEnvStack env_ids stack_id $- mkIfThenElse core_cond core_left core_right-- return (do_premap ids in_ty sum_ty res_ty- core_if- (do_choice ids then_ty else_ty res_ty core_then core_else),- fvs_cond `unionVarSet` fvs_then `unionVarSet` fvs_else)-\end{code}--Case commands are treated in much the same way as if commands-(see above) except that there are more alternatives. For example-- case e of { p1 -> c1; p2 -> c2; p3 -> c3 }--is translated to-- premap (\ ((xs)*ts) -> case e of- p1 -> (Left (Left (xs1)*ts))- p2 -> Left ((Right (xs2)*ts))- p3 -> Right ((xs3)*ts))- ((c1 ||| c2) ||| c3)--The idea is to extract the commands from the case, build a balanced tree-of choices, and replace the commands with expressions that build tagged-tuples, obtaining a case expression that can be desugared normally.-To build all this, we use triples describing segments of the list of-case bodies, containing the following fields:- * a list of expressions of the form (Left|Right)* ((xs)*ts), to be put- into the case replacing the commands- * a sum type that is the common type of these expressions, and also the- input type of the arrow- * a CoreExpr for an arrow built by combining the translated command- bodies with |||.--\begin{code}-dsCmd ids local_vars stack_ty res_ty - (HsCmdCase exp (MG { mg_alts = matches, mg_arg_tys = arg_tys, mg_origin = origin }))- env_ids = do- stack_id <- newSysLocalDs stack_ty-- -- Extract and desugar the leaf commands in the case, building tuple- -- expressions that will (after tagging) replace these leaves-- let- leaves = concatMap leavesMatch matches- make_branch (leaf, bound_vars) = do- (core_leaf, _fvs, leaf_ids) <-- dsfixCmd ids (bound_vars `unionVarSet` local_vars) stack_ty res_ty leaf- return ([mkHsEnvStackExpr leaf_ids stack_id],- envStackType leaf_ids stack_ty,- core_leaf)- - branches <- mapM make_branch leaves- either_con <- dsLookupTyCon eitherTyConName- left_con <- dsLookupDataCon leftDataConName- right_con <- dsLookupDataCon rightDataConName- let- left_id = HsVar (dataConWrapId left_con)- right_id = HsVar (dataConWrapId right_con)- left_expr ty1 ty2 e = noLoc $ HsApp (noLoc $ HsWrap (mkWpTyApps [ty1, ty2]) left_id ) e- right_expr ty1 ty2 e = noLoc $ HsApp (noLoc $ HsWrap (mkWpTyApps [ty1, ty2]) right_id) e-- -- Prefix each tuple with a distinct series of Left's and Right's,- -- in a balanced way, keeping track of the types.-- merge_branches (builds1, in_ty1, core_exp1)- (builds2, in_ty2, core_exp2)- = (map (left_expr in_ty1 in_ty2) builds1 ++- map (right_expr in_ty1 in_ty2) builds2,- mkTyConApp either_con [in_ty1, in_ty2],- do_choice ids in_ty1 in_ty2 res_ty core_exp1 core_exp2)- (leaves', sum_ty, core_choices) = foldb merge_branches branches-- -- Replace the commands in the case with these tagged tuples,- -- yielding a HsExpr Id we can feed to dsExpr.-- (_, matches') = mapAccumL (replaceLeavesMatch res_ty) leaves' matches- in_ty = envStackType env_ids stack_ty-- core_body <- dsExpr (HsCase exp (MG { mg_alts = matches', mg_arg_tys = arg_tys- , mg_res_ty = sum_ty, mg_origin = origin }))- -- Note that we replace the HsCase result type by sum_ty,- -- which is the type of matches'-- core_matches <- matchEnvStack env_ids stack_id core_body- return (do_premap ids in_ty sum_ty res_ty core_matches core_choices,- exprFreeIds core_body `intersectVarSet` local_vars)---- D; ys |-a cmd : stk --> t--- ------------------------------------- D; xs |-a let binds in cmd : stk --> t------ ---> premap (\ ((xs),stk) -> let binds in ((ys),stk)) c--dsCmd ids local_vars stack_ty res_ty (HsCmdLet binds body) env_ids = do- let- defined_vars = mkVarSet (collectLocalBinders binds)- local_vars' = defined_vars `unionVarSet` local_vars- - (core_body, _free_vars, env_ids') <- dsfixCmd ids local_vars' stack_ty res_ty body- stack_id <- newSysLocalDs stack_ty- -- build a new environment, plus the stack, using the let bindings- core_binds <- dsLocalBinds binds (buildEnvStack env_ids' stack_id)- -- match the old environment and stack against the input- core_map <- matchEnvStack env_ids stack_id core_binds- return (do_premap ids- (envStackType env_ids stack_ty)- (envStackType env_ids' stack_ty)- res_ty- core_map- core_body,- exprFreeIds core_binds `intersectVarSet` local_vars)---- D; xs |-a ss : t--- ------------------------------------- D; xs |-a do { ss } : () --> t------ ---> premap (\ (env,stk) -> env) c--dsCmd ids local_vars stack_ty res_ty (HsCmdDo stmts _) env_ids = do- (core_stmts, env_ids') <- dsCmdDo ids local_vars res_ty stmts env_ids- let env_ty = mkBigCoreVarTupTy env_ids- core_fst <- mkFstExpr env_ty stack_ty- return (do_premap ids- (mkCorePairTy env_ty stack_ty)- env_ty- res_ty- core_fst- core_stmts,- env_ids')---- D |- e :: forall e. a1 (e,stk1) t1 -> ... an (e,stkn) tn -> a (e,stk) t--- D; xs |-a ci :: stki --> ti--- -------------------------------------- D; xs |-a (|e c1 ... cn|) :: stk --> t ---> e [t_xs] c1 ... cn--dsCmd _ids local_vars _stack_ty _res_ty (HsCmdArrForm op _ args) env_ids = do- let env_ty = mkBigCoreVarTupTy env_ids- core_op <- dsLExpr op- (core_args, fv_sets) <- mapAndUnzipM (dsTrimCmdArg local_vars env_ids) args- return (mkApps (App core_op (Type env_ty)) core_args,- unionVarSets fv_sets)--dsCmd ids local_vars stack_ty res_ty (HsCmdCast coercion cmd) env_ids = do- (core_cmd, env_ids') <- dsCmd ids local_vars stack_ty res_ty cmd env_ids- wrapped_cmd <- dsHsWrapper (mkWpCast coercion) core_cmd- return (wrapped_cmd, env_ids')--dsCmd _ _ _ _ _ c = pprPanic "dsCmd" (ppr c)---- D; ys |-a c : stk --> t (ys <= xs)--- ------------------------ D; xs |-a c : stk --> t ---> premap (\ ((xs),stk) -> ((ys),stk)) c--dsTrimCmdArg- :: IdSet -- set of local vars available to this command- -> [Id] -- list of vars in the input to this command- -> LHsCmdTop Id -- command argument to desugar- -> DsM (CoreExpr, -- desugared expression- IdSet) -- subset of local vars that occur free-dsTrimCmdArg local_vars env_ids (L _ (HsCmdTop cmd stack_ty cmd_ty ids)) = do- (meth_binds, meth_ids) <- mkCmdEnv ids- (core_cmd, free_vars, env_ids') <- dsfixCmd meth_ids local_vars stack_ty cmd_ty cmd- stack_id <- newSysLocalDs stack_ty- trim_code <- matchEnvStack env_ids stack_id (buildEnvStack env_ids' stack_id)- let- in_ty = envStackType env_ids stack_ty- in_ty' = envStackType env_ids' stack_ty- arg_code = if env_ids' == env_ids then core_cmd else- do_premap meth_ids in_ty in_ty' cmd_ty trim_code core_cmd- return (mkLets meth_binds arg_code, free_vars)---- Given D; xs |-a c : stk --> t, builds c with xs fed back.--- Typically needs to be prefixed with arr (\(p, stk) -> ((xs),stk))--dsfixCmd- :: DsCmdEnv -- arrow combinators- -> IdSet -- set of local vars available to this command- -> Type -- type of the stack (right-nested tuple)- -> Type -- return type of the command- -> LHsCmd Id -- command to desugar- -> DsM (CoreExpr, -- desugared expression- IdSet, -- subset of local vars that occur free- [Id]) -- the same local vars as a list, fed back-dsfixCmd ids local_vars stk_ty cmd_ty cmd- = trimInput (dsLCmd ids local_vars stk_ty cmd_ty cmd)---- Feed back the list of local variables actually used a command,--- for use as the input tuple of the generated arrow.--trimInput- :: ([Id] -> DsM (CoreExpr, IdSet))- -> DsM (CoreExpr, -- desugared expression- IdSet, -- subset of local vars that occur free- [Id]) -- same local vars as a list, fed back to- -- the inner function to form the tuple of- -- inputs to the arrow.-trimInput build_arrow- = fixDs (\ ~(_,_,env_ids) -> do- (core_cmd, free_vars) <- build_arrow env_ids- return (core_cmd, free_vars, varSetElems free_vars))--\end{code}--Translation of command judgements of the form-- D |-a do { ss } : t--\begin{code}--dsCmdDo :: DsCmdEnv -- arrow combinators- -> IdSet -- set of local vars available to this statement- -> Type -- return type of the statement- -> [CmdLStmt Id] -- statements to desugar- -> [Id] -- list of vars in the input to this statement- -- This is typically fed back,- -- so don't pull on it too early- -> DsM (CoreExpr, -- desugared expression- IdSet) -- subset of local vars that occur free--dsCmdDo _ _ _ [] _ = panic "dsCmdDo"---- D; xs |-a c : () --> t--- ----------------------------- D; xs |-a do { c } : t------ ---> premap (\ (xs) -> ((xs), ())) c--dsCmdDo ids local_vars res_ty [L _ (LastStmt body _)] env_ids = do- (core_body, env_ids') <- dsLCmd ids local_vars unitTy res_ty body env_ids- let env_ty = mkBigCoreVarTupTy env_ids- env_var <- newSysLocalDs env_ty- let core_map = Lam env_var (mkCorePairExpr (Var env_var) mkCoreUnitExpr)- return (do_premap ids- env_ty- (mkCorePairTy env_ty unitTy)- res_ty- core_map- core_body,- env_ids')--dsCmdDo ids local_vars res_ty (stmt:stmts) env_ids = do- let- bound_vars = mkVarSet (collectLStmtBinders stmt)- local_vars' = bound_vars `unionVarSet` local_vars- (core_stmts, _, env_ids') <- trimInput (dsCmdDo ids local_vars' res_ty stmts)- (core_stmt, fv_stmt) <- dsCmdLStmt ids local_vars env_ids' stmt env_ids- return (do_compose ids- (mkBigCoreVarTupTy env_ids)- (mkBigCoreVarTupTy env_ids')- res_ty- core_stmt- core_stmts,- fv_stmt)--\end{code}-A statement maps one local environment to another, and is represented-as an arrow from one tuple type to another. A statement sequence is-translated to a composition of such arrows.-\begin{code}-dsCmdLStmt :: DsCmdEnv -> IdSet -> [Id] -> CmdLStmt Id -> [Id]- -> DsM (CoreExpr, IdSet)-dsCmdLStmt ids local_vars out_ids cmd env_ids- = dsCmdStmt ids local_vars out_ids (unLoc cmd) env_ids--dsCmdStmt- :: DsCmdEnv -- arrow combinators- -> IdSet -- set of local vars available to this statement- -> [Id] -- list of vars in the output of this statement- -> CmdStmt Id -- statement to desugar- -> [Id] -- list of vars in the input to this statement- -- This is typically fed back,- -- so don't pull on it too early- -> DsM (CoreExpr, -- desugared expression- IdSet) -- subset of local vars that occur free---- D; xs1 |-a c : () --> t--- D; xs' |-a do { ss } : t'--- --------------------------------- D; xs |-a do { c; ss } : t'------ ---> premap (\ ((xs)) -> (((xs1),()),(xs')))--- (first c >>> arr snd) >>> ss--dsCmdStmt ids local_vars out_ids (BodyStmt cmd _ _ c_ty) env_ids = do- (core_cmd, fv_cmd, env_ids1) <- dsfixCmd ids local_vars unitTy c_ty cmd- core_mux <- matchEnv env_ids- (mkCorePairExpr- (mkCorePairExpr (mkBigCoreVarTup env_ids1) mkCoreUnitExpr)- (mkBigCoreVarTup out_ids))- let- in_ty = mkBigCoreVarTupTy env_ids- in_ty1 = mkCorePairTy (mkBigCoreVarTupTy env_ids1) unitTy- out_ty = mkBigCoreVarTupTy out_ids- before_c_ty = mkCorePairTy in_ty1 out_ty- after_c_ty = mkCorePairTy c_ty out_ty- snd_fn <- mkSndExpr c_ty out_ty- return (do_premap ids in_ty before_c_ty out_ty core_mux $- do_compose ids before_c_ty after_c_ty out_ty- (do_first ids in_ty1 c_ty out_ty core_cmd) $- do_arr ids after_c_ty out_ty snd_fn,- extendVarSetList fv_cmd out_ids)---- D; xs1 |-a c : () --> t--- D; xs' |-a do { ss } : t' xs2 = xs' - defs(p)--- -------------------------------------- D; xs |-a do { p <- c; ss } : t'------ ---> premap (\ (xs) -> (((xs1),()),(xs2)))--- (first c >>> arr (\ (p, (xs2)) -> (xs'))) >>> ss------ It would be simpler and more consistent to do this using second,--- but that's likely to be defined in terms of first.--dsCmdStmt ids local_vars out_ids (BindStmt pat cmd _ _) env_ids = do- (core_cmd, fv_cmd, env_ids1) <- dsfixCmd ids local_vars unitTy (hsLPatType pat) cmd- let- pat_ty = hsLPatType pat- pat_vars = mkVarSet (collectPatBinders pat)- env_ids2 = varSetElems (mkVarSet out_ids `minusVarSet` pat_vars)- env_ty2 = mkBigCoreVarTupTy env_ids2-- -- multiplexing function- -- \ (xs) -> (((xs1),()),(xs2))-- core_mux <- matchEnv env_ids- (mkCorePairExpr- (mkCorePairExpr (mkBigCoreVarTup env_ids1) mkCoreUnitExpr)- (mkBigCoreVarTup env_ids2))-- -- projection function- -- \ (p, (xs2)) -> (zs)-- env_id <- newSysLocalDs env_ty2- uniqs <- newUniqueSupply- let- after_c_ty = mkCorePairTy pat_ty env_ty2- out_ty = mkBigCoreVarTupTy out_ids- body_expr = coreCaseTuple uniqs env_id env_ids2 (mkBigCoreVarTup out_ids)- - fail_expr <- mkFailExpr (StmtCtxt DoExpr) out_ty- pat_id <- selectSimpleMatchVarL pat- match_code <- matchSimply (Var pat_id) (StmtCtxt DoExpr) pat body_expr fail_expr- pair_id <- newSysLocalDs after_c_ty- let- proj_expr = Lam pair_id (coreCasePair pair_id pat_id env_id match_code)-- -- put it all together- let- in_ty = mkBigCoreVarTupTy env_ids- in_ty1 = mkCorePairTy (mkBigCoreVarTupTy env_ids1) unitTy- in_ty2 = mkBigCoreVarTupTy env_ids2- before_c_ty = mkCorePairTy in_ty1 in_ty2- return (do_premap ids in_ty before_c_ty out_ty core_mux $- do_compose ids before_c_ty after_c_ty out_ty- (do_first ids in_ty1 pat_ty in_ty2 core_cmd) $- do_arr ids after_c_ty out_ty proj_expr,- fv_cmd `unionVarSet` (mkVarSet out_ids `minusVarSet` pat_vars))---- D; xs' |-a do { ss } : t--- ----------------------------------------- D; xs |-a do { let binds; ss } : t------ ---> arr (\ (xs) -> let binds in (xs')) >>> ss--dsCmdStmt ids local_vars out_ids (LetStmt binds) env_ids = do- -- build a new environment using the let bindings- core_binds <- dsLocalBinds binds (mkBigCoreVarTup out_ids)- -- match the old environment against the input- core_map <- matchEnv env_ids core_binds- return (do_arr ids- (mkBigCoreVarTupTy env_ids)- (mkBigCoreVarTupTy out_ids)- core_map,- exprFreeIds core_binds `intersectVarSet` local_vars)---- D; ys |-a do { ss; returnA -< ((xs1), (ys2)) } : ...--- D; xs' |-a do { ss' } : t--- --------------------------------------- D; xs |-a do { rec ss; ss' } : t------ xs1 = xs' /\ defs(ss)--- xs2 = xs' - defs(ss)--- ys1 = ys - defs(ss)--- ys2 = ys /\ defs(ss)------ ---> arr (\(xs) -> ((ys1),(xs2))) >>>--- first (loop (arr (\((ys1),~(ys2)) -> (ys)) >>> ss)) >>>--- arr (\((xs1),(xs2)) -> (xs')) >>> ss'--dsCmdStmt ids local_vars out_ids- (RecStmt { recS_stmts = stmts- , recS_later_ids = later_ids, recS_rec_ids = rec_ids- , recS_later_rets = later_rets, recS_rec_rets = rec_rets })- env_ids = do- let- env2_id_set = mkVarSet out_ids `minusVarSet` mkVarSet later_ids- env2_ids = varSetElems env2_id_set- env2_ty = mkBigCoreVarTupTy env2_ids-- -- post_loop_fn = \((later_ids),(env2_ids)) -> (out_ids)-- uniqs <- newUniqueSupply- env2_id <- newSysLocalDs env2_ty- let- later_ty = mkBigCoreVarTupTy later_ids- post_pair_ty = mkCorePairTy later_ty env2_ty- post_loop_body = coreCaseTuple uniqs env2_id env2_ids (mkBigCoreVarTup out_ids)-- post_loop_fn <- matchEnvStack later_ids env2_id post_loop_body-- --- loop (...)-- (core_loop, env1_id_set, env1_ids)- <- dsRecCmd ids local_vars stmts later_ids later_rets rec_ids rec_rets-- -- pre_loop_fn = \(env_ids) -> ((env1_ids),(env2_ids))-- let- env1_ty = mkBigCoreVarTupTy env1_ids- pre_pair_ty = mkCorePairTy env1_ty env2_ty- pre_loop_body = mkCorePairExpr (mkBigCoreVarTup env1_ids)- (mkBigCoreVarTup env2_ids)-- pre_loop_fn <- matchEnv env_ids pre_loop_body-- -- arr pre_loop_fn >>> first (loop (...)) >>> arr post_loop_fn-- let- env_ty = mkBigCoreVarTupTy env_ids- out_ty = mkBigCoreVarTupTy out_ids- core_body = do_premap ids env_ty pre_pair_ty out_ty- pre_loop_fn- (do_compose ids pre_pair_ty post_pair_ty out_ty- (do_first ids env1_ty later_ty env2_ty- core_loop)- (do_arr ids post_pair_ty out_ty- post_loop_fn))-- return (core_body, env1_id_set `unionVarSet` env2_id_set)--dsCmdStmt _ _ _ _ s = pprPanic "dsCmdStmt" (ppr s)---- loop (premap (\ ((env1_ids), ~(rec_ids)) -> (env_ids))--- (ss >>> arr (\ (out_ids) -> ((later_rets),(rec_rets))))) >>>--dsRecCmd- :: DsCmdEnv -- arrow combinators- -> IdSet -- set of local vars available to this statement- -> [CmdLStmt Id] -- list of statements inside the RecCmd- -> [Id] -- list of vars defined here and used later- -> [HsExpr Id] -- expressions corresponding to later_ids- -> [Id] -- list of vars fed back through the loop- -> [HsExpr Id] -- expressions corresponding to rec_ids- -> DsM (CoreExpr, -- desugared statement- IdSet, -- subset of local vars that occur free- [Id]) -- same local vars as a list--dsRecCmd ids local_vars stmts later_ids later_rets rec_ids rec_rets = do- let- later_id_set = mkVarSet later_ids- rec_id_set = mkVarSet rec_ids- local_vars' = rec_id_set `unionVarSet` later_id_set `unionVarSet` local_vars-- -- mk_pair_fn = \ (out_ids) -> ((later_rets),(rec_rets))-- core_later_rets <- mapM dsExpr later_rets- core_rec_rets <- mapM dsExpr rec_rets- let- -- possibly polymorphic version of vars of later_ids and rec_ids- out_ids = varSetElems (unionVarSets (map exprFreeIds (core_later_rets ++ core_rec_rets)))- out_ty = mkBigCoreVarTupTy out_ids-- later_tuple = mkBigCoreTup core_later_rets- later_ty = mkBigCoreVarTupTy later_ids-- rec_tuple = mkBigCoreTup core_rec_rets- rec_ty = mkBigCoreVarTupTy rec_ids-- out_pair = mkCorePairExpr later_tuple rec_tuple- out_pair_ty = mkCorePairTy later_ty rec_ty-- mk_pair_fn <- matchEnv out_ids out_pair-- -- ss-- (core_stmts, fv_stmts, env_ids) <- dsfixCmdStmts ids local_vars' out_ids stmts-- -- squash_pair_fn = \ ((env1_ids), ~(rec_ids)) -> (env_ids)-- rec_id <- newSysLocalDs rec_ty- let- env1_id_set = fv_stmts `minusVarSet` rec_id_set- env1_ids = varSetElems env1_id_set- env1_ty = mkBigCoreVarTupTy env1_ids- in_pair_ty = mkCorePairTy env1_ty rec_ty- core_body = mkBigCoreTup (map selectVar env_ids)- where- selectVar v- | v `elemVarSet` rec_id_set- = mkTupleSelector rec_ids v rec_id (Var rec_id)- | otherwise = Var v-- squash_pair_fn <- matchEnvStack env1_ids rec_id core_body-- -- loop (premap squash_pair_fn (ss >>> arr mk_pair_fn))-- let- env_ty = mkBigCoreVarTupTy env_ids- core_loop = do_loop ids env1_ty later_ty rec_ty- (do_premap ids in_pair_ty env_ty out_pair_ty- squash_pair_fn- (do_compose ids env_ty out_ty out_pair_ty- core_stmts- (do_arr ids out_ty out_pair_ty mk_pair_fn)))-- return (core_loop, env1_id_set, env1_ids)--\end{code}-A sequence of statements (as in a rec) is desugared to an arrow between-two environments (no stack)-\begin{code}--dsfixCmdStmts- :: DsCmdEnv -- arrow combinators- -> IdSet -- set of local vars available to this statement- -> [Id] -- output vars of these statements- -> [CmdLStmt Id] -- statements to desugar- -> DsM (CoreExpr, -- desugared expression- IdSet, -- subset of local vars that occur free- [Id]) -- same local vars as a list--dsfixCmdStmts ids local_vars out_ids stmts- = trimInput (dsCmdStmts ids local_vars out_ids stmts)--dsCmdStmts- :: DsCmdEnv -- arrow combinators- -> IdSet -- set of local vars available to this statement- -> [Id] -- output vars of these statements- -> [CmdLStmt Id] -- statements to desugar- -> [Id] -- list of vars in the input to these statements- -> DsM (CoreExpr, -- desugared expression- IdSet) -- subset of local vars that occur free--dsCmdStmts ids local_vars out_ids [stmt] env_ids- = dsCmdLStmt ids local_vars out_ids stmt env_ids--dsCmdStmts ids local_vars out_ids (stmt:stmts) env_ids = do- let- bound_vars = mkVarSet (collectLStmtBinders stmt)- local_vars' = bound_vars `unionVarSet` local_vars- (core_stmts, _fv_stmts, env_ids') <- dsfixCmdStmts ids local_vars' out_ids stmts- (core_stmt, fv_stmt) <- dsCmdLStmt ids local_vars env_ids' stmt env_ids- return (do_compose ids- (mkBigCoreVarTupTy env_ids)- (mkBigCoreVarTupTy env_ids')- (mkBigCoreVarTupTy out_ids)- core_stmt- core_stmts,- fv_stmt)--dsCmdStmts _ _ _ [] _ = panic "dsCmdStmts []"-\end{code}--Match a list of expressions against a list of patterns, left-to-right.--\begin{code}-matchSimplys :: [CoreExpr] -- Scrutinees- -> HsMatchContext Name -- Match kind- -> [LPat Id] -- Patterns they should match- -> CoreExpr -- Return this if they all match- -> CoreExpr -- Return this if they don't- -> DsM CoreExpr-matchSimplys [] _ctxt [] result_expr _fail_expr = return result_expr-matchSimplys (exp:exps) ctxt (pat:pats) result_expr fail_expr = do- match_code <- matchSimplys exps ctxt pats result_expr fail_expr- matchSimply exp ctxt pat match_code fail_expr-matchSimplys _ _ _ _ _ = panic "matchSimplys"-\end{code}--List of leaf expressions, with set of variables bound in each--\begin{code}-leavesMatch :: LMatch Id (Located (body Id)) -> [(Located (body Id), IdSet)]-leavesMatch (L _ (Match pats _ (GRHSs grhss binds)))- = let- defined_vars = mkVarSet (collectPatsBinders pats)- `unionVarSet`- mkVarSet (collectLocalBinders binds)- in- [(body, - mkVarSet (collectLStmtsBinders stmts) - `unionVarSet` defined_vars) - | L _ (GRHS stmts body) <- grhss]-\end{code}--Replace the leaf commands in a match--\begin{code}-replaceLeavesMatch- :: Type -- new result type- -> [Located (body' Id)] -- replacement leaf expressions of that type- -> LMatch Id (Located (body Id)) -- the matches of a case command- -> ([Located (body' Id)], -- remaining leaf expressions- LMatch Id (Located (body' Id))) -- updated match-replaceLeavesMatch _res_ty leaves (L loc (Match pat mt (GRHSs grhss binds)))- = let- (leaves', grhss') = mapAccumL replaceLeavesGRHS leaves grhss- in- (leaves', L loc (Match pat mt (GRHSs grhss' binds)))--replaceLeavesGRHS- :: [Located (body' Id)] -- replacement leaf expressions of that type- -> LGRHS Id (Located (body Id)) -- rhss of a case command- -> ([Located (body' Id)], -- remaining leaf expressions- LGRHS Id (Located (body' Id))) -- updated GRHS-replaceLeavesGRHS (leaf:leaves) (L loc (GRHS stmts _))- = (leaves, L loc (GRHS stmts leaf))-replaceLeavesGRHS [] _ = panic "replaceLeavesGRHS []"-\end{code}--Balanced fold of a non-empty list.--\begin{code}-foldb :: (a -> a -> a) -> [a] -> a-foldb _ [] = error "foldb of empty list"-foldb _ [x] = x-foldb f xs = foldb f (fold_pairs xs)- where- fold_pairs [] = []- fold_pairs [x] = [x]- fold_pairs (x1:x2:xs) = f x1 x2:fold_pairs xs-\end{code}--Note [Dictionary binders in ConPatOut] See also same Note in HsUtils-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~-The following functions to collect value variables from patterns are-copied from HsUtils, with one change: we also collect the dictionary-bindings (pat_binds) from ConPatOut. We need them for cases like--h :: Arrow a => Int -> a (Int,Int) Int-h x = proc (y,z) -> case compare x y of- GT -> returnA -< z+x--The type checker turns the case into-- case compare x y of- GT { p77 = plusInt } -> returnA -< p77 z x--Here p77 is a local binding for the (+) operation.--See comments in HsUtils for why the other version does not include-these bindings.--\begin{code}-collectPatBinders :: LPat Id -> [Id]-collectPatBinders pat = collectl pat []--collectPatsBinders :: [LPat Id] -> [Id]-collectPatsBinders pats = foldr collectl [] pats------------------------collectl :: LPat Id -> [Id] -> [Id]--- See Note [Dictionary binders in ConPatOut]-collectl (L _ pat) bndrs- = go pat- where- go (VarPat var) = var : bndrs- go (WildPat _) = bndrs- go (LazyPat pat) = collectl pat bndrs- go (BangPat pat) = collectl pat bndrs- go (AsPat (L _ a) pat) = a : collectl pat bndrs- go (ParPat pat) = collectl pat bndrs-- go (ListPat pats _ _) = foldr collectl bndrs pats- go (PArrPat pats _) = foldr collectl bndrs pats- go (TuplePat pats _ _) = foldr collectl bndrs pats-- go (ConPatIn _ ps) = foldr collectl bndrs (hsConPatArgs ps)- go (ConPatOut {pat_args=ps, pat_binds=ds}) =- collectEvBinders ds- ++ foldr collectl bndrs (hsConPatArgs ps)- go (LitPat _) = bndrs- go (NPat _ _ _) = bndrs- go (NPlusKPat (L _ n) _ _ _) = n : bndrs-- go (SigPatIn pat _) = collectl pat bndrs- go (SigPatOut pat _) = collectl pat bndrs- go (CoPat _ pat _) = collectl (noLoc pat) bndrs- go (ViewPat _ pat _) = collectl pat bndrs- go p@(SplicePat {}) = pprPanic "collectl/go" (ppr p)- go p@(QuasiQuotePat {}) = pprPanic "collectl/go" (ppr p)--collectEvBinders :: TcEvBinds -> [Id]-collectEvBinders (EvBinds bs) = foldrBag add_ev_bndr [] bs-collectEvBinders (TcEvBinds {}) = panic "ToDo: collectEvBinders"--add_ev_bndr :: EvBind -> [Id] -> [Id]-add_ev_bndr (EvBind b _) bs | isId b = b:bs- | otherwise = bs- -- A worry: what about coercion variable binders??--collectLStmtsBinders :: [LStmt Id body] -> [Id]-collectLStmtsBinders = concatMap collectLStmtBinders--collectLStmtBinders :: LStmt Id body -> [Id]-collectLStmtBinders = collectStmtBinders . unLoc--collectStmtBinders :: Stmt Id body -> [Id]-collectStmtBinders (BindStmt pat _ _ _) = collectPatBinders pat-collectStmtBinders (LetStmt binds) = collectLocalBinders binds-collectStmtBinders (BodyStmt {}) = []-collectStmtBinders (LastStmt {}) = []-collectStmtBinders (ParStmt xs _ _) = collectLStmtsBinders- $ [ s | ParStmtBlock ss _ _ <- xs, s <- ss]-collectStmtBinders (TransStmt { trS_stmts = stmts }) = collectLStmtsBinders stmts-collectStmtBinders (RecStmt { recS_later_ids = later_ids }) = later_ids--\end{code}
− src/Language/Haskell/Liquid/Desugar/DsBinds.lhs
@@ -1,900 +0,0 @@-%-% (c) The University of Glasgow 2006-% (c) The GRASP/AQUA Project, Glasgow University, 1992-1998-%--Pattern-matching bindings (HsBinds and MonoBinds)--Handles @HsBinds@; those at the top level require different handling,-in that the @Rec@/@NonRec@/etc structure is thrown away (whereas at-lower levels it is preserved with @let@/@letrec@s).--\begin{code}-{-# OPTIONS -fno-warn-tabs #-}--- The above warning supression flag is a temporary kludge.--- While working on this module you are encouraged to remove it and--- detab the module (please do the detabbing in a separate patch). See--- http://ghc.haskell.org/trac/ghc/wiki/Commentary/CodingStyle#TabsvsSpaces--- for details--module Language.Haskell.Liquid.Desugar.DsBinds ( dsTopLHsBinds, dsLHsBinds, decomposeRuleLhs, dsSpec,- dsHsWrapper, dsTcEvBinds, dsEvBinds- ) where---- #include "HsVersions.h"--import {-# SOURCE #-} Language.Haskell.Liquid.Desugar.DsExpr( dsLExpr )-import {-# SOURCE #-} Language.Haskell.Liquid.Desugar.Match( matchWrapper )--import DsMonad-import Language.Haskell.Liquid.Desugar.DsGRHSs-import Language.Haskell.Liquid.Desugar.DsUtils--import HsSyn -- lots of things-import CoreSyn -- lots of things-import Literal ( Literal(MachStr) )-import CoreSubst-import MkCore-import CoreUtils-import CoreArity ( etaExpand )-import CoreUnfold-import CoreFVs-import UniqSupply-import Unique( Unique )-import Digraph---import TyCon ( tyConDataCons_maybe )-import TcEvidence-import TcType-import Type-import Coercion hiding (substCo)-import TysWiredIn ( eqBoxDataCon, coercibleDataCon, tupleCon )-import Id-import Class-import DataCon ( dataConWorkId )-import Name-import MkId ( seqId )-import Var-import VarSet-import Rules-import VarEnv-import Outputable-import SrcLoc-import Maybes-import OrdList-import Bag-import BasicTypes hiding ( TopLevel )-import DynFlags-import FastString-import ErrUtils( MsgDoc )-import ListSetOps( getNth )-import Util-import Control.Monad( when )-import MonadUtils-import Control.Monad(liftM)-\end{code}--%************************************************************************-%* *-\subsection[dsMonoBinds]{Desugaring a @MonoBinds@}-%* *-%************************************************************************--\begin{code}-dsTopLHsBinds :: LHsBinds Id -> DsM (OrdList (Id,CoreExpr))-dsTopLHsBinds binds = ds_lhs_binds binds--dsLHsBinds :: LHsBinds Id -> DsM [(Id,CoreExpr)]-dsLHsBinds binds = do { binds' <- ds_lhs_binds binds- ; return (fromOL binds') }---------------------------ds_lhs_binds :: LHsBinds Id -> DsM (OrdList (Id,CoreExpr))--ds_lhs_binds binds = do { ds_bs <- mapBagM dsLHsBind binds- ; return (foldBag appOL id nilOL ds_bs) }--dsLHsBind :: LHsBind Id -> DsM (OrdList (Id,CoreExpr))-dsLHsBind (L loc bind) = putSrcSpanDs loc $ dsHsBind bind--dsHsBind :: HsBind Id -> DsM (OrdList (Id,CoreExpr))--dsHsBind (VarBind { var_id = var, var_rhs = expr, var_inline = inline_regardless })- = do { dflags <- getDynFlags- ; core_expr <- dsLExpr expr-- -- Dictionary bindings are always VarBinds,- -- so we only need do this here- ; let var' | inline_regardless = var `setIdUnfolding` mkCompulsoryUnfolding core_expr- | otherwise = var-- ; return (unitOL (makeCorePair dflags var' False 0 core_expr)) }--dsHsBind (FunBind { fun_id = L _ fun, fun_matches = matches- , fun_co_fn = co_fn, fun_tick = tick- , fun_infix = inf })- = do { dflags <- getDynFlags- ; (args, body) <- matchWrapper (FunRhs (idName fun) inf) matches- ; let body' = mkOptTickBox tick body- ; rhs <- dsHsWrapper co_fn (mkLams args body')- ; {- pprTrace "dsHsBind" (ppr fun <+> ppr (idInlinePragma fun)) $ -}- return (unitOL (makeCorePair dflags fun False 0 rhs)) }--dsHsBind (PatBind { pat_lhs = pat, pat_rhs = grhss, pat_rhs_ty = ty- , pat_ticks = (rhs_tick, var_ticks) })- = do { body_expr <- dsGuarded grhss ty- ; let body' = mkOptTickBox rhs_tick body_expr- ; sel_binds <- mkSelectorBinds var_ticks pat body'- -- We silently ignore inline pragmas; no makeCorePair- -- Not so cool, but really doesn't matter- ; return (toOL sel_binds) }-- -- A common case: one exported variable- -- Non-recursive bindings come through this way- -- So do self-recursive bindings, and recursive bindings- -- that have been chopped up with type signatures-dsHsBind (AbsBinds { abs_tvs = tyvars, abs_ev_vars = dicts- , abs_exports = [export]- , abs_ev_binds = ev_binds, abs_binds = binds })- | ABE { abe_wrap = wrap, abe_poly = global- , abe_mono = local, abe_prags = prags } <- export- = do { dflags <- getDynFlags- ; bind_prs <- ds_lhs_binds binds- ; let core_bind = Rec (fromOL bind_prs)- ; ds_binds <- dsTcEvBinds ev_binds- ; rhs <- dsHsWrapper wrap $ -- Usually the identity- mkLams tyvars $ mkLams dicts $ - mkCoreLets ds_binds $- Let core_bind $- Var local- - ; (spec_binds, rules) <- dsSpecs rhs prags-- ; let global' = addIdSpecialisations global rules- main_bind = makeCorePair dflags global' (isDefaultMethod prags)- (dictArity dicts) rhs - - ; return (main_bind `consOL` spec_binds) }--dsHsBind (AbsBinds { abs_tvs = tyvars, abs_ev_vars = dicts- , abs_exports = exports, abs_ev_binds = ev_binds- , abs_binds = binds })- -- See Note [Desugaring AbsBinds]- = do { dflags <- getDynFlags- ; bind_prs <- ds_lhs_binds binds- ; let core_bind = Rec [ makeCorePair dflags (add_inline lcl_id) False 0 rhs- | (lcl_id, rhs) <- fromOL bind_prs ]- -- Monomorphic recursion possible, hence Rec-- locals = map abe_mono exports- tup_expr = mkBigCoreVarTup locals- tup_ty = exprType tup_expr- ; ds_binds <- dsTcEvBinds ev_binds- ; let poly_tup_rhs = mkLams tyvars $ mkLams dicts $- mkCoreLets ds_binds $- Let core_bind $- tup_expr-- ; poly_tup_id <- newSysLocalDs (exprType poly_tup_rhs)-- ; let mk_bind (ABE { abe_wrap = wrap, abe_poly = global- , abe_mono = local, abe_prags = spec_prags })- = do { tup_id <- newSysLocalDs tup_ty- ; rhs <- dsHsWrapper wrap $ - mkLams tyvars $ mkLams dicts $- mkTupleSelector locals local tup_id $- mkVarApps (Var poly_tup_id) (tyvars ++ dicts)- ; let rhs_for_spec = Let (NonRec poly_tup_id poly_tup_rhs) rhs- ; (spec_binds, rules) <- dsSpecs rhs_for_spec spec_prags- ; let global' = (global `setInlinePragma` defaultInlinePragma)- `addIdSpecialisations` rules- -- Kill the INLINE pragma because it applies to- -- the user written (local) function. The global- -- Id is just the selector. Hmm. - ; return ((global', rhs) `consOL` spec_binds) }-- ; export_binds_s <- mapM mk_bind exports-- ; return ((poly_tup_id, poly_tup_rhs) `consOL` - concatOL export_binds_s) }- where- inline_env :: IdEnv Id -- Maps a monomorphic local Id to one with- -- the inline pragma from the source- -- The type checker put the inline pragma- -- on the *global* Id, so we need to transfer it- inline_env = mkVarEnv [ (lcl_id, setInlinePragma lcl_id prag)- | ABE { abe_mono = lcl_id, abe_poly = gbl_id } <- exports- , let prag = idInlinePragma gbl_id ]-- add_inline :: Id -> Id -- tran- add_inline lcl_id = lookupVarEnv inline_env lcl_id `orElse` lcl_id--dsHsBind (PatSynBind{}) = panic "dsHsBind: PatSynBind"---------------------------makeCorePair :: DynFlags -> Id -> Bool -> Arity -> CoreExpr -> (Id, CoreExpr)-makeCorePair dflags gbl_id is_default_method dict_arity rhs- | is_default_method -- Default methods are *always* inlined- = (gbl_id `setIdUnfolding` mkCompulsoryUnfolding rhs, rhs)-- | otherwise- = case inlinePragmaSpec inline_prag of- EmptyInlineSpec -> (gbl_id, rhs)- NoInline -> (gbl_id, rhs)- Inlinable -> (gbl_id `setIdUnfolding` inlinable_unf, rhs)- Inline -> inline_pair-- where- inline_prag = idInlinePragma gbl_id- inlinable_unf = mkInlinableUnfolding dflags rhs- inline_pair- | Just arity <- inlinePragmaSat inline_prag- -- Add an Unfolding for an INLINE (but not for NOINLINE)- -- And eta-expand the RHS; see Note [Eta-expanding INLINE things]- , let real_arity = dict_arity + arity- -- NB: The arity in the InlineRule takes account of the dictionaries- = ( gbl_id `setIdUnfolding` mkInlineUnfolding (Just real_arity) rhs- , etaExpand real_arity rhs)-- | otherwise- = pprTrace "makeCorePair: arity missing" (ppr gbl_id) $- (gbl_id `setIdUnfolding` mkInlineUnfolding Nothing rhs, rhs)---dictArity :: [Var] -> Arity--- Don't count coercion variables in arity-dictArity dicts = count isId dicts-\end{code}--[Desugaring AbsBinds]-~~~~~~~~~~~~~~~~~~~~~-In the general AbsBinds case we desugar the binding to this:-- tup a (d:Num a) = let fm = ...gm...- gm = ...fm...- in (fm,gm)- f a d = case tup a d of { (fm,gm) -> fm }- g a d = case tup a d of { (fm,gm) -> fm }--Note [Rules and inlining]-~~~~~~~~~~~~~~~~~~~~~~~~~-Common special case: no type or dictionary abstraction-This is a bit less trivial than you might suppose-The naive way woudl be to desguar to something like- f_lcl = ...f_lcl... -- The "binds" from AbsBinds- M.f = f_lcl -- Generated from "exports"-But we don't want that, because if M.f isn't exported,-it'll be inlined unconditionally at every call site (its rhs is -trivial). That would be ok unless it has RULES, which would -thereby be completely lost. Bad, bad, bad.--Instead we want to generate- M.f = ...f_lcl...- f_lcl = M.f-Now all is cool. The RULES are attached to M.f (by SimplCore), -and f_lcl is rapidly inlined away.--This does not happen in the same way to polymorphic binds,-because they desugar to- M.f = /\a. let f_lcl = ...f_lcl... in f_lcl-Although I'm a bit worried about whether full laziness might-float the f_lcl binding out and then inline M.f at its call site--Note [Specialising in no-dict case]-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~-Even if there are no tyvars or dicts, we may have specialisation pragmas.-Class methods can generate- AbsBinds [] [] [( ... spec-prag]- { AbsBinds [tvs] [dicts] ...blah }-So the overloading is in the nested AbsBinds. A good example is in GHC.Float:-- class (Real a, Fractional a) => RealFrac a where- round :: (Integral b) => a -> b-- instance RealFrac Float where- {-# SPECIALIZE round :: Float -> Int #-}--The top-level AbsBinds for $cround has no tyvars or dicts (because the -instance does not). But the method is locally overloaded!--Note [Abstracting over tyvars only]-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~-When abstracting over type variable only (not dictionaries), we don't really need to-built a tuple and select from it, as we do in the general case. Instead we can take-- AbsBinds [a,b] [ ([a,b], fg, fl, _),- ([b], gg, gl, _) ]- { fl = e1- gl = e2- h = e3 }--and desugar it to-- fg = /\ab. let B in e1- gg = /\b. let a = () in let B in S(e2)- h = /\ab. let B in e3--where B is the *non-recursive* binding- fl = fg a b- gl = gg b- h = h a b -- See (b); note shadowing!--Notice (a) g has a different number of type variables to f, so we must- use the mkArbitraryType thing to fill in the gaps. - We use a type-let to do that.-- (b) The local variable h isn't in the exports, and rather than- clone a fresh copy we simply replace h by (h a b), where- the two h's have different types! Shadowing happens here,- which looks confusing but works fine.-- (c) The result is *still* quadratic-sized if there are a lot of- small bindings. So if there are more than some small- number (10), we filter the binding set B by the free- variables of the particular RHS. Tiresome.--Why got to this trouble? It's a common case, and it removes the-quadratic-sized tuple desugaring. Less clutter, hopefullly faster-compilation, especially in a case where there are a *lot* of-bindings.---Note [Eta-expanding INLINE things]-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~-Consider- foo :: Eq a => a -> a- {-# INLINE foo #-}- foo x = ...--If (foo d) ever gets floated out as a common sub-expression (which can-happen as a result of method sharing), there's a danger that we never -get to do the inlining, which is a Terribly Bad thing given that the-user said "inline"!--To avoid this we pre-emptively eta-expand the definition, so that foo-has the arity with which it is declared in the source code. In this-example it has arity 2 (one for the Eq and one for x). Doing this -should mean that (foo d) is a PAP and we don't share it.--Note [Nested arities]-~~~~~~~~~~~~~~~~~~~~~-For reasons that are not entirely clear, method bindings come out looking like-this:-- AbsBinds [] [] [$cfromT <= [] fromT]- $cfromT [InlPrag=INLINE] :: T Bool -> Bool- { AbsBinds [] [] [fromT <= [] fromT_1]- fromT :: T Bool -> Bool- { fromT_1 ((TBool b)) = not b } } }--Note the nested AbsBind. The arity for the InlineRule on $cfromT should be-gotten from the binding for fromT_1.--It might be better to have just one level of AbsBinds, but that requires more-thought!--Note [Implementing SPECIALISE pragmas]-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~-Example:- f :: (Eq a, Ix b) => a -> b -> Bool- {-# SPECIALISE f :: (Ix p, Ix q) => Int -> (p,q) -> Bool #-}- f = <poly_rhs>--From this the typechecker generates-- AbsBinds [ab] [d1,d2] [([ab], f, f_mono, prags)] binds-- SpecPrag (wrap_fn :: forall a b. (Eq a, Ix b) => XXX- -> forall p q. (Ix p, Ix q) => XXX[ Int/a, (p,q)/b ])--Note that wrap_fn can transform *any* function with the right type prefix - forall ab. (Eq a, Ix b) => XXX-regardless of XXX. It's sort of polymorphic in XXX. This is-useful: we use the same wrapper to transform each of the class ops, as-well as the dict.--From these we generate:-- Rule: forall p, q, (dp:Ix p), (dq:Ix q). - f Int (p,q) dInt ($dfInPair dp dq) = f_spec p q dp dq-- Spec bind: f_spec = wrap_fn <poly_rhs>--Note that -- * The LHS of the rule may mention dictionary *expressions* (eg- $dfIxPair dp dq), and that is essential because the dp, dq are- needed on the RHS.-- * The RHS of f_spec, <poly_rhs> has a *copy* of 'binds', so that it - can fully specialise it.--\begin{code}--------------------------dsSpecs :: CoreExpr -- Its rhs- -> TcSpecPrags- -> DsM ( OrdList (Id,CoreExpr) -- Binding for specialised Ids- , [CoreRule] ) -- Rules for the Global Ids--- See Note [Implementing SPECIALISE pragmas]-dsSpecs _ IsDefaultMethod = return (nilOL, [])-dsSpecs poly_rhs (SpecPrags sps)- = do { pairs <- mapMaybeM (dsSpec (Just poly_rhs)) sps- ; let (spec_binds_s, rules) = unzip pairs- ; return (concatOL spec_binds_s, rules) }--dsSpec :: Maybe CoreExpr -- Just rhs => RULE is for a local binding- -- Nothing => RULE is for an imported Id- -- rhs is in the Id's unfolding- -> Located TcSpecPrag- -> DsM (Maybe (OrdList (Id,CoreExpr), CoreRule))-dsSpec mb_poly_rhs (L loc (SpecPrag poly_id spec_co spec_inl))- | isJust (isClassOpId_maybe poly_id)- = putSrcSpanDs loc $ - do { warnDs (ptext (sLit "Ignoring useless SPECIALISE pragma for class method selector") - <+> quotes (ppr poly_id))- ; return Nothing } -- There is no point in trying to specialise a class op- -- Moreover, classops don't (currently) have an inl_sat arity set- -- (it would be Just 0) and that in turn makes makeCorePair bleat-- | no_act_spec && isNeverActive rule_act - = putSrcSpanDs loc $ - do { warnDs (ptext (sLit "Ignoring useless SPECIALISE pragma for NOINLINE function:")- <+> quotes (ppr poly_id))- ; return Nothing } -- Function is NOINLINE, and the specialiation inherits that- -- See Note [Activation pragmas for SPECIALISE]-- | otherwise- = putSrcSpanDs loc $ - do { uniq <- newUnique- ; let poly_name = idName poly_id- spec_occ = mkSpecOcc (getOccName poly_name)- spec_name = mkInternalName uniq spec_occ (getSrcSpan poly_name)- ; (bndrs, ds_lhs) <- liftM collectBinders- (dsHsWrapper spec_co (Var poly_id))- ; let spec_ty = mkPiTypes bndrs (exprType ds_lhs)- ; case decomposeRuleLhs bndrs ds_lhs of {- Left msg -> do { warnDs msg; return Nothing } ;- Right (rule_bndrs, _fn, args) -> do-- { dflags <- getDynFlags- ; let spec_unf = specUnfolding bndrs args (realIdUnfolding poly_id)- spec_id = mkLocalId spec_name spec_ty - `setInlinePragma` inl_prag- `setIdUnfolding` spec_unf- rule = mkRule False {- Not auto -} is_local_id- (mkFastString ("SPEC " ++ showPpr dflags poly_name))- rule_act poly_name- rule_bndrs args- (mkVarApps (Var spec_id) bndrs)-- ; spec_rhs <- dsHsWrapper spec_co poly_rhs- ; let spec_pair = makeCorePair dflags spec_id False (dictArity bndrs) spec_rhs-- ; when (isInlinePragma id_inl && wopt Opt_WarnPointlessPragmas dflags)- (warnDs (specOnInline poly_name))- ; return (Just (unitOL spec_pair, rule))- } } }- where- is_local_id = isJust mb_poly_rhs- poly_rhs | Just rhs <- mb_poly_rhs- = rhs -- Local Id; this is its rhs- | Just unfolding <- maybeUnfoldingTemplate (realIdUnfolding poly_id)- = unfolding -- Imported Id; this is its unfolding- -- Use realIdUnfolding so we get the unfolding - -- even when it is a loop breaker. - -- We want to specialise recursive functions!- | otherwise = pprPanic "dsImpSpecs" (ppr poly_id)- -- The type checker has checked that it *has* an unfolding-- id_inl = idInlinePragma poly_id-- -- See Note [Activation pragmas for SPECIALISE]- inl_prag | not (isDefaultInlinePragma spec_inl) = spec_inl- | not is_local_id -- See Note [Specialising imported functions]- -- in OccurAnal- , isStrongLoopBreaker (idOccInfo poly_id) = neverInlinePragma- | otherwise = id_inl- -- Get the INLINE pragma from SPECIALISE declaration, or,- -- failing that, from the original Id-- spec_prag_act = inlinePragmaActivation spec_inl-- -- See Note [Activation pragmas for SPECIALISE]- -- no_act_spec is True if the user didn't write an explicit- -- phase specification in the SPECIALISE pragma- no_act_spec = case inlinePragmaSpec spec_inl of- NoInline -> isNeverActive spec_prag_act- _ -> isAlwaysActive spec_prag_act- rule_act | no_act_spec = inlinePragmaActivation id_inl -- Inherit- | otherwise = spec_prag_act -- Specified by user---specUnfolding :: [Var] -> [CoreExpr] -> Unfolding -> Unfolding-specUnfolding new_bndrs new_args df@(DFunUnfolding { df_bndrs = bndrs, df_args = args })- = -- ASSERT2( equalLength new_args bndrs, ppr df $$ ppr new_args $$ ppr new_bndrs )- df { df_bndrs = new_bndrs, df_args = map (substExpr (text "specUnfolding") subst) args }- where- subst = mkOpenSubst (mkInScopeSet fvs) (bndrs `zip` new_args)- fvs = (exprsFreeVars args `delVarSetList` bndrs) `extendVarSetList` new_bndrs--specUnfolding _ _ _ = noUnfolding--specOnInline :: Name -> MsgDoc-specOnInline f = ptext (sLit "SPECIALISE pragma on INLINE function probably won't fire:") - <+> quotes (ppr f)-\end{code}---Note [Activation pragmas for SPECIALISE]-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~-From a user SPECIALISE pragma for f, we generate- a) A top-level binding spec_fn = rhs- b) A RULE f dOrd = spec_fn--We need two pragma-like things:--* spec_fn's inline pragma: inherited from f's inline pragma (ignoring - activation on SPEC), unless overriden by SPEC INLINE--* Activation of RULE: from SPECIALISE pragma (if activation given)- otherwise from f's inline pragma--This is not obvious (see Trac #5237)!--Examples Rule activation Inline prag on spec'd fn-----------------------------------------------------------------------SPEC [n] f :: ty [n] Always, or NOINLINE [n]- copy f's prag--NOINLINE f-SPEC [n] f :: ty [n] NOINLINE- copy f's prag--NOINLINE [k] f-SPEC [n] f :: ty [n] NOINLINE [k]- copy f's prag--INLINE [k] f-SPEC [n] f :: ty [n] INLINE [k] - copy f's prag--SPEC INLINE [n] f :: ty [n] INLINE [n]- (ignore INLINE prag on f,- same activation for rule and spec'd fn)--NOINLINE [k] f-SPEC f :: ty [n] INLINE [k]---%************************************************************************-%* *-\subsection{Adding inline pragmas}-%* *-%************************************************************************--\begin{code}-decomposeRuleLhs :: [Var] -> CoreExpr -> Either SDoc ([Var], Id, [CoreExpr])--- (decomposeRuleLhs bndrs lhs) takes apart the LHS of a RULE,--- The 'bndrs' are the quantified binders of the rules, but decomposeRuleLhs--- may add some extra dictionary binders (see Note [Constant rule dicts])------ Returns Nothing if the LHS isn't of the expected shape-decomposeRuleLhs bndrs lhs - = -- Note [Simplifying the left-hand side of a RULE]- case collectArgs opt_lhs of- (Var fn, args) -> check_bndrs fn args-- (Case scrut bndr ty [(DEFAULT, _, body)], args)- | isDeadBinder bndr -- Note [Matching seqId]- -> check_bndrs seqId (args' ++ args)- where- args' = [Type (idType bndr), Type ty, scrut, body]- - _other -> Left bad_shape_msg- where- opt_lhs = simpleOptExpr lhs-- check_bndrs fn args- | null dead_bndrs = Right (extra_dict_bndrs ++ bndrs, fn, args)- | otherwise = Left (vcat (map dead_msg dead_bndrs))- where- arg_fvs = exprsFreeVars args-- -- Check for dead binders: Note [Unused spec binders]- dead_bndrs = filterOut (`elemVarSet` arg_fvs) bndrs-- -- Add extra dict binders: Note [Constant rule dicts]- extra_dict_bndrs = [ mkLocalId (localiseName (idName d)) (idType d)- | d <- varSetElems (arg_fvs `delVarSetList` bndrs)- , isDictId d]--- bad_shape_msg = hang (ptext (sLit "RULE left-hand side too complicated to desugar"))- 2 (ppr opt_lhs)- dead_msg bndr = hang (sep [ ptext (sLit "Forall'd") <+> pp_bndr bndr- , ptext (sLit "is not bound in RULE lhs")])- 2 (ppr opt_lhs)- pp_bndr bndr- | isTyVar bndr = ptext (sLit "type variable") <+> quotes (ppr bndr)- | Just pred <- evVarPred_maybe bndr = ptext (sLit "constraint") <+> quotes (ppr pred)- | otherwise = ptext (sLit "variable") <+> quotes (ppr bndr)-\end{code}--Note [Simplifying the left-hand side of a RULE]-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~-simpleOptExpr occurrence-analyses and simplifies the lhs-and thereby-(a) sorts dict bindings into NonRecs and inlines them-(b) substitute trivial lets so that they don't get in the way- Note that we substitute the function too; we might - have this as a LHS: let f71 = M.f Int in f71-(c) does eta reduction--For (c) consider the fold/build rule, which without simplification-looked like:- fold k z (build (/\a. g a)) ==> ...-This doesn't match unless you do eta reduction on the build argument.-Similarly for a LHS like- augment g (build h) -we do not want to get- augment (\a. g a) (build h)-otherwise we don't match when given an argument like- augment (\a. h a a) (build h)--NB: tcSimplifyRuleLhs is very careful not to generate complicated- dictionary expressions that we might have to match--Note [Matching seqId]-~~~~~~~~~~~~~~~~~~~-The desugarer turns (seq e r) into (case e of _ -> r), via a special-case hack-and this code turns it back into an application of seq! -See Note [Rules for seq] in MkId for the details.--Note [Unused spec binders]-~~~~~~~~~~~~~~~~~~~~~~~~~~-Consider- f :: a -> a- {-# SPECIALISE f :: Eq a => a -> a #-}-It's true that this *is* a more specialised type, but the rule-we get is something like this:- f_spec d = f- RULE: f = f_spec d-Note that the rule is bogus, because it mentions a 'd' that is-not bound on the LHS! But it's a silly specialisation anyway, because-the constraint is unused. We could bind 'd' to (error "unused")-but it seems better to reject the program because it's almost certainly-a mistake. That's what the isDeadBinder call detects.--Note [Constant rule dicts]-~~~~~~~~~~~~~~~~~~~~~~~~~~-When the LHS of a specialisation rule, (/\as\ds. f es) has a free dict, -which is presumably in scope at the function definition site, we can quantify -over it too. *Any* dict with that type will do.--So for example when you have- f :: Eq a => a -> a- f = <rhs>- {-# SPECIALISE f :: Int -> Int #-}--Then we get the SpecPrag- SpecPrag (f Int dInt) --And from that we want the rule- - RULE forall dInt. f Int dInt = f_spec- f_spec = let f = <rhs> in f Int dInt--But be careful! That dInt might be GHC.Base.$fOrdInt, which is an External-Name, and you can't bind them in a lambda or forall without getting things-confused. Likewise it might have an InlineRule or something, which would be-utterly bogus. So we really make a fresh Id, with the same unique and type-as the old one, but with an Internal name and no IdInfo.---%************************************************************************-%* *- Desugaring evidence-%* *-%************************************************************************---\begin{code}-dsHsWrapper :: HsWrapper -> CoreExpr -> DsM CoreExpr-dsHsWrapper WpHole e = return e-dsHsWrapper (WpTyApp ty) e = return $ App e (Type ty)-dsHsWrapper (WpLet ev_binds) e = do bs <- dsTcEvBinds ev_binds- return (mkCoreLets bs e)-dsHsWrapper (WpCompose c1 c2) e = dsHsWrapper c1 =<< dsHsWrapper c2 e-dsHsWrapper (WpCast co) e = -- ASSERT(tcCoercionRole co == Representational)- dsTcCoercion co (mkCast e)-dsHsWrapper (WpEvLam ev) e = return $ Lam ev e -dsHsWrapper (WpTyLam tv) e = return $ Lam tv e -dsHsWrapper (WpEvApp evtrm) e = liftM (App e) (dsEvTerm evtrm)-----------------------------------------dsTcEvBinds :: TcEvBinds -> DsM [CoreBind]-dsTcEvBinds (TcEvBinds {}) = panic "dsEvBinds" -- Zonker has got rid of this-dsTcEvBinds (EvBinds bs) = dsEvBinds bs--dsEvBinds :: Bag EvBind -> DsM [CoreBind]-dsEvBinds bs = mapM ds_scc (sccEvBinds bs)- where- ds_scc (AcyclicSCC (EvBind v r)) = liftM (NonRec v) (dsEvTerm r)- ds_scc (CyclicSCC bs) = liftM Rec (mapM ds_pair bs)-- ds_pair (EvBind v r) = liftM ((,) v) (dsEvTerm r)--sccEvBinds :: Bag EvBind -> [SCC EvBind]-sccEvBinds bs = stronglyConnCompFromEdgedVertices edges- where- edges :: [(EvBind, EvVar, [EvVar])]- edges = foldrBag ((:) . mk_node) [] bs -- mk_node :: EvBind -> (EvBind, EvVar, [EvVar])- mk_node b@(EvBind var term) = (b, var, varSetElems (evVarsOfTerm term))-------------------------------------------dsEvTerm :: EvTerm -> DsM CoreExpr-dsEvTerm (EvId v) = return (Var v)--dsEvTerm (EvCast tm co) - = do { tm' <- dsEvTerm tm- ; dsTcCoercion co $ mkCast tm' }- -- 'v' is always a lifted evidence variable so it is- -- unnecessary to call varToCoreExpr v here.--dsEvTerm (EvDFunApp df tys tms) = do { tms' <- mapM dsEvTerm tms- ; return (Var df `mkTyApps` tys `mkApps` tms') }--dsEvTerm (EvCoercion (TcCoVarCo v)) = return (Var v) -- See Note [Simple coercions]-dsEvTerm (EvCoercion co) = dsTcCoercion co mkEqBox--dsEvTerm (EvTupleSel v n)- = do { tm' <- dsEvTerm v- ; let scrut_ty = exprType tm'- (tc, tys) = splitTyConApp scrut_ty- Just [dc] = tyConDataCons_maybe tc- xs = mkTemplateLocals tys- the_x = getNth xs n- ; -- ASSERT( isTupleTyCon tc )- return $- Case tm' (mkWildValBinder scrut_ty) (idType the_x) [(DataAlt dc, xs, Var the_x)] }--dsEvTerm (EvTupleMk tms) - = do { tms' <- mapM dsEvTerm tms- ; let tys = map exprType tms'- ; return $ Var (dataConWorkId dc) `mkTyApps` tys `mkApps` tms' }- where - dc = tupleCon ConstraintTuple (length tms)--dsEvTerm (EvSuperClass d n)- = do { d' <- dsEvTerm d- ; let (cls, tys) = getClassPredTys (exprType d')- sc_sel_id = classSCSelId cls n -- Zero-indexed- ; return $ Var sc_sel_id `mkTyApps` tys `App` d' }- where--dsEvTerm (EvDelayedError ty msg) = return $ Var errorId `mkTyApps` [ty] `mkApps` [litMsg]- where - errorId = rUNTIME_ERROR_ID- litMsg = Lit (MachStr (fastStringToByteString msg))--dsEvTerm (EvLit l) =- case l of- EvNum n -> mkIntegerExpr n- EvStr s -> mkStringExprFS s------------------------------------------dsTcCoercion :: TcCoercion -> (Coercion -> CoreExpr) -> DsM CoreExpr--- This is the crucial function that moves --- from TcCoercions to Coercions; see Note [TcCoercions] in Coercion--- e.g. dsTcCoercion (trans g1 g2) k--- = case g1 of EqBox g1# ->--- case g2 of EqBox g2# ->--- k (trans g1# g2#)--- thing_inside will get a coercion at the role requested-dsTcCoercion co thing_inside- = do { us <- newUniqueSupply- ; let eqvs_covs :: [(EqVar,CoVar)]- eqvs_covs = zipWith mk_co_var (varSetElems (coVarsOfTcCo co))- (uniqsFromSupply us)-- subst = mkCvSubst emptyInScopeSet [(eqv, mkCoVarCo cov) | (eqv, cov) <- eqvs_covs]- result_expr = thing_inside (ds_tc_coercion subst co)- result_ty = exprType result_expr-- ; return (foldr (wrap_in_case result_ty) result_expr eqvs_covs) }- where- mk_co_var :: Id -> Unique -> (Id, Id)- mk_co_var eqv uniq = (eqv, mkUserLocal occ uniq ty loc)- where- eq_nm = idName eqv- occ = nameOccName eq_nm- loc = nameSrcSpan eq_nm- ty = mkCoercionType (getEqPredRole (evVarPred eqv)) ty1 ty2- (ty1, ty2) = getEqPredTys (evVarPred eqv)-- wrap_in_case result_ty (eqv, cov) body- = case getEqPredRole (evVarPred eqv) of- Nominal -> Case (Var eqv) eqv result_ty [(DataAlt eqBoxDataCon, [cov], body)]- Representational -> Case (Var eqv) eqv result_ty [(DataAlt coercibleDataCon, [cov], body)]- Phantom -> panic "wrap_in_case/phantom"--ds_tc_coercion :: CvSubst -> TcCoercion -> Coercion--- If the incoming TcCoercion if of type (a ~ b) (resp. Coercible a b)--- the result is of type (a ~# b) (reps. a ~# b)--- The VarEnv maps EqVars of type (a ~ b) to Coercions of type (a ~# b) (resp. and so on)--- No need for InScope set etc because the -ds_tc_coercion subst tc_co- = go tc_co- where- go (TcRefl r ty) = Refl r (Coercion.substTy subst ty)- go (TcTyConAppCo r tc cos) = mkTyConAppCo r tc (map go cos)- go (TcAppCo co1 co2) = let leftCo = go co1- rightRole = nextRole leftCo in- mkAppCoFlexible leftCo rightRole (go co2)- go (TcForAllCo tv co) = mkForAllCo tv' (ds_tc_coercion subst' co)- where- (subst', tv') = Coercion.substTyVarBndr subst tv- go (TcAxiomInstCo ax ind cos)- = AxiomInstCo ax ind (map go cos)- go (TcPhantomCo ty1 ty2) = UnivCo Phantom ty1 ty2- go (TcSymCo co) = mkSymCo (go co)- go (TcTransCo co1 co2) = mkTransCo (go co1) (go co2)- go (TcNthCo n co) = mkNthCo n (go co)- go (TcLRCo lr co) = mkLRCo lr (go co)- go (TcSubCo co) = mkSubCo (go co)- go (TcLetCo bs co) = ds_tc_coercion (ds_co_binds bs) co- go (TcCastCo co1 co2) = mkCoCast (go co1) (go co2)- go (TcCoVarCo v) = ds_ev_id subst v- go (TcAxiomRuleCo co ts cs) = AxiomRuleCo co (map (Coercion.substTy subst) ts) (map go cs)-- ds_co_binds :: TcEvBinds -> CvSubst- ds_co_binds (EvBinds bs) = foldl ds_scc subst (sccEvBinds bs)- ds_co_binds eb@(TcEvBinds {}) = pprPanic "ds_co_binds" (ppr eb)-- ds_scc :: CvSubst -> SCC EvBind -> CvSubst- ds_scc subst (AcyclicSCC (EvBind v ev_term))- = extendCvSubstAndInScope subst v (ds_co_term subst ev_term)- ds_scc _ (CyclicSCC other) = pprPanic "ds_scc:cyclic" (ppr other $$ ppr tc_co)-- ds_co_term :: CvSubst -> EvTerm -> Coercion- ds_co_term subst (EvCoercion tc_co) = ds_tc_coercion subst tc_co- ds_co_term subst (EvId v) = ds_ev_id subst v- ds_co_term subst (EvCast tm co) = mkCoCast (ds_co_term subst tm) (ds_tc_coercion subst co)- ds_co_term _ other = pprPanic "ds_co_term" (ppr other $$ ppr tc_co)-- ds_ev_id :: CvSubst -> EqVar -> Coercion- ds_ev_id subst v- | Just co <- Coercion.lookupCoVar subst v = co- | otherwise = pprPanic "ds_tc_coercion" (ppr v $$ ppr tc_co)-\end{code}--Note [Simple coercions]-~~~~~~~~~~~~~~~~~~~~~~~-We have a special case for coercions that are simple variables.-Suppose cv :: a ~ b is in scope-Lacking the special case, if we see- f a b cv-we'd desguar to- f a b (case cv of EqBox (cv# :: a ~# b) -> EqBox cv#)-which is a bit stupid. The special case does the obvious thing.--This turns out to be important when desugaring the LHS of a RULE-(see Trac #7837). Suppose we have- normalise :: (a ~ Scalar a) => a -> a- normalise_Double :: Double -> Double- {-# RULES "normalise" normalise = normalise_Double #-}--Then the RULE we want looks like- forall a, (cv:a~Scalar a). - normalise a cv = normalise_Double-But without the special case we generate the redundant box/unbox,-which simpleOpt (currently) doesn't remove. So the rule never matches.--Maybe simpleOpt should be smarter. But it seems like a good plan-to simply never generate the redundant box/unbox in the first place.--
− src/Language/Haskell/Liquid/Desugar/DsExpr.lhs
@@ -1,867 +0,0 @@-%-% (c) The University of Glasgow 2006-% (c) The GRASP/AQUA Project, Glasgow University, 1992-1998-%--Desugaring exporessions.--\begin{code}-module Language.Haskell.Liquid.Desugar.DsExpr ( dsExpr, dsLExpr, dsLocalBinds, dsValBinds, dsLit ) where--import Language.Haskell.Liquid.Desugar.Match-import Language.Haskell.Liquid.Desugar.MatchLit-import Language.Haskell.Liquid.Desugar.DsBinds-import Language.Haskell.Liquid.Desugar.DsGRHSs-import Language.Haskell.Liquid.Desugar.DsListComp-import Language.Haskell.Liquid.Desugar.DsUtils-import Language.Haskell.Liquid.Desugar.DsArrows-import DsMonad-import Name-import NameEnv-import FamInstEnv( topNormaliseType )--import HsSyn---- NB: The desugarer, which straddles the source and Core worlds, sometimes--- needs to see source types-import TcType-import Coercion ( Role(..) )-import TcEvidence-import TcRnMonad-import Type-import CoreSyn-import CoreUtils-import CoreFVs-import MkCore--import DynFlags-import CostCentre-import Id-import Module-import VarSet-import VarEnv-import ConLike-import DataCon-import TysWiredIn-import BasicTypes-import Maybes-import SrcLoc-import Util-import Bag-import Outputable-import FastString--import Control.Monad--srcSpanTick :: Module -> SrcSpan -> Tickish a-srcSpanTick m loc- = ProfNote (AllCafsCC m loc) False True--\end{code}---%************************************************************************-%* *- dsLocalBinds, dsValBinds-%* *-%************************************************************************--\begin{code}-dsLocalBinds :: HsLocalBinds Id -> CoreExpr -> DsM CoreExpr-dsLocalBinds EmptyLocalBinds body = return body-dsLocalBinds (HsValBinds binds) body = dsValBinds binds body-dsLocalBinds (HsIPBinds binds) body = dsIPBinds binds body----------------------------dsValBinds :: HsValBinds Id -> CoreExpr -> DsM CoreExpr-dsValBinds (ValBindsOut binds _) body = foldrM ds_val_bind body binds-dsValBinds (ValBindsIn _ _) _ = panic "dsValBinds ValBindsIn"----------------------------dsIPBinds :: HsIPBinds Id -> CoreExpr -> DsM CoreExpr-dsIPBinds (IPBinds ip_binds ev_binds) body- = do { ds_binds <- dsTcEvBinds ev_binds- ; let inner = mkCoreLets ds_binds body- -- The dict bindings may not be in - -- dependency order; hence Rec- ; foldrM ds_ip_bind inner ip_binds }- where- ds_ip_bind (L _ (IPBind ~(Right n) e)) body- = do e' <- dsLExpr e- return (Let (NonRec n e') body)----------------------------ds_val_bind :: (RecFlag, LHsBinds Id) -> CoreExpr -> DsM CoreExpr--- Special case for bindings which bind unlifted variables--- We need to do a case right away, rather than building--- a tuple and doing selections.--- Silently ignore INLINE and SPECIALISE pragmas...-ds_val_bind (NonRecursive, hsbinds) body- | [L loc bind] <- bagToList hsbinds,- -- Non-recursive, non-overloaded bindings only come in ones- -- ToDo: in some bizarre case it's conceivable that there- -- could be dict binds in the 'binds'. (See the notes- -- below. Then pattern-match would fail. Urk.)- strictMatchOnly bind- = putSrcSpanDs loc (dsStrictBind bind body)---- Ordinary case for bindings; none should be unlifted-ds_val_bind (_is_rec, binds) body- = do { prs <- dsLHsBinds binds- ; -- ASSERT2( not (any (isUnLiftedType . idType . fst) prs), ppr _is_rec $$ ppr binds )- case prs of- [] -> return body- _ -> return (Let (Rec prs) body) }- -- Use a Rec regardless of is_rec. - -- Why? Because it allows the binds to be all- -- mixed up, which is what happens in one rare case- -- Namely, for an AbsBind with no tyvars and no dicts,- -- but which does have dictionary bindings.- -- See notes with TcSimplify.inferLoop [NO TYVARS]- -- It turned out that wrapping a Rec here was the easiest solution- --- -- NB The previous case dealt with unlifted bindings, so we- -- only have to deal with lifted ones now; so Rec is ok---------------------dsStrictBind :: HsBind Id -> CoreExpr -> DsM CoreExpr-dsStrictBind (AbsBinds { abs_tvs = [], abs_ev_vars = []- , abs_exports = exports- , abs_ev_binds = ev_binds- , abs_binds = lbinds }) body- = do { let body1 = foldr bind_export body exports- bind_export export b = bindNonRec (abe_poly export) (Var (abe_mono export)) b- ; body2 <- foldlBagM (\body lbind -> dsStrictBind (unLoc lbind) body)- body1 lbinds - ; ds_binds <- dsTcEvBinds ev_binds- ; return (mkCoreLets ds_binds body2) }--dsStrictBind (FunBind { fun_id = L _ fun, fun_matches = matches- , fun_tick = tick, fun_infix = inf }) body- -- Can't be a bang pattern (that looks like a PatBind)- -- so must be simply unboxed- = do { (_, rhs) <- matchWrapper (FunRhs (idName fun ) inf) matches--- ; MASSERT( null args ) -- Functions aren't lifted--- ; MASSERT( isIdHsWrapper co_fn )- ; let rhs' = mkOptTickBox tick rhs- ; return (bindNonRec fun rhs' body) }--dsStrictBind (PatBind {pat_lhs = pat, pat_rhs = grhss, pat_rhs_ty = ty }) body- = -- let C x# y# = rhs in body- -- ==> case rhs of C x# y# -> body- do { rhs <- dsGuarded grhss ty- ; let upat = unLoc pat- eqn = EqnInfo { eqn_pats = [upat], - eqn_rhs = cantFailMatchResult body }- ; var <- selectMatchVar upat- ; result <- matchEquations PatBindRhs [var] [eqn] (exprType body)- ; return (bindNonRec var rhs result) }--dsStrictBind bind body = pprPanic "dsLet: unlifted" (ppr bind $$ ppr body)-------------------------strictMatchOnly :: HsBind Id -> Bool-strictMatchOnly (AbsBinds { abs_binds = lbinds })- = anyBag (strictMatchOnly . unLoc) lbinds-strictMatchOnly (PatBind { pat_lhs = lpat, pat_rhs_ty = rhs_ty })- = isUnLiftedType rhs_ty- || isStrictLPat lpat- || any (isUnLiftedType . idType) (collectPatBinders lpat)-strictMatchOnly (FunBind { fun_id = L _ id })- = isUnLiftedType (idType id)-strictMatchOnly _ = False -- I hope! Checked immediately by caller in fact--\end{code}--%************************************************************************-%* *-\subsection[DsExpr-vars-and-cons]{Variables, constructors, literals}-%* *-%************************************************************************--\begin{code}-dsLExpr :: LHsExpr Id -> DsM CoreExpr--dsLExpr (L loc e) - = do ce <- putSrcSpanDs loc $ dsExpr e- m <- getModule- return $ Tick (srcSpanTick m loc) ce--dsExpr :: HsExpr Id -> DsM CoreExpr-dsExpr (HsPar e) = dsLExpr e-dsExpr (ExprWithTySigOut e _) = dsLExpr e-dsExpr (HsVar var) = return (varToCoreExpr var) -- See Note [Desugaring vars]-dsExpr (HsIPVar _) = panic "dsExpr: HsIPVar"-dsExpr (HsLit lit) = dsLit lit-dsExpr (HsOverLit lit) = dsOverLit lit--dsExpr (HsWrap co_fn e)- = do { e' <- dsExpr e- ; wrapped_e <- dsHsWrapper co_fn e'- ; dflags <- getDynFlags- ; warnAboutIdentities dflags e' (exprType wrapped_e)- ; return wrapped_e }--dsExpr (NegApp expr neg_expr) - = App <$> dsExpr neg_expr <*> dsLExpr expr--dsExpr (HsLam a_Match)- = uncurry mkLams <$> matchWrapper LambdaExpr a_Match--dsExpr (HsLamCase arg matches)- = do { arg_var <- newSysLocalDs arg- ; ([discrim_var], matching_code) <- matchWrapper CaseAlt matches- ; return $ Lam arg_var $ bindNonRec discrim_var (Var arg_var) matching_code }--dsExpr (HsApp fun arg)- = mkCoreAppDs <$> dsLExpr fun <*> dsLExpr arg--dsExpr (HsUnboundVar _) = panic "dsExpr: HsUnboundVar"-\end{code}--Note [Desugaring vars]-~~~~~~~~~~~~~~~~~~~~~~-In one situation we can get a *coercion* variable in a HsVar, namely-the support method for an equality superclass:- class (a~b) => C a b where ...- instance (blah) => C (T a) (T b) where ..-Then we get- $dfCT :: forall ab. blah => C (T a) (T b)- $dfCT ab blah = MkC ($c$p1C a blah) ($cop a blah)-- $c$p1C :: forall ab. blah => (T a ~ T b)- $c$p1C ab blah = let ...; g :: T a ~ T b = ... } in g--That 'g' in the 'in' part is an evidence variable, and when-converting to core it must become a CO.- -Operator sections. At first it looks as if we can convert-\begin{verbatim}- (expr op)-\end{verbatim}-to-\begin{verbatim}- \x -> op expr x-\end{verbatim}--But no! expr might be a redex, and we can lose laziness badly this-way. Consider-\begin{verbatim}- map (expr op) xs-\end{verbatim}-for example. So we convert instead to-\begin{verbatim}- let y = expr in \x -> op y x-\end{verbatim}-If \tr{expr} is actually just a variable, say, then the simplifier-will sort it out.--\begin{code}-dsExpr (OpApp e1 op _ e2)- = -- for the type of y, we need the type of op's 2nd argument- mkCoreAppsDs <$> dsLExpr op <*> mapM dsLExpr [e1, e2]- -dsExpr (SectionL expr op) -- Desugar (e !) to ((!) e)- = mkCoreAppDs <$> dsLExpr op <*> dsLExpr expr---- dsLExpr (SectionR op expr) -- \ x -> op x expr-dsExpr (SectionR op expr) = do- core_op <- dsLExpr op- -- for the type of x, we need the type of op's 2nd argument- let (x_ty:y_ty:_, _) = splitFunTys (exprType core_op)- -- See comment with SectionL- y_core <- dsLExpr expr- x_id <- newSysLocalDs x_ty- y_id <- newSysLocalDs y_ty- return (bindNonRec y_id y_core $- Lam x_id (mkCoreAppsDs core_op [Var x_id, Var y_id]))--dsExpr (ExplicitTuple tup_args boxity)- = do { let go (lam_vars, args) (Missing ty)- -- For every missing expression, we need- -- another lambda in the desugaring.- = do { lam_var <- newSysLocalDs ty- ; return (lam_var : lam_vars, Var lam_var : args) }- go (lam_vars, args) (Present expr)- -- Expressions that are present don't generate- -- lambdas, just arguments.- = do { core_expr <- dsLExpr expr- ; return (lam_vars, core_expr : args) }-- ; (lam_vars, args) <- foldM go ([], []) (reverse tup_args)- -- The reverse is because foldM goes left-to-right-- ; return $ mkCoreLams lam_vars $ - mkConApp (tupleCon (boxityNormalTupleSort boxity) (length tup_args))- (map (Type . exprType) args ++ args) }--dsExpr (HsSCC cc expr@(L loc _)) = do- mod_name <- getModule- count <- goptM Opt_ProfCountEntries- uniq <- newUnique- Tick (ProfNote (mkUserCC cc mod_name loc uniq) count True) <$> dsLExpr expr--dsExpr (HsCoreAnn _ expr)- = dsLExpr expr--dsExpr (HsCase discrim matches)- = do { core_discrim <- dsLExpr discrim- ; ([discrim_var], matching_code) <- matchWrapper CaseAlt matches- ; return (bindNonRec discrim_var core_discrim matching_code) }---- Pepe: The binds are in scope in the body but NOT in the binding group--- This is to avoid silliness in breakpoints-dsExpr (HsLet binds body) = do- body' <- dsLExpr body- dsLocalBinds binds body'---- We need the `ListComp' form to use `deListComp' (rather than the "do" form)--- because the interpretation of `stmts' depends on what sort of thing it is.----dsExpr (HsDo ListComp stmts res_ty) = dsListComp stmts res_ty-dsExpr (HsDo PArrComp stmts _) = dsPArrComp (map unLoc stmts)-dsExpr (HsDo DoExpr stmts _) = dsDo stmts -dsExpr (HsDo GhciStmtCtxt stmts _) = dsDo stmts -dsExpr (HsDo MDoExpr stmts _) = dsDo stmts -dsExpr (HsDo MonadComp stmts _) = dsMonadComp stmts--dsExpr (HsIf mb_fun guard_expr then_expr else_expr)- = do { pred <- dsLExpr guard_expr- ; b1 <- dsLExpr then_expr- ; b2 <- dsLExpr else_expr- ; case mb_fun of- Just fun -> do { core_fun <- dsExpr fun- ; return (mkCoreApps core_fun [pred,b1,b2]) }- Nothing -> return $ mkIfThenElse pred b1 b2 }--dsExpr (HsMultiIf res_ty alts)- | null alts- = mkErrorExpr-- | otherwise- = do { match_result <- liftM (foldr1 combineMatchResults)- (mapM (dsGRHS IfAlt res_ty) alts)- ; error_expr <- mkErrorExpr- ; extractMatchResult match_result error_expr }- where- mkErrorExpr = mkErrorAppDs nON_EXHAUSTIVE_GUARDS_ERROR_ID res_ty- (ptext (sLit "multi-way if"))-\end{code}---\noindent-\underline{\bf Various data construction things}-% ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~-\begin{code}-dsExpr (ExplicitList elt_ty wit xs) - = dsExplicitList elt_ty wit xs---- We desugar [:x1, ..., xn:] as--- singletonP x1 +:+ ... +:+ singletonP xn----dsExpr (ExplicitPArr ty []) = do- emptyP <- dsDPHBuiltin emptyPVar- return (Var emptyP `App` Type ty)-dsExpr (ExplicitPArr ty xs) = do- singletonP <- dsDPHBuiltin singletonPVar- appP <- dsDPHBuiltin appPVar- xs' <- mapM dsLExpr xs- return . foldr1 (binary appP) $ map (unary singletonP) xs'- where- unary fn x = mkApps (Var fn) [Type ty, x]- binary fn x y = mkApps (Var fn) [Type ty, x, y]--dsExpr (ArithSeq expr witness seq)- = case witness of- Nothing -> dsArithSeq expr seq- Just fl -> do { - ; fl' <- dsExpr fl- ; newArithSeq <- dsArithSeq expr seq- ; return (App fl' newArithSeq)}--dsExpr (PArrSeq expr (FromTo from to))- = mkApps <$> dsExpr expr <*> mapM dsLExpr [from, to]--dsExpr (PArrSeq expr (FromThenTo from thn to))- = mkApps <$> dsExpr expr <*> mapM dsLExpr [from, thn, to]--dsExpr (PArrSeq _ _)- = panic "DsExpr.dsExpr: Infinite parallel array!"- -- the parser shouldn't have generated it and the renamer and typechecker- -- shouldn't have let it through-\end{code}--\noindent-\underline{\bf Record construction and update}-% ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~-For record construction we do this (assuming T has three arguments)-\begin{verbatim}- T { op2 = e }-==>- let err = /\a -> recConErr a - T (recConErr t1 "M.lhs/230/op1") - e - (recConErr t1 "M.lhs/230/op3")-\end{verbatim}-@recConErr@ then converts its arugment string into a proper message-before printing it as-\begin{verbatim}- M.lhs, line 230: missing field op1 was evaluated-\end{verbatim}--We also handle @C{}@ as valid construction syntax for an unlabelled-constructor @C@, setting all of @C@'s fields to bottom.--\begin{code}-dsExpr (RecordCon (L _ data_con_id) con_expr rbinds) = do- con_expr' <- dsExpr con_expr- let- (arg_tys, _) = tcSplitFunTys (exprType con_expr')- -- A newtype in the corner should be opaque; - -- hence TcType.tcSplitFunTys-- mk_arg (arg_ty, lbl) -- Selector id has the field label as its name- = case findField (rec_flds rbinds) lbl of- (rhs:_) -> -- ASSERT( null rhss )- dsLExpr rhs- [] -> mkErrorAppDs rEC_CON_ERROR_ID arg_ty (ppr lbl)- unlabelled_bottom arg_ty = mkErrorAppDs rEC_CON_ERROR_ID arg_ty empty-- labels = dataConFieldLabels (idDataCon data_con_id)- -- The data_con_id is guaranteed to be the wrapper id of the constructor- - con_args <- if null labels- then mapM unlabelled_bottom arg_tys- else mapM mk_arg (zipEqual "dsExpr:RecordCon" arg_tys labels)- - return (mkApps con_expr' con_args)-\end{code}--Record update is a little harder. Suppose we have the decl:-\begin{verbatim}- data T = T1 {op1, op2, op3 :: Int}- | T2 {op4, op2 :: Int}- | T3-\end{verbatim}-Then we translate as follows:-\begin{verbatim}- r { op2 = e }-===>- let op2 = e in- case r of- T1 op1 _ op3 -> T1 op1 op2 op3- T2 op4 _ -> T2 op4 op2- other -> recUpdError "M.lhs/230"-\end{verbatim}-It's important that we use the constructor Ids for @T1@, @T2@ etc on the-RHSs, and do not generate a Core constructor application directly, because the constructor-might do some argument-evaluation first; and may have to throw away some-dictionaries.--Note [Update for GADTs]-~~~~~~~~~~~~~~~~~~~~~~~-Consider - data T a b where- T1 { f1 :: a } :: T a Int--Then the wrapper function for T1 has type - $WT1 :: a -> T a Int-But if x::T a b, then- x { f1 = v } :: T a b (not T a Int!)-So we need to cast (T a Int) to (T a b). Sigh.--\begin{code}-dsExpr (RecordUpd record_expr (HsRecFields { rec_flds = fields })- cons_to_upd in_inst_tys out_inst_tys)- | null fields- = dsLExpr record_expr- | otherwise- = -- ASSERT2( notNull cons_to_upd, ppr expr )-- do { record_expr' <- dsLExpr record_expr- ; field_binds' <- mapM ds_field fields- ; let upd_fld_env :: NameEnv Id -- Maps field name to the LocalId of the field binding- upd_fld_env = mkNameEnv [(f,l) | (f,l,_) <- field_binds']-- -- It's important to generate the match with matchWrapper,- -- and the right hand sides with applications of the wrapper Id- -- so that everything works when we are doing fancy unboxing on the- -- constructor aguments.- ; alts <- mapM (mk_alt upd_fld_env) cons_to_upd- ; ([discrim_var], matching_code) - <- matchWrapper RecUpd (MG { mg_alts = alts, mg_arg_tys = [in_ty], mg_res_ty = out_ty, mg_origin = Generated })-- ; return (add_field_binds field_binds' $- bindNonRec discrim_var record_expr' matching_code) }- where- ds_field :: HsRecField Id (LHsExpr Id) -> DsM (Name, Id, CoreExpr)- -- Clone the Id in the HsRecField, because its Name is that- -- of the record selector, and we must not make that a lcoal binder- -- else we shadow other uses of the record selector- -- Hence 'lcl_id'. Cf Trac #2735- ds_field rec_field = do { rhs <- dsLExpr (hsRecFieldArg rec_field)- ; let fld_id = unLoc (hsRecFieldId rec_field)- ; lcl_id <- newSysLocalDs (idType fld_id)- ; return (idName fld_id, lcl_id, rhs) }-- add_field_binds [] expr = expr- add_field_binds ((_,b,r):bs) expr = bindNonRec b r (add_field_binds bs expr)-- -- Awkwardly, for families, the match goes - -- from instance type to family type- tycon = dataConTyCon (head cons_to_upd)- in_ty = mkTyConApp tycon in_inst_tys- out_ty = mkFamilyTyConApp tycon out_inst_tys-- mk_alt upd_fld_env con- = do { let (univ_tvs, ex_tvs, eq_spec, - theta, arg_tys, _) = dataConFullSig con- subst = mkTopTvSubst (univ_tvs `zip` in_inst_tys)-- -- I'm not bothering to clone the ex_tvs- ; eqs_vars <- mapM newPredVarDs (substTheta subst (eqSpecPreds eq_spec))- ; theta_vars <- mapM newPredVarDs (substTheta subst theta)- ; arg_ids <- newSysLocalsDs (substTys subst arg_tys)- ; let val_args = zipWithEqual "dsExpr:RecordUpd" mk_val_arg- (dataConFieldLabels con) arg_ids- mk_val_arg field_name pat_arg_id - = nlHsVar (lookupNameEnv upd_fld_env field_name `orElse` pat_arg_id)- inst_con = noLoc $ HsWrap wrap (HsVar (dataConWrapId con))- -- Reconstruct with the WrapId so that unpacking happens- wrap = mkWpEvVarApps theta_vars <.>- mkWpTyApps (mkTyVarTys ex_tvs) <.>- mkWpTyApps [ty | (tv, ty) <- univ_tvs `zip` out_inst_tys- , not (tv `elemVarEnv` wrap_subst) ]- rhs = foldl (\a b -> nlHsApp a b) inst_con val_args-- -- Tediously wrap the application in a cast- -- Note [Update for GADTs]- wrap_co = mkTcTyConAppCo Nominal tycon- [ lookup tv ty | (tv,ty) <- univ_tvs `zip` out_inst_tys ]- lookup univ_tv ty = case lookupVarEnv wrap_subst univ_tv of- Just co' -> co'- Nothing -> mkTcReflCo Nominal ty- wrap_subst = mkVarEnv [ (tv, mkTcSymCo (mkTcCoVarCo eq_var))- | ((tv,_),eq_var) <- eq_spec `zip` eqs_vars ]-- pat = noLoc $ ConPatOut { pat_con = noLoc (RealDataCon con)- , pat_tvs = ex_tvs- , pat_dicts = eqs_vars ++ theta_vars- , pat_binds = emptyTcEvBinds- , pat_args = PrefixCon $ map nlVarPat arg_ids- , pat_arg_tys = in_inst_tys- , pat_wrap = idHsWrapper }- ; let wrapped_rhs | null eq_spec = rhs- | otherwise = mkLHsWrap (mkWpCast (mkTcSubCo wrap_co)) rhs- ; return (mkSimpleMatch [pat] wrapped_rhs) }--\end{code}--Here is where we desugar the Template Haskell brackets and escapes--\begin{code}--- Template Haskell stuff--dsExpr (HsRnBracketOut _ _) = panic "dsExpr HsRnBracketOut"--- #ifdef GHCI--- dsExpr (HsTcBracketOut x ps) = dsBracket x ps--- #else-dsExpr (HsTcBracketOut _ _) = panic "dsExpr HsBracketOut"--- #endif-dsExpr (HsSpliceE _ s) = pprPanic "dsExpr:splice" (ppr s)---- Arrow notation extension-dsExpr (HsProc pat cmd) = dsProcExpr pat cmd-\end{code}--Hpc Support --\begin{code}-dsExpr (HsTick tickish e) = do- e' <- dsLExpr e- return (Tick tickish e')---- There is a problem here. The then and else branches--- have no free variables, so they are open to lifting.--- We need someway of stopping this.--- This will make no difference to binary coverage--- (did you go here: YES or NO), but will effect accurate--- tick counting.--dsExpr (HsBinTick ixT ixF e) = do- e2 <- dsLExpr e- do { -- ASSERT(exprType e2 `eqType` boolTy)- mkBinaryTickBox ixT ixF e2- }-\end{code}--\begin{code}---- HsSyn constructs that just shouldn't be here:-dsExpr (ExprWithTySig {}) = panic "dsExpr:ExprWithTySig"-dsExpr (HsBracket {}) = panic "dsExpr:HsBracket"-dsExpr (HsQuasiQuoteE {}) = panic "dsExpr:HsQuasiQuoteE"-dsExpr (HsArrApp {}) = panic "dsExpr:HsArrApp"-dsExpr (HsArrForm {}) = panic "dsExpr:HsArrForm"-dsExpr (HsTickPragma {}) = panic "dsExpr:HsTickPragma"-dsExpr (EWildPat {}) = panic "dsExpr:EWildPat"-dsExpr (EAsPat {}) = panic "dsExpr:EAsPat"-dsExpr (EViewPat {}) = panic "dsExpr:EViewPat"-dsExpr (ELazyPat {}) = panic "dsExpr:ELazyPat"-dsExpr (HsType {}) = panic "dsExpr:HsType"-dsExpr (HsDo {}) = panic "dsExpr:HsDo"---findField :: [HsRecField Id arg] -> Name -> [arg]-findField rbinds lbl - = [rhs | HsRecField { hsRecFieldId = id, hsRecFieldArg = rhs } <- rbinds - , lbl == idName (unLoc id) ]-\end{code}--%----------------------------------------------------------------------Note [Desugaring explicit lists]-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~-Explicit lists are desugared in a cleverer way to prevent some-fruitless allocations. Essentially, whenever we see a list literal-[x_1, ..., x_n] we:--1. Find the tail of the list that can be allocated statically (say- [x_k, ..., x_n]) by later stages and ensure we desugar that- normally: this makes sure that we don't cause a code size increase- by having the cons in that expression fused (see later) and hence- being unable to statically allocate any more--2. For the prefix of the list which cannot be allocated statically,- say [x_1, ..., x_(k-1)], we turn it into an expression involving- build so that if we find any foldrs over it it will fuse away- entirely!- - So in this example we will desugar to:- build (\c n -> x_1 `c` x_2 `c` .... `c` foldr c n [x_k, ..., x_n]- - If fusion fails to occur then build will get inlined and (since we- defined a RULE for foldr (:) []) we will get back exactly the- normal desugaring for an explicit list.--This optimisation can be worth a lot: up to 25% of the total-allocation in some nofib programs. Specifically-- Program Size Allocs Runtime CompTime- rewrite +0.0% -26.3% 0.02 -1.8%- ansi -0.3% -13.8% 0.00 +0.0%- lift +0.0% -8.7% 0.00 -2.3%--Of course, if rules aren't turned on then there is pretty much no-point doing this fancy stuff, and it may even be harmful.--=======> Note by SLPJ Dec 08.--I'm unconvinced that we should *ever* generate a build for an explicit-list. See the comments in GHC.Base about the foldr/cons rule, which -points out that (foldr k z [a,b,c]) may generate *much* less code than-(a `k` b `k` c `k` z).--Furthermore generating builds messes up the LHS of RULES. -Example: the foldr/single rule in GHC.Base- foldr k z [x] = ...-We do not want to generate a build invocation on the LHS of this RULE!--We fix this by disabling rules in rule LHSs, and testing that-flag here; see Note [Desugaring RULE left hand sides] in Desugar--To test this I've added a (static) flag -fsimple-list-literals, which-makes all list literals be generated via the simple route. ---\begin{code}-dsExplicitList :: PostTcType -> Maybe (SyntaxExpr Id) -> [LHsExpr Id] -> DsM CoreExpr--- See Note [Desugaring explicit lists]-dsExplicitList elt_ty Nothing xs- = do { dflags <- getDynFlags- ; xs' <- mapM dsLExpr xs- ; let (dynamic_prefix, static_suffix) = spanTail is_static xs'- ; if gopt Opt_SimpleListLiterals dflags -- -fsimple-list-literals- || not (gopt Opt_EnableRewriteRules dflags) -- Rewrite rules off- -- Don't generate a build if there are no rules to eliminate it!- -- See Note [Desugaring RULE left hand sides] in Desugar- || null dynamic_prefix -- Avoid build (\c n. foldr c n xs)!- then return $ mkListExpr elt_ty xs'- else mkBuildExpr elt_ty (mkSplitExplicitList dynamic_prefix static_suffix) }- where- is_static :: CoreExpr -> Bool- is_static e = all is_static_var (varSetElems (exprFreeVars e))-- is_static_var :: Var -> Bool- is_static_var v - | isId v = isExternalName (idName v) -- Top-level things are given external names- | otherwise = False -- Type variables-- mkSplitExplicitList prefix suffix (c, _) (n, n_ty)- = do { let suffix' = mkListExpr elt_ty suffix- ; folded_suffix <- mkFoldrExpr elt_ty n_ty (Var c) (Var n) suffix'- ; return (foldr (App . App (Var c)) folded_suffix prefix) }--dsExplicitList elt_ty (Just fln) xs- = do { fln' <- dsExpr fln- ; list <- dsExplicitList elt_ty Nothing xs- ; dflags <- getDynFlags- ; return (App (App fln' (mkIntExprInt dflags (length xs))) list) }- -spanTail :: (a -> Bool) -> [a] -> ([a], [a])-spanTail f xs = (reverse rejected, reverse satisfying)- where (satisfying, rejected) = span f $ reverse xs- -dsArithSeq :: PostTcExpr -> (ArithSeqInfo Id) -> DsM CoreExpr-dsArithSeq expr (From from)- = App <$> dsExpr expr <*> dsLExpr from-dsArithSeq expr (FromTo from to)- = do dflags <- getDynFlags- warnAboutEmptyEnumerations dflags from Nothing to- expr' <- dsExpr expr- from' <- dsLExpr from- to' <- dsLExpr to- return $ mkApps expr' [from', to']-dsArithSeq expr (FromThen from thn)- = mkApps <$> dsExpr expr <*> mapM dsLExpr [from, thn]-dsArithSeq expr (FromThenTo from thn to)- = do dflags <- getDynFlags- warnAboutEmptyEnumerations dflags from (Just thn) to- expr' <- dsExpr expr- from' <- dsLExpr from- thn' <- dsLExpr thn- to' <- dsLExpr to- return $ mkApps expr' [from', thn', to']-\end{code}--Desugar 'do' and 'mdo' expressions (NOT list comprehensions, they're-handled in DsListComp). Basically does the translation given in the-Haskell 98 report:--\begin{code}-dsDo :: [ExprLStmt Id] -> DsM CoreExpr-dsDo stmts- = goL stmts- where- goL [] = panic "dsDo"- goL (L loc stmt:lstmts) = putSrcSpanDs loc (go loc stmt lstmts)- - go _ (LastStmt body _) _- = {- ASSERT( null stmts ) -} dsLExpr body- -- The 'return' op isn't used for 'do' expressions-- go _ (BodyStmt rhs then_expr _ _) stmts- = do { rhs2 <- dsLExpr rhs- ; warnDiscardedDoBindings rhs (exprType rhs2) - ; then_expr2 <- dsExpr then_expr- ; rest <- goL stmts- ; return (mkApps then_expr2 [rhs2, rest]) }- - go _ (LetStmt binds) stmts- = do { rest <- goL stmts- ; dsLocalBinds binds rest }-- go _ (BindStmt pat rhs bind_op fail_op) stmts- = do { body <- goL stmts- ; rhs' <- dsLExpr rhs- ; bind_op' <- dsExpr bind_op- ; var <- selectSimpleMatchVarL pat- ; let bind_ty = exprType bind_op' -- rhs -> (pat -> res1) -> res2- res1_ty = funResultTy (funArgTy (funResultTy bind_ty))- ; match <- matchSinglePat (Var var) (StmtCtxt DoExpr) pat- res1_ty (cantFailMatchResult body)- ; match_code <- handle_failure pat match fail_op- ; return (mkApps bind_op' [rhs', Lam var match_code]) }- - go loc (RecStmt { recS_stmts = rec_stmts, recS_later_ids = later_ids- , recS_rec_ids = rec_ids, recS_ret_fn = return_op- , recS_mfix_fn = mfix_op, recS_bind_fn = bind_op- , recS_rec_rets = rec_rets, recS_ret_ty = body_ty }) stmts- = goL (new_bind_stmt : stmts) -- rec_ids can be empty; eg rec { print 'x' }- where- new_bind_stmt = L loc $ BindStmt (mkBigLHsPatTup later_pats)- mfix_app bind_op - noSyntaxExpr -- Tuple cannot fail-- tup_ids = rec_ids ++ filterOut (`elem` rec_ids) later_ids- tup_ty = mkBigCoreTupTy (map idType tup_ids) -- Deals with singleton case- rec_tup_pats = map nlVarPat tup_ids- later_pats = rec_tup_pats- rets = map noLoc rec_rets- mfix_app = nlHsApp (noLoc mfix_op) mfix_arg- mfix_arg = noLoc $ HsLam (MG { mg_alts = [mkSimpleMatch [mfix_pat] body]- , mg_arg_tys = [tup_ty], mg_res_ty = body_ty- , mg_origin = Generated })- mfix_pat = noLoc $ LazyPat $ mkBigLHsPatTup rec_tup_pats- body = noLoc $ HsDo DoExpr (rec_stmts ++ [ret_stmt]) body_ty- ret_app = nlHsApp (noLoc return_op) (mkBigLHsTup rets)- ret_stmt = noLoc $ mkLastStmt ret_app- -- This LastStmt will be desugared with dsDo, - -- which ignores the return_op in the LastStmt,- -- so we must apply the return_op explicitly -- go _ (ParStmt {}) _ = panic "dsDo ParStmt"- go _ (TransStmt {}) _ = panic "dsDo TransStmt"--handle_failure :: LPat Id -> MatchResult -> SyntaxExpr Id -> DsM CoreExpr- -- In a do expression, pattern-match failure just calls- -- the monadic 'fail' rather than throwing an exception-handle_failure pat match fail_op- | matchCanFail match- = do { fail_op' <- dsExpr fail_op- ; dflags <- getDynFlags- ; fail_msg <- mkStringExpr (mk_fail_msg dflags pat)- ; extractMatchResult match (App fail_op' fail_msg) }- | otherwise- = extractMatchResult match (error "It can't fail")--mk_fail_msg :: DynFlags -> Located e -> String-mk_fail_msg dflags pat = "Pattern match failure in do expression at " ++ - showPpr dflags (getLoc pat)-\end{code}---%************************************************************************-%* *-\subsection{Errors and contexts}-%* *-%************************************************************************--\begin{code}--- Warn about certain types of values discarded in monadic bindings (#3263)-warnDiscardedDoBindings :: LHsExpr Id -> Type -> DsM ()-warnDiscardedDoBindings rhs rhs_ty- | Just (m_ty, elt_ty) <- tcSplitAppTy_maybe rhs_ty- = do { warn_unused <- woptM Opt_WarnUnusedDoBind- ; warn_wrong <- woptM Opt_WarnWrongDoBind- ; when (warn_unused || warn_wrong) $- do { fam_inst_envs <- dsGetFamInstEnvs- ; let norm_elt_ty = topNormaliseType fam_inst_envs elt_ty-- -- Warn about discarding non-() things in 'monadic' binding- ; if warn_unused && not (isUnitTy norm_elt_ty)- then warnDs (badMonadBind rhs elt_ty- (ptext (sLit "-fno-warn-unused-do-bind")))- else-- -- Warn about discarding m a things in 'monadic' binding of the same type,- -- but only if we didn't already warn due to Opt_WarnUnusedDoBind- when warn_wrong $- do { case tcSplitAppTy_maybe norm_elt_ty of- Just (elt_m_ty, _)- | m_ty `eqType` topNormaliseType fam_inst_envs elt_m_ty- -> warnDs (badMonadBind rhs elt_ty- (ptext (sLit "-fno-warn-wrong-do-bind")))- _ -> return () } } }-- | otherwise -- RHS does have type of form (m ty), which is weird- = return () -- but at lesat this warning is irrelevant--badMonadBind :: LHsExpr Id -> Type -> SDoc -> SDoc-badMonadBind rhs elt_ty flag_doc- = vcat [ hang (ptext (sLit "A do-notation statement discarded a result of type"))- 2 (quotes (ppr elt_ty))- , hang (ptext (sLit "Suppress this warning by saying"))- 2 (quotes $ ptext (sLit "_ <-") <+> ppr rhs)- , ptext (sLit "or by using the flag") <+> flag_doc ]-\end{code}
− src/Language/Haskell/Liquid/Desugar/DsExpr.lhs-boot
@@ -1,11 +0,0 @@-\begin{code}-module Language.Haskell.Liquid.Desugar.DsExpr where-import HsSyn ( HsExpr, LHsExpr, HsLocalBinds )-import Var ( Id )-import DsMonad ( DsM )-import CoreSyn ( CoreExpr )--dsExpr :: HsExpr Id -> DsM CoreExpr-dsLExpr :: LHsExpr Id -> DsM CoreExpr-dsLocalBinds :: HsLocalBinds Id -> CoreExpr -> DsM CoreExpr-\end{code}
− src/Language/Haskell/Liquid/Desugar/DsForeign.lhs
@@ -1,807 +0,0 @@-%-% (c) The University of Glasgow 2006-% (c) The AQUA Project, Glasgow University, 1998-%--Desugaring foreign declarations (see also DsCCall).--\begin{code}-module Language.Haskell.Liquid.Desugar.DsForeign ( dsForeigns- , dsForeigns'- , dsFImport, dsCImport, dsFCall, dsPrimCall- , dsFExport, dsFExportDynamic, mkFExportCBits- , toCType- , foreignExportInitialiser- ) where---- #include "HsVersions.h"-import TcRnMonad -- temp--import TypeRep--import CoreSyn--import DsCCall-import DsMonad--import HsSyn-import DataCon-import CoreUnfold-import Id-import Literal-import Module-import Name-import Type-import TyCon-import Coercion-import TcEnv-import TcType--import CmmExpr-import CmmUtils-import HscTypes-import ForeignCall-import TysWiredIn-import TysPrim-import PrelNames-import BasicTypes-import SrcLoc-import Outputable-import FastString-import DynFlags-import Platform-import Config-import OrdList-import Pair-import Hooks--import Data.Maybe-import Data.List-\end{code}--Desugaring of @foreign@ declarations is naturally split up into-parts, an @import@ and an @export@ part. A @foreign import@-declaration-\begin{verbatim}- foreign import cc nm f :: prim_args -> IO prim_res-\end{verbatim}-is the same as-\begin{verbatim}- f :: prim_args -> IO prim_res- f a1 ... an = _ccall_ nm cc a1 ... an-\end{verbatim}-so we reuse the desugaring code in @DsCCall@ to deal with these.--\begin{code}-type Binding = (Id, CoreExpr) -- No rec/nonrec structure;- -- the occurrence analyser will sort it all out--dsForeigns :: [LForeignDecl Id]- -> DsM (ForeignStubs, OrdList Binding)-dsForeigns fos = getHooked dsForeignsHook dsForeigns' >>= ($ fos)--dsForeigns' :: [LForeignDecl Id]- -> DsM (ForeignStubs, OrdList Binding)-dsForeigns' []- = return (NoStubs, nilOL)-dsForeigns' fos = do- fives <- mapM do_ldecl fos- let- (hs, cs, idss, bindss) = unzip4 fives- fe_ids = concat idss- fe_init_code = map foreignExportInitialiser fe_ids- --- return (ForeignStubs- (vcat hs)- (vcat cs $$ vcat fe_init_code),- foldr (appOL . toOL) nilOL bindss)- where- do_ldecl (L loc decl) = putSrcSpanDs loc (do_decl decl)-- do_decl (ForeignImport id _ co spec) = do- traceIf (text "fi start" <+> ppr id)- (bs, h, c) <- dsFImport (unLoc id) co spec- traceIf (text "fi end" <+> ppr id)- return (h, c, [], bs)-- do_decl (ForeignExport (L _ id) _ co (CExport (CExportStatic ext_nm cconv))) = do- (h, c, _, _) <- dsFExport id co ext_nm cconv False- return (h, c, [id], [])-\end{code}---%************************************************************************-%* *-\subsection{Foreign import}-%* *-%************************************************************************--Desugaring foreign imports is just the matter of creating a binding-that on its RHS unboxes its arguments, performs the external call-(using the @CCallOp@ primop), before boxing the result up and returning it.--However, we create a worker/wrapper pair, thus:-- foreign import f :: Int -> IO Int-==>- f x = IO ( \s -> case x of { I# x# ->- case fw s x# of { (# s1, y# #) ->- (# s1, I# y# #)}})-- fw s x# = ccall f s x#--The strictness/CPR analyser won't do this automatically because it doesn't look-inside returned tuples; but inlining this wrapper is a Really Good Idea-because it exposes the boxing to the call site.--\begin{code}-dsFImport :: Id- -> Coercion- -> ForeignImport- -> DsM ([Binding], SDoc, SDoc)-dsFImport id co (CImport cconv safety mHeader spec) = do- (ids, h, c) <- dsCImport id co spec cconv safety mHeader- return (ids, h, c)--dsCImport :: Id- -> Coercion- -> CImportSpec- -> CCallConv- -> Safety- -> Maybe Header- -> DsM ([Binding], SDoc, SDoc)-dsCImport id co (CLabel _) _ _ _ = do- -- dflags <- getDynFlags- -- let ty = pFst $ coercionKind co- -- fod = case tyConAppTyCon_maybe (dropForAlls ty) of- -- Just tycon- -- | tyConUnique tycon == funPtrTyConKey ->- -- IsFunction- -- _ -> IsData- -- (resTy, foRhs) <- resultWrapper ty- -- ASSERT(fromJust resTy `eqType` addrPrimTy) -- typechecker ensures this- let rhs = let x = x in x -- foRhs (Lit (MachLabel cid stdcall_info fod))- let rhs' = Cast rhs co- -- let stdcall_info = fun_type_arg_stdcall_info dflags cconv ty- return ([(id, rhs')], empty, empty)--dsCImport id co (CFunction target) cconv@PrimCallConv safety _- = dsPrimCall id co (CCall (CCallSpec target cconv safety))-dsCImport id co (CFunction target) cconv safety mHeader- = dsFCall id co (CCall (CCallSpec target cconv safety)) mHeader-dsCImport id co CWrapper cconv _ _- = dsFExportDynamic id co cconv---- For stdcall labels, if the type was a FunPtr or newtype thereof,--- then we need to calculate the size of the arguments in order to add--- the @n suffix to the label.--- fun_type_arg_stdcall_info :: DynFlags -> CCallConv -> Type -> Maybe Int--- fun_type_arg_stdcall_info dflags StdCallConv ty--- | Just (tc,[arg_ty]) <- splitTyConApp_maybe ty,--- tyConUnique tc == funPtrTyConKey--- = let--- (_tvs,sans_foralls) = tcSplitForAllTys arg_ty--- (fe_arg_tys, _orig_res_ty) = tcSplitFunTys sans_foralls--- in Just $ sum (map (widthInBytes . typeWidth . typeCmmType dflags . getPrimTyOf) fe_arg_tys)--- fun_type_arg_stdcall_info _ _other_conv _--- = Nothing-\end{code}---%************************************************************************-%* *-\subsection{Foreign calls}-%* *-%************************************************************************--\begin{code}-dsFCall :: Id -> Coercion -> ForeignCall -> Maybe Header- -> DsM ([(Id, Expr TyVar)], SDoc, SDoc)-dsFCall fn_id co fcall mDeclHeader = do- let- ty = pFst $ coercionKind co- (tvs, fun_ty) = tcSplitForAllTys ty- (arg_tys, io_res_ty) = tcSplitFunTys fun_ty- -- Must use tcSplit* functions because we want to- -- see that (IO t) in the corner-- args <- newSysLocalsDs arg_tys- (val_args, arg_wrappers) <- mapAndUnzipM unboxArg (map Var args)-- let- work_arg_ids = [v | Var v <- val_args] -- All guaranteed to be vars-- (ccall_result_ty, res_wrapper) <- boxResult io_res_ty-- ccall_uniq <- newUnique- work_uniq <- newUnique-- dflags <- getDynFlags- (fcall', cDoc) <-- case fcall of- CCall (CCallSpec (StaticTarget cName mPackageId isFun) CApiConv safety) ->- do wrapperName <- mkWrapperName "ghc_wrapper" (unpackFS cName)- let fcall' = CCall (CCallSpec (StaticTarget wrapperName mPackageId True) CApiConv safety)- c = includes- $$ fun_proto <+> braces (cRet <> semi)- includes = vcat [ text "#include <" <> ftext h <> text ">"- | Header h <- nub headers ]- fun_proto = cResType <+> pprCconv <+> ppr wrapperName <> parens argTypes- cRet- | isVoidRes = cCall- | otherwise = text "return" <+> cCall- cCall = if isFun- then ppr cName <> parens argVals- else if null arg_tys- then ppr cName- else panic "dsFCall: Unexpected arguments to FFI value import"- raw_res_ty = case tcSplitIOType_maybe io_res_ty of- Just (_ioTyCon, res_ty) -> res_ty- Nothing -> io_res_ty- isVoidRes = raw_res_ty `eqType` unitTy- (mHeader, cResType)- | isVoidRes = (Nothing, text "void")- | otherwise = toCType raw_res_ty- pprCconv = ccallConvAttribute CApiConv- mHeadersArgTypeList- = [ (header, cType <+> char 'a' <> int n)- | (t, n) <- zip arg_tys [1..]- , let (header, cType) = toCType t ]- (mHeaders, argTypeList) = unzip mHeadersArgTypeList- argTypes = if null argTypeList- then text "void"- else hsep $ punctuate comma argTypeList- mHeaders' = mDeclHeader : mHeader : mHeaders- headers = catMaybes mHeaders'- argVals = hsep $ punctuate comma- [ char 'a' <> int n- | (_, n) <- zip arg_tys [1..] ]- return (fcall', c)- _ ->- return (fcall, empty)- let- -- Build the worker- worker_ty = mkForAllTys tvs (mkFunTys (map idType work_arg_ids) ccall_result_ty)- the_ccall_app = mkFCall dflags ccall_uniq fcall' val_args ccall_result_ty- work_rhs = mkLams tvs (mkLams work_arg_ids the_ccall_app)- work_id = mkSysLocal (fsLit "$wccall") work_uniq worker_ty-- -- Build the wrapper- work_app = mkApps (mkVarApps (Var work_id) tvs) val_args- wrapper_body = foldr ($) (res_wrapper work_app) arg_wrappers- wrap_rhs = mkLams (tvs ++ args) wrapper_body- wrap_rhs' = Cast wrap_rhs co- fn_id_w_inl = fn_id `setIdUnfolding` mkInlineUnfolding (Just (length args)) wrap_rhs'-- return ([(work_id, work_rhs), (fn_id_w_inl, wrap_rhs')], empty, cDoc)-\end{code}---%************************************************************************-%* *-\subsection{Primitive calls}-%* *-%************************************************************************--This is for `@foreign import prim@' declarations.--Currently, at the core level we pretend that these primitive calls are-foreign calls. It may make more sense in future to have them as a distinct-kind of Id, or perhaps to bundle them with PrimOps since semantically and-for calling convention they are really prim ops.--\begin{code}-dsPrimCall :: Id -> Coercion -> ForeignCall- -> DsM ([(Id, Expr TyVar)], SDoc, SDoc)-dsPrimCall fn_id co fcall = do- let- ty = pFst $ coercionKind co- (tvs, fun_ty) = tcSplitForAllTys ty- (arg_tys, io_res_ty) = tcSplitFunTys fun_ty- -- Must use tcSplit* functions because we want to- -- see that (IO t) in the corner-- args <- newSysLocalsDs arg_tys-- ccall_uniq <- newUnique- dflags <- getDynFlags- let- call_app = mkFCall dflags ccall_uniq fcall (map Var args) io_res_ty- rhs = mkLams tvs (mkLams args call_app)- rhs' = Cast rhs co- return ([(fn_id, rhs')], empty, empty)--\end{code}--%************************************************************************-%* *-\subsection{Foreign export}-%* *-%************************************************************************--The function that does most of the work for `@foreign export@' declarations.-(see below for the boilerplate code a `@foreign export@' declaration expands- into.)--For each `@foreign export foo@' in a module M we generate:-\begin{itemize}-\item a C function `@foo@', which calls-\item a Haskell stub `@M.\$ffoo@', which calls-\end{itemize}-the user-written Haskell function `@M.foo@'.--\begin{code}-dsFExport :: Id -- Either the exported Id,- -- or the foreign-export-dynamic constructor- -> Coercion -- Coercion between the Haskell type callable- -- from C, and its representation type- -> CLabelString -- The name to export to C land- -> CCallConv- -> Bool -- True => foreign export dynamic- -- so invoke IO action that's hanging off- -- the first argument's stable pointer- -> DsM ( SDoc -- contents of Module_stub.h- , SDoc -- contents of Module_stub.c- , String -- string describing type to pass to createAdj.- , Int -- size of args to stub function- )--dsFExport fn_id co ext_name cconv isDyn = do- let- ty = pSnd $ coercionKind co- (_tvs,sans_foralls) = tcSplitForAllTys ty- (fe_arg_tys', orig_res_ty) = tcSplitFunTys sans_foralls- -- We must use tcSplits here, because we want to see- -- the (IO t) in the corner of the type!- fe_arg_tys | isDyn = tail fe_arg_tys'- | otherwise = fe_arg_tys'-- -- Look at the result type of the exported function, orig_res_ty- -- If it's IO t, return (t, True)- -- If it's plain t, return (t, False)- (res_ty, is_IO_res_ty) = case tcSplitIOType_maybe orig_res_ty of- -- The function already returns IO t- Just (_ioTyCon, res_ty) -> (res_ty, True)- -- The function returns t- Nothing -> (orig_res_ty, False)-- dflags <- getDynFlags- return $- mkFExportCBits dflags ext_name- (if isDyn then Nothing else Just fn_id)- fe_arg_tys res_ty is_IO_res_ty cconv-\end{code}--@foreign import "wrapper"@ (previously "foreign export dynamic") lets-you dress up Haskell IO actions of some fixed type behind an-externally callable interface (i.e., as a C function pointer). Useful-for callbacks and stuff.--\begin{verbatim}-type Fun = Bool -> Int -> IO Int-foreign import "wrapper" f :: Fun -> IO (FunPtr Fun)---- Haskell-visible constructor, which is generated from the above:--- SUP: No check for NULL from createAdjustor anymore???--f :: Fun -> IO (FunPtr Fun)-f cback =- bindIO (newStablePtr cback)- (\StablePtr sp# -> IO (\s1# ->- case _ccall_ createAdjustor cconv sp# ``f_helper'' <arg info> s1# of- (# s2#, a# #) -> (# s2#, A# a# #)))--foreign import "&f_helper" f_helper :: FunPtr (StablePtr Fun -> Fun)---- and the helper in C:--f_helper(StablePtr s, HsBool b, HsInt i)-{- rts_evalIO(rts_apply(rts_apply(deRefStablePtr(s),- rts_mkBool(b)), rts_mkInt(i)));-}-\end{verbatim}--\begin{code}-dsFExportDynamic :: Id- -> Coercion- -> CCallConv- -> DsM ([Binding], SDoc, SDoc)-dsFExportDynamic id co0 cconv = do- fe_id <- newSysLocalDs ty- mod <- getModule- dflags <- getDynFlags- let- -- hack: need to get at the name of the C stub we're about to generate.- -- TODO: There's no real need to go via String with- -- (mkFastString . zString). In fact, is there a reason to convert- -- to FastString at all now, rather than sticking with FastZString?- fe_nm = mkFastString (zString (zEncodeFS (moduleNameFS (moduleName mod))) ++ "_" ++ toCName dflags fe_id)-- cback <- newSysLocalDs arg_ty- newStablePtrId <- dsLookupGlobalId newStablePtrName- stable_ptr_tycon <- dsLookupTyCon stablePtrTyConName- let- stable_ptr_ty = mkTyConApp stable_ptr_tycon [arg_ty]- export_ty = mkFunTy stable_ptr_ty arg_ty- bindIOId <- dsLookupGlobalId bindIOName- stbl_value <- newSysLocalDs stable_ptr_ty- (h_code, c_code, typestring, args_size) <- dsFExport id (mkReflCo Representational export_ty) fe_nm cconv True- let- {-- The arguments to the external function which will- create a little bit of (template) code on the fly- for allowing the (stable pointed) Haskell closure- to be entered using an external calling convention- (stdcall, ccall).- -}- adj_args = [ mkIntLitInt dflags (ccallConvToInt cconv)- , Var stbl_value- , Lit (MachLabel fe_nm mb_sz_args IsFunction)- , Lit (mkMachString typestring)- ]- -- name of external entry point providing these services.- -- (probably in the RTS.)- adjustor = fsLit "createAdjustor"-- -- Determine the number of bytes of arguments to the stub function,- -- so that we can attach the '@N' suffix to its label if it is a- -- stdcall on Windows.- mb_sz_args = case cconv of- StdCallConv -> Just args_size- _ -> Nothing-- ccall_adj <- dsCCall adjustor adj_args PlayRisky (mkTyConApp io_tc [res_ty])- -- PlayRisky: the adjustor doesn't allocate in the Haskell heap or do a callback-- let io_app = mkLams tvs $- Lam cback $- mkApps (Var bindIOId)- [ Type stable_ptr_ty- , Type res_ty- , mkApps (Var newStablePtrId) [ Type arg_ty, Var cback ]- , Lam stbl_value ccall_adj- ]-- fed = (id `setInlineActivation` NeverActive, Cast io_app co0)- -- Never inline the f.e.d. function, because the litlit- -- might not be in scope in other modules.-- return ([fed], h_code, c_code)-- where- ty = pFst (coercionKind co0)- (tvs,sans_foralls) = tcSplitForAllTys ty- ([arg_ty], fn_res_ty) = tcSplitFunTys sans_foralls- Just (io_tc, res_ty) = tcSplitIOType_maybe fn_res_ty- -- Must have an IO type; hence Just--toCName :: DynFlags -> Id -> String-toCName dflags i = showSDoc dflags (pprCode CStyle (ppr (idName i)))-\end{code}--%*-%-\subsection{Generating @foreign export@ stubs}-%-%*--For each @foreign export@ function, a C stub function is generated.-The C stub constructs the application of the exported Haskell function-using the hugs/ghc rts invocation API.--\begin{code}-mkFExportCBits :: DynFlags- -> FastString- -> Maybe Id -- Just==static, Nothing==dynamic- -> [Type]- -> Type- -> Bool -- True <=> returns an IO type- -> CCallConv- -> (SDoc,- SDoc,- String, -- the argument reps- Int -- total size of arguments- )-mkFExportCBits dflags c_nm maybe_target arg_htys res_hty is_IO_res_ty cc- = (header_bits, c_bits, type_string,- sum [ widthInBytes (typeWidth rep) | (_,_,_,rep) <- aug_arg_info] -- all the args- -- NB. the calculation here isn't strictly speaking correct.- -- We have a primitive Haskell type (eg. Int#, Double#), and- -- we want to know the size, when passed on the C stack, of- -- the associated C type (eg. HsInt, HsDouble). We don't have- -- this information to hand, but we know what GHC's conventions- -- are for passing around the primitive Haskell types, so we- -- use that instead. I hope the two coincide --SDM- )- where- -- list the arguments to the C function- arg_info :: [(SDoc, -- arg name- SDoc, -- C type- Type, -- Haskell type- CmmType)] -- the CmmType- arg_info = [ let stg_type = showStgType ty in- (arg_cname n stg_type,- stg_type,- ty,- typeCmmType dflags (getPrimTyOf ty))- | (ty,n) <- zip arg_htys [1::Int ..] ]-- arg_cname n stg_ty- | libffi = char '*' <> parens (stg_ty <> char '*') <>- ptext (sLit "args") <> brackets (int (n-1))- | otherwise = text ('a':show n)-- -- generate a libffi-style stub if this is a "wrapper" and libffi is enabled- libffi = cLibFFI && isNothing maybe_target-- type_string- -- libffi needs to know the result type too:- | libffi = primTyDescChar dflags res_hty : arg_type_string- | otherwise = arg_type_string-- arg_type_string = [primTyDescChar dflags ty | (_,_,ty,_) <- arg_info]- -- just the real args-- -- add some auxiliary args; the stable ptr in the wrapper case, and- -- a slot for the dummy return address in the wrapper + ccall case- aug_arg_info- | isNothing maybe_target = stable_ptr_arg : insertRetAddr dflags cc arg_info- | otherwise = arg_info-- stable_ptr_arg =- (text "the_stableptr", text "StgStablePtr", undefined,- typeCmmType dflags (mkStablePtrPrimTy alphaTy))-- -- stuff to do with the return type of the C function- res_hty_is_unit = res_hty `eqType` unitTy -- Look through any newtypes-- cResType | res_hty_is_unit = text "void"- | otherwise = showStgType res_hty-- -- when the return type is integral and word-sized or smaller, it- -- must be assigned as type ffi_arg (#3516). To see what type- -- libffi is expecting here, take a look in its own testsuite, e.g.- -- libffi/testsuite/libffi.call/cls_align_ulonglong.c- ffi_cResType- | is_ffi_arg_type = text "ffi_arg"- | otherwise = cResType- where- res_ty_key = getUnique (getName (typeTyCon res_hty))- is_ffi_arg_type = res_ty_key `notElem`- [floatTyConKey, doubleTyConKey,- int64TyConKey, word64TyConKey]-- -- Now we can cook up the prototype for the exported function.- pprCconv = ccallConvAttribute cc-- header_bits = ptext (sLit "extern") <+> fun_proto <> semi-- fun_args- | null aug_arg_info = text "void"- | otherwise = hsep $ punctuate comma- $ map (\(nm,ty,_,_) -> ty <+> nm) aug_arg_info-- fun_proto- | libffi- = ptext (sLit "void") <+> ftext c_nm <>- parens (ptext (sLit "void *cif STG_UNUSED, void* resp, void** args, void* the_stableptr"))- | otherwise- = cResType <+> pprCconv <+> ftext c_nm <> parens fun_args-- -- the target which will form the root of what we ask rts_evalIO to run- the_cfun- = case maybe_target of- Nothing -> text "(StgClosure*)deRefStablePtr(the_stableptr)"- Just hs_fn -> char '&' <> ppr hs_fn <> text "_closure"-- cap = text "cap" <> comma-- -- the expression we give to rts_evalIO- expr_to_run- = foldl appArg the_cfun arg_info -- NOT aug_arg_info- where- appArg acc (arg_cname, _, arg_hty, _)- = text "rts_apply"- <> parens (cap <> acc <> comma <> mkHObj arg_hty <> parens (cap <> arg_cname))-- -- various other bits for inside the fn- declareResult = text "HaskellObj ret;"- declareCResult | res_hty_is_unit = empty- | otherwise = cResType <+> text "cret;"-- assignCResult | res_hty_is_unit = empty- | otherwise =- text "cret=" <> unpackHObj res_hty <> parens (text "ret") <> semi-- -- an extern decl for the fn being called- extern_decl- = case maybe_target of- Nothing -> empty- Just hs_fn -> text "extern StgClosure " <> ppr hs_fn <> text "_closure" <> semi--- -- finally, the whole darn thing- c_bits =- space $$- extern_decl $$- fun_proto $$- vcat- [ lbrace- , ptext (sLit "Capability *cap;")- , declareResult- , declareCResult- , text "cap = rts_lock();"- -- create the application + perform it.- , ptext (sLit "rts_evalIO") <> parens (- char '&' <> cap <>- ptext (sLit "rts_apply") <> parens (- cap <>- text "(HaskellObj)"- <> ptext (if is_IO_res_ty- then (sLit "runIO_closure")- else (sLit "runNonIO_closure"))- <> comma- <> expr_to_run- ) <+> comma- <> text "&ret"- ) <> semi- , ptext (sLit "rts_checkSchedStatus") <> parens (doubleQuotes (ftext c_nm)- <> comma <> text "cap") <> semi- , assignCResult- , ptext (sLit "rts_unlock(cap);")- , ppUnless res_hty_is_unit $- if libffi- then char '*' <> parens (ffi_cResType <> char '*') <>- ptext (sLit "resp = cret;")- else ptext (sLit "return cret;")- , rbrace- ]---foreignExportInitialiser :: Id -> SDoc-foreignExportInitialiser hs_fn =- -- Initialise foreign exports by registering a stable pointer from an- -- __attribute__((constructor)) function.- -- The alternative is to do this from stginit functions generated in- -- codeGen/CodeGen.lhs; however, stginit functions have a negative impact- -- on binary sizes and link times because the static linker will think that- -- all modules that are imported directly or indirectly are actually used by- -- the program.- -- (this is bad for big umbrella modules like Graphics.Rendering.OpenGL)- vcat- [ text "static void stginit_export_" <> ppr hs_fn- <> text "() __attribute__((constructor));"- , text "static void stginit_export_" <> ppr hs_fn <> text "()"- , braces (text "foreignExportStablePtr"- <> parens (text "(StgPtr) &" <> ppr hs_fn <> text "_closure")- <> semi)- ]---mkHObj :: Type -> SDoc-mkHObj t = text "rts_mk" <> text (showFFIType t)--unpackHObj :: Type -> SDoc-unpackHObj t = text "rts_get" <> text (showFFIType t)--showStgType :: Type -> SDoc-showStgType t = text "Hs" <> text (showFFIType t)--showFFIType :: Type -> String-showFFIType t = getOccString (getName (typeTyCon t))--toCType :: Type -> (Maybe Header, SDoc)-toCType = f False- where f voidOK t- -- First, if we have (Ptr t) of (FunPtr t), then we need to- -- convert t to a C type and put a * after it. If we don't- -- know a type for t, then "void" is fine, though.- | Just (ptr, [t']) <- splitTyConApp_maybe t- , tyConName ptr `elem` [ptrTyConName, funPtrTyConName]- = case f True t' of- (mh, cType') ->- (mh, cType' <> char '*')- -- Otherwise, if we have a type constructor application, then- -- see if there is a C type associated with that constructor.- -- Note that we aren't looking through type synonyms or- -- anything, as it may be the synonym that is annotated.- | TyConApp tycon _ <- t- , Just (CType mHeader cType) <- tyConCType_maybe tycon- = (mHeader, ftext cType)- -- If we don't know a C type for this type, then try looking- -- through one layer of type synonym etc.- | Just t' <- coreView t- = f voidOK t'- -- Otherwise we don't know the C type. If we are allowing- -- void then return that; otherwise something has gone wrong.- | voidOK = (Nothing, ptext (sLit "void"))- | otherwise- = pprPanic "toCType" (ppr t)--typeTyCon :: Type -> TyCon-typeTyCon ty- | UnaryRep rep_ty <- repType ty- , Just (tc, _) <- tcSplitTyConApp_maybe rep_ty- = tc- | otherwise- = pprPanic "DsForeign.typeTyCon" (ppr ty)--insertRetAddr :: DynFlags -> CCallConv- -> [(SDoc, SDoc, Type, CmmType)]- -> [(SDoc, SDoc, Type, CmmType)]-insertRetAddr dflags CCallConv args- = case platformArch platform of- ArchX86_64- | platformOS platform == OSMinGW32 ->- -- On other Windows x86_64 we insert the return address- -- after the 4th argument, because this is the point- -- at which we need to flush a register argument to the stack- -- (See rts/Adjustor.c for details).- let go :: Int -> [(SDoc, SDoc, Type, CmmType)]- -> [(SDoc, SDoc, Type, CmmType)]- go 4 args = ret_addr_arg dflags : args- go n (arg:args) = arg : go (n+1) args- go _ [] = []- in go 0 args- | otherwise ->- -- On other x86_64 platforms we insert the return address- -- after the 6th integer argument, because this is the point- -- at which we need to flush a register argument to the stack- -- (See rts/Adjustor.c for details).- let go :: Int -> [(SDoc, SDoc, Type, CmmType)]- -> [(SDoc, SDoc, Type, CmmType)]- go 6 args = ret_addr_arg dflags : args- go n (arg@(_,_,_,rep):args)- | cmmEqType_ignoring_ptrhood rep b64 = arg : go (n+1) args- | otherwise = arg : go n args- go _ [] = []- in go 0 args- _ ->- ret_addr_arg dflags : args- where platform = targetPlatform dflags-insertRetAddr _ _ args = args--ret_addr_arg :: DynFlags -> (SDoc, SDoc, Type, CmmType)-ret_addr_arg dflags = (text "original_return_addr", text "void*", undefined,- typeCmmType dflags addrPrimTy)---- This function returns the primitive type associated with the boxed--- type argument to a foreign export (eg. Int ==> Int#).-getPrimTyOf :: Type -> UnaryType-getPrimTyOf ty- | isBoolTy rep_ty = intPrimTy- -- Except for Bool, the types we are interested in have a single constructor- -- with a single primitive-typed argument (see TcType.legalFEArgTyCon).- | otherwise =- case splitDataProductType_maybe rep_ty of- Just (_, _, _, [prim_ty]) ->- -- ASSERT(dataConSourceArity data_con == 1)- -- ASSERT2(isUnLiftedType prim_ty, ppr prim_ty)- prim_ty- _other -> pprPanic "DsForeign.getPrimTyOf" (ppr ty)- where- UnaryRep rep_ty = repType ty---- represent a primitive type as a Char, for building a string that--- described the foreign function type. The types are size-dependent,--- e.g. 'W' is a signed 32-bit integer.-primTyDescChar :: DynFlags -> Type -> Char-primTyDescChar dflags ty- | ty `eqType` unitTy = 'v'- | otherwise- = case typePrimRep (getPrimTyOf ty) of- IntRep -> signed_word- WordRep -> unsigned_word- Int64Rep -> 'L'- Word64Rep -> 'l'- AddrRep -> 'p'- FloatRep -> 'f'- DoubleRep -> 'd'- _ -> pprPanic "primTyDescChar" (ppr ty)- where- (signed_word, unsigned_word)- | wORD_SIZE dflags == 4 = ('W','w')- | wORD_SIZE dflags == 8 = ('L','l')- | otherwise = panic "primTyDescChar"-\end{code}
− src/Language/Haskell/Liquid/Desugar/DsGRHSs.lhs
@@ -1,160 +0,0 @@-%-% (c) The University of Glasgow 2006-% (c) The GRASP/AQUA Project, Glasgow University, 1992-1998-%--Matching guarded right-hand-sides (GRHSs)--\begin{code}-module Language.Haskell.Liquid.Desugar.DsGRHSs ( dsGuarded, dsGRHSs, dsGRHS ) where---- #include "HsVersions.h"--import {-# SOURCE #-} Language.Haskell.Liquid.Desugar.DsExpr ( dsLExpr, dsLocalBinds )-import {-# SOURCE #-} Language.Haskell.Liquid.Desugar.Match ( matchSinglePat )--import HsSyn-import MkCore-import CoreSyn-import Var-import Type--import DsMonad-import Language.Haskell.Liquid.Desugar.DsUtils-import TysWiredIn-import PrelNames-import Module-import Name-import SrcLoc-import Outputable-\end{code}--@dsGuarded@ is used for both @case@ expressions and pattern bindings.-It desugars:-\begin{verbatim}- | g1 -> e1- ...- | gn -> en- where binds-\end{verbatim}-producing an expression with a runtime error in the corner if-necessary. The type argument gives the type of the @ei@.--\begin{code}-dsGuarded :: GRHSs Id (LHsExpr Id) -> Type -> DsM CoreExpr--dsGuarded grhss rhs_ty = do- match_result <- dsGRHSs PatBindRhs [] grhss rhs_ty- error_expr <- mkErrorAppDs nON_EXHAUSTIVE_GUARDS_ERROR_ID rhs_ty empty- extractMatchResult match_result error_expr-\end{code}--In contrast, @dsGRHSs@ produces a @MatchResult@.--\begin{code}-dsGRHSs :: HsMatchContext Name -> [Pat Id] -- These are to build a MatchContext from- -> GRHSs Id (LHsExpr Id) -- Guarded RHSs- -> Type -- Type of RHS- -> DsM MatchResult-dsGRHSs hs_ctx _ (GRHSs grhss binds) rhs_ty - = -- ASSERT( notNull grhss )- do { match_results <- mapM (dsGRHS hs_ctx rhs_ty) grhss- ; let match_result1 = foldr1 combineMatchResults match_results- match_result2 = adjustMatchResultDs- (\e -> dsLocalBinds binds e)- match_result1- -- NB: nested dsLet inside matchResult- ; return match_result2 }--dsGRHS :: HsMatchContext Name -> Type -> LGRHS Id (LHsExpr Id) -> DsM MatchResult-dsGRHS hs_ctx rhs_ty (L _ (GRHS guards rhs))- = matchGuards (map unLoc guards) (PatGuard hs_ctx) rhs rhs_ty-\end{code}---%************************************************************************-%* *-%* matchGuard : make a MatchResult from a guarded RHS *-%* *-%************************************************************************--\begin{code}-matchGuards :: [GuardStmt Id] -- Guard- -> HsStmtContext Name -- Context- -> LHsExpr Id -- RHS- -> Type -- Type of RHS of guard- -> DsM MatchResult---- See comments with HsExpr.Stmt re what a BodyStmt means--- Here we must be in a guard context (not do-expression, nor list-comp)--matchGuards [] _ rhs _- = do { core_rhs <- dsLExpr rhs- ; return (cantFailMatchResult core_rhs) }-- -- BodyStmts must be guards- -- Turn an "otherwise" guard is a no-op. This ensures that- -- you don't get a "non-exhaustive eqns" message when the guards- -- finish in "otherwise".- -- NB: The success of this clause depends on the typechecker not- -- wrapping the 'otherwise' in empty HsTyApp or HsWrap constructors- -- If it does, you'll get bogus overlap warnings-matchGuards (BodyStmt e _ _ _ : stmts) ctx rhs rhs_ty- | Just addTicks <- isTrueLHsExpr e = do- match_result <- matchGuards stmts ctx rhs rhs_ty- return (adjustMatchResultDs addTicks match_result)-matchGuards (BodyStmt expr _ _ _ : stmts) ctx rhs rhs_ty = do- match_result <- matchGuards stmts ctx rhs rhs_ty- pred_expr <- dsLExpr expr- return (mkGuardedMatchResult pred_expr match_result)--matchGuards (LetStmt binds : stmts) ctx rhs rhs_ty = do- match_result <- matchGuards stmts ctx rhs rhs_ty- return (adjustMatchResultDs (dsLocalBinds binds) match_result)- -- NB the dsLet occurs inside the match_result- -- Reason: dsLet takes the body expression as its argument- -- so we can't desugar the bindings without the- -- body expression in hand--matchGuards (BindStmt pat bind_rhs _ _ : stmts) ctx rhs rhs_ty = do- match_result <- matchGuards stmts ctx rhs rhs_ty- core_rhs <- dsLExpr bind_rhs- matchSinglePat core_rhs (StmtCtxt ctx) pat rhs_ty match_result--matchGuards (LastStmt {} : _) _ _ _ = panic "matchGuards LastStmt"-matchGuards (ParStmt {} : _) _ _ _ = panic "matchGuards ParStmt"-matchGuards (TransStmt {} : _) _ _ _ = panic "matchGuards TransStmt"-matchGuards (RecStmt {} : _) _ _ _ = panic "matchGuards RecStmt"--isTrueLHsExpr :: LHsExpr Id -> Maybe (CoreExpr -> DsM CoreExpr)---- Returns Just {..} if we're sure that the expression is True--- I.e. * 'True' datacon--- * 'otherwise' Id--- * Trivial wappings of these--- The arguments to Just are any HsTicks that we have found,--- because we still want to tick then, even it they are aways evaluted.-isTrueLHsExpr (L _ (HsVar v)) | v `hasKey` otherwiseIdKey- || v `hasKey` getUnique trueDataConId- = Just return- -- trueDataConId doesn't have the same unique as trueDataCon-isTrueLHsExpr (L _ (HsTick tickish e))- | Just ticks <- isTrueLHsExpr e- = Just (\x -> ticks x >>= return . (Tick tickish))- -- This encodes that the result is constant True for Hpc tick purposes;- -- which is specifically what isTrueLHsExpr is trying to find out.-isTrueLHsExpr (L _ (HsBinTick ixT _ e))- | Just ticks <- isTrueLHsExpr e- = Just (\x -> do e <- ticks x- this_mod <- getModule- return (Tick (HpcTick this_mod ixT) e))--isTrueLHsExpr (L _ (HsPar e)) = isTrueLHsExpr e-isTrueLHsExpr _ = Nothing-\end{code}--Should {\em fail} if @e@ returns @D@-\begin{verbatim}-f x | p <- e', let C y# = e, f y# = r1- | otherwise = r2-\end{verbatim}
− src/Language/Haskell/Liquid/Desugar/DsListComp.lhs
@@ -1,879 +0,0 @@-%-% (c) The University of Glasgow 2006-% (c) The GRASP/AQUA Project, Glasgow University, 1992-1998-%--Desugaring list comprehensions, monad comprehensions and array comprehensions--\begin{code}-{-# LANGUAGE NamedFieldPuns #-}--module Language.Haskell.Liquid.Desugar.DsListComp ( dsListComp, dsPArrComp, dsMonadComp ) where---- #include "HsVersions.h"--import {-# SOURCE #-} Language.Haskell.Liquid.Desugar.DsExpr ( dsExpr, dsLExpr, dsLocalBinds )--import HsSyn-import TcHsSyn-import CoreSyn-import MkCore--import DsMonad -- the monadery used in the desugarer-import Language.Haskell.Liquid.Desugar.DsUtils--import DynFlags-import CoreUtils-import Id-import Type-import TysWiredIn-import Language.Haskell.Liquid.Desugar.Match-import PrelNames-import SrcLoc-import Outputable-import FastString-import TcType-import ListSetOps( getNth )-\end{code}--List comprehensions may be desugared in one of two ways: ``ordinary''-(as you would expect if you read SLPJ's book) and ``with foldr/build-turned on'' (if you read Gill {\em et al.}'s paper on the subject).--There will be at least one ``qualifier'' in the input.--\begin{code}-dsListComp :: [ExprLStmt Id]- -> Type -- Type of entire list- -> DsM CoreExpr-dsListComp lquals res_ty = do- dflags <- getDynFlags- let quals = map unLoc lquals- elt_ty = case tcTyConAppArgs res_ty of- [elt_ty] -> elt_ty- _ -> pprPanic "dsListComp" (ppr res_ty $$ ppr lquals)-- if not (gopt Opt_EnableRewriteRules dflags) || gopt Opt_IgnoreInterfacePragmas dflags- -- Either rules are switched off, or we are ignoring what there are;- -- Either way foldr/build won't happen, so use the more efficient- -- Wadler-style desugaring- || isParallelComp quals- -- Foldr-style desugaring can't handle parallel list comprehensions- then deListComp quals (mkNilExpr elt_ty)- else mkBuildExpr elt_ty (\(c, _) (n, _) -> dfListComp c n quals)- -- Foldr/build should be enabled, so desugar- -- into foldrs and builds-- where- -- We must test for ParStmt anywhere, not just at the head, because an extension- -- to list comprehensions would be to add brackets to specify the associativity- -- of qualifier lists. This is really easy to do by adding extra ParStmts into the- -- mix of possibly a single element in length, so we do this to leave the possibility open- isParallelComp = any isParallelStmt-- isParallelStmt (ParStmt {}) = True- isParallelStmt _ = False----- This function lets you desugar a inner list comprehension and a list of the binders--- of that comprehension that we need in the outer comprehension into such an expression--- and the type of the elements that it outputs (tuples of binders)-dsInnerListComp :: (ParStmtBlock Id Id) -> DsM (CoreExpr, Type)-dsInnerListComp (ParStmtBlock stmts bndrs _)- = do { expr <- dsListComp (stmts ++ [noLoc $ mkLastStmt (mkBigLHsVarTup bndrs)])- (mkListTy bndrs_tuple_type)- ; return (expr, bndrs_tuple_type) }- where- bndrs_tuple_type = mkBigCoreVarTupTy bndrs---- This function factors out commonality between the desugaring strategies for GroupStmt.--- Given such a statement it gives you back an expression representing how to compute the transformed--- list and the tuple that you need to bind from that list in order to proceed with your desugaring-dsTransStmt :: ExprStmt Id -> DsM (CoreExpr, LPat Id)-dsTransStmt (TransStmt { trS_form = form, trS_stmts = stmts, trS_bndrs = binderMap- , trS_by = by, trS_using = using }) = do- let (from_bndrs, to_bndrs) = unzip binderMap- from_bndrs_tys = map idType from_bndrs- to_bndrs_tys = map idType to_bndrs- to_bndrs_tup_ty = mkBigCoreTupTy to_bndrs_tys-- -- Desugar an inner comprehension which outputs a list of tuples of the "from" binders- (expr, from_tup_ty) <- dsInnerListComp (ParStmtBlock stmts from_bndrs noSyntaxExpr)-- -- Work out what arguments should be supplied to that expression: i.e. is an extraction- -- function required? If so, create that desugared function and add to arguments- usingExpr' <- dsLExpr using- usingArgs <- case by of- Nothing -> return [expr]- Just by_e -> do { by_e' <- dsLExpr by_e- ; lam <- matchTuple from_bndrs by_e'- ; return [lam, expr] }-- -- Create an unzip function for the appropriate arity and element types and find "map"- unzip_stuff <- mkUnzipBind form from_bndrs_tys- map_id <- dsLookupGlobalId mapName-- -- Generate the expressions to build the grouped list- let -- First we apply the grouping function to the inner list- inner_list_expr = mkApps usingExpr' usingArgs- -- Then we map our "unzip" across it to turn the lists of tuples into tuples of lists- -- We make sure we instantiate the type variable "a" to be a list of "from" tuples and- -- the "b" to be a tuple of "to" lists!- -- Then finally we bind the unzip function around that expression- bound_unzipped_inner_list_expr- = case unzip_stuff of- Nothing -> inner_list_expr- Just (unzip_fn, unzip_rhs) -> Let (Rec [(unzip_fn, unzip_rhs)]) $- mkApps (Var map_id) $- [ Type (mkListTy from_tup_ty)- , Type to_bndrs_tup_ty- , Var unzip_fn- , inner_list_expr]-- -- Build a pattern that ensures the consumer binds into the NEW binders,- -- which hold lists rather than single values- let pat = mkBigLHsVarPatTup to_bndrs- return (bound_unzipped_inner_list_expr, pat)--dsTransStmt _ = panic "dsTransStmt: Not given a TransStmt"-\end{code}--%************************************************************************-%* *-\subsection[DsListComp-ordinary]{Ordinary desugaring of list comprehensions}-%* *-%************************************************************************--Just as in Phil's chapter~7 in SLPJ, using the rules for-optimally-compiled list comprehensions. This is what Kevin followed-as well, and I quite happily do the same. The TQ translation scheme-transforms a list of qualifiers (either boolean expressions or-generators) into a single expression which implements the list-comprehension. Because we are generating 2nd-order polymorphic-lambda-calculus, calls to NIL and CONS must be applied to a type-argument, as well as their usual value arguments.-\begin{verbatim}-TE << [ e | qs ] >> = TQ << [ e | qs ] ++ Nil (typeOf e) >>--(Rule C)-TQ << [ e | ] ++ L >> = Cons (typeOf e) TE <<e>> TE <<L>>--(Rule B)-TQ << [ e | b , qs ] ++ L >> =- if TE << b >> then TQ << [ e | qs ] ++ L >> else TE << L >>--(Rule A')-TQ << [ e | p <- L1, qs ] ++ L2 >> =- letrec- h = \ u1 ->- case u1 of- [] -> TE << L2 >>- (u2 : u3) ->- (( \ TE << p >> -> ( TQ << [e | qs] ++ (h u3) >> )) u2)- [] (h u3)- in- h ( TE << L1 >> )--"h", "u1", "u2", and "u3" are new variables.-\end{verbatim}--@deListComp@ is the TQ translation scheme. Roughly speaking, @dsExpr@-is the TE translation scheme. Note that we carry around the @L@ list-already desugared. @dsListComp@ does the top TE rule mentioned above.--To the above, we add an additional rule to deal with parallel list-comprehensions. The translation goes roughly as follows:- [ e | p1 <- e11, let v1 = e12, p2 <- e13- | q1 <- e21, let v2 = e22, q2 <- e23]- =>- [ e | ((x1, .., xn), (y1, ..., ym)) <-- zip [(x1,..,xn) | p1 <- e11, let v1 = e12, p2 <- e13]- [(y1,..,ym) | q1 <- e21, let v2 = e22, q2 <- e23]]-where (x1, .., xn) are the variables bound in p1, v1, p2- (y1, .., ym) are the variables bound in q1, v2, q2--In the translation below, the ParStmt branch translates each parallel branch-into a sub-comprehension, and desugars each independently. The resulting lists-are fed to a zip function, we create a binding for all the variables bound in all-the comprehensions, and then we hand things off the the desugarer for bindings.-The zip function is generated here a) because it's small, and b) because then we-don't have to deal with arbitrary limits on the number of zip functions in the-prelude, nor which library the zip function came from.-The introduced tuples are Boxed, but only because I couldn't get it to work-with the Unboxed variety.--\begin{code}--deListComp :: [ExprStmt Id] -> CoreExpr -> DsM CoreExpr--deListComp [] _ = panic "deListComp"--deListComp (LastStmt body _ : _) list- = -- Figure 7.4, SLPJ, p 135, rule C above- -- ASSERT( null quals )- do { core_body <- dsLExpr body- ; return (mkConsExpr (exprType core_body) core_body list) }-- -- Non-last: must be a guard-deListComp (BodyStmt guard _ _ _ : quals) list = do -- rule B above- core_guard <- dsLExpr guard- core_rest <- deListComp quals list- return (mkIfThenElse core_guard core_rest list)---- [e | let B, qs] = let B in [e | qs]-deListComp (LetStmt binds : quals) list = do- core_rest <- deListComp quals list- dsLocalBinds binds core_rest--deListComp (stmt@(TransStmt {}) : quals) list = do- (inner_list_expr, pat) <- dsTransStmt stmt- deBindComp pat inner_list_expr quals list--deListComp (BindStmt pat list1 _ _ : quals) core_list2 = do -- rule A' above- core_list1 <- dsLExpr list1- deBindComp pat core_list1 quals core_list2--deListComp (ParStmt stmtss_w_bndrs _ _ : quals) list- = do { exps_and_qual_tys <- mapM dsInnerListComp stmtss_w_bndrs- ; let (exps, qual_tys) = unzip exps_and_qual_tys-- ; (zip_fn, zip_rhs) <- mkZipBind qual_tys-- -- Deal with [e | pat <- zip l1 .. ln] in example above- ; deBindComp pat (Let (Rec [(zip_fn, zip_rhs)]) (mkApps (Var zip_fn) exps))- quals list }- where- bndrs_s = [bs | ParStmtBlock _ bs _ <- stmtss_w_bndrs]-- -- pat is the pattern ((x1,..,xn), (y1,..,ym)) in the example above- pat = mkBigLHsPatTup pats- pats = map mkBigLHsVarPatTup bndrs_s--deListComp (RecStmt {} : _) _ = panic "deListComp RecStmt"-\end{code}---\begin{code}-deBindComp :: OutPat Id- -> CoreExpr- -> [ExprStmt Id]- -> CoreExpr- -> DsM (Expr Id)-deBindComp pat core_list1 quals core_list2 = do- let- u3_ty@u1_ty = exprType core_list1 -- two names, same thing-- -- u1_ty is a [alpha] type, and u2_ty = alpha- u2_ty = hsLPatType pat-- res_ty = exprType core_list2- h_ty = u1_ty `mkFunTy` res_ty-- [h, u1, u2, u3] <- newSysLocalsDs [h_ty, u1_ty, u2_ty, u3_ty]-- -- the "fail" value ...- let- core_fail = App (Var h) (Var u3)- letrec_body = App (Var h) core_list1-- rest_expr <- deListComp quals core_fail- core_match <- matchSimply (Var u2) (StmtCtxt ListComp) pat rest_expr core_fail-- let- rhs = Lam u1 $- Case (Var u1) u1 res_ty- [(DataAlt nilDataCon, [], core_list2),- (DataAlt consDataCon, [u2, u3], core_match)]- -- Increasing order of tag-- return (Let (Rec [(h, rhs)]) letrec_body)-\end{code}--%************************************************************************-%* *-\subsection[DsListComp-foldr-build]{Foldr/Build desugaring of list comprehensions}-%* *-%************************************************************************--@dfListComp@ are the rules used with foldr/build turned on:--\begin{verbatim}-TE[ e | ] c n = c e n-TE[ e | b , q ] c n = if b then TE[ e | q ] c n else n-TE[ e | p <- l , q ] c n = let- f = \ x b -> case x of- p -> TE[ e | q ] c b- _ -> b- in- foldr f n l-\end{verbatim}--\begin{code}-dfListComp :: Id -> Id -- 'c' and 'n'- -> [ExprStmt Id] -- the rest of the qual's- -> DsM CoreExpr--dfListComp _ _ [] = panic "dfListComp"--dfListComp c_id n_id (LastStmt body _ : _)- = -- ASSERT( null quals )- do { core_body <- dsLExpr body- ; return (mkApps (Var c_id) [core_body, Var n_id]) }-- -- Non-last: must be a guard-dfListComp c_id n_id (BodyStmt guard _ _ _ : quals) = do- core_guard <- dsLExpr guard- core_rest <- dfListComp c_id n_id quals- return (mkIfThenElse core_guard core_rest (Var n_id))--dfListComp c_id n_id (LetStmt binds : quals) = do- -- new in 1.3, local bindings- core_rest <- dfListComp c_id n_id quals- dsLocalBinds binds core_rest--dfListComp c_id n_id (stmt@(TransStmt {}) : quals) = do- (inner_list_expr, pat) <- dsTransStmt stmt- -- Anyway, we bind the newly grouped list via the generic binding function- dfBindComp c_id n_id (pat, inner_list_expr) quals--dfListComp c_id n_id (BindStmt pat list1 _ _ : quals) = do- -- evaluate the two lists- core_list1 <- dsLExpr list1-- -- Do the rest of the work in the generic binding builder- dfBindComp c_id n_id (pat, core_list1) quals--dfListComp _ _ (ParStmt {} : _) = panic "dfListComp ParStmt"-dfListComp _ _ (RecStmt {} : _) = panic "dfListComp RecStmt"--dfBindComp :: Id -> Id -- 'c' and 'n'- -> (LPat Id, CoreExpr)- -> [ExprStmt Id] -- the rest of the qual's- -> DsM CoreExpr-dfBindComp c_id n_id (pat, core_list1) quals = do- -- find the required type- let x_ty = hsLPatType pat- b_ty = idType n_id-- -- create some new local id's- [b, x] <- newSysLocalsDs [b_ty, x_ty]-- -- build rest of the comprehesion- core_rest <- dfListComp c_id b quals-- -- build the pattern match- core_expr <- matchSimply (Var x) (StmtCtxt ListComp)- pat core_rest (Var b)-- -- now build the outermost foldr, and return- mkFoldrExpr x_ty b_ty (mkLams [x, b] core_expr) (Var n_id) core_list1-\end{code}--%************************************************************************-%* *-\subsection[DsFunGeneration]{Generation of zip/unzip functions for use in desugaring}-%* *-%************************************************************************--\begin{code}--mkZipBind :: [Type] -> DsM (Id, CoreExpr)--- mkZipBind [t1, t2]--- = (zip, \as1:[t1] as2:[t2]--- -> case as1 of--- [] -> []--- (a1:as'1) -> case as2 of--- [] -> []--- (a2:as'2) -> (a1, a2) : zip as'1 as'2)]--mkZipBind elt_tys = do- ass <- mapM newSysLocalDs elt_list_tys- as' <- mapM newSysLocalDs elt_tys- as's <- mapM newSysLocalDs elt_list_tys-- zip_fn <- newSysLocalDs zip_fn_ty-- let inner_rhs = mkConsExpr elt_tuple_ty- (mkBigCoreVarTup as')- (mkVarApps (Var zip_fn) as's)- zip_body = foldr mk_case inner_rhs (zip3 ass as' as's)-- return (zip_fn, mkLams ass zip_body)- where- elt_list_tys = map mkListTy elt_tys- elt_tuple_ty = mkBigCoreTupTy elt_tys- elt_tuple_list_ty = mkListTy elt_tuple_ty-- zip_fn_ty = mkFunTys elt_list_tys elt_tuple_list_ty-- mk_case (as, a', as') rest- = Case (Var as) as elt_tuple_list_ty- [(DataAlt nilDataCon, [], mkNilExpr elt_tuple_ty),- (DataAlt consDataCon, [a', as'], rest)]- -- Increasing order of tag---mkUnzipBind :: TransForm -> [Type] -> DsM (Maybe (Id, CoreExpr))--- mkUnzipBind [t1, t2]--- = (unzip, \ys :: [(t1, t2)] -> foldr (\ax :: (t1, t2) axs :: ([t1], [t2])--- -> case ax of--- (x1, x2) -> case axs of--- (xs1, xs2) -> (x1 : xs1, x2 : xs2))--- ([], [])--- ys)------ We use foldr here in all cases, even if rules are turned off, because we may as well!-mkUnzipBind ThenForm _- = return Nothing -- No unzipping for ThenForm-mkUnzipBind _ elt_tys- = do { ax <- newSysLocalDs elt_tuple_ty- ; axs <- newSysLocalDs elt_list_tuple_ty- ; ys <- newSysLocalDs elt_tuple_list_ty- ; xs <- mapM newSysLocalDs elt_tys- ; xss <- mapM newSysLocalDs elt_list_tys-- ; unzip_fn <- newSysLocalDs unzip_fn_ty-- ; [us1, us2] <- sequence [newUniqueSupply, newUniqueSupply]-- ; let nil_tuple = mkBigCoreTup (map mkNilExpr elt_tys)- concat_expressions = map mkConcatExpression (zip3 elt_tys (map Var xs) (map Var xss))- tupled_concat_expression = mkBigCoreTup concat_expressions-- folder_body_inner_case = mkTupleCase us1 xss tupled_concat_expression axs (Var axs)- folder_body_outer_case = mkTupleCase us2 xs folder_body_inner_case ax (Var ax)- folder_body = mkLams [ax, axs] folder_body_outer_case-- ; unzip_body <- mkFoldrExpr elt_tuple_ty elt_list_tuple_ty folder_body nil_tuple (Var ys)- ; return (Just (unzip_fn, mkLams [ys] unzip_body)) }- where- elt_tuple_ty = mkBigCoreTupTy elt_tys- elt_tuple_list_ty = mkListTy elt_tuple_ty- elt_list_tys = map mkListTy elt_tys- elt_list_tuple_ty = mkBigCoreTupTy elt_list_tys-- unzip_fn_ty = elt_tuple_list_ty `mkFunTy` elt_list_tuple_ty-- mkConcatExpression (list_element_ty, head, tail) = mkConsExpr list_element_ty head tail-\end{code}--%************************************************************************-%* *-\subsection[DsPArrComp]{Desugaring of array comprehensions}-%* *-%************************************************************************--\begin{code}---- entry point for desugaring a parallel array comprehension------ [:e | qss:] = <<[:e | qss:]>> () [:():]----dsPArrComp :: [ExprStmt Id]- -> DsM CoreExpr---- Special case for parallel comprehension-dsPArrComp (ParStmt qss _ _ : quals) = dePArrParComp qss quals---- Special case for simple generators:------ <<[:e' | p <- e, qs:]>> = <<[: e' | qs :]>> p e------ if matching again p cannot fail, or else------ <<[:e' | p <- e, qs:]>> =--- <<[:e' | qs:]>> p (filterP (\x -> case x of {p -> True; _ -> False}) e)----dsPArrComp (BindStmt p e _ _ : qs) = do- filterP <- dsDPHBuiltin filterPVar- ce <- dsLExpr e- let ety'ce = parrElemType ce- false = Var falseDataConId- true = Var trueDataConId- v <- newSysLocalDs ety'ce- pred <- matchSimply (Var v) (StmtCtxt PArrComp) p true false- let gen | isIrrefutableHsPat p = ce- | otherwise = mkApps (Var filterP) [Type ety'ce, mkLams [v] pred, ce]- dePArrComp qs p gen--dsPArrComp qs = do -- no ParStmt in `qs'- sglP <- dsDPHBuiltin singletonPVar- let unitArray = mkApps (Var sglP) [Type unitTy, mkCoreTup []]- dePArrComp qs (noLoc $ WildPat unitTy) unitArray------ the work horse----dePArrComp :: [ExprStmt Id]- -> LPat Id -- the current generator pattern- -> CoreExpr -- the current generator expression- -> DsM CoreExpr--dePArrComp [] _ _ = panic "dePArrComp"------- <<[:e' | :]>> pa ea = mapP (\pa -> e') ea----dePArrComp (LastStmt e' _ : _) pa cea- = -- ASSERT( null quals )- do { mapP <- dsDPHBuiltin mapPVar- ; let ty = parrElemType cea- ; (clam, ty'e') <- deLambda ty pa e'- ; return $ mkApps (Var mapP) [Type ty, Type ty'e', clam, cea] }------ <<[:e' | b, qs:]>> pa ea = <<[:e' | qs:]>> pa (filterP (\pa -> b) ea)----dePArrComp (BodyStmt b _ _ _ : qs) pa cea = do- filterP <- dsDPHBuiltin filterPVar- let ty = parrElemType cea- (clam,_) <- deLambda ty pa b- dePArrComp qs pa (mkApps (Var filterP) [Type ty, clam, cea])------- <<[:e' | p <- e, qs:]>> pa ea =--- let ef = \pa -> e--- in--- <<[:e' | qs:]>> (pa, p) (crossMap ea ef)------ if matching again p cannot fail, or else------ <<[:e' | p <- e, qs:]>> pa ea =--- let ef = \pa -> filterP (\x -> case x of {p -> True; _ -> False}) e--- in--- <<[:e' | qs:]>> (pa, p) (crossMapP ea ef)----dePArrComp (BindStmt p e _ _ : qs) pa cea = do- filterP <- dsDPHBuiltin filterPVar- crossMapP <- dsDPHBuiltin crossMapPVar- ce <- dsLExpr e- let ety'cea = parrElemType cea- ety'ce = parrElemType ce- false = Var falseDataConId- true = Var trueDataConId- v <- newSysLocalDs ety'ce- pred <- matchSimply (Var v) (StmtCtxt PArrComp) p true false- let cef | isIrrefutableHsPat p = ce- | otherwise = mkApps (Var filterP) [Type ety'ce, mkLams [v] pred, ce]- (clam, _) <- mkLambda ety'cea pa cef- let ety'cef = ety'ce -- filter doesn't change the element type- pa' = mkLHsPatTup [pa, p]-- dePArrComp qs pa' (mkApps (Var crossMapP)- [Type ety'cea, Type ety'cef, cea, clam])------ <<[:e' | let ds, qs:]>> pa ea =--- <<[:e' | qs:]>> (pa, (x_1, ..., x_n))--- (mapP (\v@pa -> let ds in (v, (x_1, ..., x_n))) ea)--- where--- {x_1, ..., x_n} = DV (ds) -- Defined Variables----dePArrComp (LetStmt ds : qs) pa cea = do- mapP <- dsDPHBuiltin mapPVar- let xs = collectLocalBinders ds- ty'cea = parrElemType cea- v <- newSysLocalDs ty'cea- clet <- dsLocalBinds ds (mkCoreTup (map Var xs))- let'v <- newSysLocalDs (exprType clet)- let projBody = mkCoreLet (NonRec let'v clet) $- mkCoreTup [Var v, Var let'v]- errTy = exprType projBody- errMsg = ptext (sLit "DsListComp.dePArrComp: internal error!")- cerr <- mkErrorAppDs pAT_ERROR_ID errTy errMsg- ccase <- matchSimply (Var v) (StmtCtxt PArrComp) pa projBody cerr- let pa' = mkLHsPatTup [pa, mkLHsPatTup (map nlVarPat xs)]- proj = mkLams [v] ccase- dePArrComp qs pa' (mkApps (Var mapP)- [Type ty'cea, Type errTy, proj, cea])------ The parser guarantees that parallel comprehensions can only appear as--- singleton qualifier lists, which we already special case in the caller.--- So, encountering one here is a bug.----dePArrComp (ParStmt {} : _) _ _ =- panic "DsListComp.dePArrComp: malformed comprehension AST: ParStmt"-dePArrComp (TransStmt {} : _) _ _ = panic "DsListComp.dePArrComp: TransStmt"-dePArrComp (RecStmt {} : _) _ _ = panic "DsListComp.dePArrComp: RecStmt"---- <<[:e' | qs | qss:]>> pa ea =--- <<[:e' | qss:]>> (pa, (x_1, ..., x_n))--- (zipP ea <<[:(x_1, ..., x_n) | qs:]>>)--- where--- {x_1, ..., x_n} = DV (qs)----dePArrParComp :: [ParStmtBlock Id Id] -> [ExprStmt Id] -> DsM CoreExpr-dePArrParComp qss quals = do- (pQss, ceQss) <- deParStmt qss- dePArrComp quals pQss ceQss- where- deParStmt [] =- -- empty parallel statement lists have no source representation- panic "DsListComp.dePArrComp: Empty parallel list comprehension"- deParStmt (ParStmtBlock qs xs _:qss) = do -- first statement- let res_expr = mkLHsVarTuple xs- cqs <- dsPArrComp (map unLoc qs ++ [mkLastStmt res_expr])- parStmts qss (mkLHsVarPatTup xs) cqs- ---- parStmts [] pa cea = return (pa, cea)- parStmts (ParStmtBlock qs xs _:qss) pa cea = do -- subsequent statements (zip'ed)- zipP <- dsDPHBuiltin zipPVar- let pa' = mkLHsPatTup [pa, mkLHsVarPatTup xs]- ty'cea = parrElemType cea- res_expr = mkLHsVarTuple xs- cqs <- dsPArrComp (map unLoc qs ++ [mkLastStmt res_expr])- let ty'cqs = parrElemType cqs- cea' = mkApps (Var zipP) [Type ty'cea, Type ty'cqs, cea, cqs]- parStmts qss pa' cea'---- generate Core corresponding to `\p -> e'----deLambda :: Type -- type of the argument- -> LPat Id -- argument pattern- -> LHsExpr Id -- body- -> DsM (CoreExpr, Type)-deLambda ty p e =- mkLambda ty p =<< dsLExpr e---- generate Core for a lambda pattern match, where the body is already in Core----mkLambda :: Type -- type of the argument- -> LPat Id -- argument pattern- -> CoreExpr -- desugared body- -> DsM (CoreExpr, Type)-mkLambda ty p ce = do- v <- newSysLocalDs ty- let errMsg = ptext (sLit "DsListComp.deLambda: internal error!")- ce'ty = exprType ce- cerr <- mkErrorAppDs pAT_ERROR_ID ce'ty errMsg- res <- matchSimply (Var v) (StmtCtxt PArrComp) p ce cerr- return (mkLams [v] res, ce'ty)---- obtain the element type of the parallel array produced by the given Core--- expression----parrElemType :: CoreExpr -> Type-parrElemType e =- case splitTyConApp_maybe (exprType e) of- Just (tycon, [ty]) | tycon == parrTyCon -> ty- _ -> panic- "DsListComp.parrElemType: not a parallel array type"-\end{code}--Translation for monad comprehensions--\begin{code}--- Entry point for monad comprehension desugaring-dsMonadComp :: [ExprLStmt Id] -> DsM CoreExpr-dsMonadComp stmts = dsMcStmts stmts--dsMcStmts :: [ExprLStmt Id] -> DsM CoreExpr-dsMcStmts [] = panic "dsMcStmts"-dsMcStmts (L loc stmt : lstmts) = putSrcSpanDs loc (dsMcStmt stmt lstmts)------------------dsMcStmt :: ExprStmt Id -> [ExprLStmt Id] -> DsM CoreExpr--dsMcStmt (LastStmt body ret_op) _- = -- ASSERT( null stmts )- do { body' <- dsLExpr body- ; ret_op' <- dsExpr ret_op- ; return (App ret_op' body') }---- [ .. | let binds, stmts ]-dsMcStmt (LetStmt binds) stmts- = do { rest <- dsMcStmts stmts- ; dsLocalBinds binds rest }---- [ .. | a <- m, stmts ]-dsMcStmt (BindStmt pat rhs bind_op fail_op) stmts- = do { rhs' <- dsLExpr rhs- ; dsMcBindStmt pat rhs' bind_op fail_op stmts }---- Apply `guard` to the `exp` expression------ [ .. | exp, stmts ]----dsMcStmt (BodyStmt exp then_exp guard_exp _) stmts- = do { exp' <- dsLExpr exp- ; guard_exp' <- dsExpr guard_exp- ; then_exp' <- dsExpr then_exp- ; rest <- dsMcStmts stmts- ; return $ mkApps then_exp' [ mkApps guard_exp' [exp']- , rest ] }---- Group statements desugar like this:------ [| (q, then group by e using f); rest |]--- ---> f {qt} (\qv -> e) [| q; return qv |] >>= \ n_tup ->--- case unzip n_tup of qv' -> [| rest |]------ where variables (v1:t1, ..., vk:tk) are bound by q--- qv = (v1, ..., vk)--- qt = (t1, ..., tk)--- (>>=) :: m2 a -> (a -> m3 b) -> m3 b--- f :: forall a. (a -> t) -> m1 a -> m2 (n a)--- n_tup :: n qt--- unzip :: n qt -> (n t1, ..., n tk) (needs Functor n)--dsMcStmt (TransStmt { trS_stmts = stmts, trS_bndrs = bndrs- , trS_by = by, trS_using = using- , trS_ret = return_op, trS_bind = bind_op- , trS_fmap = fmap_op, trS_form = form }) stmts_rest- = do { let (from_bndrs, to_bndrs) = unzip bndrs- from_bndr_tys = map idType from_bndrs -- Types ty-- -- Desugar an inner comprehension which outputs a list of tuples of the "from" binders- ; expr <- dsInnerMonadComp stmts from_bndrs return_op-- -- Work out what arguments should be supplied to that expression: i.e. is an extraction- -- function required? If so, create that desugared function and add to arguments- ; usingExpr' <- dsLExpr using- ; usingArgs <- case by of- Nothing -> return [expr]- Just by_e -> do { by_e' <- dsLExpr by_e- ; lam <- matchTuple from_bndrs by_e'- ; return [lam, expr] }-- -- Generate the expressions to build the grouped list- -- Build a pattern that ensures the consumer binds into the NEW binders,- -- which hold monads rather than single values- ; bind_op' <- dsExpr bind_op- ; let bind_ty = exprType bind_op' -- m2 (n (a,b,c)) -> (n (a,b,c) -> r1) -> r2- n_tup_ty = funArgTy $ funArgTy $ funResultTy bind_ty -- n (a,b,c)- tup_n_ty = mkBigCoreVarTupTy to_bndrs-- ; body <- dsMcStmts stmts_rest- ; n_tup_var <- newSysLocalDs n_tup_ty- ; tup_n_var <- newSysLocalDs tup_n_ty- ; tup_n_expr <- mkMcUnzipM form fmap_op n_tup_var from_bndr_tys- ; us <- newUniqueSupply- ; let rhs' = mkApps usingExpr' usingArgs- body' = mkTupleCase us to_bndrs body tup_n_var tup_n_expr-- ; return (mkApps bind_op' [rhs', Lam n_tup_var body']) }---- Parallel statements. Use `Control.Monad.Zip.mzip` to zip parallel--- statements, for example:------ [ body | qs1 | qs2 | qs3 ]--- -> [ body | (bndrs1, (bndrs2, bndrs3))--- <- [bndrs1 | qs1] `mzip` ([bndrs2 | qs2] `mzip` [bndrs3 | qs3]) ]------ where `mzip` has type--- mzip :: forall a b. m a -> m b -> m (a,b)--- NB: we need a polymorphic mzip because we call it several times--dsMcStmt (ParStmt blocks mzip_op bind_op) stmts_rest- = do { exps_w_tys <- mapM ds_inner blocks -- Pairs (exp :: m ty, ty)- ; mzip_op' <- dsExpr mzip_op-- ; let -- The pattern variables- pats = [ mkBigLHsVarPatTup bs | ParStmtBlock _ bs _ <- blocks]- -- Pattern with tuples of variables- -- [v1,v2,v3] => (v1, (v2, v3))- pat = foldr1 (\p1 p2 -> mkLHsPatTup [p1, p2]) pats- (rhs, _) = foldr1 (\(e1,t1) (e2,t2) ->- (mkApps mzip_op' [Type t1, Type t2, e1, e2],- mkBoxedTupleTy [t1,t2]))- exps_w_tys-- ; dsMcBindStmt pat rhs bind_op noSyntaxExpr stmts_rest }- where- ds_inner (ParStmtBlock stmts bndrs return_op) - = do { exp <- dsInnerMonadComp stmts bndrs return_op- ; return (exp, mkBigCoreVarTupTy bndrs) }--dsMcStmt stmt _ = pprPanic "dsMcStmt: unexpected stmt" (ppr stmt)---matchTuple :: [Id] -> CoreExpr -> DsM CoreExpr--- (matchTuple [a,b,c] body)--- returns the Core term--- \x. case x of (a,b,c) -> body-matchTuple ids body- = do { us <- newUniqueSupply- ; tup_id <- newSysLocalDs (mkBigCoreVarTupTy ids)- ; return (Lam tup_id $ mkTupleCase us ids body tup_id (Var tup_id)) }---- general `rhs' >>= \pat -> stmts` desugaring where `rhs'` is already a--- desugared `CoreExpr`-dsMcBindStmt :: LPat Id- -> CoreExpr -- ^ the desugared rhs of the bind statement- -> SyntaxExpr Id- -> SyntaxExpr Id- -> [ExprLStmt Id]- -> DsM CoreExpr-dsMcBindStmt pat rhs' bind_op fail_op stmts- = do { body <- dsMcStmts stmts- ; bind_op' <- dsExpr bind_op- ; var <- selectSimpleMatchVarL pat- ; let bind_ty = exprType bind_op' -- rhs -> (pat -> res1) -> res2- res1_ty = funResultTy (funArgTy (funResultTy bind_ty))- ; match <- matchSinglePat (Var var) (StmtCtxt DoExpr) pat- res1_ty (cantFailMatchResult body)- ; match_code <- handle_failure pat match fail_op- ; return (mkApps bind_op' [rhs', Lam var match_code]) }-- where- -- In a monad comprehension expression, pattern-match failure just calls- -- the monadic `fail` rather than throwing an exception- handle_failure pat match fail_op- | matchCanFail match- = do { fail_op' <- dsExpr fail_op- ; dflags <- getDynFlags- ; fail_msg <- mkStringExpr (mk_fail_msg dflags pat)- ; extractMatchResult match (App fail_op' fail_msg) }- | otherwise- = extractMatchResult match (error "It can't fail")-- mk_fail_msg :: DynFlags -> Located e -> String- mk_fail_msg dflags pat- = "Pattern match failure in monad comprehension at " ++- showPpr dflags (getLoc pat)---- Desugar nested monad comprehensions, for example in `then..` constructs--- dsInnerMonadComp quals [a,b,c] ret_op--- returns the desugaring of--- [ (a,b,c) | quals ]--dsInnerMonadComp :: [ExprLStmt Id]- -> [Id] -- Return a tuple of these variables- -> HsExpr Id -- The monomorphic "return" operator- -> DsM CoreExpr-dsInnerMonadComp stmts bndrs ret_op- = dsMcStmts (stmts ++ [noLoc (LastStmt (mkBigLHsVarTup bndrs) ret_op)])---- The `unzip` function for `GroupStmt` in a monad comprehensions------ unzip :: m (a,b,..) -> (m a,m b,..)--- unzip m_tuple = ( liftM selN1 m_tuple--- , liftM selN2 m_tuple--- , .. )------ mkMcUnzipM fmap ys [t1, t2]--- = ( fmap (selN1 :: (t1, t2) -> t1) ys--- , fmap (selN2 :: (t1, t2) -> t2) ys )--mkMcUnzipM :: TransForm- -> SyntaxExpr TcId -- fmap- -> Id -- Of type n (a,b,c)- -> [Type] -- [a,b,c]- -> DsM CoreExpr -- Of type (n a, n b, n c)-mkMcUnzipM ThenForm _ ys _- = return (Var ys) -- No unzipping to do--mkMcUnzipM _ fmap_op ys elt_tys- = do { fmap_op' <- dsExpr fmap_op- ; xs <- mapM newSysLocalDs elt_tys- ; let tup_ty = mkBigCoreTupTy elt_tys- ; tup_xs <- newSysLocalDs tup_ty-- ; let mk_elt i = mkApps fmap_op' -- fmap :: forall a b. (a -> b) -> n a -> n b- [ Type tup_ty, Type (getNth elt_tys i)- , mk_sel i, Var ys]-- mk_sel n = Lam tup_xs $- mkTupleSelector xs (getNth xs n) tup_xs (Var tup_xs)-- ; return (mkBigCoreTup (map mk_elt [0..length elt_tys - 1])) }-\end{code}
− src/Language/Haskell/Liquid/Desugar/DsMeta.hs
@@ -1,2816 +0,0 @@------------------------------------------------------------------------------------ (c) The University of Glasgow 2006------ The purpose of this module is to transform an HsExpr into a CoreExpr which--- when evaluated, returns a (Meta.Q Meta.Exp) computation analogous to the--- input HsExpr. We do this in the DsM monad, which supplies access to--- CoreExpr's of the "smart constructors" of the Meta.Exp datatype.------ It also defines a bunch of knownKeyNames, in the same way as is done--- in prelude/PrelNames. It's much more convenient to do it here, because--- otherwise we have to recompile PrelNames whenever we add a Name, which is--- a Royal Pain (triggers other recompilation).--------------------------------------------------------------------------------module Language.Haskell.Liquid.Desugar.DsMeta( dsBracket,- templateHaskellNames, qTyConName, nameTyConName,- liftName, liftStringName, expQTyConName, patQTyConName,- decQTyConName, decsQTyConName, typeQTyConName,- decTyConName, typeTyConName, mkNameG_dName, mkNameG_vName, mkNameG_tcName,- quoteExpName, quotePatName, quoteDecName, quoteTypeName,- tExpTyConName, tExpDataConName, unTypeName, unTypeQName,- unsafeTExpCoerceName- ) where---- #include "HsVersions.h"--import Language.Haskell.Liquid.Desugar.DsExpr ( dsExpr )--import Language.Haskell.Liquid.Desugar.MatchLit-import DsMonad--import qualified Language.Haskell.TH as TH--import HsSyn-import Class-import PrelNames--- To avoid clashes with DsMeta.varName we must make a local alias for--- OccName.varName we do this by removing varName from the import of--- OccName above, making a qualified instance of OccName and using--- OccNameAlias.varName where varName ws previously used in this file.-import qualified OccName( isDataOcc, isVarOcc, isTcOcc, varName, tcName, dataName )--import Module-import Id-import Name hiding( isVarOcc, isTcOcc, varName, tcName )-import NameEnv-import TcType-import TyCon-import TysWiredIn-import TysPrim ( liftedTypeKindTyConName, constraintKindTyConName )-import CoreSyn-import MkCore-import CoreUtils-import SrcLoc-import Unique-import BasicTypes-import Outputable-import Bag-import DynFlags-import FastString-import ForeignCall-import Util--import Data.Maybe-import Control.Monad-import Data.List--------------------------------------------------------------------------------dsBracket :: HsBracket Name -> [PendingTcSplice] -> DsM CoreExpr--- Returns a CoreExpr of type TH.ExpQ--- The quoted thing is parameterised over Name, even though it has--- been type checked. We don't want all those type decorations!--dsBracket brack splices- = dsExtendMetaEnv new_bit (do_brack brack)- where- new_bit = mkNameEnv [(n, Splice (unLoc e)) | (n, e) <- splices]-- do_brack (VarBr _ n) = do { MkC e1 <- lookupOcc n ; return e1 }- do_brack (ExpBr e) = do { MkC e1 <- repLE e ; return e1 }- do_brack (PatBr p) = do { MkC p1 <- repTopP p ; return p1 }- do_brack (TypBr t) = do { MkC t1 <- repLTy t ; return t1 }- do_brack (DecBrG gp) = do { MkC ds1 <- repTopDs gp ; return ds1 }- do_brack (DecBrL _) = panic "dsBracket: unexpected DecBrL"- do_brack (TExpBr e) = do { MkC e1 <- repLE e ; return e1 }--{- -------------- Examples ---------------------- [| \x -> x |]-====>- gensym (unpackString "x"#) `bindQ` \ x1::String ->- lam (pvar x1) (var x1)--- [| \x -> $(f [| x |]) |]-====>- gensym (unpackString "x"#) `bindQ` \ x1::String ->- lam (pvar x1) (f (var x1))--}------------------------------------------------------------- Declarations----------------------------------------------------------repTopP :: LPat Name -> DsM (Core TH.PatQ)-repTopP pat = do { ss <- mkGenSyms (collectPatBinders pat)- ; pat' <- addBinds ss (repLP pat)- ; wrapGenSyms ss pat' }--repTopDs :: HsGroup Name -> DsM (Core (TH.Q [TH.Dec]))-repTopDs group- = do { let { tv_bndrs = hsSigTvBinders (hs_valds group)- ; bndrs = tv_bndrs ++ hsGroupBinders group } ;- ss <- mkGenSyms bndrs ;-- -- Bind all the names mainly to avoid repeated use of explicit strings.- -- Thus we get- -- do { t :: String <- genSym "T" ;- -- return (Data t [] ...more t's... }- -- The other important reason is that the output must mention- -- only "T", not "Foo:T" where Foo is the current module-- decls <- addBinds ss (do {- fix_ds <- mapM repFixD (hs_fixds group) ;- val_ds <- rep_val_binds (hs_valds group) ;- tycl_ds <- mapM repTyClD (tyClGroupConcat (hs_tyclds group)) ;- role_ds <- mapM repRoleD (concatMap group_roles (hs_tyclds group)) ;- inst_ds <- mapM repInstD (hs_instds group) ;- rule_ds <- mapM repRuleD (hs_ruleds group) ;- for_ds <- mapM repForD (hs_fords group) ;- -- more needed- return (de_loc $ sort_by_loc $- val_ds ++ catMaybes tycl_ds ++ role_ds ++ fix_ds- ++ inst_ds ++ rule_ds ++ for_ds) }) ;-- decl_ty <- lookupType decQTyConName ;- let { core_list = coreList' decl_ty decls } ;-- dec_ty <- lookupType decTyConName ;- q_decs <- repSequenceQ dec_ty core_list ;-- wrapGenSyms ss q_decs- }---hsSigTvBinders :: HsValBinds Name -> [Name]--- See Note [Scoped type variables in bindings]-hsSigTvBinders binds- = [hsLTyVarName tv | L _ (TypeSig _ (L _ (HsForAllTy Explicit qtvs _ _))) <- sigs- , tv <- hsQTvBndrs qtvs]- where- sigs = case binds of- ValBindsIn _ sigs -> sigs- ValBindsOut _ sigs -> sigs---{- Notes--Note [Scoped type variables in bindings]-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~-Consider- f :: forall a. a -> a- f x = x::a-Here the 'forall a' brings 'a' into scope over the binding group.-To achieve this we-- a) Gensym a binding for 'a' at the same time as we do one for 'f'- collecting the relevant binders with hsSigTvBinders-- b) When processing the 'forall', don't gensym--The relevant places are signposted with references to this Note--Note [Binders and occurrences]-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~-When we desugar [d| data T = MkT |]-we want to get- Data "T" [] [Con "MkT" []] []-and *not*- Data "Foo:T" [] [Con "Foo:MkT" []] []-That is, the new data decl should fit into whatever new module it is-asked to fit in. We do *not* clone, though; no need for this:- Data "T79" ....--But if we see this:- data T = MkT- foo = reifyDecl T--then we must desugar to- foo = Data "Foo:T" [] [Con "Foo:MkT" []] []--So in repTopDs we bring the binders into scope with mkGenSyms and addBinds.-And we use lookupOcc, rather than lookupBinder-in repTyClD and repC.---}---- represent associated family instances----repTyClD :: LTyClDecl Name -> DsM (Maybe (SrcSpan, Core TH.DecQ))--repTyClD (L loc (FamDecl { tcdFam = fam })) = liftM Just $ repFamilyDecl (L loc fam)--repTyClD (L loc (SynDecl { tcdLName = tc, tcdTyVars = tvs, tcdRhs = rhs }))- = do { tc1 <- lookupLOcc tc -- See note [Binders and occurrences]- ; dec <- addTyClTyVarBinds tvs $ \bndrs ->- repSynDecl tc1 bndrs rhs- ; return (Just (loc, dec)) }--repTyClD (L loc (DataDecl { tcdLName = tc, tcdTyVars = tvs, tcdDataDefn = defn }))- = do { tc1 <- lookupLOcc tc -- See note [Binders and occurrences]- ; tc_tvs <- mk_extra_tvs tc tvs defn- ; dec <- addTyClTyVarBinds tc_tvs $ \bndrs ->- repDataDefn tc1 bndrs Nothing (hsLTyVarNames tc_tvs) defn- ; return (Just (loc, dec)) }--repTyClD (L loc (ClassDecl { tcdCtxt = cxt, tcdLName = cls,- tcdTyVars = tvs, tcdFDs = fds,- tcdSigs = sigs, tcdMeths = meth_binds,- tcdATs = ats, tcdATDefs = [] }))- = do { cls1 <- lookupLOcc cls -- See note [Binders and occurrences]- ; dec <- addTyVarBinds tvs $ \bndrs ->- do { cxt1 <- repLContext cxt- ; sigs1 <- rep_sigs sigs- ; binds1 <- rep_binds meth_binds- ; fds1 <- repLFunDeps fds- ; ats1 <- repFamilyDecls ats- ; decls1 <- coreList decQTyConName (ats1 ++ sigs1 ++ binds1)- ; repClass cxt1 cls1 bndrs fds1 decls1- }- ; return $ Just (loc, dec)- }---- Un-handled cases-repTyClD (L loc d) = putSrcSpanDs loc $- do { warnDs (hang ds_msg 4 (ppr d))- ; return Nothing }----------------------------repRoleD :: LRoleAnnotDecl Name -> DsM (SrcSpan, Core TH.DecQ)-repRoleD (L loc (RoleAnnotDecl tycon roles))- = do { tycon1 <- lookupLOcc tycon- ; roles1 <- mapM repRole roles- ; roles2 <- coreList roleTyConName roles1- ; dec <- repRoleAnnotD tycon1 roles2- ; return (loc, dec) }----------------------------repDataDefn :: Core TH.Name -> Core [TH.TyVarBndr]- -> Maybe (Core [TH.TypeQ])- -> [Name] -> HsDataDefn Name- -> DsM (Core TH.DecQ)-repDataDefn tc bndrs opt_tys tv_names- (HsDataDefn { dd_ND = new_or_data, dd_ctxt = cxt- , dd_cons = cons, dd_derivs = mb_derivs })- = do { cxt1 <- repLContext cxt- ; derivs1 <- repDerivs mb_derivs- ; case new_or_data of- NewType -> do { con1 <- repC tv_names (head cons)- ; repNewtype cxt1 tc bndrs opt_tys con1 derivs1 }- DataType -> do { cons1 <- repList conQTyConName (repC tv_names) cons- ; repData cxt1 tc bndrs opt_tys cons1 derivs1 } }--repSynDecl :: Core TH.Name -> Core [TH.TyVarBndr]- -> LHsType Name- -> DsM (Core TH.DecQ)-repSynDecl tc bndrs ty- = do { ty1 <- repLTy ty- ; repTySyn tc bndrs ty1 }--repFamilyDecl :: LFamilyDecl Name -> DsM (SrcSpan, Core TH.DecQ)-repFamilyDecl (L loc (FamilyDecl { fdInfo = info,- fdLName = tc,- fdTyVars = tvs,- fdKindSig = opt_kind }))- = do { tc1 <- lookupLOcc tc -- See note [Binders and occurrences]- ; dec <- addTyClTyVarBinds tvs $ \bndrs ->- case (opt_kind, info) of - (Nothing, ClosedTypeFamily eqns) ->- do { eqns1 <- mapM repTyFamEqn eqns- ; eqns2 <- coreList tySynEqnQTyConName eqns1- ; repClosedFamilyNoKind tc1 bndrs eqns2 }- (Just ki, ClosedTypeFamily eqns) ->- do { eqns1 <- mapM repTyFamEqn eqns- ; eqns2 <- coreList tySynEqnQTyConName eqns1- ; ki1 <- repLKind ki- ; repClosedFamilyKind tc1 bndrs ki1 eqns2 } - (Nothing, _) ->- do { info' <- repFamilyInfo info- ; repFamilyNoKind info' tc1 bndrs }- (Just ki, _) ->- do { info' <- repFamilyInfo info- ; ki1 <- repLKind ki - ; repFamilyKind info' tc1 bndrs ki1 }- ; return (loc, dec)- }--repFamilyDecls :: [LFamilyDecl Name] -> DsM [Core TH.DecQ]-repFamilyDecls fds = liftM de_loc (mapM repFamilyDecl fds)----------------------------mk_extra_tvs :: Located Name -> LHsTyVarBndrs Name- -> HsDataDefn Name -> DsM (LHsTyVarBndrs Name)--- If there is a kind signature it must be of form--- k1 -> .. -> kn -> *--- Return type variables [tv1:k1, tv2:k2, .., tvn:kn]-mk_extra_tvs tc tvs defn- | HsDataDefn { dd_kindSig = Just hs_kind } <- defn- = do { extra_tvs <- go hs_kind- ; return (tvs { hsq_tvs = hsq_tvs tvs ++ extra_tvs }) }- | otherwise- = return tvs- where- go :: LHsKind Name -> DsM [LHsTyVarBndr Name]- go (L loc (HsFunTy kind rest))- = do { uniq <- newUnique- ; let { occ = mkTyVarOccFS (fsLit "t")- ; nm = mkInternalName uniq occ loc- ; hs_tv = L loc (KindedTyVar nm kind) }- ; hs_tvs <- go rest- ; return (hs_tv : hs_tvs) }-- go (L _ (HsTyVar n))- | n == liftedTypeKindTyConName- = return []-- go _ = failWithDs (ptext (sLit "Malformed kind signature for") <+> ppr tc)------------------------------ represent fundeps----repLFunDeps :: [Located (FunDep Name)] -> DsM (Core [TH.FunDep])-repLFunDeps fds = repList funDepTyConName repLFunDep fds--repLFunDep :: Located (FunDep Name) -> DsM (Core TH.FunDep)-repLFunDep (L _ (xs, ys)) = do xs' <- repList nameTyConName lookupBinder xs- ys' <- repList nameTyConName lookupBinder ys- repFunDep xs' ys'---- represent family declaration flavours----repFamilyInfo :: FamilyInfo Name -> DsM (Core TH.FamFlavour)-repFamilyInfo OpenTypeFamily = rep2 typeFamName []-repFamilyInfo DataFamily = rep2 dataFamName []-repFamilyInfo ClosedTypeFamily {} = panic "repFamilyInfo"---- Represent instance declarations----repInstD :: LInstDecl Name -> DsM (SrcSpan, Core TH.DecQ)-repInstD (L loc (TyFamInstD { tfid_inst = fi_decl }))- = do { dec <- repTyFamInstD fi_decl- ; return (loc, dec) }-repInstD (L loc (DataFamInstD { dfid_inst = fi_decl }))- = do { dec <- repDataFamInstD fi_decl- ; return (loc, dec) }-repInstD (L loc (ClsInstD { cid_inst = cls_decl }))- = do { dec <- repClsInstD cls_decl- ; return (loc, dec) }--repClsInstD :: ClsInstDecl Name -> DsM (Core TH.DecQ)-repClsInstD (ClsInstDecl { cid_poly_ty = ty, cid_binds = binds- , cid_sigs = prags, cid_tyfam_insts = ats- , cid_datafam_insts = adts })- = addTyVarBinds tvs $ \_ ->- -- We must bring the type variables into scope, so their- -- occurrences don't fail, even though the binders don't- -- appear in the resulting data structure- --- -- But we do NOT bring the binders of 'binds' into scope- -- because they are properly regarded as occurrences- -- For example, the method names should be bound to- -- the selector Ids, not to fresh names (Trac #5410)- --- do { cxt1 <- repContext cxt- ; cls_tcon <- repTy (HsTyVar (unLoc cls))- ; cls_tys <- repLTys tys- ; inst_ty1 <- repTapps cls_tcon cls_tys- ; binds1 <- rep_binds binds- ; prags1 <- rep_sigs prags- ; ats1 <- mapM (repTyFamInstD . unLoc) ats- ; adts1 <- mapM (repDataFamInstD . unLoc) adts- ; decls <- coreList decQTyConName (ats1 ++ adts1 ++ binds1 ++ prags1)- ; repInst cxt1 inst_ty1 decls }- where- Just (tvs, cxt, cls, tys) = splitLHsInstDeclTy_maybe ty--repTyFamInstD :: TyFamInstDecl Name -> DsM (Core TH.DecQ)-repTyFamInstD decl@(TyFamInstDecl { tfid_eqn = eqn })- = do { let tc_name = tyFamInstDeclLName decl- ; tc <- lookupLOcc tc_name -- See note [Binders and occurrences] - ; eqn1 <- repTyFamEqn eqn- ; repTySynInst tc eqn1 }--repTyFamEqn :: LTyFamInstEqn Name -> DsM (Core TH.TySynEqnQ)-repTyFamEqn (L loc (TyFamInstEqn { tfie_pats = HsWB { hswb_cts = tys- , hswb_kvs = kv_names- , hswb_tvs = tv_names }- , tfie_rhs = rhs }))- = do { let hs_tvs = HsQTvs { hsq_kvs = kv_names- , hsq_tvs = userHsTyVarBndrs loc tv_names } -- Yuk- ; addTyClTyVarBinds hs_tvs $ \ _ ->- do { tys1 <- repLTys tys- ; tys2 <- coreList typeQTyConName tys1- ; rhs1 <- repLTy rhs- ; repTySynEqn tys2 rhs1 } }--repDataFamInstD :: DataFamInstDecl Name -> DsM (Core TH.DecQ)-repDataFamInstD (DataFamInstDecl { dfid_tycon = tc_name- , dfid_pats = HsWB { hswb_cts = tys, hswb_kvs = kv_names, hswb_tvs = tv_names }- , dfid_defn = defn })- = do { tc <- lookupLOcc tc_name -- See note [Binders and occurrences]- ; let loc = getLoc tc_name- hs_tvs = HsQTvs { hsq_kvs = kv_names, hsq_tvs = userHsTyVarBndrs loc tv_names } -- Yuk- ; addTyClTyVarBinds hs_tvs $ \ bndrs ->- do { tys1 <- repList typeQTyConName repLTy tys- ; repDataDefn tc bndrs (Just tys1) tv_names defn } }--repForD :: Located (ForeignDecl Name) -> DsM (SrcSpan, Core TH.DecQ)-repForD (L loc (ForeignImport name typ _ (CImport cc s mch cis)))- = do MkC name' <- lookupLOcc name- MkC typ' <- repLTy typ- MkC cc' <- repCCallConv cc- MkC s' <- repSafety s- cis' <- conv_cimportspec cis- MkC str <- coreStringLit (static ++ chStr ++ cis')- dec <- rep2 forImpDName [cc', s', str, name', typ']- return (loc, dec)- where- conv_cimportspec (CLabel cls) = notHandled "Foreign label" (doubleQuotes (ppr cls))- conv_cimportspec (CFunction DynamicTarget) = return "dynamic"- conv_cimportspec (CFunction (StaticTarget fs _ True)) = return (unpackFS fs)- conv_cimportspec (CFunction (StaticTarget _ _ False)) = panic "conv_cimportspec: values not supported yet"- conv_cimportspec CWrapper = return "wrapper"- static = case cis of- CFunction (StaticTarget _ _ _) -> "static "- _ -> ""- chStr = case mch of- Nothing -> ""- Just (Header h) -> unpackFS h ++ " "-repForD decl = notHandled "Foreign declaration" (ppr decl)--repCCallConv :: CCallConv -> DsM (Core TH.Callconv)-repCCallConv CCallConv = rep2 cCallName []-repCCallConv StdCallConv = rep2 stdCallName []-repCCallConv callConv = notHandled "repCCallConv" (ppr callConv)--repSafety :: Safety -> DsM (Core TH.Safety)-repSafety PlayRisky = rep2 unsafeName []-repSafety PlayInterruptible = rep2 interruptibleName []-repSafety PlaySafe = rep2 safeName []--repFixD :: LFixitySig Name -> DsM (SrcSpan, Core TH.DecQ)-repFixD (L loc (FixitySig name (Fixity prec dir)))- = do { MkC name' <- lookupLOcc name- ; MkC prec' <- coreIntLit prec- ; let rep_fn = case dir of- InfixL -> infixLDName- InfixR -> infixRDName- InfixN -> infixNDName- ; dec <- rep2 rep_fn [prec', name']- ; return (loc, dec) }--repRuleD :: LRuleDecl Name -> DsM (SrcSpan, Core TH.DecQ)-repRuleD (L loc (HsRule n act bndrs lhs _ rhs _))- = do { let bndr_names = concatMap ruleBndrNames bndrs- ; ss <- mkGenSyms bndr_names- ; rule1 <- addBinds ss $- do { bndrs' <- repList ruleBndrQTyConName repRuleBndr bndrs- ; n' <- coreStringLit $ unpackFS n- ; act' <- repPhases act- ; lhs' <- repLE lhs- ; rhs' <- repLE rhs- ; repPragRule n' bndrs' lhs' rhs' act' }- ; rule2 <- wrapGenSyms ss rule1- ; return (loc, rule2) }--ruleBndrNames :: RuleBndr Name -> [Name]-ruleBndrNames (RuleBndr n) = [unLoc n]-ruleBndrNames (RuleBndrSig n (HsWB { hswb_kvs = kvs, hswb_tvs = tvs }))- = unLoc n : kvs ++ tvs--repRuleBndr :: RuleBndr Name -> DsM (Core TH.RuleBndrQ)-repRuleBndr (RuleBndr n)- = do { MkC n' <- lookupLBinder n- ; rep2 ruleVarName [n'] }-repRuleBndr (RuleBndrSig n (HsWB { hswb_cts = ty }))- = do { MkC n' <- lookupLBinder n- ; MkC ty' <- repLTy ty- ; rep2 typedRuleVarName [n', ty'] }--ds_msg :: SDoc-ds_msg = ptext (sLit "Cannot desugar this Template Haskell declaration:")------------------------------------------------------------ Constructors----------------------------------------------------------repC :: [Name] -> LConDecl Name -> DsM (Core TH.ConQ)-repC _ (L _ (ConDecl { con_name = con, con_qvars = con_tvs, con_cxt = L _ []- , con_details = details, con_res = ResTyH98 }))- | null (hsQTvBndrs con_tvs)- = do { con1 <- lookupLOcc con -- See Note [Binders and occurrences]- ; repConstr con1 details }--repC tvs (L _ (ConDecl { con_name = con- , con_qvars = con_tvs, con_cxt = L _ ctxt- , con_details = details- , con_res = res_ty }))- = do { (eq_ctxt, con_tv_subst) <- mkGadtCtxt tvs res_ty- ; let ex_tvs = HsQTvs { hsq_kvs = filterOut (in_subst con_tv_subst) (hsq_kvs con_tvs)- , hsq_tvs = filterOut (in_subst con_tv_subst . hsLTyVarName) (hsq_tvs con_tvs) }-- ; binds <- mapM dupBinder con_tv_subst- ; dsExtendMetaEnv (mkNameEnv binds) $ -- Binds some of the con_tvs- addTyVarBinds ex_tvs $ \ ex_bndrs -> -- Binds the remaining con_tvs- do { con1 <- lookupLOcc con -- See Note [Binders and occurrences]- ; c' <- repConstr con1 details- ; ctxt' <- repContext (eq_ctxt ++ ctxt)- ; rep2 forallCName [unC ex_bndrs, unC ctxt', unC c'] } }--in_subst :: [(Name,Name)] -> Name -> Bool-in_subst [] _ = False-in_subst ((n',_):ns) n = n==n' || in_subst ns n--mkGadtCtxt :: [Name] -- Tyvars of the data type- -> ResType (LHsType Name)- -> DsM (HsContext Name, [(Name,Name)])--- Given a data type in GADT syntax, figure out the equality--- context, so that we can represent it with an explicit--- equality context, because that is the only way to express--- the GADT in TH syntax------ Example:--- data T a b c where { MkT :: forall d e. d -> e -> T d [e] e--- mkGadtCtxt [a,b,c] [d,e] (T d [e] e)--- returns--- (b~[e], c~e), [d->a]------ This function is fiddly, but not really hard-mkGadtCtxt _ ResTyH98- = return ([], [])-mkGadtCtxt data_tvs (ResTyGADT res_ty)- | Just (_, tys) <- hsTyGetAppHead_maybe res_ty- , data_tvs `equalLength` tys- = return (go [] [] (data_tvs `zip` tys))-- | otherwise- = failWithDs (ptext (sLit "Malformed constructor result type:") <+> ppr res_ty)- where- go cxt subst [] = (cxt, subst)- go cxt subst ((data_tv, ty) : rest)- | Just con_tv <- is_hs_tyvar ty- , isTyVarName con_tv- , not (in_subst subst con_tv)- = go cxt ((con_tv, data_tv) : subst) rest- | otherwise- = go (eq_pred : cxt) subst rest- where- loc = getLoc ty- eq_pred = L loc (HsEqTy (L loc (HsTyVar data_tv)) ty)-- is_hs_tyvar (L _ (HsTyVar n)) = Just n -- Type variables *and* tycons- is_hs_tyvar (L _ (HsParTy ty)) = is_hs_tyvar ty- is_hs_tyvar _ = Nothing---repBangTy :: LBangType Name -> DsM (Core (TH.StrictTypeQ))-repBangTy ty= do- MkC s <- rep2 str []- MkC t <- repLTy ty'- rep2 strictTypeName [s, t]- where- (str, ty') = case ty of- L _ (HsBangTy (HsUserBang (Just True) True) ty) -> (unpackedName, ty)- L _ (HsBangTy (HsUserBang _ True) ty) -> (isStrictName, ty)- _ -> (notStrictName, ty)------------------------------------------------------------ Deriving clause----------------------------------------------------------repDerivs :: Maybe [LHsType Name] -> DsM (Core [TH.Name])-repDerivs Nothing = coreList nameTyConName []-repDerivs (Just ctxt)- = repList nameTyConName rep_deriv ctxt- where- rep_deriv :: LHsType Name -> DsM (Core TH.Name)- -- Deriving clauses must have the simple H98 form- rep_deriv ty- | Just (cls, []) <- splitHsClassTy_maybe (unLoc ty)- = lookupOcc cls- | otherwise- = notHandled "Non-H98 deriving clause" (ppr ty)------------------------------------------------------------- Signatures in a class decl, or a group of bindings----------------------------------------------------------rep_sigs :: [LSig Name] -> DsM [Core TH.DecQ]-rep_sigs sigs = do locs_cores <- rep_sigs' sigs- return $ de_loc $ sort_by_loc locs_cores--rep_sigs' :: [LSig Name] -> DsM [(SrcSpan, Core TH.DecQ)]- -- We silently ignore ones we don't recognise-rep_sigs' sigs = do { sigs1 <- mapM rep_sig sigs ;- return (concat sigs1) }--rep_sig :: LSig Name -> DsM [(SrcSpan, Core TH.DecQ)]- -- Singleton => Ok- -- Empty => Too hard, signature ignored-rep_sig (L loc (TypeSig nms ty)) = mapM (rep_ty_sig loc ty) nms-rep_sig (L _ (GenericSig nm _)) = failWithDs msg- where msg = vcat [ ptext (sLit "Illegal default signature for") <+> quotes (ppr nm)- , ptext (sLit "Default signatures are not supported by Template Haskell") ]--rep_sig (L loc (InlineSig nm ispec)) = rep_inline nm ispec loc-rep_sig (L loc (SpecSig nm ty ispec)) = rep_specialise nm ty ispec loc-rep_sig (L loc (SpecInstSig ty)) = rep_specialiseInst ty loc-rep_sig _ = return []--rep_ty_sig :: SrcSpan -> LHsType Name -> Located Name- -> DsM (SrcSpan, Core TH.DecQ)-rep_ty_sig loc (L _ ty) nm- = do { nm1 <- lookupLOcc nm- ; ty1 <- rep_ty ty- ; sig <- repProto nm1 ty1- ; return (loc, sig) }- where- -- We must special-case the top-level explicit for-all of a TypeSig- -- See Note [Scoped type variables in bindings]- rep_ty (HsForAllTy Explicit tvs ctxt ty)- = do { let rep_in_scope_tv tv = do { name <- lookupBinder (hsLTyVarName tv)- ; repTyVarBndrWithKind tv name }- ; bndrs1 <- repList tyVarBndrTyConName rep_in_scope_tv (hsQTvBndrs tvs)- ; ctxt1 <- repLContext ctxt- ; ty1 <- repLTy ty- ; repTForall bndrs1 ctxt1 ty1 }-- rep_ty ty = repTy ty---rep_inline :: Located Name- -> InlinePragma -- Never defaultInlinePragma- -> SrcSpan- -> DsM [(SrcSpan, Core TH.DecQ)]-rep_inline nm ispec loc- = do { nm1 <- lookupLOcc nm- ; inline <- repInline $ inl_inline ispec- ; rm <- repRuleMatch $ inl_rule ispec- ; phases <- repPhases $ inl_act ispec- ; pragma <- repPragInl nm1 inline rm phases- ; return [(loc, pragma)]- }--rep_specialise :: Located Name -> LHsType Name -> InlinePragma -> SrcSpan- -> DsM [(SrcSpan, Core TH.DecQ)]-rep_specialise nm ty ispec loc- = do { nm1 <- lookupLOcc nm- ; ty1 <- repLTy ty- ; phases <- repPhases $ inl_act ispec- ; let inline = inl_inline ispec- ; pragma <- if isEmptyInlineSpec inline- then -- SPECIALISE- repPragSpec nm1 ty1 phases- else -- SPECIALISE INLINE- do { inline1 <- repInline inline- ; repPragSpecInl nm1 ty1 inline1 phases }- ; return [(loc, pragma)]- }--rep_specialiseInst :: LHsType Name -> SrcSpan -> DsM [(SrcSpan, Core TH.DecQ)]-rep_specialiseInst ty loc- = do { ty1 <- repLTy ty- ; pragma <- repPragSpecInst ty1- ; return [(loc, pragma)] }--repInline :: InlineSpec -> DsM (Core TH.Inline)-repInline NoInline = dataCon noInlineDataConName-repInline Inline = dataCon inlineDataConName-repInline Inlinable = dataCon inlinableDataConName-repInline spec = notHandled "repInline" (ppr spec)--repRuleMatch :: RuleMatchInfo -> DsM (Core TH.RuleMatch)-repRuleMatch ConLike = dataCon conLikeDataConName-repRuleMatch FunLike = dataCon funLikeDataConName--repPhases :: Activation -> DsM (Core TH.Phases)-repPhases (ActiveBefore i) = do { MkC arg <- coreIntLit i- ; dataCon' beforePhaseDataConName [arg] }-repPhases (ActiveAfter i) = do { MkC arg <- coreIntLit i- ; dataCon' fromPhaseDataConName [arg] }-repPhases _ = dataCon allPhasesDataConName------------------------------------------------------------ Types----------------------------------------------------------addTyVarBinds :: LHsTyVarBndrs Name -- the binders to be added- -> (Core [TH.TyVarBndr] -> DsM (Core (TH.Q a))) -- action in the ext env- -> DsM (Core (TH.Q a))--- gensym a list of type variables and enter them into the meta environment;--- the computations passed as the second argument is executed in that extended--- meta environment and gets the *new* names on Core-level as an argument--addTyVarBinds (HsQTvs { hsq_kvs = kvs, hsq_tvs = tvs }) m- = do { fresh_kv_names <- mkGenSyms kvs- ; fresh_tv_names <- mkGenSyms (map hsLTyVarName tvs)- ; let fresh_names = fresh_kv_names ++ fresh_tv_names- ; term <- addBinds fresh_names $- do { kbs <- repList tyVarBndrTyConName mk_tv_bndr (tvs `zip` fresh_tv_names)- ; m kbs }- ; wrapGenSyms fresh_names term }- where- mk_tv_bndr (tv, (_,v)) = repTyVarBndrWithKind tv (coreVar v)--addTyClTyVarBinds :: LHsTyVarBndrs Name- -> (Core [TH.TyVarBndr] -> DsM (Core (TH.Q a)))- -> DsM (Core (TH.Q a))---- Used for data/newtype declarations, and family instances,--- so that the nested type variables work right--- instance C (T a) where--- type W (T a) = blah--- The 'a' in the type instance is the one bound by the instance decl-addTyClTyVarBinds tvs m- = do { let tv_names = hsLKiTyVarNames tvs- ; env <- dsGetMetaEnv- ; freshNames <- mkGenSyms (filterOut (`elemNameEnv` env) tv_names)- -- Make fresh names for the ones that are not already in scope- -- This makes things work for family declarations-- ; term <- addBinds freshNames $- do { kbs <- repList tyVarBndrTyConName mk_tv_bndr (hsQTvBndrs tvs)- ; m kbs }-- ; wrapGenSyms freshNames term }- where- mk_tv_bndr tv = do { v <- lookupBinder (hsLTyVarName tv)- ; repTyVarBndrWithKind tv v }---- Produce kinded binder constructors from the Haskell tyvar binders----repTyVarBndrWithKind :: LHsTyVarBndr Name- -> Core TH.Name -> DsM (Core TH.TyVarBndr)-repTyVarBndrWithKind (L _ (UserTyVar _)) nm- = repPlainTV nm-repTyVarBndrWithKind (L _ (KindedTyVar _ ki)) nm- = repLKind ki >>= repKindedTV nm---- represent a type context----repLContext :: LHsContext Name -> DsM (Core TH.CxtQ)-repLContext (L _ ctxt) = repContext ctxt--repContext :: HsContext Name -> DsM (Core TH.CxtQ)-repContext ctxt = do preds <- repList predQTyConName repLPred ctxt- repCtxt preds---- represent a type predicate----repLPred :: LHsType Name -> DsM (Core TH.PredQ)-repLPred (L _ p) = repPred p--repPred :: HsType Name -> DsM (Core TH.PredQ)-repPred (HsParTy ty) - = repLPred ty-repPred ty- | Just (cls, tys) <- splitHsClassTy_maybe ty- = do- cls1 <- lookupOcc cls- tys1 <- repList typeQTyConName repLTy tys- repClassP cls1 tys1-repPred (HsEqTy tyleft tyright)- = do- tyleft1 <- repLTy tyleft- tyright1 <- repLTy tyright- repEqualP tyleft1 tyright1-repPred ty- = notHandled "Exotic predicate type" (ppr ty)---- yield the representation of a list of types----repLTys :: [LHsType Name] -> DsM [Core TH.TypeQ]-repLTys tys = mapM repLTy tys---- represent a type----repLTy :: LHsType Name -> DsM (Core TH.TypeQ)-repLTy (L _ ty) = repTy ty--repTy :: HsType Name -> DsM (Core TH.TypeQ)-repTy (HsForAllTy _ tvs ctxt ty) =- addTyVarBinds tvs $ \bndrs -> do- ctxt1 <- repLContext ctxt- ty1 <- repLTy ty- repTForall bndrs ctxt1 ty1--repTy (HsTyVar n)- | isTvOcc occ = do tv1 <- lookupOcc n- repTvar tv1- | isDataOcc occ = do tc1 <- lookupOcc n- repPromotedTyCon tc1- | otherwise = do tc1 <- lookupOcc n- repNamedTyCon tc1- where- occ = nameOccName n--repTy (HsAppTy f a) = do- f1 <- repLTy f- a1 <- repLTy a- repTapp f1 a1-repTy (HsFunTy f a) = do- f1 <- repLTy f- a1 <- repLTy a- tcon <- repArrowTyCon- repTapps tcon [f1, a1]-repTy (HsListTy t) = do- t1 <- repLTy t- tcon <- repListTyCon- repTapp tcon t1-repTy (HsPArrTy t) = do- t1 <- repLTy t- tcon <- repTy (HsTyVar (tyConName parrTyCon))- repTapp tcon t1-repTy (HsTupleTy HsUnboxedTuple tys) = do- tys1 <- repLTys tys- tcon <- repUnboxedTupleTyCon (length tys)- repTapps tcon tys1-repTy (HsTupleTy _ tys) = do tys1 <- repLTys tys- tcon <- repTupleTyCon (length tys)- repTapps tcon tys1-repTy (HsOpTy ty1 (_, n) ty2) = repLTy ((nlHsTyVar (unLoc n) `nlHsAppTy` ty1)- `nlHsAppTy` ty2)-repTy (HsParTy t) = repLTy t-repTy (HsKindSig t k) = do- t1 <- repLTy t- k1 <- repLKind k- repTSig t1 k1-repTy (HsSpliceTy splice _) = repSplice splice-repTy (HsExplicitListTy _ tys) = do- tys1 <- repLTys tys- repTPromotedList tys1-repTy (HsExplicitTupleTy _ tys) = do- tys1 <- repLTys tys- tcon <- repPromotedTupleTyCon (length tys)- repTapps tcon tys1-repTy (HsTyLit lit) = do- lit' <- repTyLit lit- repTLit lit'-repTy ty = notHandled "Exotic form of type" (ppr ty)--repTyLit :: HsTyLit -> DsM (Core TH.TyLitQ)-repTyLit (HsNumTy i) = do iExpr <- mkIntegerExpr i- rep2 numTyLitName [iExpr]-repTyLit (HsStrTy s) = do { s' <- mkStringExprFS s- ; rep2 strTyLitName [s']- }---- represent a kind----repLKind :: LHsKind Name -> DsM (Core TH.Kind)-repLKind ki- = do { let (kis, ki') = splitHsFunType ki- ; kis_rep <- mapM repLKind kis- ; ki'_rep <- repNonArrowLKind ki'- ; kcon <- repKArrow- ; let f k1 k2 = repKApp kcon k1 >>= flip repKApp k2- ; foldrM f ki'_rep kis_rep- }--repNonArrowLKind :: LHsKind Name -> DsM (Core TH.Kind)-repNonArrowLKind (L _ ki) = repNonArrowKind ki--repNonArrowKind :: HsKind Name -> DsM (Core TH.Kind)-repNonArrowKind (HsTyVar name)- | name == liftedTypeKindTyConName = repKStar- | name == constraintKindTyConName = repKConstraint- | isTvOcc (nameOccName name) = lookupOcc name >>= repKVar- | otherwise = lookupOcc name >>= repKCon-repNonArrowKind (HsAppTy f a) = do { f' <- repLKind f- ; a' <- repLKind a- ; repKApp f' a'- }-repNonArrowKind (HsListTy k) = do { k' <- repLKind k- ; kcon <- repKList- ; repKApp kcon k'- }-repNonArrowKind (HsTupleTy _ ks) = do { ks' <- mapM repLKind ks- ; kcon <- repKTuple (length ks)- ; repKApps kcon ks'- }-repNonArrowKind k = notHandled "Exotic form of kind" (ppr k)--repRole :: Located (Maybe Role) -> DsM (Core TH.Role)-repRole (L _ (Just Nominal)) = rep2 nominalRName []-repRole (L _ (Just Representational)) = rep2 representationalRName []-repRole (L _ (Just Phantom)) = rep2 phantomRName []-repRole (L _ Nothing) = rep2 inferRName []---------------------------------------------------------------------------------- Splices--------------------------------------------------------------------------------repSplice :: HsSplice Name -> DsM (Core a)--- See Note [How brackets and nested splices are handled] in TcSplice--- We return a CoreExpr of any old type; the context should know-repSplice (HsSplice n _)- = do { mb_val <- dsLookupMetaEnv n- ; case mb_val of- Just (Splice e) -> do { e' <- dsExpr e- ; return (MkC e') }- _ -> pprPanic "HsSplice" (ppr n) }- -- Should not happen; statically checked---------------------------------------------------------------------------------- Expressions--------------------------------------------------------------------------------repLEs :: [LHsExpr Name] -> DsM (Core [TH.ExpQ])-repLEs es = repList expQTyConName repLE es---- FIXME: some of these panics should be converted into proper error messages--- unless we can make sure that constructs, which are plainly not--- supported in TH already lead to error messages at an earlier stage-repLE :: LHsExpr Name -> DsM (Core TH.ExpQ)-repLE (L loc e) = putSrcSpanDs loc (repE e)--repE :: HsExpr Name -> DsM (Core TH.ExpQ)-repE (HsVar x) =- do { mb_val <- dsLookupMetaEnv x- ; case mb_val of- Nothing -> do { str <- globalVar x- ; repVarOrCon x str }- Just (Bound y) -> repVarOrCon x (coreVar y)- Just (Splice e) -> do { e' <- dsExpr e- ; return (MkC e') } }-repE e@(HsIPVar _) = notHandled "Implicit parameters" (ppr e)-- -- Remember, we're desugaring renamer output here, so- -- HsOverlit can definitely occur-repE (HsOverLit l) = do { a <- repOverloadedLiteral l; repLit a }-repE (HsLit l) = do { a <- repLiteral l; repLit a }-repE (HsLam (MG { mg_alts = [m] })) = repLambda m-repE (HsLamCase _ (MG { mg_alts = ms }))- = do { ms' <- mapM repMatchTup ms- ; core_ms <- coreList matchQTyConName ms'- ; repLamCase core_ms }-repE (HsApp x y) = do {a <- repLE x; b <- repLE y; repApp a b}--repE (OpApp e1 op _ e2) =- do { arg1 <- repLE e1;- arg2 <- repLE e2;- the_op <- repLE op ;- repInfixApp arg1 the_op arg2 }-repE (NegApp x _) = do- a <- repLE x- negateVar <- lookupOcc negateName >>= repVar- negateVar `repApp` a-repE (HsPar x) = repLE x-repE (SectionL x y) = do { a <- repLE x; b <- repLE y; repSectionL a b }-repE (SectionR x y) = do { a <- repLE x; b <- repLE y; repSectionR a b }-repE (HsCase e (MG { mg_alts = ms }))- = do { arg <- repLE e- ; ms2 <- mapM repMatchTup ms- ; core_ms2 <- coreList matchQTyConName ms2- ; repCaseE arg core_ms2 }-repE (HsIf _ x y z) = do- a <- repLE x- b <- repLE y- c <- repLE z- repCond a b c-repE (HsMultiIf _ alts)- = do { (binds, alts') <- liftM unzip $ mapM repLGRHS alts- ; expr' <- repMultiIf (nonEmptyCoreList alts')- ; wrapGenSyms (concat binds) expr' }-repE (HsLet bs e) = do { (ss,ds) <- repBinds bs- ; e2 <- addBinds ss (repLE e)- ; z <- repLetE ds e2- ; wrapGenSyms ss z }---- FIXME: I haven't got the types here right yet-repE e@(HsDo ctxt sts _)- | case ctxt of { DoExpr -> True; GhciStmtCtxt -> True; _ -> False }- = do { (ss,zs) <- repLSts sts;- e' <- repDoE (nonEmptyCoreList zs);- wrapGenSyms ss e' }-- | ListComp <- ctxt- = do { (ss,zs) <- repLSts sts;- e' <- repComp (nonEmptyCoreList zs);- wrapGenSyms ss e' }-- | otherwise- = notHandled "mdo, monad comprehension and [: :]" (ppr e)--repE (ExplicitList _ _ es) = do { xs <- repLEs es; repListExp xs }-repE e@(ExplicitPArr _ _) = notHandled "Parallel arrays" (ppr e)-repE e@(ExplicitTuple es boxed)- | not (all tupArgPresent es) = notHandled "Tuple sections" (ppr e)- | isBoxed boxed = do { xs <- repLEs [e | Present e <- es]; repTup xs }- | otherwise = do { xs <- repLEs [e | Present e <- es]; repUnboxedTup xs }--repE (RecordCon c _ flds)- = do { x <- lookupLOcc c;- fs <- repFields flds;- repRecCon x fs }-repE (RecordUpd e flds _ _ _)- = do { x <- repLE e;- fs <- repFields flds;- repRecUpd x fs }--repE (ExprWithTySig e ty) = do { e1 <- repLE e; t1 <- repLTy ty; repSigExp e1 t1 }-repE (ArithSeq _ _ aseq) =- case aseq of- From e -> do { ds1 <- repLE e; repFrom ds1 }- FromThen e1 e2 -> do- ds1 <- repLE e1- ds2 <- repLE e2- repFromThen ds1 ds2- FromTo e1 e2 -> do- ds1 <- repLE e1- ds2 <- repLE e2- repFromTo ds1 ds2- FromThenTo e1 e2 e3 -> do- ds1 <- repLE e1- ds2 <- repLE e2- ds3 <- repLE e3- repFromThenTo ds1 ds2 ds3--repE (HsSpliceE _ splice) = repSplice splice-repE e@(PArrSeq {}) = notHandled "Parallel arrays" (ppr e)-repE e@(HsCoreAnn {}) = notHandled "Core annotations" (ppr e)-repE e@(HsSCC {}) = notHandled "Cost centres" (ppr e)-repE e@(HsTickPragma {}) = notHandled "Tick Pragma" (ppr e)-repE e@(HsTcBracketOut {}) = notHandled "TH brackets" (ppr e)-repE e = notHandled "Expression form" (ppr e)---------------------------------------------------------------------------------- Building representations of auxillary structures like Match, Clause, Stmt,--repMatchTup :: LMatch Name (LHsExpr Name) -> DsM (Core TH.MatchQ)-repMatchTup (L _ (Match [p] _ (GRHSs guards wheres))) =- do { ss1 <- mkGenSyms (collectPatBinders p)- ; addBinds ss1 $ do {- ; p1 <- repLP p- ; (ss2,ds) <- repBinds wheres- ; addBinds ss2 $ do {- ; gs <- repGuards guards- ; match <- repMatch p1 gs ds- ; wrapGenSyms (ss1++ss2) match }}}-repMatchTup _ = panic "repMatchTup: case alt with more than one arg"--repClauseTup :: LMatch Name (LHsExpr Name) -> DsM (Core TH.ClauseQ)-repClauseTup (L _ (Match ps _ (GRHSs guards wheres))) =- do { ss1 <- mkGenSyms (collectPatsBinders ps)- ; addBinds ss1 $ do {- ps1 <- repLPs ps- ; (ss2,ds) <- repBinds wheres- ; addBinds ss2 $ do {- gs <- repGuards guards- ; clause <- repClause ps1 gs ds- ; wrapGenSyms (ss1++ss2) clause }}}--repGuards :: [LGRHS Name (LHsExpr Name)] -> DsM (Core TH.BodyQ)-repGuards [L _ (GRHS [] e)]- = do {a <- repLE e; repNormal a }-repGuards other- = do { zs <- mapM repLGRHS other- ; let (xs, ys) = unzip zs- ; gd <- repGuarded (nonEmptyCoreList ys)- ; wrapGenSyms (concat xs) gd }--repLGRHS :: LGRHS Name (LHsExpr Name) -> DsM ([GenSymBind], (Core (TH.Q (TH.Guard, TH.Exp))))-repLGRHS (L _ (GRHS [L _ (BodyStmt e1 _ _ _)] e2))- = do { guarded <- repLNormalGE e1 e2- ; return ([], guarded) }-repLGRHS (L _ (GRHS ss rhs))- = do { (gs, ss') <- repLSts ss- ; rhs' <- addBinds gs $ repLE rhs- ; guarded <- repPatGE (nonEmptyCoreList ss') rhs'- ; return (gs, guarded) }--repFields :: HsRecordBinds Name -> DsM (Core [TH.Q TH.FieldExp])-repFields (HsRecFields { rec_flds = flds })- = repList fieldExpQTyConName rep_fld flds- where- rep_fld fld = do { fn <- lookupLOcc (hsRecFieldId fld)- ; e <- repLE (hsRecFieldArg fld)- ; repFieldExp fn e }----------------------------------------------------------------------------------- Representing Stmt's is tricky, especially if bound variables--- shadow each other. Consider: [| do { x <- f 1; x <- f x; g x } |]--- First gensym new names for every variable in any of the patterns.--- both static (x'1 and x'2), and dynamic ((gensym "x") and (gensym "y"))--- if variables didn't shaddow, the static gensym wouldn't be necessary--- and we could reuse the original names (x and x).------ do { x'1 <- gensym "x"--- ; x'2 <- gensym "x"--- ; doE [ BindSt (pvar x'1) [| f 1 |]--- , BindSt (pvar x'2) [| f x |]--- , NoBindSt [| g x |]--- ]--- }---- The strategy is to translate a whole list of do-bindings by building a--- bigger environment, and a bigger set of meta bindings--- (like: x'1 <- gensym "x" ) and then combining these with the translations--- of the expressions within the Do---------------------------------------------------------------------------------- The helper function repSts computes the translation of each sub expression--- and a bunch of prefix bindings denoting the dynamic renaming.--repLSts :: [LStmt Name (LHsExpr Name)] -> DsM ([GenSymBind], [Core TH.StmtQ])-repLSts stmts = repSts (map unLoc stmts)--repSts :: [Stmt Name (LHsExpr Name)] -> DsM ([GenSymBind], [Core TH.StmtQ])-repSts (BindStmt p e _ _ : ss) =- do { e2 <- repLE e- ; ss1 <- mkGenSyms (collectPatBinders p)- ; addBinds ss1 $ do {- ; p1 <- repLP p;- ; (ss2,zs) <- repSts ss- ; z <- repBindSt p1 e2- ; return (ss1++ss2, z : zs) }}-repSts (LetStmt bs : ss) =- do { (ss1,ds) <- repBinds bs- ; z <- repLetSt ds- ; (ss2,zs) <- addBinds ss1 (repSts ss)- ; return (ss1++ss2, z : zs) }-repSts (BodyStmt e _ _ _ : ss) =- do { e2 <- repLE e- ; z <- repNoBindSt e2- ; (ss2,zs) <- repSts ss- ; return (ss2, z : zs) }-repSts (ParStmt stmt_blocks _ _ : ss) =- do { (ss_s, stmt_blocks1) <- mapAndUnzipM rep_stmt_block stmt_blocks- ; let stmt_blocks2 = nonEmptyCoreList stmt_blocks1- ss1 = concat ss_s- ; z <- repParSt stmt_blocks2- ; (ss2, zs) <- addBinds ss1 (repSts ss)- ; return (ss1++ss2, z : zs) }- where- rep_stmt_block :: ParStmtBlock Name Name -> DsM ([GenSymBind], Core [TH.StmtQ])- rep_stmt_block (ParStmtBlock stmts _ _) =- do { (ss1, zs) <- repSts (map unLoc stmts)- ; zs1 <- coreList stmtQTyConName zs- ; return (ss1, zs1) }-repSts [LastStmt e _]- = do { e2 <- repLE e- ; z <- repNoBindSt e2- ; return ([], [z]) }-repSts [] = return ([],[])-repSts other = notHandled "Exotic statement" (ppr other)----------------------------------------------------------------- Bindings--------------------------------------------------------------repBinds :: HsLocalBinds Name -> DsM ([GenSymBind], Core [TH.DecQ])-repBinds EmptyLocalBinds- = do { core_list <- coreList decQTyConName []- ; return ([], core_list) }--repBinds b@(HsIPBinds _) = notHandled "Implicit parameters" (ppr b)--repBinds (HsValBinds decs)- = do { let { bndrs = hsSigTvBinders decs ++ collectHsValBinders decs }- -- No need to worrry about detailed scopes within- -- the binding group, because we are talking Names- -- here, so we can safely treat it as a mutually- -- recursive group- -- For hsSigTvBinders see Note [Scoped type variables in bindings]- ; ss <- mkGenSyms bndrs- ; prs <- addBinds ss (rep_val_binds decs)- ; core_list <- coreList decQTyConName- (de_loc (sort_by_loc prs))- ; return (ss, core_list) }--rep_val_binds :: HsValBinds Name -> DsM [(SrcSpan, Core TH.DecQ)]--- Assumes: all the binders of the binding are alrady in the meta-env-rep_val_binds (ValBindsOut binds sigs)- = do { core1 <- rep_binds' (unionManyBags (map snd binds))- ; core2 <- rep_sigs' sigs- ; return (core1 ++ core2) }-rep_val_binds (ValBindsIn _ _)- = panic "rep_val_binds: ValBindsIn"--rep_binds :: LHsBinds Name -> DsM [Core TH.DecQ]-rep_binds binds = do { binds_w_locs <- rep_binds' binds- ; return (de_loc (sort_by_loc binds_w_locs)) }--rep_binds' :: LHsBinds Name -> DsM [(SrcSpan, Core TH.DecQ)]-rep_binds' = mapM rep_bind . bagToList--rep_bind :: LHsBind Name -> DsM (SrcSpan, Core TH.DecQ)--- Assumes: all the binders of the binding are alrady in the meta-env---- Note GHC treats declarations of a variable (not a pattern)--- e.g. x = g 5 as a Fun MonoBinds. This is indicated by a single match--- with an empty list of patterns-rep_bind (L loc (FunBind { fun_id = fn,- fun_matches = MG { mg_alts = [L _ (Match [] _ (GRHSs guards wheres))] } }))- = do { (ss,wherecore) <- repBinds wheres- ; guardcore <- addBinds ss (repGuards guards)- ; fn' <- lookupLBinder fn- ; p <- repPvar fn'- ; ans <- repVal p guardcore wherecore- ; ans' <- wrapGenSyms ss ans- ; return (loc, ans') }--rep_bind (L loc (FunBind { fun_id = fn, fun_matches = MG { mg_alts = ms } }))- = do { ms1 <- mapM repClauseTup ms- ; fn' <- lookupLBinder fn- ; ans <- repFun fn' (nonEmptyCoreList ms1)- ; return (loc, ans) }--rep_bind (L loc (PatBind { pat_lhs = pat, pat_rhs = GRHSs guards wheres }))- = do { patcore <- repLP pat- ; (ss,wherecore) <- repBinds wheres- ; guardcore <- addBinds ss (repGuards guards)- ; ans <- repVal patcore guardcore wherecore- ; ans' <- wrapGenSyms ss ans- ; return (loc, ans') }--rep_bind (L _ (VarBind { var_id = v, var_rhs = e}))- = do { v' <- lookupBinder v- ; e2 <- repLE e- ; x <- repNormal e2- ; patcore <- repPvar v'- ; empty_decls <- coreList decQTyConName []- ; ans <- repVal patcore x empty_decls- ; return (srcLocSpan (getSrcLoc v), ans) }--rep_bind (L _ (AbsBinds {})) = panic "rep_bind: AbsBinds"-rep_bind (L _ dec@(PatSynBind {})) = notHandled "pattern synonyms" (ppr dec)--------------------------------------------------------------------------------- Since everything in a Bind is mutually recursive we need rename all--- all the variables simultaneously. For example:--- [| AndMonoBinds (f x = x + g 2) (g x = f 1 + 2) |] would translate to--- do { f'1 <- gensym "f"--- ; g'2 <- gensym "g"--- ; [ do { x'3 <- gensym "x"; fun f'1 [pvar x'3] [| x + g2 |]},--- do { x'4 <- gensym "x"; fun g'2 [pvar x'4] [| f 1 + 2 |]}--- ]}--- This requires collecting the bindings (f'1 <- gensym "f"), and the--- environment ( f |-> f'1 ) from each binding, and then unioning them--- together. As we do this we collect GenSymBinds's which represent the renamed--- variables bound by the Bindings. In order not to lose track of these--- representations we build a shadow datatype MB with the same structure as--- MonoBinds, but which has slots for the representations----------------------------------------------------------------------------------- GHC allows a more general form of lambda abstraction than specified--- by Haskell 98. In particular it allows guarded lambda's like :--- (\ x | even x -> 0 | odd x -> 1) at the moment we can't represent this in--- Haskell Template's Meta.Exp type so we punt if it isn't a simple thing like--- (\ p1 .. pn -> exp) by causing an error.--repLambda :: LMatch Name (LHsExpr Name) -> DsM (Core TH.ExpQ)-repLambda (L _ (Match ps _ (GRHSs [L _ (GRHS [] e)] EmptyLocalBinds)))- = do { let bndrs = collectPatsBinders ps ;- ; ss <- mkGenSyms bndrs- ; lam <- addBinds ss (- do { xs <- repLPs ps; body <- repLE e; repLam xs body })- ; wrapGenSyms ss lam }--repLambda (L _ m) = notHandled "Guarded labmdas" (pprMatch (LambdaExpr :: HsMatchContext Name) m)----------------------------------------------------------------------------------- Patterns--- repP deals with patterns. It assumes that we have already--- walked over the pattern(s) once to collect the binders, and--- have extended the environment. So every pattern-bound--- variable should already appear in the environment.---- Process a list of patterns-repLPs :: [LPat Name] -> DsM (Core [TH.PatQ])-repLPs ps = repList patQTyConName repLP ps--repLP :: LPat Name -> DsM (Core TH.PatQ)-repLP (L _ p) = repP p--repP :: Pat Name -> DsM (Core TH.PatQ)-repP (WildPat _) = repPwild-repP (LitPat l) = do { l2 <- repLiteral l; repPlit l2 }-repP (VarPat x) = do { x' <- lookupBinder x; repPvar x' }-repP (LazyPat p) = do { p1 <- repLP p; repPtilde p1 }-repP (BangPat p) = do { p1 <- repLP p; repPbang p1 }-repP (AsPat x p) = do { x' <- lookupLBinder x; p1 <- repLP p; repPaspat x' p1 }-repP (ParPat p) = repLP p-repP (ListPat ps _ Nothing) = do { qs <- repLPs ps; repPlist qs }-repP (ListPat ps ty1 (Just (_,e))) = do { p <- repP (ListPat ps ty1 Nothing); e' <- repE e; repPview e' p}-repP (TuplePat ps boxed _)- | isBoxed boxed = do { qs <- repLPs ps; repPtup qs }- | otherwise = do { qs <- repLPs ps; repPunboxedTup qs }-repP (ConPatIn dc details)- = do { con_str <- lookupLOcc dc- ; case details of- PrefixCon ps -> do { qs <- repLPs ps; repPcon con_str qs }- RecCon rec -> do { fps <- repList fieldPatQTyConName rep_fld (rec_flds rec)- ; repPrec con_str fps }- InfixCon p1 p2 -> do { p1' <- repLP p1;- p2' <- repLP p2;- repPinfix p1' con_str p2' }- }- where- rep_fld fld = do { MkC v <- lookupLOcc (hsRecFieldId fld)- ; MkC p <- repLP (hsRecFieldArg fld)- ; rep2 fieldPatName [v,p] }--repP (NPat l Nothing _) = do { a <- repOverloadedLiteral l; repPlit a }-repP (ViewPat e p _) = do { e' <- repLE e; p' <- repLP p; repPview e' p' }-repP p@(NPat _ (Just _) _) = notHandled "Negative overloaded patterns" (ppr p)-repP p@(SigPatIn {}) = notHandled "Type signatures in patterns" (ppr p)- -- The problem is to do with scoped type variables.- -- To implement them, we have to implement the scoping rules- -- here in DsMeta, and I don't want to do that today!- -- do { p' <- repLP p; t' <- repLTy t; repPsig p' t' }- -- repPsig :: Core TH.PatQ -> Core TH.TypeQ -> DsM (Core TH.PatQ)- -- repPsig (MkC p) (MkC t) = rep2 sigPName [p, t]--repP (SplicePat splice) = repSplice splice--repP other = notHandled "Exotic pattern" (ppr other)--------------------------------------------------------------- Declaration ordering helpers--sort_by_loc :: [(SrcSpan, a)] -> [(SrcSpan, a)]-sort_by_loc xs = sortBy comp xs- where comp x y = compare (fst x) (fst y)--de_loc :: [(a, b)] -> [b]-de_loc = map snd--------------------------------------------------------------- The meta-environment---- A name/identifier association for fresh names of locally bound entities-type GenSymBind = (Name, Id) -- Gensym the string and bind it to the Id- -- I.e. (x, x_id) means- -- let x_id = gensym "x" in ...---- Generate a fresh name for a locally bound entity--mkGenSyms :: [Name] -> DsM [GenSymBind]--- We can use the existing name. For example:--- [| \x_77 -> x_77 + x_77 |]--- desugars to--- do { x_77 <- genSym "x"; .... }--- We use the same x_77 in the desugared program, but with the type Bndr--- instead of Int------ We do make it an Internal name, though (hence localiseName)------ Nevertheless, it's monadic because we have to generate nameTy-mkGenSyms ns = do { var_ty <- lookupType nameTyConName- ; return [(nm, mkLocalId (localiseName nm) var_ty) | nm <- ns] }---addBinds :: [GenSymBind] -> DsM a -> DsM a--- Add a list of fresh names for locally bound entities to the--- meta environment (which is part of the state carried around--- by the desugarer monad)-addBinds bs m = dsExtendMetaEnv (mkNameEnv [(n,Bound id) | (n,id) <- bs]) m--dupBinder :: (Name, Name) -> DsM (Name, DsMetaVal)-dupBinder (new, old)- = do { mb_val <- dsLookupMetaEnv old- ; case mb_val of- Just val -> return (new, val)- Nothing -> pprPanic "dupBinder" (ppr old) }---- Look up a locally bound name----lookupLBinder :: Located Name -> DsM (Core TH.Name)-lookupLBinder (L _ n) = lookupBinder n--lookupBinder :: Name -> DsM (Core TH.Name)-lookupBinder = lookupOcc- -- Binders are brought into scope before the pattern or what-not is- -- desugared. Moreover, in instance declaration the binder of a method- -- will be the selector Id and hence a global; so we need the- -- globalVar case of lookupOcc---- Look up a name that is either locally bound or a global name------ * If it is a global name, generate the "original name" representation (ie,--- the <module>:<name> form) for the associated entity----lookupLOcc :: Located Name -> DsM (Core TH.Name)--- Lookup an occurrence; it can't be a splice.--- Use the in-scope bindings if they exist-lookupLOcc (L _ n) = lookupOcc n--lookupOcc :: Name -> DsM (Core TH.Name)-lookupOcc n- = do { mb_val <- dsLookupMetaEnv n ;- case mb_val of- Nothing -> globalVar n- Just (Bound x) -> return (coreVar x)- Just (Splice _) -> pprPanic "repE:lookupOcc" (ppr n)- }--globalVar :: Name -> DsM (Core TH.Name)--- Not bound by the meta-env--- Could be top-level; or could be local--- f x = $(g [| x |])--- Here the x will be local-globalVar name- | isExternalName name- = do { MkC mod <- coreStringLit name_mod- ; MkC pkg <- coreStringLit name_pkg- ; MkC occ <- occNameLit name- ; rep2 mk_varg [pkg,mod,occ] }- | otherwise- = do { MkC occ <- occNameLit name- ; MkC uni <- coreIntLit (getKey (getUnique name))- ; rep2 mkNameLName [occ,uni] }- where- mod = {- ASSERT( isExternalName name) -} nameModule name- name_mod = moduleNameString (moduleName mod)- name_pkg = packageIdString (modulePackageId mod)- name_occ = nameOccName name- mk_varg | OccName.isDataOcc name_occ = mkNameG_dName- | OccName.isVarOcc name_occ = mkNameG_vName- | OccName.isTcOcc name_occ = mkNameG_tcName- | otherwise = pprPanic "DsMeta.globalVar" (ppr name)--lookupType :: Name -- Name of type constructor (e.g. TH.ExpQ)- -> DsM Type -- The type-lookupType tc_name = do { tc <- dsLookupTyCon tc_name ;- return (mkTyConApp tc []) }--wrapGenSyms :: [GenSymBind]- -> Core (TH.Q a) -> DsM (Core (TH.Q a))--- wrapGenSyms [(nm1,id1), (nm2,id2)] y--- --> bindQ (gensym nm1) (\ id1 ->--- bindQ (gensym nm2 (\ id2 ->--- y))--wrapGenSyms binds body@(MkC b)- = do { var_ty <- lookupType nameTyConName- ; go var_ty binds }- where- [elt_ty] = tcTyConAppArgs (exprType b)- -- b :: Q a, so we can get the type 'a' by looking at the- -- argument type. NB: this relies on Q being a data/newtype,- -- not a type synonym-- go _ [] = return body- go var_ty ((name,id) : binds)- = do { MkC body' <- go var_ty binds- ; lit_str <- occNameLit name- ; gensym_app <- repGensym lit_str- ; repBindQ var_ty elt_ty- gensym_app (MkC (Lam id body')) }--occNameLit :: Name -> DsM (Core String)-occNameLit n = coreStringLit (occNameString (nameOccName n))----- %*********************************************************************--- %* *--- Constructing code--- %* *--- %*********************************************************************---------------------------------------------------------------------------------- PHANTOM TYPES for consistency. In order to make sure we do this correct--- we invent a new datatype which uses phantom types.--newtype Core a = MkC CoreExpr-unC :: Core a -> CoreExpr-unC (MkC x) = x--rep2 :: Name -> [ CoreExpr ] -> DsM (Core a)-rep2 n xs = do { id <- dsLookupGlobalId n- ; return (MkC (foldl App (Var id) xs)) }--dataCon' :: Name -> [CoreExpr] -> DsM (Core a)-dataCon' n args = do { id <- dsLookupDataCon n- ; return $ MkC $ mkConApp id args }--dataCon :: Name -> DsM (Core a)-dataCon n = dataCon' n []---- Then we make "repConstructors" which use the phantom types for each of the--- smart constructors of the Meta.Meta datatypes.----- %*********************************************************************--- %* *--- The 'smart constructors'--- %* *--- %*********************************************************************----------------- Patterns ------------------repPlit :: Core TH.Lit -> DsM (Core TH.PatQ)-repPlit (MkC l) = rep2 litPName [l]--repPvar :: Core TH.Name -> DsM (Core TH.PatQ)-repPvar (MkC s) = rep2 varPName [s]--repPtup :: Core [TH.PatQ] -> DsM (Core TH.PatQ)-repPtup (MkC ps) = rep2 tupPName [ps]--repPunboxedTup :: Core [TH.PatQ] -> DsM (Core TH.PatQ)-repPunboxedTup (MkC ps) = rep2 unboxedTupPName [ps]--repPcon :: Core TH.Name -> Core [TH.PatQ] -> DsM (Core TH.PatQ)-repPcon (MkC s) (MkC ps) = rep2 conPName [s, ps]--repPrec :: Core TH.Name -> Core [(TH.Name,TH.PatQ)] -> DsM (Core TH.PatQ)-repPrec (MkC c) (MkC rps) = rep2 recPName [c,rps]--repPinfix :: Core TH.PatQ -> Core TH.Name -> Core TH.PatQ -> DsM (Core TH.PatQ)-repPinfix (MkC p1) (MkC n) (MkC p2) = rep2 infixPName [p1, n, p2]--repPtilde :: Core TH.PatQ -> DsM (Core TH.PatQ)-repPtilde (MkC p) = rep2 tildePName [p]--repPbang :: Core TH.PatQ -> DsM (Core TH.PatQ)-repPbang (MkC p) = rep2 bangPName [p]--repPaspat :: Core TH.Name -> Core TH.PatQ -> DsM (Core TH.PatQ)-repPaspat (MkC s) (MkC p) = rep2 asPName [s, p]--repPwild :: DsM (Core TH.PatQ)-repPwild = rep2 wildPName []--repPlist :: Core [TH.PatQ] -> DsM (Core TH.PatQ)-repPlist (MkC ps) = rep2 listPName [ps]--repPview :: Core TH.ExpQ -> Core TH.PatQ -> DsM (Core TH.PatQ)-repPview (MkC e) (MkC p) = rep2 viewPName [e,p]----------------- Expressions ------------------repVarOrCon :: Name -> Core TH.Name -> DsM (Core TH.ExpQ)-repVarOrCon vc str | isDataOcc (nameOccName vc) = repCon str- | otherwise = repVar str--repVar :: Core TH.Name -> DsM (Core TH.ExpQ)-repVar (MkC s) = rep2 varEName [s]--repCon :: Core TH.Name -> DsM (Core TH.ExpQ)-repCon (MkC s) = rep2 conEName [s]--repLit :: Core TH.Lit -> DsM (Core TH.ExpQ)-repLit (MkC c) = rep2 litEName [c]--repApp :: Core TH.ExpQ -> Core TH.ExpQ -> DsM (Core TH.ExpQ)-repApp (MkC x) (MkC y) = rep2 appEName [x,y]--repLam :: Core [TH.PatQ] -> Core TH.ExpQ -> DsM (Core TH.ExpQ)-repLam (MkC ps) (MkC e) = rep2 lamEName [ps, e]--repLamCase :: Core [TH.MatchQ] -> DsM (Core TH.ExpQ)-repLamCase (MkC ms) = rep2 lamCaseEName [ms]--repTup :: Core [TH.ExpQ] -> DsM (Core TH.ExpQ)-repTup (MkC es) = rep2 tupEName [es]--repUnboxedTup :: Core [TH.ExpQ] -> DsM (Core TH.ExpQ)-repUnboxedTup (MkC es) = rep2 unboxedTupEName [es]--repCond :: Core TH.ExpQ -> Core TH.ExpQ -> Core TH.ExpQ -> DsM (Core TH.ExpQ)-repCond (MkC x) (MkC y) (MkC z) = rep2 condEName [x,y,z]--repMultiIf :: Core [TH.Q (TH.Guard, TH.Exp)] -> DsM (Core TH.ExpQ)-repMultiIf (MkC alts) = rep2 multiIfEName [alts]--repLetE :: Core [TH.DecQ] -> Core TH.ExpQ -> DsM (Core TH.ExpQ)-repLetE (MkC ds) (MkC e) = rep2 letEName [ds, e]--repCaseE :: Core TH.ExpQ -> Core [TH.MatchQ] -> DsM( Core TH.ExpQ)-repCaseE (MkC e) (MkC ms) = rep2 caseEName [e, ms]--repDoE :: Core [TH.StmtQ] -> DsM (Core TH.ExpQ)-repDoE (MkC ss) = rep2 doEName [ss]--repComp :: Core [TH.StmtQ] -> DsM (Core TH.ExpQ)-repComp (MkC ss) = rep2 compEName [ss]--repListExp :: Core [TH.ExpQ] -> DsM (Core TH.ExpQ)-repListExp (MkC es) = rep2 listEName [es]--repSigExp :: Core TH.ExpQ -> Core TH.TypeQ -> DsM (Core TH.ExpQ)-repSigExp (MkC e) (MkC t) = rep2 sigEName [e,t]--repRecCon :: Core TH.Name -> Core [TH.Q TH.FieldExp]-> DsM (Core TH.ExpQ)-repRecCon (MkC c) (MkC fs) = rep2 recConEName [c,fs]--repRecUpd :: Core TH.ExpQ -> Core [TH.Q TH.FieldExp] -> DsM (Core TH.ExpQ)-repRecUpd (MkC e) (MkC fs) = rep2 recUpdEName [e,fs]--repFieldExp :: Core TH.Name -> Core TH.ExpQ -> DsM (Core (TH.Q TH.FieldExp))-repFieldExp (MkC n) (MkC x) = rep2 fieldExpName [n,x]--repInfixApp :: Core TH.ExpQ -> Core TH.ExpQ -> Core TH.ExpQ -> DsM (Core TH.ExpQ)-repInfixApp (MkC x) (MkC y) (MkC z) = rep2 infixAppName [x,y,z]--repSectionL :: Core TH.ExpQ -> Core TH.ExpQ -> DsM (Core TH.ExpQ)-repSectionL (MkC x) (MkC y) = rep2 sectionLName [x,y]--repSectionR :: Core TH.ExpQ -> Core TH.ExpQ -> DsM (Core TH.ExpQ)-repSectionR (MkC x) (MkC y) = rep2 sectionRName [x,y]-------------- Right hand sides (guarded expressions) -----repGuarded :: Core [TH.Q (TH.Guard, TH.Exp)] -> DsM (Core TH.BodyQ)-repGuarded (MkC pairs) = rep2 guardedBName [pairs]--repNormal :: Core TH.ExpQ -> DsM (Core TH.BodyQ)-repNormal (MkC e) = rep2 normalBName [e]-------------- Guards -----repLNormalGE :: LHsExpr Name -> LHsExpr Name -> DsM (Core (TH.Q (TH.Guard, TH.Exp)))-repLNormalGE g e = do g' <- repLE g- e' <- repLE e- repNormalGE g' e'--repNormalGE :: Core TH.ExpQ -> Core TH.ExpQ -> DsM (Core (TH.Q (TH.Guard, TH.Exp)))-repNormalGE (MkC g) (MkC e) = rep2 normalGEName [g, e]--repPatGE :: Core [TH.StmtQ] -> Core TH.ExpQ -> DsM (Core (TH.Q (TH.Guard, TH.Exp)))-repPatGE (MkC ss) (MkC e) = rep2 patGEName [ss, e]--------------- Stmts --------------------repBindSt :: Core TH.PatQ -> Core TH.ExpQ -> DsM (Core TH.StmtQ)-repBindSt (MkC p) (MkC e) = rep2 bindSName [p,e]--repLetSt :: Core [TH.DecQ] -> DsM (Core TH.StmtQ)-repLetSt (MkC ds) = rep2 letSName [ds]--repNoBindSt :: Core TH.ExpQ -> DsM (Core TH.StmtQ)-repNoBindSt (MkC e) = rep2 noBindSName [e]--repParSt :: Core [[TH.StmtQ]] -> DsM (Core TH.StmtQ)-repParSt (MkC sss) = rep2 parSName [sss]---------------- Range (Arithmetic sequences) ------------repFrom :: Core TH.ExpQ -> DsM (Core TH.ExpQ)-repFrom (MkC x) = rep2 fromEName [x]--repFromThen :: Core TH.ExpQ -> Core TH.ExpQ -> DsM (Core TH.ExpQ)-repFromThen (MkC x) (MkC y) = rep2 fromThenEName [x,y]--repFromTo :: Core TH.ExpQ -> Core TH.ExpQ -> DsM (Core TH.ExpQ)-repFromTo (MkC x) (MkC y) = rep2 fromToEName [x,y]--repFromThenTo :: Core TH.ExpQ -> Core TH.ExpQ -> Core TH.ExpQ -> DsM (Core TH.ExpQ)-repFromThenTo (MkC x) (MkC y) (MkC z) = rep2 fromThenToEName [x,y,z]-------------- Match and Clause Tuples ------------repMatch :: Core TH.PatQ -> Core TH.BodyQ -> Core [TH.DecQ] -> DsM (Core TH.MatchQ)-repMatch (MkC p) (MkC bod) (MkC ds) = rep2 matchName [p, bod, ds]--repClause :: Core [TH.PatQ] -> Core TH.BodyQ -> Core [TH.DecQ] -> DsM (Core TH.ClauseQ)-repClause (MkC ps) (MkC bod) (MkC ds) = rep2 clauseName [ps, bod, ds]---------------- Dec ------------------------------repVal :: Core TH.PatQ -> Core TH.BodyQ -> Core [TH.DecQ] -> DsM (Core TH.DecQ)-repVal (MkC p) (MkC b) (MkC ds) = rep2 valDName [p, b, ds]--repFun :: Core TH.Name -> Core [TH.ClauseQ] -> DsM (Core TH.DecQ)-repFun (MkC nm) (MkC b) = rep2 funDName [nm, b]--repData :: Core TH.CxtQ -> Core TH.Name -> Core [TH.TyVarBndr]- -> Maybe (Core [TH.TypeQ])- -> Core [TH.ConQ] -> Core [TH.Name] -> DsM (Core TH.DecQ)-repData (MkC cxt) (MkC nm) (MkC tvs) Nothing (MkC cons) (MkC derivs)- = rep2 dataDName [cxt, nm, tvs, cons, derivs]-repData (MkC cxt) (MkC nm) (MkC _) (Just (MkC tys)) (MkC cons) (MkC derivs)- = rep2 dataInstDName [cxt, nm, tys, cons, derivs]--repNewtype :: Core TH.CxtQ -> Core TH.Name -> Core [TH.TyVarBndr]- -> Maybe (Core [TH.TypeQ])- -> Core TH.ConQ -> Core [TH.Name] -> DsM (Core TH.DecQ)-repNewtype (MkC cxt) (MkC nm) (MkC tvs) Nothing (MkC con) (MkC derivs)- = rep2 newtypeDName [cxt, nm, tvs, con, derivs]-repNewtype (MkC cxt) (MkC nm) (MkC _) (Just (MkC tys)) (MkC con) (MkC derivs)- = rep2 newtypeInstDName [cxt, nm, tys, con, derivs]--repTySyn :: Core TH.Name -> Core [TH.TyVarBndr]- -> Core TH.TypeQ -> DsM (Core TH.DecQ)-repTySyn (MkC nm) (MkC tvs) (MkC rhs)- = rep2 tySynDName [nm, tvs, rhs]--repInst :: Core TH.CxtQ -> Core TH.TypeQ -> Core [TH.DecQ] -> DsM (Core TH.DecQ)-repInst (MkC cxt) (MkC ty) (MkC ds) = rep2 instanceDName [cxt, ty, ds]--repClass :: Core TH.CxtQ -> Core TH.Name -> Core [TH.TyVarBndr]- -> Core [TH.FunDep] -> Core [TH.DecQ]- -> DsM (Core TH.DecQ)-repClass (MkC cxt) (MkC cls) (MkC tvs) (MkC fds) (MkC ds)- = rep2 classDName [cxt, cls, tvs, fds, ds]--repPragInl :: Core TH.Name -> Core TH.Inline -> Core TH.RuleMatch- -> Core TH.Phases -> DsM (Core TH.DecQ)-repPragInl (MkC nm) (MkC inline) (MkC rm) (MkC phases)- = rep2 pragInlDName [nm, inline, rm, phases]--repPragSpec :: Core TH.Name -> Core TH.TypeQ -> Core TH.Phases- -> DsM (Core TH.DecQ)-repPragSpec (MkC nm) (MkC ty) (MkC phases)- = rep2 pragSpecDName [nm, ty, phases]--repPragSpecInl :: Core TH.Name -> Core TH.TypeQ -> Core TH.Inline- -> Core TH.Phases -> DsM (Core TH.DecQ)-repPragSpecInl (MkC nm) (MkC ty) (MkC inline) (MkC phases)- = rep2 pragSpecInlDName [nm, ty, inline, phases]--repPragSpecInst :: Core TH.TypeQ -> DsM (Core TH.DecQ)-repPragSpecInst (MkC ty) = rep2 pragSpecInstDName [ty]--repPragRule :: Core String -> Core [TH.RuleBndrQ] -> Core TH.ExpQ- -> Core TH.ExpQ -> Core TH.Phases -> DsM (Core TH.DecQ)-repPragRule (MkC nm) (MkC bndrs) (MkC lhs) (MkC rhs) (MkC phases)- = rep2 pragRuleDName [nm, bndrs, lhs, rhs, phases]--repFamilyNoKind :: Core TH.FamFlavour -> Core TH.Name -> Core [TH.TyVarBndr]- -> DsM (Core TH.DecQ)-repFamilyNoKind (MkC flav) (MkC nm) (MkC tvs)- = rep2 familyNoKindDName [flav, nm, tvs]--repFamilyKind :: Core TH.FamFlavour -> Core TH.Name -> Core [TH.TyVarBndr]- -> Core TH.Kind- -> DsM (Core TH.DecQ)-repFamilyKind (MkC flav) (MkC nm) (MkC tvs) (MkC ki)- = rep2 familyKindDName [flav, nm, tvs, ki]--repTySynInst :: Core TH.Name -> Core TH.TySynEqnQ -> DsM (Core TH.DecQ)-repTySynInst (MkC nm) (MkC eqn)- = rep2 tySynInstDName [nm, eqn]--repClosedFamilyNoKind :: Core TH.Name- -> Core [TH.TyVarBndr]- -> Core [TH.TySynEqnQ]- -> DsM (Core TH.DecQ)-repClosedFamilyNoKind (MkC nm) (MkC tvs) (MkC eqns)- = rep2 closedTypeFamilyNoKindDName [nm, tvs, eqns]--repClosedFamilyKind :: Core TH.Name- -> Core [TH.TyVarBndr]- -> Core TH.Kind- -> Core [TH.TySynEqnQ]- -> DsM (Core TH.DecQ)-repClosedFamilyKind (MkC nm) (MkC tvs) (MkC ki) (MkC eqns)- = rep2 closedTypeFamilyKindDName [nm, tvs, ki, eqns]--repTySynEqn :: Core [TH.TypeQ] -> Core TH.TypeQ -> DsM (Core TH.TySynEqnQ)-repTySynEqn (MkC lhs) (MkC rhs)- = rep2 tySynEqnName [lhs, rhs]--repRoleAnnotD :: Core TH.Name -> Core [TH.Role] -> DsM (Core TH.DecQ)-repRoleAnnotD (MkC n) (MkC roles) = rep2 roleAnnotDName [n, roles]--repFunDep :: Core [TH.Name] -> Core [TH.Name] -> DsM (Core TH.FunDep)-repFunDep (MkC xs) (MkC ys) = rep2 funDepName [xs, ys]--repProto :: Core TH.Name -> Core TH.TypeQ -> DsM (Core TH.DecQ)-repProto (MkC s) (MkC ty) = rep2 sigDName [s, ty]--repCtxt :: Core [TH.PredQ] -> DsM (Core TH.CxtQ)-repCtxt (MkC tys) = rep2 cxtName [tys]--repClassP :: Core TH.Name -> Core [TH.TypeQ] -> DsM (Core TH.PredQ)-repClassP (MkC cla) (MkC tys) = rep2 classPName [cla, tys]--repEqualP :: Core TH.TypeQ -> Core TH.TypeQ -> DsM (Core TH.PredQ)-repEqualP (MkC ty1) (MkC ty2) = rep2 equalPName [ty1, ty2]--repConstr :: Core TH.Name -> HsConDeclDetails Name- -> DsM (Core TH.ConQ)-repConstr con (PrefixCon ps)- = do arg_tys <- repList strictTypeQTyConName repBangTy ps- rep2 normalCName [unC con, unC arg_tys]-repConstr con (RecCon ips)- = do { arg_vtys <- repList varStrictTypeQTyConName rep_ip ips- ; rep2 recCName [unC con, unC arg_vtys] }- where- rep_ip ip = do { MkC v <- lookupLOcc (cd_fld_name ip)- ; MkC ty <- repBangTy (cd_fld_type ip)- ; rep2 varStrictTypeName [v,ty] }--repConstr con (InfixCon st1 st2)- = do arg1 <- repBangTy st1- arg2 <- repBangTy st2- rep2 infixCName [unC arg1, unC con, unC arg2]-------------- Types ---------------------repTForall :: Core [TH.TyVarBndr] -> Core TH.CxtQ -> Core TH.TypeQ- -> DsM (Core TH.TypeQ)-repTForall (MkC tvars) (MkC ctxt) (MkC ty)- = rep2 forallTName [tvars, ctxt, ty]--repTvar :: Core TH.Name -> DsM (Core TH.TypeQ)-repTvar (MkC s) = rep2 varTName [s]--repTapp :: Core TH.TypeQ -> Core TH.TypeQ -> DsM (Core TH.TypeQ)-repTapp (MkC t1) (MkC t2) = rep2 appTName [t1, t2]--repTapps :: Core TH.TypeQ -> [Core TH.TypeQ] -> DsM (Core TH.TypeQ)-repTapps f [] = return f-repTapps f (t:ts) = do { f1 <- repTapp f t; repTapps f1 ts }--repTSig :: Core TH.TypeQ -> Core TH.Kind -> DsM (Core TH.TypeQ)-repTSig (MkC ty) (MkC ki) = rep2 sigTName [ty, ki]--repTPromotedList :: [Core TH.TypeQ] -> DsM (Core TH.TypeQ)-repTPromotedList [] = repPromotedNilTyCon-repTPromotedList (t:ts) = do { tcon <- repPromotedConsTyCon- ; f <- repTapp tcon t- ; t' <- repTPromotedList ts- ; repTapp f t'- }--repTLit :: Core TH.TyLitQ -> DsM (Core TH.TypeQ)-repTLit (MkC lit) = rep2 litTName [lit]----------- Type constructors ----------------repNamedTyCon :: Core TH.Name -> DsM (Core TH.TypeQ)-repNamedTyCon (MkC s) = rep2 conTName [s]--repTupleTyCon :: Int -> DsM (Core TH.TypeQ)--- Note: not Core Int; it's easier to be direct here-repTupleTyCon i = do dflags <- getDynFlags- rep2 tupleTName [mkIntExprInt dflags i]--repUnboxedTupleTyCon :: Int -> DsM (Core TH.TypeQ)--- Note: not Core Int; it's easier to be direct here-repUnboxedTupleTyCon i = do dflags <- getDynFlags- rep2 unboxedTupleTName [mkIntExprInt dflags i]--repArrowTyCon :: DsM (Core TH.TypeQ)-repArrowTyCon = rep2 arrowTName []--repListTyCon :: DsM (Core TH.TypeQ)-repListTyCon = rep2 listTName []--repPromotedTyCon :: Core TH.Name -> DsM (Core TH.TypeQ)-repPromotedTyCon (MkC s) = rep2 promotedTName [s]--repPromotedTupleTyCon :: Int -> DsM (Core TH.TypeQ)-repPromotedTupleTyCon i = do dflags <- getDynFlags- rep2 promotedTupleTName [mkIntExprInt dflags i]--repPromotedNilTyCon :: DsM (Core TH.TypeQ)-repPromotedNilTyCon = rep2 promotedNilTName []--repPromotedConsTyCon :: DsM (Core TH.TypeQ)-repPromotedConsTyCon = rep2 promotedConsTName []-------------- Kinds ---------------------repPlainTV :: Core TH.Name -> DsM (Core TH.TyVarBndr)-repPlainTV (MkC nm) = rep2 plainTVName [nm]--repKindedTV :: Core TH.Name -> Core TH.Kind -> DsM (Core TH.TyVarBndr)-repKindedTV (MkC nm) (MkC ki) = rep2 kindedTVName [nm, ki]--repKVar :: Core TH.Name -> DsM (Core TH.Kind)-repKVar (MkC s) = rep2 varKName [s]--repKCon :: Core TH.Name -> DsM (Core TH.Kind)-repKCon (MkC s) = rep2 conKName [s]--repKTuple :: Int -> DsM (Core TH.Kind)-repKTuple i = do dflags <- getDynFlags- rep2 tupleKName [mkIntExprInt dflags i]--repKArrow :: DsM (Core TH.Kind)-repKArrow = rep2 arrowKName []--repKList :: DsM (Core TH.Kind)-repKList = rep2 listKName []--repKApp :: Core TH.Kind -> Core TH.Kind -> DsM (Core TH.Kind)-repKApp (MkC k1) (MkC k2) = rep2 appKName [k1, k2]--repKApps :: Core TH.Kind -> [Core TH.Kind] -> DsM (Core TH.Kind)-repKApps f [] = return f-repKApps f (k:ks) = do { f' <- repKApp f k; repKApps f' ks }--repKStar :: DsM (Core TH.Kind)-repKStar = rep2 starKName []--repKConstraint :: DsM (Core TH.Kind)-repKConstraint = rep2 constraintKName []--------------------------------------------------------------- Literals--repLiteral :: HsLit -> DsM (Core TH.Lit)-repLiteral lit- = do lit' <- case lit of- HsIntPrim i -> mk_integer i- HsWordPrim w -> mk_integer w- HsInt i -> mk_integer i- HsFloatPrim r -> mk_rational r- HsDoublePrim r -> mk_rational r- _ -> return lit- lit_expr <- dsLit lit'- case mb_lit_name of- Just lit_name -> rep2 lit_name [lit_expr]- Nothing -> notHandled "Exotic literal" (ppr lit)- where- mb_lit_name = case lit of- HsInteger _ _ -> Just integerLName- HsInt _ -> Just integerLName- HsIntPrim _ -> Just intPrimLName- HsWordPrim _ -> Just wordPrimLName- HsFloatPrim _ -> Just floatPrimLName- HsDoublePrim _ -> Just doublePrimLName- HsChar _ -> Just charLName- HsString _ -> Just stringLName- HsRat _ _ -> Just rationalLName- _ -> Nothing--mk_integer :: Integer -> DsM HsLit-mk_integer i = do integer_ty <- lookupType integerTyConName- return $ HsInteger i integer_ty-mk_rational :: FractionalLit -> DsM HsLit-mk_rational r = do rat_ty <- lookupType rationalTyConName- return $ HsRat r rat_ty-mk_string :: FastString -> DsM HsLit-mk_string s = return $ HsString s--repOverloadedLiteral :: HsOverLit Name -> DsM (Core TH.Lit)-repOverloadedLiteral (OverLit { ol_val = val})- = do { lit <- mk_lit val; repLiteral lit }- -- The type Rational will be in the environment, because- -- the smart constructor 'TH.Syntax.rationalL' uses it in its type,- -- and rationalL is sucked in when any TH stuff is used--mk_lit :: OverLitVal -> DsM HsLit-mk_lit (HsIntegral i) = mk_integer i-mk_lit (HsFractional f) = mk_rational f-mk_lit (HsIsString s) = mk_string s----------------- Miscellaneous ---------------------repGensym :: Core String -> DsM (Core (TH.Q TH.Name))-repGensym (MkC lit_str) = rep2 newNameName [lit_str]--repBindQ :: Type -> Type -- a and b- -> Core (TH.Q a) -> Core (a -> TH.Q b) -> DsM (Core (TH.Q b))-repBindQ ty_a ty_b (MkC x) (MkC y)- = rep2 bindQName [Type ty_a, Type ty_b, x, y]--repSequenceQ :: Type -> Core [TH.Q a] -> DsM (Core (TH.Q [a]))-repSequenceQ ty_a (MkC list)- = rep2 sequenceQName [Type ty_a, list]-------------- Lists and Tuples ---------------------- turn a list of patterns into a single pattern matching a list--repList :: Name -> (a -> DsM (Core b))- -> [a] -> DsM (Core [b])-repList tc_name f args- = do { args1 <- mapM f args- ; coreList tc_name args1 }--coreList :: Name -- Of the TyCon of the element type- -> [Core a] -> DsM (Core [a])-coreList tc_name es- = do { elt_ty <- lookupType tc_name; return (coreList' elt_ty es) }--coreList' :: Type -- The element type- -> [Core a] -> Core [a]-coreList' elt_ty es = MkC (mkListExpr elt_ty (map unC es ))--nonEmptyCoreList :: [Core a] -> Core [a]- -- The list must be non-empty so we can get the element type- -- Otherwise use coreList-nonEmptyCoreList [] = panic "coreList: empty argument"-nonEmptyCoreList xs@(MkC x:_) = MkC (mkListExpr (exprType x) (map unC xs))--coreStringLit :: String -> DsM (Core String)-coreStringLit s = do { z <- mkStringExpr s; return(MkC z) }-------------- Literals & Variables ---------------------coreIntLit :: Int -> DsM (Core Int)-coreIntLit i = do dflags <- getDynFlags- return (MkC (mkIntExprInt dflags i))--coreVar :: Id -> Core TH.Name -- The Id has type Name-coreVar id = MkC (Var id)------------------- Failure ------------------------notHandled :: String -> SDoc -> DsM a-notHandled what doc = failWithDs msg- where- msg = hang (text what <+> ptext (sLit "not (yet) handled by Template Haskell"))- 2 doc----- %************************************************************************--- %* *--- The known-key names for Template Haskell--- %* *--- %************************************************************************---- To add a name, do three things------ 1) Allocate a key--- 2) Make a "Name"--- 3) Add the name to knownKeyNames--templateHaskellNames :: [Name]--- The names that are implicitly mentioned by ``bracket''--- Should stay in sync with the import list of DsMeta--templateHaskellNames = [- returnQName, bindQName, sequenceQName, newNameName, liftName,- mkNameName, mkNameG_vName, mkNameG_dName, mkNameG_tcName, mkNameLName,- liftStringName,- unTypeName,- unTypeQName,- unsafeTExpCoerceName,-- -- Lit- charLName, stringLName, integerLName, intPrimLName, wordPrimLName,- floatPrimLName, doublePrimLName, rationalLName,- -- Pat- litPName, varPName, tupPName, unboxedTupPName,- conPName, tildePName, bangPName, infixPName,- asPName, wildPName, recPName, listPName, sigPName, viewPName,- -- FieldPat- fieldPatName,- -- Match- matchName,- -- Clause- clauseName,- -- Exp- varEName, conEName, litEName, appEName, infixEName,- infixAppName, sectionLName, sectionRName, lamEName, lamCaseEName,- tupEName, unboxedTupEName,- condEName, multiIfEName, letEName, caseEName, doEName, compEName,- fromEName, fromThenEName, fromToEName, fromThenToEName,- listEName, sigEName, recConEName, recUpdEName,- -- FieldExp- fieldExpName,- -- Body- guardedBName, normalBName,- -- Guard- normalGEName, patGEName,- -- Stmt- bindSName, letSName, noBindSName, parSName,- -- Dec- funDName, valDName, dataDName, newtypeDName, tySynDName,- classDName, instanceDName, sigDName, forImpDName,- pragInlDName, pragSpecDName, pragSpecInlDName, pragSpecInstDName,- pragRuleDName,- familyNoKindDName, familyKindDName, dataInstDName, newtypeInstDName,- tySynInstDName, closedTypeFamilyKindDName, closedTypeFamilyNoKindDName,- infixLDName, infixRDName, infixNDName,- roleAnnotDName,- -- Cxt- cxtName,- -- Pred- classPName, equalPName,- -- Strict- isStrictName, notStrictName, unpackedName,- -- Con- normalCName, recCName, infixCName, forallCName,- -- StrictType- strictTypeName,- -- VarStrictType- varStrictTypeName,- -- Type- forallTName, varTName, conTName, appTName,- tupleTName, unboxedTupleTName, arrowTName, listTName, sigTName, litTName,- promotedTName, promotedTupleTName, promotedNilTName, promotedConsTName,- -- TyLit- numTyLitName, strTyLitName,- -- TyVarBndr- plainTVName, kindedTVName,- -- Role- nominalRName, representationalRName, phantomRName, inferRName,- -- Kind- varKName, conKName, tupleKName, arrowKName, listKName, appKName,- starKName, constraintKName,- -- Callconv- cCallName, stdCallName,- -- Safety- unsafeName,- safeName,- interruptibleName,- -- Inline- noInlineDataConName, inlineDataConName, inlinableDataConName,- -- RuleMatch- conLikeDataConName, funLikeDataConName,- -- Phases- allPhasesDataConName, fromPhaseDataConName, beforePhaseDataConName,- -- TExp- tExpDataConName,- -- RuleBndr- ruleVarName, typedRuleVarName,- -- FunDep- funDepName,- -- FamFlavour- typeFamName, dataFamName,- -- TySynEqn- tySynEqnName,-- -- And the tycons- qTyConName, nameTyConName, patTyConName, fieldPatTyConName, matchQTyConName,- clauseQTyConName, expQTyConName, fieldExpTyConName, predTyConName,- stmtQTyConName, decQTyConName, conQTyConName, strictTypeQTyConName,- varStrictTypeQTyConName, typeQTyConName, expTyConName, decTyConName,- typeTyConName, tyVarBndrTyConName, matchTyConName, clauseTyConName,- patQTyConName, fieldPatQTyConName, fieldExpQTyConName, funDepTyConName,- predQTyConName, decsQTyConName, ruleBndrQTyConName, tySynEqnQTyConName,- roleTyConName, tExpTyConName,-- -- Quasiquoting- quoteDecName, quoteTypeName, quoteExpName, quotePatName]--thSyn, thLib, qqLib :: Module-thSyn = mkTHModule (fsLit "Language.Haskell.TH.Syntax")-thLib = mkTHModule (fsLit "Language.Haskell.TH.Lib")-qqLib = mkTHModule (fsLit "Language.Haskell.TH.Quote")--mkTHModule :: FastString -> Module-mkTHModule m = mkModule thPackageId (mkModuleNameFS m)--libFun, libTc, thFun, thTc, thCon, qqFun :: FastString -> Unique -> Name-libFun = mk_known_key_name OccName.varName thLib-libTc = mk_known_key_name OccName.tcName thLib-thFun = mk_known_key_name OccName.varName thSyn-thTc = mk_known_key_name OccName.tcName thSyn-thCon = mk_known_key_name OccName.dataName thSyn-qqFun = mk_known_key_name OccName.varName qqLib---------------------- TH.Syntax ------------------------qTyConName, nameTyConName, fieldExpTyConName, patTyConName,- fieldPatTyConName, expTyConName, decTyConName, typeTyConName,- tyVarBndrTyConName, matchTyConName, clauseTyConName, funDepTyConName,- predTyConName, tExpTyConName :: Name-qTyConName = thTc (fsLit "Q") qTyConKey-nameTyConName = thTc (fsLit "Name") nameTyConKey-fieldExpTyConName = thTc (fsLit "FieldExp") fieldExpTyConKey-patTyConName = thTc (fsLit "Pat") patTyConKey-fieldPatTyConName = thTc (fsLit "FieldPat") fieldPatTyConKey-expTyConName = thTc (fsLit "Exp") expTyConKey-decTyConName = thTc (fsLit "Dec") decTyConKey-typeTyConName = thTc (fsLit "Type") typeTyConKey-tyVarBndrTyConName= thTc (fsLit "TyVarBndr") tyVarBndrTyConKey-matchTyConName = thTc (fsLit "Match") matchTyConKey-clauseTyConName = thTc (fsLit "Clause") clauseTyConKey-funDepTyConName = thTc (fsLit "FunDep") funDepTyConKey-predTyConName = thTc (fsLit "Pred") predTyConKey-tExpTyConName = thTc (fsLit "TExp") tExpTyConKey--returnQName, bindQName, sequenceQName, newNameName, liftName,- mkNameName, mkNameG_vName, mkNameG_dName, mkNameG_tcName,- mkNameLName, liftStringName, unTypeName, unTypeQName,- unsafeTExpCoerceName :: Name-returnQName = thFun (fsLit "returnQ") returnQIdKey-bindQName = thFun (fsLit "bindQ") bindQIdKey-sequenceQName = thFun (fsLit "sequenceQ") sequenceQIdKey-newNameName = thFun (fsLit "newName") newNameIdKey-liftName = thFun (fsLit "lift") liftIdKey-liftStringName = thFun (fsLit "liftString") liftStringIdKey-mkNameName = thFun (fsLit "mkName") mkNameIdKey-mkNameG_vName = thFun (fsLit "mkNameG_v") mkNameG_vIdKey-mkNameG_dName = thFun (fsLit "mkNameG_d") mkNameG_dIdKey-mkNameG_tcName = thFun (fsLit "mkNameG_tc") mkNameG_tcIdKey-mkNameLName = thFun (fsLit "mkNameL") mkNameLIdKey-unTypeName = thFun (fsLit "unType") unTypeIdKey-unTypeQName = thFun (fsLit "unTypeQ") unTypeQIdKey-unsafeTExpCoerceName = thFun (fsLit "unsafeTExpCoerce") unsafeTExpCoerceIdKey----------------------- TH.Lib -------------------------- data Lit = ...-charLName, stringLName, integerLName, intPrimLName, wordPrimLName,- floatPrimLName, doublePrimLName, rationalLName :: Name-charLName = libFun (fsLit "charL") charLIdKey-stringLName = libFun (fsLit "stringL") stringLIdKey-integerLName = libFun (fsLit "integerL") integerLIdKey-intPrimLName = libFun (fsLit "intPrimL") intPrimLIdKey-wordPrimLName = libFun (fsLit "wordPrimL") wordPrimLIdKey-floatPrimLName = libFun (fsLit "floatPrimL") floatPrimLIdKey-doublePrimLName = libFun (fsLit "doublePrimL") doublePrimLIdKey-rationalLName = libFun (fsLit "rationalL") rationalLIdKey---- data Pat = ...-litPName, varPName, tupPName, unboxedTupPName, conPName, infixPName, tildePName, bangPName,- asPName, wildPName, recPName, listPName, sigPName, viewPName :: Name-litPName = libFun (fsLit "litP") litPIdKey-varPName = libFun (fsLit "varP") varPIdKey-tupPName = libFun (fsLit "tupP") tupPIdKey-unboxedTupPName = libFun (fsLit "unboxedTupP") unboxedTupPIdKey-conPName = libFun (fsLit "conP") conPIdKey-infixPName = libFun (fsLit "infixP") infixPIdKey-tildePName = libFun (fsLit "tildeP") tildePIdKey-bangPName = libFun (fsLit "bangP") bangPIdKey-asPName = libFun (fsLit "asP") asPIdKey-wildPName = libFun (fsLit "wildP") wildPIdKey-recPName = libFun (fsLit "recP") recPIdKey-listPName = libFun (fsLit "listP") listPIdKey-sigPName = libFun (fsLit "sigP") sigPIdKey-viewPName = libFun (fsLit "viewP") viewPIdKey---- type FieldPat = ...-fieldPatName :: Name-fieldPatName = libFun (fsLit "fieldPat") fieldPatIdKey---- data Match = ...-matchName :: Name-matchName = libFun (fsLit "match") matchIdKey---- data Clause = ...-clauseName :: Name-clauseName = libFun (fsLit "clause") clauseIdKey---- data Exp = ...-varEName, conEName, litEName, appEName, infixEName, infixAppName,- sectionLName, sectionRName, lamEName, lamCaseEName, tupEName,- unboxedTupEName, condEName, multiIfEName, letEName, caseEName,- doEName, compEName :: Name-varEName = libFun (fsLit "varE") varEIdKey-conEName = libFun (fsLit "conE") conEIdKey-litEName = libFun (fsLit "litE") litEIdKey-appEName = libFun (fsLit "appE") appEIdKey-infixEName = libFun (fsLit "infixE") infixEIdKey-infixAppName = libFun (fsLit "infixApp") infixAppIdKey-sectionLName = libFun (fsLit "sectionL") sectionLIdKey-sectionRName = libFun (fsLit "sectionR") sectionRIdKey-lamEName = libFun (fsLit "lamE") lamEIdKey-lamCaseEName = libFun (fsLit "lamCaseE") lamCaseEIdKey-tupEName = libFun (fsLit "tupE") tupEIdKey-unboxedTupEName = libFun (fsLit "unboxedTupE") unboxedTupEIdKey-condEName = libFun (fsLit "condE") condEIdKey-multiIfEName = libFun (fsLit "multiIfE") multiIfEIdKey-letEName = libFun (fsLit "letE") letEIdKey-caseEName = libFun (fsLit "caseE") caseEIdKey-doEName = libFun (fsLit "doE") doEIdKey-compEName = libFun (fsLit "compE") compEIdKey--- ArithSeq skips a level-fromEName, fromThenEName, fromToEName, fromThenToEName :: Name-fromEName = libFun (fsLit "fromE") fromEIdKey-fromThenEName = libFun (fsLit "fromThenE") fromThenEIdKey-fromToEName = libFun (fsLit "fromToE") fromToEIdKey-fromThenToEName = libFun (fsLit "fromThenToE") fromThenToEIdKey--- end ArithSeq-listEName, sigEName, recConEName, recUpdEName :: Name-listEName = libFun (fsLit "listE") listEIdKey-sigEName = libFun (fsLit "sigE") sigEIdKey-recConEName = libFun (fsLit "recConE") recConEIdKey-recUpdEName = libFun (fsLit "recUpdE") recUpdEIdKey---- type FieldExp = ...-fieldExpName :: Name-fieldExpName = libFun (fsLit "fieldExp") fieldExpIdKey---- data Body = ...-guardedBName, normalBName :: Name-guardedBName = libFun (fsLit "guardedB") guardedBIdKey-normalBName = libFun (fsLit "normalB") normalBIdKey---- data Guard = ...-normalGEName, patGEName :: Name-normalGEName = libFun (fsLit "normalGE") normalGEIdKey-patGEName = libFun (fsLit "patGE") patGEIdKey---- data Stmt = ...-bindSName, letSName, noBindSName, parSName :: Name-bindSName = libFun (fsLit "bindS") bindSIdKey-letSName = libFun (fsLit "letS") letSIdKey-noBindSName = libFun (fsLit "noBindS") noBindSIdKey-parSName = libFun (fsLit "parS") parSIdKey---- data Dec = ...-funDName, valDName, dataDName, newtypeDName, tySynDName, classDName,- instanceDName, sigDName, forImpDName, pragInlDName, pragSpecDName,- pragSpecInlDName, pragSpecInstDName, pragRuleDName, familyNoKindDName,- familyKindDName, dataInstDName, newtypeInstDName, tySynInstDName,- closedTypeFamilyKindDName, closedTypeFamilyNoKindDName,- infixLDName, infixRDName, infixNDName, roleAnnotDName :: Name-funDName = libFun (fsLit "funD") funDIdKey-valDName = libFun (fsLit "valD") valDIdKey-dataDName = libFun (fsLit "dataD") dataDIdKey-newtypeDName = libFun (fsLit "newtypeD") newtypeDIdKey-tySynDName = libFun (fsLit "tySynD") tySynDIdKey-classDName = libFun (fsLit "classD") classDIdKey-instanceDName = libFun (fsLit "instanceD") instanceDIdKey-sigDName = libFun (fsLit "sigD") sigDIdKey-forImpDName = libFun (fsLit "forImpD") forImpDIdKey-pragInlDName = libFun (fsLit "pragInlD") pragInlDIdKey-pragSpecDName = libFun (fsLit "pragSpecD") pragSpecDIdKey-pragSpecInlDName = libFun (fsLit "pragSpecInlD") pragSpecInlDIdKey-pragSpecInstDName = libFun (fsLit "pragSpecInstD") pragSpecInstDIdKey-pragRuleDName = libFun (fsLit "pragRuleD") pragRuleDIdKey-familyNoKindDName = libFun (fsLit "familyNoKindD") familyNoKindDIdKey-familyKindDName = libFun (fsLit "familyKindD") familyKindDIdKey-dataInstDName = libFun (fsLit "dataInstD") dataInstDIdKey-newtypeInstDName = libFun (fsLit "newtypeInstD") newtypeInstDIdKey-tySynInstDName = libFun (fsLit "tySynInstD") tySynInstDIdKey-closedTypeFamilyKindDName- = libFun (fsLit "closedTypeFamilyKindD") closedTypeFamilyKindDIdKey-closedTypeFamilyNoKindDName- = libFun (fsLit "closedTypeFamilyNoKindD") closedTypeFamilyNoKindDIdKey-infixLDName = libFun (fsLit "infixLD") infixLDIdKey-infixRDName = libFun (fsLit "infixRD") infixRDIdKey-infixNDName = libFun (fsLit "infixND") infixNDIdKey-roleAnnotDName = libFun (fsLit "roleAnnotD") roleAnnotDIdKey---- type Ctxt = ...-cxtName :: Name-cxtName = libFun (fsLit "cxt") cxtIdKey---- data Pred = ...-classPName, equalPName :: Name-classPName = libFun (fsLit "classP") classPIdKey-equalPName = libFun (fsLit "equalP") equalPIdKey---- data Strict = ...-isStrictName, notStrictName, unpackedName :: Name-isStrictName = libFun (fsLit "isStrict") isStrictKey-notStrictName = libFun (fsLit "notStrict") notStrictKey-unpackedName = libFun (fsLit "unpacked") unpackedKey---- data Con = ...-normalCName, recCName, infixCName, forallCName :: Name-normalCName = libFun (fsLit "normalC") normalCIdKey-recCName = libFun (fsLit "recC") recCIdKey-infixCName = libFun (fsLit "infixC") infixCIdKey-forallCName = libFun (fsLit "forallC") forallCIdKey---- type StrictType = ...-strictTypeName :: Name-strictTypeName = libFun (fsLit "strictType") strictTKey---- type VarStrictType = ...-varStrictTypeName :: Name-varStrictTypeName = libFun (fsLit "varStrictType") varStrictTKey---- data Type = ...-forallTName, varTName, conTName, tupleTName, unboxedTupleTName, arrowTName,- listTName, appTName, sigTName, litTName,- promotedTName, promotedTupleTName,- promotedNilTName, promotedConsTName :: Name-forallTName = libFun (fsLit "forallT") forallTIdKey-varTName = libFun (fsLit "varT") varTIdKey-conTName = libFun (fsLit "conT") conTIdKey-tupleTName = libFun (fsLit "tupleT") tupleTIdKey-unboxedTupleTName = libFun (fsLit "unboxedTupleT") unboxedTupleTIdKey-arrowTName = libFun (fsLit "arrowT") arrowTIdKey-listTName = libFun (fsLit "listT") listTIdKey-appTName = libFun (fsLit "appT") appTIdKey-sigTName = libFun (fsLit "sigT") sigTIdKey-litTName = libFun (fsLit "litT") litTIdKey-promotedTName = libFun (fsLit "promotedT") promotedTIdKey-promotedTupleTName = libFun (fsLit "promotedTupleT") promotedTupleTIdKey-promotedNilTName = libFun (fsLit "promotedNilT") promotedNilTIdKey-promotedConsTName = libFun (fsLit "promotedConsT") promotedConsTIdKey---- data TyLit = ...-numTyLitName, strTyLitName :: Name-numTyLitName = libFun (fsLit "numTyLit") numTyLitIdKey-strTyLitName = libFun (fsLit "strTyLit") strTyLitIdKey---- data TyVarBndr = ...-plainTVName, kindedTVName :: Name-plainTVName = libFun (fsLit "plainTV") plainTVIdKey-kindedTVName = libFun (fsLit "kindedTV") kindedTVIdKey---- data Role = ...-nominalRName, representationalRName, phantomRName, inferRName :: Name-nominalRName = libFun (fsLit "nominalR") nominalRIdKey-representationalRName = libFun (fsLit "representationalR") representationalRIdKey-phantomRName = libFun (fsLit "phantomR") phantomRIdKey-inferRName = libFun (fsLit "inferR") inferRIdKey---- data Kind = ...-varKName, conKName, tupleKName, arrowKName, listKName, appKName,- starKName, constraintKName :: Name-varKName = libFun (fsLit "varK") varKIdKey-conKName = libFun (fsLit "conK") conKIdKey-tupleKName = libFun (fsLit "tupleK") tupleKIdKey-arrowKName = libFun (fsLit "arrowK") arrowKIdKey-listKName = libFun (fsLit "listK") listKIdKey-appKName = libFun (fsLit "appK") appKIdKey-starKName = libFun (fsLit "starK") starKIdKey-constraintKName = libFun (fsLit "constraintK") constraintKIdKey---- data Callconv = ...-cCallName, stdCallName :: Name-cCallName = libFun (fsLit "cCall") cCallIdKey-stdCallName = libFun (fsLit "stdCall") stdCallIdKey---- data Safety = ...-unsafeName, safeName, interruptibleName :: Name-unsafeName = libFun (fsLit "unsafe") unsafeIdKey-safeName = libFun (fsLit "safe") safeIdKey-interruptibleName = libFun (fsLit "interruptible") interruptibleIdKey---- data Inline = ...-noInlineDataConName, inlineDataConName, inlinableDataConName :: Name-noInlineDataConName = thCon (fsLit "NoInline") noInlineDataConKey-inlineDataConName = thCon (fsLit "Inline") inlineDataConKey-inlinableDataConName = thCon (fsLit "Inlinable") inlinableDataConKey---- data RuleMatch = ...-conLikeDataConName, funLikeDataConName :: Name-conLikeDataConName = thCon (fsLit "ConLike") conLikeDataConKey-funLikeDataConName = thCon (fsLit "FunLike") funLikeDataConKey---- data Phases = ...-allPhasesDataConName, fromPhaseDataConName, beforePhaseDataConName :: Name-allPhasesDataConName = thCon (fsLit "AllPhases") allPhasesDataConKey-fromPhaseDataConName = thCon (fsLit "FromPhase") fromPhaseDataConKey-beforePhaseDataConName = thCon (fsLit "BeforePhase") beforePhaseDataConKey---- newtype TExp a = ...-tExpDataConName :: Name-tExpDataConName = thCon (fsLit "TExp") tExpDataConKey---- data RuleBndr = ...-ruleVarName, typedRuleVarName :: Name-ruleVarName = libFun (fsLit ("ruleVar")) ruleVarIdKey-typedRuleVarName = libFun (fsLit ("typedRuleVar")) typedRuleVarIdKey---- data FunDep = ...-funDepName :: Name-funDepName = libFun (fsLit "funDep") funDepIdKey---- data FamFlavour = ...-typeFamName, dataFamName :: Name-typeFamName = libFun (fsLit "typeFam") typeFamIdKey-dataFamName = libFun (fsLit "dataFam") dataFamIdKey---- data TySynEqn = ...-tySynEqnName :: Name-tySynEqnName = libFun (fsLit "tySynEqn") tySynEqnIdKey--matchQTyConName, clauseQTyConName, expQTyConName, stmtQTyConName,- decQTyConName, conQTyConName, strictTypeQTyConName,- varStrictTypeQTyConName, typeQTyConName, fieldExpQTyConName,- patQTyConName, fieldPatQTyConName, predQTyConName, decsQTyConName,- ruleBndrQTyConName, tySynEqnQTyConName, roleTyConName :: Name-matchQTyConName = libTc (fsLit "MatchQ") matchQTyConKey-clauseQTyConName = libTc (fsLit "ClauseQ") clauseQTyConKey-expQTyConName = libTc (fsLit "ExpQ") expQTyConKey-stmtQTyConName = libTc (fsLit "StmtQ") stmtQTyConKey-decQTyConName = libTc (fsLit "DecQ") decQTyConKey-decsQTyConName = libTc (fsLit "DecsQ") decsQTyConKey -- Q [Dec]-conQTyConName = libTc (fsLit "ConQ") conQTyConKey-strictTypeQTyConName = libTc (fsLit "StrictTypeQ") strictTypeQTyConKey-varStrictTypeQTyConName = libTc (fsLit "VarStrictTypeQ") varStrictTypeQTyConKey-typeQTyConName = libTc (fsLit "TypeQ") typeQTyConKey-fieldExpQTyConName = libTc (fsLit "FieldExpQ") fieldExpQTyConKey-patQTyConName = libTc (fsLit "PatQ") patQTyConKey-fieldPatQTyConName = libTc (fsLit "FieldPatQ") fieldPatQTyConKey-predQTyConName = libTc (fsLit "PredQ") predQTyConKey-ruleBndrQTyConName = libTc (fsLit "RuleBndrQ") ruleBndrQTyConKey-tySynEqnQTyConName = libTc (fsLit "TySynEqnQ") tySynEqnQTyConKey-roleTyConName = libTc (fsLit "Role") roleTyConKey---- quasiquoting-quoteExpName, quotePatName, quoteDecName, quoteTypeName :: Name-quoteExpName = qqFun (fsLit "quoteExp") quoteExpKey-quotePatName = qqFun (fsLit "quotePat") quotePatKey-quoteDecName = qqFun (fsLit "quoteDec") quoteDecKey-quoteTypeName = qqFun (fsLit "quoteType") quoteTypeKey---- TyConUniques available: 200-299--- Check in PrelNames if you want to change this--expTyConKey, matchTyConKey, clauseTyConKey, qTyConKey, expQTyConKey,- decQTyConKey, patTyConKey, matchQTyConKey, clauseQTyConKey,- stmtQTyConKey, conQTyConKey, typeQTyConKey, typeTyConKey, tyVarBndrTyConKey,- decTyConKey, varStrictTypeQTyConKey, strictTypeQTyConKey,- fieldExpTyConKey, fieldPatTyConKey, nameTyConKey, patQTyConKey,- fieldPatQTyConKey, fieldExpQTyConKey, funDepTyConKey, predTyConKey,- predQTyConKey, decsQTyConKey, ruleBndrQTyConKey, tySynEqnQTyConKey,- roleTyConKey, tExpTyConKey :: Unique-expTyConKey = mkPreludeTyConUnique 200-matchTyConKey = mkPreludeTyConUnique 201-clauseTyConKey = mkPreludeTyConUnique 202-qTyConKey = mkPreludeTyConUnique 203-expQTyConKey = mkPreludeTyConUnique 204-decQTyConKey = mkPreludeTyConUnique 205-patTyConKey = mkPreludeTyConUnique 206-matchQTyConKey = mkPreludeTyConUnique 207-clauseQTyConKey = mkPreludeTyConUnique 208-stmtQTyConKey = mkPreludeTyConUnique 209-conQTyConKey = mkPreludeTyConUnique 210-typeQTyConKey = mkPreludeTyConUnique 211-typeTyConKey = mkPreludeTyConUnique 212-decTyConKey = mkPreludeTyConUnique 213-varStrictTypeQTyConKey = mkPreludeTyConUnique 214-strictTypeQTyConKey = mkPreludeTyConUnique 215-fieldExpTyConKey = mkPreludeTyConUnique 216-fieldPatTyConKey = mkPreludeTyConUnique 217-nameTyConKey = mkPreludeTyConUnique 218-patQTyConKey = mkPreludeTyConUnique 219-fieldPatQTyConKey = mkPreludeTyConUnique 220-fieldExpQTyConKey = mkPreludeTyConUnique 221-funDepTyConKey = mkPreludeTyConUnique 222-predTyConKey = mkPreludeTyConUnique 223-predQTyConKey = mkPreludeTyConUnique 224-tyVarBndrTyConKey = mkPreludeTyConUnique 225-decsQTyConKey = mkPreludeTyConUnique 226-ruleBndrQTyConKey = mkPreludeTyConUnique 227-tySynEqnQTyConKey = mkPreludeTyConUnique 228-roleTyConKey = mkPreludeTyConUnique 229-tExpTyConKey = mkPreludeTyConUnique 230---- IdUniques available: 200-499--- If you want to change this, make sure you check in PrelNames--returnQIdKey, bindQIdKey, sequenceQIdKey, liftIdKey, newNameIdKey,- mkNameIdKey, mkNameG_vIdKey, mkNameG_dIdKey, mkNameG_tcIdKey,- mkNameLIdKey, unTypeIdKey, unTypeQIdKey, unsafeTExpCoerceIdKey :: Unique-returnQIdKey = mkPreludeMiscIdUnique 200-bindQIdKey = mkPreludeMiscIdUnique 201-sequenceQIdKey = mkPreludeMiscIdUnique 202-liftIdKey = mkPreludeMiscIdUnique 203-newNameIdKey = mkPreludeMiscIdUnique 204-mkNameIdKey = mkPreludeMiscIdUnique 205-mkNameG_vIdKey = mkPreludeMiscIdUnique 206-mkNameG_dIdKey = mkPreludeMiscIdUnique 207-mkNameG_tcIdKey = mkPreludeMiscIdUnique 208-mkNameLIdKey = mkPreludeMiscIdUnique 209-unTypeIdKey = mkPreludeMiscIdUnique 210-unTypeQIdKey = mkPreludeMiscIdUnique 211-unsafeTExpCoerceIdKey = mkPreludeMiscIdUnique 212----- data Lit = ...-charLIdKey, stringLIdKey, integerLIdKey, intPrimLIdKey, wordPrimLIdKey,- floatPrimLIdKey, doublePrimLIdKey, rationalLIdKey :: Unique-charLIdKey = mkPreludeMiscIdUnique 220-stringLIdKey = mkPreludeMiscIdUnique 221-integerLIdKey = mkPreludeMiscIdUnique 222-intPrimLIdKey = mkPreludeMiscIdUnique 223-wordPrimLIdKey = mkPreludeMiscIdUnique 224-floatPrimLIdKey = mkPreludeMiscIdUnique 225-doublePrimLIdKey = mkPreludeMiscIdUnique 226-rationalLIdKey = mkPreludeMiscIdUnique 227--liftStringIdKey :: Unique-liftStringIdKey = mkPreludeMiscIdUnique 228---- data Pat = ...-litPIdKey, varPIdKey, tupPIdKey, unboxedTupPIdKey, conPIdKey, infixPIdKey, tildePIdKey, bangPIdKey,- asPIdKey, wildPIdKey, recPIdKey, listPIdKey, sigPIdKey, viewPIdKey :: Unique-litPIdKey = mkPreludeMiscIdUnique 240-varPIdKey = mkPreludeMiscIdUnique 241-tupPIdKey = mkPreludeMiscIdUnique 242-unboxedTupPIdKey = mkPreludeMiscIdUnique 243-conPIdKey = mkPreludeMiscIdUnique 244-infixPIdKey = mkPreludeMiscIdUnique 245-tildePIdKey = mkPreludeMiscIdUnique 246-bangPIdKey = mkPreludeMiscIdUnique 247-asPIdKey = mkPreludeMiscIdUnique 248-wildPIdKey = mkPreludeMiscIdUnique 249-recPIdKey = mkPreludeMiscIdUnique 250-listPIdKey = mkPreludeMiscIdUnique 251-sigPIdKey = mkPreludeMiscIdUnique 252-viewPIdKey = mkPreludeMiscIdUnique 253---- type FieldPat = ...-fieldPatIdKey :: Unique-fieldPatIdKey = mkPreludeMiscIdUnique 260---- data Match = ...-matchIdKey :: Unique-matchIdKey = mkPreludeMiscIdUnique 261---- data Clause = ...-clauseIdKey :: Unique-clauseIdKey = mkPreludeMiscIdUnique 262----- data Exp = ...-varEIdKey, conEIdKey, litEIdKey, appEIdKey, infixEIdKey, infixAppIdKey,- sectionLIdKey, sectionRIdKey, lamEIdKey, lamCaseEIdKey, tupEIdKey,- unboxedTupEIdKey, condEIdKey, multiIfEIdKey,- letEIdKey, caseEIdKey, doEIdKey, compEIdKey,- fromEIdKey, fromThenEIdKey, fromToEIdKey, fromThenToEIdKey,- listEIdKey, sigEIdKey, recConEIdKey, recUpdEIdKey :: Unique-varEIdKey = mkPreludeMiscIdUnique 270-conEIdKey = mkPreludeMiscIdUnique 271-litEIdKey = mkPreludeMiscIdUnique 272-appEIdKey = mkPreludeMiscIdUnique 273-infixEIdKey = mkPreludeMiscIdUnique 274-infixAppIdKey = mkPreludeMiscIdUnique 275-sectionLIdKey = mkPreludeMiscIdUnique 276-sectionRIdKey = mkPreludeMiscIdUnique 277-lamEIdKey = mkPreludeMiscIdUnique 278-lamCaseEIdKey = mkPreludeMiscIdUnique 279-tupEIdKey = mkPreludeMiscIdUnique 280-unboxedTupEIdKey = mkPreludeMiscIdUnique 281-condEIdKey = mkPreludeMiscIdUnique 282-multiIfEIdKey = mkPreludeMiscIdUnique 283-letEIdKey = mkPreludeMiscIdUnique 284-caseEIdKey = mkPreludeMiscIdUnique 285-doEIdKey = mkPreludeMiscIdUnique 286-compEIdKey = mkPreludeMiscIdUnique 287-fromEIdKey = mkPreludeMiscIdUnique 288-fromThenEIdKey = mkPreludeMiscIdUnique 289-fromToEIdKey = mkPreludeMiscIdUnique 290-fromThenToEIdKey = mkPreludeMiscIdUnique 291-listEIdKey = mkPreludeMiscIdUnique 292-sigEIdKey = mkPreludeMiscIdUnique 293-recConEIdKey = mkPreludeMiscIdUnique 294-recUpdEIdKey = mkPreludeMiscIdUnique 295---- type FieldExp = ...-fieldExpIdKey :: Unique-fieldExpIdKey = mkPreludeMiscIdUnique 310---- data Body = ...-guardedBIdKey, normalBIdKey :: Unique-guardedBIdKey = mkPreludeMiscIdUnique 311-normalBIdKey = mkPreludeMiscIdUnique 312---- data Guard = ...-normalGEIdKey, patGEIdKey :: Unique-normalGEIdKey = mkPreludeMiscIdUnique 313-patGEIdKey = mkPreludeMiscIdUnique 314---- data Stmt = ...-bindSIdKey, letSIdKey, noBindSIdKey, parSIdKey :: Unique-bindSIdKey = mkPreludeMiscIdUnique 320-letSIdKey = mkPreludeMiscIdUnique 321-noBindSIdKey = mkPreludeMiscIdUnique 322-parSIdKey = mkPreludeMiscIdUnique 323---- data Dec = ...-funDIdKey, valDIdKey, dataDIdKey, newtypeDIdKey, tySynDIdKey,- classDIdKey, instanceDIdKey, sigDIdKey, forImpDIdKey, pragInlDIdKey,- pragSpecDIdKey, pragSpecInlDIdKey, pragSpecInstDIdKey, pragRuleDIdKey,- familyNoKindDIdKey, familyKindDIdKey,- dataInstDIdKey, newtypeInstDIdKey, tySynInstDIdKey,- closedTypeFamilyKindDIdKey, closedTypeFamilyNoKindDIdKey,- infixLDIdKey, infixRDIdKey, infixNDIdKey, roleAnnotDIdKey :: Unique-funDIdKey = mkPreludeMiscIdUnique 330-valDIdKey = mkPreludeMiscIdUnique 331-dataDIdKey = mkPreludeMiscIdUnique 332-newtypeDIdKey = mkPreludeMiscIdUnique 333-tySynDIdKey = mkPreludeMiscIdUnique 334-classDIdKey = mkPreludeMiscIdUnique 335-instanceDIdKey = mkPreludeMiscIdUnique 336-sigDIdKey = mkPreludeMiscIdUnique 337-forImpDIdKey = mkPreludeMiscIdUnique 338-pragInlDIdKey = mkPreludeMiscIdUnique 339-pragSpecDIdKey = mkPreludeMiscIdUnique 340-pragSpecInlDIdKey = mkPreludeMiscIdUnique 341-pragSpecInstDIdKey = mkPreludeMiscIdUnique 417-pragRuleDIdKey = mkPreludeMiscIdUnique 418-familyNoKindDIdKey = mkPreludeMiscIdUnique 342-familyKindDIdKey = mkPreludeMiscIdUnique 343-dataInstDIdKey = mkPreludeMiscIdUnique 344-newtypeInstDIdKey = mkPreludeMiscIdUnique 345-tySynInstDIdKey = mkPreludeMiscIdUnique 346-closedTypeFamilyKindDIdKey = mkPreludeMiscIdUnique 347-closedTypeFamilyNoKindDIdKey = mkPreludeMiscIdUnique 348-infixLDIdKey = mkPreludeMiscIdUnique 349-infixRDIdKey = mkPreludeMiscIdUnique 350-infixNDIdKey = mkPreludeMiscIdUnique 351-roleAnnotDIdKey = mkPreludeMiscIdUnique 352---- type Cxt = ...-cxtIdKey :: Unique-cxtIdKey = mkPreludeMiscIdUnique 360---- data Pred = ...-classPIdKey, equalPIdKey :: Unique-classPIdKey = mkPreludeMiscIdUnique 361-equalPIdKey = mkPreludeMiscIdUnique 362---- data Strict = ...-isStrictKey, notStrictKey, unpackedKey :: Unique-isStrictKey = mkPreludeMiscIdUnique 363-notStrictKey = mkPreludeMiscIdUnique 364-unpackedKey = mkPreludeMiscIdUnique 365---- data Con = ...-normalCIdKey, recCIdKey, infixCIdKey, forallCIdKey :: Unique-normalCIdKey = mkPreludeMiscIdUnique 370-recCIdKey = mkPreludeMiscIdUnique 371-infixCIdKey = mkPreludeMiscIdUnique 372-forallCIdKey = mkPreludeMiscIdUnique 373---- type StrictType = ...-strictTKey :: Unique-strictTKey = mkPreludeMiscIdUnique 374---- type VarStrictType = ...-varStrictTKey :: Unique-varStrictTKey = mkPreludeMiscIdUnique 375---- data Type = ...-forallTIdKey, varTIdKey, conTIdKey, tupleTIdKey, unboxedTupleTIdKey, arrowTIdKey,- listTIdKey, appTIdKey, sigTIdKey, litTIdKey,- promotedTIdKey, promotedTupleTIdKey,- promotedNilTIdKey, promotedConsTIdKey :: Unique-forallTIdKey = mkPreludeMiscIdUnique 380-varTIdKey = mkPreludeMiscIdUnique 381-conTIdKey = mkPreludeMiscIdUnique 382-tupleTIdKey = mkPreludeMiscIdUnique 383-unboxedTupleTIdKey = mkPreludeMiscIdUnique 384-arrowTIdKey = mkPreludeMiscIdUnique 385-listTIdKey = mkPreludeMiscIdUnique 386-appTIdKey = mkPreludeMiscIdUnique 387-sigTIdKey = mkPreludeMiscIdUnique 388-litTIdKey = mkPreludeMiscIdUnique 389-promotedTIdKey = mkPreludeMiscIdUnique 390-promotedTupleTIdKey = mkPreludeMiscIdUnique 391-promotedNilTIdKey = mkPreludeMiscIdUnique 392-promotedConsTIdKey = mkPreludeMiscIdUnique 393---- data TyLit = ...-numTyLitIdKey, strTyLitIdKey :: Unique-numTyLitIdKey = mkPreludeMiscIdUnique 394-strTyLitIdKey = mkPreludeMiscIdUnique 395---- data TyVarBndr = ...-plainTVIdKey, kindedTVIdKey :: Unique-plainTVIdKey = mkPreludeMiscIdUnique 396-kindedTVIdKey = mkPreludeMiscIdUnique 397---- data Role = ...-nominalRIdKey, representationalRIdKey, phantomRIdKey, inferRIdKey :: Unique-nominalRIdKey = mkPreludeMiscIdUnique 400-representationalRIdKey = mkPreludeMiscIdUnique 401-phantomRIdKey = mkPreludeMiscIdUnique 402-inferRIdKey = mkPreludeMiscIdUnique 403---- data Kind = ...-varKIdKey, conKIdKey, tupleKIdKey, arrowKIdKey, listKIdKey, appKIdKey,- starKIdKey, constraintKIdKey :: Unique-varKIdKey = mkPreludeMiscIdUnique 404-conKIdKey = mkPreludeMiscIdUnique 405-tupleKIdKey = mkPreludeMiscIdUnique 406-arrowKIdKey = mkPreludeMiscIdUnique 407-listKIdKey = mkPreludeMiscIdUnique 408-appKIdKey = mkPreludeMiscIdUnique 409-starKIdKey = mkPreludeMiscIdUnique 410-constraintKIdKey = mkPreludeMiscIdUnique 411---- data Callconv = ...-cCallIdKey, stdCallIdKey :: Unique-cCallIdKey = mkPreludeMiscIdUnique 412-stdCallIdKey = mkPreludeMiscIdUnique 413---- data Safety = ...-unsafeIdKey, safeIdKey, interruptibleIdKey :: Unique-unsafeIdKey = mkPreludeMiscIdUnique 414-safeIdKey = mkPreludeMiscIdUnique 415-interruptibleIdKey = mkPreludeMiscIdUnique 416---- data Inline = ...-noInlineDataConKey, inlineDataConKey, inlinableDataConKey :: Unique-noInlineDataConKey = mkPreludeDataConUnique 40-inlineDataConKey = mkPreludeDataConUnique 41-inlinableDataConKey = mkPreludeDataConUnique 42---- data RuleMatch = ...-conLikeDataConKey, funLikeDataConKey :: Unique-conLikeDataConKey = mkPreludeDataConUnique 43-funLikeDataConKey = mkPreludeDataConUnique 44---- data Phases = ...-allPhasesDataConKey, fromPhaseDataConKey, beforePhaseDataConKey :: Unique-allPhasesDataConKey = mkPreludeDataConUnique 45-fromPhaseDataConKey = mkPreludeDataConUnique 46-beforePhaseDataConKey = mkPreludeDataConUnique 47---- newtype TExp a = ...-tExpDataConKey :: Unique-tExpDataConKey = mkPreludeDataConUnique 48---- data FunDep = ...-funDepIdKey :: Unique-funDepIdKey = mkPreludeMiscIdUnique 419---- data FamFlavour = ...-typeFamIdKey, dataFamIdKey :: Unique-typeFamIdKey = mkPreludeMiscIdUnique 420-dataFamIdKey = mkPreludeMiscIdUnique 421---- data TySynEqn = ...-tySynEqnIdKey :: Unique-tySynEqnIdKey = mkPreludeMiscIdUnique 422---- quasiquoting-quoteExpKey, quotePatKey, quoteDecKey, quoteTypeKey :: Unique-quoteExpKey = mkPreludeMiscIdUnique 423-quotePatKey = mkPreludeMiscIdUnique 424-quoteDecKey = mkPreludeMiscIdUnique 425-quoteTypeKey = mkPreludeMiscIdUnique 426---- data RuleBndr = ...-ruleVarIdKey, typedRuleVarIdKey :: Unique-ruleVarIdKey = mkPreludeMiscIdUnique 427-typedRuleVarIdKey = mkPreludeMiscIdUnique 428
− src/Language/Haskell/Liquid/Desugar/DsUtils.lhs
@@ -1,835 +0,0 @@-%-% (c) The University of Glasgow 2006-% (c) The GRASP/AQUA Project, Glasgow University, 1992-1998-%--Utilities for desugaring--This module exports some utility functions of no great interest.--\begin{code}-{-# OPTIONS -fno-warn-tabs #-}--- The above warning supression flag is a temporary kludge.--- While working on this module you are encouraged to remove it and--- detab the module (please do the detabbing in a separate patch). See--- http://ghc.haskell.org/trac/ghc/wiki/Commentary/CodingStyle#TabsvsSpaces--- for details---- | Utility functions for constructing Core syntax, principally for desugaring-module Language.Haskell.Liquid.Desugar.DsUtils (- EquationInfo(..), - firstPat, shiftEqns,-- MatchResult(..), CanItFail(..), CaseAlt(..),- cantFailMatchResult, alwaysFailMatchResult,- extractMatchResult, combineMatchResults, - adjustMatchResult, adjustMatchResultDs,- mkCoLetMatchResult, mkViewMatchResult, mkGuardedMatchResult, - matchCanFail, mkEvalMatchResult,- mkCoPrimCaseMatchResult, mkCoAlgCaseMatchResult, mkCoSynCaseMatchResult,- wrapBind, wrapBinds,-- mkErrorAppDs, mkCoreAppDs, mkCoreAppsDs,-- seqVar,-- -- LHs tuples- mkLHsVarPatTup, mkLHsPatTup, mkVanillaTuplePat,- mkBigLHsVarTup, mkBigLHsTup, mkBigLHsVarPatTup, mkBigLHsPatTup,-- mkSelectorBinds,-- selectSimpleMatchVarL, selectMatchVars, selectMatchVar,- mkOptTickBox, mkBinaryTickBox- ) where---- #include "HsVersions.h"--import {-# SOURCE #-} Language.Haskell.Liquid.Desugar.Match ( matchSimply )--import HsSyn-import TcHsSyn-import TcType( tcSplitTyConApp )-import CoreSyn-import DsMonad-import {-# SOURCE #-} Language.Haskell.Liquid.Desugar.DsExpr ( dsLExpr )--import CoreUtils-import MkCore-import MkId-import Id-import Literal-import TyCon-import ConLike-import DataCon-import PatSyn-import Type-import Coercion-import TysPrim-import TysWiredIn-import BasicTypes-import UniqSet-import UniqSupply-import Module-import PrelNames-import Outputable-import SrcLoc-import Util-import DynFlags-import FastString--import TcEvidence--import Control.Monad ( zipWithM )-\end{code}---%************************************************************************-%* *-\subsection{ Selecting match variables}-%* *-%************************************************************************--We're about to match against some patterns. We want to make some-@Ids@ to use as match variables. If a pattern has an @Id@ readily at-hand, which should indeed be bound to the pattern as a whole, then use it;-otherwise, make one up.--\begin{code}-selectSimpleMatchVarL :: LPat Id -> DsM Id-selectSimpleMatchVarL pat = selectMatchVar (unLoc pat)---- (selectMatchVars ps tys) chooses variables of type tys--- to use for matching ps against. If the pattern is a variable,--- we try to use that, to save inventing lots of fresh variables.------ OLD, but interesting note:--- But even if it is a variable, its type might not match. Consider--- data T a where--- T1 :: Int -> T Int--- T2 :: a -> T a------ f :: T a -> a -> Int--- f (T1 i) (x::Int) = x--- f (T2 i) (y::a) = 0--- Then we must not choose (x::Int) as the matching variable!--- And nowadays we won't, because the (x::Int) will be wrapped in a CoPat--selectMatchVars :: [Pat Id] -> DsM [Id]-selectMatchVars ps = mapM selectMatchVar ps--selectMatchVar :: Pat Id -> DsM Id-selectMatchVar (BangPat pat) = selectMatchVar (unLoc pat)-selectMatchVar (LazyPat pat) = selectMatchVar (unLoc pat)-selectMatchVar (ParPat pat) = selectMatchVar (unLoc pat)-selectMatchVar (VarPat var) = return (localiseId var) -- Note [Localise pattern binders]-selectMatchVar (AsPat var _) = return (unLoc var)-selectMatchVar other_pat = newSysLocalDs (hsPatType other_pat)- -- OK, better make up one...-\end{code}--Note [Localise pattern binders]-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~-Consider module M where- [Just a] = e-After renaming it looks like- module M where- [Just M.a] = e--We don't generalise, since it's a pattern binding, monomorphic, etc,-so after desugaring we may get something like- M.a = case e of (v:_) ->- case v of Just M.a -> M.a-Notice the "M.a" in the pattern; after all, it was in the original-pattern. However, after optimisation those pattern binders can become-let-binders, and then end up floated to top level. They have a-different *unique* by then (the simplifier is good about maintaining-proper scoping), but it's BAD to have two top-level bindings with the-External Name M.a, because that turns into two linker symbols for M.a.-It's quite rare for this to actually *happen* -- the only case I know-of is tc003 compiled with the 'hpc' way -- but that only makes it -all the more annoying.--To avoid this, we craftily call 'localiseId' in the desugarer, which-simply turns the External Name for the Id into an Internal one, but-doesn't change the unique. So the desugarer produces this:- M.a{r8} = case e of (v:_) ->- case v of Just a{r8} -> M.a{r8}-The unique is still 'r8', but the binding site in the pattern-is now an Internal Name. Now the simplifier's usual mechanisms-will propagate that Name to all the occurrence sites, as well as-un-shadowing it, so we'll get- M.a{r8} = case e of (v:_) ->- case v of Just a{s77} -> a{s77}-In fact, even CoreSubst.simplOptExpr will do this, and simpleOptExpr-runs on the output of the desugarer, so all is well by the end of-the desugaring pass.---%************************************************************************-%* *-%* type synonym EquationInfo and access functions for its pieces *-%* *-%************************************************************************-\subsection[EquationInfo-synonym]{@EquationInfo@: a useful synonym}--The ``equation info'' used by @match@ is relatively complicated and-worthy of a type synonym and a few handy functions.--\begin{code}-firstPat :: EquationInfo -> Pat Id-firstPat eqn = {- ASSERT( notNull (eqn_pats eqn) ) -} head (eqn_pats eqn)--shiftEqns :: [EquationInfo] -> [EquationInfo]--- Drop the first pattern in each equation-shiftEqns eqns = [ eqn { eqn_pats = tail (eqn_pats eqn) } | eqn <- eqns ]-\end{code}--Functions on MatchResults--\begin{code}-matchCanFail :: MatchResult -> Bool-matchCanFail (MatchResult CanFail _) = True-matchCanFail (MatchResult CantFail _) = False--alwaysFailMatchResult :: MatchResult-alwaysFailMatchResult = MatchResult CanFail (\fail -> return fail)--cantFailMatchResult :: CoreExpr -> MatchResult-cantFailMatchResult expr = MatchResult CantFail (\_ -> return expr)--extractMatchResult :: MatchResult -> CoreExpr -> DsM CoreExpr-extractMatchResult (MatchResult CantFail match_fn) _- = match_fn (error "It can't fail!")--extractMatchResult (MatchResult CanFail match_fn) fail_expr = do- (fail_bind, if_it_fails) <- mkFailurePair fail_expr- body <- match_fn if_it_fails- return (mkCoreLet fail_bind body)---combineMatchResults :: MatchResult -> MatchResult -> MatchResult-combineMatchResults (MatchResult CanFail body_fn1)- (MatchResult can_it_fail2 body_fn2)- = MatchResult can_it_fail2 body_fn- where- body_fn fail = do body2 <- body_fn2 fail- (fail_bind, duplicatable_expr) <- mkFailurePair body2- body1 <- body_fn1 duplicatable_expr- return (Let fail_bind body1)--combineMatchResults match_result1@(MatchResult CantFail _) _- = match_result1--adjustMatchResult :: DsWrapper -> MatchResult -> MatchResult-adjustMatchResult encl_fn (MatchResult can_it_fail body_fn)- = MatchResult can_it_fail (\fail -> encl_fn <$> body_fn fail)--adjustMatchResultDs :: (CoreExpr -> DsM CoreExpr) -> MatchResult -> MatchResult-adjustMatchResultDs encl_fn (MatchResult can_it_fail body_fn)- = MatchResult can_it_fail (\fail -> encl_fn =<< body_fn fail)--wrapBinds :: [(Var,Var)] -> CoreExpr -> CoreExpr-wrapBinds [] e = e-wrapBinds ((new,old):prs) e = wrapBind new old (wrapBinds prs e)--wrapBind :: Var -> Var -> CoreExpr -> CoreExpr-wrapBind new old body -- NB: this function must deal with term- | new==old = body -- variables, type variables or coercion variables- | otherwise = Let (NonRec new (varToCoreExpr old)) body--seqVar :: Var -> CoreExpr -> CoreExpr-seqVar var body = Case (Var var) var (exprType body)- [(DEFAULT, [], body)]--mkCoLetMatchResult :: CoreBind -> MatchResult -> MatchResult-mkCoLetMatchResult bind = adjustMatchResult (mkCoreLet bind)---- (mkViewMatchResult var' viewExpr var mr) makes the expression--- let var' = viewExpr var in mr-mkViewMatchResult :: Id -> CoreExpr -> Id -> MatchResult -> MatchResult-mkViewMatchResult var' viewExpr var = - adjustMatchResult (mkCoreLet (NonRec var' (mkCoreAppDs viewExpr (Var var))))--mkEvalMatchResult :: Id -> Type -> MatchResult -> MatchResult-mkEvalMatchResult var ty- = adjustMatchResult (\e -> Case (Var var) var ty [(DEFAULT, [], e)]) --mkGuardedMatchResult :: CoreExpr -> MatchResult -> MatchResult-mkGuardedMatchResult pred_expr (MatchResult _ body_fn)- = MatchResult CanFail (\fail -> do body <- body_fn fail- return (mkIfThenElse pred_expr body fail))--mkCoPrimCaseMatchResult :: Id -- Scrutinee- -> Type -- Type of the case- -> [(Literal, MatchResult)] -- Alternatives- -> MatchResult -- Literals are all unlifted-mkCoPrimCaseMatchResult var ty match_alts- = MatchResult CanFail mk_case- where- mk_case fail = do- alts <- mapM (mk_alt fail) sorted_alts- return (Case (Var var) var ty ((DEFAULT, [], fail) : alts))-- sorted_alts = sortWith fst match_alts -- Right order for a Case- mk_alt fail (lit, MatchResult _ body_fn)- = -- ASSERT( not (litIsLifted lit) )- do body <- body_fn fail- return (LitAlt lit, [], body)--data CaseAlt a = MkCaseAlt{ alt_pat :: a,- alt_bndrs :: [CoreBndr],- alt_wrapper :: HsWrapper,- alt_result :: MatchResult }--mkCoAlgCaseMatchResult - :: DynFlags- -> Id -- Scrutinee- -> Type -- Type of exp- -> [CaseAlt DataCon] -- Alternatives (bndrs *include* tyvars, dicts)- -> MatchResult-mkCoAlgCaseMatchResult dflags var ty match_alts - | isNewtype -- Newtype case; use a let- = -- ASSERT( null (tail match_alts) && null (tail arg_ids1) )- mkCoLetMatchResult (NonRec arg_id1 newtype_rhs) match_result1-- | isPArrFakeAlts match_alts- = MatchResult CanFail $ mkPArrCase dflags var ty (sort_alts match_alts)- | otherwise- = mkDataConCase var ty match_alts- where- isNewtype = isNewTyCon (dataConTyCon (alt_pat alt1))-- -- [Interesting: because of GADTs, we can't rely on the type of - -- the scrutinised Id to be sufficiently refined to have a TyCon in it]-- alt1@MkCaseAlt{ alt_bndrs = arg_ids1, alt_result = match_result1 }- = {- ASSERT( notNull match_alts ) -} head match_alts- -- Stuff for newtype- arg_id1 = {- ASSERT( notNull arg_ids1 ) -} head arg_ids1- var_ty = idType var- (tc, ty_args) = tcSplitTyConApp var_ty -- Don't look through newtypes- -- (not that splitTyConApp does, these days)- newtype_rhs = unwrapNewTypeBody tc ty_args (Var var)-- --- Stuff for parallel arrays- --- -- Concerning `isPArrFakeAlts':- --- -- * it is *not* sufficient to just check the type of the type- -- constructor, as we have to be careful not to confuse the real- -- representation of parallel arrays with the fake constructors;- -- moreover, a list of alternatives must not mix fake and real- -- constructors (this is checked earlier on)- --- -- FIXME: We actually go through the whole list and make sure that- -- either all or none of the constructors are fake parallel- -- array constructors. This is to spot equations that mix fake- -- constructors with the real representation defined in- -- `PrelPArr'. It would be nicer to spot this situation- -- earlier and raise a proper error message, but it can really- -- only happen in `PrelPArr' anyway.- ---- isPArrFakeAlts :: [CaseAlt DataCon] -> Bool- isPArrFakeAlts [alt] = isPArrFakeCon (alt_pat alt)- isPArrFakeAlts (alt:alts) =- case (isPArrFakeCon (alt_pat alt), isPArrFakeAlts alts) of- (True , True ) -> True- (False, False) -> False- _ -> panic "DsUtils: you may not mix `[:...:]' with `PArr' patterns"- isPArrFakeAlts [] = panic "DsUtils: unexpectedly found an empty list of PArr fake alternatives"--mkCoSynCaseMatchResult :: Id -> Type -> CaseAlt PatSyn -> MatchResult-mkCoSynCaseMatchResult var ty alt = MatchResult CanFail $ mkPatSynCase var ty alt--\end{code}--\begin{code}-sort_alts :: [CaseAlt DataCon] -> [CaseAlt DataCon]-sort_alts = sortWith (dataConTag . alt_pat)--mkPatSynCase :: Id -> Type -> CaseAlt PatSyn -> CoreExpr -> DsM CoreExpr-mkPatSynCase var ty alt fail = do- matcher <- dsLExpr $ mkLHsWrap wrapper $ nlHsTyApp matcher [ty]- let MatchResult _ mkCont = match_result- cont <- mkCoreLams bndrs <$> mkCont fail- return $ mkCoreAppsDs matcher [Var var, cont, fail]- where- MkCaseAlt{ alt_pat = psyn,- alt_bndrs = bndrs,- alt_wrapper = wrapper,- alt_result = match_result} = alt- matcher = patSynMatcher psyn--mkDataConCase :: Id -> Type -> [CaseAlt DataCon] -> MatchResult-mkDataConCase _ _ [] = panic "mkDataConCase: no alternatives"-mkDataConCase var ty alts@(alt1:_) = MatchResult fail_flag mk_case- where- con1 = alt_pat alt1- tycon = dataConTyCon con1- data_cons = tyConDataCons tycon- match_results = map alt_result alts-- sorted_alts :: [CaseAlt DataCon]- sorted_alts = sort_alts alts-- var_ty = idType var- (_, ty_args) = tcSplitTyConApp var_ty -- Don't look through newtypes- -- (not that splitTyConApp does, these days)-- mk_case :: CoreExpr -> DsM CoreExpr- mk_case fail = do- alts <- mapM (mk_alt fail) sorted_alts- return $ mkWildCase (Var var) (idType var) ty (mk_default fail ++ alts)-- mk_alt :: CoreExpr -> CaseAlt DataCon -> DsM CoreAlt- mk_alt fail MkCaseAlt{ alt_pat = con,- alt_bndrs = args,- alt_result = MatchResult _ body_fn }- = do { body <- body_fn fail- ; case dataConBoxer con of {- Nothing -> return (DataAlt con, args, body) ;- Just (DCB boxer) ->- do { us <- newUniqueSupply- ; let (rep_ids, binds) = initUs_ us (boxer ty_args args)- ; return (DataAlt con, rep_ids, mkLets binds body) } } }-- mk_default :: CoreExpr -> [CoreAlt]- mk_default fail | exhaustive_case = []- | otherwise = [(DEFAULT, [], fail)]-- fail_flag :: CanItFail- fail_flag | exhaustive_case- = foldr orFail CantFail [can_it_fail | MatchResult can_it_fail _ <- match_results]- | otherwise- = CanFail-- mentioned_constructors = mkUniqSet $ map alt_pat alts- un_mentioned_constructors- = mkUniqSet data_cons `minusUniqSet` mentioned_constructors- exhaustive_case = isEmptyUniqSet un_mentioned_constructors----- Stuff for parallel arrays------ * the following is to desugar cases over fake constructors for--- parallel arrays, which are introduced by `tidy1' in the `PArrPat'--- case----mkPArrCase :: DynFlags -> Id -> Type -> [CaseAlt DataCon] -> CoreExpr -> DsM CoreExpr-mkPArrCase dflags var ty sorted_alts fail = do- lengthP <- dsDPHBuiltin lengthPVar- alt <- unboxAlt- return (mkWildCase (len lengthP) intTy ty [alt])- where- elemTy = case splitTyConApp (idType var) of- (_, [elemTy]) -> elemTy- _ -> panic panicMsg- panicMsg = "DsUtils.mkCoAlgCaseMatchResult: not a parallel array?"- len lengthP = mkApps (Var lengthP) [Type elemTy, Var var]- --- unboxAlt = do- l <- newSysLocalDs intPrimTy- indexP <- dsDPHBuiltin indexPVar- alts <- mapM (mkAlt indexP) sorted_alts- return (DataAlt intDataCon, [l], mkWildCase (Var l) intPrimTy ty (dft : alts))- where- dft = (DEFAULT, [], fail)-- --- -- each alternative matches one array length (corresponding to one- -- fake array constructor), so the match is on a literal; each- -- alternative's body is extended by a local binding for each- -- constructor argument, which are bound to array elements starting- -- with the first- --- mkAlt indexP alt@MkCaseAlt{alt_result = MatchResult _ bodyFun} = do- body <- bodyFun fail- return (LitAlt lit, [], mkCoreLets binds body)- where- lit = MachInt $ toInteger (dataConSourceArity (alt_pat alt))- binds = [NonRec arg (indexExpr i) | (i, arg) <- zip [1..] (alt_bndrs alt)]- --- indexExpr i = mkApps (Var indexP) [Type elemTy, Var var, mkIntExpr dflags i]-\end{code}--%************************************************************************-%* *-\subsection{Desugarer's versions of some Core functions}-%* *-%************************************************************************--\begin{code}-mkErrorAppDs :: Id -- The error function- -> Type -- Type to which it should be applied- -> SDoc -- The error message string to pass- -> DsM CoreExpr--mkErrorAppDs err_id ty msg = do- src_loc <- getSrcSpanDs- dflags <- getDynFlags- let- full_msg = showSDoc dflags (hcat [ppr src_loc, text "|", msg])- core_msg = Lit (mkMachString full_msg)- -- mkMachString returns a result of type String#- return (mkApps (Var err_id) [Type ty, core_msg])-\end{code}--'mkCoreAppDs' and 'mkCoreAppsDs' hand the special-case desugaring of 'seq'.--Note [Desugaring seq (1)] cf Trac #1031-~~~~~~~~~~~~~~~~~~~~~~~~~- f x y = x `seq` (y `seq` (# x,y #))--The [CoreSyn let/app invariant] means that, other things being equal, because -the argument to the outer 'seq' has an unlifted type, we'll use call-by-value thus:-- f x y = case (y `seq` (# x,y #)) of v -> x `seq` v--But that is bad for two reasons: - (a) we now evaluate y before x, and - (b) we can't bind v to an unboxed pair--Seq is very, very special! So we recognise it right here, and desugar to- case x of _ -> case y of _ -> (# x,y #)--Note [Desugaring seq (2)] cf Trac #2273-~~~~~~~~~~~~~~~~~~~~~~~~~-Consider- let chp = case b of { True -> fst x; False -> 0 }- in chp `seq` ...chp...-Here the seq is designed to plug the space leak of retaining (snd x)-for too long.--If we rely on the ordinary inlining of seq, we'll get- let chp = case b of { True -> fst x; False -> 0 }- case chp of _ { I# -> ...chp... }--But since chp is cheap, and the case is an alluring contet, we'll-inline chp into the case scrutinee. Now there is only one use of chp,-so we'll inline a second copy. Alas, we've now ruined the purpose of-the seq, by re-introducing the space leak:- case (case b of {True -> fst x; False -> 0}) of- I# _ -> ...case b of {True -> fst x; False -> 0}...--We can try to avoid doing this by ensuring that the binder-swap in the-case happens, so we get his at an early stage:- case chp of chp2 { I# -> ...chp2... }-But this is fragile. The real culprit is the source program. Perhaps we-should have said explicitly- let !chp2 = chp in ...chp2...--But that's painful. So the code here does a little hack to make seq-more robust: a saturated application of 'seq' is turned *directly* into-the case expression, thus:- x `seq` e2 ==> case x of x -> e2 -- Note shadowing!- e1 `seq` e2 ==> case x of _ -> e2--So we desugar our example to:- let chp = case b of { True -> fst x; False -> 0 }- case chp of chp { I# -> ...chp... }-And now all is well.--The reason it's a hack is because if you define mySeq=seq, the hack-won't work on mySeq. --Note [Desugaring seq (3)] cf Trac #2409-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~-The isLocalId ensures that we don't turn - True `seq` e-into- case True of True { ... }-which stupidly tries to bind the datacon 'True'. --\begin{code}-mkCoreAppDs :: CoreExpr -> CoreExpr -> CoreExpr-mkCoreAppDs (Var f `App` Type ty1 `App` Type ty2 `App` arg1) arg2- | f `hasKey` seqIdKey -- Note [Desugaring seq (1), (2)]- = Case arg1 case_bndr ty2 [(DEFAULT,[],arg2)]- where- case_bndr = case arg1 of- Var v1 | isLocalId v1 -> v1 -- Note [Desugaring seq (2) and (3)]- _ -> mkWildValBinder ty1--mkCoreAppDs fun arg = mkCoreApp fun arg -- The rest is done in MkCore--mkCoreAppsDs :: CoreExpr -> [CoreExpr] -> CoreExpr-mkCoreAppsDs fun args = foldl mkCoreAppDs fun args-\end{code}---%************************************************************************-%* *-\subsection[mkSelectorBind]{Make a selector bind}-%* *-%************************************************************************--This is used in various places to do with lazy patterns.-For each binder $b$ in the pattern, we create a binding:-\begin{verbatim}- b = case v of pat' -> b'-\end{verbatim}-where @pat'@ is @pat@ with each binder @b@ cloned into @b'@.--ToDo: making these bindings should really depend on whether there's-much work to be done per binding. If the pattern is complex, it-should be de-mangled once, into a tuple (and then selected from).-Otherwise the demangling can be in-line in the bindings (as here).--Boring! Boring! One error message per binder. The above ToDo is-even more helpful. Something very similar happens for pattern-bound-expressions.--Note [mkSelectorBinds]-~~~~~~~~~~~~~~~~~~~~~~-Given p = e, where p binds x,y-we are going to make EITHER--EITHER (A) v = e (where v is fresh)- x = case v of p -> x- y = case v of p -> y--OR (B) t = case e of p -> (x,y)- x = case t of (x,_) -> x- y = case t of (_,y) -> y--We do (A) when - * Matching the pattern is cheap so we don't mind- doing it twice. - * Or if the pattern binds only one variable (so we'll only- match once)- * AND the pattern can't fail (else we tiresomely get two inexhaustive - pattern warning messages)--Otherwise we do (B). Really (A) is just an optimisation for very common-cases like- Just x = e- (p,q) = e--\begin{code}-mkSelectorBinds :: [Maybe (Tickish Id)] -- ticks to add, possibly- -> LPat Id -- The pattern- -> CoreExpr -- Expression to which the pattern is bound- -> DsM [(Id,CoreExpr)]--mkSelectorBinds ticks (L _ (VarPat v)) val_expr- = return [(v, case ticks of- [t] -> mkOptTickBox t val_expr- _ -> val_expr)]--mkSelectorBinds ticks pat val_expr- | null binders - = return []-- | isSingleton binders || is_simple_lpat pat- -- See Note [mkSelectorBinds]- = do { val_var <- newSysLocalDs (hsLPatType pat)- -- Make up 'v' in Note [mkSelectorBinds]- -- NB: give it the type of *pattern* p, not the type of the *rhs* e.- -- This does not matter after desugaring, but there's a subtle - -- issue with implicit parameters. Consider- -- (x,y) = ?i- -- Then, ?i is given type {?i :: Int}, a PredType, which is opaque- -- to the desugarer. (Why opaque? Because newtypes have to be. Why- -- does it get that type? So that when we abstract over it we get the- -- right top-level type (?i::Int) => ...)- --- -- So to get the type of 'v', use the pattern not the rhs. Often more- -- efficient too.-- -- For the error message we make one error-app, to avoid duplication.- -- But we need it at different types... so we use coerce for that- ; err_expr <- mkErrorAppDs iRREFUT_PAT_ERROR_ID unitTy (ppr pat)- ; err_var <- newSysLocalDs unitTy- ; binds <- zipWithM (mk_bind val_var err_var) ticks' binders- ; return ( (val_var, val_expr) : - (err_var, err_expr) :- binds ) }-- | otherwise- = do { error_expr <- mkErrorAppDs iRREFUT_PAT_ERROR_ID tuple_ty (ppr pat)- ; tuple_expr <- matchSimply val_expr PatBindRhs pat local_tuple error_expr- ; tuple_var <- newSysLocalDs tuple_ty- ; let mk_tup_bind tick binder- = (binder, mkOptTickBox tick $- mkTupleSelector local_binders binder- tuple_var (Var tuple_var))- ; return ( (tuple_var, tuple_expr) : zipWith mk_tup_bind ticks' binders ) }- where- binders = collectPatBinders pat- ticks' = ticks ++ repeat Nothing-- local_binders = map localiseId binders -- See Note [Localise pattern binders]- local_tuple = mkBigCoreVarTup binders- tuple_ty = exprType local_tuple-- mk_bind scrut_var err_var tick bndr_var = do- -- (mk_bind sv err_var) generates- -- bv = case sv of { pat -> bv; other -> coerce (type-of-bv) err_var }- -- Remember, pat binds bv- rhs_expr <- matchSimply (Var scrut_var) PatBindRhs pat- (Var bndr_var) error_expr- return (bndr_var, mkOptTickBox tick rhs_expr)- where- error_expr = mkCast (Var err_var) co- co = mkUnsafeCo (exprType (Var err_var)) (idType bndr_var)-- is_simple_lpat p = is_simple_pat (unLoc p)-- is_simple_pat (TuplePat ps Boxed _) = all is_triv_lpat ps- is_simple_pat pat@(ConPatOut{}) = case unLoc (pat_con pat) of- RealDataCon con -> isProductTyCon (dataConTyCon con)- && all is_triv_lpat (hsConPatArgs (pat_args pat))- PatSynCon _ -> False- is_simple_pat (VarPat _) = True- is_simple_pat (ParPat p) = is_simple_lpat p- is_simple_pat _ = False-- is_triv_lpat p = is_triv_pat (unLoc p)-- is_triv_pat (VarPat _) = True- is_triv_pat (WildPat _) = True- is_triv_pat (ParPat p) = is_triv_lpat p- is_triv_pat _ = False-\end{code}--Creating big tuples and their types for full Haskell expressions.-They work over *Ids*, and create tuples replete with their types,-which is whey they are not in HsUtils.--\begin{code}-mkLHsPatTup :: [LPat Id] -> LPat Id-mkLHsPatTup [] = noLoc $ mkVanillaTuplePat [] Boxed-mkLHsPatTup [lpat] = lpat-mkLHsPatTup lpats = L (getLoc (head lpats)) $ - mkVanillaTuplePat lpats Boxed--mkLHsVarPatTup :: [Id] -> LPat Id-mkLHsVarPatTup bs = mkLHsPatTup (map nlVarPat bs)--mkVanillaTuplePat :: [OutPat Id] -> Boxity -> Pat Id--- A vanilla tuple pattern simply gets its type from its sub-patterns-mkVanillaTuplePat pats box = TuplePat pats box (map hsLPatType pats)---- The Big equivalents for the source tuple expressions-mkBigLHsVarTup :: [Id] -> LHsExpr Id-mkBigLHsVarTup ids = mkBigLHsTup (map nlHsVar ids)--mkBigLHsTup :: [LHsExpr Id] -> LHsExpr Id-mkBigLHsTup = mkChunkified mkLHsTupleExpr---- The Big equivalents for the source tuple patterns-mkBigLHsVarPatTup :: [Id] -> LPat Id-mkBigLHsVarPatTup bs = mkBigLHsPatTup (map nlVarPat bs)--mkBigLHsPatTup :: [LPat Id] -> LPat Id-mkBigLHsPatTup = mkChunkified mkLHsPatTup-\end{code}--%************************************************************************-%* *-\subsection[mkFailurePair]{Code for pattern-matching and other failures}-%* *-%************************************************************************--Generally, we handle pattern matching failure like this: let-bind a-fail-variable, and use that variable if the thing fails:-\begin{verbatim}- let fail.33 = error "Help"- in- case x of- p1 -> ...- p2 -> fail.33- p3 -> fail.33- p4 -> ...-\end{verbatim}-Then-\begin{itemize}-\item-If the case can't fail, then there'll be no mention of @fail.33@, and the-simplifier will later discard it.--\item-If it can fail in only one way, then the simplifier will inline it.--\item-Only if it is used more than once will the let-binding remain.-\end{itemize}--There's a problem when the result of the case expression is of-unboxed type. Then the type of @fail.33@ is unboxed too, and-there is every chance that someone will change the let into a case:-\begin{verbatim}- case error "Help" of- fail.33 -> case ....-\end{verbatim}--which is of course utterly wrong. Rather than drop the condition that-only boxed types can be let-bound, we just turn the fail into a function-for the primitive case:-\begin{verbatim}- let fail.33 :: Void -> Int#- fail.33 = \_ -> error "Help"- in- case x of- p1 -> ...- p2 -> fail.33 void- p3 -> fail.33 void- p4 -> ...-\end{verbatim}--Now @fail.33@ is a function, so it can be let-bound.--\begin{code}-mkFailurePair :: CoreExpr -- Result type of the whole case expression- -> DsM (CoreBind, -- Binds the newly-created fail variable- -- to \ _ -> expression- CoreExpr) -- Fail variable applied to realWorld#--- See Note [Failure thunks and CPR]-mkFailurePair expr- = do { fail_fun_var <- newFailLocalDs (voidPrimTy `mkFunTy` ty)- ; fail_fun_arg <- newSysLocalDs voidPrimTy- ; let real_arg = setOneShotLambda fail_fun_arg- ; return (NonRec fail_fun_var (Lam real_arg expr),- App (Var fail_fun_var) (Var voidPrimId)) }- where- ty = exprType expr-\end{code}--Note [Failure thunks and CPR]-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~-When we make a failure point we ensure that it-does not look like a thunk. Example:-- let fail = \rw -> error "urk"- in case x of - [] -> fail realWorld#- (y:ys) -> case ys of- [] -> fail realWorld# - (z:zs) -> (y,z)--Reason: we know that a failure point is always a "join point" and is-entered at most once. Adding a dummy 'realWorld' token argument makes-it clear that sharing is not an issue. And that in turn makes it more-CPR-friendly. This matters a lot: if you don't get it right, you lose-the tail call property. For example, see Trac #3403.--\begin{code}-mkOptTickBox :: Maybe (Tickish Id) -> CoreExpr -> CoreExpr-mkOptTickBox Nothing e = e-mkOptTickBox (Just tickish) e = Tick tickish e--mkBinaryTickBox :: Int -> Int -> CoreExpr -> DsM CoreExpr-mkBinaryTickBox ixT ixF e = do- uq <- newUnique - this_mod <- getModule- let bndr1 = mkSysLocal (fsLit "t1") uq boolTy- let- falseBox = Tick (HpcTick this_mod ixF) (Var falseDataConId)- trueBox = Tick (HpcTick this_mod ixT) (Var trueDataConId)- --- return $ Case e bndr1 boolTy- [ (DataAlt falseDataCon, [], falseBox)- , (DataAlt trueDataCon, [], trueBox)- ]-\end{code}
− src/Language/Haskell/Liquid/Desugar/HscMain.hs
@@ -1,95 +0,0 @@-------------------------------------------------------------------------------------- | Main API for compiling plain Haskell source code.------ This module implements compilation of a Haskell source. It is--- /not/ concerned with preprocessing of source files; this is handled--- in "DriverPipeline".------ There are various entry points depending on what mode we're in:--- "batch" mode (@--make@), "one-shot" mode (@-c@, @-S@ etc.), and--- "interactive" mode (GHCi). There are also entry points for--- individual passes: parsing, typechecking/renaming, desugaring, and--- simplification.------ All the functions here take an 'HscEnv' as a parameter, but none of--- them return a new one: 'HscEnv' is treated as an immutable value--- from here on in (although it has mutable components, for the--- caches).------ Warning messages are dealt with consistently throughout this API:--- during compilation warnings are collected, and before any function--- in @HscMain@ returns, the warnings are either printed, or turned--- into a real compialtion error if the @-Werror@ flag is enabled.------ (c) The GRASP/AQUA Project, Glasgow University, 1993-2000-------------------------------------------------------------------------------------module Language.Haskell.Liquid.Desugar.HscMain (hscDesugarWithLoc) where--import Language.Haskell.Liquid.Desugar.Desugar (deSugarWithLoc)--import Module -import Lexer-import TcRnMonad--import ErrUtils--import HscTypes-import Bag-import Exception----- -------------------------------------------------------------------------------getWarnings :: Hsc WarningMessages-getWarnings = Hsc $ \_ w -> return (w, w)--clearWarnings :: Hsc ()-clearWarnings = Hsc $ \_ _ -> return ((), emptyBag)--logWarnings :: WarningMessages -> Hsc ()-logWarnings w = Hsc $ \_ w0 -> return ((), w0 `unionBags` w)------ | Throw some errors.-throwErrors :: ErrorMessages -> Hsc a-throwErrors = liftIO . throwIO . mkSrcErr---- --- | Convert a typechecked module to Core-hscDesugarWithLoc :: HscEnv -> ModSummary -> TcGblEnv -> IO ModGuts-hscDesugarWithLoc hsc_env mod_summary tc_result =- runHsc hsc_env $ hscDesugar' (ms_location mod_summary) tc_result--hscDesugar' :: ModLocation -> TcGblEnv -> Hsc ModGuts-hscDesugar' mod_location tc_result = do- hsc_env <- getHscEnv- r <- ioMsgMaybe $- {-# SCC "deSugar" #-}- deSugarWithLoc hsc_env mod_location tc_result-- -- always check -Werror after desugaring, this is the last opportunity for- -- warnings to arise before the backend.- handleWarnings- return r--getHscEnv :: Hsc HscEnv-getHscEnv = Hsc $ \e w -> return (e, w)--handleWarnings :: Hsc ()-handleWarnings = do- dflags <- getDynFlags- w <- getWarnings- liftIO $ printOrThrowWarnings dflags w- clearWarnings--ioMsgMaybe :: IO (Messages, Maybe a) -> Hsc a-ioMsgMaybe ioA = do- ((warns,errs), mb_r) <- liftIO ioA- logWarnings warns- case mb_r of- Nothing -> throwErrors errs- Just r -> return r
− src/Language/Haskell/Liquid/Desugar/Match.lhs
@@ -1,1050 +0,0 @@-%-% (c) The University of Glasgow 2006-% (c) The GRASP/AQUA Project, Glasgow University, 1992-1998-%--The @match@ function--\begin{code}-module Language.Haskell.Liquid.Desugar.Match ( match, matchEquations, matchWrapper, matchSimply, matchSinglePat ) where---- #include "HsVersions.h"--import {-#SOURCE#-} Language.Haskell.Liquid.Desugar.DsExpr (dsLExpr, dsExpr)--import DynFlags-import HsSyn-import TcHsSyn-import TcEvidence-import TcRnMonad-import Check-import CoreSyn-import Literal-import CoreUtils-import MkCore-import DsMonad-import Language.Haskell.Liquid.Desugar.DsBinds-import Language.Haskell.Liquid.Desugar.DsGRHSs-import Language.Haskell.Liquid.Desugar.DsUtils-import Id-import ConLike-import DataCon-import PatSyn-import Language.Haskell.Liquid.Desugar.MatchCon-import Language.Haskell.Liquid.Desugar.MatchLit-import Type-import TysWiredIn-import ListSetOps-import SrcLoc-import Maybes-import Util-import Name-import Outputable-import BasicTypes ( boxityNormalTupleSort, isGenerated )-import FastString--import Control.Monad( when )-import qualified Data.Map as Map-\end{code}--This function is a wrapper of @match@, it must be called from all the parts where-it was called match, but only substitutes the first call, ....-if the associated flags are declared, warnings will be issued.-It can not be called matchWrapper because this name already exists :-(--JJCQ 30-Nov-1997--\begin{code}-matchCheck :: DsMatchContext- -> [Id] -- Vars rep'ing the exprs we're matching with- -> Type -- Type of the case expression- -> [EquationInfo] -- Info about patterns, etc. (type synonym below)- -> DsM MatchResult -- Desugared result!--matchCheck ctx vars ty qs- = do { dflags <- getDynFlags- ; matchCheck_really dflags ctx vars ty qs }--matchCheck_really :: DynFlags- -> DsMatchContext- -> [Id]- -> Type- -> [EquationInfo]- -> DsM MatchResult-matchCheck_really dflags ctx@(DsMatchContext hs_ctx _) vars ty qs- = do { when shadow (dsShadowWarn ctx eqns_shadow)- ; when incomplete (dsIncompleteWarn ctx pats)- ; match vars ty qs }- where- (pats, eqns_shadow) = check qs- incomplete = incomplete_flag hs_ctx && (notNull pats)- shadow = wopt Opt_WarnOverlappingPatterns dflags- && notNull eqns_shadow-- incomplete_flag :: HsMatchContext id -> Bool- incomplete_flag (FunRhs {}) = wopt Opt_WarnIncompletePatterns dflags- incomplete_flag CaseAlt = wopt Opt_WarnIncompletePatterns dflags- incomplete_flag IfAlt = False-- incomplete_flag LambdaExpr = wopt Opt_WarnIncompleteUniPatterns dflags- incomplete_flag PatBindRhs = wopt Opt_WarnIncompleteUniPatterns dflags- incomplete_flag ProcExpr = wopt Opt_WarnIncompleteUniPatterns dflags-- incomplete_flag RecUpd = wopt Opt_WarnIncompletePatternsRecUpd dflags-- incomplete_flag ThPatSplice = False- incomplete_flag PatSyn = False- incomplete_flag ThPatQuote = False- incomplete_flag (StmtCtxt {}) = False -- Don't warn about incomplete patterns- -- in list comprehensions, pattern guards- -- etc. They are often *supposed* to be- -- incomplete-\end{code}--This variable shows the maximum number of lines of output generated for warnings.-It will limit the number of patterns/equations displayed to@ maximum_output@.--(ToDo: add command-line option?)--\begin{code}-maximum_output :: Int-maximum_output = 4-\end{code}--The next two functions create the warning message.--\begin{code}-dsShadowWarn :: DsMatchContext -> [EquationInfo] -> DsM ()-dsShadowWarn ctx@(DsMatchContext kind loc) qs- = putSrcSpanDs loc (warnDs warn)- where- warn | qs `lengthExceeds` maximum_output- = pp_context ctx (ptext (sLit "are overlapped"))- (\ f -> vcat (map (ppr_eqn f kind) (take maximum_output qs)) $$- ptext (sLit "..."))- | otherwise- = pp_context ctx (ptext (sLit "are overlapped"))- (\ f -> vcat $ map (ppr_eqn f kind) qs)---dsIncompleteWarn :: DsMatchContext -> [ExhaustivePat] -> DsM ()-dsIncompleteWarn ctx@(DsMatchContext kind loc) pats- = putSrcSpanDs loc (warnDs warn)- where- warn = pp_context ctx (ptext (sLit "are non-exhaustive"))- (\_ -> hang (ptext (sLit "Patterns not matched:"))- 4 ((vcat $ map (ppr_incomplete_pats kind)- (take maximum_output pats))- $$ dots))-- dots | pats `lengthExceeds` maximum_output = ptext (sLit "...")- | otherwise = empty--pp_context :: DsMatchContext -> SDoc -> ((SDoc -> SDoc) -> SDoc) -> SDoc-pp_context (DsMatchContext kind _loc) msg rest_of_msg_fun- = vcat [ptext (sLit "Pattern match(es)") <+> msg,- sep [ptext (sLit "In") <+> ppr_match <> char ':', nest 4 (rest_of_msg_fun pref)]]- where- (ppr_match, pref)- = case kind of- FunRhs fun _ -> (pprMatchContext kind, \ pp -> ppr fun <+> pp)- _ -> (pprMatchContext kind, \ pp -> pp)--ppr_pats :: Outputable a => [a] -> SDoc-ppr_pats pats = sep (map ppr pats)--ppr_shadow_pats :: HsMatchContext Name -> [Pat Id] -> SDoc-ppr_shadow_pats kind pats- = sep [ppr_pats pats, matchSeparator kind, ptext (sLit "...")]--ppr_incomplete_pats :: HsMatchContext Name -> ExhaustivePat -> SDoc-ppr_incomplete_pats _ (pats,[]) = ppr_pats pats-ppr_incomplete_pats _ (pats,constraints) =- sep [ppr_pats pats, ptext (sLit "with"),- sep (map ppr_constraint constraints)]--ppr_constraint :: (Name,[HsLit]) -> SDoc-ppr_constraint (var,pats) = sep [ppr var, ptext (sLit "`notElem`"), ppr pats]--ppr_eqn :: (SDoc -> SDoc) -> HsMatchContext Name -> EquationInfo -> SDoc-ppr_eqn prefixF kind eqn = prefixF (ppr_shadow_pats kind (eqn_pats eqn))-\end{code}---%************************************************************************-%* *- The main matching function-%* *-%************************************************************************--The function @match@ is basically the same as in the Wadler chapter,-except it is monadised, to carry around the name supply, info about-annotations, etc.--Notes on @match@'s arguments, assuming $m$ equations and $n$ patterns:-\begin{enumerate}-\item-A list of $n$ variable names, those variables presumably bound to the-$n$ expressions being matched against the $n$ patterns. Using the-list of $n$ expressions as the first argument showed no benefit and-some inelegance.--\item-The second argument, a list giving the ``equation info'' for each of-the $m$ equations:-\begin{itemize}-\item-the $n$ patterns for that equation, and-\item-a list of Core bindings [@(Id, CoreExpr)@ pairs] to be ``stuck on-the front'' of the matching code, as in:-\begin{verbatim}-let <binds>-in <matching-code>-\end{verbatim}-\item-and finally: (ToDo: fill in)--The right way to think about the ``after-match function'' is that it-is an embryonic @CoreExpr@ with a ``hole'' at the end for the-final ``else expression''.-\end{itemize}--There is a type synonym, @EquationInfo@, defined in module @DsUtils@.--An experiment with re-ordering this information about equations (in-particular, having the patterns available in column-major order)-showed no benefit.--\item-A default expression---what to evaluate if the overall pattern-match-fails. This expression will (almost?) always be-a measly expression @Var@, unless we know it will only be used once-(as we do in @glue_success_exprs@).--Leaving out this third argument to @match@ (and slamming in lots of-@Var "fail"@s) is a positively {\em bad} idea, because it makes it-impossible to share the default expressions. (Also, it stands no-chance of working in our post-upheaval world of @Locals@.)-\end{enumerate}--Note: @match@ is often called via @matchWrapper@ (end of this module),-a function that does much of the house-keeping that goes with a call-to @match@.--It is also worth mentioning the {\em typical} way a block of equations-is desugared with @match@. At each stage, it is the first column of-patterns that is examined. The steps carried out are roughly:-\begin{enumerate}-\item-Tidy the patterns in column~1 with @tidyEqnInfo@ (this may add-bindings to the second component of the equation-info):-\begin{itemize}-\item-Remove the `as' patterns from column~1.-\item-Make all constructor patterns in column~1 into @ConPats@, notably-@ListPats@ and @TuplePats@.-\item-Handle any irrefutable (or ``twiddle'') @LazyPats@.-\end{itemize}-\item-Now {\em unmix} the equations into {\em blocks} [w\/ local function-@unmix_eqns@], in which the equations in a block all have variable-patterns in column~1, or they all have constructor patterns in ...-(see ``the mixture rule'' in SLPJ).-\item-Call @matchEqnBlock@ on each block of equations; it will do the-appropriate thing for each kind of column-1 pattern, usually ending up-in a recursive call to @match@.-\end{enumerate}--We are a little more paranoid about the ``empty rule'' (SLPJ, p.~87)-than the Wadler-chapter code for @match@ (p.~93, first @match@ clause).-And gluing the ``success expressions'' together isn't quite so pretty.--This (more interesting) clause of @match@ uses @tidy_and_unmix_eqns@-(a)~to get `as'- and `twiddle'-patterns out of the way (tidying), and-(b)~to do ``the mixture rule'' (SLPJ, p.~88) [which really {\em-un}mixes the equations], producing a list of equation-info-blocks, each block having as its first column of patterns either all-constructors, or all variables (or similar beasts), etc.--@match_unmixed_eqn_blks@ simply takes the place of the @foldr@ in the-Wadler-chapter @match@ (p.~93, last clause), and @match_unmixed_blk@-corresponds roughly to @matchVarCon@.--\begin{code}--match :: [Id] -- Variables rep\'ing the exprs we\'re matching with- -> Type -- Type of the case expression- -> [EquationInfo] -- Info about patterns, etc. (type synonym below)- -> DsM MatchResult -- Desugared result!--match [] _ eqns- = -- ASSERT2( not (null eqns), ppr ty )- return (foldr1 combineMatchResults match_results)- where- match_results = [ -- ASSERT( null (eqn_pats eqn) )- eqn_rhs eqn- | eqn <- eqns ]--match vars@(v:_) ty eqns -- Eqns *can* be empty- = do { dflags <- getDynFlags- ; -- Tidy the first pattern, generating- -- auxiliary bindings if necessary- (aux_binds, tidy_eqns) <- mapAndUnzipM (tidyEqnInfo v) eqns-- -- Group the equations and match each group in turn- ; let grouped = groupEquations dflags tidy_eqns-- -- print the view patterns that are commoned up to help debug- ; whenDOptM Opt_D_dump_view_pattern_commoning (debug grouped)-- ; match_results <- match_groups grouped- ; return (adjustMatchResult (foldr (.) id aux_binds) $- foldr1 combineMatchResults match_results) }- where- dropGroup :: [(PatGroup,EquationInfo)] -> [EquationInfo]- dropGroup = map snd-- match_groups :: [[(PatGroup,EquationInfo)]] -> DsM [MatchResult]- -- Result list of [MatchResult] is always non-empty- match_groups [] = matchEmpty v ty- match_groups gs = mapM match_group gs-- match_group :: [(PatGroup,EquationInfo)] -> DsM MatchResult- match_group [] = panic "match_group"- match_group eqns@((group,_) : _)- = case group of- PgCon _ -> matchConFamily vars ty (subGroup [(c,e) | (PgCon c, e) <- eqns])- PgSyn _ -> matchPatSyn vars ty (dropGroup eqns)- PgLit _ -> matchLiterals vars ty (subGroup [(l,e) | (PgLit l, e) <- eqns])- PgAny -> matchVariables vars ty (dropGroup eqns)- PgN _ -> matchNPats vars ty (dropGroup eqns)- PgNpK _ -> matchNPlusKPats vars ty (dropGroup eqns)- PgBang -> matchBangs vars ty (dropGroup eqns)- PgCo _ -> matchCoercion vars ty (dropGroup eqns)- PgView _ _ -> matchView vars ty (dropGroup eqns)- PgOverloadedList -> matchOverloadedList vars ty (dropGroup eqns)-- -- FIXME: we should also warn about view patterns that should be- -- commoned up but are not-- -- print some stuff to see what's getting grouped- -- use -dppr-debug to see the resolution of overloaded literals- debug eqns =- let gs = map (\group -> foldr (\ (p,_) -> \acc ->- case p of PgView e _ -> e:acc- _ -> acc) [] group) eqns- maybeWarn [] = return ()- maybeWarn l = warnDs (vcat l)- in- maybeWarn $ (map (\g -> text "Putting these view expressions into the same case:" <+> (ppr g))- (filter (not . null) gs))--matchEmpty :: Id -> Type -> DsM [MatchResult]--- See Note [Empty case expressions]-matchEmpty var res_ty- = return [MatchResult CanFail mk_seq]- where- mk_seq fail = return $ mkWildCase (Var var) (idType var) res_ty- [(DEFAULT, [], fail)]--matchVariables :: [Id] -> Type -> [EquationInfo] -> DsM MatchResult--- Real true variables, just like in matchVar, SLPJ p 94--- No binding to do: they'll all be wildcards by now (done in tidy)-matchVariables (_:vars) ty eqns = match vars ty (shiftEqns eqns)-matchVariables [] _ _ = panic "matchVariables"--matchBangs :: [Id] -> Type -> [EquationInfo] -> DsM MatchResult-matchBangs (var:vars) ty eqns- = do { match_result <- match (var:vars) ty $- map (decomposeFirstPat getBangPat) eqns- ; return (mkEvalMatchResult var ty match_result) }-matchBangs [] _ _ = panic "matchBangs"--matchCoercion :: [Id] -> Type -> [EquationInfo] -> DsM MatchResult--- Apply the coercion to the match variable and then match that-matchCoercion (var:vars) ty (eqns@(eqn1:_))- = do { let CoPat co pat _ = firstPat eqn1- ; var' <- newUniqueId var (hsPatType pat)- ; match_result <- match (var':vars) ty $- map (decomposeFirstPat getCoPat) eqns- ; rhs' <- dsHsWrapper co (Var var)- ; return (mkCoLetMatchResult (NonRec var' rhs') match_result) }-matchCoercion _ _ _ = panic "matchCoercion"--matchView :: [Id] -> Type -> [EquationInfo] -> DsM MatchResult--- Apply the view function to the match variable and then match that-matchView (var:vars) ty (eqns@(eqn1:_))- = do { -- we could pass in the expr from the PgView,- -- but this needs to extract the pat anyway- -- to figure out the type of the fresh variable- let ViewPat viewExpr (L _ pat) _ = firstPat eqn1- -- do the rest of the compilation- ; var' <- newUniqueId var (hsPatType pat)- ; match_result <- match (var':vars) ty $- map (decomposeFirstPat getViewPat) eqns- -- compile the view expressions- ; viewExpr' <- dsLExpr viewExpr- ; return (mkViewMatchResult var' viewExpr' var match_result) }-matchView _ _ _ = panic "matchView"--matchOverloadedList :: [Id] -> Type -> [EquationInfo] -> DsM MatchResult-matchOverloadedList (var:vars) ty (eqns@(eqn1:_))--- Since overloaded list patterns are treated as view patterns,--- the code is roughly the same as for matchView- = do { let ListPat _ elt_ty (Just (_,e)) = firstPat eqn1- ; var' <- newUniqueId var (mkListTy elt_ty) -- we construct the overall type by hand- ; match_result <- match (var':vars) ty $- map (decomposeFirstPat getOLPat) eqns -- getOLPat builds the pattern inside as a non-overloaded version of the overloaded list pattern- ; e' <- dsExpr e- ; return (mkViewMatchResult var' e' var match_result) }-matchOverloadedList _ _ _ = panic "matchOverloadedList"---- decompose the first pattern and leave the rest alone-decomposeFirstPat :: (Pat Id -> Pat Id) -> EquationInfo -> EquationInfo-decomposeFirstPat extractpat (eqn@(EqnInfo { eqn_pats = pat : pats }))- = eqn { eqn_pats = extractpat pat : pats}-decomposeFirstPat _ _ = panic "decomposeFirstPat"--getCoPat, getBangPat, getViewPat, getOLPat :: Pat Id -> Pat Id-getCoPat (CoPat _ pat _) = pat-getCoPat _ = panic "getCoPat"-getBangPat (BangPat pat ) = unLoc pat-getBangPat _ = panic "getBangPat"-getViewPat (ViewPat _ pat _) = unLoc pat-getViewPat _ = panic "getViewPat"-getOLPat (ListPat pats ty (Just _)) = ListPat pats ty Nothing-getOLPat _ = panic "getOLPat"-\end{code}--Note [Empty case alternatives]-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~-The list of EquationInfo can be empty, arising from- case x of {} or \case {}-In that situation we desugar to- case x of { _ -> error "pattern match failure" }-The *desugarer* isn't certain whether there really should be no-alternatives, so it adds a default case, as it always does. A later-pass may remove it if it's inaccessible. (See also Note [Empty case-alternatives] in CoreSyn.)--We do *not* desugar simply to- error "empty case"-or some such, because 'x' might be bound to (error "hello"), in which-case we want to see that "hello" exception, not (error "empty case").-See also Note [Case elimination: lifted case] in Simplify.---%************************************************************************-%* *- Tidying patterns-%* *-%************************************************************************--Tidy up the leftmost pattern in an @EquationInfo@, given the variable @v@-which will be scrutinised. This means:-\begin{itemize}-\item-Replace variable patterns @x@ (@x /= v@) with the pattern @_@,-together with the binding @x = v@.-\item-Replace the `as' pattern @x@@p@ with the pattern p and a binding @x = v@.-\item-Removing lazy (irrefutable) patterns (you don't want to know...).-\item-Converting explicit tuple-, list-, and parallel-array-pats into ordinary-@ConPats@.-\item-Convert the literal pat "" to [].-\end{itemize}--The result of this tidying is that the column of patterns will include-{\em only}:-\begin{description}-\item[@WildPats@:]-The @VarPat@ information isn't needed any more after this.--\item[@ConPats@:]-@ListPats@, @TuplePats@, etc., are all converted into @ConPats@.--\item[@LitPats@ and @NPats@:]-@LitPats@/@NPats@ of ``known friendly types'' (Int, Char,-Float, Double, at least) are converted to unboxed form; e.g.,-\tr{(NPat (HsInt i) _ _)} is converted to:-\begin{verbatim}-(ConPat I# _ _ [LitPat (HsIntPrim i)])-\end{verbatim}-\end{description}--\begin{code}-tidyEqnInfo :: Id -> EquationInfo- -> DsM (DsWrapper, EquationInfo)- -- DsM'd because of internal call to dsLHsBinds- -- and mkSelectorBinds.- -- "tidy1" does the interesting stuff, looking at- -- one pattern and fiddling the list of bindings.- --- -- POST CONDITION: head pattern in the EqnInfo is- -- WildPat- -- ConPat- -- NPat- -- LitPat- -- NPlusKPat- -- but no other--tidyEqnInfo _ (EqnInfo { eqn_pats = [] })- = panic "tidyEqnInfo"--tidyEqnInfo v eqn@(EqnInfo { eqn_pats = pat : pats })- = do { (wrap, pat') <- tidy1 v pat- ; return (wrap, eqn { eqn_pats = do pat' : pats }) }--tidy1 :: Id -- The Id being scrutinised- -> Pat Id -- The pattern against which it is to be matched- -> DsM (DsWrapper, -- Extra bindings to do before the match- Pat Id) -- Equivalent pattern------------------------------------------------------------ (pat', mr') = tidy1 v pat mr--- tidies the *outer level only* of pat, giving pat'--- It eliminates many pattern forms (as-patterns, variable patterns,--- list patterns, etc) yielding one of:--- WildPat--- ConPatOut--- LitPat--- NPat--- NPlusKPat--tidy1 v (ParPat pat) = tidy1 v (unLoc pat)-tidy1 v (SigPatOut pat _) = tidy1 v (unLoc pat)-tidy1 _ (WildPat ty) = return (idDsWrapper, WildPat ty)-tidy1 v (BangPat (L l p)) = tidy_bang_pat v l p-- -- case v of { x -> mr[] }- -- = case v of { _ -> let x=v in mr[] }-tidy1 v (VarPat var)- = return (wrapBind var v, WildPat (idType var))-- -- case v of { x@p -> mr[] }- -- = case v of { p -> let x=v in mr[] }-tidy1 v (AsPat (L _ var) pat)- = do { (wrap, pat') <- tidy1 v (unLoc pat)- ; return (wrapBind var v . wrap, pat') }--{- now, here we handle lazy patterns:- tidy1 v ~p bs = (v, v1 = case v of p -> v1 :- v2 = case v of p -> v2 : ... : bs )-- where the v_i's are the binders in the pattern.-- ToDo: in "v_i = ... -> v_i", are the v_i's really the same thing?-- The case expr for v_i is just: match [v] [(p, [], \ x -> Var v_i)] any_expr--}--tidy1 v (LazyPat pat)- = do { sel_prs <- mkSelectorBinds [] pat (Var v)- ; let sel_binds = [NonRec b rhs | (b,rhs) <- sel_prs]- ; return (mkCoreLets sel_binds, WildPat (idType v)) }--tidy1 _ (ListPat pats ty Nothing)- = return (idDsWrapper, unLoc list_ConPat)- where- list_ConPat = foldr (\ x y -> mkPrefixConPat consDataCon [x, y] [ty])- (mkNilPat ty)- pats---- Introduce fake parallel array constructors to be able to handle parallel--- arrays with the existing machinery for constructor pattern-tidy1 _ (PArrPat pats ty)- = return (idDsWrapper, unLoc parrConPat)- where- arity = length pats- parrConPat = mkPrefixConPat (parrFakeCon arity) pats [ty]--tidy1 _ (TuplePat pats boxity tys)- = return (idDsWrapper, unLoc tuple_ConPat)- where- arity = length pats- tuple_ConPat = mkPrefixConPat (tupleCon (boxityNormalTupleSort boxity) arity) pats tys---- LitPats: we *might* be able to replace these w/ a simpler form-tidy1 _ (LitPat lit)- = return (idDsWrapper, tidyLitPat lit)---- NPats: we *might* be able to replace these w/ a simpler form-tidy1 _ (NPat lit mb_neg eq)- = return (idDsWrapper, tidyNPat tidyLitPat lit mb_neg eq)---- Everything else goes through unchanged...--tidy1 _ non_interesting_pat- = return (idDsWrapper, non_interesting_pat)-----------------------tidy_bang_pat :: Id -> SrcSpan -> Pat Id -> DsM (DsWrapper, Pat Id)---- Discard bang around strict pattern-tidy_bang_pat v _ p@(ListPat {}) = tidy1 v p-tidy_bang_pat v _ p@(TuplePat {}) = tidy1 v p-tidy_bang_pat v _ p@(PArrPat {}) = tidy1 v p-tidy_bang_pat v _ p@(ConPatOut {}) = tidy1 v p-tidy_bang_pat v _ p@(LitPat {}) = tidy1 v p---- Discard par/sig under a bang-tidy_bang_pat v _ (ParPat (L l p)) = tidy_bang_pat v l p-tidy_bang_pat v _ (SigPatOut (L l p) _) = tidy_bang_pat v l p---- Push the bang-pattern inwards, in the hope that--- it may disappear next time-tidy_bang_pat v l (AsPat v' p) = tidy1 v (AsPat v' (L l (BangPat p)))-tidy_bang_pat v l (CoPat w p t) = tidy1 v (CoPat w (BangPat (L l p)) t)---- Default case, leave the bang there:--- VarPat, LazyPat, WildPat, ViewPat, NPat, NPlusKPat--- For LazyPat, remember that it's semantically like a VarPat--- i.e. !(~p) is not like ~p, or p! (Trac #8952)--tidy_bang_pat _ l p = return (idDsWrapper, BangPat (L l p))- -- NB: SigPatIn, ConPatIn should not happen-\end{code}--\noindent-{\bf Previous @matchTwiddled@ stuff:}--Now we get to the only interesting part; note: there are choices for-translation [from Simon's notes]; translation~1:-\begin{verbatim}-deTwiddle [s,t] e-\end{verbatim}-returns-\begin{verbatim}-[ w = e,- s = case w of [s,t] -> s- t = case w of [s,t] -> t-]-\end{verbatim}--Here \tr{w} is a fresh variable, and the \tr{w}-binding prevents multiple-evaluation of \tr{e}. An alternative translation (No.~2):-\begin{verbatim}-[ w = case e of [s,t] -> (s,t)- s = case w of (s,t) -> s- t = case w of (s,t) -> t-]-\end{verbatim}--%************************************************************************-%* *-\subsubsection[improved-unmixing]{UNIMPLEMENTED idea for improved unmixing}-%* *-%************************************************************************--We might be able to optimise unmixing when confronted by-only-one-constructor-possible, of which tuples are the most notable-examples. Consider:-\begin{verbatim}-f (a,b,c) ... = ...-f d ... (e:f) = ...-f (g,h,i) ... = ...-f j ... = ...-\end{verbatim}-This definition would normally be unmixed into four equation blocks,-one per equation. But it could be unmixed into just one equation-block, because if the one equation matches (on the first column),-the others certainly will.--You have to be careful, though; the example-\begin{verbatim}-f j ... = ...---------------------f (a,b,c) ... = ...-f d ... (e:f) = ...-f (g,h,i) ... = ...-\end{verbatim}-{\em must} be broken into two blocks at the line shown; otherwise, you-are forcing unnecessary evaluation. In any case, the top-left pattern-always gives the cue. You could then unmix blocks into groups of...-\begin{description}-\item[all variables:]-As it is now.-\item[constructors or variables (mixed):]-Need to make sure the right names get bound for the variable patterns.-\item[literals or variables (mixed):]-Presumably just a variant on the constructor case (as it is now).-\end{description}--%************************************************************************-%* *-%* matchWrapper: a convenient way to call @match@ *-%* *-%************************************************************************-\subsection[matchWrapper]{@matchWrapper@: a convenient interface to @match@}--Calls to @match@ often involve similar (non-trivial) work; that work-is collected here, in @matchWrapper@. This function takes as-arguments:-\begin{itemize}-\item-Typchecked @Matches@ (of a function definition, or a case or lambda-expression)---the main input;-\item-An error message to be inserted into any (runtime) pattern-matching-failure messages.-\end{itemize}--As results, @matchWrapper@ produces:-\begin{itemize}-\item-A list of variables (@Locals@) that the caller must ``promise'' to-bind to appropriate values; and-\item-a @CoreExpr@, the desugared output (main result).-\end{itemize}--The main actions of @matchWrapper@ include:-\begin{enumerate}-\item-Flatten the @[TypecheckedMatch]@ into a suitable list of-@EquationInfo@s.-\item-Create as many new variables as there are patterns in a pattern-list-(in any one of the @EquationInfo@s).-\item-Create a suitable ``if it fails'' expression---a call to @error@ using-the error-string input; the {\em type} of this fail value can be found-by examining one of the RHS expressions in one of the @EquationInfo@s.-\item-Call @match@ with all of this information!-\end{enumerate}--\begin{code}-matchWrapper :: HsMatchContext Name -- For shadowing warning messages- -> MatchGroup Id (LHsExpr Id) -- Matches being desugared- -> DsM ([Id], CoreExpr) -- Results-\end{code}-- There is one small problem with the Lambda Patterns, when somebody- writes something similar to:-\begin{verbatim}- (\ (x:xs) -> ...)-\end{verbatim}- he/she don't want a warning about incomplete patterns, that is done with- the flag @opt_WarnSimplePatterns@.- This problem also appears in the:-\begin{itemize}-\item @do@ patterns, but if the @do@ can fail- it creates another equation if the match can fail- (see @DsExpr.doDo@ function)-\item @let@ patterns, are treated by @matchSimply@- List Comprension Patterns, are treated by @matchSimply@ also-\end{itemize}--We can't call @matchSimply@ with Lambda patterns,-due to the fact that lambda patterns can have more than-one pattern, and match simply only accepts one pattern.--JJQC 30-Nov-1997--\begin{code}-matchWrapper ctxt (MG { mg_alts = matches- , mg_arg_tys = arg_tys- , mg_res_ty = rhs_ty- , mg_origin = origin })- = do { eqns_info <- mapM mk_eqn_info matches- ; new_vars <- case matches of- [] -> mapM newSysLocalDs arg_tys- (m:_) -> selectMatchVars (map unLoc (hsLMatchPats m))- ; result_expr <- handleWarnings $- matchEquations ctxt new_vars eqns_info rhs_ty- ; return (new_vars, result_expr) }- where- mk_eqn_info (L _ (Match pats _ grhss))- = do { let upats = map unLoc pats- ; match_result <- dsGRHSs ctxt upats grhss rhs_ty- ; return (EqnInfo { eqn_pats = upats, eqn_rhs = match_result}) }-- handleWarnings = if isGenerated origin- then discardWarningsDs- else id---matchEquations :: HsMatchContext Name- -> [Id] -> [EquationInfo] -> Type- -> DsM CoreExpr-matchEquations ctxt vars eqns_info rhs_ty- = do { locn <- getSrcSpanDs- ; let ds_ctxt = DsMatchContext ctxt locn- error_doc = matchContextErrString ctxt-- ; match_result <- matchCheck ds_ctxt vars rhs_ty eqns_info-- ; fail_expr <- mkErrorAppDs pAT_ERROR_ID rhs_ty error_doc- ; extractMatchResult match_result fail_expr }-\end{code}--%************************************************************************-%* *-\subsection[matchSimply]{@matchSimply@: match a single expression against a single pattern}-%* *-%************************************************************************--@mkSimpleMatch@ is a wrapper for @match@ which deals with the-situation where we want to match a single expression against a single-pattern. It returns an expression.--\begin{code}-matchSimply :: CoreExpr -- Scrutinee- -> HsMatchContext Name -- Match kind- -> LPat Id -- Pattern it should match- -> CoreExpr -- Return this if it matches- -> CoreExpr -- Return this if it doesn't- -> DsM CoreExpr--- Do not warn about incomplete patterns; see matchSinglePat comments-matchSimply scrut hs_ctx pat result_expr fail_expr = do- let- match_result = cantFailMatchResult result_expr- rhs_ty = exprType fail_expr- -- Use exprType of fail_expr, because won't refine in the case of failure!- match_result' <- matchSinglePat scrut hs_ctx pat rhs_ty match_result- extractMatchResult match_result' fail_expr--matchSinglePat :: CoreExpr -> HsMatchContext Name -> LPat Id- -> Type -> MatchResult -> DsM MatchResult--- Do not warn about incomplete patterns--- Used for things like [ e | pat <- stuff ], where--- incomplete patterns are just fine-matchSinglePat (Var var) ctx (L _ pat) ty match_result- = do { locn <- getSrcSpanDs- ; matchCheck (DsMatchContext ctx locn)- [var] ty- [EqnInfo { eqn_pats = [pat], eqn_rhs = match_result }] }--matchSinglePat scrut hs_ctx pat ty match_result- = do { var <- selectSimpleMatchVarL pat- ; match_result' <- matchSinglePat (Var var) hs_ctx pat ty match_result- ; return (adjustMatchResult (bindNonRec var scrut) match_result') }-\end{code}---%************************************************************************-%* *- Pattern classification-%* *-%************************************************************************--\begin{code}-data PatGroup- = PgAny -- Immediate match: variables, wildcards,- -- lazy patterns- | PgCon DataCon -- Constructor patterns (incl list, tuple)- | PgSyn PatSyn- | PgLit Literal -- Literal patterns- | PgN Literal -- Overloaded literals- | PgNpK Literal -- n+k patterns- | PgBang -- Bang patterns- | PgCo Type -- Coercion patterns; the type is the type- -- of the pattern *inside*- | PgView (LHsExpr Id) -- view pattern (e -> p):- -- the LHsExpr is the expression e- Type -- the Type is the type of p (equivalently, the result type of e)- | PgOverloadedList--groupEquations :: DynFlags -> [EquationInfo] -> [[(PatGroup, EquationInfo)]]--- If the result is of form [g1, g2, g3],--- (a) all the (pg,eq) pairs in g1 have the same pg--- (b) none of the gi are empty--- The ordering of equations is unchanged-groupEquations dflags eqns- = runs same_gp [(patGroup dflags (firstPat eqn), eqn) | eqn <- eqns]- where- same_gp :: (PatGroup,EquationInfo) -> (PatGroup,EquationInfo) -> Bool- (pg1,_) `same_gp` (pg2,_) = pg1 `sameGroup` pg2--subGroup :: Ord a => [(a, EquationInfo)] -> [[EquationInfo]]--- Input is a particular group. The result sub-groups the--- equations by with particular constructor, literal etc they match.--- Each sub-list in the result has the same PatGroup--- See Note [Take care with pattern order]-subGroup group- = map reverse $ Map.elems $ foldl accumulate Map.empty group- where- accumulate pg_map (pg, eqn)- = case Map.lookup pg pg_map of- Just eqns -> Map.insert pg (eqn:eqns) pg_map- Nothing -> Map.insert pg [eqn] pg_map-- -- pg_map :: Map a [EquationInfo]- -- Equations seen so far in reverse order of appearance-\end{code}--Note [Take care with pattern order]-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~-In the subGroup function we must be very careful about pattern re-ordering,-Consider the patterns [ (True, Nothing), (False, x), (True, y) ]-Then in bringing together the patterns for True, we must not-swap the Nothing and y!---\begin{code}-sameGroup :: PatGroup -> PatGroup -> Bool--- Same group means that a single case expression--- or test will suffice to match both, *and* the order--- of testing within the group is insignificant.-sameGroup PgAny PgAny = True-sameGroup PgBang PgBang = True-sameGroup (PgCon _) (PgCon _) = True -- One case expression-sameGroup (PgSyn p1) (PgSyn p2) = p1==p2-sameGroup (PgLit _) (PgLit _) = True -- One case expression-sameGroup (PgN l1) (PgN l2) = l1==l2 -- Order is significant-sameGroup (PgNpK l1) (PgNpK l2) = l1==l2 -- See Note [Grouping overloaded literal patterns]-sameGroup (PgCo t1) (PgCo t2) = t1 `eqType` t2- -- CoPats are in the same goup only if the type of the- -- enclosed pattern is the same. The patterns outside the CoPat- -- always have the same type, so this boils down to saying that- -- the two coercions are identical.-sameGroup (PgView e1 t1) (PgView e2 t2) = viewLExprEq (e1,t1) (e2,t2)- -- ViewPats are in the same group iff the expressions- -- are "equal"---conservatively, we use syntactic equality-sameGroup _ _ = False---- An approximation of syntactic equality used for determining when view--- exprs are in the same group.--- This function can always safely return false;--- but doing so will result in the application of the view function being repeated.------ Currently: compare applications of literals and variables--- and anything else that we can do without involving other--- HsSyn types in the recursion------ NB we can't assume that the two view expressions have the same type. Consider--- f (e1 -> True) = ...--- f (e2 -> "hi") = ...-viewLExprEq :: (LHsExpr Id,Type) -> (LHsExpr Id,Type) -> Bool-viewLExprEq (e1,_) (e2,_) = lexp e1 e2- where- lexp :: LHsExpr Id -> LHsExpr Id -> Bool- lexp e e' = exp (unLoc e) (unLoc e')-- ---------- exp :: HsExpr Id -> HsExpr Id -> Bool- -- real comparison is on HsExpr's- -- strip parens- exp (HsPar (L _ e)) e' = exp e e'- exp e (HsPar (L _ e')) = exp e e'- -- because the expressions do not necessarily have the same type,- -- we have to compare the wrappers- exp (HsWrap h e) (HsWrap h' e') = wrap h h' && exp e e'- exp (HsVar i) (HsVar i') = i == i'- -- the instance for IPName derives using the id, so this works if the- -- above does- exp (HsIPVar i) (HsIPVar i') = i == i'- exp (HsOverLit l) (HsOverLit l') =- -- Overloaded lits are equal if they have the same type- -- and the data is the same.- -- this is coarser than comparing the SyntaxExpr's in l and l',- -- which resolve the overloading (e.g., fromInteger 1),- -- because these expressions get written as a bunch of different variables- -- (presumably to improve sharing)- eqType (overLitType l) (overLitType l') && l == l'- exp (HsApp e1 e2) (HsApp e1' e2') = lexp e1 e1' && lexp e2 e2'- -- the fixities have been straightened out by now, so it's safe- -- to ignore them?- exp (OpApp l o _ ri) (OpApp l' o' _ ri') =- lexp l l' && lexp o o' && lexp ri ri'- exp (NegApp e n) (NegApp e' n') = lexp e e' && exp n n'- exp (SectionL e1 e2) (SectionL e1' e2') =- lexp e1 e1' && lexp e2 e2'- exp (SectionR e1 e2) (SectionR e1' e2') =- lexp e1 e1' && lexp e2 e2'- exp (ExplicitTuple es1 _) (ExplicitTuple es2 _) =- eq_list tup_arg es1 es2- exp (HsIf _ e e1 e2) (HsIf _ e' e1' e2') =- lexp e e' && lexp e1 e1' && lexp e2 e2'-- -- Enhancement: could implement equality for more expressions- -- if it seems useful- -- But no need for HsLit, ExplicitList, ExplicitTuple,- -- because they cannot be functions- exp _ _ = False-- ---------- tup_arg (Present e1) (Present e2) = lexp e1 e2- tup_arg (Missing t1) (Missing t2) = eqType t1 t2- tup_arg _ _ = False-- ---------- wrap :: HsWrapper -> HsWrapper -> Bool- -- Conservative, in that it demands that wrappers be- -- syntactically identical and doesn't look under binders- --- -- Coarser notions of equality are possible- -- (e.g., reassociating compositions,- -- equating different ways of writing a coercion)- wrap WpHole WpHole = True- wrap (WpCompose w1 w2) (WpCompose w1' w2') = wrap w1 w1' && wrap w2 w2'- wrap (WpCast co) (WpCast co') = co `eq_co` co'- wrap (WpEvApp et1) (WpEvApp et2) = et1 `ev_term` et2- wrap (WpTyApp t) (WpTyApp t') = eqType t t'- -- Enhancement: could implement equality for more wrappers- -- if it seems useful (lams and lets)- wrap _ _ = False-- ---------- ev_term :: EvTerm -> EvTerm -> Bool- ev_term (EvId a) (EvId b) = a==b- ev_term (EvCoercion a) (EvCoercion b) = a `eq_co` b- ev_term _ _ = False-- ---------- eq_list :: (a->a->Bool) -> [a] -> [a] -> Bool- eq_list _ [] [] = True- eq_list _ [] (_:_) = False- eq_list _ (_:_) [] = False- eq_list eq (x:xs) (y:ys) = eq x y && eq_list eq xs ys-- ---------- eq_co :: TcCoercion -> TcCoercion -> Bool- -- Just some simple cases (should the r1 == r2 rather be an ASSERT?)- eq_co (TcRefl r1 t1) (TcRefl r2 t2) = r1 == r2 && eqType t1 t2- eq_co (TcCoVarCo v1) (TcCoVarCo v2) = v1==v2- eq_co (TcSymCo co1) (TcSymCo co2) = co1 `eq_co` co2- eq_co (TcTyConAppCo r1 tc1 cos1) (TcTyConAppCo r2 tc2 cos2) = r1 == r2 && tc1==tc2 && eq_list eq_co cos1 cos2- eq_co _ _ = False--patGroup :: DynFlags -> Pat Id -> PatGroup-patGroup _ (WildPat {}) = PgAny-patGroup _ (BangPat {}) = PgBang-patGroup _ (ConPatOut { pat_con = con }) = case unLoc con of- RealDataCon dcon -> PgCon dcon- PatSynCon psyn -> PgSyn psyn-patGroup dflags (LitPat lit) = PgLit (hsLitKey dflags lit)-patGroup _ (NPat olit mb_neg _) = PgN (hsOverLitKey olit (isJust mb_neg))-patGroup _ (NPlusKPat _ olit _ _) = PgNpK (hsOverLitKey olit False)-patGroup _ (CoPat _ p _) = PgCo (hsPatType p) -- Type of innelexp pattern-patGroup _ (ViewPat expr p _) = PgView expr (hsPatType (unLoc p))-patGroup _ (ListPat _ _ (Just _)) = PgOverloadedList-patGroup _ pat = pprPanic "patGroup" (ppr pat)-\end{code}--Note [Grouping overloaded literal patterns]-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~-WATCH OUT! Consider-- f (n+1) = ...- f (n+2) = ...- f (n+1) = ...--We can't group the first and third together, because the second may match-the same thing as the first. Same goes for *overloaded* literal patterns- f 1 True = ...- f 2 False = ...- f 1 False = ...-If the first arg matches '1' but the second does not match 'True', we-cannot jump to the third equation! Because the same argument might-match '2'!-Hence we don't regard 1 and 2, or (n+1) and (n+2), as part of the same group.-
− src/Language/Haskell/Liquid/Desugar/Match.lhs-boot
@@ -1,35 +0,0 @@-\begin{code}-module Language.Haskell.Liquid.Desugar.Match where-import Var ( Id )-import TcType ( Type )-import DsMonad ( DsM, EquationInfo, MatchResult )-import CoreSyn ( CoreExpr )-import HsSyn ( LPat, HsMatchContext, MatchGroup, LHsExpr )-import Name ( Name )--match :: [Id]- -> Type- -> [EquationInfo]- -> DsM MatchResult--matchWrapper- :: HsMatchContext Name- -> MatchGroup Id (LHsExpr Id)- -> DsM ([Id], CoreExpr)--matchSimply- :: CoreExpr- -> HsMatchContext Name- -> LPat Id- -> CoreExpr- -> CoreExpr- -> DsM CoreExpr--matchSinglePat- :: CoreExpr- -> HsMatchContext Name- -> LPat Id- -> Type- -> MatchResult- -> DsM MatchResult-\end{code}
− src/Language/Haskell/Liquid/Desugar/MatchCon.lhs
@@ -1,293 +0,0 @@-%-% (c) The University of Glasgow 2006-% (c) The GRASP/AQUA Project, Glasgow University, 1992-1998-%--Pattern-matching constructors--\begin{code}-{-# OPTIONS -fno-warn-tabs #-}--- The above warning supression flag is a temporary kludge.--- While working on this module you are encouraged to remove it and--- detab the module (please do the detabbing in a separate patch). See--- http://ghc.haskell.org/trac/ghc/wiki/Commentary/CodingStyle#TabsvsSpaces--- for details--module Language.Haskell.Liquid.Desugar.MatchCon ( matchConFamily, matchPatSyn ) where---- #include "HsVersions.h"--import {-# SOURCE #-} Language.Haskell.Liquid.Desugar.Match ( match )--import HsSyn-import DsBinds-import ConLike-import DataCon-import PatSyn-import TcType-import DsMonad-import Language.Haskell.Liquid.Desugar.DsUtils-import MkCore ( mkCoreLets )-import Util-import ListSetOps ( runs )-import Id-import NameEnv-import SrcLoc-import DynFlags-import Outputable-import Control.Monad(liftM)-\end{code}--We are confronted with the first column of patterns in a set of-equations, all beginning with constructors from one ``family'' (e.g.,-@[]@ and @:@ make up the @List@ ``family''). We want to generate the-alternatives for a @Case@ expression. There are several choices:-\begin{enumerate}-\item-Generate an alternative for every constructor in the family, whether-they are used in this set of equations or not; this is what the Wadler-chapter does.-\begin{description}-\item[Advantages:]-(a)~Simple. (b)~It may also be that large sparsely-used constructor-families are mainly handled by the code for literals.-\item[Disadvantages:]-(a)~Not practical for large sparsely-used constructor families, e.g.,-the ASCII character set. (b)~Have to look up a list of what-constructors make up the whole family.-\end{description}--\item-Generate an alternative for each constructor used, then add a default-alternative in case some constructors in the family weren't used.-\begin{description}-\item[Advantages:]-(a)~Alternatives aren't generated for unused constructors. (b)~The-STG is quite happy with defaults. (c)~No lookup in an environment needed.-\item[Disadvantages:]-(a)~A spurious default alternative may be generated.-\end{description}--\item-``Do it right:'' generate an alternative for each constructor used,-and add a default alternative if all constructors in the family-weren't used.-\begin{description}-\item[Advantages:]-(a)~You will get cases with only one alternative (and no default),-which should be amenable to optimisation. Tuples are a common example.-\item[Disadvantages:]-(b)~Have to look up constructor families in TDE (as above).-\end{description}-\end{enumerate}--We are implementing the ``do-it-right'' option for now. The arguments-to @matchConFamily@ are the same as to @match@; the extra @Int@-returned is the number of constructors in the family.--The function @matchConFamily@ is concerned with this-have-we-used-all-the-constructors? question; the local function-@match_cons_used@ does all the real work.-\begin{code}-matchConFamily :: [Id]- -> Type- -> [[EquationInfo]]- -> DsM MatchResult--- Each group of eqns is for a single constructor-matchConFamily (var:vars) ty groups- = do dflags <- getDynFlags- alts <- mapM (fmap toRealAlt . matchOneConLike vars ty) groups- return (mkCoAlgCaseMatchResult dflags var ty alts)- where- toRealAlt alt = case alt_pat alt of- RealDataCon dcon -> alt{ alt_pat = dcon }- _ -> panic "matchConFamily: not RealDataCon"-matchConFamily [] _ _ = panic "matchConFamily []"--matchPatSyn :: [Id]- -> Type- -> [EquationInfo]- -> DsM MatchResult-matchPatSyn (var:vars) ty eqns- = do alt <- fmap toSynAlt $ matchOneConLike vars ty eqns- return (mkCoSynCaseMatchResult var ty alt)- where- toSynAlt alt = case alt_pat alt of- PatSynCon psyn -> alt{ alt_pat = psyn }- _ -> panic "matchPatSyn: not PatSynCon"-matchPatSyn _ _ _ = panic "matchPatSyn []"--type ConArgPats = HsConDetails (LPat Id) (HsRecFields Id (LPat Id))--matchOneConLike :: [Id]- -> Type- -> [EquationInfo]- -> DsM (CaseAlt ConLike)-matchOneConLike vars ty (eqn1 : eqns) -- All eqns for a single constructor- = do { arg_vars <- selectConMatchVars val_arg_tys args1- -- Use the first equation as a source of - -- suggestions for the new variables-- -- Divide into sub-groups; see Note [Record patterns]- ; let groups :: [[(ConArgPats, EquationInfo)]]- groups = runs compatible_pats [ (pat_args (firstPat eqn), eqn) - | eqn <- eqn1:eqns ]-- ; match_results <- mapM (match_group arg_vars) groups-- ; return $ MkCaseAlt{ alt_pat = con1,- alt_bndrs = tvs1 ++ dicts1 ++ arg_vars,- alt_wrapper = wrapper1,- alt_result = foldr1 combineMatchResults match_results } }- where- ConPatOut { pat_con = L _ con1, pat_arg_tys = arg_tys, pat_wrap = wrapper1,- pat_tvs = tvs1, pat_dicts = dicts1, pat_args = args1 }- = firstPat eqn1- fields1 = case con1 of- RealDataCon dcon1 -> dataConFieldLabels dcon1- PatSynCon{} -> []-- val_arg_tys = case con1 of- RealDataCon dcon1 -> dataConInstOrigArgTys dcon1 inst_tys- PatSynCon psyn1 -> patSynInstArgTys psyn1 inst_tys- inst_tys = -- ASSERT( tvs1 `equalLength` ex_tvs )- arg_tys ++ mkTyVarTys tvs1- -- dataConInstOrigArgTys takes the univ and existential tyvars- -- and returns the types of the *value* args, which is what we want---- ex_tvs = case con1 of--- RealDataCon dcon1 -> dataConExTyVars dcon1--- PatSynCon psyn1 -> patSynExTyVars psyn1-- match_group :: [Id] -> [(ConArgPats, EquationInfo)] -> DsM MatchResult- -- All members of the group have compatible ConArgPats- match_group arg_vars arg_eqn_prs- = -- ASSERT( notNull arg_eqn_prs )- do { (wraps, eqns') <- liftM unzip (mapM shift arg_eqn_prs)- ; let group_arg_vars = select_arg_vars arg_vars arg_eqn_prs- ; match_result <- match (group_arg_vars ++ vars) ty eqns'- ; return (adjustMatchResult (foldr1 (.) wraps) match_result) }-- shift (_, eqn@(EqnInfo { eqn_pats = ConPatOut{ pat_tvs = tvs, pat_dicts = ds, - pat_binds = bind, pat_args = args- } : pats }))- = do ds_bind <- dsTcEvBinds bind- return ( wrapBinds (tvs `zip` tvs1)- . wrapBinds (ds `zip` dicts1)- . mkCoreLets ds_bind- , eqn { eqn_pats = conArgPats val_arg_tys args ++ pats }- )- shift (_, (EqnInfo { eqn_pats = ps })) = pprPanic "matchOneCon/shift" (ppr ps)-- -- Choose the right arg_vars in the right order for this group- -- Note [Record patterns]- select_arg_vars arg_vars ((arg_pats, _) : _)- | RecCon flds <- arg_pats- , let rpats = rec_flds flds - , not (null rpats) -- Treated specially; cf conArgPats- = -- ASSERT2( length fields1 == length arg_vars, - -- ppr con1 $$ ppr fields1 $$ ppr arg_vars )- map lookup_fld rpats- | otherwise- = arg_vars- where- fld_var_env = mkNameEnv $ zipEqual "get_arg_vars" fields1 arg_vars- lookup_fld rpat = lookupNameEnv_NF fld_var_env - (idName (unLoc (hsRecFieldId rpat)))- select_arg_vars _ [] = panic "matchOneCon/select_arg_vars []"-matchOneConLike _ _ [] = panic "matchOneCon []"--------------------compatible_pats :: (ConArgPats,a) -> (ConArgPats,a) -> Bool--- Two constructors have compatible argument patterns if the number--- and order of sub-matches is the same in both cases-compatible_pats (RecCon flds1, _) (RecCon flds2, _) = same_fields flds1 flds2-compatible_pats (RecCon flds1, _) _ = null (rec_flds flds1)-compatible_pats _ (RecCon flds2, _) = null (rec_flds flds2)-compatible_pats _ _ = True -- Prefix or infix con--same_fields :: HsRecFields Id (LPat Id) -> HsRecFields Id (LPat Id) -> Bool-same_fields flds1 flds2 - = all2 (\f1 f2 -> unLoc (hsRecFieldId f1) == unLoc (hsRecFieldId f2))- (rec_flds flds1) (rec_flds flds2)---------------------selectConMatchVars :: [Type] -> ConArgPats -> DsM [Id]-selectConMatchVars arg_tys (RecCon {}) = newSysLocalsDs arg_tys-selectConMatchVars _ (PrefixCon ps) = selectMatchVars (map unLoc ps)-selectConMatchVars _ (InfixCon p1 p2) = selectMatchVars [unLoc p1, unLoc p2]--conArgPats :: [Type] -- Instantiated argument types - -- Used only to fill in the types of WildPats, which- -- are probably never looked at anyway- -> ConArgPats- -> [Pat Id]-conArgPats _arg_tys (PrefixCon ps) = map unLoc ps-conArgPats _arg_tys (InfixCon p1 p2) = [unLoc p1, unLoc p2]-conArgPats arg_tys (RecCon (HsRecFields { rec_flds = rpats }))- | null rpats = map WildPat arg_tys- -- Important special case for C {}, which can be used for a - -- datacon that isn't declared to have fields at all- | otherwise = map (unLoc . hsRecFieldArg) rpats-\end{code}--Note [Record patterns]-~~~~~~~~~~~~~~~~~~~~~~-Consider - data T = T { x,y,z :: Bool }-- f (T { y=True, x=False }) = ...--We must match the patterns IN THE ORDER GIVEN, thus for the first-one we match y=True before x=False. See Trac #246; or imagine -matching against (T { y=False, x=undefined }): should fail without-touching the undefined. --Now consider:-- f (T { y=True, x=False }) = ...- f (T { x=True, y= False}) = ...--In the first we must test y first; in the second we must test x -first. So we must divide even the equations for a single constructor-T into sub-goups, based on whether they match the same field in the-same order. That's what the (runs compatible_pats) grouping.--All non-record patterns are "compatible" in this sense, because the-positional patterns (T a b) and (a `T` b) all match the arguments-in order. Also T {} is special because it's equivalent to (T _ _).-Hence the (null rpats) checks here and there.---Note [Existentials in shift_con_pat]-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~-Consider- data T = forall a. Ord a => T a (a->Int)-- f (T x f) True = ...expr1...- f (T y g) False = ...expr2..--When we put in the tyvars etc we get-- f (T a (d::Ord a) (x::a) (f::a->Int)) True = ...expr1...- f (T b (e::Ord b) (y::a) (g::a->Int)) True = ...expr2...--After desugaring etc we'll get a single case:-- f = \t::T b::Bool -> - case t of- T a (d::Ord a) (x::a) (f::a->Int)) ->- case b of- True -> ...expr1...- False -> ...expr2...--*** We have to substitute [a/b, d/e] in expr2! **-Hence- False -> ....((/\b\(e:Ord b).expr2) a d)....--Originally I tried to use - (\b -> let e = d in expr2) a -to do this substitution. While this is "correct" in a way, it fails-Lint, because e::Ord b but d::Ord a. -
− src/Language/Haskell/Liquid/Desugar/MatchLit.lhs
@@ -1,468 +0,0 @@-%-% (c) The University of Glasgow 2006-% (c) The GRASP/AQUA Project, Glasgow University, 1992-1998-%--Pattern-matching literal patterns--\begin{code}-{-# LANGUAGE RankNTypes #-}--module Language.Haskell.Liquid.Desugar.MatchLit ( dsLit, dsOverLit, hsLitKey, hsOverLitKey- , tidyLitPat, tidyNPat- , matchLiterals, matchNPlusKPats, matchNPats- , warnAboutIdentities, warnAboutEmptyEnumerations - ) where---- #include "HsVersions.h"--import {-# SOURCE #-} Language.Haskell.Liquid.Desugar.Match ( match )-import {-# SOURCE #-} Language.Haskell.Liquid.Desugar.DsExpr ( dsExpr )--import DsMonad-import Language.Haskell.Liquid.Desugar.DsUtils--import HsSyn--import Id-import CoreSyn-import MkCore-import TyCon-import DataCon-import TcHsSyn ( shortCutLit )-import TcType-import Name-import Type-import PrelNames-import TysWiredIn-import Literal-import SrcLoc-import Data.Ratio-import MonadUtils-import Outputable-import BasicTypes-import DynFlags-import Util-import FastString--\end{code}--%************************************************************************-%* *- Desugaring literals- [used to be in DsExpr, but DsMeta needs it,- and it's nice to avoid a loop]-%* *-%************************************************************************--We give int/float literals type @Integer@ and @Rational@, respectively.-The typechecker will (presumably) have put \tr{from{Integer,Rational}s}-around them.--ToDo: put in range checks for when converting ``@i@''-(or should that be in the typechecker?)--For numeric literals, we try to detect there use at a standard type-(@Int@, @Float@, etc.) are directly put in the right constructor.-[NB: down with the @App@ conversion.]--See also below where we look for @DictApps@ for \tr{plusInt}, etc.--\begin{code}-dsLit :: HsLit -> DsM CoreExpr-dsLit (HsStringPrim s) = return (Lit (MachStr s))-dsLit (HsCharPrim c) = return (Lit (MachChar c))-dsLit (HsIntPrim i) = return (Lit (MachInt i))-dsLit (HsWordPrim w) = return (Lit (MachWord w))-dsLit (HsInt64Prim i) = return (Lit (MachInt64 i))-dsLit (HsWord64Prim w) = return (Lit (MachWord64 w))-dsLit (HsFloatPrim f) = return (Lit (MachFloat (fl_value f)))-dsLit (HsDoublePrim d) = return (Lit (MachDouble (fl_value d)))--dsLit (HsChar c) = return (mkCharExpr c)-dsLit (HsString str) = mkStringExprFS str-dsLit (HsInteger i _) = mkIntegerExpr i-dsLit (HsInt i) = do dflags <- getDynFlags- return (mkIntExpr dflags i)--dsLit (HsRat r ty) = do- num <- mkIntegerExpr (numerator (fl_value r))- denom <- mkIntegerExpr (denominator (fl_value r))- return (mkConApp ratio_data_con [Type integer_ty, num, denom])- where- (ratio_data_con, integer_ty)- = case tcSplitTyConApp ty of- (tycon, [i_ty]) -> -- ASSERT(isIntegerTy i_ty && tycon `hasKey` ratioTyConKey)- (head (tyConDataCons tycon), i_ty)- x -> pprPanic "dsLit" (ppr x)--dsOverLit :: HsOverLit Id -> DsM CoreExpr-dsOverLit lit = do { dflags <- getDynFlags- ; warnAboutOverflowedLiterals dflags lit- ; dsOverLit' dflags lit }--dsOverLit' :: DynFlags -> HsOverLit Id -> DsM CoreExpr--- Post-typechecker, the SyntaxExpr field of an OverLit contains--- (an expression for) the literal value itself-dsOverLit' dflags (OverLit { ol_val = val, ol_rebindable = rebindable- , ol_witness = witness, ol_type = ty })- | not rebindable- , Just expr <- shortCutLit dflags val ty = dsExpr expr -- Note [Literal short cut]- | otherwise = dsExpr witness-\end{code}--Note [Literal short cut]-~~~~~~~~~~~~~~~~~~~~~~~~-The type checker tries to do this short-cutting as early as possible, but-because of unification etc, more information is available to the desugarer.-And where it's possible to generate the correct literal right away, it's-much better to do so.---%************************************************************************-%* *- Warnings about overflowed literals-%* *-%************************************************************************--Warn about functions like toInteger, fromIntegral, that convert-between one type and another when the to- and from- types are the-same. Then it's probably (albeit not definitely) the identity--\begin{code}-warnAboutIdentities :: DynFlags -> CoreExpr -> Type -> DsM ()-warnAboutIdentities dflags (Var conv_fn) type_of_conv- | wopt Opt_WarnIdentities dflags- , idName conv_fn `elem` conversionNames- , Just (arg_ty, res_ty) <- splitFunTy_maybe type_of_conv- , arg_ty `eqType` res_ty -- So we are converting ty -> ty- = warnDs (vcat [ ptext (sLit "Call of") <+> ppr conv_fn <+> dcolon <+> ppr type_of_conv- , nest 2 $ ptext (sLit "can probably be omitted")- , parens (ptext (sLit "Use -fno-warn-identities to suppress this message"))- ])-warnAboutIdentities _ _ _ = return ()--conversionNames :: [Name]-conversionNames- = [ toIntegerName, toRationalName- , fromIntegralName, realToFracName ]- -- We can't easily add fromIntegerName, fromRationalName,- -- because they are generated by literals-\end{code}--\begin{code}-warnAboutOverflowedLiterals :: DynFlags -> HsOverLit Id -> DsM ()-warnAboutOverflowedLiterals _ _--- | wopt Opt_WarnOverflowedLiterals dflags--- , Just (i, tc) <- getIntegralLit lit--- = if tc == intTyConName then check i tc (undefined :: Int)--- else if tc == int8TyConName then check i tc (undefined :: Int8)--- else if tc == int16TyConName then check i tc (undefined :: Int16)--- else if tc == int32TyConName then check i tc (undefined :: Int32)--- else if tc == int64TyConName then check i tc (undefined :: Int64)--- else if tc == wordTyConName then check i tc (undefined :: Word)--- else if tc == word8TyConName then check i tc (undefined :: Word8)--- else if tc == word16TyConName then check i tc (undefined :: Word16)--- else if tc == word32TyConName then check i tc (undefined :: Word32)--- else if tc == word64TyConName then check i tc (undefined :: Word64)--- else return ()--- - | otherwise = return ()--- where--- check :: forall a. (Bounded a, Integral a) => Integer -> Name -> a -> DsM ()--- check i tc _proxy--- = when (i < minB || i > maxB) $ do--- warnDs (vcat [ ptext (sLit "Literal") <+> integer i--- <+> ptext (sLit "is out of the") <+> ppr tc <+> ptext (sLit "range")--- <+> integer minB <> ptext (sLit "..") <> integer maxB--- , sug ])--- where--- minB = toInteger (minBound :: a)--- maxB = toInteger (maxBound :: a)--- sug | minB == -i -- Note [Suggest NegativeLiterals]--- , i > 0--- , not (xopt Opt_NegativeLiterals dflags)--- = ptext (sLit "If you are trying to write a large negative literal, use NegativeLiterals")--- | otherwise = empty-\end{code}--Note [Suggest NegativeLiterals]-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~-If you write- x :: Int8- x = -128-it'll parse as (negate 128), and overflow. In this case, suggest NegativeLiterals.-We get an erroneous suggestion for- x = 128-but perhaps that does not matter too much.--\begin{code}-warnAboutEmptyEnumerations :: DynFlags -> LHsExpr Id -> Maybe (LHsExpr Id) -> LHsExpr Id -> DsM ()--- Warns about [2,3 .. 1] which returns the empty list--- Only works for integral types, not floating point-warnAboutEmptyEnumerations _ _ _ _--- | wopt Opt_WarnEmptyEnumerations dflags--- , Just (from,tc) <- getLHsIntegralLit fromExpr--- , Just mThn <- traverse getLHsIntegralLit mThnExpr--- , Just (to,_) <- getLHsIntegralLit toExpr--- , let check :: forall a. (Enum a, Num a) => a -> DsM ()--- check _proxy--- = when (null enumeration) $--- warnDs (ptext (sLit "Enumeration is empty"))--- where--- enumeration :: [a]--- enumeration = case mThn of--- Nothing -> [fromInteger from .. fromInteger to]--- Just (thn,_) -> [fromInteger from, fromInteger thn .. fromInteger to]--- --- = if tc == intTyConName then check (undefined :: Int)--- else if tc == int8TyConName then check (undefined :: Int8)--- else if tc == int16TyConName then check (undefined :: Int16)--- else if tc == int32TyConName then check (undefined :: Int32)--- else if tc == int64TyConName then check (undefined :: Int64)--- else if tc == wordTyConName then check (undefined :: Word)--- else if tc == word8TyConName then check (undefined :: Word8)--- else if tc == word16TyConName then check (undefined :: Word16)--- else if tc == word32TyConName then check (undefined :: Word32)--- else if tc == word64TyConName then check (undefined :: Word64)--- else return ()--- - | otherwise = return ()-{--getLHsIntegralLit :: LHsExpr Id -> Maybe (Integer, Name)--- See if the expression is an Integral literal--- Remember to look through automatically-added tick-boxes! (Trac #8384)-getLHsIntegralLit (L _ (HsPar e)) = getLHsIntegralLit e-getLHsIntegralLit (L _ (HsTick _ e)) = getLHsIntegralLit e-getLHsIntegralLit (L _ (HsBinTick _ _ e)) = getLHsIntegralLit e-getLHsIntegralLit (L _ (HsOverLit over_lit)) = getIntegralLit over_lit-getLHsIntegralLit _ = Nothing--getIntegralLit :: HsOverLit Id -> Maybe (Integer, Name)-getIntegralLit (OverLit { ol_val = HsIntegral i, ol_type = ty })- | Just tc <- tyConAppTyCon_maybe ty- = Just (i, tyConName tc)-getIntegralLit _ = Nothing--}-\end{code}---%************************************************************************-%* *- Tidying lit pats-%* *-%************************************************************************--\begin{code}-tidyLitPat :: HsLit -> Pat Id--- Result has only the following HsLits:--- HsIntPrim, HsWordPrim, HsCharPrim, HsFloatPrim--- HsDoublePrim, HsStringPrim, HsString--- * HsInteger, HsRat, HsInt can't show up in LitPats--- * We get rid of HsChar right here-tidyLitPat (HsChar c) = unLoc (mkCharLitPat c)-tidyLitPat (HsString s)- | lengthFS s <= 1 -- Short string literals only- = unLoc $ foldr (\c pat -> mkPrefixConPat consDataCon [mkCharLitPat c, pat] [charTy])- (mkNilPat charTy) (unpackFS s)- -- The stringTy is the type of the whole pattern, not- -- the type to instantiate (:) or [] with!-tidyLitPat lit = LitPat lit-------------------tidyNPat :: (HsLit -> Pat Id) -- How to tidy a LitPat- -- We need this argument because tidyNPat is called- -- both by Match and by Check, but they tidy LitPats- -- slightly differently; and we must desugar- -- literals consistently (see Trac #5117)- -> HsOverLit Id -> Maybe (SyntaxExpr Id) -> SyntaxExpr Id- -> Pat Id-tidyNPat tidy_lit_pat (OverLit val False _ ty) mb_neg _- -- False: Take short cuts only if the literal is not using rebindable syntax- --- -- Once that is settled, look for cases where the type of the- -- entire overloaded literal matches the type of the underlying literal,- -- and in that case take the short cut- -- NB: Watch out for weird cases like Trac #3382- -- f :: Int -> Int- -- f "blah" = 4- -- which might be ok if we hvae 'instance IsString Int'- ---- | isIntTy ty, Just int_lit <- mb_int_lit = mk_con_pat intDataCon (HsIntPrim int_lit)- | isWordTy ty, Just int_lit <- mb_int_lit = mk_con_pat wordDataCon (HsWordPrim int_lit)- | isFloatTy ty, Just rat_lit <- mb_rat_lit = mk_con_pat floatDataCon (HsFloatPrim rat_lit)- | isDoubleTy ty, Just rat_lit <- mb_rat_lit = mk_con_pat doubleDataCon (HsDoublePrim rat_lit)- | isStringTy ty, Just str_lit <- mb_str_lit = tidy_lit_pat (HsString str_lit)- where- mk_con_pat :: DataCon -> HsLit -> Pat Id- mk_con_pat con lit = unLoc (mkPrefixConPat con [noLoc $ LitPat lit] [])-- mb_int_lit :: Maybe Integer- mb_int_lit = case (mb_neg, val) of- (Nothing, HsIntegral i) -> Just i- (Just _, HsIntegral i) -> Just (-i)- _ -> Nothing-- mb_rat_lit :: Maybe FractionalLit- mb_rat_lit = case (mb_neg, val) of- (Nothing, HsIntegral i) -> Just (integralFractionalLit (fromInteger i))- (Just _, HsIntegral i) -> Just (integralFractionalLit (fromInteger (-i)))- (Nothing, HsFractional f) -> Just f- (Just _, HsFractional f) -> Just (negateFractionalLit f)- _ -> Nothing-- mb_str_lit :: Maybe FastString- mb_str_lit = case (mb_neg, val) of- (Nothing, HsIsString s) -> Just s- _ -> Nothing--tidyNPat _ over_lit mb_neg eq- = NPat over_lit mb_neg eq-\end{code}---%************************************************************************-%* *- Pattern matching on LitPat-%* *-%************************************************************************--\begin{code}-matchLiterals :: [Id]- -> Type -- Type of the whole case expression- -> [[EquationInfo]] -- All PgLits- -> DsM MatchResult--matchLiterals (var:vars) ty sub_groups- = -- ASSERT( notNull sub_groups && all notNull sub_groups )- do { -- Deal with each group- ; alts <- mapM match_group sub_groups-- -- Combine results. For everything except String- -- we can use a case expression; for String we need- -- a chain of if-then-else- ; if isStringTy (idType var) then- do { eq_str <- dsLookupGlobalId eqStringName- ; mrs <- mapM (wrap_str_guard eq_str) alts- ; return (foldr1 combineMatchResults mrs) }- else- return (mkCoPrimCaseMatchResult var ty alts)- }- where- match_group :: [EquationInfo] -> DsM (Literal, MatchResult)- match_group eqns- = do dflags <- getDynFlags- let LitPat hs_lit = firstPat (head eqns)- match_result <- match vars ty (shiftEqns eqns)- return (hsLitKey dflags hs_lit, match_result)-- wrap_str_guard :: Id -> (Literal,MatchResult) -> DsM MatchResult- -- Equality check for string literals- wrap_str_guard eq_str (MachStr s, mr)- = do { -- We now have to convert back to FastString. Perhaps there- -- should be separate MachBytes and MachStr constructors?- s' <- liftIO $ mkFastStringByteString s- ; lit <- mkStringExprFS s'- ; let pred = mkApps (Var eq_str) [Var var, lit]- ; return (mkGuardedMatchResult pred mr) }- wrap_str_guard _ (l, _) = pprPanic "matchLiterals/wrap_str_guard" (ppr l)--matchLiterals [] _ _ = panic "matchLiterals []"------------------------------hsLitKey :: DynFlags -> HsLit -> Literal--- Get a Core literal to use (only) a grouping key--- Hence its type doesn't need to match the type of the original literal--- (and doesn't for strings)--- It only works for primitive types and strings;--- others have been removed by tidy-hsLitKey dflags (HsIntPrim i) = mkMachInt dflags i-hsLitKey dflags (HsWordPrim w) = mkMachWord dflags w-hsLitKey _ (HsInt64Prim i) = mkMachInt64 i-hsLitKey _ (HsWord64Prim w) = mkMachWord64 w-hsLitKey _ (HsCharPrim c) = MachChar c-hsLitKey _ (HsStringPrim s) = MachStr s-hsLitKey _ (HsFloatPrim f) = MachFloat (fl_value f)-hsLitKey _ (HsDoublePrim d) = MachDouble (fl_value d)-hsLitKey _ (HsString s) = MachStr (fastStringToByteString s)-hsLitKey _ l = pprPanic "hsLitKey" (ppr l)------------------------------hsOverLitKey :: OutputableBndr a => HsOverLit a -> Bool -> Literal--- Ditto for HsOverLit; the boolean indicates to negate-hsOverLitKey (OverLit { ol_val = l }) neg = litValKey l neg------------------------------litValKey :: OverLitVal -> Bool -> Literal-litValKey (HsIntegral i) False = MachInt i-litValKey (HsIntegral i) True = MachInt (-i)-litValKey (HsFractional r) False = MachFloat (fl_value r)-litValKey (HsFractional r) True = MachFloat (negate (fl_value r))-litValKey (HsIsString s) _ = {- ASSERT( not neg) -} MachStr (fastStringToByteString s)-\end{code}--%************************************************************************-%* *- Pattern matching on NPat-%* *-%************************************************************************--\begin{code}-matchNPats :: [Id] -> Type -> [EquationInfo] -> DsM MatchResult-matchNPats (var:vars) ty (eqn1:eqns) -- All for the same literal- = do { let NPat lit mb_neg eq_chk = firstPat eqn1- ; lit_expr <- dsOverLit lit- ; neg_lit <- case mb_neg of- Nothing -> return lit_expr- Just neg -> do { neg_expr <- dsExpr neg- ; return (App neg_expr lit_expr) }- ; eq_expr <- dsExpr eq_chk- ; let pred_expr = mkApps eq_expr [Var var, neg_lit]- ; match_result <- match vars ty (shiftEqns (eqn1:eqns))- ; return (mkGuardedMatchResult pred_expr match_result) }-matchNPats vars _ eqns = pprPanic "matchOneNPat" (ppr (vars, eqns))-\end{code}---%************************************************************************-%* *- Pattern matching on n+k patterns-%* *-%************************************************************************--For an n+k pattern, we use the various magic expressions we've been given.-We generate:-\begin{verbatim}- if ge var lit then- let n = sub var lit- in <expr-for-a-successful-match>- else- <try-next-pattern-or-whatever>-\end{verbatim}---\begin{code}-matchNPlusKPats :: [Id] -> Type -> [EquationInfo] -> DsM MatchResult--- All NPlusKPats, for the *same* literal k-matchNPlusKPats (var:vars) ty (eqn1:eqns)- = do { let NPlusKPat (L _ n1) lit ge minus = firstPat eqn1- ; ge_expr <- dsExpr ge- ; minus_expr <- dsExpr minus- ; lit_expr <- dsOverLit lit- ; let pred_expr = mkApps ge_expr [Var var, lit_expr]- minusk_expr = mkApps minus_expr [Var var, lit_expr]- (wraps, eqns') = mapAndUnzip (shift n1) (eqn1:eqns)- ; match_result <- match vars ty eqns'- ; return (mkGuardedMatchResult pred_expr $- mkCoLetMatchResult (NonRec n1 minusk_expr) $- adjustMatchResult (foldr1 (.) wraps) $- match_result) }- where- shift n1 eqn@(EqnInfo { eqn_pats = NPlusKPat (L _ n) _ _ _ : pats })- = (wrapBind n n1, eqn { eqn_pats = pats })- -- The wrapBind is a no-op for the first equation- shift _ e = pprPanic "matchNPlusKPats/shift" (ppr e)--matchNPlusKPats vars _ eqns = pprPanic "matchNPlusKPats" (ppr (vars, eqns))-\end{code}
src/Language/Haskell/Liquid/Desugar710/Check.hs view
@@ -11,6 +11,7 @@ -- #include "HsVersions.h" +import Prelude hiding (error) import HsSyn import TcHsSyn import Language.Haskell.Liquid.Desugar710.DsUtils
src/Language/Haskell/Liquid/Desugar710/Coverage.hs view
@@ -7,6 +7,7 @@ module Language.Haskell.Liquid.Desugar710.Coverage (addTicksToBinds, hpcInitCode) where +import Prelude hiding (error) import Type import HsSyn import Module
src/Language/Haskell/Liquid/Desugar710/Desugar.hs view
@@ -10,6 +10,7 @@ module Language.Haskell.Liquid.Desugar710.Desugar ( deSugarWithLoc, deSugar, deSugarExpr ) where +import Prelude hiding (error) import DynFlags import HscTypes import HsSyn@@ -66,7 +67,7 @@ deSugarWithLoc, deSugar :: HscEnv -> ModLocation -> TcGblEnv -> IO (Messages, Maybe ModGuts) -- Can modify PCS by faulting in more declarations -deSugarWithLoc = deSugar +deSugarWithLoc = deSugar deSugar hsc_env mod_loc
src/Language/Haskell/Liquid/Desugar710/DsArrows.hs view
@@ -33,6 +33,7 @@ import CoreUtils import MkCore import Language.Haskell.Liquid.Desugar710.DsBinds (dsHsWrapper)+import qualified Language.Haskell.Liquid.Types.Errors as Err import Name import Var@@ -1084,7 +1085,7 @@ -- Balanced fold of a non-empty list. foldb :: (a -> a -> a) -> [a] -> a-foldb _ [] = error "foldb of empty list"+foldb _ [] = Err.panic Nothing "foldb of empty list" foldb _ [x] = x foldb f xs = foldb f (fold_pairs xs) where
src/Language/Haskell/Liquid/Desugar710/DsBinds.hs view
@@ -21,6 +21,7 @@ import {-# SOURCE #-} Language.Haskell.Liquid.Desugar710.DsExpr( dsLExpr ) import {-# SOURCE #-} Language.Haskell.Liquid.Desugar710.Match( matchWrapper ) +import Prelude hiding (error) import DsMonad import Language.Haskell.Liquid.Desugar710.DsGRHSs import Language.Haskell.Liquid.Desugar710.DsUtils
src/Language/Haskell/Liquid/Desugar710/DsCCall.hs view
@@ -17,7 +17,7 @@ -- #include "HsVersions.h" -+import Prelude hiding (error) import CoreSyn import DsMonad@@ -42,7 +42,6 @@ import VarSet import DynFlags import Outputable-import Util import Data.Maybe
src/Language/Haskell/Liquid/Desugar710/DsExpr.hs view
@@ -12,6 +12,7 @@ -- #include "HsVersions.h" +import Prelude hiding (error) import Language.Haskell.Liquid.Desugar710.Match import Language.Haskell.Liquid.Desugar710.MatchLit import Language.Haskell.Liquid.Desugar710.DsBinds@@ -23,7 +24,7 @@ import Name import NameEnv import FamInstEnv( topNormaliseType )-+import Language.Haskell.Liquid.Types.Errors (impossible) import HsSyn @@ -190,7 +191,7 @@ dsLExpr :: LHsExpr Id -> DsM CoreExpr -dsLExpr (L loc e) +dsLExpr (L loc e) = do ce <- putSrcSpanDs loc $ dsExpr e m <- getModule return $ Tick (srcSpanTick m loc) ce@@ -299,7 +300,7 @@ ; (lam_vars, args) <- foldM go ([], []) (reverse tup_args) -- The reverse is because foldM goes left-to-right - ; return $ mkCoreLams lam_vars $ + ; return $ mkCoreLams lam_vars $ mkConApp (tupleCon (boxityNormalTupleSort boxity) (length tup_args)) (map (Type . exprType) args ++ args) } @@ -899,7 +900,7 @@ ; fail_msg <- mkStringExpr (mk_fail_msg dflags pat) ; extractMatchResult match (App fail_op' fail_msg) } | otherwise- = extractMatchResult match (error "It can't fail")+ = extractMatchResult match (impossible Nothing "It can't fail") mk_fail_msg :: DynFlags -> Located e -> String mk_fail_msg dflags pat = "Pattern match failure in do expression at " ++
src/Language/Haskell/Liquid/Desugar710/DsForeign.hs view
@@ -18,7 +18,7 @@ -- #include "HsVersions.h" import TcRnMonad -- temp-+import Prelude hiding (error) import TypeRep import CoreSyn
src/Language/Haskell/Liquid/Desugar710/DsGRHSs.hs view
@@ -14,7 +14,7 @@ import {-# SOURCE #-} Language.Haskell.Liquid.Desugar710.DsExpr ( dsLExpr, dsLocalBinds ) import {-# SOURCE #-} Language.Haskell.Liquid.Desugar710.Match ( matchSinglePat )-+import Prelude hiding (error) import HsSyn import MkCore import CoreSyn
src/Language/Haskell/Liquid/Desugar710/DsListComp.hs view
@@ -14,6 +14,7 @@ import {-# SOURCE #-} Language.Haskell.Liquid.Desugar710.DsExpr ( dsExpr, dsLExpr, dsLocalBinds ) +import Prelude hiding (error) import HsSyn import TcHsSyn import CoreSyn@@ -21,6 +22,7 @@ import DsMonad -- the monadery used in the desugarer import Language.Haskell.Liquid.Desugar710.DsUtils+import Language.Haskell.Liquid.Types.Errors (impossible) import DynFlags import CoreUtils@@ -817,7 +819,7 @@ ; fail_msg <- mkStringExpr (mk_fail_msg dflags pat) ; extractMatchResult match (App fail_op' fail_msg) } | otherwise- = extractMatchResult match (error "It can't fail")+ = extractMatchResult match (impossible Nothing "It can't fail") mk_fail_msg :: DynFlags -> Located e -> String mk_fail_msg dflags pat
src/Language/Haskell/Liquid/Desugar710/DsMeta.hs view
@@ -28,7 +28,7 @@ -- #include "HsVersions.h" import Language.Haskell.Liquid.Desugar710.DsExpr ( dsExpr )-+import Prelude hiding (error) import Language.Haskell.Liquid.Desugar710.MatchLit import DsMonad @@ -912,7 +912,7 @@ repTy (HsTyLit lit) = do lit' <- repTyLit lit repTLit lit'- + repTy ty = notHandled "Exotic form of type" (ppr ty) repTyLit :: HsTyLit -> DsM (Core TH.TyLitQ)
src/Language/Haskell/Liquid/Desugar710/DsUtils.hs view
@@ -42,6 +42,7 @@ import {-# SOURCE #-} Language.Haskell.Liquid.Desugar710.Match ( matchSimply ) +import Prelude hiding (error) import HsSyn import TcHsSyn import Coercion( Coercion, isReflCo )@@ -49,6 +50,7 @@ import CoreSyn import DsMonad import {-# SOURCE #-} Language.Haskell.Liquid.Desugar710.DsExpr ( dsLExpr )+import Language.Haskell.Liquid.Types.Errors (impossible) import CoreUtils import MkCore@@ -192,7 +194,7 @@ extractMatchResult :: MatchResult -> CoreExpr -> DsM CoreExpr extractMatchResult (MatchResult CantFail match_fn) _- = match_fn (error "It can't fail!")+ = match_fn (impossible Nothing "It can't fail!") extractMatchResult (MatchResult CanFail match_fn) fail_expr = do (fail_bind, if_it_fails) <- mkFailurePair fail_expr
src/Language/Haskell/Liquid/Desugar710/HscMain.hs view
@@ -29,8 +29,8 @@ module Language.Haskell.Liquid.Desugar710.HscMain (hscDesugarWithLoc) where import Language.Haskell.Liquid.Desugar710.Desugar (deSugarWithLoc)--import Module +import Prelude hiding (error)+import Module import Lexer import TcRnMonad @@ -58,7 +58,7 @@ throwErrors :: ErrorMessages -> Hsc a throwErrors = liftIO . throwIO . mkSrcErr --- +-- -- | Convert a typechecked module to Core hscDesugarWithLoc :: HscEnv -> ModSummary -> TcGblEnv -> IO ModGuts hscDesugarWithLoc hsc_env mod_summary tc_result =
src/Language/Haskell/Liquid/Desugar710/Match.hs view
@@ -13,7 +13,7 @@ -- #include "HsVersions.h" import {-#SOURCE#-} Language.Haskell.Liquid.Desugar710.DsExpr (dsLExpr, dsExpr)-+import Prelude hiding (error) import DynFlags import HsSyn import TcHsSyn
src/Language/Haskell/Liquid/Desugar710/MatchCon.hs view
@@ -13,7 +13,7 @@ -- #include "HsVersions.h" import {-# SOURCE #-} Language.Haskell.Liquid.Desugar710.Match ( match )-+import Prelude hiding (error) import HsSyn import DsBinds import ConLike
src/Language/Haskell/Liquid/Desugar710/MatchLit.hs view
@@ -19,7 +19,7 @@ import {-# SOURCE #-} Language.Haskell.Liquid.Desugar710.Match ( match ) import {-# SOURCE #-} Language.Haskell.Liquid.Desugar710.DsExpr ( dsExpr )-+import Prelude hiding (error) import DsMonad import Language.Haskell.Liquid.Desugar710.DsUtils
− src/Language/Haskell/Liquid/Dictionaries.hs
@@ -1,65 +0,0 @@-module Language.Haskell.Liquid.Dictionaries (- makeDictionaries- , makeDictionary-- , dfromList- , dmapty- , dmap- , dinsert- , dlookup- , dhasinfo- ) where--import Control.Applicative ((<$>))--import Var---import Language.Fixpoint.Names (dropModuleNames)-import Language.Fixpoint.Types-import Language.Fixpoint.Misc--import Language.Haskell.Liquid.GhcMisc ()-import Language.Haskell.Liquid.Types--import qualified Data.HashMap.Strict as M-import Language.Haskell.Liquid.PrettyPrint ()--makeDictionaries :: [RInstance SpecType] -> DEnv Symbol SpecType-makeDictionaries = DEnv . M.fromList . map makeDictionary---makeDictionary :: RInstance SpecType -> (Symbol, M.HashMap Symbol SpecType)-makeDictionary (RI c t xts) = (makeDictionaryName c t, M.fromList (mapFst val <$> xts))--makeDictionaryName :: Located Symbol -> SpecType -> Symbol-makeDictionaryName t (RApp c _ _ _) = symbol ("$f" ++ (symbolString $ val t) ++ c')- where- c' = symbolString (dropModuleNames $ symbol $ rtc_tc c)--makeDictionaryName _ _ = errorstar "makeDictionaryName: called with invalid type"---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Dictionay Environment ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------dfromList :: [(Var, M.HashMap Symbol t)] -> DEnv Var t-dfromList = DEnv . M.fromList--dmapty :: (a -> b) -> DEnv v a -> DEnv v b-dmapty f (DEnv e) = DEnv (M.map (M.map f) e)--dmap f xts = M.map f xts--dinsert (DEnv denv) x xts = DEnv $ M.insert x xts denv--dlookup (DEnv denv) x = M.lookup x denv---dhasinfo Nothing _ = Nothing-dhasinfo (Just xts) x = M.lookup x' xts- where- x' = (dropModuleNames $ symbol $ show x)
− src/Language/Haskell/Liquid/DiffCheck.hs
@@ -1,459 +0,0 @@--- | This module contains the code for Incremental checking, which finds the--- part of a target file (the subset of the @[CoreBind]@ that have been--- modified since it was last checked, as determined by a diff against--- a saved version of the file.--{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE FlexibleInstances #-}--module Language.Haskell.Liquid.DiffCheck (-- -- * Changed binders + Unchanged Errors- DiffCheck (..)-- -- * Use previously saved info to generate DiffCheck target- , slice-- -- * Use target binders to generate DiffCheck target- , thin-- -- * Save current information for next time- , saveResult-- )- where---- import Debug.Trace (trace)-import Control.Applicative ((<$>), (<*>))-import Data.Aeson-import qualified Data.Text as T-import Data.Algorithm.Diff-import Data.Monoid (mempty)-import Data.Maybe (listToMaybe, mapMaybe, fromMaybe)-import Data.Hashable-import qualified Data.IntervalMap.FingerTree as IM-import CoreSyn hiding (sourceName)-import Name-import SrcLoc hiding (Located)-import Var-import qualified Data.HashSet as S-import qualified Data.HashMap.Strict as M-import qualified Data.List as L-import System.Directory (copyFile, doesFileExist)-import Language.Fixpoint.Misc (mkGraph)-import Language.Fixpoint.Types (FixResult (..), Located (..))-import Language.Fixpoint.Files-import Language.Haskell.Liquid.Types (SpecType, GhcSpec (..), AnnInfo (..), DataConP (..), Error, TError (..), Output (..))-import Language.Haskell.Liquid.GhcMisc-import Language.Haskell.Liquid.Visitors-import Language.Haskell.Liquid.Errors ()-import Text.Parsec.Pos (sourceName, sourceLine, sourceColumn, SourcePos, newPos)-import Text.PrettyPrint.HughesPJ (text, render, Doc)---import qualified Data.ByteString as B-import qualified Data.ByteString.Lazy as LB------------------------------------------------------------------------------- Data Types ----------------------------------------------------------------------------------------------------------------------------------------- | Main type of value returned for diff-check.-data DiffCheck = DC { newBinds :: [CoreBind]- , oldOutput :: !(Output Doc)- , newSpec :: !GhcSpec- }---- | Variable definitions-data Def = D { start :: Int -- ^ line at which binder definition starts- , end :: Int -- ^ line at which binder definition ends- , binder :: Var -- ^ name of binder- }- deriving (Eq, Ord)---- | Variable dependencies "call-graph"-type Deps = M.HashMap Var (S.HashSet Var)---- | Map from saved-line-num ---> current-line-num-type LMap = IM.IntervalMap Int Int---- | Intervals of line numbers that have been re-checked-type ChkItv = IM.IntervalMap Int ()--instance Show Def where- show (D i j x) = showPpr x ++ " start: " ++ show i ++ " end: " ++ show j-------------------------------------------------------------------------------- | `slice` returns a subset of the @[CoreBind]@ of the input `target`--- file which correspond to top-level binders whose code has changed--- and their transitive dependencies.---------------------------------------------------------------------------slice :: FilePath -> [CoreBind] -> GhcSpec -> IO (Maybe DiffCheck)---------------------------------------------------------------------------slice target cbs sp = ifM (doesFileExist saved) dc (return Nothing)- where- saved = extFileName Saved target- dc = sliceSaved target saved cbs sp--sliceSaved :: FilePath -> FilePath -> [CoreBind] -> GhcSpec -> IO (Maybe DiffCheck)-sliceSaved target saved cbs sp- = do (is, lm) <- lineDiff target saved- res <- loadResult target- return $ sliceSaved' is lm (DC cbs res sp)--sliceSaved' :: [Int] -> LMap -> DiffCheck -> Maybe DiffCheck-sliceSaved' is lm (DC cbs res sp)- | globalDiff is sp = Nothing- | otherwise = Just $ DC cbs' res' sp'- where- cbs' = thinWith sigs cbs $ diffVars is dfs- sigs = S.fromList $ M.keys sigm- sigm = sigVars is sp- res' = adjustOutput lm cm res- cm = checkedItv chDfs- dfs = coreDefs cbs ++ specDefs sp- chDfs = coreDefs cbs'- sp' = assumeSpec sigm sp---- Add the specified signatures for vars-with-preserved-sigs,--- whose bodies have been pruned from [CoreBind] into the "assumes"-assumeSpec :: M.HashMap Var (Located SpecType) -> GhcSpec -> GhcSpec-assumeSpec sigm sp = sp { asmSigs = M.toList $ M.union sigm assm }- where- assm = M.fromList $ asmSigs sp- -- sigm' = trace ("INCCHECK: sigm = " ++ show zs) sigm- -- zs = M.keys sigm--diffVars :: [Int] -> [Def] -> [Var]-diffVars ls defs' = -- tracePpr ("INCCHECK: diffVars lines = " ++ show ls ++ " defs= " ++ show defs) $- go (L.sort ls) defs- where- defs = L.sort defs'- go _ [] = []- go [] _ = []- go (i:is) (d:ds)- | i < start d = go is (d:ds)- | i > end d = go (i:is) ds- | otherwise = binder d : go (i:is) ds--sigVars :: [Int] -> GhcSpec -> M.HashMap Var (Located SpecType)-sigVars ls sp = M.fromList $ filter (ok . snd) $ specSigs sp- where- ok = not . isDiff ls--globalDiff :: [Int] -> GhcSpec -> Bool-globalDiff ls sp = measDiff || invsDiff || dconsDiff- where- measDiff = any (isDiff ls) (snd <$> meas sp)- invsDiff = any (isDiff ls) (invariants sp)- dconsDiff = any (isDiff ls) (dloc . snd <$> dconsP sp)- dloc dc = Loc (dc_loc dc) (dc_locE dc) ()--isDiff :: [Int] -> Located a -> Bool-isDiff ls x = any hits ls- where- hits i = line x <= i && i <= lineE x------------------------------------------------------------------------------ | @thin@ returns a subset of the @[CoreBind]@ given which correspond--- to those binders that depend on any of the @Var@s provided.---------------------------------------------------------------------------thin :: [CoreBind] -> [Var] -> [CoreBind]---------------------------------------------------------------------------thin = thinWith S.empty--thinWith :: S.HashSet Var -> [CoreBind] -> [Var] -> [CoreBind]-thinWith sigs cbs xs = filterBinds cbs ys- where- ys = txClosure (coreDeps cbs) sigs (S.fromList xs)--coreDeps :: [CoreBind] -> Deps-coreDeps bs = mkGraph $ calls ++ calls'- where- calls = concatMap deps bs- calls' = [(y, x) | (x, y) <- calls]- deps b = [(x, y) | x <- bindersOf b- , y <- freeVars S.empty b]----txClosure :: Deps -> S.HashSet Var -> S.HashSet Var -> S.HashSet Var-txClosure d sigs xs = go S.empty xs- where- next = S.unions . fmap deps . S.toList- deps x = M.lookupDefault S.empty x d- go seen new- | S.null new = seen- | otherwise = let seen' = S.union seen new- new' = next new `S.difference` seen'- new'' = new' `S.difference` sigs- in go seen' new''------------------------------------------------------------------------------filterBinds :: [CoreBind] -> S.HashSet Var -> [CoreBind]---------------------------------------------------------------------------filterBinds cbs ys = filter f cbs- where- f (NonRec x _) = x `S.member` ys- f (Rec xes) = any (`S.member` ys) $ fst <$> xes-----------------------------------------------------------------------------specDefs :: GhcSpec -> [Def]---------------------------------------------------------------------------specDefs = map def . specSigs- where- def (x, t) = D (line t) (lineE t) x--specSigs :: GhcSpec -> [(Var, Located SpecType)]-specSigs sp = tySigs sp ++ asmSigs sp ++ ctors sp----------------------------------------------------------------------------coreDefs :: [CoreBind] -> [Def]---------------------------------------------------------------------------coreDefs cbs = L.sort [D l l' x | b <- cbs- , x <- bindersOf b- , isGoodSrcSpan (getSrcSpan x)- , (l, l') <- coreDef b]-coreDef b = meetSpans b eSp vSp- where- eSp = lineSpan b $ catSpans b $ bindSpans b- vSp = lineSpan b $ catSpans b $ getSrcSpan <$> bindersOf b------------------------------------------------------------------------------- | `meetSpans` cuts off the start-line to be no less than the line at which--- the binder is defined. Without this, i.e. if we ONLY use the ticks and--- spans appearing inside the definition of the binder (i.e. just `eSp`)--- then the generated span can be WAY before the actual definition binder,--- possibly due to GHC INLINE pragmas or dictionaries OR ...--- for an example: see the "INCCHECK: Def" generated by--- liquid -d benchmarks/bytestring-0.9.2.1/Data/ByteString.hs--- where `spanEnd` is a single line function around 1092 but where--- the generated span starts mysteriously at 222 where Data.List is imported.--meetSpans _ Nothing _- = []-meetSpans _ (Just (l,l')) Nothing- = [(l, l')]-meetSpans _ (Just (l,l')) (Just (m,_))- = [(max l m, l')]--lineSpan _ (RealSrcSpan sp) = Just (srcSpanStartLine sp, srcSpanEndLine sp)-lineSpan _ _ = Nothing--catSpans b [] = error $ "DIFFCHECK: catSpans: no spans found for " ++ showPpr b-catSpans b xs = foldr combineSrcSpans noSrcSpan [x | x@(RealSrcSpan z) <- xs, bindFile b == srcSpanFile z]--bindFile (NonRec x _) = varFile x-bindFile (Rec xes) = varFile $ fst $ head xes--varFile b = case getSrcSpan b of- RealSrcSpan z -> srcSpanFile z- _ -> error $ "DIFFCHECK: getFile: no file found for: " ++ showPpr b---bindSpans (NonRec x e) = getSrcSpan x : exprSpans e-bindSpans (Rec xes) = map getSrcSpan xs ++ concatMap exprSpans es- where- (xs, es) = unzip xes--exprSpans (Tick t e)- | isJunkSpan sp = exprSpans e- | otherwise = [sp]- where- sp = tickSrcSpan t--exprSpans (Var x) = [getSrcSpan x]-exprSpans (Lam x e) = getSrcSpan x : exprSpans e-exprSpans (App e a) = exprSpans e ++ exprSpans a-exprSpans (Let b e) = bindSpans b ++ exprSpans e-exprSpans (Cast e _) = exprSpans e-exprSpans (Case e x _ cs) = getSrcSpan x : exprSpans e ++ concatMap altSpans cs-exprSpans _ = []--altSpans (_, xs, e) = map getSrcSpan xs ++ exprSpans e--isJunkSpan (RealSrcSpan _) = False-isJunkSpan _ = True------------------------------------------------------------------------------ | Diff Interface ------------------------------------------------------------------------------------------------------------------------------------ | `lineDiff new old` compares the contents of `src` with `dst`--- and returns the lines of `src` that are different.---------------------------------------------------------------------------lineDiff :: FilePath -> FilePath -> IO ([Int], LMap)---------------------------------------------------------------------------lineDiff new old = lineDiff' <$> getLines new <*> getLines old- where- getLines = fmap lines . readFile--lineDiff' :: [String] -> [String] -> ([Int], LMap)-lineDiff' new old = (ns, lm)- where- ns = diffLines 1 diff- lm = foldr setShift IM.empty $ diffShifts diff- diff = fmap length <$> getGroupedDiff new old--diffLines _ [] = []-diffLines n (Both i _ : d) = diffLines n' d where n' = n + i -- length ls-diffLines n (First i : d) = [n .. (n' - 1)] ++ diffLines n' d where n' = n + i -- length ls-diffLines n (Second _ : d) = diffLines n d--diffShifts :: [Diff Int] -> [(Int, Int, Int)]-diffShifts = go 1 1- where- go old new (Both n _ : d) = (old, old + n - 1, new - old) : go (old + n) (new + n) d- go old new (Second n : d) = go (old + n) new d- go old new (First n : d) = go old (new + n) d- go _ _ [] = []--instance Functor Diff where- fmap f (First x) = First (f x)- fmap f (Second x) = Second (f x)- fmap f (Both x y) = Both (f x) (f y)---- | @save@ creates an .saved version of the @target@ file, which will be--- used to find what has changed the /next time/ @target@ is checked.---------------------------------------------------------------------------saveResult :: FilePath -> Output Doc -> IO ()---------------------------------------------------------------------------saveResult target res- = do copyFile target saveF- B.writeFile errF $ LB.toStrict $ encode res- where- saveF = extFileName Saved target- errF = extFileName Cache target----------------------------------------------------------------------------loadResult :: FilePath -> IO (Output Doc)---------------------------------------------------------------------------loadResult f = ifM (doesFileExist jsonF) out (return mempty)- where- jsonF = extFileName Cache f- out = (fromMaybe mempty . decode . LB.fromStrict) <$> B.readFile jsonF----------------------------------------------------------------------------adjustOutput :: LMap -> ChkItv -> Output Doc -> Output Doc---------------------------------------------------------------------------adjustOutput lm cm o = mempty { o_types = adjustTypes lm cm (o_types o) }- { o_result = adjustResult lm cm (o_result o) }--adjustTypes :: LMap -> ChkItv -> AnnInfo a -> AnnInfo a-adjustTypes lm cm (AI m) = AI $ M.fromList- [(sp', v) | (sp, v) <- M.toList m- , Just sp' <- [adjustSrcSpan lm cm sp]]--adjustResult :: LMap -> ChkItv -> FixResult Error -> FixResult Error-adjustResult lm cm (Unsafe es) = errorsResult Unsafe $ adjustErrors lm cm es-adjustResult lm cm (Crash es z) = errorsResult (`Crash` z) $ adjustErrors lm cm es-adjustResult _ _ r = r--errorsResult :: ([a] -> FixResult b) -> [a] -> FixResult b-errorsResult _ [] = Safe-errorsResult f es = f es--adjustErrors :: LMap -> ChkItv -> [TError a] -> [TError a]-adjustErrors lm cm = mapMaybe adjustError- where- adjustError (ErrSaved sp m) = (`ErrSaved` m) <$> adjustSrcSpan lm cm sp- adjustError e = Just e----------------------------------------------------------------------------adjustSrcSpan :: LMap -> ChkItv -> SrcSpan -> Maybe SrcSpan---------------------------------------------------------------------------adjustSrcSpan lm cm sp- = do sp' <- adjustSpan lm sp- if isCheckedSpan cm sp'- then Nothing- else Just sp'--isCheckedSpan cm (RealSrcSpan sp) = isCheckedRealSpan cm sp-isCheckedSpan _ _ = False-isCheckedRealSpan cm = not . null . (`IM.search` cm) . srcSpanStartLine--adjustSpan lm (RealSrcSpan rsp) = RealSrcSpan <$> adjustReal lm rsp-adjustSpan _ sp = Just sp-adjustReal lm rsp- | Just δ <- getShift l1 lm = Just $ realSrcSpan f (l1 + δ) c1 (l2 + δ) c2- | otherwise = Nothing- where- (f, l1, c1, l2, c2) = unpackRealSrcSpan rsp----- | @getShift lm old@ returns @Just δ@ if the line number @old@ shifts by @δ@--- in the diff and returns @Nothing@ otherwise.-getShift :: Int -> LMap -> Maybe Int-getShift old = fmap snd . listToMaybe . IM.search old---- | @setShift (lo, hi, δ) lm@ updates the interval map @lm@ appropriately-setShift :: (Int, Int, Int) -> LMap -> LMap-setShift (l1, l2, δ) = IM.insert (IM.Interval l1 l2) δ---checkedItv :: [Def] -> ChkItv-checkedItv chDefs = foldr (`IM.insert` ()) IM.empty is- where- is = [IM.Interval l1 l2 | D l1 l2 _ <- chDefs]---ifM b x y = b >>= \z -> if z then x else y------------------------------------------------------------------------------ | Aeson instances --------------------------------------------------------------------------------------------------------------------------------instance ToJSON SourcePos where- toJSON p = object [ "sourceName" .= f- , "sourceLine" .= l- , "sourceColumn" .= c- ]- where- f = sourceName p- l = sourceLine p- c = sourceColumn p--instance FromJSON SourcePos where- parseJSON (Object v) = newPos <$> v .: "sourceName"- <*> v .: "sourceLine"- <*> v .: "sourceColumn"- parseJSON _ = mempty---instance ToJSON (FixResult Error)-instance FromJSON (FixResult Error)--instance ToJSON Doc where- toJSON = String . T.pack . render--instance FromJSON Doc where- parseJSON (String s) = return $ text $ T.unpack s- parseJSON _ = mempty--instance (ToJSON k, ToJSON v) => ToJSON (M.HashMap k v) where- toJSON = toJSON . M.toList--instance (Eq k, Hashable k, FromJSON k, FromJSON v) => FromJSON (M.HashMap k v) where- parseJSON = fmap M.fromList . parseJSON--instance ToJSON a => ToJSON (AnnInfo a)-instance FromJSON a => FromJSON (AnnInfo a)--instance ToJSON (Output Doc)-instance FromJSON (Output Doc)---line :: Located a -> Int-line = sourceLine . loc--lineE :: Located a -> Int-lineE = sourceLine . locE
− src/Language/Haskell/Liquid/Errors.hs
@@ -1,304 +0,0 @@--{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE OverloadedStrings #-}---- | This module contains the functions related to @Error@ type,--- in particular, to @tidyError@ using a solution, and @pprint@ errors.--module Language.Haskell.Liquid.Errors (tidyError, exitWithPanic) where---import Control.Applicative ((<$>), (<*>))-import Control.Arrow (second)-import Control.Exception (Exception (..))-import Data.Aeson-import Data.Generics (everywhere, mkT)-import qualified Data.HashMap.Strict as M-import qualified Data.HashSet as S-import Data.Hashable-import Data.List (intersperse)-import Data.Maybe (fromMaybe, maybeToList)-import Data.Monoid hiding ((<>))-import Language.Fixpoint.Misc hiding (intersperse)-import Language.Fixpoint.Types hiding (shiftVV)-import Language.Haskell.Liquid.PrettyPrint-import Language.Haskell.Liquid.RefType-import Language.Haskell.Liquid.Simplify-import Language.Haskell.Liquid.Tidy-import Language.Haskell.Liquid.Types-import SrcLoc (SrcSpan)-import Text.PrettyPrint.HughesPJ-import qualified Control.Exception as Ex--type Ctx = M.HashMap Symbol SpecType---------------------------------------------------------------------------tidyError :: FixSolution -> Error -> Error--------------------------------------------------------------------------tidyError sol- = fmap (tidySpecType Full)- . tidyErrContext sol- . applySolution sol--tidyErrContext _ err@(ErrSubType {})- = err { ctx = c', tact = subst θ tA, texp = subst θ tE }- where- (θ, c') = tidyCtx xs $ ctx err- xs = syms tA ++ syms tE- tA = tact err- tE = texp err--tidyErrContext _ err- = err------------------------------------------------------------------------------------tidyCtx :: [Symbol] -> Ctx -> (Subst, Ctx)-----------------------------------------------------------------------------------tidyCtx xs m = (θ, M.fromList yts)- where- yts = [tBind x t | (x, t) <- xts]- (θ, xts) = tidyTemps $ second stripReft <$> tidyREnv xs m- tBind x t = (x', shiftVV t x') where x' = tidySymbol x---stripReft :: SpecType -> SpecType-stripReft t = maybe t' (strengthen t') ro- where- (t', ro) = stripRType t--stripRType :: SpecType -> (SpecType, Maybe RReft)-stripRType st = (t', ro)- where- t' = fmap (const (uTop mempty)) t- ro = stripRTypeBase t- t = simplifyBounds st--tidyREnv :: [Symbol] -> M.HashMap Symbol SpecType -> [(Symbol, SpecType)]-tidyREnv xs m = [(x, t) | x <- xs', t <- maybeToList (M.lookup x m), ok t]- where- xs' = expandFix deps xs- deps y = fromMaybe [] $ fmap (syms . rTypeReft) $ M.lookup y m- ok = not . isFunTy--expandFix :: (Eq a, Hashable a) => (a -> [a]) -> [a] -> [a]-expandFix f xs = S.toList $ go S.empty xs- where- go seen [] = seen- go seen (x:xs)- | x `S.member` seen = go seen xs- | otherwise = go (S.insert x seen) (f x ++ xs)--tidyTemps :: (Subable t) => [(Symbol, t)] -> (Subst, [(Symbol, t)])-tidyTemps xts = (θ, [(txB x, txTy t) | (x, t) <- xts])- where- txB x = M.lookupDefault x x m- txTy = subst θ- m = M.fromList yzs- θ = mkSubst [(y, EVar z) | (y, z) <- yzs]- yzs = zip ys niceTemps- ys = [ x | (x,_) <- xts, isTmpSymbol x]--niceTemps :: [Symbol]-niceTemps = mkSymbol <$> xs ++ ys- where- mkSymbol = symbol . ('?' :)- xs = single <$> ['a' .. 'z']- ys = ("a" ++) <$> [show n | n <- [0 ..]]------------------------------------------------------------------------------ | Pretty Printing Error Messages ----------------------------------------------------------------------------------------------------------------- | Need to put @PPrint Error@ instance here (instead of in Types),--- as it depends on @PPrint SpecTypes@, which lives in this module.--instance PPrint Error where- pprint = pprintTidy Full- pprintTidy k = ppError k . fmap ppSpecTypeErr--ppSpecTypeErr :: SpecType -> Doc-ppSpecTypeErr- = rtypeDoc Lossy . tidySpecType Lossy . fmap (everywhere (mkT noCasts))- where- noCasts (ECst x _) = x- noCasts e = e---- full = isNontrivialVV $ rTypeValueVar t =--instance Show Error where- show = showpp--instance Exception Error-instance Exception [Error]---------------------------------------------------------------------------ppError :: (PPrint a, Show a) => Tidy -> TError a -> Doc---------------------------------------------------------------------------ppError k e = ppError' k (pprintE $ errSpan e) e-pprintE l = pprint l <> text ": Error:"--nests n = foldr (\d acc -> nest n (d $+$ acc)) empty--sepVcat d ds = vcat $ intersperse d ds-blankLine = sizedText 5 " "---------------------------------------------------------------------------ppError' :: (PPrint a, Show a) => Tidy -> Doc -> TError a -> Doc--------------------------------------------------------------------------ppError' _ dSp (ErrAssType _ OCons _ _)- = dSp <+> text "Constraint Check"--ppError' _ dSp (ErrAssType _ OTerm _ _)- = dSp <+> text "Termination Check"--ppError' _ dSp (ErrAssType _ OInv _ _)- = dSp <+> text "Invariant Check"--ppError' Lossy dSp (ErrSubType _ _ _ _ _)- = dSp <+> text "Liquid Type Mismatch"--ppError' Full dSp (ErrSubType _ _ c tA tE)- = dSp <+> text "Liquid Type Mismatch"- $+$ sepVcat blankLine- [ nests 2 [ text "Inferred type"- , text "VV :" <+> pprint tA]- , nests 2 [ text "not a subtype of Required type"- , text "VV :" <+> pprint tE]- , nests 2 [ text "In Context"- , pprint c ]]--ppError' _ dSp (ErrFCrash _ _ c tA tE)- = dSp <+> text "Fixpoint Crash on Constraint"- $+$ sepVcat blankLine- [ nests 2 [ text "Inferred type"- , text "VV :" <+> pprint tA]- , nests 2 [ text "Required type"- , text "VV :" <+> pprint tE]- , nests 2 [ text "Context"- , pprint c ]]--ppError' _ dSp (ErrParse _ _ e)- = dSp <+> text "Cannot parse specification:"- $+$ (nest 4 $ pprint e)--ppError' _ dSp (ErrTySpec _ v t s)- = dSp <+> text "Bad Type Specification"- $+$ (pprint v <+> dcolon <+> pprint t)- $+$ (nest 4 $ pprint s)--ppError' _ dSp (ErrBadData _ v s)- = dSp <+> text "Bad Data Specification"- $+$ (pprint v <+> dcolon <+> pprint s)--ppError' _ dSp (ErrTermSpec _ v e s)- = dSp <+> text "Bad Termination Specification"- $+$ (pprint v <+> dcolon <+> pprint e)- $+$ (nest 4 $ pprint s)--ppError' _ dSp (ErrInvt _ t s)- = dSp <+> text "Bad Invariant Specification"- $+$ (nest 4 $ text "invariant " <+> pprint t $+$ pprint s)--ppError' _ dSp (ErrIAl _ t s)- = dSp <+> text "Bad Using Specification"- $+$ (nest 4 $ text "as" <+> pprint t $+$ pprint s)--ppError' _ dSp (ErrIAlMis _ t1 t2 s)- = dSp <+> text "Incompatible Using Specification"- $+$ (nest 4 $ (text "using" <+> pprint t1 <+> text "as" <+> pprint t2) $+$ pprint s)--ppError' _ dSp (ErrMeas _ t s)- = dSp <+> text "Bad Measure Specification"- $+$ (nest 4 $ text "measure " <+> pprint t $+$ pprint s)--ppError' _ dSp (ErrHMeas _ t s)- = dSp <+> text "Cannot promote Haskell function" <+> pprint t <+> text "to logic"- $+$ (nest 4 $ pprint s)--ppError' _ dSp (ErrDupSpecs _ v ls)- = dSp <+> text "Multiple Specifications for" <+> pprint v <> colon- $+$ (nest 4 $ vcat $ pprint <$> ls)--ppError' _ dSp (ErrDupAlias _ k v ls)- = dSp <+> text "Multiple Declarations! "- $+$ (nest 2 $ text "Multiple Declarations of" <+> pprint k <+> ppVar v $+$ text "Declared at:")- <+> (nest 4 $ vcat $ pprint <$> ls)--ppError' _ dSp (ErrUnbound _ x)- = dSp <+> text "Unbound variable"- $+$ (nest 4 $ pprint x)--ppError' _ dSp (ErrGhc _ s)- = dSp <+> text "GHC Error"- $+$ (nest 4 $ pprint s)--ppError' _ dSp (ErrMismatch _ x τ t)- = dSp <+> text "Specified Type Does Not Refine Haskell Type for" <+> pprint x- $+$ text "Haskell:" <+> pprint τ- $+$ text "Liquid :" <+> pprint t--ppError' _ dSp (ErrAliasCycle _ acycle)- = dSp <+> text "Cyclic Alias Definitions"- $+$ text "The following alias definitions form a cycle:"- $+$ (nest 4 $ sepVcat blankLine $ map describe acycle)- where- describe (pos, name)- = text "Type alias:" <+> pprint name- $+$ text "Defined at:" <+> pprint pos--ppError' _ dSp (ErrIllegalAliasApp _ dn dl)- = dSp <+> text "Refinement Type Alias cannot be used in this context"- $+$ text "Type alias:" <+> pprint dn- $+$ text "Defined at:" <+> pprint dl--ppError' _ dSp (ErrAliasApp _ n name dl dn)- = dSp <+> text "Malformed Type Alias Application"- $+$ text "Type alias:" <+> pprint name- $+$ text "Defined at:" <+> pprint dl- $+$ text "Expects" <+> pprint dn <+> text "arguments, but is given" <+> pprint n--ppError' _ dSp (ErrSaved _ s)- = dSp <+> s--ppError' _ dSp (ErrTermin xs _ s)- = dSp <+> text "Termination Error on" <+> (hsep $ intersperse comma $ map pprint xs) $+$ s--ppError' _ dSp (ErrRClass pos cls insts)- = dSp <+> text "Refined classes cannot have refined instances"- $+$ (nest 4 $ sepVcat blankLine $ describeCls : map describeInst insts)- where- describeCls- = text "Refined class definition for:" <+> cls- $+$ text "Defined at:" <+> pprint pos- describeInst (pos, t)- = text "Refined instance for:" <+> t- $+$ text "Defined at:" <+> pprint pos--ppError' _ _ (ErrOther _ s)- = text "Panic!" <+> nest 4 (pprint s)---ppVar v = text "`" <> pprint v <> text "'"---instance ToJSON Error where- toJSON e = object [ "pos" .= (errSpan e)- , "msg" .= (render $ ppError' Full empty e)- ]--instance FromJSON Error where- parseJSON (Object v) = errSaved <$> v .: "pos"- <*> v .: "msg"- parseJSON _ = mempty---errSaved :: SrcSpan -> String -> Error-errSaved x = ErrSaved x . text---- | Throw a panic exception-exitWithPanic :: String -> a-exitWithPanic = Ex.throw . errOther . text-
− src/Language/Haskell/Liquid/Fresh.hs
@@ -1,140 +0,0 @@-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TupleSections #-}-{-# LANGUAGE TypeSynonymInstances #-}-{-# LANGUAGE UndecidableInstances #-}--module Language.Haskell.Liquid.Fresh (Freshable(..)) where--import Control.Applicative (Applicative, (<$>), (<*>))-import Data.Monoid (mempty)-import Language.Fixpoint.Misc-import Language.Fixpoint.Types-import Language.Haskell.Liquid.Types--class (Applicative m, Monad m) => Freshable m a where- fresh :: m a- true :: a -> m a- true = return . id- refresh :: a -> m a- refresh = return . id--instance Freshable m Integer => Freshable m Symbol where- fresh = tempSymbol "x" <$> fresh--instance Freshable m Integer => Freshable m Refa where- fresh = kv <$> fresh- where- kv = Refa . (`PKVar` mempty) . intKvar--instance Freshable m Integer => Freshable m [Refa] where- fresh = single <$> fresh--instance Freshable m Integer => Freshable m Reft where- fresh = errorstar "fresh Reft"- true (Reft (v,_)) = return $ Reft (v, mempty)- refresh (Reft (_,_)) = (Reft .) . (,) <$> freshVV <*> fresh- where- freshVV = vv . Just <$> fresh--instance Freshable m Integer => Freshable m RReft where- fresh = errorstar "fresh RReft"- true (U r _ s) = U <$> true r <*> return mempty <*> true s- refresh (U r _ s) = U <$> refresh r <*> return mempty <*> refresh s--instance Freshable m Integer => Freshable m Strata where- fresh = (:[]) . SVar <$> fresh- true [] = fresh- true s = return s- refresh [] = fresh- refresh s = return s--instance (Freshable m Integer, Freshable m r, Reftable r, RefTypable RTyCon RTyVar r) => Freshable m (RRType r) where- fresh = errorstar "fresh RefType"- refresh = refreshRefType- true = trueRefType--------------------------------------------------------------------------------------------------trueRefType :: (Freshable m Integer, Freshable m r, Reftable r, RefTypable RTyCon RTyVar r) => RRType r -> m (RRType r)-------------------------------------------------------------------------------------------------trueRefType (RAllT α t)- = RAllT α <$> true t--trueRefType (RAllP π t)- = RAllP π <$> true t--trueRefType (RFun _ t t' _)- = rFun <$> fresh <*> true t <*> true t'--trueRefType (RApp c ts _ _) | isClass c- = rRCls c <$> mapM true ts--trueRefType (RApp c ts rs r)- = RApp c <$> mapM true ts <*> mapM trueRef rs <*> true r--trueRefType (RAppTy t t' _)- = RAppTy <$> true t <*> true t' <*> return mempty--trueRefType (RVar a r)- = RVar a <$> true r--trueRefType (RAllE y ty tx)- = do y' <- fresh - ty' <- true ty- tx' <- true tx- return $ RAllE y' ty' (tx' `subst1` (y, EVar y')) --trueRefType (RRTy e o r t)- = RRTy e o r <$> trueRefType t --trueRefType t - = return t--trueRef (RProp s t) = RProp s <$> trueRefType t-trueRef _ = errorstar "trueRef: unexpected"---------------------------------------------------------------------------------------------------refreshRefType :: (Freshable m Integer, Freshable m r, Reftable r, RefTypable RTyCon RTyVar r) => RRType r -> m (RRType r)-------------------------------------------------------------------------------------------------refreshRefType (RAllT α t)- = RAllT α <$> refresh t--refreshRefType (RAllP π t)- = RAllP π <$> refresh t--refreshRefType (RFun b t t' _)- | b == dummySymbol = rFun <$> fresh <*> refresh t <*> refresh t'- | otherwise = rFun b <$> refresh t <*> refresh t'--refreshRefType (RApp rc ts _ _) | isClass rc- = return $ rRCls rc ts --refreshRefType (RApp rc ts rs r)- = RApp rc <$> mapM refresh ts <*> mapM refreshRef rs <*> refresh r--refreshRefType (RVar a r)- = RVar a <$> refresh r--refreshRefType (RAppTy t t' r)- = RAppTy <$> refresh t <*> refresh t' <*> refresh r--refreshRefType (RAllE y ty tx)- = do y' <- fresh - ty' <- refresh ty- tx' <- refresh tx- return $ RAllE y' ty' (tx' `subst1` (y, EVar y')) --refreshRefType (RRTy e o r t)- = RRTy e o r <$> refreshRefType t --refreshRefType t- = return t--refreshRef (RProp s t) = RProp <$> mapM freshSym s <*> refreshRefType t-refreshRef _ = errorstar "refreshRef: unexpected"-freshSym (_, t) = (, t) <$> fresh-
+ src/Language/Haskell/Liquid/GHC/Interface.hs view
@@ -0,0 +1,402 @@+{-# LANGUAGE NoMonomorphismRestriction #-}+{-# LANGUAGE TypeSynonymInstances #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE TupleSections #-}+{-# LANGUAGE ScopedTypeVariables #-}++module Language.Haskell.Liquid.GHC.Interface (++ -- * extract all information needed for verification+ getGhcInfo++ -- * printer+ , pprintCBs+ ) where++import Prelude hiding (error)++import GHC hiding (Target, desugarModule)+import GHC.Paths (libdir)++import Bag+import Class+import CoreMonad+import CoreSyn+import DataCon+import DriverPhases+import DriverPipeline+import DynFlags+import ErrUtils+import HscTypes hiding (Target)+import IdInfo+import InstEnv+import Var++import Control.Exception+import Control.Monad++import Data.List hiding (intersperse)+import Data.Maybe+import qualified Data.HashSet as S++import System.Console.CmdArgs.Verbosity hiding (Loud)+import System.Directory+import System.FilePath+import System.IO.Temp++import Text.PrettyPrint.HughesPJ++import Language.Fixpoint.Types hiding (Error, Result, Expr)+import Language.Fixpoint.Misc++import Language.Haskell.Liquid.Bare+import Language.Haskell.Liquid.GHC.Misc+import qualified Language.Haskell.Liquid.Measure as Ms+import Language.Haskell.Liquid.Misc+import Language.Haskell.Liquid.Parse+import Language.Haskell.Liquid.Transforms.ANF+import Language.Haskell.Liquid.Types+import Language.Haskell.Liquid.Types.PrettyPrint+import Language.Haskell.Liquid.Types.Visitors+import Language.Haskell.Liquid.UX.CmdLine+import Language.Haskell.Liquid.UX.Tidy+import Language.Fixpoint.Utils.Files++--------------------------------------------------------------------------------+-- GHC Interface Pipeline ------------------------------------------------------+--------------------------------------------------------------------------------++getGhcInfo :: Maybe HscEnv -> Config -> FilePath -> IO (GhcInfo, HscEnv)+getGhcInfo hscEnv cfg0 target = do+ tryIgnore "create temp directory" $+ createDirectoryIfMissing False $ tempDirectory target+ (cfg, name, tgtSpec) <- parseRootTarget cfg0 target+ runLiquidGhc hscEnv cfg $ getGhcInfo' cfg target name tgtSpec++getGhcInfo' :: Config -> FilePath -> ModName -> Ms.BareSpec -> Ghc (GhcInfo, HscEnv)+getGhcInfo' cfg target name tgtSpec = do+ paths <- importPaths <$> getSessionDynFlags+ liftIO $ whenLoud $ putStrLn $ "paths = " ++ show paths++ impSpecs <- findAndLoadTargets cfg paths target++ modGuts <- makeMGIModGuts target+ hscEnv <- getSession+ coreBinds <- liftIO $ anormalize (not $ nocaseexpand cfg) hscEnv modGuts++ logicMap <- liftIO makeLogicMap++ let dataCons = concatMap (map dataConWorkId . tyConDataCons) (mgi_tcs modGuts)++ let impVs = importVars coreBinds ++ classCons (mgi_cls_inst modGuts)+ let defVs = definedVars coreBinds+ let useVs = readVars coreBinds+ let letVs = letVars coreBinds+ let derVs = derivedVars coreBinds $ ((is_dfun <$>) <$>) $ mgi_cls_inst modGuts++ (spc, imps, incs) <- moduleSpec cfg coreBinds (impVs ++ defVs) letVs name modGuts tgtSpec logicMap impSpecs+ liftIO $ whenLoud $ putStrLn $ "Module Imports: " ++ show imps+ hqualFiles <- moduleHquals modGuts paths target imps incs++ let info = GI target hscEnv coreBinds derVs impVs (letVs ++ dataCons) useVs hqualFiles imps incs spc+ hscEnv' <- getSession+ return (info, hscEnv')++--------------------------------------------------------------------------------+-- Configure GHC for Liquid Haskell --------------------------------------------+--------------------------------------------------------------------------------++runLiquidGhc :: Maybe HscEnv -> Config -> Ghc a -> IO a+runLiquidGhc hscEnv cfg act =+ withSystemTempDirectory "liquid" $ \tmp ->+ runGhc (Just libdir) $ do+ maybe (return ()) setSession hscEnv+ df <- getSessionDynFlags+ (df',_,_) <- parseDynamicFlags df (map noLoc $ ghcOptions cfg)+ loud <- liftIO isLoud+ let df'' = df' { importPaths = nub $ idirs cfg ++ importPaths df'+ , libraryPaths = nub $ idirs cfg ++ libraryPaths df'+ , includePaths = nub $ idirs cfg ++ includePaths df'+ , packageFlags = ExposePackage (PackageArg "ghc-prim") (ModRenaming True []) : packageFlags df'+ -- , profAuto = ProfAutoCalls+ , ghcLink = LinkInMemory+ --FIXME: this *should* be HscNothing, but that prevents us from+ -- looking up *unexported* names in another source module..+ , hscTarget = HscInterpreted -- HscNothing+ , ghcMode = CompManager+ -- prevent GHC from printing anything, unless in Loud mode+ , log_action = if loud+ then defaultLogAction+ else \_ _ _ _ _ -> return ()+ -- redirect .hi/.o/etc files to temp directory+ , objectDir = Just tmp+ , hiDir = Just tmp+ , stubDir = Just tmp+ } `xopt_set` Opt_MagicHash+ `gopt_set` Opt_ImplicitImportQualified+ `gopt_set` Opt_PIC+ setSessionDynFlags df''+ defaultCleanupHandler df'' act++--------------------------------------------------------------------------------+-- Parse, Find, & Load Targets -------------------------------------------------+--------------------------------------------------------------------------------++parseRootTarget :: Config -> FilePath -> IO (Config, ModName, Ms.BareSpec)+parseRootTarget cfg0 target = do+ (name, tgtSpec) <- parseSpec target+ cfg <- withPragmas cfg0 target $ Ms.pragmas tgtSpec+ return (cfg, ModName Target $ getModName name, tgtSpec)++findAndLoadTargets :: Config -> [FilePath] -> FilePath -> Ghc [(ModName, Ms.BareSpec)]+findAndLoadTargets cfg paths target = do+ setTargets . return =<< guessTarget target Nothing++ impNames <- allDepNames <$> depanal [] False+ impSpecs <- getSpecs cfg paths target impNames [Spec, Hs, LHs]+ liftIO $ whenNormal $ donePhase Loud "Parsed All Specifications"++ compileCFiles =<< liftIO (foldM (\c (f,_,s) -> withPragmas c f (Ms.pragmas s)) cfg impSpecs)++ impSpecs' <- forM impSpecs $ \(f, n, s) -> do+ unless (isSpecImport n) $+ addTarget =<< guessTarget f Nothing+ return (n, s)+ load LoadAllTargets+ liftIO $ whenNormal $ donePhase Loud "Loaded Targets"++ return impSpecs'++allDepNames :: [ModSummary] -> [String]+allDepNames = concatMap (map declNameString . ms_textual_imps)++declNameString :: GHC.Located (ImportDecl RdrName) -> String+declNameString = moduleNameString . unLoc . ideclName . unLoc++compileCFiles :: Config -> Ghc ()+compileCFiles cfg = do+ df <- getSessionDynFlags+ setSessionDynFlags $ df { includePaths = nub $ idirs cfg ++ includePaths df+ , importPaths = nub $ idirs cfg ++ importPaths df+ , libraryPaths = nub $ idirs cfg ++ libraryPaths df }+ hsc <- getSession+ os <- mapM (\x -> liftIO $ compileFile hsc StopLn (x,Nothing)) (nub $ cFiles cfg)+ df <- getSessionDynFlags+ void $ setSessionDynFlags $ df { ldInputs = map (FileOption "") os ++ ldInputs df }++--------------------------------------------------------------------------------+-- Assemble Information for Spec Extraction ------------------------------------+--------------------------------------------------------------------------------++makeMGIModGuts :: FilePath -> Ghc MGIModGuts+makeMGIModGuts f = do+ modGraph <- getModuleGraph+ case find (\m -> not (isBootSummary m) && f == msHsFilePath m) modGraph of+ Just modSummary -> do+ parsed <- parseModule modSummary+ modGuts <- coreModule <$> (desugarModule =<< typecheckModule (ignoreInline parsed))+ let deriv = Just $ instEnvElts $ mg_inst_env modGuts+ return $! miModGuts deriv modGuts+ Nothing ->+ panic Nothing $ "Ghc Interface: Unable to get GhcModGuts"++makeLogicMap :: IO (Either Error LogicMap)+makeLogicMap = do+ lg <- getCoreToLogicPath+ lspec <- readFile lg+ return $ parseSymbolToLogic lg lspec++--------------------------------------------------------------------------------+-- Extract Ids -----------------------------------------------------------------+--------------------------------------------------------------------------------++classCons :: Maybe [ClsInst] -> [Id]+classCons Nothing = []+classCons (Just cs) = concatMap (dataConImplicitIds . head . tyConDataCons . classTyCon . is_cls) cs++derivedVars :: CoreProgram -> Maybe [DFunId] -> [Id]+derivedVars cbs (Just fds) = concatMap (derivedVs cbs) fds+derivedVars _ Nothing = []++derivedVs :: CoreProgram -> DFunId -> [Id]+derivedVs cbs fd = concatMap bindersOf cbs' ++ deps+ where+ cbs' = filter f cbs+ f (NonRec x _) = eqFd x+ f (Rec xes) = any eqFd (fst <$> xes)+ eqFd x = varName x == varName fd+ deps = concatMap unfoldDep unfolds+ unfolds = unfoldingInfo . idInfo <$> concatMap bindersOf cbs'++unfoldDep :: Unfolding -> [Id]+unfoldDep (DFunUnfolding _ _ e) = concatMap exprDep e+unfoldDep (CoreUnfolding {uf_tmpl = e}) = exprDep e+unfoldDep _ = []++exprDep :: CoreExpr -> [Id]+exprDep = freeVars S.empty++importVars :: CoreProgram -> [Id]+importVars = freeVars S.empty++definedVars :: CoreProgram -> [Id]+definedVars = concatMap defs+ where+ defs (NonRec x _) = [x]+ defs (Rec xes) = map fst xes++--------------------------------------------------------------------------------+-- Find & Parse Specs ----------------------------------------------------------+--------------------------------------------------------------------------------++getSpecs cfg paths target names exts = do+ fs' <- sortNub <$> moduleImports exts paths names+ patSpec <- getPatSpec paths $ totality cfg+ rlSpec <- getRealSpec paths $ not $ linear cfg+ let fs = patSpec ++ rlSpec ++ fs'+ transParseSpecs exts paths (S.singleton target) mempty (map snd fs \\ [target])++getPatSpec paths totalitycheck+ | totalitycheck = (map (patErrorName,)) . maybeToList <$> moduleFile paths patErrorName Spec+ | otherwise = return []+ where+ patErrorName = "PatErr"++getRealSpec paths freal+ | freal = (map (realSpecName,)) . maybeToList <$> moduleFile paths realSpecName Spec+ | otherwise = (map (notRealSpecName,)) . maybeToList <$> moduleFile paths notRealSpecName Spec+ where+ realSpecName = "Real"+ notRealSpecName = "NotReal"+++transParseSpecs _ _ _ specs [] = return specs+transParseSpecs exts paths seenFiles specs newFiles = do+ newSpecs <- liftIO $ mapM (\f -> addFst3 f <$> parseSpec f) newFiles+ impFiles <- moduleImports exts paths $ specsImports newSpecs+ let seenFiles' = seenFiles `S.union` (S.fromList newFiles)+ let specs' = specs ++ map (third3 noTerm) newSpecs+ let newFiles' = [f | (_, f) <- impFiles, not (f `S.member` seenFiles')]+ transParseSpecs exts paths seenFiles' specs' newFiles'+ where+ specsImports ss = nub $ concatMap (map symbolString . Ms.imports . thd3) ss+ noTerm spec = spec { Ms.decr = mempty, Ms.lazy = mempty, Ms.termexprs = mempty }++parseSpec :: FilePath -> IO (ModName, Ms.BareSpec)+parseSpec file = either throw return . specParser file =<< readFile file++specParser f str+ | isExtFile Spec f = specSpecificationP f str+ | isExtFile Hs f = hsSpecificationP f str+ | isExtFile HsBoot f = hsSpecificationP f str+ | isExtFile LHs f = lhsSpecificationP f str+ | otherwise = panic Nothing $ "SpecParser: Cannot Parse File " ++ f+++moduleSpec cfg cbs vars letVs tgtMod mgi tgtSpec lm impSpecs = do+ let tgtCxt = IIModule $ getModName tgtMod+ let impCxt = map (IIDecl . qualImportDecl . getModName . fst) impSpecs+ setContext (tgtCxt : impCxt)++ hsc <-getSession++ let impNames = map (getModString . fst) impSpecs+ let exports = mgi_exports mgi++ let specs = (tgtMod, tgtSpec) : impSpecs+ let imps = sortNub $ impNames ++ [ symbolString x+ | (_, sp) <- specs+ , x <- Ms.imports sp+ ]++ ghcSpec <- liftIO $ makeGhcSpec cfg tgtMod cbs vars letVs exports hsc lm specs+ return (ghcSpec, imps, Ms.includes tgtSpec)++moduleHquals mgi paths target imps incs = do+ hqs <- specIncludes Hquals paths incs+ hqs' <- moduleImports [Hquals] paths (mgi_namestring mgi : imps)+ hqs'' <- liftIO $ filterM doesFileExist [extFileName Hquals target]+ return $ sortNub $ hqs'' ++ hqs ++ (snd <$> hqs')+++moduleImports :: [Ext] -> [FilePath] -> [String] -> Ghc [(String, FilePath)]+moduleImports exts paths names = liftM concat $ forM names $ \name ->+ map (name,) . catMaybes <$> mapM (moduleFile paths name) exts++moduleFile :: [FilePath] -> String -> Ext -> Ghc (Maybe FilePath)+moduleFile paths name ext+ | ext `elem` [Hs, LHs] = do+ graph <- getModuleGraph+ case find (\m -> not (isBootSummary m) &&+ name == moduleNameString (ms_mod_name m)) graph of+ Nothing -> liftIO $ getFileInDirs (extModuleName name ext) paths+ Just ms -> return $ normalise <$> ml_hs_file (ms_location ms)+ | otherwise = liftIO $ getFileInDirs (extModuleName name ext) paths++specIncludes :: Ext -> [FilePath] -> [FilePath] -> Ghc [FilePath]+specIncludes ext paths reqs = do+ let libFile = extFileNameR ext $ symbolString preludeName+ let incFiles = catMaybes $ reqFile ext <$> reqs+ liftIO $ forM (libFile : incFiles) $ \f -> do+ mfile <- getFileInDirs f paths+ case mfile of+ Just file -> return file+ Nothing -> panic Nothing $ "cannot find " ++ f ++ " in " ++ show paths++reqFile :: Ext -> FilePath -> Maybe FilePath+reqFile ext s+ | isExtFile ext s = Just s+ | otherwise = Nothing++--------------------------------------------------------------------------------+-- Pretty Printing -------------------------------------------------------------+--------------------------------------------------------------------------------++instance PPrint GhcSpec where+ pprintTidy k spec = (text "******* Target Variables ********************")+ $$ (pprintTidy k $ tgtVars spec)+ $$ (text "******* Type Signatures *********************")+ $$ (pprintLongList $ tySigs spec)+ $$ (text "******* Assumed Type Signatures *************")+ $$ (pprintLongList $ asmSigs spec)+ $$ (text "******* DataCon Specifications (Measure) ****")+ $$ (pprintLongList $ ctors spec)+ $$ (text "******* Measure Specifications **************")+ $$ (pprintLongList $ meas spec)++instance PPrint GhcInfo where+ pprintTidy k info = (text "*************** Imports *********************")+ $+$ (intersperse comma $ text <$> imports info)+ $+$ (text "*************** Includes ********************")+ $+$ (intersperse comma $ text <$> includes info)+ $+$ (text "*************** Imported Variables **********")+ $+$ (pprDoc $ impVars info)+ $+$ (text "*************** Defined Variables ***********")+ $+$ (pprDoc $ defVars info)+ $+$ (text "*************** Specification ***************")+ $+$ (pprintTidy k $ spec info)+ $+$ (text "*************** Core Bindings ***************")+ $+$ (pprintCBs $ cbs info)++pprintCBs :: [CoreBind] -> Doc+pprintCBs = pprDoc . tidyCBs++instance Show GhcInfo where+ show = showpp++instance PPrint TargetVars where+ pprintTidy _ AllVars = text "All Variables"+ pprintTidy k (Only vs) = text "Only Variables: " <+> pprintTidy k vs++------------------------------------------------------------------------+-- Dealing with Errors ---------------------------------------------------+------------------------------------------------------------------------++instance Result SourceError where+ result = (`Crash` "Invalid Source")+ . concatMap errMsgErrors+ . bagToList+ . srcErrorMessages++errMsgErrors e = [ ErrGhc (errMsgSpan e) (pprint e)]+
+ src/Language/Haskell/Liquid/GHC/Misc.hs view
@@ -0,0 +1,542 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE NoMonomorphismRestriction #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE TupleSections #-}+{-# LANGUAGE TypeSynonymInstances #-}+{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE ViewPatterns #-}++-- | This module contains a wrappers and utility functions for+-- accessing GHC module information. It should NEVER depend on+-- ANY module inside the Language.Haskell.Liquid.* tree.++module Language.Haskell.Liquid.GHC.Misc where++import PrelNames (fractionalClassKeys)+import Class (classKey)++import Debug.Trace++import Prelude hiding (error)+import Avail (availsToNameSet)+import BasicTypes (Arity)+import CoreSyn hiding (Expr, sourceName)+import qualified CoreSyn as Core+import CostCentre+import GHC hiding (L)+import HscTypes (Dependencies, ImportedMods, ModGuts(..), HscEnv(..), FindResult(..))+import Kind (superKind)+import NameSet (NameSet)+import SrcLoc hiding (L)+import Bag+import ErrUtils+import CoreLint+import CoreMonad++import Text.Parsec.Pos (sourceName, sourceLine, sourceColumn, newPos)++import Name (mkInternalName, getSrcSpan, nameModule_maybe)+import Module (moduleNameFS)+import OccName (mkTyVarOcc, mkVarOcc, mkTcOcc, occNameFS)+import Unique+import Finder (findImportedModule, cannotFindModule)+import Panic (throwGhcException)+import FastString+import TcRnDriver+-- import TcRnTypes+++import RdrName+import Type (liftedTypeKind)+import TypeRep+import Var+import IdInfo+import qualified TyCon as TC+import Data.Char (isLower, isSpace)+import Data.Maybe (fromMaybe)+import Data.Hashable+import qualified Data.HashSet as S++import qualified Data.Text.Encoding as T+import qualified Data.Text as T+import Control.Arrow (second)+import Control.Monad ((>=>))+import Outputable (Outputable (..), text, ppr)+import qualified Outputable as Out+import DynFlags+import qualified Text.PrettyPrint.HughesPJ as PJ+import Language.Fixpoint.Types hiding (L, Loc (..), SrcSpan, Constant, SESearch (..))+import qualified Language.Fixpoint.Types as F+import Language.Fixpoint.Misc (safeHead, safeLast, safeInit)+import Language.Haskell.Liquid.Desugar710.HscMain+import Control.DeepSeq+import Language.Haskell.Liquid.Types.Errors+++-----------------------------------------------------------------------+--------------- Datatype For Holding GHC ModGuts ----------------------+-----------------------------------------------------------------------++data MGIModGuts = MI {+ mgi_binds :: !CoreProgram+ , mgi_module :: !Module+ , mgi_deps :: !Dependencies+ , mgi_dir_imps :: !ImportedMods+ , mgi_rdr_env :: !GlobalRdrEnv+ , mgi_tcs :: ![TyCon]+ , mgi_fam_insts :: ![FamInst]+ , mgi_exports :: !NameSet+ , mgi_cls_inst :: !(Maybe [ClsInst])+ }++miModGuts cls mg = MI {+ mgi_binds = mg_binds mg+ , mgi_module = mg_module mg+ , mgi_deps = mg_deps mg+ , mgi_dir_imps = mg_dir_imps mg+ , mgi_rdr_env = mg_rdr_env mg+ , mgi_tcs = mg_tcs mg+ , mgi_fam_insts = mg_fam_insts mg+ , mgi_exports = availsToNameSet $ mg_exports mg+ , mgi_cls_inst = cls+ }++mgi_namestring = moduleNameString . moduleName . mgi_module++--------------------------------------------------------------------------------+-- | Encoding and Decoding Location --------------------------------------------+--------------------------------------------------------------------------------+srcSpanTick :: Module -> SrcSpan -> Tickish a+srcSpanTick m sp = ProfNote (AllCafsCC m sp) False True++tickSrcSpan :: Outputable a => Tickish a -> SrcSpan+tickSrcSpan (ProfNote cc _ _) = cc_loc cc+tickSrcSpan (SourceNote ss _) = RealSrcSpan ss+tickSrcSpan _ = noSrcSpan++-----------------------------------------------------------------------+--------------- Generic Helpers for Accessing GHC Innards -------------+-----------------------------------------------------------------------++stringTyVar :: String -> TyVar+stringTyVar s = mkTyVar name liftedTypeKind+ where name = mkInternalName (mkUnique 'x' 24) occ noSrcSpan+ occ = mkTyVarOcc s++stringVar :: String -> Type -> Var+stringVar s t = mkLocalVar VanillaId name t vanillaIdInfo+ where+ name = mkInternalName (mkUnique 'x' 25) occ noSrcSpan+ occ = mkVarOcc s++stringTyCon :: Char -> Int -> String -> TyCon+stringTyCon = stringTyConWithKind superKind++stringTyConWithKind :: Kind -> Char -> Int -> String -> TyCon+stringTyConWithKind k c n s = TC.mkKindTyCon name k+ where+ name = mkInternalName (mkUnique c n) occ noSrcSpan+ occ = mkTcOcc s++hasBaseTypeVar = isBaseType . varType++-- same as Constraint isBase+isBaseType (ForAllTy _ t) = isBaseType t+isBaseType (TyVarTy _) = True+isBaseType (TyConApp _ ts) = all isBaseType ts+isBaseType (AppTy t1 t2) = isBaseType t1 && isBaseType t2+isBaseType (FunTy _ _) = False -- isBaseType t1 && isBaseType t2+isBaseType _ = False++validTyVar :: String -> Bool+validTyVar s@(c:_) = isLower c && all (not . isSpace) s+validTyVar _ = False++tvId α = {- traceShow ("tvId: α = " ++ show α) $ -} showPpr α ++ show (varUnique α)++tracePpr s x = trace ("\nTrace: [" ++ s ++ "] : " ++ showPpr x) x++pprShow = text . show+++tidyCBs = map unTick++unTick (NonRec b e) = NonRec b (unTickExpr e)+unTick (Rec bs) = Rec $ map (second unTickExpr) bs++unTickExpr (App e a) = App (unTickExpr e) (unTickExpr a)+unTickExpr (Lam b e) = Lam b (unTickExpr e)+unTickExpr (Let b e) = Let (unTick b) (unTickExpr e)+unTickExpr (Case e b t as) = Case (unTickExpr e) b t (map unTickAlt as)+ where unTickAlt (a, b, e) = (a, b, unTickExpr e)+unTickExpr (Cast e c) = Cast (unTickExpr e) c+unTickExpr (Tick _ e) = unTickExpr e+unTickExpr x = x++isFractionalClass clas = classKey clas `elem` fractionalClassKeys++-----------------------------------------------------------------------+------------------ Generic Helpers for DataConstructors ---------------+-----------------------------------------------------------------------++isDataConId id = case idDetails id of+ DataConWorkId _ -> True+ DataConWrapId _ -> True+ _ -> False++getDataConVarUnique v+ | isId v && isDataConId v = getUnique $ idDataCon v+ | otherwise = getUnique v+++newtype Loc = L (Int, Int) deriving (Eq, Ord, Show)++instance Hashable Loc where+ hashWithSalt i (L z) = hashWithSalt i z++--instance (Uniquable a) => Hashable a where++instance Hashable SrcSpan where+ hashWithSalt i (UnhelpfulSpan s) = hashWithSalt i (uniq s)+ hashWithSalt i (RealSrcSpan s) = hashWithSalt i (srcSpanStartLine s, srcSpanStartCol s, srcSpanEndCol s)++instance Outputable a => Outputable (S.HashSet a) where+ ppr = ppr . S.toList++++-------------------------------------------------------++toFixSDoc = PJ.text . PJ.render . toFix+sDocDoc = PJ.text . showSDoc+pprDoc = sDocDoc . ppr++-- Overriding Outputable functions because they now require DynFlags!+showPpr = showSDoc . ppr++-- FIXME: somewhere we depend on this printing out all GHC entities with+-- fully-qualified names...+showSDoc sdoc = Out.renderWithStyle unsafeGlobalDynFlags sdoc (Out.mkUserStyle Out.alwaysQualify Out.AllTheWay)+showSDocDump = Out.showSDocDump unsafeGlobalDynFlags++typeUniqueString = {- ("sort_" ++) . -} showSDocDump . ppr++fSrcSpan :: (F.Loc a) => a -> SrcSpan+fSrcSpan = fSrcSpanSrcSpan . F.srcSpan++fSrcSpanSrcSpan :: F.SrcSpan -> SrcSpan+fSrcSpanSrcSpan (F.SS p p') = sourcePos2SrcSpan p p'++srcSpanFSrcSpan :: SrcSpan -> F.SrcSpan+srcSpanFSrcSpan sp = F.SS p p'+ where+ p = srcSpanSourcePos sp+ p' = srcSpanSourcePosE sp++sourcePos2SrcSpan :: SourcePos -> SourcePos -> SrcSpan+sourcePos2SrcSpan p p' = RealSrcSpan $ realSrcSpan f l c l' c'+ where+ (f, l, c) = F.sourcePosElts p+ (_, l', c') = F.sourcePosElts p'++sourcePosSrcSpan :: SourcePos -> SrcSpan+sourcePosSrcSpan = srcLocSpan . sourcePosSrcLoc++sourcePosSrcLoc :: SourcePos -> SrcLoc+sourcePosSrcLoc p = mkSrcLoc (fsLit file) line col+ where+ file = sourceName p+ line = sourceLine p+ col = sourceColumn p++srcSpanSourcePos :: SrcSpan -> SourcePos+srcSpanSourcePos (UnhelpfulSpan _) = dummyPos "<no source information>"+srcSpanSourcePos (RealSrcSpan s) = realSrcSpanSourcePos s++srcSpanSourcePosE :: SrcSpan -> SourcePos+srcSpanSourcePosE (UnhelpfulSpan _) = dummyPos "<no source information>"+srcSpanSourcePosE (RealSrcSpan s) = realSrcSpanSourcePosE s++++srcSpanFilename = maybe "" unpackFS . srcSpanFileName_maybe+srcSpanStartLoc l = L (srcSpanStartLine l, srcSpanStartCol l)+srcSpanEndLoc l = L (srcSpanEndLine l, srcSpanEndCol l)+oneLine l = srcSpanStartLine l == srcSpanEndLine l+lineCol l = (srcSpanStartLine l, srcSpanStartCol l)++realSrcSpanSourcePos :: RealSrcSpan -> SourcePos+realSrcSpanSourcePos s = newPos file line col+ where+ file = unpackFS $ srcSpanFile s+ line = srcSpanStartLine s+ col = srcSpanStartCol s+++realSrcSpanSourcePosE :: RealSrcSpan -> SourcePos+realSrcSpanSourcePosE s = newPos file line col+ where+ file = unpackFS $ srcSpanFile s+ line = srcSpanEndLine s+ col = srcSpanEndCol s+++getSourcePos = srcSpanSourcePos . getSrcSpan+getSourcePosE = srcSpanSourcePosE . getSrcSpan++collectArguments n e = if length xs > n then take n xs else xs+ where (vs', e') = collectValBinders' $ snd $ collectTyBinders e+ vs = fst $ collectValBinders $ ignoreLetBinds e'+ xs = vs' ++ vs++collectValBinders' = go []+ where+ go tvs (Lam b e) | isTyVar b = go tvs e+ go tvs (Lam b e) | isId b = go (b:tvs) e+ go tvs (Tick _ e) = go tvs e+ go tvs e = (reverse tvs, e)++ignoreLetBinds (Let (NonRec _ _) e')+ = ignoreLetBinds e'+ignoreLetBinds e+ = e++isDictionaryExpression :: Core.Expr Id -> Maybe Id+isDictionaryExpression (Tick _ e) = isDictionaryExpression e+isDictionaryExpression (Var x) | isDictionary x = Just x+isDictionaryExpression _ = Nothing+++realTcArity :: TyCon -> Arity+realTcArity+ = kindArity . TC.tyConKind++kindArity :: Kind -> Arity+kindArity (FunTy _ res)+ = 1 + kindArity res+kindArity (ForAllTy _ res)+ = kindArity res+kindArity _+ = 0+++uniqueHash i = hashWithSalt i . getKey . getUnique++-- slightly modified version of DynamicLoading.lookupRdrNameInModule+lookupRdrName :: HscEnv -> ModuleName -> RdrName -> IO (Maybe Name)+lookupRdrName hsc_env mod_name rdr_name = do+ -- First find the package the module resides in by searching exposed packages and home modules+ found_module <- findImportedModule hsc_env mod_name Nothing+ case found_module of+ Found _ mod -> do+ -- Find the exports of the module+ (_, mb_iface) <- getModuleInterface hsc_env mod+ case mb_iface of+ Just iface -> do+ -- Try and find the required name in the exports+ let decl_spec = ImpDeclSpec { is_mod = mod_name, is_as = mod_name+ , is_qual = False, is_dloc = noSrcSpan }+ provenance = Imported [ImpSpec decl_spec ImpAll]+ env = case mi_globals iface of+ Nothing -> mkGlobalRdrEnv (gresFromAvails provenance (mi_exports iface))+ Just e -> e+ case lookupGRE_RdrName rdr_name env of+ [gre] -> return (Just (gre_name gre))+ [] -> return Nothing+ _ -> Out.panic "lookupRdrNameInModule"+ Nothing -> throwCmdLineErrorS dflags $ Out.hsep [Out.ptext (sLit "Could not determine the exports of the module"), ppr mod_name]+ err -> throwCmdLineErrorS dflags $ cannotFindModule dflags mod_name err+ where dflags = hsc_dflags hsc_env+ throwCmdLineErrorS dflags = throwCmdLineError . Out.showSDoc dflags+ throwCmdLineError = throwGhcException . CmdLineError+++qualImportDecl mn = (simpleImportDecl mn) { ideclQualified = True }++ignoreInline x = x {pm_parsed_source = go <$> pm_parsed_source x}+ where go x = x {hsmodDecls = filter go' $ hsmodDecls x}+ go' x | SigD (InlineSig _ _) <- unLoc x = False+ | otherwise = True++symbolTyConWithKind k x i n = stringTyConWithKind k x i (symbolString n)+symbolTyCon x i n = stringTyCon x i (symbolString n)+symbolTyVar n = stringTyVar (symbolString n)++++varSymbol :: Var -> Symbol+varSymbol v+ | us `isSuffixOfSym` vs = vs+ | otherwise = suffixSymbol vs us+ where+ us = symbol $ showPpr $ getDataConVarUnique v+ vs = symbol $ getName v++qualifiedNameSymbol n = symbol $+ case nameModule_maybe n of+ Nothing -> occNameFS (getOccName n)+ Just m -> concatFS [moduleNameFS (moduleName m), fsLit ".", occNameFS (getOccName n)]++instance Symbolic FastString where+ symbol = symbol . fastStringText++fastStringText = T.decodeUtf8 . fastStringToByteString++tyConTyVarsDef c | TC.isPrimTyCon c || isFunTyCon c = []+tyConTyVarsDef c | TC.isPromotedTyCon c = panic Nothing ("TyVars on " ++ show c) -- tyConTyVarsDef $ TC.ty_con c+tyConTyVarsDef c | TC.isPromotedDataCon c = panic Nothing ("TyVars on " ++ show c) -- DC.dataConUnivTyVars $ TC.datacon c+tyConTyVarsDef c = TC.tyConTyVars c++----------------------------------------------------------------------+-- Myriad Instances+----------------------------------------------------------------------++instance Symbolic TyCon where+ symbol = symbol . qualifiedNameSymbol . getName++instance Symbolic Name where+ symbol = symbol . showPpr++instance Symbolic Var where+ symbol = varSymbol++instance Hashable Var where+ hashWithSalt = uniqueHash++instance Hashable TyCon where+ hashWithSalt = uniqueHash++instance Fixpoint Var where+ toFix = pprDoc++instance Fixpoint Name where+ toFix = pprDoc++instance Fixpoint Type where+ toFix = pprDoc++instance Show Name where+ show = showPpr++instance Show Var where+ show = showPpr++instance Show Class where+ show = showPpr++instance Show TyCon where+ show = showPpr++instance NFData Class where+ rnf t = seq t ()++instance NFData SrcSpan where+ rnf t = seq t ()++instance NFData TyCon where+ rnf t = seq t ()++instance NFData Type where+ rnf t = seq t ()++instance NFData Var where+ rnf t = seq t ()+++----------------------------------------------------------------------+-- GHC Compatibility Layer+----------------------------------------------------------------------++gHC_VERSION :: String+gHC_VERSION = show __GLASGOW_HASKELL__++symbolFastString :: Symbol -> FastString+symbolFastString = mkFastStringByteString . T.encodeUtf8 . symbolText++desugarModule :: TypecheckedModule -> Ghc DesugaredModule+desugarModule tcm = do+ let ms = pm_mod_summary $ tm_parsed_module tcm+ -- let ms = modSummary tcm+ let (tcg, _) = tm_internals_ tcm+ hsc_env <- getSession+ let hsc_env_tmp = hsc_env { hsc_dflags = ms_hspp_opts ms }+ guts <- liftIO $ hscDesugarWithLoc hsc_env_tmp ms tcg+ return DesugaredModule { dm_typechecked_module = tcm, dm_core_module = guts }++-- desugarModule = GHC.desugarModule++type Prec = TyPrec++lintCoreBindings :: [Var] -> CoreProgram -> (Bag MsgDoc, Bag MsgDoc)+lintCoreBindings = CoreLint.lintCoreBindings CoreDoNothing++synTyConRhs_maybe :: TyCon -> Maybe Type+synTyConRhs_maybe = TC.synTyConRhs_maybe++tcRnLookupRdrName :: HscEnv -> GHC.Located RdrName -> IO (Messages, Maybe [Name])+tcRnLookupRdrName = TcRnDriver.tcRnLookupRdrName+++------------------------------------------------------------------------+-- | Manipulating Symbols ----------------------------------------------+------------------------------------------------------------------------++dropModuleNames, takeModuleNames, dropModuleUnique :: Symbol -> Symbol+dropModuleNames = mungeNames lastName sepModNames "dropModuleNames: "+ where+ lastName msg = symbol . safeLast msg++takeModuleNames = mungeNames initName sepModNames "takeModuleNames: "+ where+ initName msg = symbol . T.intercalate "." . safeInit msg++dropModuleUnique = mungeNames headName sepUnique "dropModuleUnique: "+ where+ headName msg = symbol . safeHead msg+++sepModNames = "."+sepUnique = "#"+++-- safeHead :: String -> [T.Text] -> Symbol+-- safeHead msg [] = errorstar $ "safeHead with empty list" ++ msg+-- safeHead _ (x:_) = symbol x++-- safeInit :: String -> [T.Text] -> Symbol+-- safeInit _ xs@(_:_) = symbol $ T.intercalate "." $ init xs+-- safeInit msg _ = errorstar $ "safeInit with empty list " ++ msg++mungeNames :: (String -> [T.Text] -> Symbol) -> T.Text -> String -> Symbol -> Symbol+mungeNames _ _ _ "" = ""+mungeNames f d msg s'@(symbolText -> s)+ | s' == tupConName = tupConName+ | otherwise = f (msg ++ T.unpack s) $ T.splitOn d $ stripParens s++qualifySymbol :: Symbol -> Symbol -> Symbol+qualifySymbol (symbolText -> m) x'@(symbolText -> x)+ | isQualified x = x'+ | isParened x = symbol (wrapParens (m `mappend` "." `mappend` stripParens x))+ | otherwise = symbol (m `mappend` "." `mappend` x)++isQualified y = "." `T.isInfixOf` y+wrapParens x = "(" `mappend` x `mappend` ")"+isParened xs = xs /= stripParens xs++isDictionary = isPrefixOfSym "$f" . dropModuleNames . symbol+isInternal = isPrefixOfSym "$" . dropModuleNames . symbol++stripParens :: T.Text -> T.Text+stripParens t = fromMaybe t (strip t)+ where+ strip = T.stripPrefix "(" >=> T.stripSuffix ")"++stripParensSym :: Symbol -> Symbol+stripParensSym (symbolText -> t) = symbol $ stripParens t++--------------------------------------------------------------------------------+-- | Source Info = Stack of most recent binders/spans+--------------------------------------------------------------------------------
+ src/Language/Haskell/Liquid/GHC/Play.hs view
@@ -0,0 +1,86 @@+{-# LANGUAGE NoMonomorphismRestriction #-}+{-# LANGUAGE TypeSynonymInstances #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE TupleSections #-}++module Language.Haskell.Liquid.GHC.Play where++import Prelude hiding (error)+import GHC+import CoreSyn+import Var+import TypeRep++import Coercion++import Control.Arrow ((***))+import qualified Data.HashMap.Strict as M++import Language.Haskell.Liquid.GHC.Misc ()+import Language.Haskell.Liquid.Types.Errors++class Subable a where+ sub :: M.HashMap CoreBndr CoreExpr -> a -> a+ subTy :: M.HashMap TyVar Type -> a -> a++instance Subable CoreExpr where+ sub s (Var v) = M.lookupDefault (Var v) v s+ sub _ (Lit l) = Lit l+ sub s (App e1 e2) = App (sub s e1) (sub s e2)+ sub s (Lam b e) = Lam b (sub s e)+ sub s (Let b e) = Let (sub s b) (sub s e)+ sub s (Case e b t a) = Case (sub s e) (sub s b) t (map (sub s) a)+ sub s (Cast e c) = Cast (sub s e) c+ sub s (Tick t e) = Tick t (sub s e)+ sub _ (Type t) = Type t+ sub _ (Coercion c) = Coercion c++ subTy s (Var v) = Var (subTy s v)+ subTy _ (Lit l) = Lit l+ subTy s (App e1 e2) = App (subTy s e1) (subTy s e2)+ subTy s (Lam b e) | isTyVar b = Lam v' (subTy s e)+ where v' = case M.lookup b s of+ Just (TyVarTy v) -> v+ _ -> b++ subTy s (Lam b e) = Lam (subTy s b) (subTy s e)+ subTy s (Let b e) = Let (subTy s b) (subTy s e)+ subTy s (Case e b t a) = Case (subTy s e) (subTy s b) (subTy s t) (map (subTy s) a)+ subTy s (Cast e c) = Cast (subTy s e) (subTy s c)+ subTy s (Tick t e) = Tick t (subTy s e)+ subTy s (Type t) = Type (subTy s t)+ subTy s (Coercion c) = Coercion (subTy s c)++instance Subable Coercion where+ sub _ c = c+ subTy _ _ = panic Nothing "subTy Coercion"++instance Subable (Alt Var) where+ sub s (a, b, e) = (a, map (sub s) b, sub s e)+ subTy s (a, b, e) = (a, map (subTy s) b, subTy s e)++instance Subable Var where+ sub s v | M.member v s = subVar $ s M.! v+ | otherwise = v+ subTy s v = setVarType v (subTy s (varType v))++subVar (Var x) = x+subVar _ = panic Nothing "sub Var"++instance Subable (Bind Var) where+ sub s (NonRec x e) = NonRec (sub s x) (sub s e)+ sub s (Rec xes) = Rec ((sub s *** sub s) <$> xes)++ subTy s (NonRec x e) = NonRec (subTy s x) (subTy s e)+ subTy s (Rec xes) = Rec ((subTy s *** subTy s) <$> xes)++instance Subable Type where+ sub _ e = e+ subTy = substTysWith++substTysWith s tv@(TyVarTy v) = M.lookupDefault tv v s+substTysWith s (FunTy t1 t2) = FunTy (substTysWith s t1) (substTysWith s t2)+substTysWith s (ForAllTy v t) = ForAllTy v (substTysWith (M.delete v s) t)+substTysWith s (TyConApp c ts) = TyConApp c (map (substTysWith s) ts)+substTysWith s (AppTy t1 t2) = AppTy (substTysWith s t1) (substTysWith s t2)+substTysWith _ (LitTy t) = LitTy t
+ src/Language/Haskell/Liquid/GHC/SpanStack.hs view
@@ -0,0 +1,75 @@+{-# LANGUAGE BangPatterns #-}++module Language.Haskell.Liquid.GHC.SpanStack+ ( -- * Stack of positions+ Span (..)+ , SpanStack++ -- * Creating Stacks+ , empty, push++ -- * Using Stacks+ , srcSpan++ -- * Creating general spans+ , showSpan+ ) where++import Prelude hiding (error)+import SrcLoc+import qualified Var+import CoreSyn hiding (Tick, Var)+import Name (getSrcSpan)+import FastString (fsLit)+import Data.Maybe (listToMaybe, fromMaybe)+import Language.Haskell.Liquid.GHC.Misc (tickSrcSpan, showPpr)++-- | Opaque type for a stack of spans+newtype SpanStack = SpanStack { unStack :: [(Span, SrcSpan)] }++--------------------------------------------------------------------------------+empty :: SpanStack+--------------------------------------------------------------------------------+empty = SpanStack []++--------------------------------------------------------------------------------+push :: Span -> SpanStack -> SpanStack+--------------------------------------------------------------------------------+push !s stk -- @(SpanStack stk)+ | Just sp <- spanSrcSpan s = SpanStack ((s, sp) : unStack stk)+ | otherwise = stk++-- | A single span+data Span+ = Var !Var.Var -- ^ binder for whom we are generating constraint+ | Tick !(Tickish Var.Var) -- ^ nearest known Source Span++instance Show Span where+ show (Var x) = show x+ show (Tick tt) = showPpr tt++--------------------------------------------------------------------------------+srcSpan :: SpanStack -> SrcSpan+--------------------------------------------------------------------------------+srcSpan s = fromMaybe noSpan (mbSrcSpan s)+ where+ noSpan = showSpan "Yikes! No source information"++mbSrcSpan :: SpanStack -> Maybe SrcSpan+mbSrcSpan = fmap snd . listToMaybe . unStack++spanSrcSpan :: Span -> Maybe SrcSpan+spanSrcSpan = maybeSpan Nothing . go+ where+ go (Var x) = getSrcSpan x+ go (Tick tt) = tickSrcSpan tt++maybeSpan :: Maybe SrcSpan -> SrcSpan -> Maybe SrcSpan+maybeSpan d sp+ | isGoodSrcSpan sp = Just sp+ | otherwise = d++--------------------------------------------------------------------------------+showSpan :: (Show a) => a -> SrcSpan+--------------------------------------------------------------------------------+showSpan = mkGeneralSrcSpan . fsLit . show
− src/Language/Haskell/Liquid/GhcInterface.hs
@@ -1,387 +0,0 @@-{-# LANGUAGE CPP #-}-{-# LANGUAGE NoMonomorphismRestriction #-}-{-# LANGUAGE TypeSynonymInstances #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE TupleSections #-}-{-# LANGUAGE ScopedTypeVariables #-}--module Language.Haskell.Liquid.GhcInterface (-- -- * extract all information needed for verification- getGhcInfo-- ) where-import IdInfo-import InstEnv-import Bag (bagToList)-import ErrUtils-import GHC hiding (Target, desugarModule)-import DriverPhases (Phase(..))-import DriverPipeline (compileFile)-import Text.PrettyPrint.HughesPJ-import HscTypes hiding (Target)-import CoreSyn--import Class-import Var-import CoreMonad (liftIO)-import DataCon-import qualified Control.Exception as Ex--import GHC.Paths (libdir)-import System.FilePath ( replaceExtension, normalise)--import DynFlags-import Control.Monad (filterM, foldM, when, forM, forM_, liftM)-import Control.Applicative hiding (empty)-import Data.Monoid hiding ((<>))-import Data.List (find, nub)-import Data.Maybe (catMaybes, maybeToList)-import qualified Data.HashSet as S--import System.Console.CmdArgs.Verbosity (whenLoud)-import System.Directory (removeFile, createDirectoryIfMissing, doesFileExist)-import Language.Fixpoint.Types hiding (Result, Expr)-import Language.Fixpoint.Misc--import Language.Haskell.Liquid.Types-import Language.Haskell.Liquid.Errors-import Language.Haskell.Liquid.ANFTransform-import Language.Haskell.Liquid.Bare-import Language.Haskell.Liquid.GhcMisc-import Language.Haskell.Liquid.Misc-import Language.Haskell.Liquid.PrettyPrint-import Language.Haskell.Liquid.Visitors-import Language.Haskell.Liquid.CmdLine (withCabal, withPragmas)-import Language.Haskell.Liquid.Parse-import qualified Language.Haskell.Liquid.Measure as Ms--import Language.Fixpoint.Names-import Language.Fixpoint.Files-------------------------------------------------------------------------getGhcInfo :: Config -> FilePath -> IO (Either ErrorResult GhcInfo)----------------------------------------------------------------------getGhcInfo cfg target = (Right <$> getGhcInfo' cfg target)- `Ex.catch` (\(e :: SourceError) -> handle e)- `Ex.catch` (\(e :: Error) -> handle e)- `Ex.catch` (\(e :: [Error]) -> handle e)- where- handle = return . Left . result---getGhcInfo' cfg0 target- = runGhc (Just libdir) $ do- liftIO $ cleanFiles target- addTarget =<< guessTarget target Nothing- (name,tgtSpec) <- liftIO $ parseSpec target- cfg <- liftIO $ withPragmas cfg0 target $ Ms.pragmas tgtSpec- cfg <- liftIO $ withCabal cfg- let paths = idirs cfg- updateDynFlags cfg- liftIO $ whenLoud $ putStrLn ("paths = " ++ show paths)- let name' = ModName Target (getModName name)- impNames <- allDepNames <$> depanal [] False- impSpecs <- getSpecs (real cfg) (totality cfg) target paths impNames [Spec, Hs, LHs]- compileCFiles =<< liftIO (foldM (\c (f,_,s) -> withPragmas c f (Ms.pragmas s)) cfg impSpecs)- impSpecs' <- forM impSpecs $ \(f,n,s) -> do- when (not $ isSpecImport n) $- addTarget =<< guessTarget f Nothing- return (n,s)- load LoadAllTargets- modguts <- getGhcModGuts1 target- hscEnv <- getSession- coreBinds <- liftIO $ anormalize (not $ nocaseexpand cfg) hscEnv modguts- let datacons = [ dataConWorkId dc- | tc <- mgi_tcs modguts- , dc <- tyConDataCons tc- ]- let impVs = importVars coreBinds ++ classCons (mgi_cls_inst modguts)- let defVs = definedVars coreBinds- let useVs = readVars coreBinds- let letVs = letVars coreBinds- let derVs = derivedVars coreBinds $ fmap (fmap is_dfun) $ mgi_cls_inst modguts- logicmap <- liftIO makeLogicMap- (spec, imps, incs) <- moduleSpec cfg coreBinds (impVs ++ defVs) letVs name' modguts tgtSpec logicmap impSpecs'- liftIO $ whenLoud $ putStrLn $ "Module Imports: " ++ show imps- hqualFiles <- moduleHquals modguts paths target imps incs- return $ GI hscEnv coreBinds derVs impVs (letVs ++ datacons) useVs hqualFiles imps incs spec---makeLogicMap- = do lg <- getCoreToLogicPath- lspec <- readFile lg- return $ parseSymbolToLogic lg lspec--classCons :: Maybe [ClsInst] -> [Id]-classCons Nothing = []-classCons (Just cs) = concatMap (dataConImplicitIds . head . tyConDataCons . classTyCon . is_cls) cs--derivedVars :: CoreProgram -> Maybe [DFunId] -> [Id]-derivedVars cbs (Just fds) = concatMap (derivedVs cbs) fds-derivedVars _ Nothing = []--derivedVs :: CoreProgram -> DFunId -> [Id]-derivedVs cbs fd = concatMap bindersOf cbf ++ deps- where cbf = filter f cbs-- f (NonRec x _) = eqFd x- f (Rec xes ) = any eqFd (fst <$> xes)- eqFd x = varName x == varName fd- deps :: [Id]- deps = concatMap dep $ (unfoldingInfo . idInfo <$> concatMap bindersOf cbf)-- dep (DFunUnfolding _ _ e) = concatMap grapDep e- dep (CoreUnfolding {uf_tmpl = e}) = grapDep e- dep _ = []-- grapDep :: CoreExpr -> [Id]- grapDep e = freeVars S.empty e--updateDynFlags cfg- = do df <- getSessionDynFlags- let df' = df { importPaths = idirs cfg ++ importPaths df- , libraryPaths = idirs cfg ++ libraryPaths df- , includePaths = idirs cfg ++ includePaths df- , profAuto = ProfAutoCalls- , ghcLink = LinkInMemory- --FIXME: this *should* be HscNothing, but that prevents us from- -- looking up *unexported* names in another source module..- , hscTarget = HscInterpreted -- HscNothing- , ghcMode = CompManager- -- prevent GHC from printing anything- , log_action = \_ _ _ _ _ -> return ()- -- , verbosity = 3- } `xopt_set` Opt_MagicHash- -- `gopt_set` Opt_Hpc- `gopt_set` Opt_ImplicitImportQualified- `gopt_set` Opt_PIC-#if __GLASGOW_HASKELL__ >= 710- `gopt_set` Opt_Debug-#endif- (df'',_,_) <- parseDynamicFlags df' (map noLoc $ ghcOptions cfg)- setSessionDynFlags $ df'' -- {profAuto = ProfAutoAll}--compileCFiles cfg- = do df <- getSessionDynFlags- setSessionDynFlags $ df { includePaths = nub $ idirs cfg ++ includePaths df- , importPaths = nub $ idirs cfg ++ importPaths df- , libraryPaths = nub $ idirs cfg ++ libraryPaths df }- hsc <- getSession- os <- mapM (\x -> liftIO $ compileFile hsc StopLn (x,Nothing)) (nub $ cFiles cfg)- df <- getSessionDynFlags- setSessionDynFlags $ df { ldInputs = map (FileOption "") os ++ ldInputs df }---mgi_namestring = moduleNameString . moduleName . mgi_module--importVars = freeVars S.empty--definedVars = concatMap defs- where- defs (NonRec x _) = [x]- defs (Rec xes) = map fst xes------------------------------------------------------------------------ | Extracting CoreBindings From File -----------------------------------------------------------------------------------------------getGhcModGuts1 :: FilePath -> Ghc MGIModGuts-getGhcModGuts1 fn = do- modGraph <- getModuleGraph- case find ((== fn) . msHsFilePath) modGraph of- Just modSummary -> do- -- mod_guts <- modSummaryModGuts modSummary- mod_p <- parseModule modSummary- mod_guts <- coreModule <$> (desugarModule =<< typecheckModule (ignoreInline mod_p))- let deriv = getDerivedDictionaries mod_guts - return $! (miModGuts (Just deriv) mod_guts)- Nothing -> exitWithPanic "Ghc Interface: Unable to get GhcModGuts"--getDerivedDictionaries cm = instEnvElts $ mg_inst_env cm--cleanFiles :: FilePath -> IO ()-cleanFiles fn- = do forM_ bins (tryIgnore "delete binaries" . removeFileIfExists)- tryIgnore "create temp directory" $ createDirectoryIfMissing False dir- where- bins = replaceExtension fn <$> ["hi", "o"]- dir = tempDirectory fn---removeFileIfExists f = doesFileExist f >>= (`when` removeFile f)------------------------------------------------------------------------------------- | Desugaring (Taken from GHC, modified to hold onto Loc in Ticks) ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | Extracting Qualifiers ----------------------------------------------------------------------------------------------------------------------------------------moduleHquals mg paths target imps incs- = do hqs <- specIncludes Hquals paths incs- hqs' <- moduleImports [Hquals] paths (mgi_namestring mg : imps)- hqs'' <- liftIO $ filterM doesFileExist [extFileName Hquals target]- let rv = sortNub $ hqs'' ++ hqs ++ (snd <$> hqs')- liftIO $ whenLoud $ putStrLn $ "Reading Qualifiers From: " ++ show rv- return rv------------------------------------------------------------------------------------- | Extracting Specifications (Measures + Assumptions) -----------------------------------------------------------------------------------------------------------moduleSpec cfg cbs vars defVars target mg tgtSpec logicmap impSpecs- = do addImports impSpecs- addContext $ IIModule $ moduleName $ mgi_module mg- env <- getSession- let specs = (target,tgtSpec):impSpecs- let imps = sortNub $ impNames ++ [ symbolString x- | (_,spec) <- specs- , x <- Ms.imports spec- ]- ghcSpec <- liftIO $ makeGhcSpec cfg target cbs vars defVars exports env logicmap specs- return (ghcSpec, imps, Ms.includes tgtSpec)- where- exports = mgi_exports mg- impNames = map (getModString.fst) impSpecs- addImports = mapM (addContext . IIDecl . qualImportDecl . getModName . fst)--allDepNames = concatMap (map declNameString . ms_textual_imps)--declNameString = moduleNameString . unLoc . ideclName . unLoc--patErrorName = "PatErr"-realSpecName = "Real"-notRealSpecName = "NotReal"--getSpecs rflag tflag target paths names exts- = do fs' <- sortNub <$> moduleImports exts paths names- patSpec <- getPatSpec paths tflag- rlSpec <- getRealSpec paths rflag- let fs = patSpec ++ rlSpec ++ fs'- liftIO $ whenLoud $ putStrLn ("getSpecs: " ++ show fs)- transParseSpecs exts paths (S.singleton target) mempty (map snd fs)--getPatSpec paths totalitycheck- | totalitycheck- = (map (patErrorName, )) . maybeToList <$> moduleFile paths patErrorName Spec- | otherwise- = return []--getRealSpec paths freal- | freal- = (map (realSpecName, )) . maybeToList <$> moduleFile paths realSpecName Spec- | otherwise- = (map (notRealSpecName, )) . maybeToList <$> moduleFile paths notRealSpecName Spec--transParseSpecs _ _ _ specs []- = return specs-transParseSpecs exts paths seenFiles specs newFiles- = do newSpecs <- liftIO $ mapM (\f -> addFst3 f <$> parseSpec f) newFiles- impFiles <- moduleImports exts paths $ specsImports newSpecs- let seenFiles' = seenFiles `S.union` (S.fromList newFiles)- let specs' = specs ++ map (third noTerm) newSpecs- let newFiles' = [f | (_,f) <- impFiles, not (f `S.member` seenFiles')]- transParseSpecs exts paths seenFiles' specs' newFiles'- where- specsImports ss = nub $ concatMap (map symbolString . Ms.imports . thd3) ss- noTerm spec = spec { Ms.decr=mempty, Ms.lazy=mempty, Ms.termexprs=mempty }- third f (a,b,c) = (a,b,f c)--parseSpec :: FilePath -> IO (ModName, Ms.BareSpec)-parseSpec file- = do whenLoud $ putStrLn $ "parseSpec: " ++ file- either Ex.throw return . specParser file =<< readFile file--specParser file str- | isExtFile Spec file = specSpecificationP file str- | isExtFile Hs file = hsSpecificationP file str- | isExtFile LHs file = lhsSpecificationP file str- | otherwise = exitWithPanic $ "SpecParser: Cannot Parse File " ++ file--moduleImports :: GhcMonad m => [Ext] -> [FilePath] -> [String] -> m [(String, FilePath)]-moduleImports exts paths names- = liftM concat $ forM names $ \name -> do- map (name,) . catMaybes <$> mapM (moduleFile paths name) exts--moduleFile :: GhcMonad m => [FilePath] -> String -> Ext -> m (Maybe FilePath)-moduleFile paths name ext- | ext `elem` [Hs, LHs]- = do mg <- getModuleGraph- case find ((==name) . moduleNameString . ms_mod_name) mg of- Nothing -> liftIO $ getFileInDirs (extModuleName name ext) paths- Just ms -> return $ normalise <$> ml_hs_file (ms_location ms)- | otherwise- = liftIO $ getFileInDirs (extModuleName name ext) paths--specIncludes :: GhcMonad m => Ext -> [FilePath] -> [FilePath] -> m [FilePath]-specIncludes ext paths reqs- = do let libFile = extFileNameR ext $ symbolString preludeName- let incFiles = catMaybes $ reqFile ext <$> reqs- liftIO $ forM (libFile : incFiles) $ \f -> do- mfile <- getFileInDirs f paths- case mfile of- Just file -> return file- Nothing -> errorstar $ "cannot find " ++ f ++ " in " ++ show paths--reqFile ext s- | isExtFile ext s- = Just s- | otherwise- = Nothing------instance PPrint GhcSpec where- pprint spec = (text "******* Target Variables ********************")- $$ (pprint $ tgtVars spec)- $$ (text "******* Type Signatures *********************")- $$ (pprintLongList $ tySigs spec)- $$ (text "******* Assumed Type Signatures *************")- $$ (pprintLongList $ asmSigs spec)- $$ (text "******* DataCon Specifications (Measure) ****")- $$ (pprintLongList $ ctors spec)- $$ (text "******* Measure Specifications **************")- $$ (pprintLongList $ meas spec)--instance PPrint GhcInfo where- pprint info = (text "*************** Imports *********************")- $+$ (intersperse comma $ text <$> imports info)- $+$ (text "*************** Includes ********************")- $+$ (intersperse comma $ text <$> includes info)- $+$ (text "*************** Imported Variables **********")- $+$ (pprDoc $ impVars info)- $+$ (text "*************** Defined Variables ***********")- $+$ (pprDoc $ defVars info)- $+$ (text "*************** Specification ***************")- $+$ (pprint $ spec info)- $+$ (text "*************** Core Bindings ***************")- $+$ (pprint $ cbs info)--instance Show GhcInfo where- show = showpp--instance PPrint [CoreBind] where- pprint = pprDoc . tidyCBs--instance PPrint TargetVars where- pprint AllVars = text "All Variables"- pprint (Only vs) = text "Only Variables: " <+> pprint vs----------------------------------------------------------------------------- Dealing With Errors ----------------------------------------------------------------------------------------------------------------------------- | Convert a GHC error into one of ours-instance Result SourceError where- result = (`Crash` "Invalid Source")- . concatMap errMsgErrors- . bagToList- . srcErrorMessages--errMsgErrors e = [ ErrGhc (errMsgSpan e) (pprint e)]
− src/Language/Haskell/Liquid/GhcMisc.hs
@@ -1,520 +0,0 @@-{-# LANGUAGE CPP #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE GADTs #-}-{-# LANGUAGE NoMonomorphismRestriction #-}-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE TupleSections #-}-{-# LANGUAGE TypeSynonymInstances #-}-{-# LANGUAGE UndecidableInstances #-}---- | This module contains a wrappers and utility functions for--- accessing GHC module information. It should NEVER depend on--- ANY module inside the Language.Haskell.Liquid.* tree.--module Language.Haskell.Liquid.GhcMisc where--import PrelNames (fractionalClassKeys)-import Class (classKey)--import Debug.Trace--import Avail (availsToNameSet)-import BasicTypes (Arity)-import CoreSyn hiding (Expr, sourceName)-import qualified CoreSyn as Core-import CostCentre-import GHC hiding (L)-import HscTypes (Dependencies, ImportedMods, ModGuts(..))-import Kind (superKind)-import NameSet (NameSet)-import SrcLoc (mkRealSrcLoc, mkRealSrcSpan, srcSpanFileName_maybe)-import Bag-import ErrUtils-import CoreLint-import CoreMonad--import Language.Fixpoint.Names (dropModuleNames)-import Text.Parsec.Pos (sourceName, sourceLine, sourceColumn, SourcePos, newPos)-import Language.Fixpoint.Types hiding (Constant (..), SESearch(..))-import Name (mkInternalName, getSrcSpan, nameModule_maybe)-import Module (moduleNameFS)-import OccName (mkTyVarOcc, mkTcOcc, occNameFS)-import Unique-import Finder (findImportedModule, cannotFindModule)-import Panic (throwGhcException)-import HscTypes (HscEnv(..), FindResult(..))-import FastString-import TcRnDriver-import TcRnTypes--import RdrName-import Type (liftedTypeKind)-import TypeRep-import Var-import IdInfo-import qualified TyCon as TC--- import qualified DataCon as DC-import Data.Char (isLower, isSpace)-import Data.Monoid (mempty)-import Data.Hashable-import qualified Data.HashSet as S-import qualified Data.List as L-import Data.Aeson-import qualified Data.Text.Encoding as T-import qualified Data.Text.Unsafe as T-import Control.Applicative ((<$>), (<*>))-import Control.Arrow (second)-import Outputable (Outputable (..), text, ppr)-import qualified Outputable as Out-import DynFlags--import qualified Text.PrettyPrint.HughesPJ as PJ--import Data.Monoid (mappend)--import Language.Fixpoint.Names (symSepName, isSuffixOfSym, singletonSym)---#if __GLASGOW_HASKELL__ < 710-import Language.Haskell.Liquid.Desugar.HscMain-#else-import Language.Haskell.Liquid.Desugar710.HscMain---import qualified HscMain as GHC-#endif------------------------------------------------------------------------------------------ Datatype For Holding GHC ModGuts ------------------------------------------------------------------------------------------------data MGIModGuts = MI {- mgi_binds :: !CoreProgram- , mgi_module :: !Module- , mgi_deps :: !Dependencies- , mgi_dir_imps :: !ImportedMods- , mgi_rdr_env :: !GlobalRdrEnv- , mgi_tcs :: ![TyCon]- , mgi_fam_insts :: ![FamInst]- , mgi_exports :: !NameSet- , mgi_cls_inst :: !(Maybe [ClsInst])- }--miModGuts cls mg = MI {- mgi_binds = mg_binds mg- , mgi_module = mg_module mg- , mgi_deps = mg_deps mg- , mgi_dir_imps = mg_dir_imps mg- , mgi_rdr_env = mg_rdr_env mg- , mgi_tcs = mg_tcs mg- , mgi_fam_insts = mg_fam_insts mg- , mgi_exports = availsToNameSet $ mg_exports mg- , mgi_cls_inst = cls- }----------------------------------------------------------------------------------------- Generic Helpers for Encoding Location -------------------------------------------------------------------------------------------srcSpanTick :: Module -> SrcSpan -> Tickish a-srcSpanTick m loc- = ProfNote (AllCafsCC m loc) False True--tickSrcSpan :: Outputable a => Tickish a -> SrcSpan-tickSrcSpan (ProfNote cc _ _) = cc_loc cc-#if __GLASGOW_HASKELL__ >= 710-tickSrcSpan (SourceNote ss _) = RealSrcSpan ss-#endif-tickSrcSpan _ = noSrcSpan----------------------------------------------------------------------------------------- Generic Helpers for Accessing GHC Innards ---------------------------------------------------------------------------------------stringTyVar :: String -> TyVar-stringTyVar s = mkTyVar name liftedTypeKind- where name = mkInternalName (mkUnique 'x' 24) occ noSrcSpan- occ = mkTyVarOcc s--stringTyCon :: Char -> Int -> String -> TyCon-stringTyCon c n s = TC.mkKindTyCon name superKind- where- name = mkInternalName (mkUnique c n) occ noSrcSpan- occ = mkTcOcc s--hasBaseTypeVar = isBaseType . varType---- same as Constraint isBase-isBaseType (TyVarTy _) = True-isBaseType (TyConApp _ ts) = all isBaseType ts-isBaseType (FunTy t1 t2) = isBaseType t1 && isBaseType t2-isBaseType _ = False-validTyVar :: String -> Bool-validTyVar s@(c:_) = isLower c && all (not . isSpace) s-validTyVar _ = False--tvId α = {- traceShow ("tvId: α = " ++ show α) $ -} showPpr α ++ show (varUnique α)--tracePpr s x = trace ("\nTrace: [" ++ s ++ "] : " ++ showPpr x) x--pprShow = text . show---tidyCBs = map unTick--unTick (NonRec b e) = NonRec b (unTickExpr e)-unTick (Rec bs) = Rec $ map (second unTickExpr) bs--unTickExpr (App e a) = App (unTickExpr e) (unTickExpr a)-unTickExpr (Lam b e) = Lam b (unTickExpr e)-unTickExpr (Let b e) = Let (unTick b) (unTickExpr e)-unTickExpr (Case e b t as) = Case (unTickExpr e) b t (map unTickAlt as)- where unTickAlt (a, b, e) = (a, b, unTickExpr e)-unTickExpr (Cast e c) = Cast (unTickExpr e) c-unTickExpr (Tick _ e) = unTickExpr e-unTickExpr x = x--isFractionalClass clas = classKey clas `elem` fractionalClassKeys-------------------------------------------------------------------------------------------- Generic Helpers for DataConstructors -----------------------------------------------------------------------------------------isDataConId id = case idDetails id of- DataConWorkId _ -> True- DataConWrapId _ -> True- _ -> False--getDataConVarUnique v- | isId v && isDataConId v = getUnique $ idDataCon v- | otherwise = getUnique v---newtype Loc = L (Int, Int) deriving (Eq, Ord, Show)--instance Hashable Loc where- hashWithSalt i (L z) = hashWithSalt i z----instance (Uniquable a) => Hashable a where--instance Hashable SrcSpan where- hashWithSalt i (UnhelpfulSpan s) = hashWithSalt i (uniq s)- hashWithSalt i (RealSrcSpan s) = hashWithSalt i (srcSpanStartLine s, srcSpanStartCol s, srcSpanEndCol s)--instance Outputable a => Outputable (S.HashSet a) where- ppr = ppr . S.toList--instance ToJSON RealSrcSpan where- toJSON sp = object [ "filename" .= f -- (unpackFS $ srcSpanFile sp)- , "startLine" .= l1 -- srcSpanStartLine sp- , "startCol" .= c1 -- srcSpanStartCol sp- , "endLine" .= l2 -- srcSpanEndLine sp- , "endCol" .= c2 -- srcSpanEndCol sp- ]- where- (f, l1, c1, l2, c2) = unpackRealSrcSpan sp--unpackRealSrcSpan rsp = (f, l1, c1, l2, c2)- where- f = unpackFS $ srcSpanFile rsp- l1 = srcSpanStartLine rsp- c1 = srcSpanStartCol rsp- l2 = srcSpanEndLine rsp- c2 = srcSpanEndCol rsp---instance FromJSON RealSrcSpan where- parseJSON (Object v) = realSrcSpan <$> v .: "filename"- <*> v .: "startLine"- <*> v .: "startCol"- <*> v .: "endLine"- <*> v .: "endCol"- parseJSON _ = mempty--realSrcSpan f l1 c1 l2 c2 = mkRealSrcSpan loc1 loc2- where- loc1 = mkRealSrcLoc (fsLit f) l1 c1- loc2 = mkRealSrcLoc (fsLit f) l2 c2----instance ToJSON SrcSpan where- toJSON (RealSrcSpan rsp) = object [ "realSpan" .= True, "spanInfo" .= rsp ]- toJSON (UnhelpfulSpan _) = object [ "realSpan" .= False ]--instance FromJSON SrcSpan where- parseJSON (Object v) = do tag <- v .: "realSpan"- case tag of- False -> return noSrcSpan- True -> RealSrcSpan <$> v .: "spanInfo"- parseJSON _ = mempty------------------------------------------------------------toFixSDoc = PJ.text . PJ.render . toFix-sDocDoc = PJ.text . showSDoc-pprDoc = sDocDoc . ppr---- Overriding Outputable functions because they now require DynFlags!-showPpr = showSDoc . ppr---- FIXME: somewhere we depend on this printing out all GHC entities with--- fully-qualified names...-showSDoc sdoc = Out.renderWithStyle unsafeGlobalDynFlags sdoc (Out.mkUserStyle Out.alwaysQualify Out.AllTheWay)-showSDocDump = Out.showSDocDump unsafeGlobalDynFlags--typeUniqueString = {- ("sort_" ++) . -} showSDocDump . ppr--instance Fixpoint Var where- toFix = pprDoc--instance Fixpoint Name where- toFix = pprDoc--instance Fixpoint Type where- toFix = pprDoc--instance Show Name where- show = showPpr--instance Show Var where- show = showPpr--instance Show Class where- show = showPpr--instance Show TyCon where- show = showPpr--sourcePosSrcSpan :: SourcePos -> SrcSpan-sourcePosSrcSpan = srcLocSpan . sourcePosSrcLoc--sourcePosSrcLoc :: SourcePos -> SrcLoc-sourcePosSrcLoc p = mkSrcLoc (fsLit file) line col- where- file = sourceName p- line = sourceLine p- col = sourceColumn p--srcSpanSourcePos :: SrcSpan -> SourcePos-srcSpanSourcePos (UnhelpfulSpan _) = dummyPos "LH.GhcMisc.srcSpanSourcePos"-srcSpanSourcePos (RealSrcSpan s) = realSrcSpanSourcePos s--srcSpanSourcePosE :: SrcSpan -> SourcePos-srcSpanSourcePosE (UnhelpfulSpan _) = dummyPos "LH.GhcMisc.srcSpanSourcePos"-srcSpanSourcePosE (RealSrcSpan s) = realSrcSpanSourcePosE s----srcSpanFilename = maybe "" unpackFS . srcSpanFileName_maybe-srcSpanStartLoc l = L (srcSpanStartLine l, srcSpanStartCol l)-srcSpanEndLoc l = L (srcSpanEndLine l, srcSpanEndCol l)-oneLine l = srcSpanStartLine l == srcSpanEndLine l-lineCol l = (srcSpanStartLine l, srcSpanStartCol l)--realSrcSpanSourcePos :: RealSrcSpan -> SourcePos-realSrcSpanSourcePos s = newPos file line col- where- file = unpackFS $ srcSpanFile s- line = srcSpanStartLine s- col = srcSpanStartCol s---realSrcSpanSourcePosE :: RealSrcSpan -> SourcePos-realSrcSpanSourcePosE s = newPos file line col- where- file = unpackFS $ srcSpanFile s- line = srcSpanEndLine s- col = srcSpanEndCol s---getSourcePos = srcSpanSourcePos . getSrcSpan-getSourcePosE = srcSpanSourcePosE . getSrcSpan--collectArguments n e = if length xs > n then take n xs else xs- where (vs', e') = collectValBinders' $ snd $ collectTyBinders e- vs = fst $ collectValBinders $ ignoreLetBinds e'- xs = vs' ++ vs--collectValBinders' expr = go [] expr- where- go tvs (Lam b e) | isTyVar b = go tvs e- go tvs (Lam b e) | isId b = go (b:tvs) e- go tvs (Tick _ e) = go tvs e- go tvs e = (reverse tvs, e)--ignoreLetBinds (Let (NonRec _ _) e')- = ignoreLetBinds e'-ignoreLetBinds e- = e--isDictionaryExpression :: Core.Expr Id -> Maybe Id-isDictionaryExpression (Tick _ e) = isDictionaryExpression e-isDictionaryExpression (Var x) | isDictionary x = Just x-isDictionaryExpression _ = Nothing--isDictionary x = L.isPrefixOf "$f" (symbolString $ dropModuleNames $ symbol x)-isInternal x = L.isPrefixOf "$" (symbolString $ dropModuleNames $ symbol x)---realTcArity :: TyCon -> Arity-realTcArity- = kindArity . TC.tyConKind--kindArity :: Kind -> Arity-kindArity (FunTy _ res)- = 1 + kindArity res-kindArity (ForAllTy _ res)- = kindArity res-kindArity _- = 0---instance Hashable Var where- hashWithSalt = uniqueHash--instance Hashable TyCon where- hashWithSalt = uniqueHash--uniqueHash i = hashWithSalt i . getKey . getUnique---- slightly modified version of DynamicLoading.lookupRdrNameInModule-lookupRdrName :: HscEnv -> ModuleName -> RdrName -> IO (Maybe Name)-lookupRdrName hsc_env mod_name rdr_name = do- -- First find the package the module resides in by searching exposed packages and home modules- found_module <- findImportedModule hsc_env mod_name Nothing- case found_module of- Found _ mod -> do- -- Find the exports of the module- (_, mb_iface) <- getModuleInterface hsc_env mod- case mb_iface of- Just iface -> do- -- Try and find the required name in the exports- let decl_spec = ImpDeclSpec { is_mod = mod_name, is_as = mod_name- , is_qual = False, is_dloc = noSrcSpan }- provenance = Imported [ImpSpec decl_spec ImpAll]- env = case mi_globals iface of- Nothing -> mkGlobalRdrEnv (gresFromAvails provenance (mi_exports iface))- Just e -> e- case lookupGRE_RdrName rdr_name env of- [gre] -> return (Just (gre_name gre))- [] -> return Nothing- _ -> Out.panic "lookupRdrNameInModule"- Nothing -> throwCmdLineErrorS dflags $ Out.hsep [Out.ptext (sLit "Could not determine the exports of the module"), ppr mod_name]- err -> throwCmdLineErrorS dflags $ cannotFindModule dflags mod_name err- where dflags = hsc_dflags hsc_env- throwCmdLineErrorS dflags = throwCmdLineError . Out.showSDoc dflags- throwCmdLineError = throwGhcException . CmdLineError---addContext m = getContext >>= setContext . (m:)--qualImportDecl mn = (simpleImportDecl mn) { ideclQualified = True }--ignoreInline x = x {pm_parsed_source = go <$> pm_parsed_source x}- where go x = x {hsmodDecls = filter go' $ hsmodDecls x}- go' x | SigD (InlineSig _ _) <- unLoc x = False- | otherwise = True--symbolTyCon x i n = stringTyCon x i (symbolString n)-symbolTyVar n = stringTyVar (symbolString n)--instance Symbolic TyCon where- symbol = symbol . qualifiedNameSymbol . getName--instance Symbolic Name where- symbol = symbol . showPpr -- qualifiedNameSymbol---instance Symbolic Var where- symbol = varSymbol--varSymbol :: Var -> Symbol-varSymbol v- | us `isSuffixOfSym` vs = vs- | otherwise = vs `mappend` singletonSym symSepName `mappend` us- where us = symbol $ showPpr $ getDataConVarUnique v- vs = symbol $ getName v---qualifiedNameSymbol n = symbol $- case nameModule_maybe n of- Nothing -> occNameFS (getOccName n)- Just m -> concatFS [moduleNameFS (moduleName m), fsLit ".", occNameFS (getOccName n)]--instance Symbolic FastString where- symbol = symbol . fastStringText--fastStringText = T.decodeUtf8 . fastStringToByteString--tyConTyVarsDef c | TC.isPrimTyCon c || isFunTyCon c = []-tyConTyVarsDef c | TC.isPromotedTyCon c = error ("TyVars on " ++ show c) -- tyConTyVarsDef $ TC.ty_con c-tyConTyVarsDef c | TC.isPromotedDataCon c = error ("TyVars on " ++ show c) -- DC.dataConUnivTyVars $ TC.datacon c-tyConTyVarsDef c = TC.tyConTyVars c ----------------------------------------------------------------------------- GHC Compatibility Layer-------------------------------------------------------------------------gHC_VERSION :: String-gHC_VERSION = show __GLASGOW_HASKELL__--desugarModule :: TypecheckedModule -> Ghc DesugaredModule--symbolFastString :: Symbol -> FastString--lintCoreBindings :: [Var] -> CoreProgram -> (Bag MsgDoc, Bag MsgDoc)--synTyConRhs_maybe :: TyCon -> Maybe Type--tcRnLookupRdrName :: HscEnv -> GHC.Located RdrName -> IO (Messages, Maybe [Name])--desugarModule tcm = do- let ms = pm_mod_summary $ tm_parsed_module tcm - -- let ms = modSummary tcm- let (tcg, _) = tm_internals_ tcm- hsc_env <- getSession- let hsc_env_tmp = hsc_env { hsc_dflags = ms_hspp_opts ms }- guts <- liftIO $ hscDesugarWithLoc hsc_env_tmp ms tcg- return $ DesugaredModule { dm_typechecked_module = tcm, dm_core_module = guts }--#if __GLASGOW_HASKELL__ < 710---- desugarModule tcm = do--- let ms = pm_mod_summary $ tm_parsed_module tcm --- -- let ms = modSummary tcm--- let (tcg, _) = tm_internals_ tcm--- hsc_env <- getSession--- let hsc_env_tmp = hsc_env { hsc_dflags = ms_hspp_opts ms }--- guts <- liftIO $ hscDesugarWithLoc hsc_env_tmp ms tcg--- return $ DesugaredModule { dm_typechecked_module = tcm, dm_core_module = guts }--symbolFastString = T.unsafeDupablePerformIO . mkFastStringByteString . T.encodeUtf8 . symbolText--lintCoreBindings = CoreLint.lintCoreBindings--synTyConRhs_maybe t- | Just (TC.SynonymTyCon rhs) <- TC.synTyConRhs_maybe t- = Just rhs-synTyConRhs_maybe _ = Nothing--tcRnLookupRdrName env rn = TcRnDriver.tcRnLookupRdrName env (unLoc rn)--#else---- desugarModule = GHC.desugarModule--symbolFastString = mkFastStringByteString . T.encodeUtf8 . symbolText--type Prec = TyPrec--lintCoreBindings = CoreLint.lintCoreBindings CoreDoNothing--synTyConRhs_maybe = TC.synTyConRhs_maybe--tcRnLookupRdrName = TcRnDriver.tcRnLookupRdrName--#endif
− src/Language/Haskell/Liquid/GhcPlay.hs
@@ -1,84 +0,0 @@-{-# LANGUAGE NoMonomorphismRestriction #-}-{-# LANGUAGE TypeSynonymInstances #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE TupleSections #-}--module Language.Haskell.Liquid.GhcPlay where--import GHC-import CoreSyn-import Var-import TypeRep-import TcRnMonad-import Coercion--import Control.Arrow ((***))-import qualified Data.HashMap.Strict as M--import Language.Haskell.Liquid.GhcMisc ()--class Subable a where- sub :: M.HashMap CoreBndr CoreExpr -> a -> a- subTy :: M.HashMap TyVar Type -> a -> a--instance Subable CoreExpr where- sub s (Var v) = M.lookupDefault (Var v) v s- sub _ (Lit l) = Lit l- sub s (App e1 e2) = App (sub s e1) (sub s e2)- sub s (Lam b e) = Lam b (sub s e)- sub s (Let b e) = Let (sub s b) (sub s e)- sub s (Case e b t a) = Case (sub s e) (sub s b) t (map (sub s) a)- sub s (Cast e c) = Cast (sub s e) c- sub s (Tick t e) = Tick t (sub s e)- sub _ (Type t) = Type t- sub _ (Coercion c) = Coercion c-- subTy s (Var v) = Var (subTy s v)- subTy _ (Lit l) = Lit l- subTy s (App e1 e2) = App (subTy s e1) (subTy s e2)- subTy s (Lam b e) | isTyVar b = Lam v' (subTy s e)- where v' = case M.lookup b s of- Just (TyVarTy v) -> v- _ -> b-- subTy s (Lam b e) = Lam (subTy s b) (subTy s e)- subTy s (Let b e) = Let (subTy s b) (subTy s e)- subTy s (Case e b t a) = Case (subTy s e) (subTy s b) (subTy s t) (map (subTy s) a)- subTy s (Cast e c) = Cast (subTy s e) (subTy s c)- subTy s (Tick t e) = Tick t (subTy s e)- subTy s (Type t) = Type (subTy s t)- subTy s (Coercion c) = Coercion (subTy s c)--instance Subable Coercion where- sub _ c = c- subTy _ _ = error "subTy Coercion"--instance Subable (Alt Var) where- sub s (a, b, e) = (a, map (sub s) b, sub s e)- subTy s (a, b, e) = (a, map (subTy s) b, subTy s e)--instance Subable Var where- sub s v | M.member v s = subVar $ s M.! v- | otherwise = v- subTy s v = setVarType v (subTy s (varType v))--subVar (Var x) = x-subVar _ = error "sub Var"--instance Subable (Bind Var) where- sub s (NonRec x e) = NonRec (sub s x) (sub s e)- sub s (Rec xes) = Rec ((sub s *** sub s) <$> xes)-- subTy s (NonRec x e) = NonRec (subTy s x) (subTy s e)- subTy s (Rec xes) = Rec ((subTy s *** subTy s) <$> xes)--instance Subable Type where- sub _ e = e- subTy = substTysWith--substTysWith s tv@(TyVarTy v) = M.lookupDefault tv v s-substTysWith s (FunTy t1 t2) = FunTy (substTysWith s t1) (substTysWith s t2)-substTysWith s (ForAllTy v t) = ForAllTy v (substTysWith (M.delete v s) t)-substTysWith s (TyConApp c ts) = TyConApp c (map (substTysWith s) ts)-substTysWith s (AppTy t1 t2) = AppTy (substTysWith s t1) (substTysWith s t2)-substTysWith _ (LitTy t) = LitTy t
+ src/Language/Haskell/Liquid/Interactive/Handler.hs view
@@ -0,0 +1,30 @@+module Language.Haskell.Liquid.Interactive.Handler (+ -- * Initial state for server+ initial++ -- * Command handler+ , handler+ ) where++import Prelude hiding (error)+import Control.Concurrent.MVar+import Language.Haskell.Liquid.Interactive.Types+import Language.Haskell.Liquid.Liquid++------------------------------------------------------------------------------+handler :: MVar State -> Command -> IO Response+------------------------------------------------------------------------------+handler r = modifyMVar r . runLiquid'++runLiquid' :: Command -> State -> IO (State, Response)+runLiquid' cfg s = do+ let mE = sMbEnv s+ let n = sCount s+ (c, mE') <- runLiquid mE cfg+ let s' = State (n + 1) mE'+ return (s', (status c, n))++------------------------------------------------------------------------------+initial :: State+------------------------------------------------------------------------------+initial = State 0 Nothing
+ src/Language/Haskell/Liquid/Interactive/Types.hs view
@@ -0,0 +1,57 @@+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE FlexibleInstances #-}++module Language.Haskell.Liquid.Interactive.Types+ (+ -- * Commands+ Command++ -- * Response+ , Response++ , status++ -- * State+ , State (..)++ ) where++import Prelude hiding (error)+import Data.Serialize ( Serialize )+import GHC.Generics+import System.Console.CmdArgs+import System.Exit+import Language.Haskell.Liquid.Types (Config (..))+import Language.Haskell.Liquid.Liquid+import Language.Fixpoint.Types ()++-------------------------------------------------------------------------------+-- | State --------------------------------------------------------------------+-------------------------------------------------------------------------------++data State = State { sCount :: Int+ , sMbEnv :: MbEnv+ }++-------------------------------------------------------------------------------+-- | Command ------------------------------------------------------------------+-------------------------------------------------------------------------------++type Command = Config++-------------------------------------------------------------------------------+-- | Response -----------------------------------------------------------------+-------------------------------------------------------------------------------++data Status = ResOk+ | ResFail Int+ deriving ( Generic, Data, Typeable, Show )++type Response = (Status, Int)++instance Serialize Status++status :: ExitCode -> Status+status ExitSuccess = ResOk+status (ExitFailure n) = ResFail n
+ src/Language/Haskell/Liquid/Liquid.hs view
@@ -0,0 +1,204 @@+{-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE TupleSections #-}+{-# LANGUAGE ScopedTypeVariables #-}++{-@ LIQUID "--diff" @-}++module Language.Haskell.Liquid.Liquid (+ -- * Executable command+ liquid++ -- * Single query+ , runLiquid++ -- * Ghci State+ , MbEnv+ ) where++import Prelude hiding (error)+import Data.Maybe+import System.Exit+import Control.DeepSeq+import Text.PrettyPrint.HughesPJ+import CoreSyn+import Var+import HscTypes (SourceError)+import System.Console.CmdArgs.Verbosity (whenLoud, whenNormal)+import System.Console.CmdArgs.Default+import GHC (HscEnv)++import qualified Control.Exception as Ex+import qualified Language.Fixpoint.Types.Config as FC+import qualified Language.Haskell.Liquid.UX.DiffCheck as DC+import Language.Fixpoint.Misc+import Language.Fixpoint.Solver+import qualified Language.Fixpoint.Types as F+import Language.Haskell.Liquid.Types+import Language.Haskell.Liquid.UX.Errors+import Language.Haskell.Liquid.UX.CmdLine+import Language.Haskell.Liquid.UX.Tidy+import Language.Haskell.Liquid.GHC.Interface+import Language.Haskell.Liquid.Constraint.Generate+import Language.Haskell.Liquid.Constraint.ToFixpoint+import Language.Haskell.Liquid.Constraint.Types+import Language.Haskell.Liquid.Transforms.Rec+import Language.Haskell.Liquid.UX.Annotate (mkOutput)++type MbEnv = Maybe HscEnv++------------------------------------------------------------------------------+liquid :: [String] -> IO b+------------------------------------------------------------------------------+liquid args = getOpts args >>= runLiquid Nothing >>= exitWith . fst++------------------------------------------------------------------------------+-- | This fellow does the real work+------------------------------------------------------------------------------+runLiquid :: MbEnv -> Config -> IO (ExitCode, MbEnv)+------------------------------------------------------------------------------+runLiquid mE cfg = do+ (d, mE') <- checkMany cfg mempty mE (files cfg)+ return (ec d, mE')+ where+ ec = resultExit . o_result+++------------------------------------------------------------------------------+checkMany :: Config -> Output Doc -> MbEnv -> [FilePath] -> IO (Output Doc, MbEnv)+------------------------------------------------------------------------------+checkMany cfg d mE (f:fs) = do+ (d', mE') <- checkOne mE cfg f+ checkMany cfg (d `mappend` d') mE' fs++checkMany _ d mE [] =+ return (d, mE)++------------------------------------------------------------------------------+checkOne :: MbEnv -> Config -> FilePath -> IO (Output Doc, Maybe HscEnv)+------------------------------------------------------------------------------+checkOne mE cfg t = do+ z <- actOrDie (checkOne' mE cfg t)+ case z of+ Left e -> do+ d <- exitWithResult cfg t $ mempty { o_result = e }+ return (d, Nothing)+ Right r ->+ return r+++checkOne' :: MbEnv -> Config -> FilePath -> IO (Output Doc, Maybe HscEnv)+checkOne' mE cfg t = do+ (gInfo, hEnv) <- getGhcInfo mE cfg t+ d <- liquidOne t gInfo+ return (d, Just hEnv)+++actOrDie :: IO a -> IO (Either ErrorResult a)+actOrDie act =+ (Right <$> act)+ `Ex.catch` (\(e :: SourceError) -> handle e)+ `Ex.catch` (\(e :: Error) -> handle e)+ `Ex.catch` (\(e :: UserError) -> handle e)+ `Ex.catch` (\(e :: [Error]) -> handle e)++handle :: (Result a) => a -> IO (Either ErrorResult b)+handle = return . Left . result++------------------------------------------------------------------------------+liquidOne :: FilePath -> GhcInfo -> IO (Output Doc)+------------------------------------------------------------------------------+liquidOne tgt info = do+ whenNormal $ donePhase Loud "Extracted Core using GHC"+ let cfg = config $ spec info+ whenLoud $ do putStrLn "**** Config **************************************************"+ print cfg+ whenLoud $ do putStrLn $ showpp info+ putStrLn "*************** Original CoreBinds ***************************"+ putStrLn $ render $ pprintCBs (cbs info)+ let cbs' = transformScope (cbs info)+ whenLoud $ do donePhase Loud "transformRecExpr"+ putStrLn "*************** Transform Rec Expr CoreBinds *****************"+ putStrLn $ render $ pprintCBs cbs'+ putStrLn "*************** Slicing Out Unchanged CoreBinds *****************"+ dc <- prune cfg cbs' tgt info+ let cbs'' = maybe cbs' DC.newBinds dc+ let info' = maybe info (\z -> info {spec = DC.newSpec z}) dc+ let cgi = {-# SCC "generateConstraints" #-} generateConstraints $! info' {cbs = cbs''}+ cgi `deepseq` donePhase Loud "generateConstraints"+ whenLoud $ dumpCs cgi+ out <- solveCs cfg tgt cgi info' dc+ whenNormal $ donePhase Loud "solve"+ let out' = mconcat [maybe mempty DC.oldOutput dc, out]+ DC.saveResult tgt out'+ exitWithResult cfg tgt out'++dumpCs :: CGInfo -> IO ()+dumpCs cgi = do+ putStrLn "***************************** SubCs *******************************"+ putStrLn $ render $ pprintMany (hsCs cgi)+ putStrLn "***************************** FixCs *******************************"+ putStrLn $ render $ pprintMany (fixCs cgi)+ putStrLn "***************************** WfCs ********************************"+ putStrLn $ render $ pprintMany (hsWfs cgi)++pprintMany :: (PPrint a) => [a] -> Doc+pprintMany xs = vcat [ pprint x $+$ text " " | x <- xs ]++checkedNames :: Maybe DC.DiffCheck -> Maybe [String]+checkedNames dc = concatMap names . DC.newBinds <$> dc+ where+ names (NonRec v _ ) = [render . text $ shvar v]+ names (Rec xs) = map (shvar . fst) xs+ shvar = showpp . varName++prune :: Config -> [CoreBind] -> FilePath -> GhcInfo -> IO (Maybe DC.DiffCheck)+prune cfg cbinds tgt info+ | not (null vs) = return . Just $ DC.DC (DC.thin cbinds vs) mempty sp+ | diffcheck cfg = DC.slice tgt cbinds sp+ | otherwise = return Nothing+ where+ vs = tgtVars sp+ sp = spec info++++solveCs :: Config -> FilePath -> CGInfo -> GhcInfo -> Maybe DC.DiffCheck -> IO (Output Doc)+solveCs cfg tgt cgi info dc+ = do finfo <- cgInfoFInfo info cgi tgt+ F.Result r sol <- solve fx finfo+ let names = checkedNames dc+ let warns = logErrors cgi+ let annm = annotMap cgi+ let res = ferr sol r+ let out0 = mkOutput cfg res sol annm+ return $ out0 { o_vars = names }+ { o_errors = e2u sol <$> warns }+ { o_result = res }+ where+ fx = def { FC.solver = fromJust (smtsolver cfg)+ , FC.linear = linear cfg+ , FC.newcheck = newcheck cfg+ -- , FC.extSolver = extSolver cfg+ , FC.eliminate = eliminate cfg+ , FC.save = saveQuery cfg+ , FC.srcFile = tgt+ , FC.cores = cores cfg+ , FC.minPartSize = minPartSize cfg+ , FC.maxPartSize = maxPartSize cfg+ , FC.elimStats = elimStats cfg+ -- , FC.stats = True+ }+ ferr s = fmap (cinfoUserError s . snd)+++cinfoUserError :: F.FixSolution -> Cinfo -> UserError+cinfoUserError s = e2u s . cinfoError++e2u :: F.FixSolution -> Error -> UserError+e2u s = fmap pprint . tidyError s++-- writeCGI tgt cgi = {-# SCC "ConsWrite" #-} writeFile (extFileName Cgi tgt) str+-- where+-- str = {-# SCC "PPcgi" #-} showpp cgi
− src/Language/Haskell/Liquid/Literals.hs
@@ -1,52 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}-module Language.Haskell.Liquid.Literals (- literalFRefType, literalFReft, literalConst- ) where--import TypeRep-import Literal --import Language.Haskell.Liquid.Measure-import Language.Haskell.Liquid.Types-import Language.Haskell.Liquid.RefType-import Language.Haskell.Liquid.CoreToLogic (mkLit)--import qualified Language.Fixpoint.Types as F--import qualified Data.Text as T-import qualified Data.Text.Encoding as T-import Data.Monoid-import Control.Applicative----------------------------------------------------------------------------------------- Typing Literals -----------------------------------------------------------------------------------------makeRTypeBase (TyVarTy α) x- = RVar (rTyVar α) x-makeRTypeBase (TyConApp c ts) x- = rApp c ((`makeRTypeBase` mempty) <$> ts) [] x-makeRTypeBase _ _- = error "RefType : makeRTypeBase"--literalFRefType l- = makeRTypeBase (literalType l) (literalFReft l)--literalFReft l = maybe mempty mkReft $ mkLit l--mkReft e = case e of- F.ESym (F.SL str) ->- -- FIXME: unsorted equality is shady, better to not embed Add# as int..- F.meet (F.uexprReft e)- (F.reft "v" (F.PAtom F.Eq- (F.EApp (name strLen) [F.EVar "v"])- (F.ECon (F.I (fromIntegral (T.length str))))))- _ -> F.exprReft e---- | `literalConst` returns `Nothing` for unhandled lits because--- otherwise string-literals show up as global int-constants--- which blow up qualifier instantiation.--literalConst tce l = (sort, mkLit l)- where- sort = typeSort tce $ literalType l
src/Language/Haskell/Liquid/Measure.hs view
@@ -9,13 +9,13 @@ , MSpec (..) , mkM, mkMSpec, mkMSpec' , qualifySpec- , mapTy , dataConTypes , defRefType , strLen , wiredInMeasures ) where +import Prelude hiding (error) import GHC hiding (Located) import Var import Type@@ -24,30 +24,33 @@ import Text.PrettyPrint.HughesPJ hiding (first) import Text.Printf (printf) import DataCon+import Language.Haskell.Liquid.Types.Errors -import qualified Data.HashMap.Strict as M -import qualified Data.HashSet as S -import Data.List (foldl')+import qualified Data.HashMap.Strict as M+import qualified Data.HashSet as S+import Data.List (foldl', partition) -import Data.Monoid hiding ((<>))-import Data.Bifunctor-import Control.Applicative ((<$>)) -import Data.Maybe (fromMaybe) +++import Data.Maybe (fromMaybe, isNothing)+ import Language.Fixpoint.Misc-import Language.Fixpoint.Types hiding (Def, R)-import Language.Haskell.Liquid.GhcMisc+import Language.Fixpoint.Types hiding (R, SrcSpan)+import Language.Haskell.Liquid.GHC.Misc import Language.Haskell.Liquid.Types hiding (GhcInfo(..), GhcSpec (..))-import Language.Haskell.Liquid.RefType-import Language.Haskell.Liquid.Variance-import Language.Haskell.Liquid.Bounds +import Language.Haskell.Liquid.Types.RefType+import Language.Haskell.Liquid.Types.Variance+import Language.Haskell.Liquid.Types.Bounds+import Language.Haskell.Liquid.UX.Tidy+ -- MOVE TO TYPES type BareSpec = Spec BareType LocSymbol -data Spec ty bndr = Spec {- measures :: ![Measure ty bndr] -- ^ User-defined properties for ADTs+data Spec ty bndr = Spec+ { measures :: ![Measure ty bndr] -- ^ User-defined properties for ADTs , asmSigs :: ![(LocSymbol, ty)] -- ^ Assumed (unchecked) types , sigs :: ![(LocSymbol, ty)] -- ^ Imported functions and types , localSigs :: ![(LocSymbol, ty)] -- ^ Local type signatures@@ -57,17 +60,17 @@ , dataDecls :: ![DataDecl] -- ^ Predicated data definitions , includes :: ![FilePath] -- ^ Included qualifier files , aliases :: ![RTAlias Symbol BareType] -- ^ RefType aliases- , paliases :: ![RTAlias Symbol Pred] -- ^ Refinement/Predicate aliases , ealiases :: ![RTAlias Symbol Expr] -- ^ Expression aliases- , embeds :: !(TCEmb (LocSymbol)) -- ^ GHC-Tycon-to-fixpoint Tycon map+ , embeds :: !(TCEmb LocSymbol) -- ^ GHC-Tycon-to-fixpoint Tycon map , qualifiers :: ![Qualifier] -- ^ Qualifiers in source/spec files , decr :: ![(LocSymbol, [Int])] -- ^ Information on decreasing arguments- , lvars :: ![(LocSymbol)] -- ^ Variables that should be checked in the environment they are used+ , lvars :: ![LocSymbol] -- ^ Variables that should be checked in the environment they are used , lazy :: !(S.HashSet LocSymbol) -- ^ Ignore Termination Check in these Functions+ , axioms :: !(S.HashSet LocSymbol) -- ^ Binders to turn into axiomatized functions , hmeas :: !(S.HashSet LocSymbol) -- ^ Binders to turn into measures using haskell definitions , hbounds :: !(S.HashSet LocSymbol) -- ^ Binders to turn into bounds using haskell definitions , inlines :: !(S.HashSet LocSymbol) -- ^ Binders to turn into logic inline using haskell definitions- , autosize :: !(S.HashSet LocSymbol) -- ^ Type Constructors that get automatically sizing info + , autosize :: !(S.HashSet LocSymbol) -- ^ Type Constructors that get automatically sizing info , pragmas :: ![Located String] -- ^ Command-line configurations passed in through source , cmeasures :: ![Measure ty ()] -- ^ Measures attached to a type-class , imeasures :: ![Measure ty bndr] -- ^ Mappings from (measure,type) -> measure@@ -79,36 +82,6 @@ } --- MOVE TO TYPES-data MSpec ty ctor = MSpec { - ctorMap :: M.HashMap Symbol [Def ty ctor]- , measMap :: M.HashMap LocSymbol (Measure ty ctor)- , cmeasMap :: M.HashMap LocSymbol (Measure ty ())- , imeas :: ![Measure ty ctor]- }---instance (Show ty, Show ctor, PPrint ctor, PPrint ty) => Show (MSpec ty ctor) where- show (MSpec ct m cm im)- = "\nMSpec:\n" ++- "\nctorMap:\t " ++ show ct ++- "\nmeasMap:\t " ++ show m ++- "\ncmeasMap:\t " ++ show cm ++- "\nimeas:\t " ++ show im ++- "\n"--instance Eq ctor => Monoid (MSpec ty ctor) where- mempty = MSpec M.empty M.empty M.empty []-- (MSpec c1 m1 cm1 im1) `mappend` (MSpec c2 m2 cm2 im2)- | null dups- = MSpec (M.unionWith (++) c1 c2) (m1 `M.union` m2)- (cm1 `M.union` cm2) (im1 ++ im2)- | otherwise- = errorstar $ err (head dups)- where dups = [(k1, k2) | k1 <- M.keys m1 , k2 <- M.keys m2, val k1 == val k2]- err (k1, k2) = printf "\nDuplicate Measure Definitions for %s\n%s" (showpp k1) (showpp $ map loc [k1, k2])- qualifySpec name sp = sp { sigs = [ (tx x, t) | (x, t) <- sigs sp] , asmSigs = [ (tx x, t) | (x, t) <- asmSigs sp] -- , termexprs = [ (tx x, es) | (x, es) <- termexprs sp]@@ -117,11 +90,11 @@ tx = fmap (qualifySymbol name) mkM :: LocSymbol -> ty -> [Def ty bndr] -> Measure ty bndr-mkM name typ eqns +mkM name typ eqns | all ((name ==) . measure) eqns = M name typ eqns | otherwise- = errorstar $ "invalid measure definition for " ++ (show name)+ = panic Nothing $ "invalid measure definition for " ++ show name -- mkMSpec :: [Measure ty LocSymbol] -> [Measure ty ()] -> [Measure ty LocSymbol] -- -> MSpec ty LocSymbol@@ -139,14 +112,21 @@ ms' = checkDuplicateMeasure ms -- ms' = checkFail "Duplicate Measure Definition" (distinct . fmap name) ms -+--checkFail :: [Char] -> (a -> Bool) -> a -> a+--checkFail msg f x+-- | f x+-- = x+-- | otherwise+-- = errorstar $ "Check-Failure: " ++ msg +--distinct :: Ord a => [a] -> Bool+--distinct xs = length xs == length (sortNub xs) checkDuplicateMeasure ms = case M.toList dups of [] -> ms- mms -> errorstar $ concatMap err mms+ mms -> panic Nothing $ concatMap err mms where gms = group [(name m , m) | m <- ms] dups = M.filter ((1 <) . length) gms@@ -168,13 +148,13 @@ , dataDecls = dataDecls s1 ++ dataDecls s2 , includes = sortNub $ includes s1 ++ includes s2 , aliases = aliases s1 ++ aliases s2- , paliases = paliases s1 ++ paliases s2 , ealiases = ealiases s1 ++ ealiases s2- , embeds = M.union (embeds s1) (embeds s2)+ , embeds = M.union (embeds s1) (embeds s2) , qualifiers = qualifiers s1 ++ qualifiers s2 , decr = decr s1 ++ decr s2 , lvars = lvars s1 ++ lvars s2 , lazy = S.union (lazy s1) (lazy s2)+ , axioms = S.union (axioms s1) (axioms s2) , hmeas = S.union (hmeas s1) (hmeas s2) , hbounds = S.union (hbounds s1) (hbounds s2) , inlines = S.union (inlines s1) (inlines s2)@@ -200,7 +180,6 @@ , dataDecls = [] , includes = [] , aliases = []- , paliases = [] , ealiases = [] , embeds = M.empty , qualifiers = []@@ -208,6 +187,7 @@ , lvars = [] , lazy = S.empty , hmeas = S.empty+ , axioms = S.empty , hbounds = S.empty , inlines = S.empty , autosize = S.empty@@ -221,136 +201,157 @@ , bounds = M.empty } --- MOVE TO TYPES-instance Functor (Def t) where- fmap f def = def { ctor = f (ctor def) }+dataConTypes :: MSpec (RRType Reft) DataCon -> ([(Var, RRType Reft)], [(LocSymbol, RRType Reft)])+dataConTypes s = (ctorTys, measTys)+ where+ measTys = [(name m, sort m) | m <- M.elems (measMap s) ++ imeas s]+ ctorTys = concatMap makeDataConType (snd <$> (M.toList $ ctorMap s)) --- MOVE TO TYPES-instance Functor (Measure t) where- fmap f (M n s eqs) = M n s (fmap (fmap f) eqs) -instance Functor CMeasure where- fmap f (CM n t) = CM n (f t) --- MOVE TO TYPES-instance Functor (MSpec t) where- fmap f (MSpec c m cm im) = MSpec (fc c) (fm m) cm (fmap (fmap f) im)- where fc = fmap $ fmap $ fmap f- fm = fmap $ fmap f+makeDataConType :: [Def (RRType Reft) DataCon] -> [(Var, RRType Reft)]+makeDataConType []+ = []+makeDataConType ds | isNothing (dataConWrapId_maybe dc)+ = [(woId, combineDCTypes t ts)]+ where+ dc = ctor $ head ds+ woId = dataConWorkId dc+ t = varType woId+ ts = defRefType t <$> ds --- MOVE TO TYPES-instance Bifunctor Def where- first f def = def { dparams = mapSnd f <$> dparams def- , dsort = f <$> dsort def- , binds = mapSnd (f <$>) <$> binds def}- second f def = def {ctor = f $ ctor def}+makeDataConType ds+ = [(woId, extend loci woRType wrRType), (wrId, extend loci wrRType woRType)]+ where+ (wo, wr) = partition isWorkerDef ds+ dc = ctor $ head ds+ loci = loc $ measure $ head ds+ woId = dataConWorkId dc+ wot = varType woId+ wrId = dataConWrapId dc+ wrt = varType wrId+ wots = defRefType wot <$> wo+ wrts = defRefType wrt <$> wr --- MOVE TO TYPES-instance Bifunctor Measure where- first f (M n s eqs) = M n (f s) (first f <$> eqs)- second f (M n s eqs) = M n s (second f <$> eqs)+ wrRType = combineDCTypes wrt wrts+ woRType = combineDCTypes wot wots --- MOVE TO TYPES-instance Bifunctor MSpec where- first f (MSpec c m cm im) = MSpec (fmap (fmap (first f)) c) (fmap (first f) m) (fmap (first f) cm) (fmap (first f) im)- second = fmap --- MOVE TO TYPES-instance Bifunctor Spec where- first f s- = s { measures = first f <$> (measures s)- , asmSigs = second f <$> (asmSigs s)- , sigs = second f <$> (sigs s)- , localSigs = second f <$> (localSigs s)- , invariants = fmap f <$> (invariants s)- , ialiases = fmapP f <$> (ialiases s)- , cmeasures = first f <$> (cmeasures s)- , imeasures = first f <$> (imeasures s)- , classes = fmap f <$> (classes s)- , rinstance = fmap f <$> (rinstance s)- , bounds = fmap (first f) (bounds s)- }- where fmapP f (x, y) = (fmap f x, fmap f y)+ isWorkerDef def+ -- types are missing for arguments, so definition came from a logical measure+ -- and it is for the worker datacon+ | any isNothing (snd <$> binds def)+ = True+ | otherwise+ = length (binds def) == length (fst $ splitFunTys $ snd $ splitForAllTys wot) - second f s- = s { measures = fmap (second f) (measures s)- , imeasures = fmap (second f) (imeasures s)- } --- MOVE TO TYPES-instance PPrint Body where- pprint (E e) = pprint e- pprint (P p) = pprint p- pprint (R v p) = braces (pprint v <+> text "|" <+> pprint p)+extend lc t1' t2+ | Just su <- mapArgumens lc t1 t2+ = t1 `strengthenResult` (subst su $ fromMaybe mempty (stripRTypeBase $ resultTy t2))+ | otherwise+ = t1+ where+ t1 = noDummySyms t1' --- instance PPrint a => Fixpoint (PPrint a) where--- toFix (BDc c) = toFix c--- toFix (BTup n) = parens $ toFix n --- MOVE TO TYPES-instance PPrint a => PPrint (Def t a) where- pprint (Def m p c _ bs body) = pprint m <+> pprint (fst <$> p) <+> cbsd <> text " = " <> pprint body - where cbsd = parens (pprint c <> hsep (pprint `fmap` (fst <$> bs)))+resultTy = ty_res . toRTypeRep --- MOVE TO TYPES-instance (PPrint t, PPrint a) => PPrint (Measure t a) where- pprint (M n s eqs) = pprint n <> text " :: " <> pprint s- $$ vcat (pprint `fmap` eqs)+strengthenResult t r = fromRTypeRep $ rep{ty_res = ty_res rep `strengthen` r}+ where+ rep = toRTypeRep t --- MOVE TO TYPES-instance (PPrint t, PPrint a) => PPrint (MSpec t a) where- pprint = vcat . fmap pprint . fmap snd . M.toList . measMap --- MOVE TO TYPES-instance PPrint (Measure t a) => Show (Measure t a) where- show = showpp+noDummySyms t+ | any isDummy (ty_binds rep)+ = subst su $ fromRTypeRep $ rep{ty_binds = xs'}+ | otherwise+ = t+ where+ rep = toRTypeRep t+ xs' = zipWith (\_ i -> symbol ("x" ++ show i)) (ty_binds rep) [1..]+ su = mkSubst $ zip (ty_binds rep) (EVar <$> xs') -instance PPrint t => PPrint (CMeasure t) where- pprint (CM n s) = pprint n <> text " :: " <> pprint s+combineDCTypes t = foldl' strengthenRefTypeGen (ofType t) -instance PPrint (CMeasure t) => Show (CMeasure t) where- show = showpp+mapArgumens :: SourcePos -> RRType Reft -> RRType Reft -> Maybe Subst+mapArgumens lc t1 t2 = go xts1' xts2'+ where+ xts1 = zip (ty_binds rep1) (ty_args rep1)+ xts2 = zip (ty_binds rep2) (ty_args rep2)+ rep1 = toRTypeRep t1+ rep2 = toRTypeRep t2 --- MOVE TO TYPES-mapTy :: (tya -> tyb) -> Measure tya c -> Measure tyb c-mapTy = first + xts1' = dropWhile canDrop xts1+ xts2' = dropWhile canDrop xts2 -dataConTypes :: MSpec (RRType Reft) DataCon -> ([(Var, RRType Reft)], [(LocSymbol, RRType Reft)])-dataConTypes s = (ctorTys, measTys)+ canDrop (_, t) = isClassType t || isEqType t++ go xs ys+ | length xs == length ys && and (zipWith (==) (toRSort . snd <$> xts1') (toRSort . snd <$> xts2'))+ = Just $ mkSubst $ zipWith (\y x -> (fst x, EVar $ fst y)) xts1' xts2'+ | otherwise+ = panic (Just $ sourcePosSrcSpan lc) ("The types for the wrapper and worker data constroctors cannot be merged\n"+ ++ show t1 ++ "\n" ++ show t2 )++defRefType :: Type -> Def (RRType Reft) DataCon -> RRType Reft+defRefType tdc (Def f args dc mt xs body)+ = {- traceShow "defRefType: " $ -} generalize $ mkArrow [] [] [] xts t' where- measTys = [(name m, sort m) | m <- M.elems (measMap s) ++ imeas s]- ctorTys = concatMap mkDataConIdsTy [(defsVar ds, defsTy ds)- | (_, ds) <- M.toList (ctorMap s)- ]- defsTy ds@(d:_) = foldl' strengthenRefTypeGen (ofType $ dataConUserType $ ctor d) (defRefType <$> ds)- defsTy [] = errorstar "Measure.defsTy: This cannot happen"+ xts = stitchArgs (fSrcSpan f) dc xs ts+ t = fromMaybe (ofType tr) mt+ t' = mkForAlls args $ refineWithCtorBody dc f (fst <$> args) body t+ mkForAlls xts t = foldl' (\t (x, tx) -> RAllE x tx t) t xts+ (ts, tr) = splitFunTys $ snd $ splitForAllTys tdc - defsVar = ctor . safeHead "defsVar" -defRefType :: Def (RRType Reft) DataCon -> RRType Reft-defRefType (Def f args dc mt xs body) = generalize $ mkArrow [] [] [] xts t'- where - t = fromMaybe (ofType $ dataConOrigResTy dc) mt- xts = safeZipWith msg g xs $ ofType `fmap` dataConOrigArgTys dc- g (x, Nothing) t = (x, t, mempty) - g (x, Just t) _ = (x, t, mempty)- t' = mkForAlls args $ refineWithCtorBody dc f (fst <$> args) body t - msg = "defRefType dc = " ++ showPpr dc +stitchArgs sp dc xs ts+ | nXs == nTs = zipWith g xs $ ofType `fmap` ts+ | otherwise = panicFieldNumMismatch sp dc nXs nTs+ where+ nXs = length xs+ nTs = length ts+ g (x, Just t) _ = (x, t, mempty)+ g (x, _) t = (x, t, mempty) - mkForAlls xts t = foldl' (\t (x, tx) -> RAllE x tx t) t xts+-- validArgs :: [(Symbol, Maybe (RRType Reft))] -> [Type] -> Bool+-- validArgs xs ts = nXs == nTs+-- where+-- otherwise = and (zipWith eqBSort xs ts)+-- nXs /= nTs = panicFieldNumMismatch sp dc nXs nTs+-- eqBSort (_, Nothing) _ = True+-- eqBSort (x, Just t) t'+-- | eqSort t t' = True+-- | otherwise = panicFieldSortMismatch sp dc x +-- eqSort :: RRType Reft -> Type -> Bool+-- eqSort t t' = s == s'+ -- where+ -- s = traceShow "sort1" $ toRSort t+ -- s' = traceShow "sort2" $ toRSort (ofType t' :: RRType Reft) +panicFieldNumMismatch sp dc nXs nTs = panicDataCon sp dc msg+ where+ msg = "Requires" <+> pprint nTs <+> "fields but given" <+> pprint nXs++-- panicFieldSortMismatch sp dc x = panicDataCon sp dc msg+ -- where+ -- msg = "Field type mismatch for" <+> pprint x++panicDataCon sp dc d+ = panicError $ ErrDataCon sp (pprint dc) d+ refineWithCtorBody dc f as body t =- case stripRTypeBase t of + case stripRTypeBase t of Just (Reft (v, _)) ->- strengthen t $ Reft (v, Refa $ bodyPred (EApp f (eVar <$> (as ++ [v]))) body)- Nothing -> - errorstar $ "measure mismatch " ++ showpp f ++ " on con " ++ showPpr dc+ strengthen t $ Reft (v, bodyPred (mkEApp f (eVar <$> (as ++ [v]))) body)+ Nothing ->+ panic Nothing $ "measure mismatch " ++ showpp f ++ " on con " ++ showPpr dc -bodyPred :: Expr -> Body -> Pred+bodyPred :: Expr -> Body -> Expr bodyPred fv (E e) = PAtom Eq fv e-bodyPred fv (P p) = PIff (PBexp fv) p+bodyPred fv (P p) = PIff fv p bodyPred fv (R v' p) = subst1 p (v', fv)
src/Language/Haskell/Liquid/Misc.hs view
@@ -1,40 +1,34 @@-{-# LANGUAGE CPP #-} {-# LANGUAGE TupleSections #-} module Language.Haskell.Liquid.Misc where -import Control.Applicative-import System.FilePath--import qualified Data.List as L--import Language.Fixpoint.Misc (errorstar)+import Prelude hiding (error)+import Control.Monad (liftM2) -import Data.List (sort)+import Control.Arrow (first)+import System.FilePath -import Paths_liquidhaskell+import Control.Exception (catch, IOException)+import qualified Data.HashSet as S+import qualified Data.HashMap.Strict as M+import qualified Data.List as L+import Data.Maybe+import Data.Hashable+import qualified Data.ByteString as B+import Data.ByteString.Char8 (pack, unpack)+import Text.PrettyPrint.HughesPJ ((<>), char) -firstDuplicate :: Ord a => [a] -> Maybe a-firstDuplicate = go . sort- where- go (y:x:xs) | x == y = Just x - | otherwise = go (x:xs)- go _ = Nothing +import Language.Fixpoint.Misc+import Paths_liquidhaskell -safeIndex err n ls - | n >= length ls- = errorstar err- | otherwise - = ls !! n- (!?) :: [a] -> Int -> Maybe a [] !? _ = Nothing (x:_) !? 0 = Just x (_:xs) !? n = xs !? (n-1) safeFromJust _ (Just x) = x-safeFromJust err _ = errorstar err+safeFromJust err _ = errorstar err fst4 (a,_,_,_) = a snd4 (_,b,_,_) = b@@ -51,7 +45,9 @@ fourth4 (_,_,_,x) = x third4 (_,_,x,_) = x -mapSndM f (x, y) = return . (x,) =<< f y+mapSndM :: (Applicative m) => (b -> m c) -> (a, b) -> m (a, c)+-- mapSndM f (x, y) = return . (x,) =<< f y+mapSndM f (x, y) = (x, ) <$> f y firstM f (a,b) = (,b) <$> f a secondM f (a,b) = (a,) <$> f b@@ -62,23 +58,15 @@ third3 f (a,b,c) = (a,b,f c) -zip4 (x1:xs1) (x2:xs2) (x3:xs3) (x4:xs4) = (x1, x2, x3, x4) : (zip4 xs1 xs2 xs3 xs4) +zip4 (x1:xs1) (x2:xs2) (x3:xs3) (x4:xs4) = (x1, x2, x3, x4) : zip4 xs1 xs2 xs3 xs4 zip4 _ _ _ _ = [] -#if __GLASGOW_HASKELL__ < 710-ghc = "ghc-7.8"-#else-ghc = "ghc-7.10"-#endif getIncludeDir = dropFileName <$> getDataFileName ("include" </> "Prelude.spec") getCssPath = getDataFileName $ "syntax" </> "liquid.css" getCoreToLogicPath = fmap (</> "CoreToLogic.lg") getIncludeDir -maximumWithDefault zero [] = zero-maximumWithDefault _ xs = maximum xs- {-@ type ListN a N = {v:[a] | len v = N} @-} {-@ type ListL a L = ListN a (len L) @-} @@ -97,25 +85,86 @@ mapN n f (x:xs) = x : mapN (n-1) f xs mapN _ _ [] = [] +zipWithDefM :: Monad m => (a -> a -> m a) -> [a] -> [a] -> m [a]+zipWithDefM _ [] [] = return []+zipWithDefM _ xs [] = return xs+zipWithDefM _ [] ys = return ys+zipWithDefM f (x:xs) (y:ys) = liftM2 (:) (f x y) (zipWithDefM f xs ys) - -pad _ f [] ys = (f <$> ys, ys)-pad _ f xs [] = (xs, f <$> xs)-pad msg _ xs ys- | nxs == nys = (xs, ys)- | otherwise = errorstar $ "pad: " ++ msg+--------------------------------------------------------------------------------+-- Originally part of Fixpoint's Misc:+--------------------------------------------------------------------------------++single x = [x]++mapFst f (x, y) = (f x, y)+mapSnd f (x, y) = (x, f y)++mapFst3 f (x, y, z) = (f x, y, z)+mapSnd3 f (x, y, z) = (x, f y, z)+mapThd3 f (x, y, z) = (x, y, f z)+++hashMapMapWithKey :: (k -> v1 -> v2) -> M.HashMap k v1 -> M.HashMap k v2+hashMapMapWithKey f = fromJust . M.traverseWithKey (\k v -> Just (f k v))++hashMapMapKeys :: (Eq k, Hashable k) => (t -> k) -> M.HashMap t v -> M.HashMap k v+hashMapMapKeys f = M.fromList . fmap (first f) . M.toList++concatMapM f = fmap concat . mapM f++firstElems :: [(B.ByteString, B.ByteString)] -> B.ByteString -> Maybe (Int, B.ByteString, (B.ByteString, B.ByteString))+firstElems seps str+ = case splitters seps str of+ [] -> Nothing+ is -> Just $ L.minimumBy (\x y -> compare (fst3 x) (fst3 y)) is++splitters seps str+ = [(i, c', z) | (c, c') <- seps+ , let z = B.breakSubstring c str+ , let i = B.length (fst z)+ , i < B.length str ]++bchopAlts :: [(B.ByteString, B.ByteString)] -> B.ByteString -> [B.ByteString]+bchopAlts seps = go where- nxs = length xs- nys = length ys+ go s = maybe [s] go' (firstElems seps s)+ go' (_,c',(s0, s1)) = if (B.length s2 == B.length s1) then [B.concat [s0,s1]] else (s0 : s2' : go s3')+ where (s2, s3) = B.breakSubstring c' s1+ s2' = B.append s2 c'+ s3' = B.drop (B.length c') s3 +chopAlts seps str = unpack <$> bchopAlts [(pack c, pack c') | (c, c') <- seps] (pack str) +sortDiff :: (Ord a) => [a] -> [a] -> [a]+sortDiff x1s x2s = go (sortNub x1s) (sortNub x2s)+ where+ go xs@(x:xs') ys@(y:ys')+ | x < y = x : go xs' ys+ | x == y = go xs' ys'+ | otherwise = go xs ys'+ go xs [] = xs+ go [] _ = [] -ordNub :: Ord a => [a] -> [a]-ordNub = map head . L.group . L.sort+angleBrackets p = char '<' <> p <> char '>' +mkGraph :: (Eq a, Eq b, Hashable a, Hashable b) => [(a, b)] -> M.HashMap a (S.HashSet b)+mkGraph = fmap S.fromList . group++tryIgnore :: String -> IO () -> IO ()+tryIgnore s a = catch a $ \e ->+ do let err = show (e :: IOException)+ writeLoud ("Warning: Couldn't do " ++ s ++ ": " ++ err)+ return ()++(=>>) m f = m >>= (\x -> f x >> return x)+++firstJust :: (a -> Maybe b) -> [a] -> Maybe b+firstJust f xs = listToMaybe $ mapMaybe f xs+ intToString :: Int -> String intToString 1 = "1st" intToString 2 = "2nd" intToString 3 = "3rd" intToString n = show n ++ "th"-
− src/Language/Haskell/Liquid/Names.hs
@@ -1,6 +0,0 @@-module Language.Haskell.Liquid.Names where--import Language.Fixpoint.Types---lenLocSymbol = dummyLoc $ symbol ("autolen" :: String)
src/Language/Haskell/Liquid/Parse.hs view
@@ -12,6 +12,7 @@ ) where +import Prelude hiding (error) import Control.Monad import Text.Parsec import Text.Parsec.Error (newErrorMessage, Message (..))@@ -23,8 +24,8 @@ import qualified Data.HashSet as S import Data.Monoid -import Control.Applicative ((<$>), (<*), (<*>))-import Data.Char (isLower, isSpace, isAlpha, isUpper, isAlphaNum)++import Data.Char (isSpace, isAlpha, isUpper, isAlphaNum) import Data.List (foldl', partition) import GHC (mkModuleName)@@ -32,19 +33,21 @@ import Language.Preprocessor.Unlit (unlit) -import Language.Fixpoint.Types hiding (Def, R)+import Language.Fixpoint.Types hiding (Error, R) -import Language.Haskell.Liquid.GhcMisc-import Language.Haskell.Liquid.Types-import Language.Haskell.Liquid.RefType-import Language.Haskell.Liquid.Variance-import Language.Haskell.Liquid.Bounds+import Language.Haskell.Liquid.GHC.Misc+import Language.Haskell.Liquid.Types hiding (Axiom)+import Language.Haskell.Liquid.Misc (mapSnd)+import Language.Haskell.Liquid.Types.RefType+import Language.Haskell.Liquid.Types.Variance+import Language.Haskell.Liquid.Types.Bounds import qualified Language.Haskell.Liquid.Measure as Measure-import Language.Fixpoint.Names (listConName, hpropConName, propConName, tupConName, headSym)-import Language.Fixpoint.Misc hiding (dcolon, dot)-import Language.Fixpoint.Parse hiding (angles) +import Language.Fixpoint.Parse hiding (angles, refBindP, refP, refDefP)++-- import Debug.Trace+ ---------------------------------------------------------------------------- -- Top Level Parsing API --------------------------------------------------- ----------------------------------------------------------------------------@@ -97,7 +100,7 @@ parseWithError parser f s = case runParser (remainderP (whiteSpace >> parser)) 0 f s of Left e -> Left $ parseErrorError f e- Right (r, "", _) -> Right $ r+ Right (r, "", _) -> Right r Right (_, rem, _) -> Left $ parseErrorError f $ remParseError f s rem ---------------------------------------------------------------------------@@ -125,9 +128,9 @@ remLine = length remLines col = srcCol - remCol srcCol = length $ srcLines !! (line - 1)- remCol = length $ remLines !! 0- srcLines = lines $ src- remLines = lines $ rem+ remCol = length $ head remLines+ srcLines = lines src+ remLines = lines rem @@ -175,9 +178,9 @@ <|> try bareConstraintP <|> try bareFunP <|> bareAtomP (refBindP bindP)- <|> try (angles (do t <- parens $ bareTypeP+ <|> try (angles (do t <- parens bareTypeP p <- monoPredicateP- return $ t `strengthen` (U mempty p mempty)))+ return $ t `strengthen` MkUReft mempty p mempty)) bareArgP vv = bareAtomP (refDefP vv)@@ -188,10 +191,27 @@ <|> holeP <|> try (dummyP (bbaseP <* spaces)) -holeP = reserved "_" >> spaces >> return (RHole $ uTop $ Reft ("VV", Refa hole))+refBindP :: Subable a => Parser Symbol -> Parser Expr -> Parser (Reft -> a) -> Parser a+refBindP bp rp kindP+ = braces $ do+ x <- bp+ i <- freshIntP+ t <- kindP+ reserved "|"+ ra <- rp <* spaces+ let xi = intSymbol x i+ let su v = if v == x then xi else v+ return $ substa su $ t (Reft (x, ra))++refP = refBindP bindP refaP+refDefP x = refBindP (optBindP x)++optBindP x = try bindP <|> return x++holeP = reserved "_" >> spaces >> return (RHole $ uTop $ Reft ("VV", hole)) holeRefP = reserved "_" >> spaces >> return (RHole . uTop) refasHoleP = try refaP- <|> (reserved "_" >> return (Refa hole))+ <|> (reserved "_" >> return hole) -- FIXME: the use of `blanks = oneOf " \t"` here is a terrible and fragile hack -- to avoid parsing:@@ -259,7 +279,7 @@ return xts) <|> return [] -rrTy ct t = RRTy (xts ++ [(dummySymbol, tr)]) mempty OCons t+rrTy ct = RRTy (xts ++ [(dummySymbol, tr)]) mempty OCons where tr = ty_res trep xts = zip (ty_binds trep) (ty_args trep)@@ -267,7 +287,7 @@ bareAllS = do reserved "forall"- ss <- (angles $ sepBy1 symbolP comma)+ ss <- angles $ sepBy1 symbolP comma dot t <- bareTypeP return $ foldr RAllS t ss@@ -281,8 +301,9 @@ return $ foldr RAllT (foldr RAllP t ps) as tyVarIdP :: Parser Symbol-tyVarIdP = symbol <$> condIdP alphanums (isLower . head)- where alphanums = ['a'..'z'] ++ ['0'..'9']+tyVarIdP = symbol <$> condIdP alphanums (isSmall . head)+ where+ alphanums = S.fromList $ ['a'..'z'] ++ ['0'..'9'] predVarDefsP = try (angles $ sepBy1 predVarDefP comma)@@ -298,6 +319,8 @@ where (_, τ) = safeLast "bPVar last" xts τxs = [ (τ, x, EVar x) | (x, τ) <- init xts ]+ safeLast _ xs@(_:_) = last xs+ safeLast msg _ = panic Nothing $ "safeLast with empty list " ++ msg predVarTypeP :: Parser [(Symbol, BSort)] predVarTypeP = bareTypeP >>= either parserFail return . mkPredVarType@@ -314,7 +337,7 @@ err = "Predicate Variable with non-Prop output sort: " ++ showpp t xyP lP sepP rP- = liftM3 (\x _ y -> (x, y)) lP (spaces >> sepP) rP+ = (\x _ y -> (x, y)) <$> lP <*> (spaces >> sepP) <*> rP data ArrowSym = ArrowFun | ArrowPred @@ -374,7 +397,7 @@ predicate1P = try (RProp <$> symsP <*> refP bbaseP)- <|> (RPropP [] . predUReft <$> monoPredicate1P)+ <|> (rPropP [] . predUReft <$> monoPredicate1P) <|> (braces $ bRProp <$> symsP' <*> refaP) where symsP' = do ss <- symsP@@ -402,8 +425,8 @@ funArgsP = try realP <|> empP where empP = (,[]) <$> predVarIdP- realP = do EApp lp xs <- funAppP- return (val lp, xs)+ realP = do (EVar lp, xs) <- splitEApp <$> funAppP+ return (lp, xs) @@ -433,7 +456,7 @@ ----------------------- Wrapped Constructors --------------------------- ------------------------------------------------------------------------ -bRProp [] _ = errorstar "Parse.bRProp empty list"+bRProp [] _ = panic Nothing "Parse.bRProp empty list" bRProp syms' expr = RProp ss $ bRVar dummyName mempty mempty r where (ss, (v, _)) = (init syms, last syms)@@ -441,7 +464,7 @@ su = mkSubst [(x, EVar y) | ((x, _), y) <- syms'] r = su `subst` Reft (v, expr) -bRVar α s p r = RVar α (U r p s)+bRVar α s p r = RVar α (MkUReft r p s) bLst (Just t) rs r = RApp (dummyLoc listConName) [t] rs (reftUReft r) bLst (Nothing) rs r = RApp (dummyLoc listConName) [] rs (reftUReft r) @@ -453,16 +476,19 @@ -- Temporarily restore this hack benchmarks/esop2013-submission/Array.hs fails -- w/o it -- TODO RApp Int [] [p] true should be syntactically different than RApp Int [] [] p-bCon b s [RPropP _ r1] [] _ r = RApp b [] [] $ r1 `meet` (U r mempty s)-bCon b s rs ts p r = RApp b ts rs $ U r p s+-- bCon b s [RProp _ (RHole r1)] [] _ r = RApp b [] [] $ r1 `meet` (MkUReft r mempty s)+bCon b s rs ts p r = RApp b ts rs $ MkUReft r p s --- bAppTy v t r = RAppTy (RVar v top) t (reftUReft r)-bAppTy v ts r = (foldl' (\a b -> RAppTy a b mempty) (RVar v mempty) ts) `strengthen` (reftUReft r)+bAppTy v ts r = ts' `strengthen` reftUReft r+ where+ ts' = foldl' (\a b -> RAppTy a b mempty) (RVar v mempty) ts +reftUReft r = MkUReft r mempty mempty -reftUReft = \r -> U r mempty mempty-predUReft = \p -> U dummyReft p mempty+predUReft p = MkUReft dummyReft p mempty+ dummyReft = mempty+ dummyTyId = "" ------------------------------------------------------------------@@ -481,7 +507,6 @@ | Invt (Located ty) | IAlias (Located ty, Located ty) | Alias (RTAlias Symbol BareType)- | PAlias (RTAlias Symbol Pred) | EAlias (RTAlias Symbol Expr) | Embed (LocSymbol, FTycon) | Qualif Qualifier@@ -489,10 +514,11 @@ | LVars LocSymbol | Lazy LocSymbol | HMeas LocSymbol+ | Axiom LocSymbol | Inline LocSymbol | ASize LocSymbol | HBound LocSymbol- | PBound (Bound ty Pred)+ | PBound (Bound ty Expr) | Pragma (Located String) | CMeas (Measure ty ()) | IMeas (Measure ty ctor)@@ -513,13 +539,13 @@ show (Invt _) = "Invt" show (IAlias _) = "IAlias" show (Alias _) = "Alias"- show (PAlias _) = "PAlias" show (EAlias _) = "EAlias" show (Embed _) = "Embed" show (Qualif _) = "Qualif" show (Decr _) = "Decr" show (LVars _) = "LVars" show (Lazy _) = "Lazy"+ show (Axiom _) = "Axiom" show (HMeas _) = "HMeas" show (HBound _) = "HBound" show (Inline _) = "Inline"@@ -547,13 +573,13 @@ , Measure.dataDecls = [d | DDecl d <- xs] , Measure.includes = [q | Incl q <- xs] , Measure.aliases = [a | Alias a <- xs]- , Measure.paliases = [p | PAlias p <- xs] , Measure.ealiases = [e | EAlias e <- xs] , Measure.embeds = M.fromList [e | Embed e <- xs] , Measure.qualifiers = [q | Qualif q <- xs] , Measure.decr = [d | Decr d <- xs] , Measure.lvars = [d | LVars d <- xs] , Measure.lazy = S.fromList [s | Lazy s <- xs]+ , Measure.axioms = S.fromList [s | Axiom s <- xs] , Measure.hmeas = S.fromList [s | HMeas s <- xs] , Measure.inlines = S.fromList [s | Inline s <- xs] , Measure.autosize = S.fromList [s | ASize s <- xs]@@ -574,6 +600,7 @@ <|> (reservedToken "assert" >> liftM Asrt tyBindP ) <|> (reservedToken "autosize" >> liftM ASize asizeP ) <|> (reservedToken "Local" >> liftM LAsrt tyBindP )+ <|> (reservedToken "axiomatize" >> liftM Axiom axiomP ) <|> try (reservedToken "measure" >> liftM Meas measureP ) <|> (reservedToken "measure" >> liftM HMeas hmeasureP ) <|> (reservedToken "inline" >> liftM Inline inlineP )@@ -590,7 +617,7 @@ <|> (reservedToken "invariant" >> liftM Invt invariantP) <|> (reservedToken "using" >> liftM IAlias invaliasP ) <|> (reservedToken "type" >> liftM Alias aliasP )- <|> (reservedToken "predicate" >> liftM PAlias paliasP )+ <|> (reservedToken "predicate" >> liftM EAlias ealiasP ) <|> (reservedToken "expression">> liftM EAlias ealiasP ) <|> (reservedToken "embed" >> liftM Embed embedP ) <|> (reservedToken "qualif" >> liftM Qualif (qualifierP sortP))@@ -614,6 +641,9 @@ hmeasureP :: Parser LocSymbol hmeasureP = locParserP binderP +axiomP :: Parser LocSymbol+axiomP = locParserP binderP+ hboundP :: Parser LocSymbol hboundP = locParserP binderP @@ -625,7 +655,8 @@ decreaseP :: Parser (LocSymbol, [Int]) decreaseP = mapSnd f <$> liftM2 (,) (locParserP binderP) (spaces >> (many integer))- where f = ((\n -> fromInteger n - 1) <$>)+ where+ f = ((\n -> fromInteger n - 1) <$>) filePathP :: Parser FilePath filePathP = angles $ many1 pathCharP@@ -633,7 +664,7 @@ pathCharP = choice $ char <$> pathChars pathChars = ['a'..'z'] ++ ['A'..'Z'] ++ ['0'..'9'] ++ ['.', '/'] -datavarianceP = liftM2 (,) (locUpperIdP) (spaces >> many varianceP)+datavarianceP = liftM2 (,) locUpperIdP (spaces >> many varianceP) varianceP = (reserved "bivariant" >> return Bivariant) <|> (reserved "invariant" >> return Invariant)@@ -674,8 +705,8 @@ aliasP = rtAliasP id bareTypeP-paliasP = rtAliasP symbol predP-ealiasP = rtAliasP symbol exprP+ealiasP = try (rtAliasP symbol predP)+ <|> rtAliasP symbol exprP rtAliasP :: (Symbol -> tv) -> Parser ty -> Parser (RTAlias tv ty) rtAliasP f bodyP@@ -686,11 +717,13 @@ whiteSpace >> reservedOp "=" >> whiteSpace body <- bodyP posE <- getPosition- let (tArgs, vArgs) = partition (isLower . headSym) args+ let (tArgs, vArgs) = partition (isSmall . headSym) args return $ RTA name (f <$> tArgs) (f <$> vArgs) body pos posE aliasIdP :: Parser Symbol-aliasIdP = condIdP (['A' .. 'Z'] ++ ['a'..'z'] ++ ['0'..'9']) (isAlpha . head)+aliasIdP = condIdP alphaNums (isAlpha . head)+ where+ alphaNums = S.fromList $ ['A' .. 'Z'] ++ ['a'..'z'] ++ ['0'..'9'] measureP :: Parser (Measure BareType LocSymbol) measureP@@ -720,17 +753,23 @@ classP :: Parser (RClass BareType) classP- = do sups <- superP+ = do sups <- supersP c <- locUpperIdP spaces tvs <- manyTill tyVarIdP (try $ reserved "where") ms <- grabs tyBindP spaces- return $ RClass (fmap symbol c) (mb sups) tvs ms+ return $ RClass (fmap symbol c) sups tvs ms where- mb Nothing = []- mb (Just xs) = xs- superP = maybeP (parens ( liftM (toRCls <$>) (bareTypeP `sepBy1` comma)) <* reserved "=>")+ superP = toRCls <$> bareAtomP (refBindP bindP)+ -- c <- locUpperIdP+ -- spaces+ -- tvs <- many1 bareAtomNoAppP+ -- return (RApp c tvs [] mempty)++ supersP = try (((parens (superP `sepBy1` comma)) <|> fmap pure superP)+ <* reserved "=>")+ <|> return [] toRCls x = x -- toRCls (RApp c ts rs r) = RCls c ts -- toRCls t@(RCls _ _) = t@@ -838,14 +877,15 @@ = try upperIdP <|> pwr <$> parens (idP bad) where- idP p = symbol <$> many1 (satisfy (not . p))+ idP p = many1 (satisfy (not . p)) bad c = isSpace c || c `elem` ("(,)" :: String)- pwr s = "(" <> s <> ")"+ pwr s = symbol $ "(" <> s <> ")" dataSizeP = (brackets $ (Just . mkFun) <$> locLowerIdP) <|> return Nothing- where mkFun s = \x -> EApp (symbol <$> s) [EVar x]+ where+ mkFun s x = mkEApp (symbol <$> s) [EVar x] dataDeclP :: Parser DataDecl dataDeclP = try dataDeclFullP <|> dataDeclSizeP@@ -875,29 +915,6 @@ -- | Parsing Qualifiers --------------------------------------------- --------------------------------------------------------------------- --- qualifierP = do--- pos <- getPosition--- n <- upperIdP--- params <- parens $ sepBy1 sortBindP comma--- _ <- colon--- body <- predP--- return $ mkQual n params body pos------ sortBindP = (,) <$> symbolP <* colon <*> sortP--sortP- = try (parens $ sortP)- -- <|> try (string "@" >> varSortP)- <|> try (fApp (Left listFTyCon) . single <$> brackets sortP)- -- <|> try bvSortP- -- <|> try baseSortP- -- THIS IS THE PROBLEM HEREHEREHERE <|> try (symbolSort <$> locLowerIdP)- <|> try (fApp <$> (Left <$> fTyConP) <*> sepBy sortP blanks)- <|> (FObj . symbol <$> lowerIdP)---- varSortP = FVar <$> parens intP--- funcSortP = parens $ FFunc <$> intP <* comma <*> sortsP- fTyConP :: Parser FTycon fTyConP = (reserved "int" >> return intFTyCon)@@ -909,16 +926,14 @@ <|> (symbolFTycon <$> locUpperIdP) -- --------------------------------------------------------------------- ------------ Interacting with Fixpoint ------------------------------ --------------------------------------------------------------------- grabUpto p- = try (lookAhead p >>= return . Just)- <|> try (eof >> return Nothing)- <|> (anyChar >> grabUpto p)+ = try (Just <$> lookAhead p)+ <|> try (eof >> return Nothing)+ <|> (anyChar >> grabUpto p) betweenMany leftP rightP p = do z <- grabUpto leftP
− src/Language/Haskell/Liquid/PredType.hs
@@ -1,334 +0,0 @@-{-# LANGUAGE DeriveDataTypeable, FlexibleInstances, FlexibleContexts, UndecidableInstances, TupleSections, OverloadedStrings #-}-module Language.Haskell.Liquid.PredType (- PrType- , TyConP (..), DataConP (..)- , dataConTy- , dataConPSpecType- , makeTyConInfo- , replacePreds-- , replacePredsWithRefs- , pVartoRConc-- -- * Dummy `Type` that represents _all_ abstract-predicates- , predType-- -- * Compute @RType@ of a given @PVar@- , pvarRType-- , substParg- , pApp- , wiredSortedSyms- ) where--import Type-import TypeRep-import qualified TyCon as TC-import Text.PrettyPrint.HughesPJ-import DataCon--import qualified Data.HashMap.Strict as M-import Data.List (partition, foldl')-import Data.Monoid (mempty, mappend, mconcat)--import Language.Fixpoint.Misc-import Language.Fixpoint.Types hiding (Predicate, Expr)-import qualified Language.Fixpoint.Types as F-import Language.Haskell.Liquid.Types-import Language.Haskell.Liquid.RefType hiding (generalize)-import Language.Haskell.Liquid.GhcMisc-import Language.Haskell.Liquid.Misc--import Control.Applicative ((<$>))-import Data.List (nub)--import Data.Default--makeTyConInfo = hashMapMapWithKey mkRTyCon . M.fromList--mkRTyCon :: TC.TyCon -> TyConP -> RTyCon-mkRTyCon tc (TyConP αs' ps _ tyvariance predvariance size) = RTyCon tc pvs' (mkTyConInfo tc tyvariance predvariance size)- where τs = [rVar α :: RSort | α <- tyConTyVarsDef tc]- pvs' = subts (zip αs' τs) <$> ps--dataConPSpecType :: DataCon -> DataConP -> SpecType-dataConPSpecType dc (DataConP _ vs ps ls cs yts rt _) = mkArrow vs ps ls ts' rt'- where- (xs, ts) = unzip $ reverse yts- mkDSym = (`mappend` symbol dc) . (`mappend` "_") . symbol- ys = mkDSym <$> xs- tx _ [] [] [] = []- tx su (x:xs) (y:ys) (t:ts) = (y, subst (F.mkSubst su) t, mempty)- : tx ((x, F.EVar y):su) xs ys ts- tx _ _ _ _ = errorstar "PredType.dataConPSpecType.tx called on invalid inputs"- yts' = tx [] xs ys ts- ts' = map ("" , , mempty) cs ++ yts'- su = F.mkSubst [(x, F.EVar y) | (x, y) <- zip xs ys]- rt' = subst su rt--instance PPrint TyConP where- pprint (TyConP vs ps ls _ _ _)- = (parens $ hsep (punctuate comma (map pprint vs))) <+>- (parens $ hsep (punctuate comma (map pprint ps))) <+>- (parens $ hsep (punctuate comma (map pprint ls)))--instance Show TyConP where- show = showpp -- showSDoc . ppr--instance PPrint DataConP where- pprint (DataConP _ vs ps ls cs yts t _)- = (parens $ hsep (punctuate comma (map pprint vs))) <+>- (parens $ hsep (punctuate comma (map pprint ps))) <+>- (parens $ hsep (punctuate comma (map pprint ls))) <+>- (parens $ hsep (punctuate comma (map pprint cs))) <+>- (parens $ hsep (punctuate comma (map pprint yts))) <+>- pprint t--instance Show DataConP where- show = showpp--dataConTy m (TyVarTy v)- = M.lookupDefault (rVar v) (RTV v) m-dataConTy m (FunTy t1 t2)- = rFun dummySymbol (dataConTy m t1) (dataConTy m t2)-dataConTy m (ForAllTy α t)- = RAllT (rTyVar α) (dataConTy m t)-dataConTy m (TyConApp c ts)- = rApp c (dataConTy m <$> ts) [] mempty-dataConTy _ _- = error "ofTypePAppTy"------------------------------------------------------------------------------------ Interface: Replace Predicate With Uninterprented Function Symbol ------------------------------------------------------------------------------------replacePredsWithRefs (p, r) (U (Reft(v, Refa rs)) (Pr ps) s)- = U (Reft (v, Refa rs'')) (Pr ps2) s- where- rs'' = mconcat $ rs : rs'- rs' = r . (v,) . pargs <$> ps1- (ps1, ps2) = partition (== p) ps--pVartoRConc p (v, args) | length args == length (pargs p)- = pApp (pname p) $ EVar v : (thd3 <$> args)--pVartoRConc p (v, args)- = pApp (pname p) $ EVar v : args'- where- args' = (thd3 <$> args) ++ (drop (length args) (thd3 <$> pargs p))---------------------------------------------------------------------------- | @pvarRType π@ returns a trivial @RType@ corresponding to the--- function signature for a @PVar@ @π@. For example, if--- @π :: T1 -> T2 -> T3 -> Prop@--- then @pvarRType π@ returns an @RType@ with an @RTycon@ called--- @predRTyCon@ `RApp predRTyCon [T1, T2, T3]`-------------------------------------------------------------------------pvarRType :: (PPrint r, Reftable r) => PVar RSort -> RRType r-------------------------------------------------------------------------pvarRType (PV _ k {- (PVProp τ) -} _ args) = rpredType k (fst3 <$> args) -- (ty:tys)- -- where- -- ty = uRTypeGen τ- -- tys = uRTypeGen . fst3 <$> args----- rpredType :: (PPrint r, Reftable r) => PVKind (RRType r) -> [RRType r] -> RRType r-rpredType (PVProp t) ts = RApp predRTyCon (uRTypeGen <$> t : ts) [] mempty-rpredType PVHProp ts = RApp wpredRTyCon (uRTypeGen <$> ts) [] mempty--predRTyCon :: RTyCon-predRTyCon = symbolRTyCon predName--wpredRTyCon :: RTyCon-wpredRTyCon = symbolRTyCon wpredName--symbolRTyCon :: Symbol -> RTyCon-symbolRTyCon n = RTyCon (stringTyCon 'x' 42 $ symbolString n) [] def------------------------------------------------------------------------------------------ | Instantiate `PVar` with `RTProp` ---------------------------------------------------------------------------------------------------------------------------------------- | @replacePreds@ is the main function used to substitute an (abstract)--- predicate with a concrete Ref, that is either an `RProp` or `RHProp`--- type. The substitution is invoked to obtain the `SpecType` resulting--- at /predicate application/ sites in 'Language.Haskell.Liquid.Constraint'.--- The range of the `PVar` substitutions are /fresh/ or /true/ `RefType`.--- That is, there are no further _quantified_ `PVar` in the target.---------------------------------------------------------------------------------------replacePreds :: String -> SpecType -> [(RPVar, SpecProp)] -> SpecType---------------------------------------------------------------------------------------replacePreds msg = foldl' go- where- go z (π, t@(RProp _ _)) = substPred msg (π, t) z- go _ (_, RPropP _ _) = error "replacePreds on RPropP"- go _ (_, RHProp _ _) = errorstar "TODO:EFFECTS:replacePreds"---- TODO: replace `replacePreds` with--- instance SubsTy RPVar (Ref RReft SpecType) SpecType where--- subt (pv, r) t = replacePreds "replacePred" t (pv, r)---- replacePreds :: String -> SpecType -> [(RPVar, Ref Reft RefType)] -> SpecType--- replacePreds msg = foldl' go--- where go z (π, RProp t) = substPred msg (π, t) z--- go z (π, RPropP r) = replacePVarReft (π, r) <$> z----------------------------------------------------------------------------------substPred :: String -> (RPVar, SpecProp) -> SpecType -> SpecType----------------------------------------------------------------------------------substPred _ (π, RProp ss (RVar a1 r1)) t@(RVar a2 r2)- | isPredInReft && a1 == a2 = RVar a1 $ meetListWithPSubs πs ss r1 r2'- | isPredInReft = errorstar ("substPred RVar Var Mismatch" ++ show (a1, a2))- | otherwise = t- where- (r2', πs) = splitRPvar π r2- isPredInReft = not $ null πs--substPred msg su@(π, _ ) (RApp c ts rs r)- | null πs = t'- | otherwise = substRCon msg su t' πs r2'- where- t' = RApp c (substPred msg su <$> ts) (substPredP msg su <$> rs) r- (r2', πs) = splitRPvar π r--substPred msg (p, tp) (RAllP (q@(PV _ _ _ _)) t)- | p /= q = RAllP q $ substPred msg (p, tp) t- | otherwise = RAllP q t--substPred msg su (RAllT a t) = RAllT a (substPred msg su t)--substPred msg su@(π,_ ) (RFun x t t' r)- | null πs = RFun x (substPred msg su t) (substPred msg su t') r- | otherwise = {-meetListWithPSubs πs πt -}(RFun x t t' r')- where (r', πs) = splitRPvar π r--substPred msg su (RRTy e r o t) = RRTy (mapSnd (substPred msg su) <$> e) r o (substPred msg su t)-substPred msg su (RAllE x t t') = RAllE x (substPred msg su t) (substPred msg su t')-substPred msg su (REx x t t') = REx x (substPred msg su t) (substPred msg su t')-substPred _ _ t = t---- | Requires: @not $ null πs@--- substRCon :: String -> (RPVar, SpecType) -> SpecType -> SpecType--substRCon msg (_, RProp ss (RApp c1 ts1 rs1 r1)) (RApp c2 ts2 rs2 _) πs r2'- | rtc_tc c1 == rtc_tc c2 = RApp c1 ts rs $ meetListWithPSubs πs ss r1 r2'- where- ts = safeZipWith (msg ++ ": substRCon") strSub ts1 ts2- rs = safeZipWith (msg ++ ": substRCon2") strSubR rs1' rs2'- -- TODO: REMOVE `pad` just use rs2 ?- (rs1', rs2') = pad "substRCon" top rs1 rs2- strSub r1 r2 = meetListWithPSubs πs ss r1 r2- strSubR r1 r2 = meetListWithPSubsRef πs ss r1 r2----substRCon msg su t _ _ = errorstar $ msg ++ " substRCon " ++ showpp (su, t)--substPredP msg su@(p, RProp ss _) (RProp s t)- = RProp ss' $ substPred (msg ++ ": substPredP") su t- where- ss' = drop n ss ++ s- n = length ss - length (freeArgsPs p t)--substPredP _ _ (RHProp _ _)- = errorstar "TODO:EFFECTS:substPredP"--substPredP _ su p@(RPropP _ _)- = errorstar ("PredType.substPredP1 called on invalid inputs" ++ showpp (su, p))--substPredP _ su p- = errorstar ("PredType.substPredP called on invalid inputs" ++ showpp (su, p))---splitRPvar pv (U x (Pr pvs) s) = (U x (Pr pvs') s, epvs)- where- (epvs, pvs') = partition (uPVar pv ==) pvs--freeArgsPs p (RVar _ r)- = freeArgsPsRef p r-freeArgsPs p (RFun _ t1 t2 r)- = nub $ freeArgsPsRef p r ++ freeArgsPs p t1 ++ freeArgsPs p t2-freeArgsPs p (RAllT _ t)- = freeArgsPs p t-freeArgsPs p (RAllS _ t)- = freeArgsPs p t-freeArgsPs p (RAllP p' t)- | p == p' = []- | otherwise = freeArgsPs p t-freeArgsPs p (RApp _ ts _ r)- = nub $ freeArgsPsRef p r ++ concatMap (freeArgsPs p) ts-freeArgsPs p (RAllE _ t1 t2)- = nub $ freeArgsPs p t1 ++ freeArgsPs p t2-freeArgsPs p (REx _ t1 t2)- = nub $ freeArgsPs p t1 ++ freeArgsPs p t2-freeArgsPs p (RAppTy t1 t2 r)- = nub $ freeArgsPsRef p r ++ freeArgsPs p t1 ++ freeArgsPs p t2-freeArgsPs _ (RExprArg _)- = []-freeArgsPs p (RHole r)- = freeArgsPsRef p r-freeArgsPs p (RRTy env r _ t)- = nub $ concatMap (freeArgsPs p) (snd <$> env) ++ freeArgsPsRef p r ++ freeArgsPs p t--freeArgsPsRef p (U _ (Pr ps) _) = [x | (_, x, w) <- (concatMap pargs ps'), (EVar x) == w]- where- ps' = f <$> filter (uPVar p ==) ps- f q = q {pargs = pargs q ++ drop (length (pargs q)) (pargs $ uPVar p)}--meetListWithPSubs πs ss r1 r2 = foldl' (meetListWithPSub ss r1) r2 πs-meetListWithPSubsRef πs ss r1 r2 = foldl' ((meetListWithPSubRef ss) r1) r2 πs--meetListWithPSub :: (Reftable r, PPrint t) => [(Symbol, RSort)]-> r -> r -> PVar t -> r-meetListWithPSub ss r1 r2 π- | all (\(_, x, EVar y) -> x == y) (pargs π)- = r2 `meet` r1- | all (\(_, x, EVar y) -> x /= y) (pargs π)- = r2 `meet` (subst su r1)- | otherwise- = errorstar $ "PredType.meetListWithPSub partial application to " ++ showpp π- where- su = mkSubst [(x, y) | (x, (_, _, y)) <- zip (fst <$> ss) (pargs π)]--meetListWithPSubRef ss (RProp s1 r1) (RProp s2 r2) π- | all (\(_, x, EVar y) -> x == y) (pargs π)- = RProp s1 $ r2 `meet` r1- | all (\(_, x, EVar y) -> x /= y) (pargs π)- = RProp s2 $ r2 `meet` (subst su r1)- | otherwise- = errorstar $ "PredType.meetListWithPSubRef partial application to " ++ showpp π- where su = mkSubst [(x, y) | (x, (_, _, y)) <- zip (fst <$> ss) (pargs π)]-meetListWithPSubRef _ _ _ _- = errorstar "PredType.meetListWithPSubRef called with invalid input"--------------------------------------------------------------------------------- | Interface: Modified CoreSyn.exprType due to predApp -------------------------------------------------------------------------------------------------predType :: Type-predType = symbolType predName--wpredName, predName :: Symbol-predName = "Pred"-wpredName = "WPred"--symbolType = TyVarTy . symbolTyVar---substParg :: Functor f => (Symbol, F.Expr) -> f Predicate -> f Predicate-substParg (x, y) = fmap fp- where- fxy s = if (s == EVar x) then y else s- fp = subvPredicate (\pv -> pv { pargs = mapThd3 fxy <$> pargs pv })--------------------------------------------------------------------------------------------------------------- Predicate Application ------------------------------------------------------------------------------------------------------------pappArity = 7--pappSort n = FFunc (2 * n) $ [ptycon] ++ args ++ [boolSort]- where ptycon = fApp (Left predFTyCon) $ FVar <$> [0..n-1]- args = FVar <$> [n..(2*n-1)]--wiredSortedSyms = [(pappSym n, pappSort n) | n <- [1..pappArity]]--predFTyCon = symbolFTycon $ dummyLoc predName
− src/Language/Haskell/Liquid/PrettyPrint.hs
@@ -1,337 +0,0 @@-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE UndecidableInstances #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE TupleSections #-}---- | Module with all the printing and serialization routines--module Language.Haskell.Liquid.PrettyPrint (-- -- * Tidy level- Tidy (..)-- -- * Printing RType- , rtypeDoc- , ppr_rtype-- -- * Printing an Orderable List- , pprManyOrdered-- -- * Printing a List with many large items- , pprintLongList- , ppSpine- , pprintSymbol- ) where--import ErrUtils (ErrMsg)-import HscTypes (SourceError)-import SrcLoc -- (RealSrcSpan, SrcSpan (..))-import GHC (Name, Class)---import VarEnv (emptyTidyEnv)-import Language.Haskell.Liquid.Misc-import Language.Haskell.Liquid.GhcMisc-import Text.PrettyPrint.HughesPJ-import Language.Fixpoint.Types hiding (Predicate)-import Language.Fixpoint.Misc-import Language.Haskell.Liquid.Types hiding (sort)-import Language.Fixpoint.Names (dropModuleNames, propConName, hpropConName)-import TypeRep hiding (maybeParen, pprArrowChain)-import Text.Parsec.Error (ParseError, errorMessages, showErrorMessages)-import Var (Var)-import TyCon (TyCon)-import Control.Applicative ((<$>))-import Data.Maybe (fromMaybe)-import Data.List (sort, sortBy)-import Data.Function (on)-import Data.Monoid (mempty)-import qualified Data.HashMap.Strict as M----pprintSymbol :: Symbol -> Doc-pprintSymbol x = char '‘' <> pprint x <> char '’'--instance PPrint SrcSpan where- pprint = pprDoc--instance PPrint Doc where- pprint x = x--instance PPrint ErrMsg where- pprint = text . show--instance PPrint SourceError where- pprint = text . show--instance PPrint ParseError where- pprint e = vcat $ tail $ map text ls- where- ls = lines $ showErrorMessages "or" "unknown parse error"- "expecting" "unexpected" "end of input"- (errorMessages e)---- instance PPrint LParseError where--- pprint (LPE _ msgs) = text "Parse Error: " <> vcat (map pprint msgs)--instance PPrint Var where- pprint = pprDoc--instance PPrint Name where- pprint = pprDoc--instance PPrint TyCon where- pprint = pprDoc--instance PPrint Type where- pprint = pprDoc -- . tidyType emptyTidyEnv -- WHY WOULD YOU DO THIS???--instance PPrint Class where- pprint = pprDoc--instance Show Predicate where- show = showpp----- | Printing an Ordered List------------------------------------------------------------------pprManyOrdered :: (PPrint a, Ord a) => Tidy -> String -> [a] -> [Doc]-----------------------------------------------------------------pprManyOrdered k msg = map ((text msg <+>) . pprintTidy k) . sort--------------------------------------------------------------------- | Pretty Printing RefType ------------------------------------------------------------------------------------------------------ Should just make this a @Pretty@ instance but its too damn tedious--- to figure out all the constraints.--rtypeDoc k = ppr_rtype (ppE k) TopPrec- where- ppE Lossy = ppEnvShort ppEnv- ppE Full = ppEnv--ppTyConB bb- | ppShort bb = text . symbolString . dropModuleNames . symbol . render . ppTycon- | otherwise = ppTycon---ppr_rtype bb p t@(RAllT _ _)- = ppr_forall bb p t-ppr_rtype bb p t@(RAllP _ _)- = ppr_forall bb p t-ppr_rtype bb p t@(RAllS _ _)- = ppr_forall bb p t-ppr_rtype _ _ (RVar a r)- = ppTy r $ pprint a-ppr_rtype bb p t@(RFun _ _ _ _)- = maybeParen p FunPrec $ ppr_rty_fun bb empty t-ppr_rtype bb p (RApp c [t] rs r)- | isList c- = ppTy r $ brackets (ppr_rtype bb p t) <> ppReftPs bb rs-ppr_rtype bb p (RApp c ts rs r)- | isTuple c- = ppTy r $ parens (intersperse comma (ppr_rtype bb p <$> ts)) <> ppReftPs bb rs-ppr_rtype bb p (RApp c ts rs r)- | isEmpty rsDoc && isEmpty tsDoc- = ppTy r $ ppT c- | otherwise- = ppTy r $ parens $ ppT c <+> rsDoc <+> tsDoc- where- rsDoc = ppReftPs bb rs- tsDoc = hsep (ppr_rtype bb p <$> ts)- ppT = ppTyConB bb--ppr_rtype bb p t@(REx _ _ _)- = ppExists bb p t-ppr_rtype bb p t@(RAllE _ _ _)- = ppAllExpr bb p t-ppr_rtype _ _ (RExprArg e)- = braces $ pprint e-ppr_rtype bb p (RAppTy t t' r)- = ppTy r $ ppr_rtype bb p t <+> ppr_rtype bb p t'-ppr_rtype bb p (RRTy e _ OCons t) - = sep [braces (ppr_rsubtype bb p e) <+> "=>", ppr_rtype bb p t]-ppr_rtype bb p (RRTy e r o t)- = sep [ppp (pprint o <+> ppe <+> pprint r), ppr_rtype bb p t]- where ppe = (hsep $ punctuate comma (pprint <$> e)) <+> colon <> colon- ppp = \doc -> text "<<" <+> doc <+> text ">>"-ppr_rtype _ _ (RHole r)- = ppTy r $ text "_"---ppr_rsubtype bb p e - = pprint_env <+> text "|-" <+> ppr_rtype bb p tl <+> "<:" <+> ppr_rtype bb p tr- where- (el, r) = (init e, last e)- (env, l) = (init el, last el)- tr = snd $ r- tl = snd $ l- pprint_bind (x, t) = pprint x <+> colon <> colon <+> ppr_rtype bb p t - pprint_env = hsep $ punctuate comma (pprint_bind <$> env)--ppSpine (RAllT _ t) = text "RAllT" <+> parens (ppSpine t)-ppSpine (RAllP _ t) = text "RAllP" <+> parens (ppSpine t)-ppSpine (RAllS _ t) = text "RAllS" <+> parens (ppSpine t)-ppSpine (RAllE _ _ t) = text "RAllE" <+> parens (ppSpine t)-ppSpine (REx _ _ t) = text "REx" <+> parens (ppSpine t)-ppSpine (RFun _ i o _) = ppSpine i <+> text "->" <+> ppSpine o-ppSpine (RAppTy t t' _) = text "RAppTy" <+> parens (ppSpine t) <+> parens (ppSpine t')-ppSpine (RHole _) = text "RHole"-ppSpine (RApp c _ _ _) = text "RApp" <+> parens (pprint c)-ppSpine (RVar _ _) = text "RVar"-ppSpine (RExprArg _) = text "RExprArg"-ppSpine (RRTy _ _ _ _) = text "RRTy"---- | From GHC: TypeRep -maybeParen :: Prec -> Prec -> Doc -> Doc-maybeParen ctxt_prec inner_prec pretty- | ctxt_prec < inner_prec = pretty- | otherwise = parens pretty----- ppExists :: (RefTypable p c tv (), RefTypable p c tv r) => Bool -> Prec -> RType p c tv r -> Doc-ppExists bb p t- = text "exists" <+> brackets (intersperse comma [ppr_dbind bb TopPrec x t | (x, t) <- zs]) <> dot <> ppr_rtype bb p t'- where (zs, t') = split [] t- split zs (REx x t t') = split ((x,t):zs) t'- split zs t = (reverse zs, t)---- ppAllExpr :: (RefTypable p c tv (), RefTypable p c tv r) => Bool -> Prec -> RType p c tv r -> Doc-ppAllExpr bb p t- = text "forall" <+> brackets (intersperse comma [ppr_dbind bb TopPrec x t | (x, t) <- zs]) <> dot <> ppr_rtype bb p t'- where (zs, t') = split [] t- split zs (RAllE x t t') = split ((x,t):zs) t'- split zs t = (reverse zs, t)--ppReftPs _ rs- | all isTauto rs = empty- | not (ppPs ppEnv) = empty- | otherwise = angleBrackets $ hsep $ punctuate comma $ pprint <$> rs---- ppr_dbind :: (RefTypable p c tv (), RefTypable p c tv r) => Bool -> Prec -> Symbol -> RType p c tv r -> Doc-ppr_dbind bb p x t- | isNonSymbol x || (x == dummySymbol)- = ppr_rtype bb p t- | otherwise- = pprint x <> colon <> ppr_rtype bb p t---ppr_rty_fun bb prefix t- = prefix <+> ppr_rty_fun' bb t--ppr_rty_fun' bb (RFun b t t' _)- = ppr_dbind bb FunPrec b t <+> ppr_rty_fun bb arrow t'-ppr_rty_fun' bb t- = ppr_rtype bb TopPrec t----- ppr_forall :: (RefTypable p c tv (), RefTypable p c tv r) => Bool -> Prec -> RType p c tv r -> Doc-ppr_forall bb p t- = maybeParen p FunPrec $ sep [ ppr_foralls (ppPs bb) (ty_vars trep) (ty_preds trep) (ty_labels trep) , ppr_clss cls, ppr_rtype bb TopPrec t' ]- where- trep = toRTypeRep t- (cls, t') = bkClass $ fromRTypeRep $ trep {ty_vars = [], ty_preds = [], ty_labels = []}-- ppr_foralls False _ _ _= empty- ppr_foralls _ [] [] [] = empty- ppr_foralls True αs πs ss = text "forall" <+> dαs αs <+> dπs (ppPs bb) πs <+> dss (ppSs bb) ss <> dot- ppr_clss [] = empty- ppr_clss cs = (parens $ hsep $ punctuate comma (uncurry (ppr_cls bb p) <$> cs)) <+> text "=>"-- dαs αs = sep $ pprint <$> αs-- dπs _ [] = empty- dπs False _ = empty- dπs True πs = angleBrackets $ intersperse comma $ ppr_pvar_def pprint <$> πs- dss _ [] = empty- dss _ ss = angleBrackets $ intersperse comma $ pprint <$> ss---ppr_cls bb p c ts- = pp c <+> hsep (map (ppr_rtype bb p) ts)- where- pp | ppShort bb = text . symbolString . dropModuleNames . symbol . render . pprint- | otherwise = pprint---ppr_pvar_def pprv (PV s t _ xts)- = pprint s <+> dcolon <+> intersperse arrow dargs <+> ppr_pvar_kind pprv t-- where- dargs = [pprv t | (t,_,_) <- xts]--ppr_pvar_kind pprv (PVProp t) = pprv t <+> arrow <+> ppr_name propConName-ppr_pvar_kind _ (PVHProp) = ppr_name hpropConName-ppr_name = text . symbolString--instance PPrint RTyVar where- pprint (RTV α)- | ppTyVar ppEnv = ppr_tyvar α- | otherwise = ppr_tyvar_short α--ppr_tyvar = text . tvId-ppr_tyvar_short = text . showPpr--instance (Reftable s, PPrint s, PPrint p, Reftable p, PPrint t, PPrint (RType b c p)) => PPrint (Ref t s (RType b c p)) where- pprint (RPropP ss s) = ppRefArgs (fst <$> ss) <+> pprint s- pprint (RProp ss s) = ppRefArgs (fst <$> ss) <+> pprint (fromMaybe mempty (stripRTypeBase s))- pprint (RHProp ss _) = ppRefArgs (fst <$> ss) <+> text "world"---ppRefArgs [] = empty-ppRefArgs ss = text "\\" <> hsep (ppRefSym <$> ss ++ [vv Nothing]) <+> text "->"--ppRefSym "" = text "_"-ppRefSym s = pprint s--instance (PPrint r, Reftable r) => PPrint (UReft r) where- pprint (U r p _)- | isTauto r = pprint p- | isTauto p = pprint r- | otherwise = pprint p <> text " & " <> pprint r--pprintLongList :: PPrint a => [a] -> Doc-pprintLongList = brackets . vcat . map pprint----instance (PPrint t) => PPrint (Annot t) where- pprint (AnnUse t) = text "AnnUse" <+> pprint t- pprint (AnnDef t) = text "AnnDef" <+> pprint t- pprint (AnnRDf t) = text "AnnRDf" <+> pprint t- pprint (AnnLoc l) = text "AnnLoc" <+> pprDoc l--pprAnnInfoBinds (l, xvs)- = vcat $ map (pprAnnInfoBind . (l,)) xvs--pprAnnInfoBind (RealSrcSpan k, xv)- = xd $$ pprDoc l $$ pprDoc c $$ pprint n $$ vd $$ text "\n\n\n"- where- l = srcSpanStartLine k- c = srcSpanStartCol k- (xd, vd) = pprXOT xv- n = length $ lines $ render vd--pprAnnInfoBind (_, _)- = empty--pprXOT (x, v) = (xd, pprint v)- where- xd = maybe (text "unknown") pprint x--instance PPrint a => PPrint (AnnInfo a) where- pprint (AI m) = vcat $ map pprAnnInfoBinds $ M.toList m--instance (Ord k, PPrint k, PPrint v) => PPrint (M.HashMap k v) where- pprint = ppTable--ppTable m = vcat $ pprxt <$> xts- where- pprxt (x,t) = pprint x $$ nest n (colon <+> pprint t)- n = 1 + maximumWithDefault 0 [ i | (x, _) <- xts, let i = keySize x, i <= thresh ]- keySize = length . render . pprint- xts = sortBy (compare `on` fst) $ M.toList m- thresh = 6
+ src/Language/Haskell/Liquid/Prover/Constants.hs view
@@ -0,0 +1,25 @@+module Language.Haskell.Liquid.Prover.Constants where++-------------------------------------------------------------------------------+---------------------------- Debugging -------------------------------------+-------------------------------------------------------------------------------++debug = True +whenLoud act = if debug then act else return ()++-------------------------------------------------------------------------------+------------------------ Constant Numbers ---------------------------------+-------------------------------------------------------------------------------++delta, epsilon, default_depth :: Int +delta = 5 +epsilon = 10 +default_depth = 2 +++-------------------------------------------------------------------------------+------------------------ Files ---------------------------------------------+-------------------------------------------------------------------------------++smtFileExtention = ".smt"+smtFile fn = fn ++ smtFileExtention
+ src/Language/Haskell/Liquid/Prover/Misc.hs view
@@ -0,0 +1,38 @@+module Language.Haskell.Liquid.Prover.Misc where++import Data.List+++++-------------------------------------------------------------------------------+----------------------- Playing with lists -------------------------------+-------------------------------------------------------------------------------++-- | Powerset +powerset = sortBy (\l1 l2 -> compare (length l1) (length l2)) . powerset'++powerset' :: [a] -> [[a]]+powerset' [] = [[]]+powerset' (x:xs) = xss /\/ map (x:) xss+ where xss = powerset' xs++(/\/) :: [a] -> [a] -> [a]+[] /\/ ys = ys+(x:xs) /\/ ys = x : (ys /\/ xs)+++++-------------------------------------------------------------------------------+----------------------- Playing with monads -------------------------------+-------------------------------------------------------------------------------++findM :: (Monad m) => (a -> m Bool) -> [a] -> m (Maybe a)+findM _ [] = return Nothing +findM p (x:xs) = do {r <- p x; if r then return (Just x) else findM p xs}+++mapSnd f (x, y) = (x, f y)++second3 f (x, y, z) = (x, f y, z)
+ src/Language/Haskell/Liquid/Prover/Names.hs view
@@ -0,0 +1,8 @@+{-# LANGUAGE OverloadedStrings #-}++module Language.Haskell.Liquid.Prover.Names where++import Language.Fixpoint.Types++exprToBoolSym :: Symbol+exprToBoolSym = "exprToBool"
+ src/Language/Haskell/Liquid/Prover/Parser.hs view
@@ -0,0 +1,100 @@+module Language.Haskell.Liquid.Prover.Parser where++import Language.Haskell.Liquid.Prover.Types+import Language.Haskell.Liquid.Prover.Constants (default_depth)++import Text.Parsec++import Language.Fixpoint.Parse hiding (bindP)+import Language.Fixpoint.Types (Expr(PAnd), symbol, Sort(FObj))++parseQuery :: String -> IO LQuery+parseQuery fn = parseFromFile (queryP fn) fn +++queryP fn = do+ n <- depthP+ bs <- sepBy envP whiteSpace+ semi+ vars <- sepBy bindP whiteSpace+ semi+ ds <- declsP+ axioms <- sepBy axiomP whiteSpace+ semi+ ctors <- sepBy ctorP whiteSpace+ semi + goal <- goalP+ return $ mempty { q_axioms = axioms+ , q_vars = vars+ , q_ctors = ctors+ , q_goal = goal+ , q_fname = fn+ , q_depth = n + , q_env = bs+ , q_decls = ds+ }+++declsP :: Parser [Predicate]+declsP = try (do {n <- sepBy declP whiteSpace; semi; return n} )+ <|> return []++declP :: Parser Predicate+declP = reserved "declare" >> predicateP++depthP :: Parser Int +depthP = try (do {reserved "depth"; reserved "="; n <- fromInteger <$> integer; semi; return n} )+ <|> return default_depth++goalP :: Parser Predicate+goalP = reserved "goal" >> colon >> predicateP++ctorP :: Parser LVarCtor+ctorP = do reserved "constructor"+ v <- varP+ (vs, p) <- try (ctorAxiomP)+ return $ VarCtor v vs p++ctorAxiomP + = do reserved "with"+ reserved "forall"+ aargs <- argumentsP+ abody <- predicateP+ return (aargs, abody) + <|> return ([], Pred $ PAnd [])++bindP :: Parser LVar+bindP = reserved "bind" >> varP++envP :: Parser LVar+envP = reserved "constant" >> varP++predicateP :: Parser Predicate+predicateP = Pred <$> predP++axiomP :: Parser LAxiom+axiomP = do + reserved "axiom"+ aname <- mkVar <$> symbolP+ colon+ reserved "forall"+ aargs <- argumentsP+ abody <- predicateP+ return $ Axiom aname aargs abody+ where+ dummySort = FObj (symbol "dummySort")+ mkVar x = Var x dummySort ()+++argumentsP :: Parser ([LVar])+argumentsP = brackets $ sepBy varP comma++varP :: Parser LVar+varP = do + x <- symbolP+ colon+ s <- sortP+ return $ Var x s ()+++
+ src/Language/Haskell/Liquid/Prover/Pretty.hs view
@@ -0,0 +1,64 @@+module Language.Haskell.Liquid.Prover.Pretty where++import Language.Haskell.Liquid.Prover.Types++import Language.Fixpoint.Types hiding (Predicate, EApp, EVar, Expr)++instance PPrint (Var a) where+ pprintTidy k = pprintTidy k . var_name++instance PPrint (Expr a) where+ pprintTidy k = pprintTidy k . mkExpr++instance PPrint Predicate where+ pprintTidy k = pprintTidy k . p_pred++instance Show (Axiom a) where+ show a = showpp (axiom_name a) ++ ": " ++ "forall"++ par(sep ", " $ map show (axiom_vars a)) ++ "." ++ show (axiom_body a) ++ "\n"++instance Show (Instance a) where+ show i = "\nInstance :: " ++ show (inst_axiom i) ++ "With Arguments :: " ++ (sep ", " $ map show (inst_args i))+ -- ++ "\n\nPredicate = " ++ show (inst_pred i) ++ "\n\n"++instance Show (Var a) where+ show v = showpp (var_name v) ++ " : " ++ showpp (var_sort v)++instance Show (Ctor a) where+ show c = show (ctor_expr c) ++ "\t \\" ++ (sep ", " $ map show (ctor_vars c)) -- ++ " -> " ++ show (ctor_prop c)++instance Show (VarCtor a) where+ show c = show (vctor_var c) ++ "\t \\" ++ (sep ", " $ map show (vctor_vars c)) -- ++ " -> " ++ show (vctor_prop c)++instance Show (Expr a) where+ show (EVar v) = showpp v+ show (EApp c es) = show c ++ par (sep ", " $ map show es)++instance Show Predicate where+ show (Pred p) = showpp $ pprint p++instance Show (Query a) where+ show q = "\nQuery\n" +++ "\nAxioms::" ++ (showNum $ q_axioms q) +++ "\nVars ::" ++ (sep ", " $ map show $ q_vars q) +++ "\nCtors ::" ++ (sep ", " $ map show $ q_ctors q) +++ "\nDecls ::" ++ (sep ", " $ map show $ q_decls q) +++ "\nGoal ::" ++ (show $ q_goal q) +++ "\nDecls ::" ++ (show $ q_decls q) +++ "\nFname ::" ++ (show $ q_fname q)++instance Show (Proof a) where+ show Invalid = "\nInvalid\n"+ show (Proof is) = "\nProof ::\n" ++ (sep "\n" $ map show is)+++instance Show (ArgExpr a) where+ show ae = "\nArgExpr for " ++ show (arg_sort ae) ++ "\n\nEXPRS = \n\n" ++ (sep ", " (map show $ arg_exprs ae)) +++ "\n\nConstructors = " ++ (sep ", " (map show $ arg_ctors ae)) ++ "\n\n"++showNum ls = concat [ show i ++ " . " ++ show l | (l, i) <- zip ls [1..] ]+++par str = " (" ++ str ++ ") "+sep _ [] = []+sep _ [x] = x+sep c (x:xs) = x ++ c ++ sep c xs
+ src/Language/Haskell/Liquid/Prover/SMTInterface.hs view
@@ -0,0 +1,14 @@+module Language.Haskell.Liquid.Prover.SMTInterface where++import Language.Fixpoint.Smt.Interface ++import Language.Fixpoint.Types++makeContext :: FilePath -> [(Symbol, Sort)] -> IO Context +makeContext = makeZ3Context++checkValid :: Context -> [Expr] -> Expr -> IO Bool+checkValid me is q = checkValidWithContext me [] (pAnd is) q++assert :: Context -> Expr -> IO ()+assert = smtAssert
+ src/Language/Haskell/Liquid/Prover/Solve.hs view
@@ -0,0 +1,304 @@+{-# LANGUAGE PatternGuards #-}+{-# LANGUAGE TupleSections #-}++module Language.Haskell.Liquid.Prover.Solve where++import Language.Haskell.Liquid.Prover.Types+import Language.Haskell.Liquid.Prover.SMTInterface+import Language.Haskell.Liquid.Prover.Pretty ()+import Language.Haskell.Liquid.Prover.Constants+import Language.Haskell.Liquid.Prover.Misc (findM, powerset)++import Language.Fixpoint.Smt.Interface (Context)+-- import Language.Fixpoint.Misc +import qualified Language.Fixpoint.Types as F ++import Data.List (nubBy, nub, isPrefixOf, partition)+import Data.Maybe (isJust, fromJust, catMaybes)++import System.IO++-- import Control.Monad (filterM)++import Language.Fixpoint.SortCheck+import Language.Fixpoint.Types.Refinements (SortedReft)++type PrEnv = F.SEnv SortedReft ++solve :: Query a -> IO (Proof a)+solve q = + do putStrLn $ "Solving Query\n" ++ show q+ cxt <- makeContext (smtFile $ q_fname q) env+ mapM_ (assert cxt) (p_pred <$> q_decls q)+ proof <- iterativeSolve γ (q_depth q) cxt (varCtorToCtor <$> q_ctors q) es (p_pred $ q_goal q) (q_axioms q)+ putStrLn $ ("\nProof = \n" ++ show proof)+ return proof+ where + es = initExpressions $ filter notGHCVar vars+ env = nub ([(var_name v, var_sort v) | v <- ((vctor_var <$> q_ctors q) ++ q_vars q), notGHCVar v ] ++ [(var_name v, var_sort v) | v <- q_env q])+ γ = F.fromListSEnv $ [(x, F.trueSortedReft s) | (x,s) <- env]+ vars = if q_isHO q then ((vctor_var <$> q_ctors q) ++ q_vars q) else q_vars q+++notGHCVar v + = not $ isPrefixOf "GHC" (show v)++iterativeSolve :: PrEnv -> Int -> Context -> [Ctor a] -> [Expr a] -> F.Expr -> [Axiom a] -> IO (Proof a)+iterativeSolve γ iter cxt cts es q axioms = go is0 [] 0 tes+ where + go _ _ i _ | i == iter = return Invalid + go as old_es i es = do prf <- findValid cxt is q + -- putStr ("Validity check with " ++ show is ++ " IS " ++ show prf) + -- putStrLn ("\nITERATION\n" ++ show i)+ if isJust prf + then do putStrLn "Minimizing Solution"+ Proof <$> minimize cxt (fromJust prf) q+ else do es' <- makeExpressions γ cxt is cts es + mapM_ (assertExpressions γ cxt) es'+ go is (mergeExpressions es old_es) (i+1) es' + where + is = concatMap (instantiate γ old_es es) asn ++ as+ (as0, asn) = partition (null . axiom_vars) axioms+ is0 = (\a -> Inst a [] (axiom_body a)) <$> as0 + tes = groupExpressions γ es +++type Arguments a = [(F.Sort, [Expr a])] ++groupExpressions :: PrEnv -> [Expr a] -> Arguments a +groupExpressions γ = go [] + where+ go acc [] = acc+ go acc (e:es) = go (placeExpr γ acc e) es ++placeExpr :: PrEnv -> Arguments a -> Expr a -> Arguments a +placeExpr γ acc e = go [] acc + where+ t = sortExpr F.dummySpan γ' $ mkExpr e+ go old_as [] = (t, [e]):(acc ++ old_as)+ go old_as ((s, es):as) | unifiable s t = (s,e:es):(as ++ old_as)+ | otherwise = go ((s,es):old_as) as + γ' = F.fromListSEnv $ [(x, F.sr_sort s) | (x,s) <- F.toListSEnv γ]++mergeExpressions :: Arguments a -> Arguments a -> Arguments a +mergeExpressions as1 as2 = merge as1 as2 + where+ merge as1 [] = as1 + merge as1 (a:as) = merge (placeArg as1 a) as ++placeArg as a = go [] a as + where+ go acc a [] = a:acc+ go acc (s, es) ((s', es'):as) | unifiable s s' = (s, es++es'):(as++acc) + | otherwise = go ((s', es'):acc) (s, es) as +++findValid :: Context -> [Instance a] -> F.Expr -> IO (Maybe [Instance a])+findValid cxt ps q + = (\b -> if b then Just ps else Nothing) <$> checkValid cxt (p_pred . inst_pred <$> ps) q++minimize :: Context -> [Instance a] -> F.Expr -> IO [Instance a]+minimize cxt ps q | length ps < epsilon = fromJust <$> bruteSearch cxt ps q +minimize cxt ps q = go 1 [] ps + where+ n = length ps `div` delta+ go _ acc [] = if (length acc < length ps) then minimize cxt acc q else fromJust <$> bruteSearch cxt acc q + go i acc is = do let (ps1, ps2) = splitAt n is + let as = p_pred . inst_pred <$> (acc ++ ps2)+ res <- checkValid cxt as q+ let _msg = show i ++ " / " ++ show delta ++ "\n"+ putStr "*" >> hFlush stdout+ if res then go (i+1) acc ps2 + else go (i+1) (acc ++ ps1) ps2 ++bruteSearch :: Context -> [Instance a] -> F.Expr -> IO (Maybe [Instance a])+bruteSearch cxt ps q + = findM (\is -> checkValid cxt (p_pred . inst_pred <$> is) q) (powerset ps)++filterEquivalentExpressions :: PrEnv -> Context -> [Instance a] -> Arguments a -> Arguments a -> IO (Arguments a)+filterEquivalentExpressions γ cxt is esold esnew + = mapM filterArguments esnew+ where + filterArguments (s, es) = (s,) <$> foo [] (grapOldArgs s esold) es + f eold e@(EApp c es) = not <$> checkValid cxt ((predCtor γ c (mkExpr <$> es)):(p_pred . inst_pred <$> is))+ (F.POr $ catMaybes $ (makeEq γ e <$> eold))+ f eold e = not <$> checkValid cxt (p_pred . inst_pred <$> is) (F.POr $ catMaybes $ (makeEq γ e <$> eold))+++ foo acc _ [] = return acc + foo acc old (e:es) = do r <- f (acc ++ old) e+ if r then foo (e:acc) old es + else foo acc old es ++++ grapOldArgs _ [] = [] + grapOldArgs s ((t, es):as) + | unifiable s t = es ++ grapOldArgs s as + | otherwise = grapOldArgs s as ++makeEq :: PrEnv -> Expr a -> Expr a -> Maybe (F.Expr)+makeEq γ e1 e2 = case (checkSortedReftFull γ p) of + Nothing -> Just p + Just _ -> Nothing + where+ p = F.PAtom F.Eq (mkExpr e1) (mkExpr e2) +++assertExpressions :: PrEnv -> Context -> (F.Sort, [Expr a]) -> IO ()+assertExpressions γ cxt a = mapM_ go (snd a) + where+ go (EApp c es) + | length es == length (ctor_vars c)+ = do mapM go es + assert cxt $ predCtor γ c (mkExpr <$> es)+ go _ + = return ()++predCtor γ c es + | length es /= length (ctor_vars c) && length (ctor_vars c) /= 0+ = F.PTrue + | otherwise + = case checkSortedReftFull γ p of+ Nothing -> p+ Just _ -> F.PTrue + where + su = F.mkSubst $ zip (var_name <$> ctor_vars c) es+ p = F.subst su (p_pred $ ctor_prop c)++makeExpressions :: PrEnv -> Context -> [Instance a] -> [Ctor a] -> Arguments a -> IO (Arguments a)+makeExpressions γ cxt is cts es + = -- traceShow ("\nNew expressions from \n" ++ show cts ++ "\nAND\n" ++ show es) <$> + filterEquivalentExpressions γ cxt is es newes + where+ newes = groupExpr [] [EApp c ess | c <- cts, ess <- makeCTorArgs c es]++ groupExpr acc [] = acc + groupExpr acc (e:es) = groupExpr (putExpr e (checkSortExpr γ' $ mkExpr e) acc) es ++ γ' = F.fromListSEnv $ [(x, F.sr_sort s) | (x,s) <- F.toListSEnv γ]+++putExpr _ Nothing as + = as +putExpr e (Just t) [] + = [(t, [e])]+putExpr e (Just t) ((s, es):as)+ | unifiable t s = (s, e:es):as+ | otherwise = (s, es):putExpr e (Just t) as +++makeArguments :: [F.Sort] -> Arguments a -> [[Expr a]]+makeArguments ss es = applyArguments ees + where + ees = -- traceShow ("\nCandicate for \n" ++ show ss ++ "\nWith arguments \n" ++ show es) + ((`makeCandicates` es) <$> ss)++ makeCandicates _ [] = [] + makeCandicates s ((t,xs):xss) + | unifiable s t = xs ++ makeCandicates s xss + | otherwise = makeCandicates s xss +++makeCTorArgs :: Ctor a -> Arguments a -> [[Expr a]]+makeCTorArgs c = makeArguments ((var_sort <$> ctor_vars c) ++ (argumentssort $ ctor_sort c))+ where+ argumentssort (F.FAbs _ s) = argumentssort s + argumentssort (F.FFunc s' s) = s':argumentssort s + argumentssort _ = [] ++applyArguments :: [[a]] -> [[a]]+applyArguments [] = []+applyArguments ([]:_) = [] +applyArguments ((x:xs):ess) = [x] : ((map (x:) (filter (not . null ) $ applyArguments ess)) ++ applyArguments (xs:ess))++makeArgumnetsExpr n es = concatMap (`makeArgs` es) [1..n]++arity :: Ctor a -> Int+arity c + = case F.functionSort $ ctor_sort c of + Nothing -> 0 + Just (_, ss, _) -> length ss ++initExpressions :: [Var a] -> [Expr a]+initExpressions = map EVar++instantiate :: PrEnv -> Arguments a -> Arguments a -> Axiom a -> [Instance a]+instantiate γ oldses ses a + = {- traceShow ("\nInstances for\n" ++ show a ++ + "ALL expr = " ++ show (oldses, mergeExpressions oldses ses) ++ + "\nTYPES = \n" ++ show ss +++ "\nmake arguments = \n" ++ show (makeArguments ss (mergeExpressions ses oldses))+ ) $ -} + catMaybes (axiomInstance γ a <$> args) + where+ args = filter (\es -> length es == length ss && hasNew es) $ makeArguments ss (mergeExpressions ses oldses)+ hasNew = any (`elem` (concatMap snd ses))+ ss = var_sort <$> axiom_vars a ++makeArgs' n es + | length es < n = []+ | otherwise = makeArgs n es +-- NV TODO: allow multiple occurences of the same argument+duplicateArgs _ e = [e]++makeArgs :: Int -> [Expr a] -> [[Expr a]]+makeArgs 0 _ = [[]]+makeArgs n (x:xs) + | n == length (x:xs)+ = [x:xs] + | otherwise+ = ((x:)<$> makeArgs (n-1) xs) ++ makeArgs n xs+makeArgs n xs = error ("makeArgs for " ++ show (n, xs))+++axiomInstance :: PrEnv -> Axiom a -> [Expr a] -> Maybe (Instance a) +axiomInstance γ a es + = case checkSortedReftFull γ $ p_pred pred of+ Nothing -> Just {- traceShow "\n\n Add instance" -} i+ Just _e -> {- traceShow (show _e ++ "\n\n Reject instance " ++ show i ) -} Nothing + where + pred = F.subst (F.mkSubst $ zip (var_name <$> (axiom_vars a)) (mkExpr <$> es)) (axiom_body a)+ i = Inst { inst_axiom = a+ , inst_args = es+ , inst_pred = pred+ }+++checkExpr :: PrEnv -> Expr a -> Bool+checkExpr γ e = not $ isJust $ checkSortedReftFull γ $ mkExpr e ++mkcheckExpr :: PrEnv -> Expr a -> F.Expr+mkcheckExpr γ e + = case checkSortedReftFull γ e' of+ Nothing -> e'+ Just d -> error ("Unsorted expression\n" ++ show e ++ "\nExpr = \n" ++ show e' ++ "\nError\n" ++ show d)++ where e' = mkExpr e +++makeSorts :: Query a -> [F.Sort]+makeSorts q = nubBy unifiable (asorts ++ csorts)+ where + asorts = var_sort <$> (concatMap axiom_vars $ q_axioms q)+ csorts = concatMap argumentsort ((var_sort . vctor_var) <$> q_ctors q)+ argumentsort s = case F.functionSort s of {Nothing -> []; Just (_, ss, s) -> s:ss}++++unifiable :: F.Sort -> F.Sort -> Bool+unifiable (F.FVar _) (F.FVar _) = True +unifiable (F.FVar _) (F.FObj _) = True +unifiable (F.FObj _) (F.FVar _) = True +unifiable (F.FVar _) _ = True +unifiable _ (F.FVar _) = True +unifiable (F.FObj _) _ = True +unifiable _ (F.FObj _) = True +unifiable (F.FApp t s) (F.FApp t' s') = unifiable t t' && unifiable s s'+unifiable (F.FFunc t s) (F.FFunc t' s') = unifiable t t' && unifiable s s'+unifiable (F.FAbs _ t) t' = unifiable t t'+unifiable t (F.FAbs _ t') = unifiable t t'++unifiable t1 t2 = isJust $ unify (const $ error "NV TODO: prover.Solve") t1 t2++
+ src/Language/Haskell/Liquid/Prover/Types.hs view
@@ -0,0 +1,129 @@+{-# LANGUAGE TypeSynonymInstances #-}+{-# LANGUAGE PatternGuards #-}++module Language.Haskell.Liquid.Prover.Types where++import Language.Haskell.Liquid.Prover.Constants (default_depth)++import qualified Language.Fixpoint.Types as F+import Language.Fixpoint.Types hiding (Predicate, EApp, EVar, Expr)++type LVar = Var ()+type LVarCtor = VarCtor ()+type LAxiom = Axiom ()+type LQuery = Query ()+++data Axiom a = Axiom { axiom_name :: Var a+ , axiom_vars :: [LVar]+ , axiom_body :: Predicate+ }++data Var a = Var { var_name :: Symbol+ , var_sort :: Sort+ , var_info :: a+ }++instance Eq (Var a) where+ v1 == v2 = (var_name v1) == (var_name v2)+++-- Note: Ctors may be higher order, like compose+-- when not fully instantiated, the predicate should not be used+data Ctor a = Ctor { ctor_expr :: Expr a+ , ctor_sort :: Sort + , ctor_vars :: [LVar]+ , ctor_prop :: Predicate+ }+ -- constructors can be expressions like (compose f g)+++data VarCtor a = VarCtor { vctor_var :: Var a+ , vctor_vars :: [LVar]+ , vctor_prop :: Predicate+ }+++instance Eq (Ctor a) where+ c1 == c2 = (ctor_expr c1) == (ctor_expr c2)++data Expr a = EVar (Var a)+ | EApp (Ctor a) [Expr a]++ deriving (Eq)++newtype Predicate = Pred {p_pred :: F.Expr}++data Proof a = Invalid+ | Proof { p_evidence :: [Instance a]}++data Instance a = Inst { inst_axiom :: Axiom a+ , inst_args :: [Expr a]+ , inst_pred :: Predicate+ }+++data Query a = Query { q_axioms :: ![Axiom a]+ , q_ctors :: ![VarCtor a]+ , q_vars :: ![Var a]+ , q_env :: ![LVar]+ , q_goal :: !Predicate+ , q_fname :: !FilePath+ , q_depth :: !Int+ , q_decls :: [Predicate]+ , q_isHO :: Bool + }++-- | ArgExpr provides for each sort s+-- | a list of expressions of sort s+-- | and the list of constroctors that can create an expression of sort s.+data ArgExpr a = ArgExpr { arg_sort :: Sort+ , arg_exprs :: [Expr a]+ , arg_ctors :: [Ctor a]+ }++instance Monoid Predicate where+ mempty = Pred mempty+ mappend (Pred p1) (Pred p2) = Pred (p1 `mappend` p2)++instance Monoid (Query a) where+ mempty = Query { q_axioms = mempty+ , q_ctors = mempty+ , q_vars = mempty+ , q_env = mempty+ , q_goal = mempty+ , q_fname = mempty+ , q_depth = default_depth+ , q_decls = mempty+ , q_isHO = False + }+ mappend q1 q2 = Query { q_axioms = q_axioms q1 `mappend` q_axioms q2+ , q_ctors = q_ctors q1 `mappend` q_ctors q2+ , q_env = q_env q1 `mappend` q_env q2+ , q_vars = q_vars q1 `mappend` q_vars q2+ , q_goal = q_goal q1 `mappend` q_goal q2+ , q_fname = q_fname q1 `mappend` q_fname q2+ , q_decls = q_decls q1 `mappend` q_decls q2+ , q_depth = q_depth q1 `max` q_depth q2+ , q_isHO = q_isHO q1 || q_isHO q2+ }+++instance F.Subable Predicate where+ subst su (Pred p) = Pred $ subst su p+ substa su (Pred p) = Pred $ substa su p+ substf su (Pred p) = Pred $ substf su p+ syms (Pred p) = syms p++varCtorToCtor :: VarCtor a -> Ctor a+varCtorToCtor (VarCtor v vs p) = Ctor (EVar v) (var_sort v) vs p+++isEVar (EVar _) = True+isEVar _ = False++mkExpr :: Expr a -> F.Expr+mkExpr (EVar v) + = F.EVar (var_name v)+mkExpr (EApp c es)+ = F.eApps (mkExpr $ ctor_expr c) (mkExpr <$> es)
− src/Language/Haskell/Liquid/Qualifier.hs
@@ -1,133 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE ViewPatterns #-}-module Language.Haskell.Liquid.Qualifier (- specificationQualifiers- ) where--import Language.Haskell.Liquid.Bare-import Language.Haskell.Liquid.RefType-import Language.Haskell.Liquid.GhcMisc (getSourcePos)-import Language.Haskell.Liquid.PredType-import Language.Haskell.Liquid.Types-import Language.Fixpoint.Types-import Language.Fixpoint.Misc--import Control.Applicative ((<$>))-import Data.List (delete, nub)-import Data.Maybe (fromMaybe)-import qualified Data.HashSet as S-import Data.Bifunctor (second)--------------------------------------------------------------------------------------specificationQualifiers :: Int -> GhcInfo -> [Qualifier]-------------------------------------------------------------------------------------specificationQualifiers k info- = [ q | (x, t) <- (tySigs $ spec info) ++ (asmSigs $ spec info) ++ (ctors $ spec info)- -- FIXME: this mines extra, useful qualifiers but causes a significant increase in running time- -- , ((isClassOp x || isDataCon x) && x `S.member` (S.fromList $ impVars info ++ defVars info)) || x `S.member` (S.fromList $ defVars info)- , x `S.member` (S.fromList $ defVars info)- , q <- refTypeQuals (getSourcePos x) (tcEmbeds $ spec info) (val t)- , length (q_params q) <= k + 1- ]---- GRAVEYARD: scraping quals from imports kills the system with too much crap--- specificationQualifiers info = {- filter okQual -} qs--- where--- qs = concatMap refTypeQualifiers ts--- refTypeQualifiers = refTypeQuals $ tcEmbeds spc--- ts = val <$> t1s ++ t2s--- t1s = [t | (x, t) <- tySigs spc, x `S.member` definedVars]--- t2s = [] -- [t | (_, t) <- ctor spc ]--- definedVars = S.fromList $ defVars info--- spc = spec info------ okQual = not . any isPred . map snd . q_params--- where--- isPred (FApp tc _) = tc == stringFTycon "Pred"--- isPred _ = False---refTypeQuals l tce t = quals ++ pAppQuals l tce preds quals- where- quals = refTypeQuals' l tce t- preds = filter isPropPV $ ty_preds $ toRTypeRep t--pAppQuals l tce ps qs = [ pAppQual l tce p xs (v, e) | p <- ps, (s, v, _) <- pargs p, (xs, e) <- mkE s ]- where- mkE s = concatMap (expressionsOfSort (rTypeSort tce s)) qs--expressionsOfSort sort (Q _ pars (PAtom Eq (EVar v) e2) _)- | (v, sort) `elem` pars- = [(filter (/=(v, sort)) pars, e2)]--expressionsOfSort _ _- = []--pAppQual l tce p args (v, expr) = Q "Auto" freeVars pred l- where- freeVars = (vv, tyvv) : (predv, typred) : args- pred = pApp predv $ EVar vv:predArgs- vv = "v"- predv = "~P"- tyvv = rTypeSort tce $ pvType p- typred = rTypeSort tce (pvarRType p :: RSort)- predArgs = mkexpr <$> (snd3 <$> pargs p)- mkexpr x = if x == v then expr else EVar x---- refTypeQuals :: SpecType -> [Qualifier]-refTypeQuals' l tce t0 = go emptySEnv t0- where- go γ t@(RVar _ _) = refTopQuals l tce t0 γ t- go γ (RAllT _ t) = go γ t- go γ (RAllP _ t) = go γ t- go γ t@(RAppTy t1 t2 _) = go γ t1 ++ go γ t2 ++ refTopQuals l tce t0 γ t- go γ (RFun x t t' _) = (go γ t)- ++ (go (insertSEnv x (rTypeSort tce t) γ) t')- go γ t@(RApp c ts rs _) = (refTopQuals l tce t0 γ t)- ++ concatMap (go (insertSEnv (rTypeValueVar t) (rTypeSort tce t) γ)) ts- ++ goRefs c (insertSEnv (rTypeValueVar t) (rTypeSort tce t) γ) rs- go γ (RAllE x t t') = (go γ t)- ++ (go (insertSEnv x (rTypeSort tce t) γ) t')- go γ (REx x t t') = (go γ t)- ++ (go (insertSEnv x (rTypeSort tce t) γ) t')- go _ _ = []- goRefs c g rs = concat $ zipWith (goRef g) rs (rTyConPVs c)- goRef g (RProp s t) _ = go (insertsSEnv g s) t- goRef _ (RPropP _ _) _ = []- goRef _ (RHProp _ _) _ = errorstar "TODO: EFFECTS"- insertsSEnv = foldr (\(x, t) γ -> insertSEnv x (rTypeSort tce t) γ)--refTopQuals l tce t0 γ t- = [ mkQual l t0 γ v so pa | let (RR so (Reft (v, ra))) = rTypeSortedReft tce t- , pa <- conjuncts $ raPred ra- , not $ isHole pa- ] ++- [ mkPQual l tce t0 γ s e | let (U _ (Pr ps) _) = fromMaybe (msg t) $ stripRTypeBase t- , p <- findPVar (ty_preds $ toRTypeRep t0) <$> ps- , (s, _, e) <- pargs p- ]- where- msg t = errorstar $ "Qualifier.refTopQuals: no typebase" ++ showpp t--mkPQual l tce t0 γ t e = mkQual l t0 γ' v so pa- where- v = "vv"- so = rTypeSort tce t- γ' = insertSEnv v so γ- pa = PAtom Eq (EVar v) e--mkQual l t0 γ v so p = Q "Auto" ((v, so) : yts) p' l- where- yts = [(y, lookupSort t0 x γ) | (x, y) <- xys ]- p' = subst (mkSubst (second EVar <$> xys)) p- xys = zipWith (\x i -> (x, symbol ("~A" ++ show i))) xs [0..]- xs = delete v $ orderedFreeVars γ p--lookupSort t0 x γ = fromMaybe (errorstar msg) $ lookupSEnv x γ- where- msg = "Unknown freeVar " ++ show x ++ " in specification " ++ show t0--orderedFreeVars γ = nub . filter (`memberSEnv` γ) . syms---- atoms (PAnd ps) = concatMap atoms ps--- atoms p = [p]
− src/Language/Haskell/Liquid/RefSplit.hs
@@ -1,123 +0,0 @@-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE UndecidableInstances #-}--module Language.Haskell.Liquid.RefSplit (-- splitXRelatedRefs-- ) where--import Control.Applicative-import Data.List (partition)-import Text.PrettyPrint.HughesPJ--import Language.Haskell.Liquid.Types-import Language.Haskell.Liquid.PrettyPrint ()--import Language.Fixpoint.Types-import Language.Fixpoint.Misc--splitXRelatedRefs :: Symbol -> SpecType -> (SpecType, SpecType)-splitXRelatedRefs x t = splitRType x t----splitRType f (RVar a r) = (RVar a r1, RVar a r2)- where- (r1, r2) = splitRef f r--splitRType f (RFun x tx t r) = (RFun x tx1 t1 r1, RFun x tx2 t2 r2)- where- (tx1, tx2) = splitRType f tx- (t1, t2) = splitRType f t- (r1, r2) = splitRef f r--splitRType f (RAllT v t) = (RAllT v t1, RAllT v t2)- where- (t1, t2) = splitRType f t--splitRType f (RAllP p t) = (RAllP p t1, RAllP p t2)- where- (t1, t2) = splitRType f t--splitRType f (RAllS s t) = (RAllS s t1, RAllS s t2)- where- (t1, t2) = splitRType f t---splitRType f (RApp c ts rs r) = (RApp c ts1 rs1 r1, RApp c ts2 rs2 r2)- where- (ts1, ts2) = unzip (splitRType f <$> ts)- (rs1, rs2) = unzip (splitUReft f <$> rs)- (r1, r2) = splitRef f r--splitRType f (RAllE x tx t) = (RAllE x tx1 t1, RAllE x tx2 t2)- where- (tx1, tx2) = splitRType f tx- (t1, t2) = splitRType f t--splitRType f (REx x tx t) = (REx x tx1 t1, REx x tx2 t2)- where- (tx1, tx2) = splitRType f tx- (t1, t2) = splitRType f t--splitRType _ (RExprArg e) = (RExprArg e, RExprArg e)--splitRType f (RAppTy tx t r) = (RAppTy tx1 t1 r1, RAppTy tx2 t2 r2)- where- (tx1, tx2) = splitRType f tx- (t1, t2) = splitRType f t- (r1, r2) = splitRef f r--splitRType f (RRTy xs r o t) = (RRTy xs1 r1 o t1, RRTy xs2 r2 o t2)- where- (xs1, xs2) = unzip (go <$> xs)- (r1, r2) = splitRef f r- (t1, t2) = splitRType f t-- go (x, t) = let (t1, t2) = splitRType f t in ((x,t1), (x, t2))---splitRType f (RHole r) = (RHole r1, RHole r2)- where- (r1, r2) = splitRef f r--splitUReft :: Symbol -> RTProp c tv (UReft Reft) -> (RTProp c tv (UReft Reft), RTProp c tv (UReft Reft))-splitUReft x (RPropP xs r) = (RPropP xs r1, RPropP xs r2)- where- (r1, r2) = splitRef x r--splitUReft x (RProp xs t) = (RProp xs t1, RProp xs t2)- where- (t1, t2) = splitRType x t--splitUReft _ (RHProp xs _) = (RHProp xs w1, RHProp xs w2)- where- (w1, w2) = error "TODO: RefSplit.splitUReft"--splitRef f (U r p s) = (U r1 p1 s, U r2 p2 s)- where- (r1, r2) = splitReft f r- (p1, p2) = splitPred f p--splitReft f (Reft (v, Refa xs)) = (Reft (v, Refa $ pAnd xs1), Reft (v, Refa $ pAnd xs2))- where- (xs1, xs2) = partition (isFree f) (unPAnd xs)-- unPAnd (PAnd ps) = concatMap unPAnd ps- unPAnd p = [p]--splitPred f (Pr ps) = (Pr ps1, Pr ps2)- where- (ps1, ps2) = partition g ps- g p = any (isFree f) (thd3 <$> pargs p)---class IsFree a where- isFree :: Symbol -> a -> Bool--instance (Subable x) => (IsFree x) where- isFree x p = x `elem` syms p--instance Show (UReft Reft) where- show = render . pprint
− src/Language/Haskell/Liquid/RefType.hs
@@ -1,1143 +0,0 @@-{-# LANGUAGE IncoherentInstances #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE NoMonomorphismRestriction #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE UndecidableInstances #-}-{-# LANGUAGE TypeSynonymInstances #-}-{-# LANGUAGE TupleSections #-}-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE GADTs #-}-{-# LANGUAGE PatternGuards #-}---- | Refinement Types. Mostly mirroring the GHC Type definition, but with--- room for refinements of various sorts.---- TODO: Desperately needs re-organization.-module Language.Haskell.Liquid.RefType (-- -- * Functions for lifting Reft-values to Spec-values- uTop, uReft, uRType, uRType', uRTypeGen, uPVar-- -- * Applying a solution to a SpecType- , applySolution-- -- * Functions for decreasing arguments- , isDecreasing, makeDecrType, makeNumEnv- , makeLexRefa-- -- * Functions for manipulating `Predicate`s- , pdVar- , findPVar- , freeTyVars, tyClasses, tyConName-- -- TODO: categorize these!- , ofType, toType- , rTyVar, rVar, rApp, rEx- , symbolRTyVar- , addTyConInfo- -- , expandRApp- , appRTyCon- , typeSort, typeUniqueSymbol- , strengthen- , generalize, normalizePds- , subts, subvPredicate, subvUReft- , subsTyVar_meet, subsTyVars_meet, subsTyVar_nomeet, subsTyVars_nomeet- , dataConSymbol, dataConMsReft, dataConReft- , classBinds-- , isSizeable-- -- * Manipulating Refinements in RTypes- , rTypeSortedReft- , rTypeSort- , shiftVV-- , mkDataConIdsTy- , mkTyConInfo--- , strengthenRefTypeGen- , strengthenDataConType-- ) where--import WwLib-import FamInstEnv (emptyFamInstEnv)-import Var-import GHC hiding (Located)-import DataCon-import qualified TyCon as TC-import TypeRep hiding (maybeParen, pprArrowChain)-import Type (splitFunTys, expandTypeSynonyms, substTyWith, isClassPred)-import TysWiredIn (listTyCon, intDataCon, trueDataCon, falseDataCon,- intTyCon, charTyCon)--import Data.Monoid hiding ((<>))-import Data.Maybe (fromMaybe, isJust)-import Data.Hashable-import qualified Data.HashMap.Strict as M-import qualified Data.HashSet as S-import qualified Data.List as L-import Control.Applicative hiding (empty)-import Control.DeepSeq-import Control.Monad (void)-import Text.Printf-import Text.PrettyPrint.HughesPJ--import Language.Haskell.Liquid.PrettyPrint-import qualified Language.Fixpoint.Types as F-import Language.Fixpoint.Types hiding (shiftVV, Predicate)-import Language.Fixpoint.Visitor (mapKVars)-import Language.Haskell.Liquid.Types hiding (R, DataConP (..), sort)--import Language.Haskell.Liquid.Variance--import Language.Haskell.Liquid.Misc-import Language.Haskell.Liquid.Names-import Language.Fixpoint.Misc-import Language.Haskell.Liquid.GhcMisc (typeUniqueString, tvId, showPpr, stringTyVar, tyConTyVarsDef)-import Language.Fixpoint.Names (listConName, tupConName)-import Data.List (sort, foldl')---strengthenDataConType (x, t) = (x, fromRTypeRep trep{ty_res = tres})- where- trep = toRTypeRep t- tres = ty_res trep `strengthen` U (exprReft expr) mempty mempty- xs = ty_binds trep- as = ty_vars trep- x' = symbol x- expr | null xs && null as = EVar x'- | null xs = EApp (dummyLoc x') []- | otherwise = EApp (dummyLoc x') (EVar <$> xs)--pdVar v = Pr [uPVar v]--findPVar :: [PVar (RType c tv ())] -> UsedPVar -> PVar (RType c tv ())-findPVar ps p- = PV name ty v (zipWith (\(_, _, e) (t, s, _) -> (t, s, e)) (pargs p) args)- where PV name ty v args = fromMaybe (msg p) $ L.find ((== pname p) . pname) ps- msg p = errorstar $ "RefType.findPVar" ++ showpp p ++ "not found"---- | Various functions for converting vanilla `Reft` to `Spec`--uRType :: RType c tv a -> RType c tv (UReft a)-uRType = fmap uTop--uRType' :: RType c tv (UReft a) -> RType c tv a-uRType' = fmap ur_reft--uRTypeGen :: Reftable b => RType c tv a -> RType c tv b-uRTypeGen = fmap $ const mempty--uPVar :: PVar t -> UsedPVar-uPVar = void--uReft :: (Symbol, Refa) -> UReft Reft-uReft = uTop . Reft--uTop :: r -> UReft r-uTop r = U r mempty mempty------------------------------------------------------------------------------------- (Class) Predicates for Valid Refinement Types -------------------------------------------------------------------------------- Monoid Instances ------------------------------------------------------------instance ( SubsTy tv (RType c tv ()) (RType c tv ())- , SubsTy tv (RType c tv ()) c- , RefTypable c tv ()- , RefTypable c tv r- , PPrint (RType c tv r)- , FreeVar c tv- )- => Monoid (RType c tv r) where- mempty = errorstar "mempty: RType"- mappend = strengthenRefType---- MOVE TO TYPES-instance ( SubsTy tv (RType c tv ()) (RType c tv ())- , SubsTy tv (RType c tv ()) c- , Reftable r- , RefTypable c tv ()- , RefTypable c tv (UReft r))- => Monoid (Ref (RType c tv ()) r (RType c tv (UReft r))) where- mempty = errorstar "mempty: RType 2"- mappend _ _ = errorstar "mappend: RType 2"--instance (SubsTy c (RType b c ()) b, Monoid r, Reftable r, RefTypable b c r, RefTypable b c (), FreeVar b c, SubsTy c (RType b c ()) (RType b c ()))- => Monoid (RTProp b c r) where- mempty = errorstar "mempty: RTProp"-- mappend (RPropP s1 r1) (RPropP s2 r2)- | isTauto r1 = RPropP s2 r2- | isTauto r2 = RPropP s1 r1- | otherwise = RPropP s1 $ r1 `meet`- (subst (mkSubst $ zip (fst <$> s2) (EVar . fst <$> s1)) r2)-- mappend (RProp s1 t1) (RProp s2 t2)- | isTrivial t1 = RProp s2 t2- | isTrivial t2 = RProp s1 t1- | otherwise = RProp s1 $ t1 `strengthenRefType`- (subst (mkSubst $ zip (fst <$> s2) (EVar . fst <$> s1)) t2)---- mappend (RPropP s1 t1) (RProp s2 t2) = errorstar "Reftable.mappend on invalid inputs"- mappend t1 t2 = errorstar ("Reftable.mappend on invalid inputs" ++ show (t1, t2))--- mappend _ _ = errorstar "Reftable.mappend on invalid inputs"--instance (Reftable r, RefTypable c tv r, RefTypable c tv (), FreeVar c tv, SubsTy tv (RType c tv ()) (RType c tv ()), SubsTy tv (RType c tv ()) c)- => Reftable (RTProp c tv r) where- isTauto (RPropP _ r) = isTauto r- isTauto (RProp _ t) = isTrivial t- isTauto (RHProp _ _) = errorstar "RefType: Reftable isTauto in RHProp"- top (RProp xs t) = RProp xs $ mapReft top t- top _ = errorstar "RefType: Reftable top"- ppTy (RPropP _ r) d = ppTy r d- ppTy (RProp _ _) _ = errorstar "RefType: Reftable ppTy in RProp"- ppTy (RHProp _ _) _ = errorstar "RefType: Reftable ppTy in RProp"- toReft = errorstar "RefType: Reftable toReft"- params = errorstar "RefType: Reftable params for Ref"- bot = errorstar "RefType: Reftable bot for Ref"- ofReft = errorstar "RefType: Reftable ofReft for Ref"---------------------------------------------------------------------------------- | Subable Instances ------------------------------------------------------------------------------------------------------------------------------------instance Subable (RRProp Reft) where- syms (RPropP ss r) = (fst <$> ss) ++ syms r- syms (RProp ss t) = (fst <$> ss) ++ syms t- syms _ = error "TODO:EFFECTS"-- subst su (RPropP ss r) = RPropP (mapSnd (subst su) <$> ss) $ subst su r- subst su (RProp ss r) = RProp (mapSnd (subst su) <$> ss) $ subst su r- subst _ _ = error "TODO:EFFECTS"-- substf f (RPropP ss r) = RPropP (mapSnd (substf f) <$> ss) $ substf f r- substf f (RProp ss r) = RProp (mapSnd (substf f) <$> ss) $ substf f r- substf _ _ = error "TODO:EFFECTS"- substa f (RPropP ss r) = RPropP (mapSnd (substa f) <$> ss) $ substa f r- substa f (RProp ss r) = RProp (mapSnd (substa f) <$> ss) $ substa f r- substa _ _ = error "TODO:EFFECTS"------------------------------------------------------------------------------------ | Reftable Instances -----------------------------------------------------------------------------------------------------------------------------------------instance (PPrint r, Reftable r) => Reftable (RType RTyCon RTyVar r) where- isTauto = isTrivial- ppTy = errorstar "ppTy RProp Reftable"- toReft = errorstar "toReft on RType"- params = errorstar "params on RType"- bot = errorstar "bot on RType"- ofReft = errorstar "ofReft on RType"-------------------------------------------------------------------------------------- | RefTypable Instances ----------------------------------------------------------------------------------------------------------------------------------------- MOVE TO TYPES-instance Fixpoint String where- toFix = text---- MOVE TO TYPES-instance Fixpoint Class where- toFix = text . showPpr---- MOVE TO TYPES-instance (SubsTy Symbol (RType c Symbol ()) c, TyConable c, Reftable r, PPrint r, PPrint c, FreeVar c Symbol, SubsTy Symbol (RType c Symbol ()) (RType c Symbol ())) => RefTypable c Symbol r where--- ppCls = ppClassSymbol- ppRType = ppr_rtype ppEnv---- MOVE TO TYPES-instance (Reftable r, PPrint r) => RefTypable RTyCon RTyVar r where--- ppCls = ppClassClassPred- ppRType = ppr_rtype ppEnv---- MOVE TO TYPES-class FreeVar a v where- freeVars :: a -> [v]---- MOVE TO TYPES-instance FreeVar RTyCon RTyVar where- freeVars = (RTV <$>) . tyConTyVarsDef . rtc_tc---- MOVE TO TYPES-instance FreeVar LocSymbol Symbol where- freeVars _ = []----- Eq Instances ---------------------------------------------------------- MOVE TO TYPES-instance (RefTypable c tv ()) => Eq (RType c tv ()) where- (==) = eqRSort M.empty--eqRSort m (RAllP _ t) (RAllP _ t')- = eqRSort m t t'-eqRSort m (RAllS _ t) (RAllS _ t')- = eqRSort m t t'-eqRSort m (RAllP _ t) t'- = eqRSort m t t'-eqRSort m (RAllT a t) (RAllT a' t')- | a == a'- = eqRSort m t t'- | otherwise- = eqRSort (M.insert a' a m) t t'-eqRSort m (RAllT _ t) t'- = eqRSort m t t'-eqRSort m t (RAllT _ t')- = eqRSort m t t'-eqRSort m (RFun _ t1 t2 _) (RFun _ t1' t2' _)- = eqRSort m t1 t1' && eqRSort m t2 t2'-eqRSort m (RAppTy t1 t2 _) (RAppTy t1' t2' _)- = eqRSort m t1 t1' && eqRSort m t2 t2'-eqRSort m (RApp c ts _ _) (RApp c' ts' _ _)- = c == c' && length ts == length ts' && and (zipWith (eqRSort m) ts ts')-eqRSort m (RVar a _) (RVar a' _)- = a == M.lookupDefault a' a' m-eqRSort _ (RHole _) _- = True-eqRSort _ _ (RHole _)- = True-eqRSort _ _ _- = False------------------------------------------------------------------------- | Wrappers for GHC Type Elements -------------------------------------------------------------------------------------------------------instance Eq Predicate where- (==) = eqpd--eqpd (Pr vs) (Pr ws)- = and $ (length vs' == length ws') : [v == w | (v, w) <- zip vs' ws']- where vs' = sort vs- ws' = sort ws---instance Eq RTyVar where- RTV α == RTV α' = tvId α == tvId α'--instance Ord RTyVar where- compare (RTV α) (RTV α') = compare (tvId α) (tvId α')--instance Hashable RTyVar where- hashWithSalt i (RTV α) = hashWithSalt i α--instance Ord RTyCon where- compare x y = compare (rtc_tc x) (rtc_tc y)--instance Hashable RTyCon where- hashWithSalt i = hashWithSalt i . rtc_tc--------------------------------------------------------------------------------------------- Helper Functions ---------------------------------------------------------------------------------------------------rVar = (`RVar` mempty) . RTV-rTyVar = RTV--symbolRTyVar = rTyVar . stringTyVar . symbolString--normalizePds t = addPds ps t'- where (t', ps) = nlzP [] t--rPred = RAllP-rEx xts t = foldr (\(x, tx) t -> REx x tx t) t xts-rApp c = RApp (RTyCon c [] (mkTyConInfo c [] [] Nothing))----- NV TODO : remove this code!!!--addPds ps (RAllT v t) = RAllT v $ addPds ps t-addPds ps t = foldl' (flip rPred) t ps--nlzP ps t@(RVar _ _ )- = (t, ps)-nlzP ps (RFun b t1 t2 r)- = (RFun b t1' t2' r, ps ++ ps1 ++ ps2)- where (t1', ps1) = nlzP [] t1- (t2', ps2) = nlzP [] t2-nlzP ps (RAppTy t1 t2 r)- = (RAppTy t1' t2' r, ps ++ ps1 ++ ps2)- where (t1', ps1) = nlzP [] t1- (t2', ps2) = nlzP [] t2-nlzP ps (RAllT v t )- = (RAllT v t', ps ++ ps')- where (t', ps') = nlzP [] t-nlzP ps t@(RApp _ _ _ _)- = (t, ps)-nlzP ps (RAllS _ t)- = (t, ps)-nlzP ps (RAllP p t)- = (t', [p] ++ ps ++ ps')- where (t', ps') = nlzP [] t-nlzP ps t@(REx _ _ _)- = (t, ps)-nlzP ps t@(RRTy _ _ _ t')- = (t, ps ++ ps')- where ps' = snd $ nlzP [] t'-nlzP ps t@(RAllE _ _ _)- = (t, ps)-nlzP _ t- = errorstar $ "RefType.nlzP: cannot handle " ++ show t---strengthenRefTypeGen, strengthenRefType ::- ( RefTypable c tv ()- , RefTypable c tv r- , PPrint (RType c tv r)- , FreeVar c tv- , SubsTy tv (RType c tv ()) (RType c tv ())- , SubsTy tv (RType c tv ()) c- ) => RType c tv r -> RType c tv r -> RType c tv r-strengthenRefType_ ::- ( RefTypable c tv ()- , RefTypable c tv r- , PPrint (RType c tv r)- , FreeVar c tv- , SubsTy tv (RType c tv ()) (RType c tv ())- , SubsTy tv (RType c tv ()) c- ) => (RType c tv r -> RType c tv r -> RType c tv r)- -> RType c tv r -> RType c tv r -> RType c tv r--strengthenRefTypeGen t1 t2 = strengthenRefType_ f t1 t2- where- f (RVar v1 r1) t = RVar v1 (r1 `meet` fromMaybe mempty (stripRTypeBase t))- f t (RVar v1 r1) = RVar v1 (r1 `meet` fromMaybe mempty (stripRTypeBase t))- f t1 t2 = error $ printf "strengthenRefTypeGen on differently shaped types \nt1 = %s [shape = %s]\nt2 = %s [shape = %s]"- (showpp t1) (showpp (toRSort t1)) (showpp t2) (showpp (toRSort t2))----- NEWISH: with unifying type variables: causes big problems with TUPLES?---strengthenRefType t1 t2 = maybe (errorstar msg) (strengthenRefType_ t1) (unifyShape t1 t2)--- where msg = printf "strengthen on differently shaped reftypes \nt1 = %s [shape = %s]\nt2 = %s [shape = %s]"--- (render t1) (render (toRSort t1)) (render t2) (render (toRSort t2))---- OLD: without unifying type variables, but checking α-equivalence-strengthenRefType t1 t2- | eqt t1 t2- = strengthenRefType_ (\x _ -> x) t1 t2- | otherwise- = errorstar msg- where- eqt t1 t2 = {- render -} toRSort t1 == {- render -} toRSort t2- msg = printf "strengthen on differently shaped reftypes \nt1 = %s [shape = %s]\nt2 = %s [shape = %s]"- (showpp t1) (showpp (toRSort t1)) (showpp t2) (showpp (toRSort t2))---strengthenRefType_ f (RAllT a1 t1) (RAllT a2 t2)- = RAllT a1 $ strengthenRefType_ f t1 (subsTyVar_meet (a2, toRSort t, t) t2)- where t = RVar a1 mempty--strengthenRefType_ f (RAllT a t1) t2- = RAllT a $ strengthenRefType_ f t1 t2--strengthenRefType_ f t1 (RAllT a t2)- = RAllT a $ strengthenRefType_ f t1 t2--strengthenRefType_ f (RAllP p1 t1) (RAllP _ t2)- = RAllP p1 $ strengthenRefType_ f t1 t2--strengthenRefType_ f (RAllP p t1) t2- = RAllP p $ strengthenRefType_ f t1 t2--strengthenRefType_ f t1 (RAllP p t2)- = RAllP p $ strengthenRefType_ f t1 t2--strengthenRefType_ f (RAllS s t1) t2- = RAllS s $ strengthenRefType_ f t1 t2--strengthenRefType_ f t1 (RAllS s t2)- = RAllS s $ strengthenRefType_ f t1 t2--strengthenRefType_ f (RAllE x tx t1) (RAllE y ty t2) | x == y- = RAllE x (strengthenRefType_ f tx ty) $ strengthenRefType_ f t1 t2--strengthenRefType_ f (RAllE x tx t1) t2- = RAllE x tx $ strengthenRefType_ f t1 t2--strengthenRefType_ f t1 (RAllE x tx t2)- = RAllE x tx $ strengthenRefType_ f t1 t2--strengthenRefType_ f (RAppTy t1 t1' r1) (RAppTy t2 t2' r2)- = RAppTy t t' (r1 `meet` r2)- where t = strengthenRefType_ f t1 t2- t' = strengthenRefType_ f t1' t2'--strengthenRefType_ f (RFun x1 t1 t1' r1) (RFun x2 t2 t2' r2)- = RFun x2 t t' (r1 `meet` r2)- where t = strengthenRefType_ f t1 t2- t' = strengthenRefType_ f (subst1 t1' (x1, EVar x2)) t2'--strengthenRefType_ f (RApp tid t1s rs1 r1) (RApp _ t2s rs2 r2)- = RApp tid ts rs (r1 `meet` r2)- where ts = zipWith (strengthenRefType_ f) t1s t2s- rs = meets rs1 rs2---strengthenRefType_ _ (RVar v1 r1) (RVar v2 r2) | v1 == v2- = RVar v1 (r1 `meet` r2)-strengthenRefType_ f t1 t2- = f t1 t2--meets :: (F.Reftable r) => [r] -> [r] -> [r]-meets [] rs = rs-meets rs [] = rs-meets rs rs'- | length rs == length rs' = zipWith meet rs rs'- | otherwise = errorstar "meets: unbalanced rs"---strengthen :: Reftable r => RType c tv r -> r -> RType c tv r-strengthen (RApp c ts rs r) r' = RApp c ts rs (r `meet` r')-strengthen (RVar a r) r' = RVar a (r `meet` r')-strengthen (RFun b t1 t2 r) r' = RFun b t1 t2 (r `meet` r')-strengthen (RAppTy t1 t2 r) r' = RAppTy t1 t2 (r `meet` r')-strengthen t _ = t------------------------------------------------------------------------------addTyConInfo :: (PPrint r, Reftable r)- => (M.HashMap TyCon FTycon)- -> (M.HashMap TyCon RTyCon)- -> RRType r- -> RRType r---------------------------------------------------------------------------addTyConInfo tce tyi = mapBot (expandRApp tce tyi)----------------------------------------------------------------------------expandRApp :: (PPrint r, Reftable r)- => (M.HashMap TyCon FTycon)- -> (M.HashMap TyCon RTyCon)- -> RRType r- -> RRType r---------------------------------------------------------------------------expandRApp tce tyi t@(RApp {}) = RApp rc' ts rs' r- where- RApp rc ts rs r = t- rc' = appRTyCon tce tyi rc as- pvs = rTyConPVs rc'- rs' = applyNonNull rs0 (rtPropPV rc pvs) rs- rs0 = rtPropTop <$> pvs- n = length fVs- fVs = tyConTyVarsDef $ rtc_tc rc- as = choosen n ts (rVar <$> fVs)-- choosen 0 _ _ = []- choosen i (x:xs) (_:ys) = x:choosen (i-1) xs ys- choosen i [] (y:ys) = y:choosen (i-1) [] ys- choosen _ _ _ = errorstar "choosen: this cannot happen"--expandRApp _ _ t = t--rtPropTop pv = case ptype pv of- PVProp t -> RProp xts $ ofRSort t- PVHProp -> RProp xts $ mempty- where- xts = pvArgs pv--rtPropPV rc = safeZipWith msg mkRTProp- where- msg = "appRefts: " ++ showFix rc--mkRTProp pv (RPropP ss r)- = RProp ss $ (ofRSort $ pvType pv) `strengthen` r--mkRTProp pv (RProp ss t)- | length (pargs pv) == length ss- = RProp ss t- | otherwise- = RProp (pvArgs pv) t--mkRTProp pv (RHProp ss w)- | length (pargs pv) == length ss- = RHProp ss w- | otherwise- = RHProp (pvArgs pv) w--pvArgs pv = [(s, t) | (t, s, _) <- pargs pv]---appRTyCon tce tyi rc ts = RTyCon c ps' (rtc_info rc'')- where- c = rtc_tc rc- ps' = subts (zip (RTV <$> αs) ts') <$> rTyConPVs rc'- ts' = if null ts then rVar <$> βs else toRSort <$> ts- rc' = M.lookupDefault rc c tyi- αs = tyConTyVarsDef $ rtc_tc rc'- βs = tyConTyVarsDef c- rc'' = if isNumeric tce rc' then addNumSizeFun rc' else rc'----- RJ: The code of `isNumeric` is incomprehensible.--- Please fix it to use intSort instead of intFTyCon-isNumeric tce c- = fromMaybe- (symbolFTycon . dummyLoc $ tyConName (rtc_tc c))- (M.lookup (rtc_tc c) tce) == F.intFTyCon--addNumSizeFun c- = c {rtc_info = (rtc_info c) {sizeFunction = Just EVar} }---generalize :: (RefTypable c tv r) => RType c tv r -> RType c tv r-generalize t = mkUnivs (freeTyVars t) [] [] t--freeTyVars (RAllP _ t) = freeTyVars t-freeTyVars (RAllS _ t) = freeTyVars t-freeTyVars (RAllT α t) = freeTyVars t L.\\ [α]-freeTyVars (RFun _ t t' _) = freeTyVars t `L.union` freeTyVars t'-freeTyVars (RApp _ ts _ _) = L.nub $ concatMap freeTyVars ts-freeTyVars (RVar α _) = [α]-freeTyVars (RAllE _ tx t) = freeTyVars tx `L.union` freeTyVars t-freeTyVars (REx _ tx t) = freeTyVars tx `L.union` freeTyVars t-freeTyVars (RExprArg _) = []-freeTyVars (RAppTy t t' _) = freeTyVars t `L.union` freeTyVars t'-freeTyVars (RHole _) = []-freeTyVars (RRTy e _ _ t) = L.nub $ concatMap freeTyVars (t:(snd <$> e))---tyClasses (RAllP _ t) = tyClasses t-tyClasses (RAllS _ t) = tyClasses t-tyClasses (RAllT _ t) = tyClasses t-tyClasses (RAllE _ _ t) = tyClasses t-tyClasses (REx _ _ t) = tyClasses t-tyClasses (RFun _ t t' _) = tyClasses t ++ tyClasses t'-tyClasses (RAppTy t t' _) = tyClasses t ++ tyClasses t'-tyClasses (RApp c ts _ _)- | Just cl <- tyConClass_maybe $ rtc_tc c- = [(cl, ts)]- | otherwise- = []-tyClasses (RVar _ _) = []-tyClasses (RRTy _ _ _ t) = tyClasses t-tyClasses (RHole _) = []-tyClasses t = errorstar ("RefType.tyClasses cannot handle" ++ show t)------------------------------------------------------------------------------------------ Strictness -------------------------------------------------------------------------------------------------instance (NFData a, NFData b, NFData t) => NFData (Ref t a b) where- rnf (RPropP s a) = rnf s `seq` rnf a- rnf (RProp s b) = rnf s `seq` rnf b- rnf (RHProp _ _) = errorstar "TODO RHProp.rnf"--instance (NFData b, NFData c, NFData e) => NFData (RType b c e) where- rnf (RVar α r) = rnf α `seq` rnf r- rnf (RAllT α t) = rnf α `seq` rnf t- rnf (RAllP π t) = rnf π `seq` rnf t- rnf (RAllS s t) = rnf s `seq` rnf t- rnf (RFun x t t' r) = rnf x `seq` rnf t `seq` rnf t' `seq` rnf r- rnf (RApp _ ts rs r) = rnf ts `seq` rnf rs `seq` rnf r- rnf (RAllE x t t') = rnf x `seq` rnf t `seq` rnf t'- rnf (REx x t t') = rnf x `seq` rnf t `seq` rnf t'- rnf (RExprArg e) = rnf e- rnf (RAppTy t t' r) = rnf t `seq` rnf t' `seq` rnf r- rnf (RRTy _ r _ t) = rnf r `seq` rnf t- rnf (RHole r) = rnf r------------------------------------------------------------------------------------- Printing Refinement Types --------------------------------------------------------------------------------------instance Show RTyVar where- show = showpp--instance PPrint (UReft r) => Show (UReft r) where- show = showpp--instance (RefTypable c tv r) => PPrint (RType c tv r) where- pprint = ppRType TopPrec--instance PPrint (RType c tv r) => Show (RType c tv r) where- show = showpp--instance PPrint (RTProp c tv r) => Show (RTProp c tv r) where- show = showpp--instance PPrint REnv where- pprint (REnv m) = pprint m----------------------------------------------------------------------------------------------- TODO: Rewrite subsTyvars with Traversable---------------------------------------------------------------------------------------------subsTyVars_meet = subsTyVars True-subsTyVars_nomeet = subsTyVars False-subsTyVar_nomeet = subsTyVar False-subsTyVar_meet = subsTyVar True-subsTyVars meet ats t = foldl' (flip (subsTyVar meet)) t ats-subsTyVar meet = subsFree meet S.empty--subsFree m s z (RAllS l t)- = RAllS l (subsFree m s z t)-subsFree m s z@(α, τ,_) (RAllP π t)- = RAllP (subt (α, τ) π) (subsFree m s z t)-subsFree m s z (RAllT α t)- = RAllT α $ subsFree m (α `S.insert` s) z t-subsFree m s z@(_, _, _) (RFun x t t' r)- = RFun x (subsFree m s z t) (subsFree m s z t') r-subsFree m s z@(α, τ, _) (RApp c ts rs r)- = RApp (subt z' c) (subsFree m s z <$> ts) (subsFreeRef m s z <$> rs) r- where z' = (α, τ) -- UNIFY: why instantiating INSIDE parameters?-subsFree meet s (α', _, t') t@(RVar α r)- | α == α' && not (α `S.member` s)- = if meet then t' `strengthen` r else t'- | otherwise- = t-subsFree m s z (RAllE x t t')- = RAllE x (subsFree m s z t) (subsFree m s z t')-subsFree m s z (REx x t t')- = REx x (subsFree m s z t) (subsFree m s z t')-subsFree m s z@(_, _, _) (RAppTy t t' r)- = subsFreeRAppTy m s (subsFree m s z t) (subsFree m s z t') r-subsFree _ _ _ t@(RExprArg _)- = t-subsFree m s z (RRTy e r o t)- = RRTy (mapSnd (subsFree m s z) <$> e) r o (subsFree m s z t)-subsFree _ _ _ t@(RHole _)- = t--subsFrees m s zs t = foldl' (flip(subsFree m s)) t zs---- GHC INVARIANT: RApp is Type Application to something other than TYCon-subsFreeRAppTy m s (RApp c ts rs r) t' r'- = mkRApp m s c (ts ++ [t']) rs r r'-subsFreeRAppTy _ _ t t' r'- = RAppTy t t' r'--mkRApp m s c ts rs r r'- | isFun c, [t1, t2] <- ts- = RFun dummySymbol t1 t2 $ refAppTyToFun r'- | otherwise- = subsFrees m s zs $ RApp c ts rs $ r `meet` r' -- (refAppTyToApp r')- where- zs = [(tv, toRSort t, t) | (tv, t) <- zip (freeVars c) ts]--refAppTyToFun r- | isTauto r = r- | otherwise = errorstar "RefType.refAppTyToFun"--subsFreeRef m s (α', τ', t') (RProp ss t)- = RProp (mapSnd (subt (α', τ')) <$> ss) $ subsFree m s (α', τ', fmap top t') t-subsFreeRef _ _ (α', τ', _) (RPropP ss r)- = RPropP (mapSnd (subt (α', τ')) <$> ss) r-subsFreeRef _ _ _ (RHProp _ _)- = errorstar "TODO RHProp.subsFreeRef"----------------------------------------------------------------------------------------- Type Substitutions --------------------------------------------------------------------------------------------------subts = flip (foldr subt)--instance SubsTy tv ty () where- subt _ = id--instance SubsTy tv ty Reft where- subt _ = id--instance (SubsTy tv ty ty) => SubsTy tv ty (PVKind ty) where- subt su (PVProp t) = PVProp (subt su t)- subt _ PVHProp = PVHProp--instance (SubsTy tv ty ty) => SubsTy tv ty (PVar ty) where- subt su (PV n t v xts) = PV n (subt su t) v [(subt su t, x, y) | (t,x,y) <- xts]--instance SubsTy RTyVar RSort RTyCon where- subt z c = RTyCon tc ps' i- where- tc = rtc_tc c- ps' = subt z <$> rTyConPVs c- i = rtc_info c---- NOTE: This DOES NOT substitute at the binders-instance SubsTy RTyVar RSort PrType where- subt (α, τ) = subsTyVar_meet (α, τ, ofRSort τ)--instance SubsTy RTyVar RSort SpecType where- subt (α, τ) = subsTyVar_meet (α, τ, ofRSort τ)--instance SubsTy RTyVar RTyVar SpecType where- subt (α, a) = subt (α, RVar a () :: RSort)---instance SubsTy RTyVar RSort RSort where- subt (α, τ) = subsTyVar_meet (α, τ, ofRSort τ)---- Here the "String" is a Bare-TyCon. TODO: wrap in newtype-instance SubsTy Symbol BSort LocSymbol where- subt _ t = t--instance SubsTy Symbol BSort BSort where- subt (α, τ) = subsTyVar_meet (α, τ, ofRSort τ)--instance (SubsTy tv ty (UReft r), SubsTy tv ty (RType c tv ())) => SubsTy tv ty (RTProp c tv (UReft r)) where- subt m (RPropP ss p) = RPropP ((mapSnd (subt m)) <$> ss) $ subt m p- subt m (RProp ss t) = RProp ((mapSnd (subt m)) <$> ss) $ fmap (subt m) t- subt _ (RHProp _ _) = errorstar "TODO: RHProp.subt"--subvUReft :: (UsedPVar -> UsedPVar) -> UReft Reft -> UReft Reft-subvUReft f (U r p s) = U r (subvPredicate f p) s--subvPredicate :: (UsedPVar -> UsedPVar) -> Predicate -> Predicate-subvPredicate f (Pr pvs) = Pr (f <$> pvs)-------------------------------------------------------------------ofType = ofType_ . expandTypeSynonyms--ofType_ (TyVarTy α)- = rVar α-ofType_ (FunTy τ τ')- = rFun dummySymbol (ofType_ τ) (ofType_ τ')-ofType_ (ForAllTy α τ)- = RAllT (rTyVar α) $ ofType_ τ-ofType_ (TyConApp c τs)- | Just (αs, τ) <- TC.synTyConDefn_maybe c- = ofType_ $ substTyWith αs τs τ- | otherwise- = rApp c (ofType_ <$> τs) [] mempty-ofType_ (AppTy t1 t2)- = RAppTy (ofType_ t1) (ofType t2) mempty-ofType_ (LitTy x)- = fromTyLit x- where- fromTyLit (NumTyLit _) = rApp intTyCon [] [] mempty- fromTyLit (StrTyLit _) = rApp listTyCon [rApp charTyCon [] [] mempty] [] mempty-------------------------------------------------------------------------------------- Converting to Fixpoint -----------------------------------------------------------------------------------------instance Expression Var where- expr = eVar--dataConSymbol :: DataCon -> Symbol-dataConSymbol = symbol . dataConWorkId---- TODO: turn this into a map lookup?-dataConReft :: DataCon -> [Symbol] -> Reft-dataConReft c []- | c == trueDataCon- = predReft $ eProp vv_- | c == falseDataCon- = predReft $ PNot $ eProp vv_--dataConReft c [x]- | c == intDataCon- = symbolReft x -- OLD (vv_, [RConc (PAtom Eq (EVar vv_) (EVar x))])-dataConReft c _- | not $ isBaseDataCon c- = mempty-dataConReft c xs- = exprReft dcValue -- OLD Reft (vv_, [RConc (PAtom Eq (EVar vv_) dcValue)])- where- dcValue- | null xs && null (dataConUnivTyVars c)- = EVar $ dataConSymbol c- | otherwise- = EApp (dummyLoc $ dataConSymbol c) (eVar <$> xs)--isBaseDataCon c = and $ isBaseTy <$> dataConOrigArgTys c ++ dataConRepArgTys c--isBaseTy (TyVarTy _) = True-isBaseTy (AppTy _ _) = False-isBaseTy (TyConApp _ ts) = and $ isBaseTy <$> ts-isBaseTy (FunTy _ _) = False-isBaseTy (ForAllTy _ _) = False-isBaseTy (LitTy _) = True---dataConMsReft ty ys = subst su (rTypeReft (ignoreOblig $ ty_res trep))- where- trep = toRTypeRep ty- xs = ty_binds trep- ts = ty_args trep- su = mkSubst $ [(x, EVar y) | ((x, _), y) <- zip (zip xs ts) ys]---------------------------------------------------------------------------------------- Embedding RefTypes ---------------------------------------------------------------------------------------- TODO: remove toType, generalize typeSort-toType :: (Reftable r, PPrint r) => RRType r -> Type-toType (RFun _ t t' _)- = FunTy (toType t) (toType t')-toType (RAllT (RTV α) t)- = ForAllTy α (toType t)-toType (RAllP _ t)- = toType t-toType (RAllS _ t)- = toType t-toType (RVar (RTV α) _)- = TyVarTy α-toType (RApp (RTyCon {rtc_tc = c}) ts _ _)- = TyConApp c (toType <$> filter notExprArg ts)- where- notExprArg (RExprArg _) = False- notExprArg _ = True-toType (RAllE _ _ t)- = toType t-toType (REx _ _ t)- = toType t-toType (RAppTy t (RExprArg _) _)- = toType t-toType (RAppTy t t' _)- = AppTy (toType t) (toType t')-toType t@(RExprArg _)- = errorstar $ "CANNOT HAPPEN: RefType.toType called with: " ++ show t-toType (RRTy _ _ _ t)- = toType t-toType t- = errorstar $ "RefType.toType cannot handle: " ++ show t----------------------------------------------------------------------------------- Annotations and Solutions --------------------------------------------------------------------------------------rTypeSortedReft :: (PPrint r, Reftable r) => TCEmb TyCon -> RRType r -> SortedReft-rTypeSortedReft emb t = RR (rTypeSort emb t) (rTypeReft t)--rTypeSort :: (PPrint r, Reftable r) => TCEmb TyCon -> RRType r -> Sort-rTypeSort tce = typeSort tce . toType----------------------------------------------------------------------------------applySolution :: (Functor f) => FixSolution -> f SpecType -> f SpecType---------------------------------------------------------------------------------applySolution = fmap . fmap . mapReft . appSolRefa- where- mapReft f (U (Reft (x, z)) p s) = U (Reft (x, f z)) p s--- OLD appSolRefa _ ra@(RConc _) = ra--- OLD appSolRefa s (RKvar k su) = RConc $ subst su $ M.lookupDefault PTop k s--appSolRefa s (Refa p) = Refa $ mapKVars f p- where- f k = Just $ M.lookupDefault PTop k s----------------------------------------------------------------------------------shiftVV :: SpecType -> Symbol -> SpecType----------------------------------------------------------------------------------shiftVV t@(RApp _ ts _ r) vv'- = t { rt_args = subst1 ts (rTypeValueVar t, EVar vv') }- { rt_reft = (`F.shiftVV` vv') <$> r }--shiftVV t@(RFun _ _ _ r) vv'- = t { rt_reft = (`F.shiftVV` vv') <$> r }--shiftVV t@(RAppTy _ _ r) vv'- = t { rt_reft = (`F.shiftVV` vv') <$> r }--shiftVV t@(RVar _ r) vv'- = t { rt_reft = (`F.shiftVV` vv') <$> r }--shiftVV t _- = t -- errorstar $ "shiftVV: cannot handle " ++ showpp t-------------------------------------------------------------------------------------------- Auxiliary Stuff Used Elsewhere ----------------------------------------------------------------------------------------------------- MOVE TO TYPES-instance (Show tv, Show ty) => Show (RTAlias tv ty) where- show (RTA n as xs t p _) =- printf "type %s %s %s = %s -- defined at %s" (symbolString n)- (L.intercalate " " (show <$> as))- (L.intercalate " " (show <$> xs))- (show t) (show p)------------------------------------------------------------------------------- From Old Fixpoint ----------------------------------------------------------------------------------------------------typeUniqueSymbol :: Type -> Symbol-typeUniqueSymbol = symbol . typeUniqueString--typeSort :: TCEmb TyCon -> Type -> Sort-typeSort tce τ@(ForAllTy _ _)- = typeSortForAll tce τ-typeSort tce t@(FunTy _ _)- = typeSortFun tce t-typeSort tce (TyConApp c τs)- = fApp (Left $ tyConFTyCon tce c) (typeSort tce <$> τs)-typeSort tce (AppTy t1 t2)- = fApp (Right $ typeSort tce t1) [typeSort tce t2]-typeSort _ τ- = FObj $ typeUniqueSymbol τ--tyConFTyCon tce c = fromMaybe (symbolFTycon $ dummyLoc $ tyConName c) (M.lookup c tce)--typeSortForAll tce τ- = genSort $ typeSort tce tbody- where genSort (FFunc _ t) = FFunc n (sortSubst su <$> t)- genSort t = FFunc n [sortSubst su t]- (as, tbody) = splitForAllTys τ- su = M.fromList $ zip sas (FVar <$> [0..])- sas = (typeUniqueSymbol . TyVarTy) <$> as- n = length as--tyConName c- | listTyCon == c = listConName- | TC.isTupleTyCon c = tupConName- | otherwise = symbol c--typeSortFun tce t -- τ1 τ2- = FFunc 0 sos- where sos = typeSort tce <$> τs- τs = grabArgs [] t-grabArgs τs (FunTy τ1 τ2 )- | not $ isClassPred τ1 = grabArgs (τ1:τs) τ2- | otherwise = grabArgs τs τ2-grabArgs τs τ = reverse (τ:τs)---mkDataConIdsTy (dc, t) = [expandProductType id t | id <- dataConImplicitIds dc]--expandProductType x t- | ofType (varType x) == toRSort t = (x, t)- | otherwise = (x, t')- where t' = fromRTypeRep $ trep {ty_binds = xs', ty_args = ts', ty_refts = rs'}- τs = fst $ splitFunTys $ toType t- trep = toRTypeRep t- (xs', ts', rs') = unzip3 $ concatMap mkProductTy $ zip4 τs (ty_binds trep) (ty_args trep) (ty_refts trep)--mkProductTy (τ, x, t, r) = maybe [(x, t, r)] f $ deepSplitProductType_maybe menv τ- where f = ((<$>) ((dummySymbol, , mempty) . ofType)) . third4- menv = (emptyFamInstEnv, emptyFamInstEnv)---------------------------------------------------------------------------------------------- | Binders generated by class predicates, typically for constraining tyvars (e.g. FNum)--------------------------------------------------------------------------------------------classBinds (RApp c ts _ _)- | isFracCls c- = [(rTyVarSymbol a, trueSortedReft FFrac) | (RVar a _) <- ts]- | isNumCls c- = [(rTyVarSymbol a, trueSortedReft FNum) | (RVar a _) <- ts]-classBinds _- = []--rTyVarSymbol (RTV α) = typeUniqueSymbol $ TyVarTy α----------------------------------------------------------------------------------------------------------------------- Termination Predicates ----------------------------------------------------------------------------------------------------------------------------------makeNumEnv = concatMap go- where- go (RApp c ts _ _) | isNumCls c || isFracCls c = [ a | (RVar a _) <- ts]- go _ = []--isDecreasing autoenv _ (RApp c _ _ _)- = isJust (sizeFunction (rtc_info c)) -- user specified size or- || isSizeable autoenv tc- where tc = rtc_tc c-isDecreasing _ cenv (RVar v _)- = v `elem` cenv-isDecreasing _ _ _- = False--makeDecrType autoenv = mkDType autoenv [] []--mkDType autoenv xvs acc [(v, (x, t))]- = (x, ) $ t `strengthen` tr- where- tr = uTop $ Reft (vv, Refa $ pOr (r:acc))- r = cmpLexRef xvs (v', vv, f)- v' = symbol v- f = mkDecrFun autoenv t- vv = "vvRec"--mkDType autoenv xvs acc ((v, (x, t)):vxts)- = mkDType autoenv ((v', x, f):xvs) (r:acc) vxts- where- r = cmpLexRef xvs (v', x, f)- v' = symbol v- f = mkDecrFun autoenv t---mkDType _ _ _ _- = errorstar "RefType.mkDType called on invalid input"--isSizeable :: S.HashSet TyCon -> TyCon -> Bool-isSizeable autoenv tc = S.member tc autoenv -- TC.isAlgTyCon tc -- && TC.isRecursiveTyCon tc--mkDecrFun autoenv (RApp c _ _ _)- | Just f <- sizeFunction $ rtc_info c- = f- | isSizeable autoenv $ rtc_tc c- = \v -> F.EApp lenLocSymbol [F.EVar v]-mkDecrFun _ (RVar _ _)- = EVar-mkDecrFun _ _- = errorstar "RefType.mkDecrFun called on invalid input"--cmpLexRef vxs (v, x, g)- = pAnd $ (PAtom Lt (g x) (g v)) : (PAtom Ge (g x) zero)- : [PAtom Eq (f y) (f z) | (y, z, f) <- vxs]- ++ [PAtom Ge (f y) zero | (y, _, f) <- vxs]- where zero = ECon $ I 0--makeLexRefa es' es = uTop $ Reft (vv, Refa $ PIff (PBexp $ EVar vv) $ pOr rs)- where- rs = makeLexReft [] [] es es'- vv = "vvRec"--makeLexReft _ acc [] []- = acc-makeLexReft old acc (e:es) (e':es')- = makeLexReft ((e,e'):old) (r:acc) es es'- where- r = pAnd $ (PAtom Lt e' e)- : (PAtom Ge e' zero)- : [PAtom Eq o' o | (o,o') <- old]- ++ [PAtom Ge o' zero | (_,o') <- old]- zero = ECon $ I 0-makeLexReft _ _ _ _- = errorstar "RefType.makeLexReft on invalid input"-----------------------------------------------------------------------------------mkTyConInfo :: TyCon -> VarianceInfo -> VarianceInfo -> (Maybe (Symbol -> Expr)) -> TyConInfo--mkTyConInfo c usertyvar userprvariance f- = TyConInfo (if null usertyvar then defaulttyvar else usertyvar) userprvariance f- where- defaulttyvar = varSignToVariance <$> [0 ..n]-- varSignToVariance i = case filter (\p -> fst p == i) varsigns of- [] -> Invariant- [(_, b)] -> if b then Covariant else Contravariant- _ -> Bivariant-- varsigns = L.nub $ concatMap goDCon $ TC.tyConDataCons c- initmap = zip (showPpr <$> tyvars) [0..n]- mkmap vs = zip (showPpr <$> vs) (repeat dindex) ++ initmap- goDCon dc = concatMap (go (mkmap (DataCon.dataConExTyVars dc)) True) (DataCon.dataConOrigArgTys dc)- go m pos (ForAllTy v t) = go ((showPpr v, dindex):m) pos t- go m pos (TyVarTy v) = [(varLookup (showPpr v) m, pos)]- go m pos (AppTy t1 t2) = go m pos t1 ++ go m pos t2- go m pos (TyConApp _ ts) = concatMap (go m pos) ts- go m pos (FunTy t1 t2) = go m (not pos) t1 ++ go m pos t2- go _ _ (LitTy _) = []-- varLookup v m = fromMaybe (errmsg v) $ L.lookup v m- tyvars = tyConTyVarsDef c- n = (TC.tyConArity c) - 1- errmsg v = error $ "GhcMisc.getTyConInfo: var not found" ++ showPpr v- dindex = -1
− src/Language/Haskell/Liquid/Simplify.hs
@@ -1,42 +0,0 @@-module Language.Haskell.Liquid.Simplify (simplifyBounds) where--import Language.Haskell.Liquid.Types-import Language.Fixpoint.Types-import Language.Fixpoint.Visitor--- import Control.Applicative ((<$>))-import Data.Monoid--simplifyBounds :: SpecType -> SpecType-simplifyBounds = fmap go- where- go x = x { ur_reft = go' $ ur_reft x }- -- OLD go' (Reft (v, rs)) = Reft(v, filter (not . isBoundLike) rs)- go' (Reft (v, Refa p)) = Reft(v, Refa $ dropBoundLike p)--dropBoundLike :: Pred -> Pred-dropBoundLike p- | isKvar p = p- | isBoundLikePred p = mempty- | otherwise = p- where- isKvar = not . null . kvars--isBoundLikePred :: Pred -> Bool-isBoundLikePred (PAnd ps) = simplifyLen <= length [p | p <- ps, isImp p ]-isBoundLikePred _ = False--isImp :: Pred -> Bool-isImp (PImp _ _) = True-isImp _ = False---- OLD isBoundLike (RConc pred) = isBoundLikePred pred--- OLD isBoundLike (RKvar _ _) = False----- OLD moreThan 0 _ = True--- OLD moreThan _ [] = False--- OLD moreThan i (True : xs) = moreThan (i-1) xs--- OLD moreThan i (False : xs) = moreThan i xs--simplifyLen :: Int-simplifyLen = 5
− src/Language/Haskell/Liquid/Strata.hs
@@ -1,70 +0,0 @@-{-# LANGUAGE TypeSynonymInstances #-}-{-# LANGUAGE FlexibleInstances #-}--module Language.Haskell.Liquid.Strata (- SubStratum(..)- , solveStrata- , (<:=)- ) where--import Control.Applicative ((<$>))--import Language.Fixpoint.Types (Symbol)-import Language.Haskell.Liquid.Types hiding (Def, Loc)--s1 <:= s2 - | any (==SDiv) s1 && any (==SFin) s2 = False- | otherwise = True--solveStrata = go True [] [] - where go False solved _ [] = solved- go True solved acc [] = go False solved [] $ {-traceShow ("OLD \n" ++ showMap solved acc ) $ -} subsS solved <$> acc- go mod solved acc (([], _):ls) = go mod solved acc ls- go mod solved acc ((_, []):ls) = go mod solved acc ls- go mod solved acc (l:ls) | allSVars l = go mod solved (l:acc) ls- | noSVar l = go mod solved acc ls - | noUpdate l = go mod solved (l:acc) ls - | otherwise = go True (solve l ++ solved) (l:acc) ls ---allSVars (xs, ys) = all isSVar $ xs ++ ys-noSVar (xs, ys) = all (not . isSVar) (xs ++ ys)-noUpdate (xs, ys) = (not $ updateFin(xs, ys)) && (not $ updateDiv (xs, ys)) --updateFin (xs, ys) = any (==SFin) ys && any isSVar xs-updateDiv (xs, ys) = any isSVar ys && any (==SDiv) xs--solve (xs, ys) - | any (== SDiv) xs = [(l, SDiv) | SVar l <- ys] - | any (== SFin) ys = [(l, SFin) | SVar l <- xs] - | otherwise = []---class SubStratum a where- subS :: (Symbol, Stratum) -> a -> a- subsS :: [(Symbol, Stratum)] -> a -> a-- subsS su x = foldr subS x su--instance SubStratum Stratum where- subS (x, s) (SVar y) | x == y = s- | otherwise = (SVar y)- subS _ s = s---instance (SubStratum a, SubStratum b) => SubStratum (a, b) where- subS su (x, y) = (subS su x, subS su y)--instance (SubStratum a) => SubStratum [a] where- subS su xs = subS su <$> xs--instance SubStratum (Annot SpecType) where- subS su (AnnUse t) = AnnUse $ subS su t- subS su (AnnDef t) = AnnDef $ subS su t- subS su (AnnRDf t) = AnnRDf $ subS su t- subS _ (AnnLoc s) = AnnLoc s--instance SubStratum SpecType where- subS su t = (\r -> r {ur_strata = subS su (ur_strata r)}) <$> t--
− src/Language/Haskell/Liquid/Tidy.hs
@@ -1,141 +0,0 @@-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE OverloadedStrings #-}------------------------------------------------------------------------- | This module contains functions for cleaning up types before--- they are rendered, e.g. in error messages or annoations.-------------------------------------------------------------------------module Language.Haskell.Liquid.Tidy (-- -- * Tidying functions- tidySpecType- , tidySymbol-- -- * Tidyness tests- , isTmpSymbol- ) where--import Control.Applicative-import qualified Data.HashMap.Strict as M-import qualified Data.HashSet as S-import qualified Data.List as L-import qualified Data.Text as T--import Language.Fixpoint.Names (symSepName, isPrefixOfSym, takeWhileSym)-import Language.Fixpoint.Types-import Language.Haskell.Liquid.GhcMisc (stringTyVar)-import Language.Haskell.Liquid.Types-import Language.Haskell.Liquid.RefType hiding (shiftVV)----------------------------------------------------------------------------tidySymbol :: Symbol -> Symbol---------------------------------------------------------------------------tidySymbol = takeWhileSym (/= symSepName)-----------------------------------------------------------------------------isTmpSymbol :: Symbol -> Bool---------------------------------------------------------------------------isTmpSymbol x = any (`isPrefixOfSym` x) [anfPrefix, tempPrefix, "ds_"]-----------------------------------------------------------------------------tidySpecType :: Tidy -> SpecType -> SpecType---------------------------------------------------------------------------tidySpecType k = tidyValueVars- . tidyDSymbols- . tidySymbols- . tidyLocalRefas k- . tidyFunBinds- . tidyTyVars--tidyValueVars :: SpecType -> SpecType-tidyValueVars = mapReft $ \u -> u { ur_reft = tidyVV $ ur_reft u }--tidyVV r@(Reft (va,_))- | isJunk va = shiftVV r v'- | otherwise = r- where- v' = if v `elem` xs then symbol ("v'" :: T.Text) else v- v = symbol ("v" :: T.Text)- xs = syms r- isJunk = isPrefixOfSym "x"--tidySymbols :: SpecType -> SpecType-tidySymbols t = substa tidySymbol $ mapBind dropBind t- where- xs = S.fromList (syms t)- dropBind x = if x `S.member` xs then tidySymbol x else nonSymbol---tidyLocalRefas :: Tidy -> SpecType -> SpecType-tidyLocalRefas k = mapReft (txStrata . txReft' k)- where- txReft' Full = id- txReft' Lossy = txReft- txStrata (U r p l) = U r p (txStr l)- txReft u = u { ur_reft = mapPredReft dropLocals $ ur_reft u }- dropLocals = pAnd . filter (not . any isTmp . syms) . conjuncts- isTmp x = any (`isPrefixOfSym` x) [anfPrefix, "ds_"]- txStr = filter (not . isSVar)---tidyDSymbols :: SpecType -> SpecType-tidyDSymbols t = mapBind tx $ substa tx t- where- tx = bindersTx [x | x <- syms t, isTmp x]- isTmp = (tempPrefix `isPrefixOfSym`)--tidyFunBinds :: SpecType -> SpecType-tidyFunBinds t = mapBind tx $ substa tx t- where- tx = bindersTx $ filter isTmpSymbol $ funBinds t--tidyTyVars :: SpecType -> SpecType-tidyTyVars t = subsTyVarsAll αβs t- where- αβs = zipWith (\α β -> (α, toRSort β, β)) αs βs- αs = L.nub (tyVars t)- βs = map (rVar . stringTyVar) pool- pool = [[c] | c <- ['a'..'z']] ++ [ "t" ++ show i | i <- [1..]]---bindersTx ds = \y -> M.lookupDefault y y m- where- m = M.fromList $ zip ds $ var <$> [1..]- var = symbol . ('x' :) . show---tyVars (RAllP _ t) = tyVars t-tyVars (RAllS _ t) = tyVars t-tyVars (RAllT α t) = α : tyVars t-tyVars (RFun _ t t' _) = tyVars t ++ tyVars t'-tyVars (RAppTy t t' _) = tyVars t ++ tyVars t'-tyVars (RApp _ ts _ _) = concatMap tyVars ts-tyVars (RVar α _) = [α]-tyVars (RAllE _ _ t) = tyVars t-tyVars (REx _ _ t) = tyVars t-tyVars (RExprArg _) = []-tyVars (RRTy _ _ _ t) = tyVars t-tyVars (RHole _) = []--subsTyVarsAll ats = go- where- abm = M.fromList [(a, b) | (a, _, (RVar b _)) <- ats]- go (RAllT a t) = RAllT (M.lookupDefault a a abm) (go t)- go t = subsTyVars_meet ats t---funBinds (RAllT _ t) = funBinds t-funBinds (RAllP _ t) = funBinds t-funBinds (RAllS _ t) = funBinds t-funBinds (RFun b t1 t2 _) = b : funBinds t1 ++ funBinds t2-funBinds (RApp _ ts _ _) = concatMap funBinds ts-funBinds (RAllE b t1 t2) = b : funBinds t1 ++ funBinds t2-funBinds (REx b t1 t2) = b : funBinds t1 ++ funBinds t2-funBinds (RVar _ _) = []-funBinds (RRTy _ _ _ t) = funBinds t-funBinds (RAppTy t1 t2 _) = funBinds t1 ++ funBinds t2-funBinds (RExprArg _) = []-funBinds (RHole _) = []
− src/Language/Haskell/Liquid/TransformRec.hs
@@ -1,245 +0,0 @@-{-# LANGUAGE DeriveDataTypeable #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE NoMonomorphismRestriction #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TupleSections #-}-{-# LANGUAGE TypeSynonymInstances #-}--module Language.Haskell.Liquid.TransformRec (- transformRecExpr, transformScope- ) where--import Bag-import Coercion-import Control.Arrow (second)-import Control.Monad.State-import CoreSyn-import CoreUtils-import qualified Data.HashMap.Strict as M-import ErrUtils-import Id (idOccInfo, setIdInfo)-import IdInfo-import MkCore (mkCoreLams)-import SrcLoc-import Type (mkForAllTys, splitForAllTys)-import TypeRep-import Unique hiding (deriveUnique)-import Var-import Name (isSystemName)-import Language.Haskell.Liquid.GhcMisc-import Language.Haskell.Liquid.GhcPlay-import Language.Haskell.Liquid.Misc (mapSndM)-import Language.Fixpoint.Misc (mapSnd)--import Data.List (foldl', isInfixOf)-import Control.Applicative ((<$>))--import qualified Data.List as L---transformRecExpr :: CoreProgram -> CoreProgram-transformRecExpr cbs- | isEmptyBag $ filterBag isTypeError e- = {-trace "new cbs"-} pg - | otherwise - = error ("Type-check" ++ showSDoc (pprMessageBag e))- where pg0 = evalState (transPg (inlineLoopBreaker <$> cbs)) initEnv- (_, e) = lintCoreBindings [] pg- pg = inlineFailCases pg0-----inlineLoopBreaker (NonRec x e) | Just (lbx, lbe) <- hasLoopBreaker be - = Rec [(x, foldr Lam (sub (M.singleton lbx e') lbe) (αs ++ as))]- where- (αs, as, be) = collectTyAndValBinders e-- e' = foldl' App (foldl' App (Var x) ((Type . TyVarTy) <$> αs)) (Var <$> as)-- hasLoopBreaker (Let (Rec [(x1, e1)]) (Var x2)) | isLoopBreaker x1 && x1 == x2 = Just (x1, e1)- hasLoopBreaker _ = Nothing-- isLoopBreaker = isStrongLoopBreaker . occInfo . idInfo--inlineLoopBreaker bs - = bs--inlineFailCases :: CoreProgram -> CoreProgram-inlineFailCases = (go [] <$>)- where - go su (Rec xes) = Rec (mapSnd (go' su) <$> xes)- go su (NonRec x e) = NonRec x (go' su e)-- go' su (App (Var x) _) | isFailId x, Just e <- getFailExpr x su = e - go' su (Let (NonRec x ex) e) | isFailId x = go' (addFailExpr x (go' su ex) su) e-- go' su (App e1 e2) = App (go' su e1) (go' su e2)- go' su (Lam x e) = Lam x (go' su e)- go' su (Let xs e) = Let (go su xs) (go' su e)- go' su (Case e x t alt) = Case (go' su e) x t (goalt su <$> alt) - go' su (Cast e c) = Cast (go' su e) c- go' su (Tick t e) = Tick t (go' su e)- go' _ e = e-- goalt su (c, xs, e) = (c, xs, go' su e)-- isFailId x = isLocalId x && (isSystemName $ varName x) && L.isPrefixOf "fail" (show x)- getFailExpr = L.lookup-- addFailExpr x (Lam _ e) su = (x, e):su - addFailExpr _ _ _ = error "internal error" -- this cannot happen--isTypeError s | isInfixOf "Non term variable" (showSDoc s) = False-isTypeError _ = True--transformScope = outerScTr . innerScTr--outerScTr = mapNonRec (go [])- where- go ack x (xe : xes) | isCaseArg x xe = go (xe:ack) x xes- go ack _ xes = ack ++ xes--isCaseArg x (NonRec _ (Case (Var z) _ _ _)) = z == x-isCaseArg _ _ = False--innerScTr = (mapBnd scTrans <$>)--scTrans x e = mapExpr scTrans $ foldr Let e0 bs- where (bs, e0) = go [] x e- go bs x (Let b e) | isCaseArg x b = go (b:bs) x e- go bs x (Tick t e) = second (Tick t) $ go bs x e- go bs _ e = (bs, e)--type TE = State TrEnv--data TrEnv = Tr { freshIndex :: !Int- , _loc :: SrcSpan- }--initEnv = Tr 0 noSrcSpan--transPg = mapM transBd--transBd (NonRec x e) = liftM (NonRec x) (transExpr =<< mapBdM transBd e)-transBd (Rec xes) = liftM Rec $ mapM (mapSndM (mapBdM transBd)) xes--transExpr :: CoreExpr -> TE CoreExpr-transExpr e- | (isNonPolyRec e') && (not (null tvs)) - = trans tvs ids bs e'- | otherwise- = return e- where (tvs, ids, e'') = collectTyAndValBinders e- (bs, e') = collectNonRecLets e''--isNonPolyRec (Let (Rec xes) _) = any nonPoly (snd <$> xes)-isNonPolyRec _ = False--nonPoly = null . fst . splitForAllTys . exprType--collectNonRecLets = go []- where go bs (Let b@(NonRec _ _) e') = go (b:bs) e'- go bs e' = (reverse bs, e')--appTysAndIds tvs ids x = mkApps (mkTyApps (Var x) (map TyVarTy tvs)) (map Var ids)--trans vs ids bs (Let (Rec xes) e)- = liftM (mkLam . mkLet) (makeTrans vs liveIds e')- where liveIds = mkAlive <$> ids- mkLet e = foldr Let e bs- mkLam e = foldr Lam e $ vs ++ liveIds- e' = Let (Rec xes') e- xes' = (second mkLet) <$> xes--trans _ _ _ _ = error "TransformRec.trans called with invalid input"--makeTrans vs ids (Let (Rec xes) e)- = do fids <- mapM (mkFreshIds vs ids) xs- let (ids', ys) = unzip fids- let yes = appTysAndIds vs ids <$> ys- ys' <- mapM fresh xs- let su = M.fromList $ zip xs (Var <$> ys')- let rs = zip ys' yes- let es' = zipWith (mkE ys) ids' es- let xes' = zip ys es'- return $ mkRecBinds rs (Rec xes') (sub su e)- where - (xs, es) = unzip xes- mkSu ys ids' = mkSubs ids vs ids' (zip xs ys)- mkE ys ids' e' = mkCoreLams (vs ++ ids') (sub (mkSu ys ids') e')--makeTrans _ _ _ = error "TransformRec.makeTrans called with invalid input"--mkRecBinds :: [(b, Expr b)] -> Bind b -> Expr b -> Expr b-mkRecBinds xes rs e = Let rs (foldl' f e xes)- where f e (x, xe) = Let (NonRec x xe) e --mkSubs ids tvs xs ys = M.fromList $ s1 ++ s2- where s1 = (second (appTysAndIds tvs xs)) <$> ys- s2 = zip ids (Var <$> xs)--mkFreshIds tvs ids x- = do ids' <- mapM fresh ids- let t = mkForAllTys tvs $ mkType (reverse ids') $ varType x- let x' = setVarType x t- return (ids', x')- where - mkType ids ty = foldl (\t x -> FunTy (varType x) t) ty ids--class Freshable a where- fresh :: a -> TE a--instance Freshable Int where- fresh _ = freshInt--instance Freshable Unique where- fresh _ = freshUnique--instance Freshable Var where- fresh v = liftM (setVarUnique v) freshUnique--freshInt- = do s <- get- let n = freshIndex s- put s{freshIndex = n+1}- return n--freshUnique = liftM (mkUnique 'X') freshInt--mkAlive x- | isId x && isDeadOcc (idOccInfo x)- = setIdInfo x (setOccInfo (idInfo x) NoOccInfo)- | otherwise- = x--mapNonRec f (NonRec x xe:xes) = NonRec x xe : f x (mapNonRec f xes)-mapNonRec f (xe:xes) = xe : mapNonRec f xes-mapNonRec _ [] = []--mapBnd f (NonRec b e) = NonRec b (mapExpr f e)-mapBnd f (Rec bs) = Rec (map (second (mapExpr f)) bs)--mapExpr f (Let (NonRec x ex) e) = Let (NonRec x (f x ex) ) (f x e)-mapExpr f (App e1 e2) = App (mapExpr f e1) (mapExpr f e2)-mapExpr f (Lam b e) = Lam b (mapExpr f e)-mapExpr f (Let bs e) = Let (mapBnd f bs) (mapExpr f e)-mapExpr f (Case e b t alt) = Case e b t (map (mapAlt f) alt)-mapExpr f (Tick t e) = Tick t (mapExpr f e)-mapExpr _ e = e--mapAlt f (d, bs, e) = (d, bs, mapExpr f e)---- Do not apply transformations to inner code--mapBdM _ = return---- mapBdM f (Let b e) = liftM2 Let (f b) (mapBdM f e)--- mapBdM f (App e1 e2) = liftM2 App (mapBdM f e1) (mapBdM f e2)--- mapBdM f (Lam b e) = liftM (Lam b) (mapBdM f e)--- mapBdM f (Case e b t alt) = liftM (Case e b t) (mapM (mapBdAltM f) alt)--- mapBdM f (Tick t e) = liftM (Tick t) (mapBdM f e)--- mapBdM _ e = return e--- --- mapBdAltM f (d, bs, e) = liftM ((,,) d bs) (mapBdM f e)
+ src/Language/Haskell/Liquid/Transforms/ANF.hs view
@@ -0,0 +1,313 @@++--------------------------------------------------------------------------------+-- | Convert GHC Core into Administrative Normal Form (ANF) --------------------+--------------------------------------------------------------------------------++{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE NoMonomorphismRestriction #-}+{-# LANGUAGE TupleSections #-}+{-# LANGUAGE TypeSynonymInstances #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE OverloadedStrings #-}+++module Language.Haskell.Liquid.Transforms.ANF (anormalize) where++import Prelude hiding (error)+import CoreSyn+import CoreUtils (exprType)+import qualified DsMonad+import DsMonad (initDs)+import GHC hiding (exprType)+import HscTypes++import OccName (mkVarOccFS)+import Id (mkUserLocalM)+import Literal+import MkCore (mkCoreLets)+import Outputable (trace)+import Var (varType, setVarType)+import TypeRep+import Type (mkForAllTys, substTy, mkForAllTys, mkTopTvSubst, isTyVar)+import TyCon (tyConDataCons_maybe)+import DataCon (dataConInstArgTys)+import FamInstEnv (emptyFamInstEnv)+import VarEnv (VarEnv, emptyVarEnv, extendVarEnv, lookupWithDefaultVarEnv)+import Control.Monad.State.Lazy+import UniqSupply (MonadUnique)+import Language.Fixpoint.Misc (fst3)+import Language.Fixpoint.Types (anfPrefix)+import Language.Haskell.Liquid.Misc (concatMapM)+import Language.Haskell.Liquid.GHC.Misc (MGIModGuts(..), showPpr, symbolFastString)+import Language.Haskell.Liquid.Transforms.Rec+import Language.Haskell.Liquid.Types.Errors+import qualified Language.Haskell.Liquid.GHC.SpanStack as Sp+import Data.Maybe (fromMaybe)+import Data.List (sortBy, (\\))+++--------------------------------------------------------------------------------+-- | A-Normalize a module ------------------------------------------------------+--------------------------------------------------------------------------------+anormalize :: Bool -> HscEnv -> MGIModGuts -> IO [CoreBind]+--------------------------------------------------------------------------------+anormalize expandFlag hscEnv modGuts+ = do -- putStrLn "***************************** GHC CoreBinds ***************************"+ -- putStrLn $ showPpr orig_cbs+ (fromMaybe err . snd) <$> initDs hscEnv m grEnv tEnv emptyFamInstEnv act+ where+ m = mgi_module modGuts+ grEnv = mgi_rdr_env modGuts+ tEnv = modGutsTypeEnv modGuts+ act = concatMapM (normalizeTopBind expandFlag emptyAnfEnv) orig_cbs+ orig_cbs = transformRecExpr $ mgi_binds modGuts+ err = panic Nothing "Oops, cannot A-Normalize GHC Core!"++modGutsTypeEnv mg = typeEnvFromEntities ids tcs fis+ where+ ids = bindersOfBinds (mgi_binds mg)+ tcs = mgi_tcs mg+ fis = mgi_fam_insts mg++--------------------------------------------------------------------------------+-- | A-Normalize a @CoreBind@ --------------------------------------------------+--------------------------------------------------------------------------------++-- Can't make the below default for normalizeBind as it+-- fails tests/pos/lets.hs due to GHCs odd let-bindings++normalizeTopBind :: Bool -> AnfEnv -> Bind CoreBndr -> DsMonad.DsM [CoreBind]+normalizeTopBind expandFlag γ (NonRec x e)+ = do e' <- runDsM $ evalStateT (stitch γ e) (DsST expandFlag [])+ return [normalizeTyVars $ NonRec x e']++normalizeTopBind expandFlag γ (Rec xes)+ = do xes' <- runDsM $ execStateT (normalizeBind γ (Rec xes)) (DsST expandFlag [])+ return $ map normalizeTyVars (st_binds xes')++normalizeTyVars :: Bind Id -> Bind Id+normalizeTyVars (NonRec x e) = NonRec (setVarType x t') $ normalizeForAllTys e+ where t' = subst msg as as' bt+ msg = "WARNING unable to renameVars on " ++ showPpr x+ as' = fst $ splitForAllTys $ exprType e+ (as, bt) = splitForAllTys (varType x)+normalizeTyVars (Rec xes) = Rec xes'+ where nrec = normalizeTyVars <$> ((\(x, e) -> NonRec x e) <$> xes)+ xes' = (\(NonRec x e) -> (x, e)) <$> nrec++subst :: String -> [TyVar] -> [TyVar] -> Type -> Type+subst msg as as' bt+ | length as == length as'+ = mkForAllTys as' $ substTy su bt+ | otherwise+ = trace msg $ mkForAllTys as bt+ where su = mkTopTvSubst $ zip as (mkTyVarTys as')++-- | eta-expand CoreBinds with quantified types+normalizeForAllTys :: CoreExpr -> CoreExpr+normalizeForAllTys e = case e of+ Lam b _ | isTyVar b+ -> e+ _ -> mkLams tvs (mkTyApps e (map mkTyVarTy tvs))+ where+ (tvs, _) = splitForAllTys (exprType e)+++newtype DsM a = DsM {runDsM :: DsMonad.DsM a}+ deriving (Functor, Monad, MonadUnique, Applicative)++data DsST = DsST { st_expandflag :: Bool+ , st_binds :: [CoreBind]+ }++type DsMW = StateT DsST DsM++------------------------------------------------------------------+normalizeBind :: AnfEnv -> CoreBind -> DsMW ()+------------------------------------------------------------------+normalizeBind γ (NonRec x e)+ = do e' <- normalize γ e+ add [NonRec x e']++normalizeBind γ (Rec xes)+ = do es' <- mapM (stitch γ) es+ add [Rec (zip xs es')]+ where (xs, es) = unzip xes++--------------------------------------------------------------------+normalizeName :: AnfEnv -> CoreExpr -> DsMW CoreExpr+--------------------------------------------------------------------++-- normalizeNameDebug γ e+-- = liftM (tracePpr ("normalizeName" ++ showPpr e)) $ normalizeName γ e++normalizeName γ e@(Lit l)+ | shouldNormalize l+ = normalizeLiteral γ e+ | otherwise+ = return e++normalizeName γ (Var x)+ = return $ Var (lookupAnfEnv γ x x)++normalizeName _ e@(Type _)+ = return e++normalizeName γ e@(Coercion _)+ = do x <- lift $ freshNormalVar γ $ exprType e+ add [NonRec x e]+ return $ Var x++normalizeName γ (Tick tt e)+ = do e' <- normalizeName (γ `at` tt) e+ return $ Tick tt e'++normalizeName γ e+ = do e' <- normalize γ e+ x <- lift $ freshNormalVar γ $ exprType e+ add [NonRec x e']+ return $ Var x++shouldNormalize l = case l of+ LitInteger _ _ -> True+ MachStr _ -> True+ _ -> False++add :: [CoreBind] -> DsMW ()+add w = modify $ \s -> s{st_binds = st_binds s++w}++---------------------------------------------------------------------+normalizeLiteral :: AnfEnv -> CoreExpr -> DsMW CoreExpr+---------------------------------------------------------------------+normalizeLiteral γ e =+ do x <- lift $ freshNormalVar γ $ exprType e+ add [NonRec x e]+ return $ Var x++---------------------------------------------------------------------+normalize :: AnfEnv -> CoreExpr -> DsMW CoreExpr+---------------------------------------------------------------------++normalize γ (Lam x e)+ = do e' <- stitch γ e+ return $ Lam x e'++normalize γ (Let b e)+ = do normalizeBind γ b+ normalize γ e+ -- Need to float bindings all the way up to the top+ -- Due to GHCs odd let-bindings (see tests/pos/lets.hs)++normalize γ (Case e x t as)+ = do n <- normalizeName γ e+ x' <- lift $ freshNormalVar γ τx -- rename "wild" to avoid shadowing+ let γ' = extendAnfEnv γ x x'+ as' <- forM as $ \(c, xs, e') -> liftM (c, xs,) (stitch γ' e')+ flag <- st_expandflag <$> get+ as'' <- lift $ expandDefaultCase γ flag τx as'+ return $ Case n x' t as''+ where τx = varType x++normalize γ (Var x)+ = return $ Var (lookupAnfEnv γ x x)++normalize _ e@(Lit _)+ = return e++normalize _ e@(Type _)+ = return e++normalize γ (Cast e τ)+ = do e' <- normalizeName γ e+ return $ Cast e' τ++normalize γ (App e1 e2)+ = do e1' <- normalize γ e1+ n2 <- normalizeName γ e2+ return $ App e1' n2++normalize γ (Tick tt e)+ = do e' <- normalize (γ `at` tt) e+ return $ Tick tt e'++normalize _ (Coercion c)+ = return $ Coercion c++stitch :: AnfEnv -> CoreExpr -> DsMW CoreExpr+stitch γ e+ = do bs' <- get+ modify $ \s -> s {st_binds = []}+ e' <- normalize γ e+ bs <- st_binds <$> get+ put bs'+ return $ mkCoreLets bs e'++--------------------------------------------------------------------------------+expandDefaultCase :: AnfEnv+ -> Bool+ -> Type+ -> [(AltCon, [Id], CoreExpr)]+ -> DsM [(AltCon, [Id], CoreExpr)]+--------------------------------------------------------------------------------++expandDefaultCase γ flag tyapp zs@((DEFAULT, _ ,_) : _) | flag+ = expandDefaultCase' γ tyapp zs++expandDefaultCase γ _ tyapp@(TyConApp tc _) z@((DEFAULT, _ ,_):dcs)+ = case tyConDataCons_maybe tc of+ Just ds -> do let ds' = ds \\ [ d | (DataAlt d, _ , _) <- dcs]+ if (length ds') == 1+ then expandDefaultCase' γ tyapp z+ else return z+ Nothing -> return z --++expandDefaultCase _ _ _ z+ = return z++expandDefaultCase' γ (TyConApp tc argτs) z@((DEFAULT, _ ,e) : dcs)+ = case tyConDataCons_maybe tc of+ Just ds -> do let ds' = ds \\ [ d | (DataAlt d, _ , _) <- dcs]+ dcs' <- forM ds' $ cloneCase γ argτs e+ return $ sortCases $ dcs' ++ dcs+ Nothing -> return z --++expandDefaultCase' _ _ z+ = return z++cloneCase γ argτs e d+ = do xs <- mapM (freshNormalVar γ) $ dataConInstArgTys d argτs+ return (DataAlt d, xs, e)++sortCases = sortBy (\x y -> cmpAltCon (fst3 x) (fst3 y))+++--------------------------------------------------------------------------------+-- | ANF Environments ----------------------------------------------------------+--------------------------------------------------------------------------------++-- freshNormalVar :: Type -> DsM Id+-- freshNormalVar = mkSysLocalM (symbolFastString anfPrefix)++freshNormalVar :: AnfEnv -> Type -> DsM Id+freshNormalVar γ t = mkUserLocalM anfOcc t sp+ where+ anfOcc = mkVarOccFS $ symbolFastString anfPrefix+ sp = Sp.srcSpan (aeSrcSpan γ)+++data AnfEnv = AnfEnv+ { aeVarEnv :: VarEnv Id+ , aeSrcSpan :: Sp.SpanStack+ }++emptyAnfEnv :: AnfEnv+emptyAnfEnv = AnfEnv emptyVarEnv Sp.empty++lookupAnfEnv :: AnfEnv -> Id -> Id -> Id+lookupAnfEnv γ x y = lookupWithDefaultVarEnv (aeVarEnv γ) x y++extendAnfEnv :: AnfEnv -> Id -> Id -> AnfEnv+extendAnfEnv γ x y = γ { aeVarEnv = extendVarEnv (aeVarEnv γ) x y }++at :: AnfEnv -> Tickish Id -> AnfEnv+at γ tt = γ { aeSrcSpan = Sp.push (Sp.Tick tt) (aeSrcSpan γ)}
+ src/Language/Haskell/Liquid/Transforms/CoreToLogic.hs view
@@ -0,0 +1,456 @@+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TupleSections #-}++module Language.Haskell.Liquid.Transforms.CoreToLogic (++ coreToDef , coreToFun,+ coreToLogic, coreToPred,+ mkLit, runToLogic,+ logicType,+ strengthenResult++ ) where++import Prelude hiding (error)+import GHC hiding (Located)+import Var+import Type+import TypeRep++import qualified CoreSyn as C+import Literal+import IdInfo++import Data.Text.Encoding++import TysWiredIn++++import Language.Fixpoint.Misc (snd3)++import Language.Fixpoint.Types hiding (Error, R, simplify)+import qualified Language.Fixpoint.Types as F+import Language.Haskell.Liquid.GHC.Misc+import Language.Haskell.Liquid.GHC.Play+import Language.Haskell.Liquid.Types hiding (GhcInfo(..), GhcSpec (..), LM)+import Language.Haskell.Liquid.Misc (mapSnd)+import Language.Haskell.Liquid.WiredIn+import Language.Haskell.Liquid.Types.RefType+++import qualified Data.HashMap.Strict as M+++++logicType :: (Reftable r) => Type -> RRType r+logicType τ = fromRTypeRep $ t{ty_res = res, ty_binds = binds, ty_args = args, ty_refts = refts}+ where+ t = toRTypeRep $ ofType τ+ res = mkResType $ ty_res t+ (binds, args, refts) = unzip3 $ dropWhile (isClassType.snd3) $ zip3 (ty_binds t) (ty_args t) (ty_refts t)+++ mkResType t+ | isBool t = propType+ | otherwise = t++isBool (RApp (RTyCon{rtc_tc = c}) _ _ _) = c == boolTyCon+isBool _ = False++{- strengthenResult type: the refinement depends on whether the result type is a Bool or not:++CASE1: measure f@logic :: X -> Prop <=> f@haskell :: x:X -> {v:Bool | (Prop v) <=> (f@logic x)}++CASE2: measure f@logic :: X -> Y <=> f@haskell :: x:X -> {v:Y | v = (f@logic x)}+-}++strengthenResult :: Var -> SpecType+strengthenResult v+ | isBool res+ = -- traceShow ("Type for " ++ showPpr v ++ "\t OF \t" ++ show (ty_binds rep)) $+ fromRTypeRep $ rep{ty_res = res `strengthen` r, ty_binds = xs}+ | otherwise+ = -- traceShow ("Type for " ++ showPpr v ++ "\t OF \t" ++ show (ty_binds rep)) $+ fromRTypeRep $ rep{ty_res = res `strengthen` r', ty_binds = xs}+ where rep = toRTypeRep t+ res = ty_res rep+ xs = intSymbol (symbol ("x" :: String)) <$> [1..length $ ty_binds rep]+ r' = MkUReft (exprReft (mkEApp f (mkA <$> vxs))) mempty mempty+ r = MkUReft (propReft (mkEApp f (mkA <$> vxs))) mempty mempty+ vxs = dropWhile (isClassType.snd) $ zip xs (ty_args rep)+ f = dummyLoc $ dropModuleNames $ simplesymbol v+ t = (ofType $ varType v) :: SpecType+ mkA = EVar . fst -- if isBool t then EApp (dummyLoc propConName) [(EVar x)] else EVar x+++simplesymbol = symbol . getName++newtype LogicM a = LM {runM :: LState -> Either a Error}++data LState = LState { symbolMap :: LogicMap+ , mkError :: String -> Error+ , ltce :: TCEmb TyCon+ }+++instance Monad LogicM where+ return = LM . const . Left+ (LM m) >>= f+ = LM $ \s -> case m s of+ (Left x) -> (runM (f x)) s+ (Right x) -> Right x++instance Functor LogicM where+ fmap f (LM m) = LM $ \s -> case m s of+ (Left x) -> Left $ f x+ (Right x) -> Right x++instance Applicative LogicM where+ pure = LM . const . Left+ (LM f) <*> (LM m)+ = LM $ \s -> case (f s, m s) of+ (Left f , Left x ) -> Left $ f x+ (Right f, Left _ ) -> Right f+ (Left _ , Right x) -> Right x+ (Right _, Right x) -> Right x++throw :: String -> LogicM a+throw str = LM $ \s -> Right $ (mkError s) str++getState :: LogicM LState+getState = LM $ Left++runToLogic tce lmap ferror (LM m)+ = m $ LState {symbolMap = lmap, mkError = ferror, ltce = tce }++coreToDef :: Reftable r => LocSymbol -> Var -> C.CoreExpr -> LogicM [Def (RRType r) DataCon]+coreToDef x _ e = go [] $ inline_preds $ simplify e+ where+ go args (C.Lam x e) = go (x:args) e+ go args (C.Tick _ e) = go args e+ go args (C.Case _ _ t alts)+ | eqType t boolTy = mapM (goalt_prop (reverse $ tail args) (head args)) alts+ | otherwise = mapM (goalt (reverse $ tail args) (head args)) alts+ go _ _ = throw "Measure Functions should have a case at top level"++ goalt args dx ((C.DataAlt d), xs, e)+ = ((Def x (toArgs id args) d (Just $ ofType $ varType dx) (toArgs Just xs)) . E)+ <$> coreToLg e+ goalt _ _ alt+ = throw $ "Bad alternative" ++ showPpr alt++ goalt_prop args dx ((C.DataAlt d), xs, e)+ = ((Def x (toArgs id args) d (Just $ ofType $ varType dx) (toArgs Just xs)) . P)+ <$> coreToPd e+ goalt_prop _ _ alt+ = throw $ "Bad alternative" ++ showPpr alt++ toArgs f args = [(symbol x, f $ ofType $ varType x) | x <- args]++ inline_preds = inline (eqType boolTy . varType)++coreToFun :: LocSymbol -> Var -> C.CoreExpr -> LogicM ([Var], Either Expr Expr)+coreToFun _ v e = go [] $ normalize e+ where+ go acc (C.Lam x e) | isTyVar x = go acc e+ go acc (C.Lam x e) | isErasable x = go acc e+ go acc (C.Lam x e) = go (x:acc) e+ go acc (C.Tick _ e) = go acc e+ go acc e | eqType rty boolTy+ = (reverse acc,) . Left <$> coreToPd e+ | otherwise+ = (reverse acc,) . Right <$> coreToLg e+++ rty = snd $ splitFunTys $ snd $ splitForAllTys $ varType v++coreToPred :: C.CoreExpr -> LogicM Expr+coreToPred e = coreToPd $ normalize e+++coreToPd :: C.CoreExpr -> LogicM Expr+coreToPd (C.Let b p) = subst1 <$> coreToPd p <*> makesub b+coreToPd (C.Tick _ p) = coreToPd p+coreToPd (C.App (C.Var v) e) | ignoreVar v = coreToPd e+coreToPd (C.Var x)+ | x == falseDataConId+ = return PFalse+ | x == trueDataConId+ = return PTrue+ | eqType boolTy (varType x)+ = return $ mkEApp (dummyLoc propConName) [(EVar $ symbol x)]+coreToPd p@(C.App _ _) = toPredApp p+coreToPd e+ = coreToLg e+-- coreToPd e+-- = throw ("Cannot transform to Logical Predicate:\t" ++ showPpr e)+++instance Show C.CoreExpr where+ show = showPpr++coreToLogic :: C.CoreExpr -> LogicM Expr+coreToLogic = coreToLg . simplify+++coreToLg :: C.CoreExpr -> LogicM Expr+coreToLg (C.Let b e) = subst1 <$> coreToLg e <*> makesub b+coreToLg (C.Tick _ e) = coreToLg e+coreToLg (C.App (C.Var v) e) | ignoreVar v = coreToLg e+coreToLg (C.Lit l)+ = case mkLit l of+ Nothing -> throw $ "Bad Literal in measure definition" ++ showPpr l+ Just i -> return i+coreToLg (C.Var x)+ | x == falseDataConId+ = return PFalse+ | x == trueDataConId+ = return PTrue+ | eqType boolTy (varType x)+ = return $ mkEApp (dummyLoc propConName) [(EVar $ symbol x)]+coreToLg (C.Var x) = (symbolMap <$> getState) >>= eVarWithMap x+coreToLg e@(C.App _ _) = toLogicApp e+coreToLg (C.Case e b _ alts) | eqType (varType b) boolTy+ = checkBoolAlts alts >>= coreToIte e+coreToLg (C.Lam x e)+ = do p <- coreToLg e+ tce <- ltce <$> getState + return $ ELam (symbol x, typeSort tce $ varType x) p+-- coreToLg p@(C.App _ _) = toPredApp p+coreToLg e = throw ("Cannot transform to Logic:\t" ++ showPpr e)++checkBoolAlts :: [C.CoreAlt] -> LogicM (C.CoreExpr, C.CoreExpr)+checkBoolAlts [(C.DataAlt false, [], efalse), (C.DataAlt true, [], etrue)]+ | false == falseDataCon, true == trueDataCon+ = return (efalse, etrue)+checkBoolAlts [(C.DataAlt true, [], etrue), (C.DataAlt false, [], efalse)]+ | false == falseDataCon, true == trueDataCon+ = return (efalse, etrue)+checkBoolAlts alts+ = throw ("checkBoolAlts failed on " ++ showPpr alts)++coreToIte e (efalse, etrue)+ = do p <- coreToPd e+ e1 <- coreToLg efalse+ e2 <- coreToLg etrue+ return $ EIte p e2 e1++toPredApp :: C.CoreExpr -> LogicM Expr+toPredApp p+ = do let (f, es) = splitArgs p+ let f' = tomaybesymbol f+ go f' es+ where+ go (Just f) [e1, e2]+ | Just rel <- M.lookup f brels+ = PAtom rel <$> (coreToLg e1) <*> (coreToLg e2)+ go (Just f) [e]+ | f == symbol ("not" :: String)+ = PNot <$> coreToPd e+ go (Just f) [e1, e2]+ | f == symbol ("||" :: String)+ = POr <$> mapM coreToPd [e1, e2]+ | f == symbol ("&&" :: String)+ = PAnd <$> mapM coreToPd [e1, e2]+ | f == symbol ("==>" :: String)+ = PImp <$> coreToPd e1 <*> coreToPd e2+ go (Just f) es+ | f == symbol ("or" :: String)+ = POr <$> mapM coreToPd es+ | f == symbol ("and" :: String)+ = PAnd <$> mapM coreToPd es+ go _ _ = toLogicApp p++toLogicApp :: C.CoreExpr -> LogicM Expr+toLogicApp e+ = do let (f, es) = splitArgs e+ case f of + C.Var _ -> do args <- mapM coreToLg es+ lmap <- symbolMap <$> getState+ def <- (`mkEApp` args) <$> tosymbol f+ (\x -> makeApp def lmap x args) <$> tosymbol' f+ _ -> do (fe:args) <- mapM coreToLg (f:es) + return $ foldl EApp fe args ++makeApp :: Expr -> LogicMap -> Located Symbol-> [Expr] -> Expr+makeApp _ _ f [e] | val f == symbol ("GHC.Num.negate" :: String)+ = ENeg e++makeApp _ _ f [e1, e2] | Just op <- M.lookup (val f) bops+ = EBin op e1 e2++makeApp def lmap f es+ = eAppWithMap lmap f es def++eVarWithMap :: Id -> LogicMap -> LogicM Expr+eVarWithMap x lmap+ = do f' <- tosymbol' (C.Var x :: C.CoreExpr)+ return $ eAppWithMap lmap f' [] (eVar x )+ where+ eVar x | isPolyCst $ varType x = mkEApp (dummyLoc $ symbol x) []+ | otherwise = EVar $ symbol x++ isPolyCst (ForAllTy _ t) = isCst t+ isPolyCst _ = False+ isCst (ForAllTy _ t) = isCst t+ isCst (FunTy _ _) = False+ isCst _ = True+++brels :: M.HashMap Symbol Brel+brels = M.fromList [ (symbol ("==" :: String), Eq)+ , (symbol ("/=" :: String), Ne)+ , (symbol (">=" :: String), Ge)+ , (symbol (">" :: String) , Gt)+ , (symbol ("<=" :: String), Le)+ , (symbol ("<" :: String) , Lt)+ ]++bops :: M.HashMap Symbol Bop+bops = M.fromList [ (numSymbol "+", Plus)+ , (numSymbol "-", Minus)+ , (numSymbol "*", Times)+ , (numSymbol "/", Div)+ , (numSymbol "%", Mod)+ ]+ where+ numSymbol :: String -> Symbol+ numSymbol = symbol . (++) "GHC.Num."++splitArgs e = (f, reverse es)+ where+ (f, es) = go e++ go (C.App (C.Var i) e) | ignoreVar i = go e+ go (C.App f (C.Var v)) | isErasable v = go f+ go (C.App f e) = (f', e:es) where (f', es) = go f+ go f = (f, [])++tomaybesymbol (C.Var c) | isDataConId c = Just $ symbol c+tomaybesymbol (C.Var x) = Just $ simpleSymbolVar x+tomaybesymbol _ = Nothing ++tosymbol e + = case tomaybesymbol e of + Just x -> return $ dummyLoc x + _ -> throw ("Bad Measure Definition:\n" ++ showPpr e ++ "\t cannot be applied")++tosymbol' (C.Var x) = return $ dummyLoc $ simpleSymbolVar' x+tosymbol' e = throw ("Bad Measure Definition:\n" ++ showPpr e ++ "\t cannot be applied")++makesub (C.NonRec x e) = (symbol x,) <$> coreToLg e+makesub _ = throw "Cannot make Logical Substitution of Recursive Definitions"++mkLit :: Literal -> Maybe Expr+mkLit (MachInt n) = mkI n+mkLit (MachInt64 n) = mkI n+mkLit (MachWord n) = mkI n+mkLit (MachWord64 n) = mkI n+mkLit (MachFloat n) = mkR n+mkLit (MachDouble n) = mkR n+mkLit (LitInteger n _) = mkI n+mkLit (MachStr s) = mkS s+mkLit _ = Nothing -- ELit sym sort++mkI = Just . ECon . I+mkR = Just . ECon . F.R . fromRational+mkS = Just . ESym . SL . decodeUtf8++ignoreVar i = simpleSymbolVar i `elem` ["I#"]+++simpleSymbolVar = dropModuleNames . symbol . showPpr . getName+simpleSymbolVar' = symbol . showPpr . getName++isErasable v = isPrefixOfSym (symbol ("$" :: String)) (simpleSymbolVar v)+isANF v = isPrefixOfSym (symbol ("lq_anf" :: String)) (simpleSymbolVar v)++isDead = isDeadOcc . occInfo . idInfo++class Simplify a where+ simplify :: a -> a+ inline :: (Id -> Bool) -> a -> a+++ normalize :: a -> a+ normalize = inline_preds . inline_anf . simplify+ where+ inline_preds = inline (eqType boolTy . varType)+ inline_anf = inline isANF++instance Simplify C.CoreExpr where+ simplify e@(C.Var _)+ = e+ simplify e@(C.Lit _)+ = e+ simplify (C.App e (C.Type _))+ = simplify e+ simplify (C.App e (C.Var dict)) | isErasable dict+ = simplify e+ simplify (C.App (C.Lam x e) _) | isDead x+ = simplify e+ simplify (C.App e1 e2)+ = C.App (simplify e1) (simplify e2)+ simplify (C.Lam x e) | isTyVar x+ = simplify e+ simplify (C.Lam x e) | isErasable x+ = simplify e+ simplify (C.Lam x e)+ = C.Lam x (simplify e)+ simplify (C.Let (C.NonRec x _) e) | isErasable x+ = simplify e+ simplify (C.Let (C.Rec xes) e) | all (isErasable . fst) xes+ = simplify e+ simplify (C.Let xes e)+ = C.Let (simplify xes) (simplify e)+ simplify (C.Case e x t alts)+ = C.Case (simplify e) x t (filter (not . isUndefined) (simplify <$> alts))+ simplify (C.Cast e _)+ = simplify e+ simplify (C.Tick _ e)+ = simplify e+ simplify (C.Coercion c)+ = C.Coercion c+ simplify (C.Type t)+ = C.Type t++ inline p (C.Let (C.NonRec x ex) e) | p x+ = sub (M.singleton x (inline p ex)) (inline p e)+ inline p (C.Let xes e) = C.Let (inline p xes) (inline p e)+ inline p (C.App e1 e2) = C.App (inline p e1) (inline p e2)+ inline p (C.Lam x e) = C.Lam x (inline p e)+ inline p (C.Case e x t alts) = C.Case (inline p e) x t (inline p <$> alts)+ inline p (C.Cast e c) = C.Cast (inline p e) c+ inline p (C.Tick t e) = C.Tick t (inline p e)+ inline _ (C.Var x) = C.Var x+ inline _ (C.Lit l) = C.Lit l+ inline _ (C.Coercion c) = C.Coercion c+ inline _ (C.Type t) = C.Type t++isUndefined (_, _, e) = isUndefinedExpr e+ where+ -- auto generated undefined case: (\_ -> (patError @type "error message")) void+ isUndefinedExpr (C.App (C.Var x) _) | (show x) `elem` perrors = True+ isUndefinedExpr (C.Let _ e) = isUndefinedExpr e+ -- otherwise+ isUndefinedExpr _ = False++ perrors = ["Control.Exception.Base.patError"]+++instance Simplify C.CoreBind where+ simplify (C.NonRec x e) = C.NonRec x (simplify e)+ simplify (C.Rec xes) = C.Rec (mapSnd simplify <$> xes )++ inline p (C.NonRec x e) = C.NonRec x (inline p e)+ inline p (C.Rec xes) = C.Rec (mapSnd (inline p) <$> xes)++instance Simplify C.CoreAlt where+ simplify (c, xs, e) = (c, xs, simplify e)++ inline p (c, xs, e) = (c, xs, inline p e)
+ src/Language/Haskell/Liquid/Transforms/Rec.hs view
@@ -0,0 +1,246 @@+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE NoMonomorphismRestriction #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TupleSections #-}+{-# LANGUAGE TypeSynonymInstances #-}++module Language.Haskell.Liquid.Transforms.Rec (+ transformRecExpr, transformScope+ ) where++import Prelude hiding (error)+import Bag+import Coercion+import Control.Arrow (second)+import Control.Monad.State+import CoreSyn+import CoreUtils+import qualified Data.HashMap.Strict as M+import ErrUtils+import Id (idOccInfo, setIdInfo)+import IdInfo+import MkCore (mkCoreLams)+import SrcLoc+import Type (mkForAllTys, splitForAllTys)+import TypeRep+import Unique hiding (deriveUnique)+import Var+import Name (isSystemName)+import Language.Haskell.Liquid.GHC.Misc+import Language.Haskell.Liquid.GHC.Play+import Language.Haskell.Liquid.Misc (mapSndM, mapSnd)+import Language.Haskell.Liquid.Types.Errors++import Data.List (foldl', isInfixOf)+++import qualified Data.List as L+++transformRecExpr :: CoreProgram -> CoreProgram+transformRecExpr cbs+ | isEmptyBag $ filterBag isTypeError e+ = {-trace "new cbs"-} pg+ | otherwise+ = panic Nothing ("Type-check" ++ showSDoc (pprMessageBag e))+ where pg0 = evalState (transPg (inlineLoopBreaker <$> cbs)) initEnv+ (_, e) = lintCoreBindings [] pg+ pg = inlineFailCases pg0+++++inlineLoopBreaker (NonRec x e) | Just (lbx, lbe) <- hasLoopBreaker be+ = Rec [(x, foldr Lam (sub (M.singleton lbx e') lbe) (αs ++ as))]+ where+ (αs, as, be) = collectTyAndValBinders e++ e' = foldl' App (foldl' App (Var x) ((Type . TyVarTy) <$> αs)) (Var <$> as)++ hasLoopBreaker (Let (Rec [(x1, e1)]) (Var x2)) | isLoopBreaker x1 && x1 == x2 = Just (x1, e1)+ hasLoopBreaker _ = Nothing++ isLoopBreaker = isStrongLoopBreaker . occInfo . idInfo++inlineLoopBreaker bs+ = bs++inlineFailCases :: CoreProgram -> CoreProgram+inlineFailCases = (go [] <$>)+ where+ go su (Rec xes) = Rec (mapSnd (go' su) <$> xes)+ go su (NonRec x e) = NonRec x (go' su e)++ go' su (App (Var x) _) | isFailId x, Just e <- getFailExpr x su = e+ go' su (Let (NonRec x ex) e) | isFailId x = go' (addFailExpr x (go' su ex) su) e++ go' su (App e1 e2) = App (go' su e1) (go' su e2)+ go' su (Lam x e) = Lam x (go' su e)+ go' su (Let xs e) = Let (go su xs) (go' su e)+ go' su (Case e x t alt) = Case (go' su e) x t (goalt su <$> alt)+ go' su (Cast e c) = Cast (go' su e) c+ go' su (Tick t e) = Tick t (go' su e)+ go' _ e = e++ goalt su (c, xs, e) = (c, xs, go' su e)++ isFailId x = isLocalId x && (isSystemName $ varName x) && L.isPrefixOf "fail" (show x)+ getFailExpr = L.lookup++ addFailExpr x (Lam _ e) su = (x, e):su+ addFailExpr _ _ _ = impossible Nothing "internal error" -- this cannot happen++isTypeError s | isInfixOf "Non term variable" (showSDoc s) = False+isTypeError _ = True++transformScope = outerScTr . innerScTr++outerScTr = mapNonRec (go [])+ where+ go ack x (xe : xes) | isCaseArg x xe = go (xe:ack) x xes+ go ack _ xes = ack ++ xes++isCaseArg x (NonRec _ (Case (Var z) _ _ _)) = z == x+isCaseArg _ _ = False++innerScTr = (mapBnd scTrans <$>)++scTrans x e = mapExpr scTrans $ foldr Let e0 bs+ where (bs, e0) = go [] x e+ go bs x (Let b e) | isCaseArg x b = go (b:bs) x e+ go bs x (Tick t e) = second (Tick t) $ go bs x e+ go bs _ e = (bs, e)++type TE = State TrEnv++data TrEnv = Tr { freshIndex :: !Int+ , _loc :: SrcSpan+ }++initEnv = Tr 0 noSrcSpan++transPg = mapM transBd++transBd (NonRec x e) = liftM (NonRec x) (transExpr =<< mapBdM transBd e)+transBd (Rec xes) = liftM Rec $ mapM (mapSndM (mapBdM transBd)) xes++transExpr :: CoreExpr -> TE CoreExpr+transExpr e+ | (isNonPolyRec e') && (not (null tvs))+ = trans tvs ids bs e'+ | otherwise+ = return e+ where (tvs, ids, e'') = collectTyAndValBinders e+ (bs, e') = collectNonRecLets e''++isNonPolyRec (Let (Rec xes) _) = any nonPoly (snd <$> xes)+isNonPolyRec _ = False++nonPoly = null . fst . splitForAllTys . exprType++collectNonRecLets = go []+ where go bs (Let b@(NonRec _ _) e') = go (b:bs) e'+ go bs e' = (reverse bs, e')++appTysAndIds tvs ids x = mkApps (mkTyApps (Var x) (map TyVarTy tvs)) (map Var ids)++trans vs ids bs (Let (Rec xes) e)+ = liftM (mkLam . mkLet) (makeTrans vs liveIds e')+ where liveIds = mkAlive <$> ids+ mkLet e = foldr Let e bs+ mkLam e = foldr Lam e $ vs ++ liveIds+ e' = Let (Rec xes') e+ xes' = (second mkLet) <$> xes++trans _ _ _ _ = panic Nothing "TransformRec.trans called with invalid input"++makeTrans vs ids (Let (Rec xes) e)+ = do fids <- mapM (mkFreshIds vs ids) xs+ let (ids', ys) = unzip fids+ let yes = appTysAndIds vs ids <$> ys+ ys' <- mapM fresh xs+ let su = M.fromList $ zip xs (Var <$> ys')+ let rs = zip ys' yes+ let es' = zipWith (mkE ys) ids' es+ let xes' = zip ys es'+ return $ mkRecBinds rs (Rec xes') (sub su e)+ where+ (xs, es) = unzip xes+ mkSu ys ids' = mkSubs ids vs ids' (zip xs ys)+ mkE ys ids' e' = mkCoreLams (vs ++ ids') (sub (mkSu ys ids') e')++makeTrans _ _ _ = panic Nothing "TransformRec.makeTrans called with invalid input"++mkRecBinds :: [(b, Expr b)] -> Bind b -> Expr b -> Expr b+mkRecBinds xes rs e = Let rs (foldl' f e xes)+ where f e (x, xe) = Let (NonRec x xe) e++mkSubs ids tvs xs ys = M.fromList $ s1 ++ s2+ where s1 = (second (appTysAndIds tvs xs)) <$> ys+ s2 = zip ids (Var <$> xs)++mkFreshIds tvs ids x+ = do ids' <- mapM fresh ids+ let t = mkForAllTys tvs $ mkType (reverse ids') $ varType x+ let x' = setVarType x t+ return (ids', x')+ where+ mkType ids ty = foldl (\t x -> FunTy (varType x) t) ty ids++class Freshable a where+ fresh :: a -> TE a++instance Freshable Int where+ fresh _ = freshInt++instance Freshable Unique where+ fresh _ = freshUnique++instance Freshable Var where+ fresh v = liftM (setVarUnique v) freshUnique++freshInt+ = do s <- get+ let n = freshIndex s+ put s{freshIndex = n+1}+ return n++freshUnique = liftM (mkUnique 'X') freshInt++mkAlive x+ | isId x && isDeadOcc (idOccInfo x)+ = setIdInfo x (setOccInfo (idInfo x) NoOccInfo)+ | otherwise+ = x++mapNonRec f (NonRec x xe:xes) = NonRec x xe : f x (mapNonRec f xes)+mapNonRec f (xe:xes) = xe : mapNonRec f xes+mapNonRec _ [] = []++mapBnd f (NonRec b e) = NonRec b (mapExpr f e)+mapBnd f (Rec bs) = Rec (map (second (mapExpr f)) bs)++mapExpr f (Let (NonRec x ex) e) = Let (NonRec x (f x ex) ) (f x e)+mapExpr f (App e1 e2) = App (mapExpr f e1) (mapExpr f e2)+mapExpr f (Lam b e) = Lam b (mapExpr f e)+mapExpr f (Let bs e) = Let (mapBnd f bs) (mapExpr f e)+mapExpr f (Case e b t alt) = Case e b t (map (mapAlt f) alt)+mapExpr f (Tick t e) = Tick t (mapExpr f e)+mapExpr _ e = e++mapAlt f (d, bs, e) = (d, bs, mapExpr f e)++-- Do not apply transformations to inner code++mapBdM _ = return++-- mapBdM f (Let b e) = liftM2 Let (f b) (mapBdM f e)+-- mapBdM f (App e1 e2) = liftM2 App (mapBdM f e1) (mapBdM f e2)+-- mapBdM f (Lam b e) = liftM (Lam b) (mapBdM f e)+-- mapBdM f (Case e b t alt) = liftM (Case e b t) (mapM (mapBdAltM f) alt)+-- mapBdM f (Tick t e) = liftM (Tick t) (mapBdM f e)+-- mapBdM _ e = return e+--+-- mapBdAltM f (d, bs, e) = liftM ((,,) d bs) (mapBdM f e)
+ src/Language/Haskell/Liquid/Transforms/RefSplit.hs view
@@ -0,0 +1,107 @@+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE UndecidableInstances #-}++module Language.Haskell.Liquid.Transforms.RefSplit (++ splitXRelatedRefs++ ) where++import Prelude hiding (error)++import Data.List (partition)+import Text.PrettyPrint.HughesPJ++import Language.Haskell.Liquid.Types+import Language.Haskell.Liquid.Types.PrettyPrint ()++import Language.Fixpoint.Types+import Language.Fixpoint.Misc++splitXRelatedRefs :: Symbol -> SpecType -> (SpecType, SpecType)+splitXRelatedRefs x t = splitRType x t++++splitRType f (RVar a r) = (RVar a r1, RVar a r2)+ where+ (r1, r2) = splitRef f r+splitRType f (RFun x tx t r) = (RFun x tx1 t1 r1, RFun x tx2 t2 r2)+ where+ (tx1, tx2) = splitRType f tx+ (t1, t2) = splitRType f t+ (r1, r2) = splitRef f r+splitRType f (RAllT v t) = (RAllT v t1, RAllT v t2)+ where+ (t1, t2) = splitRType f t+splitRType f (RAllP p t) = (RAllP p t1, RAllP p t2)+ where+ (t1, t2) = splitRType f t+splitRType f (RAllS s t) = (RAllS s t1, RAllS s t2)+ where+ (t1, t2) = splitRType f t+splitRType f (RApp c ts rs r) = (RApp c ts1 rs1 r1, RApp c ts2 rs2 r2)+ where+ (ts1, ts2) = unzip (splitRType f <$> ts)+ (rs1, rs2) = unzip (splitUReft f <$> rs)+ (r1, r2) = splitRef f r+splitRType f (RAllE x tx t) = (RAllE x tx1 t1, RAllE x tx2 t2)+ where+ (tx1, tx2) = splitRType f tx+ (t1, t2) = splitRType f t+splitRType f (REx x tx t) = (REx x tx1 t1, REx x tx2 t2)+ where+ (tx1, tx2) = splitRType f tx+ (t1, t2) = splitRType f t+splitRType _ (RExprArg e) = (RExprArg e, RExprArg e)+splitRType f (RAppTy tx t r) = (RAppTy tx1 t1 r1, RAppTy tx2 t2 r2)+ where+ (tx1, tx2) = splitRType f tx+ (t1, t2) = splitRType f t+ (r1, r2) = splitRef f r+splitRType f (RRTy xs r o t) = (RRTy xs1 r1 o t1, RRTy xs2 r2 o t2)+ where+ (xs1, xs2) = unzip (go <$> xs)+ (r1, r2) = splitRef f r+ (t1, t2) = splitRType f t++ go (x, t) = let (t1, t2) = splitRType f t in ((x,t1), (x, t2))+splitRType f (RHole r) = (RHole r1, RHole r2)+ where+ (r1, r2) = splitRef f r+++splitUReft :: Symbol -> RTProp c tv (UReft Reft) -> (RTProp c tv (UReft Reft), RTProp c tv (UReft Reft))+splitUReft x (RProp xs (RHole r)) = (RProp xs (RHole r1), RProp xs (RHole r2))+ where+ (r1, r2) = splitRef x r+splitUReft x (RProp xs t) = (RProp xs t1, RProp xs t2)+ where+ (t1, t2) = splitRType x t++splitRef f (MkUReft r p s) = (MkUReft r1 p1 s, MkUReft r2 p2 s)+ where+ (r1, r2) = splitReft f r+ (p1, p2) = splitPred f p+splitReft f (Reft (v, xs)) = (Reft (v, pAnd xs1), Reft (v, pAnd xs2))+ where+ (xs1, xs2) = partition (isFree f) (unPAnd xs)++ unPAnd (PAnd ps) = concatMap unPAnd ps+ unPAnd p = [p]+++splitPred f (Pr ps) = (Pr ps1, Pr ps2)+ where+ (ps1, ps2) = partition g ps+ g p = any (isFree f) (thd3 <$> pargs p)+++class IsFree a where+ isFree :: Symbol -> a -> Bool++instance (Subable x) => (IsFree x) where+ isFree x p = x `elem` syms p++instance Show (UReft Reft) where+ show = render . pprint
+ src/Language/Haskell/Liquid/Transforms/Simplify.hs view
@@ -0,0 +1,43 @@+module Language.Haskell.Liquid.Transforms.Simplify (simplifyBounds) where++import Prelude hiding (error)+import Language.Haskell.Liquid.Types+import Language.Fixpoint.Types+import Language.Fixpoint.Types.Visitor+-- import Control.Applicative ((<$>))+++simplifyBounds :: SpecType -> SpecType+simplifyBounds = fmap go+ where+ go x = x { ur_reft = go' $ ur_reft x }+ -- OLD go' (Reft (v, rs)) = Reft(v, filter (not . isBoundLike) rs)+ go' (Reft (v, p)) = Reft(v, dropBoundLike p)++dropBoundLike :: Expr -> Expr+dropBoundLike p+ | isKvar p = p+ | isBoundLikePred p = mempty+ | otherwise = p+ where+ isKvar = not . null . kvars++isBoundLikePred :: Expr -> Bool+isBoundLikePred (PAnd ps) = simplifyLen <= length [p | p <- ps, isImp p ]+isBoundLikePred _ = False++isImp :: Expr -> Bool+isImp (PImp _ _) = True+isImp _ = False++-- OLD isBoundLike (RConc pred) = isBoundLikePred pred+-- OLD isBoundLike (RKvar _ _) = False+++-- OLD moreThan 0 _ = True+-- OLD moreThan _ [] = False+-- OLD moreThan i (True : xs) = moreThan (i-1) xs+-- OLD moreThan i (False : xs) = moreThan i xs++simplifyLen :: Int+simplifyLen = 5
src/Language/Haskell/Liquid/Types.hs view
@@ -1,1857 +1,1662 @@ {-# LANGUAGE StandaloneDeriving #-} {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveFunctor #-}-{-# LANGUAGE DeriveGeneric #-}-{-# LANGUAGE DeriveFoldable #-}-{-# LANGUAGE DeriveTraversable #-}-{-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE TypeSynonymInstances #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE OverlappingInstances #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE RecordWildCards #-}---- | This module should contain all the global type definitions and basic instances.--{-@ LIQUID "--cabaldir" @-}--module Language.Haskell.Liquid.Types (-- -- * Options- Config (..)-- -- * Ghc Information- , GhcInfo (..)- , GhcSpec (..)- , TargetVars (..)-- -- * Located Things- , Located (..)- , dummyLoc-- -- * Symbols- , LocSymbol- , LocText-- -- * Default unknown name- , dummyName, isDummy-- -- * Refined Type Constructors- , RTyCon (RTyCon, rtc_tc, rtc_info)- , TyConInfo(..), defaultTyConInfo- , rTyConPVs- , rTyConPropVs- , isClassRTyCon, isClassType-- -- * Refinement Types- , RType (..), Ref(..), RTProp- , RTyVar (..)- , RTAlias (..)-- -- * Worlds- , HSeg (..)- , World (..)-- -- * Classes describing operations on `RTypes`- , TyConable (..)- , RefTypable (..)- , SubsTy (..)-- -- * Predicate Variables- , PVar (PV, pname, parg, ptype, pargs), isPropPV, pvType- , PVKind (..)- , Predicate (..)-- -- * Refinements- , UReft(..)-- -- * Parse-time entities describing refined data types- , DataDecl (..)- , DataConP (..)- , TyConP (..)-- -- * Pre-instantiated RType- , RRType, BRType, RRProp- , BSort, BPVar-- -- * Instantiated RType- , BareType, PrType- , SpecType, SpecProp- , RSort- , UsedPVar, RPVar, RReft- , REnv (..)-- -- * Constructing & Destructing RTypes- , RTypeRep(..), fromRTypeRep, toRTypeRep- , mkArrow, bkArrowDeep, bkArrow, safeBkArrow- , mkUnivs, bkUniv, bkClass- , rFun, rCls, rRCls-- -- * Manipulating `Predicates`- , pvars, pappSym, pApp-- -- * Some tests on RTypes- , isBase- , isFunTy- , isTrivial-- -- * Traversing `RType`- , efoldReft, foldReft- , mapReft, mapReftM- , mapBot, mapBind-- -- * ???- , Oblig(..)- , ignoreOblig- , addTermCond- , addInvCond--- -- * Inferred Annotations- , AnnInfo (..)- , Annot (..)-- -- * Overall Output- , Output (..)-- -- * Refinement Hole- , hole, isHole, hasHole-- -- * Converting To and From Sort- , ofRSort, toRSort- , rTypeValueVar- , rTypeReft- , stripRTypeBase-- -- * Class for values that can be pretty printed- , PPrint (..)- , showpp-- -- * Printer Configuration- , PPEnv (..)- , Tidy (..)- , ppEnv- , ppEnvShort-- -- * Modules and Imports- , ModName (..), ModType (..)- , isSrcImport, isSpecImport- , getModName, getModString-- -- * Refinement Type Aliases- , RTEnv (..)- , mapRT, mapRP, mapRE-- -- * Final Result- , Result (..)-- -- * Errors and Error Messages- , Error- , TError (..)- , EMsg (..)- -- , LParseError (..)- , ErrorResult- , errSpan- , errOther- , errToFCrash-- -- * Source information (associated with constraints)- , Cinfo (..)-- -- * Measures- , Measure (..)- , CMeasure (..)- , Def (..)- , Body (..)-- -- * Type Classes- , RClass (..)-- -- * KV Profiling- , KVKind (..) -- types of kvars- , KVProf -- profile table- , emptyKVProf -- empty profile- , updKVProf -- extend profile-- -- * Misc- , mapRTAVars- , insertsSEnv-- -- * Strata- , Stratum(..), Strata- , isSVar- , getStrata- , makeDivType, makeFinType-- -- * CoreToLogic- , LogicMap, toLogicMap, eAppWithMap, LMap(..)-- -- * Refined Instances- , RDEnv, DEnv(..), RInstance(..)-- -- * Ureftable Instances- , UReftable(..)-- -- * String Literals- , liquidBegin, liquidEnd- )- where--import SrcLoc (noSrcSpan, SrcSpan)-import TyCon-import DataCon-import NameSet-import Module (moduleNameFS)-import TypeRep hiding (maybeParen, pprArrowChain)-import Var-import Text.Printf-import GHC (HscEnv, ModuleName, moduleNameString)-import GHC.Generics-import Language.Haskell.Liquid.GhcMisc--import PrelInfo (isNumericClass)---import TysWiredIn (listTyCon)-import Control.Arrow (second)-import Control.Monad (liftM, liftM2, liftM3, liftM4)-import qualified Control.Monad.Error as Ex-import Control.DeepSeq-import Control.Applicative ((<$>))-import Data.Typeable (Typeable)-import Data.Generics (Data)-import Data.Monoid hiding ((<>))-import qualified Data.Foldable as F-import Data.Hashable-import qualified Data.HashMap.Strict as M-import qualified Data.HashSet as S-import Data.Maybe (fromMaybe)-import Data.Traversable hiding (mapM)-import Data.List (nub)-import Data.Text (Text)-import qualified Data.Text as T-import Text.Parsec.Pos (SourcePos)-import Text.Parsec.Error (ParseError)-import Text.PrettyPrint.HughesPJ-import Language.Fixpoint.Config hiding (Config)-import Language.Fixpoint.Misc-import Language.Fixpoint.Types hiding (Result, Predicate, Def, R)-import Language.Fixpoint.Names (funConName, listConName, tupConName)-import qualified Language.Fixpoint.PrettyPrint as F-import CoreSyn (CoreBind)--import Language.Haskell.Liquid.Variance-import Language.Haskell.Liquid.Misc (mapSndM, safeZip3WithError)---import Data.Default--------------------------------------------------------------------------------- | Command Line Config Options ------------------------------------------------------------------------------------------------------------------------------ NOTE: adding strictness annotations breaks the help message-data Config = Config {- files :: [FilePath] -- ^ source files to check- , idirs :: [FilePath] -- ^ path to directory for including specs- , diffcheck :: Bool -- ^ check subset of binders modified (+ dependencies) since last check- , real :: Bool -- ^ supports real number arithmetic- , fullcheck :: Bool -- ^ check all binders (overrides diffcheck)- , native :: Bool -- ^ use native (Haskell) fixpoint constraint solver- , binders :: [String] -- ^ set of binders to check- , noCheckUnknown :: Bool -- ^ whether to complain about specifications for unexported and unused values- , notermination :: Bool -- ^ disable termination check- , nowarnings :: Bool -- ^ disable warnings output (only show errors)- , trustinternals :: Bool -- ^ type all internal variables with true- , nocaseexpand :: Bool -- ^ disable case expand- , strata :: Bool -- ^ enable strata analysis- , notruetypes :: Bool -- ^ disable truing top level types- , totality :: Bool -- ^ check totality in definitions- , noPrune :: Bool -- ^ disable prunning unsorted Refinements- , maxParams :: Int -- ^ the maximum number of parameters to accept when mining qualifiers- , smtsolver :: Maybe SMTSolver -- ^ name of smtsolver to use [default: try z3, cvc4, mathsat in order]- , shortNames :: Bool -- ^ drop module qualifers from pretty-printed names.- , shortErrors :: Bool -- ^ don't show subtyping errors and contexts.- , cabalDir :: Bool -- ^ find and use .cabal file to include paths to sources for imported modules- , ghcOptions :: [String] -- ^ command-line options to pass to GHC- , cFiles :: [String] -- ^ .c files to compile and link against (for GHC)- } deriving (Data, Typeable, Show, Eq)----------------------------------------------------------------------------------- | Printer ------------------------------------------------------------------------------------------------------------------------------------------------data Tidy = Lossy | Full deriving (Eq, Ord)--class PPrint a where- pprint :: a -> Doc-- pprintTidy :: Tidy -> a -> Doc- pprintTidy _ = pprint--showpp :: (PPrint a) => a -> String-showpp = render . pprint--instance PPrint a => PPrint (Maybe a) where- pprint = maybe (text "Nothing") ((text "Just" <+>) . pprint)--instance PPrint a => PPrint [a] where- pprint = brackets . intersperse comma . map pprint--instance (PPrint a, PPrint b) => PPrint (a,b) where- pprint (x, y) = pprint x <+> text ":" <+> pprint y--data PPEnv- = PP { ppPs :: Bool- , ppTyVar :: Bool -- TODO if set to True all Bare fails- , ppSs :: Bool- , ppShort :: Bool- }--ppEnv = ppEnvPrintPreds-_ppEnvCurrent = PP False False False False-ppEnvPrintPreds = PP False False False False-ppEnvShort pp = pp { ppShort = True }------------------------------------------------------------------------- | GHC Information : Code & Spec ---------------------------------------------------------------------------------------------------data GhcInfo = GI {- env :: !HscEnv- , cbs :: ![CoreBind]- , derVars :: ![Var]- , impVars :: ![Var]- , defVars :: ![Var]- , useVars :: ![Var]- , hqFiles :: ![FilePath]- , imports :: ![String]- , includes :: ![FilePath]- , spec :: !GhcSpec- }---- | The following is the overall type for /specifications/ obtained from--- parsing the target source and dependent libraries--data GhcSpec = SP {- tySigs :: ![(Var, Located SpecType)] -- ^ Asserted Reftypes- -- eg. see include/Prelude.spec- , asmSigs :: ![(Var, Located SpecType)] -- ^ Assumed Reftypes- , ctors :: ![(Var, Located SpecType)] -- ^ Data Constructor Measure Sigs- -- eg. (:) :: a -> xs:[a] -> {v: Int | v = 1 + len(xs) }- , meas :: ![(Symbol, Located SpecType)] -- ^ Measure Types- -- eg. len :: [a] -> Int- , invariants :: ![Located SpecType] -- ^ Data Type Invariants- -- eg. forall a. {v: [a] | len(v) >= 0}- , ialiases :: ![(Located SpecType, Located SpecType)] -- ^ Data Type Invariant Aliases- , dconsP :: ![(DataCon, DataConP)] -- ^ Predicated Data-Constructors- -- e.g. see tests/pos/Map.hs- , tconsP :: ![(TyCon, TyConP)] -- ^ Predicated Type-Constructors- -- eg. see tests/pos/Map.hs- , freeSyms :: ![(Symbol, Var)] -- ^ List of `Symbol` free in spec and corresponding GHC var- -- eg. (Cons, Cons#7uz) from tests/pos/ex1.hs- , tcEmbeds :: TCEmb TyCon -- ^ How to embed GHC Tycons into fixpoint sorts- -- e.g. "embed Set as Set_set" from include/Data/Set.spec- , qualifiers :: ![Qualifier] -- ^ Qualifiers in Source/Spec files- -- e.g tests/pos/qualTest.hs- , tgtVars :: ![Var] -- ^ Top-level Binders To Verify (empty means ALL binders)- , decr :: ![(Var, [Int])] -- ^ Lexicographically ordered size witnesses for termination- , texprs :: ![(Var, [Expr])] -- ^ Lexicographically ordered expressions for termination- , lvars :: !(S.HashSet Var) -- ^ Variables that should be checked in the environment they are used- , lazy :: !(S.HashSet Var) -- ^ Binders to IGNORE during termination checking- , autosize :: !(S.HashSet TyCon) -- ^ Binders to IGNORE during termination checking- , config :: !Config -- ^ Configuration Options- , exports :: !NameSet -- ^ `Name`s exported by the module being verified- , measures :: [Measure SpecType DataCon]- , tyconEnv :: M.HashMap TyCon RTyCon- , dicts :: DEnv Var SpecType -- ^ Dictionary Environment- }--type LogicMap = M.HashMap Symbol LMap--data LMap = LMap { lvar :: Symbol- , largs :: [Symbol]- , lexpr :: Expr- }--instance Show LMap where- show (LMap x xs e) = show x ++ " " ++ show xs ++ "\t|->\t" ++ show e---toLogicMap = M.fromList . map toLMap- where- toLMap (x, xs, e) = (x, LMap {lvar = x, largs = xs, lexpr = e})--eAppWithMap lmap f es def- | Just (LMap _ xs e) <- M.lookup (val f) lmap- = subst (mkSubst $ zip xs es) e- | otherwise- = def---data TyConP = TyConP { freeTyVarsTy :: ![RTyVar]- , freePredTy :: ![PVar RSort]- , freeLabelTy :: ![Symbol]- , varianceTs :: !VarianceInfo- , variancePs :: !VarianceInfo- , sizeFun :: !(Maybe (Symbol -> Expr))- } deriving (Generic, Data, Typeable)--data DataConP = DataConP { dc_loc :: !SourcePos- , freeTyVars :: ![RTyVar]- , freePred :: ![PVar RSort]- , freeLabels :: ![Symbol]- , tyConsts :: ![SpecType] -- ^ FIXME: WHAT IS THIS??- , tyArgs :: ![(Symbol, SpecType)] -- ^ These are backwards, why??- , tyRes :: !SpecType- , dc_locE :: !SourcePos- } deriving (Generic, Data, Typeable)---- instance {-# OVERLAPPING #-} Data TyConP--- instance {-# OVERLAPPING #-} Data DataConP---- | Which Top-Level Binders Should be Verified-data TargetVars = AllVars | Only ![Var]-------------------------------------------------------------------------- | Abstract Predicate Variables ---------------------------------------------------------------------------------------------------------data PVar t- = PV { pname :: !Symbol- , ptype :: !(PVKind t)- , parg :: !Symbol- , pargs :: ![(t, Symbol, Expr)]- }- deriving (Generic, Data, Typeable, Show)--pvType p = case ptype p of- PVProp t -> t- PVHProp -> errorstar "pvType on HProp-PVar"--data PVKind t- = PVProp t | PVHProp- deriving (Generic, Data, Typeable, F.Foldable, Traversable, Show)--instance Eq (PVar t) where- pv == pv' = pname pv == pname pv' {- UNIFY: What about: && eqArgs pv pv' -}--instance Ord (PVar t) where- compare (PV n _ _ _) (PV n' _ _ _) = compare n n'--instance Functor PVKind where- fmap f (PVProp t) = PVProp (f t)- fmap _ (PVHProp) = PVHProp--instance Functor PVar where- fmap f (PV x t v txys) = PV x (f <$> t) v (mapFst3 f <$> txys)--instance (NFData a) => NFData (PVKind a) where- rnf (PVProp t) = rnf t- rnf (PVHProp) = ()--instance (NFData a) => NFData (PVar a) where- rnf (PV n t v txys) = rnf n `seq` rnf v `seq` rnf t `seq` rnf txys--instance Hashable (PVar a) where- hashWithSalt i (PV n _ _ _) = hashWithSalt i n------------------------------------------------------------------------------- Strictness -------------------------------------------------------------------------------------------------------------------------instance NFData Var where- rnf x = seq x ()--instance NFData SrcSpan where- rnf x = seq x ()----------------------------------------------------------------------------------------- Predicates -------------------------------------------------------------------------------------------------------------type UsedPVar = PVar ()-newtype Predicate = Pr [UsedPVar] deriving (Generic, Data, Typeable)--instance NFData Predicate where- rnf _ = ()--instance Monoid Predicate where- mempty = pdTrue- mappend p p' = pdAnd [p, p']--instance (Monoid a) => Monoid (UReft a) where- mempty = U mempty mempty mempty- mappend (U x y z) (U x' y' z') = U (mappend x x') (mappend y y') (mappend z z')---pdTrue = Pr []-pdAnd ps = Pr (nub $ concatMap pvars ps)-pvars (Pr pvs) = pvs--instance Subable UsedPVar where- syms pv = [ y | (_, x, EVar y) <- pargs pv, x /= y ]- subst s pv = pv { pargs = mapThd3 (subst s) <$> pargs pv }- substf f pv = pv { pargs = mapThd3 (substf f) <$> pargs pv }- substa f pv = pv { pargs = mapThd3 (substa f) <$> pargs pv }---instance Subable Predicate where- syms (Pr pvs) = concatMap syms pvs- subst s (Pr pvs) = Pr (subst s <$> pvs)- substf f (Pr pvs) = Pr (substf f <$> pvs)- substa f (Pr pvs) = Pr (substa f <$> pvs)--instance Subable Qualifier where- syms = syms . q_body- subst = mapQualBody . subst- substf = mapQualBody . substf- substa = mapQualBody . substa--mapQualBody f q = q { q_body = f (q_body q) }--instance NFData r => NFData (UReft r) where- rnf (U r p s) = rnf r `seq` rnf p `seq` rnf s--instance NFData Strata where- rnf _ = ()--instance NFData PrType where- rnf _ = ()--instance NFData RTyVar where- rnf _ = ()----- MOVE TO TYPES-newtype RTyVar = RTV TyVar deriving (Generic, Data, Typeable)--instance Symbolic RTyVar where- symbol (RTV tv) = symbol . T.pack . showPpr $ tv---data RTyCon = RTyCon- { rtc_tc :: TyCon -- ^ GHC Type Constructor- , rtc_pvars :: ![RPVar] -- ^ Predicate Parameters- , rtc_info :: !TyConInfo -- ^ TyConInfo- }- deriving (Generic, Data, Typeable)---- | Accessors for @RTyCon@---isClassRTyCon = isClassTyCon . rtc_tc-rTyConPVs = rtc_pvars-rTyConPropVs = filter isPropPV . rtc_pvars-isPropPV = isProp . ptype----isClassType (RApp c _ _ _) = isClass c-isClassType _ = False---- rTyConPVHPs = filter isHPropPV . rtc_pvars--- isHPropPV = not . isPropPV--isProp (PVProp _) = True-isProp _ = False---defaultTyConInfo = TyConInfo [] [] Nothing--instance Default TyConInfo where- def = defaultTyConInfo----------------------------------------------------------------------------- | Co- and Contra-variance for TyCon ------------------------------------------------------------------------------------------------------------ | Indexes start from 0 and type or predicate arguments can be both--- covariant and contravaariant e.g., for the below Foo dataType------ data Foo a b c d <p :: b -> Prop, q :: Int -> Prop, r :: a -> Prop>--- = F (a<r> -> b<p>) | Q (c -> a) | G (Int<q> -> a<r>)------ there will be:------ varianceTyArgs = [Bivariant , Covariant, Contravatiant, Invariant]--- variancePsArgs = [Covariant, Contravatiant, Bivariant]-----data TyConInfo = TyConInfo- { varianceTyArgs :: !VarianceInfo -- ^ variance info for type variables- , variancePsArgs :: !VarianceInfo -- ^ variance info for predicate variables- , sizeFunction :: !(Maybe (Symbol -> Expr)) -- ^ logical function that computes the size of the structure- } deriving (Generic, Data, Typeable)---- instance {-# OVERLAPPING #-} Data TyConInfo--instance Show TyConInfo where- show (TyConInfo x y _) = show x ++ "\n" ++ show y--------------------------------------------------------------------------- Unified Representation of Refinement Types --------------------------------------------------------------------------------------------- MOVE TO TYPES-data RType c tv r- = RVar {- rt_var :: !tv- , rt_reft :: !r- }-- | RFun {- rt_bind :: !Symbol- , rt_in :: !(RType c tv r)- , rt_out :: !(RType c tv r)- , rt_reft :: !r- }-- | RAllT {- rt_tvbind :: !tv- , rt_ty :: !(RType c tv r)- }-- | RAllP {- rt_pvbind :: !(PVar (RType c tv ()))- , rt_ty :: !(RType c tv r)- }-- | RAllS {- rt_sbind :: !(Symbol)- , rt_ty :: !(RType c tv r)- }-- | RApp {- rt_tycon :: !c- , rt_args :: ![RType c tv r]- , rt_pargs :: ![RTProp c tv r]- , rt_reft :: !r- }-- | RAllE {- rt_bind :: !Symbol- , rt_allarg :: !(RType c tv r)- , rt_ty :: !(RType c tv r)- }-- | REx {- rt_bind :: !Symbol- , rt_exarg :: !(RType c tv r)- , rt_ty :: !(RType c tv r)- }-- | RExprArg (Located Expr) -- ^ For expression arguments to type aliases- -- see tests/pos/vector2.hs- | RAppTy{- rt_arg :: !(RType c tv r)- , rt_res :: !(RType c tv r)- , rt_reft :: !r- }-- | RRTy {- rt_env :: ![(Symbol, RType c tv r)]- , rt_ref :: !r- , rt_obl :: !Oblig- , rt_ty :: !(RType c tv r)- }-- | RHole r -- ^ let LH match against the Haskell type and add k-vars, e.g. `x:_`- -- see tests/pos/Holes.hs- deriving (Generic, Data, Typeable)--data Oblig- = OTerm -- ^ Obligation that proves termination- | OInv -- ^ Obligation that proves invariants- | OCons -- ^ Obligation that proves constraints- deriving (Generic, Data, Typeable)--ignoreOblig (RRTy _ _ _ t) = t-ignoreOblig t = t--instance Show Oblig where- show OTerm = "termination-condition"- show OInv = "invariant-obligation"- show OCons = "constraint-obligation"--instance PPrint Oblig where- pprint = text . show---- | @Ref@ describes `Prop τ` and `HProp` arguments applied to type constructors.--- For example, in [a]<{\h -> v > h}>, we apply (via `RApp`)--- * the `RProp` denoted by `{\h -> v > h}` to--- * the `RTyCon` denoted by `[]`.--- Thus, @Ref@ is used for abstract-predicate (arguments) that are associated--- with _type constructors_ i.e. whose semantics are _dependent upon_ the data-type.--- In contrast, the `Predicate` argument in `ur_pred` in the @UReft@ applies--- directly to any type and has semantics _independent of_ the data-type.--data Ref τ r t- = RPropP {- rf_args :: [(Symbol, τ)]- , rf_reft :: r- } -- ^ Parse-time `RProp`-- | RProp {- rf_args :: [(Symbol, τ)]- , rf_body :: t- } -- ^ Abstract refinement associated with `RTyCon`-- | RHProp {- rf_args :: [(Symbol, τ)]- , rf_heap :: World t- } -- ^ Abstract heap-refinement associated with `RTyCon`- deriving (Generic, Data, Typeable)---- | @RTProp@ is a convenient alias for @Ref@ that will save a bunch of typing.--- In general, perhaps we need not expose @Ref@ directly at all.-type RTProp c tv r = Ref (RType c tv ()) r (RType c tv r)----- | A @World@ is a Separation Logic predicate that is essentially a sequence of binders--- that satisfies two invariants (TODO:LIQUID):--- 1. Each `hs_addr :: Symbol` appears at most once,--- 2. There is at most one `HVar` in a list.--newtype World t = World [HSeg t]- deriving (Generic, Data, Typeable)--data HSeg t = HBind {hs_addr :: !Symbol, hs_val :: t}- | HVar UsedPVar- deriving (Generic, Data, Typeable)--data UReft r- = U { ur_reft :: !r, ur_pred :: !Predicate, ur_strata :: !Strata }- deriving (Generic, Data, Typeable)--type BRType = RType LocSymbol Symbol-type RRType = RType RTyCon RTyVar--type BSort = BRType ()-type RSort = RRType ()--type BPVar = PVar BSort-type RPVar = PVar RSort--type RReft = UReft Reft-type PrType = RRType Predicate-type BareType = BRType RReft-type SpecType = RRType RReft-type SpecProp = RRProp RReft-type RRProp r = Ref RSort r (RRType r)---data Stratum = SVar Symbol | SDiv | SWhnf | SFin- deriving (Generic, Data, Typeable, Eq)--type Strata = [Stratum]--isSVar (SVar _) = True-isSVar _ = False--instance Monoid Strata where- mempty = []- mappend s1 s2 = nub $ s1 ++ s2--class SubsTy tv ty a where- subt :: (tv, ty) -> a -> a--class (Eq c) => TyConable c where- isFun :: c -> Bool- isList :: c -> Bool- isTuple :: c -> Bool- ppTycon :: c -> Doc- isClass :: c -> Bool-- isNumCls :: c -> Bool- isFracCls :: c -> Bool-- isClass = const False- isNumCls = const False- isFracCls = const False--class ( TyConable c- , Eq c, Eq tv- , Hashable tv- , Reftable r- , PPrint r- ) => RefTypable c tv r- where--- ppCls :: p -> [RType c tv r] -> Doc- ppRType :: Prec -> RType c tv r -> Doc-------------------------------------------------------------------------------------- | TyConable Instances ------------------------------------------------------------------------------------------------------------------------------------------- MOVE TO TYPES-instance TyConable RTyCon where- isFun = isFunTyCon . rtc_tc- isList = (listTyCon ==) . rtc_tc- isTuple = TyCon.isTupleTyCon . rtc_tc- isClass = isClassRTyCon- ppTycon = toFix-- isNumCls c = maybe False isNumericClass (tyConClass_maybe $ rtc_tc c)- isFracCls c = maybe False isFractionalClass (tyConClass_maybe $ rtc_tc c)---- MOVE TO TYPES-instance TyConable Symbol where- isFun s = funConName == s- isList s = listConName == s- isTuple s = tupConName == s- ppTycon = text . symbolString--instance TyConable LocSymbol where- isFun = isFun . val- isList = isList . val- isTuple = isTuple . val- ppTycon = ppTycon . val---instance Eq RTyCon where- x == y = rtc_tc x == rtc_tc y--instance Fixpoint RTyCon where- toFix (RTyCon c _ _) = text $ showPpr c -- <+> text "\n<<" <+> hsep (map toFix ts) <+> text ">>\n"--instance Fixpoint Cinfo where- toFix = text . showPpr . ci_loc--instance PPrint RTyCon where- pprint = text . showPpr . rtc_tc---instance Show RTyCon where- show = showpp------------------------------------------------------------------------------- | Refined Instances --------------------------------------------------------------------------------------------------------------------------------data RInstance t = RI { riclass :: LocSymbol- , ritype :: t- , risigs :: [(LocSymbol, t)]- }--newtype DEnv x ty = DEnv (M.HashMap x (M.HashMap Symbol ty)) deriving (Monoid)--type RDEnv = DEnv Var SpecType--instance Functor RInstance where- fmap f (RI x t xts) = RI x (f t) (mapSnd f <$> xts)-------------------------------------------------------------------------------- | Values Related to Specifications -------------------------------------------------------------------------------------------------------------------- | Data type refinements-data DataDecl = D { tycName :: LocSymbol- -- ^ Type Constructor Name- , tycTyVars :: [Symbol]- -- ^ Tyvar Parameters- , tycPVars :: [PVar BSort]- -- ^ PVar Parameters- , tycTyLabs :: [Symbol]- -- ^ PLabel Parameters- , tycDCons :: [(LocSymbol, [(Symbol, BareType)])]- -- ^ [DataCon, [(fieldName, fieldType)]]- , tycSrcPos :: !SourcePos- -- ^ Source Position- , tycSFun :: (Maybe (Symbol -> Expr))- -- ^ Measure that should decrease in recursive calls- }- -- deriving (Show)---instance Eq DataDecl where- d1 == d2 = (tycName d1) == (tycName d2)--instance Ord DataDecl where- compare d1 d2 = compare (tycName d1) (tycName d2)---- | For debugging.-instance Show DataDecl where- show dd = printf "DataDecl: data = %s, tyvars = %s"- (show $ tycName dd)- (show $ tycTyVars dd)---- | Refinement Type Aliases--data RTAlias tv ty- = RTA { rtName :: Symbol- , rtTArgs :: [tv]- , rtVArgs :: [tv]- , rtBody :: ty- , rtPos :: SourcePos- , rtPosE :: SourcePos- }--mapRTAVars f rt = rt { rtTArgs = f <$> rtTArgs rt- , rtVArgs = f <$> rtVArgs rt- }----------------------------------------------------------------------------- | Constructor and Destructors for RTypes -------------------------------------------------------------------------------------------------------data RTypeRep c tv r- = RTypeRep { ty_vars :: [tv]- , ty_preds :: [PVar (RType c tv ())]- , ty_labels :: [Symbol]- , ty_binds :: [Symbol]- , ty_refts :: [r]- , ty_args :: [RType c tv r]- , ty_res :: (RType c tv r)- }--fromRTypeRep (RTypeRep {..})- = mkArrow ty_vars ty_preds ty_labels arrs ty_res- where- arrs = safeZip3WithError "fromRTypeRep" ty_binds ty_args ty_refts--toRTypeRep :: RType c tv r -> RTypeRep c tv r-toRTypeRep t = RTypeRep αs πs ls xs rs ts t''- where- (αs, πs, ls, t') = bkUniv t- (xs, ts, rs, t'') = bkArrow t'--mkArrow αs πs ls xts = mkUnivs αs πs ls . mkArrs xts- where- mkArrs xts t = foldr (\(b,t1,r) t2 -> RFun b t1 t2 r) t xts--bkArrowDeep (RAllT _ t) = bkArrowDeep t-bkArrowDeep (RAllP _ t) = bkArrowDeep t-bkArrowDeep (RAllS _ t) = bkArrowDeep t-bkArrowDeep (RFun x t t' r) = let (xs, ts, rs, t'') = bkArrowDeep t' in (x:xs, t:ts, r:rs, t'')-bkArrowDeep t = ([], [], [], t)--bkArrow (RFun x t t' r) = let (xs, ts, rs, t'') = bkArrow t' in (x:xs, t:ts, r:rs, t'')-bkArrow t = ([], [], [], t)--safeBkArrow (RAllT _ _) = errorstar "safeBkArrow on RAllT"-safeBkArrow (RAllP _ _) = errorstar "safeBkArrow on RAllP"-safeBkArrow (RAllS _ t) = safeBkArrow t-safeBkArrow t = bkArrow t--mkUnivs αs πs ls t = foldr RAllT (foldr RAllP (foldr RAllS t ls) πs) αs--bkUniv :: RType t1 a t2 -> ([a], [PVar (RType t1 a ())], [Symbol], RType t1 a t2)-bkUniv (RAllT α t) = let (αs, πs, ls, t') = bkUniv t in (α:αs, πs, ls, t')-bkUniv (RAllP π t) = let (αs, πs, ls, t') = bkUniv t in (αs, π:πs, ls, t')-bkUniv (RAllS s t) = let (αs, πs, ss, t') = bkUniv t in (αs, πs, s:ss, t')-bkUniv t = ([], [], [], t)--bkClass (RFun _ (RApp c t _ _) t' _)- | isClass c- = let (cs, t'') = bkClass t' in ((c, t):cs, t'')-bkClass (RRTy e r o t)- = let (cs, t') = bkClass t in (cs, RRTy e r o t')-bkClass t- = ([], t)--rFun b t t' = RFun b t t' mempty-rCls c ts = RApp (RTyCon c [] defaultTyConInfo) ts [] mempty-rRCls rc ts = RApp rc ts [] mempty--addTermCond = addObligation OTerm--addInvCond :: SpecType -> RReft -> SpecType-addInvCond t r'- | isTauto $ ur_reft r' -- null rv- = t- | otherwise- = fromRTypeRep $ trep {ty_res = RRTy [(x', tbd)] r OInv tbd}- where- trep = toRTypeRep t- tbd = ty_res trep- r = r' {ur_reft = Reft (v, Refa rx)}- su = (v, EVar x')- x' = "xInv"- rx = PIff (PBexp $ EVar v) $ subst1 (raPred rv) su- Reft(v, rv) = ur_reft r'--addObligation :: Oblig -> SpecType -> RReft -> SpecType-addObligation o t r = mkArrow αs πs ls xts $ RRTy [] r o t2- where- (αs, πs, ls, t1) = bkUniv t- (xs, ts, rs, t2) = bkArrow t1- xts = zip3 xs ts rs------------------------------------------------instance Subable Stratum where- syms (SVar s) = [s]- syms _ = []- subst su (SVar s) = SVar $ subst su s- subst _ s = s- substf f (SVar s) = SVar $ substf f s- substf _ s = s- substa f (SVar s) = SVar $ substa f s- substa _ s = s--instance Subable Strata where- syms s = concatMap syms s- subst su = (subst su <$>)- substf f = (substf f <$>)- substa f = (substa f <$>)--instance Reftable Strata where- isTauto [] = True- isTauto _ = False-- ppTy _ = error "ppTy on Strata"- toReft _ = mempty- params s = [l | SVar l <- s]- bot _ = []- top _ = []-- ofReft = error "TODO: Strata.ofReft"---class Reftable r => UReftable r where- ofUReft :: UReft Reft -> r- ofUReft (U r _ _) = ofReft r---instance UReftable (UReft Reft) where- ofUReft r = r--instance UReftable () where- ofUReft _ = mempty--instance (PPrint r, Reftable r) => Reftable (UReft r) where- isTauto = isTauto_ureft- ppTy = ppTy_ureft- toReft (U r ps _) = toReft r `meet` toReft ps- params (U r _ _) = params r- bot (U r _ s) = U (bot r) (Pr []) (bot s)- top (U r p s) = U (top r) (top p) s-- ofReft r = U (ofReft r) mempty mempty--isTauto_ureft u = isTauto (ur_reft u) && isTauto (ur_pred u) -- && (isTauto $ ur_strata u)--ppTy_ureft u@(U r p s) d- | isTauto_ureft u = d- | otherwise = ppr_reft r (ppTy p d) s--ppr_reft r d s = braces (pprint v <+> colon <+> d <> ppr_str s <+> text "|" <+> pprint r')- where- r'@(Reft (v, _)) = toReft r--ppr_str [] = empty-ppr_str s = text "^" <> pprint s--instance Subable r => Subable (UReft r) where- syms (U r p _) = syms r ++ syms p- subst s (U r z l) = U (subst s r) (subst s z) (subst s l)- substf f (U r z l) = U (substf f r) (substf f z) (substf f l)- substa f (U r z l) = U (substa f r) (substa f z) (substa f l)--instance (Reftable r, RefTypable c tv r) => Subable (RTProp c tv r) where- syms (RPropP ss r) = (fst <$> ss) ++ syms r- syms (RProp ss r) = (fst <$> ss) ++ syms r- syms (RHProp _ _) = error "TODO: PHProp.syms"-- subst su (RPropP ss r) = RPropP ss (subst su r)- subst su (RProp ss t) = RProp ss (subst su <$> t)- subst _ (RHProp _ _) = error "TODO: PHProp.subst"-- substf f (RPropP ss r) = RPropP ss (substf f r)- substf f (RProp ss t) = RProp ss (substf f <$> t)- substf _ (RHProp _ _) = error "TODO PHProp.substf"- substa f (RPropP ss r) = RPropP ss (substa f r)- substa f (RProp ss t) = RProp ss (substa f <$> t)- substa _ (RHProp _ _) = error "TODO PHProp.substa"--instance (Subable r, RefTypable c tv r) => Subable (RType c tv r) where- syms = foldReft (\r acc -> syms r ++ acc) []- substa f = mapReft (substa f)- substf f = emapReft (substf . substfExcept f) []- subst su = emapReft (subst . substExcept su) []- subst1 t su = emapReft (\xs r -> subst1Except xs r su) [] t-----instance Reftable Predicate where- isTauto (Pr ps) = null ps-- bot (Pr _) = errorstar "No BOT instance for Predicate"- -- NV: This does not print abstract refinements....- -- HACK: Hiding to not render types in WEB DEMO. NEED TO FIX.- ppTy r d | isTauto r = d- | not (ppPs ppEnv) = d- | otherwise = d <> (angleBrackets $ pprint r)-- toReft (Pr ps@(p:_)) = Reft (parg p, refa $ pToRef <$> ps)- toReft _ = mempty- params = errorstar "TODO: instance of params for Predicate"-- ofReft = error "TODO: Predicate.ofReft"--pToRef p = pApp (pname p) $ (EVar $ parg p) : (thd3 <$> pargs p)--pApp :: Symbol -> [Expr] -> Pred-pApp p es = PBexp $ EApp (dummyLoc $ pappSym $ length es) (EVar p:es)--pappSym n = symbol $ "papp" ++ show n--------------------------------------------------------------------------------------------- Visitors --------------------------------------------------------------------------------------------isTrivial t = foldReft (\r b -> isTauto r && b) True t--instance Functor UReft where- fmap f (U r p s) = U (f r) p s--instance Functor (RType a b) where- fmap = mapReft---- instance Fold.Foldable (RType a b c) where--- foldr = foldReft--mapReft :: (r1 -> r2) -> RType c tv r1 -> RType c tv r2-mapReft f = emapReft (\_ -> f) []--emapReft :: ([Symbol] -> r1 -> r2) -> [Symbol] -> RType c tv r1 -> RType c tv r2--emapReft f γ (RVar α r) = RVar α (f γ r)-emapReft f γ (RAllT α t) = RAllT α (emapReft f γ t)-emapReft f γ (RAllP π t) = RAllP π (emapReft f γ t)-emapReft f γ (RAllS p t) = RAllS p (emapReft f γ t)-emapReft f γ (RFun x t t' r) = RFun x (emapReft f γ t) (emapReft f (x:γ) t') (f γ r)-emapReft f γ (RApp c ts rs r) = RApp c (emapReft f γ <$> ts) (emapRef f γ <$> rs) (f γ r)-emapReft f γ (RAllE z t t') = RAllE z (emapReft f γ t) (emapReft f γ t')-emapReft f γ (REx z t t') = REx z (emapReft f γ t) (emapReft f γ t')-emapReft _ _ (RExprArg e) = RExprArg e-emapReft f γ (RAppTy t t' r) = RAppTy (emapReft f γ t) (emapReft f γ t') (f γ r)-emapReft f γ (RRTy e r o t) = RRTy (mapSnd (emapReft f γ) <$> e) (f γ r) o (emapReft f γ t)-emapReft f γ (RHole r) = RHole (f γ r)--emapRef :: ([Symbol] -> t -> s) -> [Symbol] -> RTProp c tv t -> RTProp c tv s-emapRef f γ (RPropP s r) = RPropP s $ f γ r-emapRef f γ (RProp s t) = RProp s $ emapReft f γ t-emapRef _ _ (RHProp _ _) = error "TODO: PHProp empaReft"----------------------------------------------------------------------------------------------------------- isBase' x t = traceShow ("isBase: " ++ showpp x) $ isBase t---- isBase :: RType a -> Bool-isBase (RAllT _ t) = isBase t-isBase (RAllP _ t) = isBase t-isBase (RVar _ _) = True-isBase (RApp _ ts _ _) = all isBase ts-isBase (RFun _ t1 t2 _) = isBase t1 && isBase t2-isBase (RAppTy t1 t2 _) = isBase t1 && isBase t2-isBase (RRTy _ _ _ t) = isBase t-isBase (RAllE _ _ t) = isBase t-isBase _ = False--isFunTy (RAllE _ _ t) = isFunTy t-isFunTy (RAllS _ t) = isFunTy t-isFunTy (RAllT _ t) = isFunTy t-isFunTy (RAllP _ t) = isFunTy t-isFunTy (RFun _ _ _ _) = True-isFunTy _ = False---mapReftM :: (Monad m) => (r1 -> m r2) -> RType c tv r1 -> m (RType c tv r2)-mapReftM f (RVar α r) = liftM (RVar α) (f r)-mapReftM f (RAllT α t) = liftM (RAllT α) (mapReftM f t)-mapReftM f (RAllP π t) = liftM (RAllP π) (mapReftM f t)-mapReftM f (RAllS s t) = liftM (RAllS s) (mapReftM f t)-mapReftM f (RFun x t t' r) = liftM3 (RFun x) (mapReftM f t) (mapReftM f t') (f r)-mapReftM f (RApp c ts rs r) = liftM3 (RApp c) (mapM (mapReftM f) ts) (mapM (mapRefM f) rs) (f r)-mapReftM f (RAllE z t t') = liftM2 (RAllE z) (mapReftM f t) (mapReftM f t')-mapReftM f (REx z t t') = liftM2 (REx z) (mapReftM f t) (mapReftM f t')-mapReftM _ (RExprArg e) = return $ RExprArg e-mapReftM f (RAppTy t t' r) = liftM3 RAppTy (mapReftM f t) (mapReftM f t') (f r)-mapReftM f (RHole r) = liftM RHole (f r)-mapReftM f (RRTy xts r o t) = liftM4 RRTy (mapM (mapSndM (mapReftM f)) xts) (f r) (return o) (mapReftM f t)--mapRefM :: (Monad m) => (t -> m s) -> (RTProp c tv t) -> m (RTProp c tv s)-mapRefM f (RPropP s r) = liftM (RPropP s) (f r)-mapRefM f (RProp s t) = liftM (RProp s) (mapReftM f t)-mapRefM _ (RHProp _ _) = error "TODO PHProp.mapRefM"---- foldReft :: (r -> a -> a) -> a -> RType c tv r -> a-foldReft f = efoldReft (\_ _ -> []) (\_ -> ()) (\_ _ -> f) (\_ γ -> γ) emptySEnv---- efoldReft :: Reftable r =>(p -> [RType c tv r] -> [(Symbol, a)])-> (RType c tv r -> a)-> (SEnv a -> Maybe (RType c tv r) -> r -> c1 -> c1)-> SEnv a-> c1-> RType c tv r-> c1-efoldReft cb g f fp = go- where- -- folding over RType- go γ z me@(RVar _ r) = f γ (Just me) r z- go γ z (RAllT _ t) = go γ z t- go γ z (RAllP p t) = go (fp p γ) z t- go γ z (RAllS _ t) = go γ z t- go γ z me@(RFun _ (RApp c ts _ _) t' r)- | isClass c = f γ (Just me) r (go (insertsSEnv γ (cb c ts)) (go' γ z ts) t')- go γ z me@(RFun x t t' r) = f γ (Just me) r (go (insertSEnv x (g t) γ) (go γ z t) t')- go γ z me@(RApp _ ts rs r) = f γ (Just me) r (ho' γ (go' (insertSEnv (rTypeValueVar me) (g me) γ) z ts) rs)-- go γ z (RAllE x t t') = go (insertSEnv x (g t) γ) (go γ z t) t'- go γ z (REx x t t') = go (insertSEnv x (g t) γ) (go γ z t) t'- go γ z me@(RRTy [] r _ t) = f γ (Just me) r (go γ z t)- go γ z me@(RRTy xts r _ t) = f γ (Just me) r (go γ (go γ z (envtoType xts)) t)- go γ z me@(RAppTy t t' r) = f γ (Just me) r (go γ (go γ z t) t')- go _ z (RExprArg _) = z- go γ z me@(RHole r) = f γ (Just me) r z-- -- folding over Ref- ho γ z (RPropP ss r) = f (insertsSEnv γ (mapSnd (g . ofRSort) <$> ss)) Nothing r z- ho γ z (RProp ss t) = go (insertsSEnv γ ((mapSnd (g . ofRSort)) <$> ss)) z t- ho _ _ (RHProp _ _) = error "TODO: RHProp.ho"-- -- folding over [RType]- go' γ z ts = foldr (flip $ go γ) z ts-- -- folding over [Ref]- ho' γ z rs = foldr (flip $ ho γ) z rs-- envtoType xts = foldr (\(x,t1) t2 -> rFun x t1 t2) (snd $ last xts) (init xts)--mapBot f (RAllT α t) = RAllT α (mapBot f t)-mapBot f (RAllP π t) = RAllP π (mapBot f t)-mapBot f (RAllS s t) = RAllS s (mapBot f t)-mapBot f (RFun x t t' r) = RFun x (mapBot f t) (mapBot f t') r-mapBot f (RAppTy t t' r) = RAppTy (mapBot f t) (mapBot f t') r-mapBot f (RApp c ts rs r) = f $ RApp c (mapBot f <$> ts) (mapBotRef f <$> rs) r-mapBot f (REx b t1 t2) = REx b (mapBot f t1) (mapBot f t2)-mapBot f (RAllE b t1 t2) = RAllE b (mapBot f t1) (mapBot f t2)-mapBot f (RRTy e r o t) = RRTy (mapSnd (mapBot f) <$> e) r o (mapBot f t)-mapBot f t' = f t'-mapBotRef _ (RPropP s r) = RPropP s $ r-mapBotRef f (RProp s t) = RProp s $ mapBot f t-mapBotRef _ (RHProp _ _) = error "TODO: RHProp.mapBotRef"--mapBind f (RAllT α t) = RAllT α (mapBind f t)-mapBind f (RAllP π t) = RAllP π (mapBind f t)-mapBind f (RAllS s t) = RAllS s (mapBind f t)-mapBind f (RFun b t1 t2 r) = RFun (f b) (mapBind f t1) (mapBind f t2) r-mapBind f (RApp c ts rs r) = RApp c (mapBind f <$> ts) (mapBindRef f <$> rs) r-mapBind f (RAllE b t1 t2) = RAllE (f b) (mapBind f t1) (mapBind f t2)-mapBind f (REx b t1 t2) = REx (f b) (mapBind f t1) (mapBind f t2)-mapBind _ (RVar α r) = RVar α r-mapBind _ (RHole r) = RHole r-mapBind f (RRTy e r o t) = RRTy e r o (mapBind f t)-mapBind _ (RExprArg e) = RExprArg e-mapBind f (RAppTy t t' r) = RAppTy (mapBind f t) (mapBind f t') r--mapBindRef f (RPropP s r) = RPropP (mapFst f <$> s) r-mapBindRef f (RProp s t) = RProp (mapFst f <$> s) $ mapBind f t-mapBindRef _ (RHProp _ _) = error "TODO: RHProp.mapBindRef"------------------------------------------------------ofRSort :: Reftable r => RType c tv () -> RType c tv r-ofRSort = fmap mempty--toRSort :: RType c tv r -> RType c tv ()-toRSort = stripAnnotations . mapBind (const dummySymbol) . fmap (const ())--stripAnnotations (RAllT α t) = RAllT α (stripAnnotations t)-stripAnnotations (RAllP _ t) = stripAnnotations t-stripAnnotations (RAllS _ t) = stripAnnotations t-stripAnnotations (RAllE _ _ t) = stripAnnotations t-stripAnnotations (REx _ _ t) = stripAnnotations t-stripAnnotations (RFun x t t' r) = RFun x (stripAnnotations t) (stripAnnotations t') r-stripAnnotations (RAppTy t t' r) = RAppTy (stripAnnotations t) (stripAnnotations t') r-stripAnnotations (RApp c ts rs r) = RApp c (stripAnnotations <$> ts) (stripAnnotationsRef <$> rs) r-stripAnnotations (RRTy _ _ _ t) = stripAnnotations t-stripAnnotations t = t-stripAnnotationsRef (RProp s t) = RProp s $ stripAnnotations t-stripAnnotationsRef r = r---insertsSEnv = foldr (\(x, t) γ -> insertSEnv x t γ)--rTypeValueVar :: (Reftable r) => RType c tv r -> Symbol-rTypeValueVar t = vv where Reft (vv,_) = rTypeReft t--rTypeReft :: (Reftable r) => RType c tv r -> Reft-rTypeReft = fromMaybe trueReft . fmap toReft . stripRTypeBase---- stripRTypeBase :: RType a -> Maybe a-stripRTypeBase (RApp _ _ _ x)- = Just x-stripRTypeBase (RVar _ x)- = Just x-stripRTypeBase (RFun _ _ _ x)- = Just x-stripRTypeBase (RAppTy _ _ x)- = Just x-stripRTypeBase _- = Nothing--mapRBase f (RApp c ts rs r) = RApp c ts rs $ f r-mapRBase f (RVar a r) = RVar a $ f r-mapRBase f (RFun x t1 t2 r) = RFun x t1 t2 $ f r-mapRBase f (RAppTy t1 t2 r) = RAppTy t1 t2 $ f r-mapRBase _ t = t----makeLType :: Stratum -> SpecType -> SpecType-makeLType l t = fromRTypeRep trep{ty_res = mapRBase f $ ty_res trep}- where trep = toRTypeRep t- f (U r p _) = U r p [l]---makeDivType = makeLType SDiv-makeFinType = makeLType SFin--getStrata = maybe [] ur_strata . stripRTypeBase---------------------------------------------------------------------------------- | PPrint -------------------------------------------------------------------------------------------------------------------------------------------------instance Show Stratum where- show SFin = "Fin"- show SDiv = "Div"- show SWhnf = "Whnf"- show (SVar s) = show s--instance PPrint Stratum where- pprint = text . show--instance PPrint Strata where- pprint [] = empty- pprint ss = hsep (pprint <$> nub ss)--instance PPrint SourcePos where- pprint = text . show--instance PPrint () where- pprint = text . show--instance PPrint String where- pprint = text--instance PPrint Text where- pprint = text . T.unpack--instance PPrint a => PPrint (Located a) where- pprint = pprint . val--instance PPrint Int where- pprint = F.pprint--instance PPrint Integer where- pprint = F.pprint--instance PPrint Constant where- pprint = F.pprint--instance PPrint Brel where- pprint = F.pprint--instance PPrint Bop where- pprint = F.pprint--instance PPrint Sort where- pprint = F.pprint--instance PPrint Symbol where- pprint = pprint . symbolText--instance PPrint Expr where- pprint = F.pprint--instance PPrint SymConst where- pprint = F.pprint--instance PPrint Pred where- pprint = F.pprint--instance PPrint a => PPrint (PVar a) where- pprint (PV s _ _ xts) = pprint s <+> hsep (pprint <$> dargs xts)- where- dargs = map thd3 . takeWhile (\(_, x, y) -> EVar x /= y)--instance PPrint Predicate where- pprint (Pr []) = text "True"- pprint (Pr pvs) = hsep $ punctuate (text "&") (map pprint pvs)--instance PPrint Refa where- pprint = pprint . raPred--instance PPrint Reft where- pprint = F.pprint--instance PPrint SortedReft where- pprint = F.pprint----------------------------------------------------------------------------- | Error Data Type ------------------------------------------------------------------------------------------------------------------------------- | The type used during constraint generation, used also to define contexts--- for errors, hence in this file, and NOT in Constraint.hs-newtype REnv = REnv (M.HashMap Symbol SpecType)--type ErrorResult = FixResult Error--newtype EMsg = EMsg String deriving (Generic, Data, Typeable)--instance PPrint EMsg where- pprint (EMsg s) = text s---- | In the below, we use EMsg instead of, say, SpecType because--- the latter is impossible to serialize, as it contains GHC--- internals like TyCon and Class inside it.--type Error = TError SpecType----- | INVARIANT : all Error constructors should have a pos field-data TError t =- ErrSubType { pos :: !SrcSpan- , msg :: !Doc- , ctx :: !(M.HashMap Symbol t)- , tact :: !t- , texp :: !t- } -- ^ liquid type error- | ErrFCrash { pos :: !SrcSpan- , msg :: !Doc- , ctx :: !(M.HashMap Symbol t)- , tact :: !t- , texp :: !t- } -- ^ liquid type error- | ErrAssType { pos :: !SrcSpan- , obl :: !Oblig- , msg :: !Doc- , ref :: !RReft- } -- ^ liquid type error-- | ErrParse { pos :: !SrcSpan- , msg :: !Doc- , err :: !ParseError- } -- ^ specification parse error-- | ErrTySpec { pos :: !SrcSpan- , var :: !Doc- , typ :: !t- , msg :: !Doc- } -- ^ sort error in specification-- | ErrTermSpec { pos :: !SrcSpan- , var :: !Doc- , exp :: !Expr- , msg :: !Doc- } -- ^ sort error in specification- | ErrDupAlias { pos :: !SrcSpan- , var :: !Doc- , kind :: !Doc- , locs :: ![SrcSpan]- } -- ^ multiple alias with same name error-- | ErrDupSpecs { pos :: !SrcSpan- , var :: !Doc- , locs:: ![SrcSpan]- } -- ^ multiple specs for same binder error-- | ErrBadData { pos :: !SrcSpan- , var :: !Doc- , msg :: !Doc- } -- ^ multiple specs for same binder error-- | ErrInvt { pos :: !SrcSpan- , inv :: !t- , msg :: !Doc- } -- ^ Invariant sort error-- | ErrIAl { pos :: !SrcSpan- , inv :: !t- , msg :: !Doc- } -- ^ Using sort error-- | ErrIAlMis { pos :: !SrcSpan- , t1 :: !t- , t2 :: !t- , msg :: !Doc- } -- ^ Incompatible using error-- | ErrMeas { pos :: !SrcSpan- , ms :: !Symbol- , msg :: !Doc- } -- ^ Measure sort error-- | ErrHMeas { pos :: !SrcSpan- , ms :: !Symbol- , msg :: !Doc- } -- ^ Haskell bad Measure error-- | ErrUnbound { pos :: !SrcSpan- , var :: !Doc- } -- ^ Unbound symbol in specification-- | ErrGhc { pos :: !SrcSpan- , msg :: !Doc- } -- ^ GHC error: parsing or type checking-- | ErrMismatch { pos :: !SrcSpan- , var :: !Doc- , hs :: !Type- , lq :: !Type- } -- ^ Mismatch between Liquid and Haskell types-- | ErrAliasCycle { pos :: !SrcSpan- , acycle :: ![(SrcSpan, Doc)]- } -- ^ Cyclic Refined Type Alias Definitions-- | ErrIllegalAliasApp { pos :: !SrcSpan- , dname :: !Doc- , dpos :: !SrcSpan- } -- ^ Illegal RTAlias application (from BSort, eg. in PVar)-- | ErrAliasApp { pos :: !SrcSpan- , nargs :: !Int- , dname :: !Doc- , dpos :: !SrcSpan- , dargs :: !Int- }-- | ErrSaved { pos :: !SrcSpan- , msg :: !Doc- } -- ^ Previously saved error, that carries over after DiffCheck-- | ErrTermin { bind :: ![Var]- , pos :: !SrcSpan- , msg :: !Doc- } -- ^ Termination Error-- | ErrRClass { pos :: !SrcSpan- , cls :: !Doc- , insts :: ![(SrcSpan, Doc)]- } -- ^ Refined Class/Interfaces Conflict-- | ErrOther { pos :: !SrcSpan- , msg :: !Doc- } -- ^ Unexpected PANIC- deriving (Typeable, Functor)---- data LParseError = LPE !SourcePos [String]--- deriving (Data, Typeable, Generic)-----errToFCrash :: Error -> Error-errToFCrash (ErrSubType l m g t1 t2)- = ErrFCrash l m g t1 t2-errToFCrash e- = e---instance Eq Error where- e1 == e2 = pos e1 == pos e2--instance Ord Error where- e1 <= e2 = pos e1 <= pos e2--instance Ex.Error Error where- strMsg = errOther . pprint--errSpan :: TError a -> SrcSpan-errSpan = pos--errOther :: Doc -> Error-errOther = ErrOther noSrcSpan----------------------------------------------------------------------------- | Source Information Associated With Constraints -----------------------------------------------------------------------------------------------data Cinfo = Ci { ci_loc :: !SrcSpan- , ci_err :: !(Maybe Error)- }- deriving (Eq, Ord, Generic)--instance NFData Cinfo where- rnf x = seq x ()------------------------------------------------------------------------------ | Converting Results To Answers ----------------------------------------------------------------------------------------------------------------class Result a where- result :: a -> FixResult Error--instance Result [Error] where- result es = Crash es ""--instance Result Error where- result (ErrOther _ d) = UnknownError $ render d- result e = result [e]--instance Result (FixResult Cinfo) where- result = fmap cinfoError-------------------------------------------------------------------------------------- Module Names-----------------------------------------------------------------------------------data ModName = ModName !ModType !ModuleName deriving (Eq,Ord)--instance Show ModName where- show = getModString--instance Symbolic ModName where- symbol (ModName _ m) = symbol m--instance Symbolic ModuleName where- symbol = symbol . moduleNameFS--data ModType = Target | SrcImport | SpecImport deriving (Eq,Ord)--isSrcImport (ModName SrcImport _) = True-isSrcImport _ = False--isSpecImport (ModName SpecImport _) = True-isSpecImport _ = False--getModName (ModName _ m) = m--getModString = moduleNameString . getModName---------------------------------------------------------------------------------------------- Refinement Type Aliases -----------------------------------------------------------------------------------------------------------------------------data RTEnv = RTE { typeAliases :: M.HashMap Symbol (RTAlias RTyVar SpecType)- , predAliases :: M.HashMap Symbol (RTAlias Symbol Pred)- , exprAliases :: M.HashMap Symbol (RTAlias Symbol Expr)- }--instance Monoid RTEnv where- (RTE ta1 pa1 ea1) `mappend` (RTE ta2 pa2 ea2)- = RTE (ta1 `M.union` ta2) (pa1 `M.union` pa2) (ea1 `M.union` ea2)- mempty = RTE M.empty M.empty M.empty--mapRT f e = e { typeAliases = f $ typeAliases e }-mapRP f e = e { predAliases = f $ predAliases e }-mapRE f e = e { exprAliases = f $ exprAliases e }--cinfoError (Ci _ (Just e)) = e-cinfoError (Ci l _) = errOther $ text $ "Cinfo:" ++ showPpr l--------------------------------------------------------------------------------------- Measures----------------------------------------------------------------------------------data Measure ty ctor = M {- name :: LocSymbol- , sort :: ty- , eqns :: [Def ty ctor]- } deriving (Data, Typeable)--data CMeasure ty- = CM { cName :: LocSymbol- , cSort :: ty- }--data Def ty ctor- = Def {- measure :: LocSymbol- , dparams :: [(Symbol, ty)]- , ctor :: ctor- , dsort :: Maybe ty- , binds :: [(Symbol, Maybe ty)]- , body :: Body- } deriving (Show, Data, Typeable)-deriving instance (Eq ctor, Eq ty) => Eq (Def ty ctor)--data Body- = E Expr -- ^ Measure Refinement: {v | v = e }- | P Pred -- ^ Measure Refinement: {v | (? v) <=> p }- | R Symbol Pred -- ^ Measure Refinement: {v | p}- deriving (Show, Eq, Data, Typeable)--instance Subable (Measure ty ctor) where- syms (M _ _ es) = concatMap syms es- substa f (M n s es) = M n s $ substa f <$> es- substf f (M n s es) = M n s $ substf f <$> es- subst su (M n s es) = M n s $ subst su <$> es--instance Subable (Def ty ctor) where- syms (Def _ sp _ _ sb bd) = (fst <$> sp) ++ (fst <$> sb) ++ syms bd- substa f (Def m p c t b bd) = Def m p c t b $ substa f bd- substf f (Def m p c t b bd) = Def m p c t b $ substf f bd- subst su (Def m p c t b bd) = Def m p c t b $ subst su bd--instance Subable Body where- syms (E e) = syms e- syms (P e) = syms e- syms (R s e) = s:syms e-- substa f (E e) = E $ substa f e- substa f (P e) = P $ substa f e- substa f (R s e) = R s $ substa f e-- substf f (E e) = E $ substf f e- substf f (P e) = P $ substf f e- substf f (R s e) = R s $ substf f e-- subst su (E e) = E $ subst su e- subst su (P e) = P $ subst su e- subst su (R s e) = R s $ subst su e----data RClass ty- = RClass { rcName :: LocSymbol- , rcSupers :: [ty]- , rcTyVars :: [Symbol]- , rcMethods :: [(LocSymbol,ty)]- } deriving (Show)--instance Functor RClass where- fmap f (RClass n ss tvs ms) = RClass n (fmap f ss) tvs (fmap (second f) ms)----------------------------------------------------------------------------- | Annotations ----------------------------------------------------------------------------------------------------------------------------------newtype AnnInfo a = AI (M.HashMap SrcSpan [(Maybe Text, a)]) deriving (Generic)--data Annot t = AnnUse t- | AnnDef t- | AnnRDf t- | AnnLoc SrcSpan--instance Monoid (AnnInfo a) where- mempty = AI M.empty- mappend (AI m1) (AI m2) = AI $ M.unionWith (++) m1 m2--instance Functor AnnInfo where- fmap f (AI m) = AI (fmap (fmap (\(x, y) -> (x, f y)) ) m)---instance NFData a => NFData (AnnInfo a) where- rnf (AI _) = ()--instance NFData (Annot a) where- rnf (AnnDef _) = ()- rnf (AnnRDf _) = ()- rnf (AnnUse _) = ()- rnf (AnnLoc _) = ()----------------------------------------------------------------------------- | Output ---------------------------------------------------------------------------------------------------------------------------------------data Output a = O { o_vars :: Maybe [String]- , o_errors :: ! [Error]- , o_types :: !(AnnInfo a)- , o_templs :: !(AnnInfo a)- , o_bots :: ![SrcSpan]- , o_result :: FixResult Error- } deriving (Generic)--emptyOutput = O Nothing [] mempty mempty [] mempty--instance Monoid (Output a) where- mempty = emptyOutput- mappend o1 o2 = O { o_vars = sortNub <$> mappend (o_vars o1) (o_vars o2)- , o_errors = sortNub $ mappend (o_errors o1) (o_errors o2)- , o_types = mappend (o_types o1) (o_types o2)- , o_templs = mappend (o_templs o1) (o_templs o2)- , o_bots = sortNub $ mappend (o_bots o1) (o_bots o2)- , o_result = mappend (o_result o1) (o_result o2)- }---------------------------------------------------------------- | KVar Profile -------------------------------------------------------------------------------------------------------data KVKind- = RecBindE- | NonRecBindE- | TypeInstE- | PredInstE- | LamE- | CaseE- | LetE- deriving (Generic, Eq, Ord, Show, Enum, Data, Typeable)--instance Hashable KVKind where- hashWithSalt i = hashWithSalt i. fromEnum--newtype KVProf = KVP (M.HashMap KVKind Int)--emptyKVProf :: KVProf-emptyKVProf = KVP M.empty--updKVProf :: KVKind -> [KVar] -> KVProf -> KVProf-updKVProf k kvs (KVP m) = KVP $ M.insert k (kn + length kvs) m- where- kn = M.lookupDefault 0 k m--instance NFData KVKind where- rnf z = z `seq` ()--instance PPrint KVKind where- pprint = text . show--instance PPrint KVProf where- pprint (KVP m) = pprint $ M.toList m--instance NFData KVProf where- rnf (KVP m) = rnf m `seq` ()---- hasHole (toReft -> (Reft (_, rs))) = any isHole rs--hole :: Pred-hole = PKVar "HOLE" mempty--isHole :: Pred -> Bool-isHole (PKVar ("HOLE") _) = True-isHole _ = False--hasHole :: Reftable r => r -> Bool-hasHole = any isHole . conjuncts . reftPred . toReft----- isHole :: KVar -> Bool--- isHole "HOLE" = True--- isHole _ = False----- classToRApp :: SpecType -> SpecType--- classToRApp (RCls cl ts)--- = RApp (RTyCon (classTyCon cl) def def) ts mempty mempty--instance Symbolic DataCon where- symbol = symbol . dataConWorkId---instance PPrint DataCon where- pprint = text . showPpr--instance Show DataCon where- show = showpp---liquidBegin :: String-liquidBegin = ['{', '-', '@']--liquidEnd :: String-liquidEnd = ['@', '-', '}']+{-# LANGUAGE DeriveFoldable #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE DeriveTraversable #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE TypeSynonymInstances #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE TemplateHaskell #-}++-- | This module should contain all the global type definitions and basic instances.++module Language.Haskell.Liquid.Types (++ -- * Options+ Config (..)+ , HasConfig (..)+ , hasOpt++ -- * Ghc Information+ , GhcInfo (..)+ , GhcSpec (..)+ , TargetVars (..)++ -- * Located Things+ , Located (..)+ , dummyLoc++ -- * Symbols+ , LocSymbol+ , LocText++ -- * Default unknown name+ , dummyName, isDummy++ -- * Refined Type Constructors+ , RTyCon (RTyCon, rtc_tc, rtc_info)+ , TyConInfo(..), defaultTyConInfo+ , rTyConPVs+ , rTyConPropVs+ , isClassRTyCon, isClassType, isEqType++ -- * Refinement Types+ , RType (..), Ref(..), RTProp, rPropP+ , RTyVar (..)+ , RTAlias (..)++ -- * Worlds+ , HSeg (..)+ , World (..)++ -- * Classes describing operations on `RTypes`+ , TyConable (..)+ , RefTypable (..)+ , SubsTy (..)++ -- * Predicate Variables+ , PVar (PV, pname, parg, ptype, pargs), isPropPV, pvType+ , PVKind (..)+ , Predicate (..)++ -- * Refinements+ , UReft(..)++ -- * Parse-time entities describing refined data types+ , DataDecl (..)+ , DataConP (..)+ , TyConP (..)++ -- * Pre-instantiated RType+ , RRType, BRType, RRProp+ , BSort, BPVar++ -- * Instantiated RType+ , BareType, PrType+ , SpecType, SpecProp+ , RSort+ , UsedPVar, RPVar, RReft+ , REnv (..)++ -- * Constructing & Destructing RTypes+ , RTypeRep(..), fromRTypeRep, toRTypeRep+ , mkArrow, bkArrowDeep, bkArrow, safeBkArrow+ , mkUnivs, bkUniv, bkClass+ , rFun, rCls, rRCls++ -- * Manipulating `Predicates`+ , pvars, pappSym, pApp++ -- * Some tests on RTypes+ , isBase+ , isFunTy+ , isTrivial++ -- * Traversing `RType`+ , efoldReft, foldReft, foldReft'+ , mapReft, mapReftM+ , mapBot, mapBind++ -- * ???+ , Oblig(..)+ , ignoreOblig+ , addInvCond+++ -- * Inferred Annotations+ , AnnInfo (..)+ , Annot (..)++ -- * Overall Output+ , Output (..)++ -- * Refinement Hole+ , hole, isHole, hasHole++ -- * Converting To and From Sort+ , ofRSort, toRSort+ , rTypeValueVar+ , rTypeReft+ , stripRTypeBase++ -- * Class for values that can be pretty printed+ , PPrint (..), pprint+ , showpp++ -- * Printer Configuration+ , PPEnv (..)+ , ppEnv+ , ppEnvShort++ -- * Modules and Imports+ , ModName (..), ModType (..)+ , isSrcImport, isSpecImport+ , getModName, getModString++ -- * Refinement Type Aliases+ , RTEnv (..)+ , mapRT, mapRE++ -- * Errors and Error Messages+ , module Language.Haskell.Liquid.Types.Errors+ , Error+ , ErrorResult++ -- * Source information (associated with constraints)+ , Cinfo (..)++ -- * Measures+ , Measure (..)+ , CMeasure (..)+ , Def (..)+ , Body (..)+ , MSpec (..)++ -- * Type Classes+ , RClass (..)++ -- * KV Profiling+ , KVKind (..) -- types of kvars+ , KVProf -- profile table+ , emptyKVProf -- empty profile+ , updKVProf -- extend profile++ -- * Misc+ , mapRTAVars+ , insertsSEnv++ -- * Strata+ , Stratum(..), Strata+ , isSVar+ , getStrata+ , makeDivType, makeFinType++ -- * CoreToLogic+ , LogicMap(..), toLogicMap, eAppWithMap, LMap(..)++ -- * Refined Instances+ , RDEnv, DEnv(..), RInstance(..)++ -- * Ureftable Instances+ , UReftable(..)++ -- * String Literals+ , liquidBegin, liquidEnd++ , Axiom(..), HAxiom, LAxiom+ )+ where++import Prelude hiding (error)+import SrcLoc (SrcSpan)+import TyCon+import DataCon+import NameSet+import Module (moduleNameFS)+import TypeRep hiding (maybeParen, pprArrowChain)+import Var+import GHC (HscEnv, ModuleName, moduleNameString)+import GHC.Generics+import Class+import CoreSyn (CoreBind, CoreExpr)+import PrelInfo (isNumericClass)+import Type (getClassPredTys_maybe)+import TysPrim (eqPrimTyCon)+import TysWiredIn (listTyCon)+++import Control.Monad (liftM, liftM2, liftM3, liftM4)+++import Control.DeepSeq++import Data.Bifunctor+import Data.Bifunctor.TH+import Data.Typeable (Typeable)+import Data.Generics (Data)+++++import qualified Data.Foldable as F+import Data.Hashable+import qualified Data.HashMap.Strict as M+import qualified Data.HashSet as S+import Data.Maybe (fromMaybe, mapMaybe)++import Data.List (nub)+import Data.Text (Text)+import qualified Data.Text as T+++import Text.PrettyPrint.HughesPJ hiding (first)+import Text.Printf++import Language.Fixpoint.Misc+import Language.Fixpoint.Types hiding (Error, SrcSpan, Result, Predicate, R)+++++import Language.Haskell.Liquid.GHC.Misc+import Language.Haskell.Liquid.Types.Variance+import Language.Haskell.Liquid.Types.Errors+import Language.Haskell.Liquid.Misc+import Language.Haskell.Liquid.UX.Config+import Data.Default++-----------------------------------------------------------------------------+-- | Printer ----------------------------------------------------------------+-----------------------------------------------------------------------------++data PPEnv+ = PP { ppPs :: Bool+ , ppTyVar :: Bool -- TODO if set to True all Bare fails+ , ppSs :: Bool+ , ppShort :: Bool+ }++ppEnv = ppEnvCurrent+ppEnvCurrent = PP False False False False+_ppEnvPrintPreds = PP False False False False+ppEnvShort pp = pp { ppShort = True }++++------------------------------------------------------------------+-- | GHC Information : Code & Spec ------------------------------+------------------------------------------------------------------++data GhcInfo = GI {+ target :: !FilePath+ , env :: !HscEnv+ , cbs :: ![CoreBind]+ , derVars :: ![Var]+ , impVars :: ![Var]+ , defVars :: ![Var]+ , useVars :: ![Var]+ , hqFiles :: ![FilePath]+ , imports :: ![String]+ , includes :: ![FilePath]+ , spec :: !GhcSpec+ }++instance HasConfig GhcInfo where+ getConfig = getConfig . spec+++-- | The following is the overall type for /specifications/ obtained from+-- parsing the target source and dependent libraries++data GhcSpec = SP {+ tySigs :: ![(Var, Located SpecType)] -- ^ Asserted Reftypes+ -- eg. see include/Prelude.spec+ , asmSigs :: ![(Var, Located SpecType)] -- ^ Assumed Reftypes+ , inSigs :: ![(Var, Located SpecType)] -- ^ Auto generated Signatures + , ctors :: ![(Var, Located SpecType)] -- ^ Data Constructor Measure Sigs+ -- eg. (:) :: a -> xs:[a] -> {v: Int | v = 1 + len(xs) }+ , meas :: ![(Symbol, Located SpecType)] -- ^ Measure Types+ -- eg. len :: [a] -> Int+ , invariants :: ![Located SpecType] -- ^ Data Type Invariants+ -- eg. forall a. {v: [a] | len(v) >= 0}+ , ialiases :: ![(Located SpecType, Located SpecType)] -- ^ Data Type Invariant Aliases+ , dconsP :: ![(DataCon, DataConP)] -- ^ Predicated Data-Constructors+ -- e.g. see tests/pos/Map.hs+ , tconsP :: ![(TyCon, TyConP)] -- ^ Predicated Type-Constructors+ -- eg. see tests/pos/Map.hs+ , freeSyms :: ![(Symbol, Var)] -- ^ List of `Symbol` free in spec and corresponding GHC var+ -- eg. (Cons, Cons#7uz) from tests/pos/ex1.hs+ , tcEmbeds :: TCEmb TyCon -- ^ How to embed GHC Tycons into fixpoint sorts+ -- e.g. "embed Set as Set_set" from include/Data/Set.spec+ , qualifiers :: ![Qualifier] -- ^ Qualifiers in Source/Spec files+ -- e.g tests/pos/qualTest.hs+ , tgtVars :: ![Var] -- ^ Top-level Binders To Verify (empty means ALL binders)+ , decr :: ![(Var, [Int])] -- ^ Lexicographically ordered size witnesses for termination+ , texprs :: ![(Var, [Expr])] -- ^ Lexicographically ordered expressions for termination+ , lvars :: !(S.HashSet Var) -- ^ Variables that should be checked in the environment they are used+ , lazy :: !(S.HashSet Var) -- ^ Binders to IGNORE during termination checking+ , autosize :: !(S.HashSet TyCon) -- ^ Binders to IGNORE during termination checking+ , config :: !Config -- ^ Configuration Options+ , exports :: !NameSet -- ^ `Name`s exported by the module being verified+ , measures :: [Measure SpecType DataCon]+ , tyconEnv :: M.HashMap TyCon RTyCon+ , dicts :: DEnv Var SpecType -- ^ Dictionary Environment+ , axioms :: [HAxiom] -- Axioms from axiomatized functions+ , logicMap :: LogicMap+ , proofType :: Maybe Type+ }++instance HasConfig GhcSpec where+ getConfig = config++data LogicMap = LM { logic_map :: M.HashMap Symbol LMap+ , axiom_map :: M.HashMap Var Symbol+ } deriving (Show)++instance Monoid LogicMap where+ mempty = LM M.empty M.empty+ mappend (LM x1 x2) (LM y1 y2) = LM (M.union x1 y1) (M.union x2 y2)++data LMap = LMap { lvar :: Symbol+ , largs :: [Symbol]+ , lexpr :: Expr+ }++instance Show LMap where+ show (LMap x xs e) = show x ++ " " ++ show xs ++ "\t|->\t" ++ show e+++toLogicMap ls = mempty {logic_map = M.fromList $ map toLMap ls}+ where+ toLMap (x, xs, e) = (x, LMap {lvar = x, largs = xs, lexpr = e})++eAppWithMap lmap f es def+ | Just (LMap _ xs e) <- M.lookup (val f) (logic_map lmap), length xs == length es + = subst (mkSubst $ zip xs es) e+ | Just (LMap _ xs e) <- M.lookup (val f) (logic_map lmap), isApp e + = subst (mkSubst $ zip xs es) $ dropApp e (length xs - length es)+ | otherwise+ = def++dropApp e i | i <= 0 = e +dropApp (EApp e _) i = dropApp e (i-1)+dropApp _ _ = errorstar "impossible"+ +isApp (EApp (EVar _) (EVar _)) = True +isApp (EApp e (EVar _)) = isApp e +isApp _ = False++data TyConP = TyConP { freeTyVarsTy :: ![RTyVar]+ , freePredTy :: ![PVar RSort]+ , freeLabelTy :: ![Symbol]+ , varianceTs :: !VarianceInfo+ , variancePs :: !VarianceInfo+ , sizeFun :: !(Maybe (Symbol -> Expr))+ } deriving (Generic, Data, Typeable)++data DataConP = DataConP { dc_loc :: !SourcePos+ , freeTyVars :: ![RTyVar]+ , freePred :: ![PVar RSort]+ , freeLabels :: ![Symbol]+ , tyConsts :: ![SpecType] -- FIXME: WHAT IS THIS??+ , tyArgs :: ![(Symbol, SpecType)] -- FIXME: These are backwards, why??+ , tyRes :: !SpecType+ , dc_locE :: !SourcePos+ } deriving (Generic, Data, Typeable)+++-- | Which Top-Level Binders Should be Verified+data TargetVars = AllVars | Only ![Var]+++--------------------------------------------------------------------+-- | Abstract Predicate Variables ----------------------------------+--------------------------------------------------------------------++data PVar t = PV+ { pname :: !Symbol+ , ptype :: !(PVKind t)+ , parg :: !Symbol+ , pargs :: ![(t, Symbol, Expr)]+ } deriving (Generic, Data, Typeable, Show, Functor)++instance Eq (PVar t) where+ pv == pv' = pname pv == pname pv' {- UNIFY: What about: && eqArgs pv pv' -}++instance Ord (PVar t) where+ compare (PV n _ _ _) (PV n' _ _ _) = compare n n'++instance NFData t => NFData (PVar t)++instance Hashable (PVar a) where+ hashWithSalt i (PV n _ _ _) = hashWithSalt i n++pvType :: PVar t -> t+pvType p = case ptype p of+ PVProp t -> t+ PVHProp -> panic Nothing "pvType on HProp-PVar"++data PVKind t+ = PVProp t+ | PVHProp+ deriving (Generic, Data, Typeable, Functor, F.Foldable, Traversable, Show)++instance NFData a => NFData (PVKind a)+++--------------------------------------------------------------------+------------------ Predicates --------------------------------------+--------------------------------------------------------------------++type UsedPVar = PVar ()+newtype Predicate = Pr [UsedPVar] deriving (Generic, Data, Typeable)++instance NFData Predicate where+ rnf _ = ()++instance Monoid Predicate where+ mempty = pdTrue+ mappend p p' = pdAnd [p, p']++instance (Monoid a) => Monoid (UReft a) where+ mempty = MkUReft mempty mempty mempty+ mappend (MkUReft x y z) (MkUReft x' y' z') = MkUReft (mappend x x') (mappend y y') (mappend z z')+++pdTrue = Pr []+pdAnd ps = Pr (nub $ concatMap pvars ps)+pvars (Pr pvs) = pvs++instance Subable UsedPVar where+ syms pv = [ y | (_, x, EVar y) <- pargs pv, x /= y ]+ subst s pv = pv { pargs = mapThd3 (subst s) <$> pargs pv }+ substf f pv = pv { pargs = mapThd3 (substf f) <$> pargs pv }+ substa f pv = pv { pargs = mapThd3 (substa f) <$> pargs pv }+++instance Subable Predicate where+ syms (Pr pvs) = concatMap syms pvs+ subst s (Pr pvs) = Pr (subst s <$> pvs)+ substf f (Pr pvs) = Pr (substf f <$> pvs)+ substa f (Pr pvs) = Pr (substa f <$> pvs)++instance Subable Qualifier where+ syms = syms . q_body+ subst = mapQualBody . subst+ substf = mapQualBody . substf+ substa = mapQualBody . substa++mapQualBody f q = q { q_body = f (q_body q) }++instance NFData r => NFData (UReft r)++instance NFData RTyVar+++-- MOVE TO TYPES+newtype RTyVar = RTV TyVar deriving (Generic, Data, Typeable)++instance Symbolic RTyVar where+ symbol (RTV tv) = symbol . T.pack . showPpr $ tv+++data RTyCon = RTyCon+ { rtc_tc :: TyCon -- ^ GHC Type Constructor+ , rtc_pvars :: ![RPVar] -- ^ Predicate Parameters+ , rtc_info :: !TyConInfo -- ^ TyConInfo+ }+ deriving (Generic, Data, Typeable)++instance NFData RTyCon++-- | Accessors for @RTyCon@+++isClassRTyCon = isClassTyCon . rtc_tc+rTyConPVs = rtc_pvars+rTyConPropVs = filter isPropPV . rtc_pvars+isPropPV = isProp . ptype++isEqType (RApp c _ _ _) = isEqual c+isEqType _ = False+++isClassType (RApp c _ _ _) = isClass c+isClassType _ = False++-- rTyConPVHPs = filter isHPropPV . rtc_pvars+-- isHPropPV = not . isPropPV++isProp (PVProp _) = True+isProp _ = False+++defaultTyConInfo = TyConInfo [] [] Nothing++instance Default TyConInfo where+ def = defaultTyConInfo+++-----------------------------------------------------------------------+-- | Co- and Contra-variance for TyCon --------------------------------+-----------------------------------------------------------------------++-- | Indexes start from 0 and type or predicate arguments can be both+-- covariant and contravaariant e.g., for the below Foo dataType+--+-- data Foo a b c d <p :: b -> Prop, q :: Int -> Prop, r :: a -> Prop>+-- = F (a<r> -> b<p>) | Q (c -> a) | G (Int<q> -> a<r>)+--+-- there will be:+--+-- varianceTyArgs = [Bivariant , Covariant, Contravatiant, Invariant]+-- variancePsArgs = [Covariant, Contravatiant, Bivariant]+--++data TyConInfo = TyConInfo+ { varianceTyArgs :: !VarianceInfo -- ^ variance info for type variables+ , variancePsArgs :: !VarianceInfo -- ^ variance info for predicate variables+ , sizeFunction :: !(Maybe (Symbol -> Expr)) -- ^ logical function that computes the size of the structure+ } deriving (Generic, Data, Typeable)++instance NFData TyConInfo++instance Show TyConInfo where+ show (TyConInfo x y _) = show x ++ "\n" ++ show y++--------------------------------------------------------------------+---- Unified Representation of Refinement Types --------------------+--------------------------------------------------------------------++-- MOVE TO TYPES+data RType c tv r+ = RVar {+ rt_var :: !tv+ , rt_reft :: !r+ }++ | RFun {+ rt_bind :: !Symbol+ , rt_in :: !(RType c tv r)+ , rt_out :: !(RType c tv r)+ , rt_reft :: !r+ }++ | RAllT {+ rt_tvbind :: !tv+ , rt_ty :: !(RType c tv r)+ }++ | RAllP {+ rt_pvbind :: !(PVar (RType c tv ()))+ , rt_ty :: !(RType c tv r)+ }++ | RAllS {+ rt_sbind :: !(Symbol)+ , rt_ty :: !(RType c tv r)+ }++ | RApp {+ rt_tycon :: !c+ , rt_args :: ![RType c tv r]+ , rt_pargs :: ![RTProp c tv r]+ , rt_reft :: !r+ }++ | RAllE {+ rt_bind :: !Symbol+ , rt_allarg :: !(RType c tv r)+ , rt_ty :: !(RType c tv r)+ }++ | REx {+ rt_bind :: !Symbol+ , rt_exarg :: !(RType c tv r)+ , rt_ty :: !(RType c tv r)+ }++ | RExprArg (Located Expr) -- ^ For expression arguments to type aliases+ -- see tests/pos/vector2.hs+ | RAppTy{+ rt_arg :: !(RType c tv r)+ , rt_res :: !(RType c tv r)+ , rt_reft :: !r+ }++ | RRTy {+ rt_env :: ![(Symbol, RType c tv r)]+ , rt_ref :: !r+ , rt_obl :: !Oblig+ , rt_ty :: !(RType c tv r)+ }++ | RHole r -- ^ let LH match against the Haskell type and add k-vars, e.g. `x:_`+ -- see tests/pos/Holes.hs+ deriving (Generic, Data, Typeable, Functor)++instance (NFData c, NFData tv, NFData r) => NFData (RType c tv r)++ignoreOblig (RRTy _ _ _ t) = t+ignoreOblig t = t+++-- | @Ref@ describes `Prop τ` and `HProp` arguments applied to type constructors.+-- For example, in [a]<{\h -> v > h}>, we apply (via `RApp`)+-- * the `RProp` denoted by `{\h -> v > h}` to+-- * the `RTyCon` denoted by `[]`.+-- Thus, @Ref@ is used for abstract-predicate (arguments) that are associated+-- with _type constructors_ i.e. whose semantics are _dependent upon_ the data-type.+-- In contrast, the `Predicate` argument in `ur_pred` in the @UReft@ applies+-- directly to any type and has semantics _independent of_ the data-type.++data Ref τ t = RProp+ { rf_args :: [(Symbol, τ)]+ , rf_body :: t -- ^ Abstract refinement associated with `RTyCon`+ } deriving (Generic, Data, Typeable, Functor)++instance (NFData τ, NFData t) => NFData (Ref τ t)++rPropP τ r = RProp τ (RHole r)++-- | @RTProp@ is a convenient alias for @Ref@ that will save a bunch of typing.+-- In general, perhaps we need not expose @Ref@ directly at all.+type RTProp c tv r = Ref (RType c tv ()) (RType c tv r)+++-- | A @World@ is a Separation Logic predicate that is essentially a sequence of binders+-- that satisfies two invariants (TODO:LIQUID):+-- 1. Each `hs_addr :: Symbol` appears at most once,+-- 2. There is at most one `HVar` in a list.++newtype World t = World [HSeg t]+ deriving (Generic, Data, Typeable)++data HSeg t = HBind {hs_addr :: !Symbol, hs_val :: t}+ | HVar UsedPVar+ deriving (Generic, Data, Typeable)++data UReft r+ = MkUReft { ur_reft :: !r+ , ur_pred :: !Predicate+ , ur_strata :: !Strata+ }+ deriving (Generic, Data, Typeable, Functor)++type BRType = RType LocSymbol Symbol+type RRType = RType RTyCon RTyVar++type BSort = BRType ()+type RSort = RRType ()++type BPVar = PVar BSort+type RPVar = PVar RSort++type RReft = UReft Reft+type PrType = RRType Predicate+type BareType = BRType RReft+type SpecType = RRType RReft+type SpecProp = RRProp RReft+type RRProp r = Ref RSort (RRType r)+++data Stratum = SVar Symbol | SDiv | SWhnf | SFin+ deriving (Generic, Data, Typeable, Eq)+instance NFData Stratum++type Strata = [Stratum]++isSVar (SVar _) = True+isSVar _ = False++instance {-# OVERLAPPING #-} Monoid Strata where+ mempty = []+ mappend s1 s2 = nub $ s1 ++ s2++class SubsTy tv ty a where+ subt :: (tv, ty) -> a -> a++class (Eq c) => TyConable c where+ isFun :: c -> Bool+ isList :: c -> Bool+ isTuple :: c -> Bool+ ppTycon :: c -> Doc+ isClass :: c -> Bool+ isEqual :: c -> Bool++ isNumCls :: c -> Bool+ isFracCls :: c -> Bool++ isClass = const False+ isEqual = const False+ isNumCls = const False+ isFracCls = const False++class ( TyConable c+ , Eq c, Eq tv+ , Hashable tv+ , Reftable r+ , PPrint r+ ) => RefTypable c tv r+ where+ ppRType :: Prec -> RType c tv r -> Doc++++-------------------------------------------------------------------------------+-- | TyConable Instances -------------------------------------------------------+-------------------------------------------------------------------------------++-- MOVE TO TYPES+instance TyConable RTyCon where+ isFun = isFunTyCon . rtc_tc+ isList = (listTyCon ==) . rtc_tc+ isTuple = TyCon.isTupleTyCon . rtc_tc+ isClass = isClassRTyCon+ isEqual = (eqPrimTyCon ==) . rtc_tc+ ppTycon = toFix++ isNumCls c = maybe False (isClassOrSubClass isNumericClass)+ (tyConClass_maybe $ rtc_tc c)+ isFracCls c = maybe False (isClassOrSubClass isFractionalClass)+ (tyConClass_maybe $ rtc_tc c)++isClassOrSubClass p cls+ = p cls || any (isClassOrSubClass p . fst)+ (mapMaybe getClassPredTys_maybe (classSCTheta cls))++-- MOVE TO TYPES+instance TyConable Symbol where+ isFun s = funConName == s+ isList s = listConName == s+ isTuple s = tupConName == s+ ppTycon = text . symbolString++instance TyConable LocSymbol where+ isFun = isFun . val+ isList = isList . val+ isTuple = isTuple . val+ ppTycon = ppTycon . val+++instance Eq RTyCon where+ x == y = rtc_tc x == rtc_tc y++instance Fixpoint RTyCon where+ toFix (RTyCon c _ _) = text $ showPpr c -- <+> text "\n<<" <+> hsep (map toFix ts) <+> text ">>\n"++instance Fixpoint Cinfo where+ toFix = text . showPpr . ci_loc++instance PPrint RTyCon where+ pprintTidy _ = text . showPpr . rtc_tc+++instance Show RTyCon where+ show = showpp++--------------------------------------------------------------------------+-- | Refined Instances ---------------------------------------------------+--------------------------------------------------------------------------++data RInstance t = RI+ { riclass :: LocSymbol+ , ritype :: t+ , risigs :: [(LocSymbol, t)]+ } deriving Functor++newtype DEnv x ty = DEnv (M.HashMap x (M.HashMap Symbol ty)) deriving (Monoid)++type RDEnv = DEnv Var SpecType+++--------------------------------------------------------------------------+-- | Values Related to Specifications ------------------------------------+--------------------------------------------------------------------------++data Axiom b s e = Axiom { aname :: (Var, Maybe DataCon)+ , abinds :: [b]+ , atypes :: [s]+ , alhs :: e+ , arhs :: e+ }+type HAxiom = Axiom Var Type CoreExpr+type LAxiom = Axiom Symbol Sort Expr+++instance Show (Axiom Var Type CoreExpr) where+ show (Axiom (n, c) bs _ts lhs rhs) = "Axiom : " +++ "\nFun Name: " ++ (showPpr n) +++ "\nData Con: " ++ (showPpr c) +++ "\nArguments:" ++ (showPpr bs) +++ -- "\nTypes :" ++ (showPpr ts) +++ "\nLHS :" ++ (showPpr lhs) +++ "\nRHS :" ++ (showPpr rhs)++--------------------------------------------------------------------------+-- | Values Related to Specifications ------------------------------------+--------------------------------------------------------------------------+++-- | Data type refinements+data DataDecl = D { tycName :: LocSymbol+ -- ^ Type Constructor Name+ , tycTyVars :: [Symbol]+ -- ^ Tyvar Parameters+ , tycPVars :: [PVar BSort]+ -- ^ PVar Parameters+ , tycTyLabs :: [Symbol]+ -- ^ PLabel Parameters+ , tycDCons :: [(LocSymbol, [(Symbol, BareType)])]+ -- ^ [DataCon, [(fieldName, fieldType)]]+ , tycSrcPos :: !SourcePos+ -- ^ Source Position+ , tycSFun :: (Maybe (Symbol -> Expr))+ -- ^ Measure that should decrease in recursive calls+ }+ -- deriving (Show)+++instance Eq DataDecl where+ d1 == d2 = tycName d1 == tycName d2++instance Ord DataDecl where+ compare d1 d2 = compare (tycName d1) (tycName d2)++-- | For debugging.+instance Show DataDecl where+ show dd = printf "DataDecl: data = %s, tyvars = %s"+ (show $ tycName dd)+ (show $ tycTyVars dd)++-- | Refinement Type Aliases++data RTAlias tv ty+ = RTA { rtName :: Symbol+ , rtTArgs :: [tv]+ , rtVArgs :: [tv]+ , rtBody :: ty+ , rtPos :: SourcePos+ , rtPosE :: SourcePos+ }++mapRTAVars f rt = rt { rtTArgs = f <$> rtTArgs rt+ , rtVArgs = f <$> rtVArgs rt+ }++------------------------------------------------------------------------+-- | Constructor and Destructors for RTypes ----------------------------+------------------------------------------------------------------------++data RTypeRep c tv r+ = RTypeRep { ty_vars :: [tv]+ , ty_preds :: [PVar (RType c tv ())]+ , ty_labels :: [Symbol]+ , ty_binds :: [Symbol]+ , ty_refts :: [r]+ , ty_args :: [RType c tv r]+ , ty_res :: (RType c tv r)+ }++fromRTypeRep (RTypeRep {..})+ = mkArrow ty_vars ty_preds ty_labels arrs ty_res+ where+ arrs = safeZip3WithError ("fromRTypeRep: " ++ show (length ty_binds, length ty_args, length ty_refts)) ty_binds ty_args ty_refts++toRTypeRep :: RType c tv r -> RTypeRep c tv r+toRTypeRep t = RTypeRep αs πs ls xs rs ts t''+ where+ (αs, πs, ls, t') = bkUniv t+ (xs, ts, rs, t'') = bkArrow t'++mkArrow αs πs ls xts = mkUnivs αs πs ls . mkArrs xts+ where+ mkArrs xts t = foldr (\(b,t1,r) t2 -> RFun b t1 t2 r) t xts++bkArrowDeep (RAllT _ t) = bkArrowDeep t+bkArrowDeep (RAllP _ t) = bkArrowDeep t+bkArrowDeep (RAllS _ t) = bkArrowDeep t+bkArrowDeep (RFun x t t' r) = let (xs, ts, rs, t'') = bkArrowDeep t' in (x:xs, t:ts, r:rs, t'')+bkArrowDeep t = ([], [], [], t)++bkArrow (RFun x t t' r) = let (xs, ts, rs, t'') = bkArrow t' in (x:xs, t:ts, r:rs, t'')+bkArrow t = ([], [], [], t)++safeBkArrow (RAllT _ _) = panic Nothing "safeBkArrow on RAllT"+safeBkArrow (RAllP _ _) = panic Nothing "safeBkArrow on RAllP"+safeBkArrow (RAllS _ t) = safeBkArrow t+safeBkArrow t = bkArrow t++mkUnivs αs πs ls t = foldr RAllT (foldr RAllP (foldr RAllS t ls) πs) αs++bkUniv :: RType t1 a t2 -> ([a], [PVar (RType t1 a ())], [Symbol], RType t1 a t2)+bkUniv (RAllT α t) = let (αs, πs, ls, t') = bkUniv t in (α:αs, πs, ls, t')+bkUniv (RAllP π t) = let (αs, πs, ls, t') = bkUniv t in (αs, π:πs, ls, t')+bkUniv (RAllS s t) = let (αs, πs, ss, t') = bkUniv t in (αs, πs, s:ss, t')+bkUniv t = ([], [], [], t)++bkClass (RFun _ (RApp c t _ _) t' _)+ | isClass c+ = let (cs, t'') = bkClass t' in ((c, t):cs, t'')+bkClass (RRTy e r o t)+ = let (cs, t') = bkClass t in (cs, RRTy e r o t')+bkClass t+ = ([], t)++rFun b t t' = RFun b t t' mempty+rCls c ts = RApp (RTyCon c [] defaultTyConInfo) ts [] mempty+rRCls rc ts = RApp rc ts [] mempty++addInvCond :: SpecType -> RReft -> SpecType+addInvCond t r'+ | isTauto $ ur_reft r' -- null rv+ = t+ | otherwise+ = fromRTypeRep $ trep {ty_res = RRTy [(x', tbd)] r OInv tbd}+ where+ trep = toRTypeRep t+ tbd = ty_res trep+ r = r' {ur_reft = Reft (v, rx)}+ su = (v, EVar x')+ x' = "xInv"+ rx = PIff (EVar v) $ subst1 rv su+ Reft(v, rv) = ur_reft r'++-------------------------------------------++instance Subable Stratum where+ syms (SVar s) = [s]+ syms _ = []+ subst su (SVar s) = SVar $ subst su s+ subst _ s = s+ substf f (SVar s) = SVar $ substf f s+ substf _ s = s+ substa f (SVar s) = SVar $ substa f s+ substa _ s = s++instance Reftable Strata where+ isTauto [] = True+ isTauto _ = False++ ppTy _ = panic Nothing "ppTy on Strata"+ toReft _ = mempty+ params s = [l | SVar l <- s]+ bot _ = []+ top _ = []++ ofReft = todo Nothing "TODO: Strata.ofReft"+++class Reftable r => UReftable r where+ ofUReft :: UReft Reft -> r+ ofUReft (MkUReft r _ _) = ofReft r+++instance UReftable (UReft Reft) where+ ofUReft r = r++instance UReftable () where+ ofUReft _ = mempty++instance (PPrint r, Reftable r) => Reftable (UReft r) where+ isTauto = isTauto_ureft+ ppTy = ppTy_ureft+ toReft (MkUReft r ps _) = toReft r `meet` toReft ps+ params (MkUReft r _ _) = params r+ bot (MkUReft r _ s) = MkUReft (bot r) (Pr []) (bot s)+ top (MkUReft r p s) = MkUReft (top r) (top p) s++ ofReft r = MkUReft (ofReft r) mempty mempty++isTauto_ureft u = isTauto (ur_reft u) && isTauto (ur_pred u) -- && (isTauto $ ur_strata u)++ppTy_ureft u@(MkUReft r p s) d+ | isTauto_ureft u = d+ | otherwise = ppr_reft r (ppTy p d) s++ppr_reft r d s = braces (pprint v <+> colon <+> d <> ppr_str s <+> text "|" <+> pprint r')+ where+ r'@(Reft (v, _)) = toReft r++ppr_str [] = empty+ppr_str s = text "^" <> pprint s++instance Subable r => Subable (UReft r) where+ syms (MkUReft r p _) = syms r ++ syms p+ subst s (MkUReft r z l) = MkUReft (subst s r) (subst s z) (subst s l)+ substf f (MkUReft r z l) = MkUReft (substf f r) (substf f z) (substf f l)+ substa f (MkUReft r z l) = MkUReft (substa f r) (substa f z) (substa f l)++instance (Reftable r, RefTypable c tv r) => Subable (RTProp c tv r) where+ syms (RProp ss r) = (fst <$> ss) ++ syms r++ subst su (RProp ss (RHole r)) = RProp ss (RHole (subst su r))+ subst su (RProp ss t) = RProp ss (subst su <$> t)++ substf f (RProp ss (RHole r)) = RProp ss (RHole (substf f r))+ substf f (RProp ss t) = RProp ss (substf f <$> t)++ substa f (RProp ss (RHole r)) = RProp ss (RHole (substa f r))+ substa f (RProp ss t) = RProp ss (substa f <$> t)+++instance (Subable r, RefTypable c tv r) => Subable (RType c tv r) where+ syms = foldReft (\_ r acc -> syms r ++ acc) []+ substa f = mapReft (substa f)+ substf f = emapReft (substf . substfExcept f) []+ subst su = emapReft (subst . substExcept su) []+ subst1 t su = emapReft (\xs r -> subst1Except xs r su) [] t+++++instance Reftable Predicate where+ isTauto (Pr ps) = null ps++ bot (Pr _) = panic Nothing "No BOT instance for Predicate"+ -- NV: This does not print abstract refinements....+ -- HACK: Hiding to not render types in WEB DEMO. NEED TO FIX.+ ppTy r d | isTauto r = d+ | not (ppPs ppEnv) = d+ | otherwise = d <> (angleBrackets $ pprint r)++ toReft (Pr ps@(p:_)) = Reft (parg p, pAnd $ pToRef <$> ps)+ toReft _ = mempty+ params = todo Nothing "TODO: instance of params for Predicate"++ ofReft = todo Nothing "TODO: Predicate.ofReft"++pToRef p = pApp (pname p) $ (EVar $ parg p) : (thd3 <$> pargs p)++pApp :: Symbol -> [Expr] -> Expr+pApp p es = mkEApp (dummyLoc $ pappSym $ length es) (EVar p:es)++pappSym n = symbol $ "papp" ++ show n++---------------------------------------------------------------+--------------------------- Visitors --------------------------+---------------------------------------------------------------++isTrivial t = foldReft (\_ r b -> isTauto r && b) True t++mapReft :: (r1 -> r2) -> RType c tv r1 -> RType c tv r2+mapReft f = emapReft (\_ -> f) []++emapReft :: ([Symbol] -> r1 -> r2) -> [Symbol] -> RType c tv r1 -> RType c tv r2++emapReft f γ (RVar α r) = RVar α (f γ r)+emapReft f γ (RAllT α t) = RAllT α (emapReft f γ t)+emapReft f γ (RAllP π t) = RAllP π (emapReft f γ t)+emapReft f γ (RAllS p t) = RAllS p (emapReft f γ t)+emapReft f γ (RFun x t t' r) = RFun x (emapReft f γ t) (emapReft f (x:γ) t') (f γ r)+emapReft f γ (RApp c ts rs r) = RApp c (emapReft f γ <$> ts) (emapRef f γ <$> rs) (f γ r)+emapReft f γ (RAllE z t t') = RAllE z (emapReft f γ t) (emapReft f γ t')+emapReft f γ (REx z t t') = REx z (emapReft f γ t) (emapReft f γ t')+emapReft _ _ (RExprArg e) = RExprArg e+emapReft f γ (RAppTy t t' r) = RAppTy (emapReft f γ t) (emapReft f γ t') (f γ r)+emapReft f γ (RRTy e r o t) = RRTy (mapSnd (emapReft f γ) <$> e) (f γ r) o (emapReft f γ t)+emapReft f γ (RHole r) = RHole (f γ r)++emapRef :: ([Symbol] -> t -> s) -> [Symbol] -> RTProp c tv t -> RTProp c tv s+emapRef f γ (RProp s (RHole r)) = RProp s $ RHole (f γ r)+emapRef f γ (RProp s t) = RProp s $ emapReft f γ t++------------------------------------------------------------------------------------------------------+-- isBase' x t = traceShow ("isBase: " ++ showpp x) $ isBase t+-- same as GhcMisc isBaseType++-- isBase :: RType a -> Bool++-- set all types to basic types, haskell `tx -> t` is translated to Arrow tx t+-- isBase _ = True++isBase (RAllT _ t) = isBase t+isBase (RAllP _ t) = isBase t+isBase (RVar _ _) = True+isBase (RApp _ ts _ _) = all isBase ts+isBase (RFun _ _ _ _) = False+isBase (RAppTy t1 t2 _) = isBase t1 && isBase t2+isBase (RRTy _ _ _ t) = isBase t+isBase (RAllE _ _ t) = isBase t+isBase _ = False++isFunTy (RAllE _ _ t) = isFunTy t+isFunTy (RAllS _ t) = isFunTy t+isFunTy (RAllT _ t) = isFunTy t+isFunTy (RAllP _ t) = isFunTy t+isFunTy (RFun _ _ _ _) = True+isFunTy _ = False+++mapReftM :: (Monad m) => (r1 -> m r2) -> RType c tv r1 -> m (RType c tv r2)+mapReftM f (RVar α r) = liftM (RVar α) (f r)+mapReftM f (RAllT α t) = liftM (RAllT α) (mapReftM f t)+mapReftM f (RAllP π t) = liftM (RAllP π) (mapReftM f t)+mapReftM f (RAllS s t) = liftM (RAllS s) (mapReftM f t)+mapReftM f (RFun x t t' r) = liftM3 (RFun x) (mapReftM f t) (mapReftM f t') (f r)+mapReftM f (RApp c ts rs r) = liftM3 (RApp c) (mapM (mapReftM f) ts) (mapM (mapRefM f) rs) (f r)+mapReftM f (RAllE z t t') = liftM2 (RAllE z) (mapReftM f t) (mapReftM f t')+mapReftM f (REx z t t') = liftM2 (REx z) (mapReftM f t) (mapReftM f t')+mapReftM _ (RExprArg e) = return $ RExprArg e+mapReftM f (RAppTy t t' r) = liftM3 RAppTy (mapReftM f t) (mapReftM f t') (f r)+mapReftM f (RHole r) = liftM RHole (f r)+mapReftM f (RRTy xts r o t) = liftM4 RRTy (mapM (mapSndM (mapReftM f)) xts) (f r) (return o) (mapReftM f t)++mapRefM :: (Monad m) => (t -> m s) -> (RTProp c tv t) -> m (RTProp c tv s)+mapRefM f (RProp s t) = liftM (RProp s) (mapReftM f t)+++--------------------------------------------------------------------------------+-- foldReft :: (Reftable r, TyConable c) => (r -> a -> a) -> a -> RType c tv r -> a+--------------------------------------------------------------------------------+-- foldReft f = efoldReft (\_ _ -> []) (\_ -> ()) (\_ _ -> f) (\_ γ -> γ) emptySEnv++--------------------------------------------------------------------------------+foldReft :: (Reftable r, TyConable c) => (SEnv (RType c tv r) -> r -> a -> a) -> a -> RType c tv r -> a+--------------------------------------------------------------------------------+foldReft f = foldReft' id (\γ _ -> f γ)++--------------------------------------------------------------------------------+foldReft' :: (Reftable r, TyConable c)+ => (RType c tv r -> b)+ -> (SEnv b -> Maybe (RType c tv r) -> r -> a -> a)+ -> a -> RType c tv r -> a+--------------------------------------------------------------------------------+foldReft' g f = efoldReft (\_ _ -> []) g (\γ t r z -> f γ t r z) (\_ γ -> γ) emptySEnv++++-- efoldReft :: Reftable r =>(p -> [RType c tv r] -> [(Symbol, a)])-> (RType c tv r -> a)-> (SEnv a -> Maybe (RType c tv r) -> r -> c1 -> c1)-> SEnv a-> c1-> RType c tv r-> c1+efoldReft cb g f fp = go+ where+ -- folding over RType+ go γ z me@(RVar _ r) = f γ (Just me) r z+ go γ z (RAllT _ t) = go γ z t+ go γ z (RAllP p t) = go (fp p γ) z t+ go γ z (RAllS _ t) = go γ z t+ go γ z me@(RFun _ (RApp c ts _ _) t' r)+ | isClass c = f γ (Just me) r (go (insertsSEnv γ (cb c ts)) (go' γ z ts) t')+ go γ z me@(RFun x t t' r) = f γ (Just me) r (go (insertSEnv x (g t) γ) (go γ z t) t')+-- go γ z me@(RFun _ t t' r) = f γ (Just me) r (go γ (go γ z t) t')+ go γ z me@(RApp _ ts rs r) = f γ (Just me) r (ho' γ (go' (insertSEnv (rTypeValueVar me) (g me) γ) z ts) rs)++ go γ z (RAllE x t t') = go (insertSEnv x (g t) γ) (go γ z t) t'+ go γ z (REx x t t') = go (insertSEnv x (g t) γ) (go γ z t) t'+ go γ z me@(RRTy [] r _ t) = f γ (Just me) r (go γ z t)+ go γ z me@(RRTy xts r _ t) = f γ (Just me) r (go γ (go γ z (envtoType xts)) t)+ go γ z me@(RAppTy t t' r) = f γ (Just me) r (go γ (go γ z t) t')+ go _ z (RExprArg _) = z+ go γ z me@(RHole r) = f γ (Just me) r z++ -- folding over Ref+ ho γ z (RProp ss (RHole r)) = f (insertsSEnv γ (mapSnd (g . ofRSort) <$> ss)) Nothing r z+ ho γ z (RProp ss t) = go (insertsSEnv γ ((mapSnd (g . ofRSort)) <$> ss)) z t++ -- folding over [RType]+ go' γ z ts = foldr (flip $ go γ) z ts++ -- folding over [Ref]+ ho' γ z rs = foldr (flip $ ho γ) z rs++ envtoType xts = foldr (\(x,t1) t2 -> rFun x t1 t2) (snd $ last xts) (init xts)++mapBot f (RAllT α t) = RAllT α (mapBot f t)+mapBot f (RAllP π t) = RAllP π (mapBot f t)+mapBot f (RAllS s t) = RAllS s (mapBot f t)+mapBot f (RFun x t t' r) = RFun x (mapBot f t) (mapBot f t') r+mapBot f (RAppTy t t' r) = RAppTy (mapBot f t) (mapBot f t') r+mapBot f (RApp c ts rs r) = f $ RApp c (mapBot f <$> ts) (mapBotRef f <$> rs) r+mapBot f (REx b t1 t2) = REx b (mapBot f t1) (mapBot f t2)+mapBot f (RAllE b t1 t2) = RAllE b (mapBot f t1) (mapBot f t2)+mapBot f (RRTy e r o t) = RRTy (mapSnd (mapBot f) <$> e) r o (mapBot f t)+mapBot f t' = f t'+mapBotRef _ (RProp s (RHole r)) = RProp s $ RHole r+mapBotRef f (RProp s t) = RProp s $ mapBot f t++mapBind f (RAllT α t) = RAllT α (mapBind f t)+mapBind f (RAllP π t) = RAllP π (mapBind f t)+mapBind f (RAllS s t) = RAllS s (mapBind f t)+mapBind f (RFun b t1 t2 r) = RFun (f b) (mapBind f t1) (mapBind f t2) r+mapBind f (RApp c ts rs r) = RApp c (mapBind f <$> ts) (mapBindRef f <$> rs) r+mapBind f (RAllE b t1 t2) = RAllE (f b) (mapBind f t1) (mapBind f t2)+mapBind f (REx b t1 t2) = REx (f b) (mapBind f t1) (mapBind f t2)+mapBind _ (RVar α r) = RVar α r+mapBind _ (RHole r) = RHole r+mapBind f (RRTy e r o t) = RRTy e r o (mapBind f t)+mapBind _ (RExprArg e) = RExprArg e+mapBind f (RAppTy t t' r) = RAppTy (mapBind f t) (mapBind f t') r++mapBindRef f (RProp s (RHole r)) = RProp (mapFst f <$> s) (RHole r)+mapBindRef f (RProp s t) = RProp (mapFst f <$> s) $ mapBind f t+++--------------------------------------------------+ofRSort :: Reftable r => RType c tv () -> RType c tv r+ofRSort = fmap mempty++toRSort :: RType c tv r -> RType c tv ()+toRSort = stripAnnotations . mapBind (const dummySymbol) . fmap (const ())++stripAnnotations (RAllT α t) = RAllT α (stripAnnotations t)+stripAnnotations (RAllP _ t) = stripAnnotations t+stripAnnotations (RAllS _ t) = stripAnnotations t+stripAnnotations (RAllE _ _ t) = stripAnnotations t+stripAnnotations (REx _ _ t) = stripAnnotations t+stripAnnotations (RFun x t t' r) = RFun x (stripAnnotations t) (stripAnnotations t') r+stripAnnotations (RAppTy t t' r) = RAppTy (stripAnnotations t) (stripAnnotations t') r+stripAnnotations (RApp c ts rs r) = RApp c (stripAnnotations <$> ts) (stripAnnotationsRef <$> rs) r+stripAnnotations (RRTy _ _ _ t) = stripAnnotations t+stripAnnotations t = t+stripAnnotationsRef (RProp s (RHole r)) = RProp s (RHole r)+stripAnnotationsRef (RProp s t) = RProp s $ stripAnnotations t+++insertsSEnv = foldr (\(x, t) γ -> insertSEnv x t γ)++rTypeValueVar :: (Reftable r) => RType c tv r -> Symbol+rTypeValueVar t = vv where Reft (vv,_) = rTypeReft t++rTypeReft :: (Reftable r) => RType c tv r -> Reft+rTypeReft = fromMaybe trueReft . fmap toReft . stripRTypeBase++ +-- stripRTypeBase :: RType a -> Maybe a+stripRTypeBase (RApp _ _ _ x)+ = Just x+stripRTypeBase (RVar _ x)+ = Just x+stripRTypeBase (RFun _ _ _ x)+ = Just x+stripRTypeBase (RAppTy _ _ x)+ = Just x+stripRTypeBase _+ = Nothing++mapRBase f (RApp c ts rs r) = RApp c ts rs $ f r+mapRBase f (RVar a r) = RVar a $ f r+mapRBase f (RFun x t1 t2 r) = RFun x t1 t2 $ f r+mapRBase f (RAppTy t1 t2 r) = RAppTy t1 t2 $ f r+mapRBase _ t = t++++makeLType :: Stratum -> SpecType -> SpecType+makeLType l t = fromRTypeRep trep{ty_res = mapRBase f $ ty_res trep}+ where trep = toRTypeRep t+ f (MkUReft r p _) = MkUReft r p [l]+++makeDivType = makeLType SDiv+makeFinType = makeLType SFin++getStrata = maybe [] ur_strata . stripRTypeBase++-----------------------------------------------------------------------------+-- | PPrint -----------------------------------------------------------------+-----------------------------------------------------------------------------++instance Show Stratum where+ show SFin = "Fin"+ show SDiv = "Div"+ show SWhnf = "Whnf"+ show (SVar s) = show s++instance PPrint Stratum where+ pprintTidy _ = text . show++instance {-# OVERLAPPING #-} PPrint Strata where+ pprintTidy _ [] = empty+ pprintTidy k ss = hsep (pprintTidy k <$> nub ss)++instance PPrint (PVar a) where+ pprintTidy _ = ppr_pvar++ppr_pvar :: PVar a -> Doc+ppr_pvar (PV s _ _ xts) = pprint s <+> hsep (pprint <$> dargs xts)+ where+ dargs = map thd3 . takeWhile (\(_, x, y) -> EVar x /= y)+++instance PPrint Predicate where+ pprintTidy _ (Pr []) = text "True"+ pprintTidy k (Pr pvs) = hsep $ punctuate (text "&") (map (pprintTidy k) pvs)+++-- | The type used during constraint generation, used+-- also to define contexts for errors, hence in this+-- file, and NOT in elsewhere. **DO NOT ATTEMPT TO MOVE**+-- Am splitting into+-- + global : many bindings, shared across all constraints+-- + local : few bindings, relevant to particular constraints++data REnv = REnv+ { reGlobal :: M.HashMap Symbol SpecType -- ^ the "global" names for module+ , reLocal :: M.HashMap Symbol SpecType -- ^ the "local" names for sub-exprs+ }++instance NFData REnv where+ rnf (REnv {}) = ()++------------------------------------------------------------------------+-- | Error Data Type ---------------------------------------------------+------------------------------------------------------------------------++type ErrorResult = FixResult UserError+type Error = TError SpecType++instance NFData a => NFData (TError a)++------------------------------------------------------------------------+-- | Source Information Associated With Constraints --------------------+------------------------------------------------------------------------++data Cinfo = Ci { ci_loc :: !SrcSpan+ , ci_err :: !(Maybe Error)+ }+ deriving (Eq, Ord, Generic)++instance NFData Cinfo++--------------------------------------------------------------------------------+--- Module Names+--------------------------------------------------------------------------------++data ModName = ModName !ModType !ModuleName deriving (Eq,Ord)++instance Show ModName where+ show = getModString++instance Symbolic ModName where+ symbol (ModName _ m) = symbol m++instance Symbolic ModuleName where+ symbol = symbol . moduleNameFS++data ModType = Target | SrcImport | SpecImport deriving (Eq,Ord)++isSrcImport (ModName SrcImport _) = True+isSrcImport _ = False++isSpecImport (ModName SpecImport _) = True+isSpecImport _ = False++getModName (ModName _ m) = m++getModString = moduleNameString . getModName+++-------------------------------------------------------------------------------+----------- Refinement Type Aliases -------------------------------------------+-------------------------------------------------------------------------------++data RTEnv = RTE { typeAliases :: M.HashMap Symbol (RTAlias RTyVar SpecType)+ , exprAliases :: M.HashMap Symbol (RTAlias Symbol Expr)+ }++instance Monoid RTEnv where+ (RTE ta1 ea1) `mappend` (RTE ta2 ea2)+ = RTE (ta1 `M.union` ta2) (ea1 `M.union` ea2)+ mempty = RTE M.empty M.empty++mapRT f e = e { typeAliases = f $ typeAliases e }+mapRE f e = e { exprAliases = f $ exprAliases e }+++--------------------------------------------------------------------------------+--- Measures+--------------------------------------------------------------------------------+data Body+ = E Expr -- ^ Measure Refinement: {v | v = e }+ | P Expr -- ^ Measure Refinement: {v | (? v) <=> p }+ | R Symbol Expr -- ^ Measure Refinement: {v | p}+ deriving (Show, Data, Typeable, Generic, Eq)++data Def ty ctor = Def+ { measure :: LocSymbol+ , dparams :: [(Symbol, ty)]+ , ctor :: ctor+ , dsort :: Maybe ty+ , binds :: [(Symbol, Maybe ty)]+ , body :: Body+ } deriving (Show, Data, Typeable, Generic, Eq, Functor)++data Measure ty ctor = M+ { name :: LocSymbol+ , sort :: ty+ , eqns :: [Def ty ctor]+ } deriving (Data, Typeable, Generic, Functor)++deriveBifunctor ''Def+deriveBifunctor ''Measure++data CMeasure ty = CM+ { cName :: LocSymbol+ , cSort :: ty+ } deriving (Data, Typeable, Generic, Functor)++instance PPrint Body where+ pprintTidy k (E e) = pprintTidy k e+ pprintTidy k (P p) = pprintTidy k p+ pprintTidy k (R v p) = braces (pprintTidy k v <+> text "|" <+> pprintTidy k p)++instance PPrint a => PPrint (Def t a) where+ pprintTidy k (Def m p c _ bs body) = pprintTidy k m <+> pprintTidy k (fst <$> p) <+> cbsd <> text " = " <> pprintTidy k body+ where cbsd = parens (pprintTidy k c <> hsep (pprintTidy k `fmap` (fst <$> bs)))++instance (PPrint t, PPrint a) => PPrint (Measure t a) where+ pprintTidy k (M n s eqs) = pprintTidy k n <> text " :: " <> pprintTidy k s+ $$ vcat (pprintTidy k `fmap` eqs)++instance PPrint (Measure t a) => Show (Measure t a) where+ show = showpp++instance PPrint t => PPrint (CMeasure t) where+ pprintTidy k (CM n s) = pprintTidy k n <> text " :: " <> pprintTidy k s++instance PPrint (CMeasure t) => Show (CMeasure t) where+ show = showpp+++instance Subable (Measure ty ctor) where+ syms (M _ _ es) = concatMap syms es+ substa f (M n s es) = M n s $ substa f <$> es+ substf f (M n s es) = M n s $ substf f <$> es+ subst su (M n s es) = M n s $ subst su <$> es++instance Subable (Def ty ctor) where+ syms (Def _ sp _ _ sb bd) = (fst <$> sp) ++ (fst <$> sb) ++ syms bd+ substa f (Def m p c t b bd) = Def m p c t b $ substa f bd+ substf f (Def m p c t b bd) = Def m p c t b $ substf f bd+ subst su (Def m p c t b bd) = Def m p c t b $ subst su bd++instance Subable Body where+ syms (E e) = syms e+ syms (P e) = syms e+ syms (R s e) = s:syms e++ substa f (E e) = E $ substa f e+ substa f (P e) = P $ substa f e+ substa f (R s e) = R s $ substa f e++ substf f (E e) = E $ substf f e+ substf f (P e) = P $ substf f e+ substf f (R s e) = R s $ substf f e++ subst su (E e) = E $ subst su e+ subst su (P e) = P $ subst su e+ subst su (R s e) = R s $ subst su e++++data RClass ty+ = RClass { rcName :: LocSymbol+ , rcSupers :: [ty]+ , rcTyVars :: [Symbol]+ , rcMethods :: [(LocSymbol,ty)]+ } deriving (Show, Functor)+++------------------------------------------------------------------------+-- | Annotations -------------------------------------------------------+------------------------------------------------------------------------++newtype AnnInfo a = AI (M.HashMap SrcSpan [(Maybe Text, a)])+ deriving (Data, Typeable, Generic, Functor)++data Annot t+ = AnnUse t+ | AnnDef t+ | AnnRDf t+ | AnnLoc SrcSpan+ deriving (Data, Typeable, Generic, Functor)++instance Monoid (AnnInfo a) where+ mempty = AI M.empty+ mappend (AI m1) (AI m2) = AI $ M.unionWith (++) m1 m2++instance NFData a => NFData (AnnInfo a)++instance NFData a => NFData (Annot a)++--------------------------------------------------------------------------------+-- | Output --------------------------------------------------------------------+--------------------------------------------------------------------------------++data Output a = O+ { o_vars :: Maybe [String]+ , o_errors :: ![UserError]+ , o_types :: !(AnnInfo a)+ , o_templs :: !(AnnInfo a)+ , o_bots :: ![SrcSpan]+ , o_result :: ErrorResult+ } deriving (Typeable, Generic, Functor)++emptyOutput = O Nothing [] mempty mempty [] mempty++instance Monoid (Output a) where+ mempty = emptyOutput+ mappend o1 o2 = O { o_vars = sortNub <$> mappend (o_vars o1) (o_vars o2)+ , o_errors = sortNub $ mappend (o_errors o1) (o_errors o2)+ , o_types = mappend (o_types o1) (o_types o2)+ , o_templs = mappend (o_templs o1) (o_templs o2)+ , o_bots = sortNub $ mappend (o_bots o1) (o_bots o2)+ , o_result = mappend (o_result o1) (o_result o2)+ }++--------------------------------------------------------------------------------+-- | KVar Profile --------------------------------------------------------------+--------------------------------------------------------------------------------++data KVKind+ = RecBindE+ | NonRecBindE+ | TypeInstE+ | PredInstE+ | LamE+ | CaseE+ | LetE+ deriving (Generic, Eq, Ord, Show, Enum, Data, Typeable)++instance Hashable KVKind++newtype KVProf = KVP (M.HashMap KVKind Int) deriving (Generic)++emptyKVProf :: KVProf+emptyKVProf = KVP M.empty++updKVProf :: KVKind -> Kuts -> KVProf -> KVProf+updKVProf k kvs (KVP m) = KVP $ M.insert k (kn + n) m+ where+ kn = M.lookupDefault 0 k m+ n = S.size $ ksVars kvs+++instance NFData KVKind++instance PPrint KVKind where+ pprintTidy _ = text . show++instance PPrint KVProf where+ pprintTidy k (KVP m) = pprintTidy k $ M.toList m++instance NFData KVProf++hole :: Expr+hole = PKVar "HOLE" mempty++isHole :: Expr -> Bool+isHole (PKVar ("HOLE") _) = True+isHole _ = False++hasHole :: Reftable r => r -> Bool+hasHole = any isHole . conjuncts . reftPred . toReft++-- classToRApp :: SpecType -> SpecType+-- classToRApp (RCls cl ts)+-- = RApp (RTyCon (classTyCon cl) def def) ts mempty mempty++instance Symbolic DataCon where+ symbol = symbol . dataConWorkId+++instance PPrint DataCon where+ pprintTidy _ = text . showPpr++instance Show DataCon where+ show = showpp+++liquidBegin :: String+liquidBegin = ['{', '-', '@']++liquidEnd :: String+liquidEnd = ['@', '-', '}']++data MSpec ty ctor = MSpec+ { ctorMap :: M.HashMap Symbol [Def ty ctor]+ , measMap :: M.HashMap LocSymbol (Measure ty ctor)+ , cmeasMap :: M.HashMap LocSymbol (Measure ty ())+ , imeas :: ![Measure ty ctor]+ } deriving (Data, Typeable, Generic, Functor)++instance Bifunctor MSpec where+ first f (MSpec c m cm im) = MSpec (fmap (fmap (first f)) c)+ (fmap (first f) m)+ (fmap (first f) cm)+ (fmap (first f) im)+ second = fmap++instance (PPrint t, PPrint a) => PPrint (MSpec t a) where+ pprintTidy k = vcat . fmap (pprintTidy k) . fmap snd . M.toList . measMap++instance (Show ty, Show ctor, PPrint ctor, PPrint ty) => Show (MSpec ty ctor) where+ show (MSpec ct m cm im)+ = "\nMSpec:\n" +++ "\nctorMap:\t " ++ show ct +++ "\nmeasMap:\t " ++ show m +++ "\ncmeasMap:\t " ++ show cm +++ "\nimeas:\t " ++ show im +++ "\n"++instance Eq ctor => Monoid (MSpec ty ctor) where+ mempty = MSpec M.empty M.empty M.empty []++ (MSpec c1 m1 cm1 im1) `mappend` (MSpec c2 m2 cm2 im2)+ | null dups+ = MSpec (M.unionWith (++) c1 c2) (m1 `M.union` m2)+ (cm1 `M.union` cm2) (im1 ++ im2)+ | otherwise+ = panic Nothing $ err (head dups)+ where dups = [(k1, k2) | k1 <- M.keys m1 , k2 <- M.keys m2, val k1 == val k2]+ err (k1, k2) = printf "\nDuplicate Measure Definitions for %s\n%s" (showpp k1) (showpp $ map loc [k1, k2])++--------------------------------------------------------------------------------+-- Nasty PP stuff+--------------------------------------------------------------------------------++instance PPrint RTyVar where+ pprintTidy _k (RTV α)+ | ppTyVar ppEnv = ppr_tyvar α+ | otherwise = ppr_tyvar_short α++ppr_tyvar = text . tvId+ppr_tyvar_short = text . showPpr++instance (PPrint r, Reftable r, PPrint t, PPrint (RType c tv r)) => PPrint (Ref t (RType c tv r)) where+ pprintTidy k (RProp ss s) = ppRefArgs (fst <$> ss) <+> pprintTidy k s+ -- pprint (RProp ss (RHole s)) = ppRefArgs (fst <$> ss) <+> pprint s+ -- pprint (RProp ss s) = ppRefArgs (fst <$> ss) <+> pprint (fromMaybe mempty (stripRTypeBase s))+++ppRefArgs :: [Symbol] -> Doc+ppRefArgs [] = empty+ppRefArgs ss = text "\\" <> hsep (ppRefSym <$> ss ++ [vv Nothing]) <+> text "->"++ppRefSym "" = text "_"+ppRefSym s = pprint s
+ src/Language/Haskell/Liquid/Types/Bounds.hs view
@@ -0,0 +1,162 @@+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE TupleSections #-}++module Language.Haskell.Liquid.Types.Bounds (++ Bound(..),++ RBound, RRBound,++ RBEnv, RRBEnv,++ makeBound,++ ) where++import Prelude hiding (error)+import Text.PrettyPrint.HughesPJ++import Data.List (partition)+import Data.Maybe+import Data.Hashable+-- import Data.Monoid+import Data.Bifunctor++import qualified Data.HashMap.Strict as M+-- import Control.Applicative ((<$>))++import Language.Fixpoint.Types++import Language.Haskell.Liquid.Types+import Language.Haskell.Liquid.Misc (mapFst, mapSnd)+import Language.Haskell.Liquid.Types.RefType+++data Bound t e+ = Bound { bname :: LocSymbol -- ^ The name of the bound+ , tyvars :: [t] -- ^ Type variables that appear in the bounds+ , bparams :: [(LocSymbol, t)] -- ^ These are abstract refinements, for now+ , bargs :: [(LocSymbol, t)] -- ^ These are value variables+ , bbody :: e -- ^ The body of the bound+ }++type RBound = RRBound RSort+type RRBound tv = Bound tv Expr++type RBEnv = M.HashMap LocSymbol RBound+type RRBEnv tv = M.HashMap LocSymbol (RRBound tv)+++instance Hashable (Bound t e) where+ hashWithSalt i = hashWithSalt i . bname++instance Eq (Bound t e) where+ b1 == b2 = (bname b1) == (bname b2)++instance (PPrint e, PPrint t) => (Show (Bound t e)) where+ show = showpp+++instance (PPrint e, PPrint t) => (PPrint (Bound t e)) where+ pprintTidy k (Bound s vs ps xs e) = text "bound" <+> pprintTidy k s <+>+ text "forall" <+> pprintTidy k vs <+> text "." <+>+ pprintTidy k (fst <$> ps) <+> text "=" <+>+ pprint_bsyms k (fst <$> xs) <+> pprintTidy k e++pprint_bsyms _ [] = text ""+pprint_bsyms k xs = text "\\" <+> pprintTidy k xs <+> text "->"++instance Bifunctor Bound where+ first f (Bound s vs ps xs e) = Bound s (f <$> vs) (mapSnd f <$> ps) (mapSnd f <$> xs) e+ second f (Bound s vs ps xs e) = Bound s vs ps xs (f e)+++makeBound :: (PPrint r, UReftable r)+ => RRBound RSort -> [RRType r] -> [Symbol] -> (RRType r) -> (RRType r)+makeBound (Bound _ vs ps xs p) ts qs t+ = RRTy cts mempty OCons t+ where+ cts = (\(x, t) -> (x, foldr subsTyVar_meet t su)) <$> cts'++ cts' = makeBoundType penv rs xs++ penv = zip (val . fst <$> ps) qs+ rs = bkImp [] p++ bkImp acc (PImp p q) = bkImp (p:acc) q+ bkImp acc p = p:acc++ su = [(α, toRSort t, t) | (RVar α _, t) <- zip vs ts ]++makeBoundType :: (PPrint r, UReftable r)+ => [(Symbol, Symbol)]+ -> [Expr]+ -> [(LocSymbol, RSort)]+ -> [(Symbol, RRType r)]+makeBoundType penv (q:qs) xts = go xts+ where+ -- NV TODO: Turn this into a proper error+ go [] = panic Nothing "Bound with empty symbols"++ go [(x, t)] = [(dummySymbol, tp t x), (dummySymbol, tq t x)]+ go ((x, t):xtss) = (val x, mkt t x):(go xtss)++ mkt t x = ofRSort t `strengthen` ofUReft (MkUReft (Reft (val x, mempty))+ (Pr $ M.lookupDefault [] (val x) ps) mempty)+ tp t x = ofRSort t `strengthen` ofUReft (MkUReft (Reft (val x, pAnd rs))+ (Pr $ M.lookupDefault [] (val x) ps) mempty)+ tq t x = ofRSort t `strengthen` makeRef penv x q++ (ps, rs) = partitionPs penv qs+++-- NV TODO: Turn this into a proper error+makeBoundType _ _ _ = panic Nothing "Bound with empty predicates"+++partitionPs :: [(Symbol, Symbol)] -> [Expr] -> (M.HashMap Symbol [UsedPVar], [Expr])+partitionPs penv qs = mapFst makeAR $ partition (isPApp penv) qs+ where+ makeAR ps = M.fromListWith (++) $ map (toUsedPVars penv) ps++isPApp penv (EApp (EVar p) _) = isJust $ lookup p penv+isPApp penv (EApp e _) = isPApp penv e +isPApp _ _ = False++toUsedPVars penv q@(EApp _ e) = (x, [toUsedPVar penv q])+ where+ -- NV : TODO make this a better error+ x = case unProp e of {EVar x -> x; e -> todo Nothing ("Bound fails in " ++ show e) }+toUsedPVars _ _ = impossible Nothing "This cannot happen"++unProp (EApp (EVar f) e)+ | f == propConName+ = e+unProp e+ = e++toUsedPVar penv ee@(EApp _ _)+ = PV q (PVProp ()) e (((), dummySymbol,) <$> es')+ where+ EVar e = unProp $ last es+ es' = init es+ Just q = lookup p penv+ (EVar p, es) = splitEApp ee ++toUsedPVar _ _ = impossible Nothing "This cannot happen"++-- `makeRef` is used to make the refinement of the last implication,+-- thus it can contain both concrete and abstract refinements++makeRef :: (UReftable r) => [(Symbol, Symbol)] -> LocSymbol -> Expr -> r+makeRef penv v (PAnd rs) = ofUReft (MkUReft (Reft (val v, pAnd rrs)) r mempty)+ where+ r = Pr (toUsedPVar penv <$> pps)+ (pps, rrs) = partition (isPApp penv) rs++makeRef penv v rr+ | isPApp penv rr = ofUReft (MkUReft (Reft(val v, mempty)) r mempty)+ where+ r = Pr [toUsedPVar penv rr]++makeRef _ v p = ofReft (Reft(val v, p))
+ src/Language/Haskell/Liquid/Types/Dictionaries.hs view
@@ -0,0 +1,65 @@+module Language.Haskell.Liquid.Types.Dictionaries (+ makeDictionaries+ , makeDictionary++ , dfromList+ , dmapty+ , dmap+ , dinsert+ , dlookup+ , dhasinfo+ ) where++import Prelude hiding (error)++import Var++++import Language.Fixpoint.Types++import Language.Haskell.Liquid.GHC.Misc (dropModuleNames)+import Language.Haskell.Liquid.Types+import Language.Haskell.Liquid.Misc (mapFst)++import qualified Data.HashMap.Strict as M+import Language.Haskell.Liquid.Types.PrettyPrint ()++makeDictionaries :: [RInstance SpecType] -> DEnv Symbol SpecType+makeDictionaries = DEnv . M.fromList . map makeDictionary+++makeDictionary :: RInstance SpecType -> (Symbol, M.HashMap Symbol SpecType)+makeDictionary (RI c t xts) = (makeDictionaryName c t, M.fromList (mapFst val <$> xts))++makeDictionaryName :: Located Symbol -> SpecType -> Symbol+makeDictionaryName t (RApp c _ _ _) = symbol ("$f" ++ symbolString (val t) ++ c')+ where+ c' = symbolString (dropModuleNames $ symbol $ rtc_tc c)++makeDictionaryName _ _ = panic Nothing "makeDictionaryName: called with invalid type"++------------------------------------------------------------------------------+------------------------------------------------------------------------------+------------------------ Dictionay Environment -------------------------------+------------------------------------------------------------------------------+------------------------------------------------------------------------------+++dfromList :: [(Var, M.HashMap Symbol t)] -> DEnv Var t+dfromList = DEnv . M.fromList++dmapty :: (a -> b) -> DEnv v a -> DEnv v b+dmapty f (DEnv e) = DEnv (M.map (M.map f) e)++dmap f xts = M.map f xts++dinsert (DEnv denv) x xts = DEnv $ M.insert x xts denv++dlookup (DEnv denv) x = M.lookup x denv+++dhasinfo Nothing _ = Nothing+dhasinfo (Just xts) x = M.lookup x' xts+ where+ x' = (dropModuleNames $ symbol $ show x)
+ src/Language/Haskell/Liquid/Types/Errors.hs view
@@ -0,0 +1,674 @@+{-# LANGUAGE ImplicitParams #-}+{-# LANGUAGE TupleSections #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE DeriveFunctor #-}+{-# LANGUAGE OverloadedStrings #-}++-- | This module contains the *types* related creating Errors.+-- It depends only on Fixpoint and basic haskell libraries,+-- and hence, should be importable everywhere.++module Language.Haskell.Liquid.Types.Errors (+ -- * Generic Error Type+ TError (..)++ -- * Error with Source Context+ , CtxError (..)+ , errorWithContext++ -- * Subtyping Obligation Type+ , Oblig (..)++ -- * Panic (unexpected failures)+ , UserError+ --, HiddenType (..)+ , panic+ , panicDoc+ , todo+ , impossible+ , uError++ -- * Printing Errors+ , ppError+ , ppError'++ -- * SrcSpan Helpers+ , realSrcSpan+ , unpackRealSrcSpan+ ) where++import Prelude hiding (error)++import SrcLoc -- (SrcSpan (..), noSrcSpan)+import FastString+import GHC.Generics+import Control.DeepSeq+import Data.Typeable (Typeable)+import Data.Generics (Data)+import Data.Maybe+import Text.PrettyPrint.HughesPJ+import Data.Aeson hiding (Result)+import qualified Data.HashMap.Strict as M+import Language.Fixpoint.Types (showpp, Tidy (..), PPrint (..), pprint, Symbol, Expr)+import Language.Fixpoint.Misc (dcolon)+import Language.Haskell.Liquid.Misc (intToString)+import Text.Parsec.Error (ParseError)+import qualified Control.Exception as Ex+import System.Directory+import System.FilePath+import Data.List (intersperse )+import Text.Parsec.Error (errorMessages, showErrorMessages)++++instance PPrint ParseError where+ pprintTidy _ e = vcat $ tail $ map text ls+ where+ ls = lines $ showErrorMessages "or" "unknown parse error"+ "expecting" "unexpected" "end of input"+ (errorMessages e)++--------------------------------------------------------------------------------+-- | Context information for Error Messages ------------------------------------+--------------------------------------------------------------------------------+data CtxError t = CtxError+ { ctErr :: TError t+ , ctCtx :: Doc+ } deriving (Functor)++instance Eq (CtxError t) where+ e1 == e2 = ctErr e1 == ctErr e2++instance Ord (CtxError t) where+ e1 <= e2 = ctErr e1 <= ctErr e2++--------------------------------------------------------------------------------+errorWithContext :: TError t -> IO (CtxError t)+--------------------------------------------------------------------------------+errorWithContext e = CtxError e <$> srcSpanContext (pos e)++srcSpanContext :: SrcSpan -> IO Doc+srcSpanContext sp+ | Just (f, l, c, c') <- srcSpanInfo sp+ = maybe empty (makeContext l c c') <$> getFileLine f l+ | otherwise+ = return empty++srcSpanInfo :: SrcSpan -> Maybe (FilePath, Int, Int, Int)+srcSpanInfo (RealSrcSpan s)+ | l == l' = Just (f, l, c, c')+ | otherwise = Nothing+ where+ f = unpackFS $ srcSpanFile s+ l = srcSpanStartLine s+ c = srcSpanStartCol s+ l' = srcSpanEndLine s+ c' = srcSpanEndCol s+srcSpanInfo _ = Nothing++getFileLine :: FilePath -> Int -> IO (Maybe String)+getFileLine f i = do+ b <- doesFileExist f+ if b+ then getNth (i - 1) . lines <$> readFile f+ else return Nothing++getNth :: Int -> [a] -> Maybe a+getNth i xs+ | i < length xs = Just (xs !! i)+ | otherwise = Nothing++makeContext :: Int -> Int -> Int -> String -> Doc+makeContext l c c' s = vcat [ text ""+ , lnum l <+> (text s $+$ cursor)+ , text ""+ ]+ where+ lnum n = text (show n) <+> text "|"+ cursor = blanks (c - 1) <> pointer (c' - c)+ blanks n = text $ replicate n ' '+ pointer n = text $ replicate n '^'++--------------------------------------------------------------------------------+-- | Different kinds of Check "Obligations" ------------------------------------+--------------------------------------------------------------------------------++data Oblig+ = OTerm -- ^ Obligation that proves termination+ | OInv -- ^ Obligation that proves invariants+ | OCons -- ^ Obligation that proves subtyping constraints+ deriving (Generic, Data, Typeable)++instance Show Oblig where+ show OTerm = "termination-condition"+ show OInv = "invariant-obligation"+ show OCons = "constraint-obligation"++instance NFData Oblig++instance PPrint Oblig where+ pprintTidy _ = ppOblig++ppOblig :: Oblig -> Doc+ppOblig OCons = text "Constraint Check"+ppOblig OTerm = text "Termination Check"+ppOblig OInv = text "Invariant Check"++--------------------------------------------------------------------------------+-- | Generic Type for Error Messages -------------------------------------------+--------------------------------------------------------------------------------++-- | INVARIANT : all Error constructors should have a pos field++data TError t =+ ErrSubType { pos :: !SrcSpan+ , msg :: !Doc+ , ctx :: !(M.HashMap Symbol t)+ , tact :: !t+ , texp :: !t+ } -- ^ liquid type error++ | ErrFCrash { pos :: !SrcSpan+ , msg :: !Doc+ , ctx :: !(M.HashMap Symbol t)+ , tact :: !t+ , texp :: !t+ } -- ^ liquid type error++ | ErrAssType { pos :: !SrcSpan+ , obl :: !Oblig+ , msg :: !Doc+ , ctx :: !(M.HashMap Symbol t)+ , cond :: t+ } -- ^ condition failure error++ | ErrParse { pos :: !SrcSpan+ , msg :: !Doc+ , pErr :: !ParseError+ } -- ^ specification parse error++ | ErrTySpec { pos :: !SrcSpan+ , var :: !Doc+ , typ :: !t+ , msg :: !Doc+ } -- ^ sort error in specification++ | ErrTermSpec { pos :: !SrcSpan+ , var :: !Doc+ , exp :: !Expr+ , msg :: !Doc+ } -- ^ sort error in specification++ | ErrDupAlias { pos :: !SrcSpan+ , var :: !Doc+ , kind :: !Doc+ , locs :: ![SrcSpan]+ } -- ^ multiple alias with same name error++ | ErrDupSpecs { pos :: !SrcSpan+ , var :: !Doc+ , locs:: ![SrcSpan]+ } -- ^ multiple specs for same binder error++ | ErrDupMeas { pos :: !SrcSpan+ , var :: !Doc+ , tycon :: !Doc+ , locs:: ![SrcSpan]+ } -- ^ multiple definitions of the same measure+++ | ErrBadData { pos :: !SrcSpan+ , var :: !Doc+ , msg :: !Doc+ } -- ^ bad data type specification (?)++ | ErrDataCon { pos :: !SrcSpan+ , var :: !Doc+ , msg :: !Doc+ } -- ^ refined datacon mismatches haskell datacon++ | ErrInvt { pos :: !SrcSpan+ , inv :: !t+ , msg :: !Doc+ } -- ^ Invariant sort error++ | ErrIAl { pos :: !SrcSpan+ , inv :: !t+ , msg :: !Doc+ } -- ^ Using sort error++ | ErrIAlMis { pos :: !SrcSpan+ , tAs :: !t+ , tUs :: !t+ , msg :: !Doc+ } -- ^ Incompatible using error++ | ErrMeas { pos :: !SrcSpan+ , ms :: !Doc+ , msg :: !Doc+ } -- ^ Measure sort error++ | ErrHMeas { pos :: !SrcSpan+ , ms :: !Doc+ , msg :: !Doc+ } -- ^ Haskell bad Measure error++ | ErrUnbound { pos :: !SrcSpan+ , var :: !Doc+ } -- ^ Unbound symbol in specification++ | ErrGhc { pos :: !SrcSpan+ , msg :: !Doc+ } -- ^ GHC error: parsing or type checking++ | ErrMismatch { pos :: !SrcSpan -- ^ haskell type location+ , var :: !Doc+ , hs :: !Doc+ , lq :: !Doc+ , lqPos :: !SrcSpan -- ^ lq type location+ } -- ^ Mismatch between Liquid and Haskell types++ | ErrPartPred { pos :: !SrcSpan+ , ectr :: !Doc+ , var :: !Doc+ , argN :: !Int+ , expN :: !Int+ , actN :: !Int+ } -- ^ Mismatch in expected/actual args of abstract refinement++ | ErrAliasCycle { pos :: !SrcSpan+ , acycle :: ![(SrcSpan, Doc)]+ } -- ^ Cyclic Refined Type Alias Definitions++ | ErrIllegalAliasApp { pos :: !SrcSpan+ , dname :: !Doc+ , dpos :: !SrcSpan+ } -- ^ Illegal RTAlias application (from BSort, eg. in PVar)++ | ErrAliasApp { pos :: !SrcSpan+ , nargs :: !Int+ , dname :: !Doc+ , dpos :: !SrcSpan+ , dargs :: !Int+ }++ | ErrSaved { pos :: !SrcSpan+ , msg :: !Doc+ } -- ^ Previously saved error, that carries over after DiffCheck++ | ErrTermin { pos :: !SrcSpan+ , bind :: ![Doc]+ , msg :: !Doc+ } -- ^ Termination Error++ | ErrRClass { pos :: !SrcSpan+ , cls :: !Doc+ , insts :: ![(SrcSpan, Doc)]+ } -- ^ Refined Class/Interfaces Conflict++ | ErrBadQual { pos :: !SrcSpan+ , qname :: !Doc+ , msg :: !Doc+ } -- ^ Non well sorted Qualifier++ | ErrOther { pos :: SrcSpan+ , msg :: !Doc+ } -- ^ Sigh. Other.++ deriving (Typeable, Generic, Functor)++instance NFData ParseError where+ rnf t = seq t ()++-- FIXME ES: this is very suspicious, why can't we have multiple errors+-- arising from the same span?++instance Eq (TError a) where+ e1 == e2 = errSpan e1 == errSpan e2++instance Ord (TError a) where+ e1 <= e2 = errSpan e1 <= errSpan e2+++errSpan :: TError a -> SrcSpan+errSpan = pos++--------------------------------------------------------------------------------+-- | Simple unstructured type for panic ----------------------------------------+--------------------------------------------------------------------------------+type UserError = TError Doc++instance PPrint SrcSpan where+ pprintTidy _ = pprSrcSpan++pprSrcSpan :: SrcSpan -> Doc+pprSrcSpan (UnhelpfulSpan s) = text $ unpackFS s+pprSrcSpan (RealSrcSpan s) = pprRealSrcSpan s++pprRealSrcSpan :: RealSrcSpan -> Doc+pprRealSrcSpan span+ | sline == eline && scol == ecol =+ hcat [ pathDoc <> colon+ , int sline <> colon+ , int scol+ ]+ | sline == eline =+ hcat $ [ pathDoc <> colon+ , int sline <> colon+ , int scol+ ] ++ if ecol - scol <= 1 then [] else [char '-' <> int (ecol - 1)]+ | otherwise =+ hcat [ pathDoc <> colon+ , parens (int sline <> comma <> int scol)+ , char '-'+ , parens (int eline <> comma <> int ecol')+ ]+ where+ path = srcSpanFile span+ sline = srcSpanStartLine span+ eline = srcSpanEndLine span+ scol = srcSpanStartCol span+ ecol = srcSpanEndCol span++ pathDoc = text $ normalise $ unpackFS path+ ecol' = if ecol == 0 then ecol else ecol - 1++instance PPrint UserError where+ pprintTidy k = ppError k empty . fmap pprint++instance Show UserError where+ show = showpp++instance Ex.Exception UserError++-- | Construct and show an Error, then crash+uError :: UserError -> a+uError = Ex.throw++-- | Construct and show an Error, then crash+panicDoc :: {- (?callStack :: CallStack) => -} SrcSpan -> Doc -> a+panicDoc sp d = Ex.throw (ErrOther sp d :: UserError)++-- | Construct and show an Error, then crash+panic :: {- (?callStack :: CallStack) => -} Maybe SrcSpan -> String -> a+panic sp d = panicDoc (sspan sp) (text d)+ where+ sspan = fromMaybe noSrcSpan++-- | Construct and show an Error with an optional SrcSpan, then crash+-- This function should be used to mark unimplemented functionality+todo :: {- (?callStack :: CallStack) => -} Maybe SrcSpan -> String -> a+todo s m = panic s $ unlines+ [ "This functionality is currently unimplemented. "+ , "If this functionality is critical to you, please contact us at: "+ , "https://github.com/ucsd-progsys/liquidhaskell/issues"+ , m+ ]++-- | Construct and show an Error with an optional SrcSpan, then crash+-- This function should be used to mark impossible-to-reach codepaths+impossible :: {- (?callStack :: CallStack) => -} Maybe SrcSpan -> String -> a+impossible s m = panic s $ unlines msg ++ m+ where+ msg = [ "This should never happen! If you are seeing this message, "+ , "please submit a bug report at "+ , "https://github.com/ucsd-progsys/liquidhaskell/issues "+ , "with this message and the source file that caused this error."+ , ""+ ]++++-- type CtxError = Error+--------------------------------------------------------------------------------+ppError :: (PPrint a, Show a) => Tidy -> Doc -> TError a -> Doc+--------------------------------------------------------------------------------+ppError k dCtx e = ppError' k dSp dCtx e+ where+ dSp = pprint (pos e) <> text ": Error:"++nests n = foldr (\d acc -> nest n (d $+$ acc)) empty+sepVcat d ds = vcat $ intersperse d ds+blankLine = sizedText 5 " "++ppFull :: Tidy -> Doc -> Doc+ppFull Full d = d+ppFull Lossy _ = empty++ppReqInContext :: (PPrint t, PPrint c) => t -> t -> c -> Doc+ppReqInContext tA tE c+ = sepVcat blankLine+ [ nests 2 [ text "Inferred type"+ , text "VV :" <+> pprint tA]+ , nests 2 [ text "not a subtype of Required type"+ , text "VV :" <+> pprint tE]+ , nests 2 [ text "In Context"+ , pprint c ]]+++ppPropInContext :: (PPrint p, PPrint c) => p -> c -> Doc+ppPropInContext p c+ = sepVcat blankLine+ [ nests 2 [ text "Property"+ , pprint p]+ , nests 2 [ text "Not provable in context"+ , pprint c ]]++instance ToJSON RealSrcSpan where+ toJSON sp = object [ "filename" .= f+ , "startLine" .= l1+ , "startCol" .= c1+ , "endLine" .= l2+ , "endCol" .= c2+ ]+ where+ (f, l1, c1, l2, c2) = unpackRealSrcSpan sp++unpackRealSrcSpan rsp = (f, l1, c1, l2, c2)+ where+ f = unpackFS $ srcSpanFile rsp+ l1 = srcSpanStartLine rsp+ c1 = srcSpanStartCol rsp+ l2 = srcSpanEndLine rsp+ c2 = srcSpanEndCol rsp+++instance FromJSON RealSrcSpan where+ parseJSON (Object v) = realSrcSpan <$> v .: "filename"+ <*> v .: "startLine"+ <*> v .: "startCol"+ <*> v .: "endLine"+ <*> v .: "endCol"+ parseJSON _ = mempty++realSrcSpan :: FilePath -> Int -> Int -> Int -> Int -> RealSrcSpan+realSrcSpan f l1 c1 l2 c2 = mkRealSrcSpan loc1 loc2+ where+ loc1 = mkRealSrcLoc (fsLit f) l1 c1+ loc2 = mkRealSrcLoc (fsLit f) l2 c2++instance ToJSON SrcSpan where+ toJSON (RealSrcSpan rsp) = object [ "realSpan" .= True, "spanInfo" .= rsp ]+ toJSON (UnhelpfulSpan _) = object [ "realSpan" .= False ]++instance FromJSON SrcSpan where+ parseJSON (Object v) = do tag <- v .: "realSpan"+ case tag of+ False -> return noSrcSpan+ True -> RealSrcSpan <$> v .: "spanInfo"+ parseJSON _ = mempty++instance (PPrint a, Show a) => ToJSON (TError a) where+ toJSON e = object [ "pos" .= (pos e)+ , "msg" .= (render $ ppError' Full empty empty e)+ ]++instance FromJSON (TError a) where+ parseJSON (Object v) = errSaved <$> v .: "pos"+ <*> v .: "msg"+ parseJSON _ = mempty++errSaved :: SrcSpan -> String -> TError a+errSaved x = ErrSaved x . text++--------------------------------------------------------------------------------+ppError' :: (PPrint a, Show a) => Tidy -> Doc -> Doc -> TError a -> Doc+--------------------------------------------------------------------------------+ppError' td dSp dCtx (ErrAssType _ o _ c p)+ = dSp <+> pprint o+ $+$ dCtx+ $+$ (ppFull td $ ppPropInContext p c)++ppError' td dSp dCtx (ErrSubType _ _ c tA tE)+ = dSp <+> text "Liquid Type Mismatch"+ $+$ dCtx+ $+$ (ppFull td $ ppReqInContext tA tE c)++ppError' td dSp dCtx (ErrFCrash _ _ c tA tE)+ = dSp <+> text "Fixpoint Crash on Constraint"+ $+$ dCtx+ $+$ (ppFull td $ ppReqInContext tA tE c)++ppError' _ dSp dCtx (ErrParse _ _ e)+ = dSp <+> text "Cannot parse specification:"+ $+$ dCtx+ $+$ (nest 4 $ pprint e)++ppError' _ dSp _ (ErrTySpec _ v t s)+ = dSp <+> text "Bad Type Specification"+ $+$ (pprint v <+> dcolon <+> pprint t)+ $+$ (nest 4 $ pprint s)++ppError' _ dSp _ (ErrBadData _ v s)+ = dSp <+> text "Bad Data Specification"+ $+$ (pprint v <+> dcolon <+> pprint s)++ppError' _ dSp dCtx (ErrDataCon _ d s)+ = dSp <+> "Malformed refined data constructor" <+> pprint d+ $+$ dCtx+ $+$ s++ppError' _ dSp dCtx (ErrBadQual _ n d)+ = dSp <+> text "Bad Qualifier Specification for" <+> n+ $+$ dCtx+ $+$ (pprint d)++ppError' _ dSp _ (ErrTermSpec _ v e s)+ = dSp <+> text "Bad Termination Specification"+ $+$ (pprint v <+> dcolon <+> pprint e)+ $+$ (nest 4 $ pprint s)++ppError' _ dSp _ (ErrInvt _ t s)+ = dSp <+> text "Bad Invariant Specification"+ $+$ (nest 4 $ text "invariant " <+> pprint t $+$ pprint s)++ppError' _ dSp _ (ErrIAl _ t s)+ = dSp <+> text "Bad Using Specification"+ $+$ (nest 4 $ text "as" <+> pprint t $+$ pprint s)++ppError' _ dSp _ (ErrIAlMis _ t1 t2 s)+ = dSp <+> text "Incompatible Using Specification"+ $+$ (nest 4 $ (text "using" <+> pprint t1 <+> text "as" <+> pprint t2) $+$ pprint s)++ppError' _ dSp _ (ErrMeas _ t s)+ = dSp <+> text "Bad Measure Specification"+ $+$ (nest 4 $ text "measure " <+> pprint t $+$ pprint s)++ppError' _ dSp _ (ErrHMeas _ t s)+ = dSp <+> text "Cannot promote Haskell function" <+> pprint t <+> text "to logic"+ $+$ (nest 4 $ pprint s)++ppError' _ dSp _ (ErrDupSpecs _ v ls)+ = dSp <+> text "Multiple Specifications for" <+> pprint v <> colon+ $+$ (nest 4 $ vcat $ pprint <$> ls)++ppError' _ dSp _ (ErrDupMeas _ v t ls)+ = dSp <+> text "Multiple Instance Measures for" <+> pprint v+ <+> text "and" <+> pprint t+ <> colon+ $+$ (nest 4 $ vcat $ pprint <$> ls)++ppError' _ dSp _ (ErrDupAlias _ k v ls)+ = dSp <+> text "Multiple Declarations! "+ $+$ (nest 2 $ text "Multiple Declarations of" <+> pprint k <+> ppVar v $+$ text "Declared at:")+ <+> (nest 4 $ vcat $ pprint <$> ls)++ppError' _ dSp dCtx (ErrUnbound _ x)+ = dSp <+> text "Unbound variable" <+> pprint x+ $+$ dCtx++ppError' _ dSp dCtx (ErrGhc _ s)+ = dSp <+> text "GHC Error"+ $+$ dCtx+ $+$ (nest 4 $ pprint s)++ppError' _ dSp dCtx (ErrPartPred _ c p i eN aN)+ = dSp <+> text "Malformed Predicate Application"+ $+$ dCtx+ $+$ (nest 4 $ vcat [ "The" <+> text (intToString i) <+> "argument of" <+> c <+> "is predicate" <+> p+ , "which expects" <+> pprint eN <+> "arguments" <+> "but is given only" <+> pprint aN+ , "Abstract predicates cannot be partially applied, see "+ , nest 2 "https://github.com/ucsd-progsys/liquidhaskell/issues/594"+ , "for possible fix."+ ])++ppError' _ dSp dCtx (ErrMismatch _ x τ t hsSp)+ = dSp <+> "Specified Type Does Not Refine Haskell Type for" <+> pprint x+ $+$ dCtx+ $+$ (sepVcat blankLine+ [ "The Liquid type"+ , nest 4 t+ , "is inconsistent with the Haskell type"+ , nest 4 τ+ , "defined at" <+> pprint hsSp+ ])++ppError' _ dSp _ (ErrAliasCycle _ acycle)+ = dSp <+> text "Cyclic Alias Definitions"+ $+$ text "The following alias definitions form a cycle:"+ $+$ (nest 4 $ sepVcat blankLine $ map describe acycle)+ where+ describe (p, n)+ = text "Type alias:" <+> pprint n+ $+$ text "Defined at:" <+> pprint p++ppError' _ dSp dCtx (ErrIllegalAliasApp _ dn dl)+ = dSp <+> text "Refinement Type Alias cannot be used in this context"+ $+$ dCtx+ $+$ text "Type alias:" <+> pprint dn+ $+$ text "Defined at:" <+> pprint dl++ppError' _ dSp dCtx (ErrAliasApp _ n name dl dn)+ = dSp <+> text "Malformed Type Alias Application"+ $+$ dCtx+ $+$ text "Type alias:" <+> pprint name+ $+$ text "Defined at:" <+> pprint dl+ $+$ text "Expects" <+> pprint dn <+> text "arguments, but is given" <+> pprint n++ppError' _ dSp _ (ErrSaved _ s)+ = dSp <+> s++ppError' _ dSp dCtx (ErrOther _ s)+ = dSp <+> text "Uh oh."+ $+$ dCtx+ $+$ nest 4 s++ppError' _ dSp _ (ErrTermin _ xs s)+ = dSp <+> text "Termination Error"+ <+> (hsep $ intersperse comma xs) $+$ s++ppError' _ dSp _ (ErrRClass p0 c is)+ = dSp <+> text "Refined classes cannot have refined instances"+ $+$ (nest 4 $ sepVcat blankLine $ describeCls : map describeInst is)+ where+ describeCls+ = text "Refined class definition for:" <+> c+ $+$ text "Defined at:" <+> pprint p0+ describeInst (p, t)+ = text "Refined instance for:" <+> t+ $+$ text "Defined at:" <+> pprint p++ppVar v = text "`" <> pprint v <> text "'"
+ src/Language/Haskell/Liquid/Types/Literals.hs view
@@ -0,0 +1,58 @@+{-# LANGUAGE OverloadedStrings #-}++module Language.Haskell.Liquid.Types.Literals (+ literalFRefType+ , literalFReft+ , literalConst+ ) where++import Prelude hiding (error)+import TypeRep+import Literal+import qualified TyCon as TC+import Language.Haskell.Liquid.Measure+import Language.Haskell.Liquid.Types+import Language.Haskell.Liquid.Types.RefType+import Language.Haskell.Liquid.Transforms.CoreToLogic (mkLit)+++import qualified Language.Fixpoint.Types as F++import qualified Data.Text as T+++++---------------------------------------------------------------+----------------------- Typing Literals -----------------------+---------------------------------------------------------------++makeRTypeBase (TyVarTy α) x+ = RVar (rTyVar α) x+makeRTypeBase (TyConApp c ts) x+ = rApp c ((`makeRTypeBase` mempty) <$> ts) [] x+makeRTypeBase _ _+ = panic Nothing "RefType : makeRTypeBase"++literalFRefType l+ = makeRTypeBase (literalType l) (literalFReft l)++literalFReft l = maybe mempty mkReft $ mkLit l++mkReft e = case e of+ F.ESym (F.SL str) ->+ -- FIXME: unsorted equality is shady, better to not embed Add# as int..+ F.meet (F.uexprReft e)+ (F.reft "v" (F.PAtom F.Eq+ (F.mkEApp (name strLen) [F.EVar "v"])+ (F.ECon (F.I (fromIntegral (T.length str))))))+ _ -> F.exprReft e++-- | `literalConst` returns `Nothing` for unhandled lits because+-- otherwise string-literals show up as global int-constants+-- which blow up qualifier instantiation.++literalConst :: F.TCEmb TC.TyCon -> Literal -> (F.Sort, Maybe F.Expr)+literalConst tce l = (t, mkLit l)+ where+ t = typeSort tce $ literalType l
+ src/Language/Haskell/Liquid/Types/Meet.hs view
@@ -0,0 +1,28 @@+-- | This code has various wrappers around `meet` and `strengthen`+-- that are here so that we can throw decent error messages if+-- they fail. The module depends on `RefType` and `UX.Tidy`.++module Language.Haskell.Liquid.Types.Meet+ ( meetVarTypes ) where++import SrcLoc+import Text.PrettyPrint.HughesPJ (Doc)+import qualified Language.Fixpoint.Types as F+import Language.Haskell.Liquid.Types++import Language.Haskell.Liquid.Types.RefType+import Language.Haskell.Liquid.UX.Tidy++meetVarTypes :: Doc -> (SrcSpan, SpecType) -> (SrcSpan, SpecType) -> SpecType+meetVarTypes v hs lq = meetError err hsT lqT+ where+ (hsSp, hsT) = hs+ (lqSp, lqT) = lq+ err = ErrMismatch lqSp v hsD lqD hsSp+ hsD = pprint (toRSort hsT)+ lqD = pprint (toRSort lqT)++meetError :: Error -> SpecType -> SpecType -> SpecType+meetError e t t'+ | meetable t t' = t `F.meet` t'+ | otherwise = panicError e
+ src/Language/Haskell/Liquid/Types/Names.hs view
@@ -0,0 +1,6 @@+module Language.Haskell.Liquid.Types.Names where++import Language.Fixpoint.Types+++lenLocSymbol = dummyLoc $ symbol ("autolen" :: String)
+ src/Language/Haskell/Liquid/Types/PredType.hs view
@@ -0,0 +1,355 @@+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TupleSections #-}+{-# LANGUAGE UndecidableInstances #-}++module Language.Haskell.Liquid.Types.PredType (+ PrType+ , TyConP (..), DataConP (..)+ , dataConTy+ , dataConPSpecType+ , makeTyConInfo+ , replacePreds++ , replacePredsWithRefs+ , pVartoRConc++ -- * Dummy `Type` that represents _all_ abstract-predicates+ , predType++ -- * Compute @RType@ of a given @PVar@+ , pvarRType++ , substParg+ , pApp+ , pappSort, pappArity+ ) where++import Prelude hiding (error)+import DataCon+import Text.PrettyPrint.HughesPJ+import qualified TyCon as TC+import Type+import TypeRep++import qualified Data.HashMap.Strict as M+import Data.List (foldl', partition)++import Language.Fixpoint.Misc++import Language.Fixpoint.Types hiding (Expr, Predicate)+import qualified Language.Fixpoint.Types as F+import Language.Haskell.Liquid.GHC.Misc+import Language.Haskell.Liquid.Misc+import Language.Haskell.Liquid.Types.RefType hiding (generalize)+import Language.Haskell.Liquid.Types+++import Data.List (nub)+++import Data.Default++makeTyConInfo = hashMapMapWithKey mkRTyCon . M.fromList++mkRTyCon :: TC.TyCon -> TyConP -> RTyCon+mkRTyCon tc (TyConP αs' ps _ tyvariance predvariance size) = RTyCon tc pvs' (mkTyConInfo tc tyvariance predvariance size)+ where τs = [rVar α :: RSort | α <- tyConTyVarsDef tc]+ pvs' = subts (zip αs' τs) <$> ps++dataConPSpecType :: DataCon -> DataConP -> SpecType+dataConPSpecType dc (DataConP _ vs ps ls cs yts rt _) = mkArrow vs ps ls ts' rt'+ where+ (xs, ts) = unzip $ reverse yts+ -- mkDSym = (`mappend` symbol dc) . (`mappend` "_") . symbol+ mkDSym z = (symbol z) `suffixSymbol` (symbol dc)+ ys = mkDSym <$> xs+ tx _ [] [] [] = []+ tx su (x:xs) (y:ys) (t:ts) = (y, subst (F.mkSubst su) t, mempty)+ : tx ((x, F.EVar y):su) xs ys ts+ tx _ _ _ _ = panic Nothing "PredType.dataConPSpecType.tx called on invalid inputs"+ yts' = tx [] xs ys ts+ ts' = map ("" , , mempty) cs ++ yts'+ su = F.mkSubst [(x, F.EVar y) | (x, y) <- zip xs ys]+ rt' = subst su rt++instance PPrint TyConP where+ pprintTidy k (TyConP vs ps ls _ _ _)+ = (parens $ hsep (punctuate comma (map (pprintTidy k) vs))) <+>+ (parens $ hsep (punctuate comma (map (pprintTidy k) ps))) <+>+ (parens $ hsep (punctuate comma (map (pprintTidy k) ls)))++instance Show TyConP where+ show = showpp -- showSDoc . ppr++instance PPrint DataConP where+ pprintTidy k (DataConP _ vs ps ls cs yts t _)+ = (parens $ hsep (punctuate comma (map (pprintTidy k) vs))) <+>+ (parens $ hsep (punctuate comma (map (pprintTidy k) ps))) <+>+ (parens $ hsep (punctuate comma (map (pprintTidy k) ls))) <+>+ (parens $ hsep (punctuate comma (map (pprintTidy k) cs))) <+>+ (parens $ hsep (punctuate comma (map (pprintTidy k) yts))) <+>+ pprintTidy k t++instance Show DataConP where+ show = showpp++dataConTy m (TyVarTy v)+ = M.lookupDefault (rVar v) (RTV v) m+dataConTy m (FunTy t1 t2)+ = rFun dummySymbol (dataConTy m t1) (dataConTy m t2)+dataConTy m (ForAllTy α t)+ = RAllT (rTyVar α) (dataConTy m t)+dataConTy m (TyConApp c ts)+ = rApp c (dataConTy m <$> ts) [] mempty+dataConTy _ _+ = panic Nothing "ofTypePAppTy"++----------------------------------------------------------------------------+----- Interface: Replace Predicate With Uninterprented Function Symbol -----+----------------------------------------------------------------------------++replacePredsWithRefs (p, r) (MkUReft (Reft(v, rs)) (Pr ps) s)+ = MkUReft (Reft (v, rs'')) (Pr ps2) s+ where+ rs'' = mconcat $ rs : rs'+ rs' = r . (v,) . pargs <$> ps1+ (ps1, ps2) = partition (== p) ps++pVartoRConc p (v, args) | length args == length (pargs p)+ = pApp (pname p) $ EVar v : (thd3 <$> args)++pVartoRConc p (v, args)+ = pApp (pname p) $ EVar v : args'+ where+ args' = (thd3 <$> args) ++ (drop (length args) (thd3 <$> pargs p))++-----------------------------------------------------------------------+-- | @pvarRType π@ returns a trivial @RType@ corresponding to the+-- function signature for a @PVar@ @π@. For example, if+-- @π :: T1 -> T2 -> T3 -> Prop@+-- then @pvarRType π@ returns an @RType@ with an @RTycon@ called+-- @predRTyCon@ `RApp predRTyCon [T1, T2, T3]`+-----------------------------------------------------------------------+pvarRType :: (PPrint r, Reftable r) => PVar RSort -> RRType r+-----------------------------------------------------------------------+pvarRType (PV _ k {- (PVProp τ) -} _ args) = rpredType k (fst3 <$> args) -- (ty:tys)+ -- where+ -- ty = uRTypeGen τ+ -- tys = uRTypeGen . fst3 <$> args+++-- rpredType :: (PPrint r, Reftable r) => PVKind (RRType r) -> [RRType r] -> RRType r+rpredType (PVProp t) ts = RApp predRTyCon (uRTypeGen <$> t : ts) [] mempty+rpredType PVHProp ts = RApp wpredRTyCon (uRTypeGen <$> ts) [] mempty++predRTyCon :: RTyCon+predRTyCon = symbolRTyCon predName++wpredRTyCon :: RTyCon+wpredRTyCon = symbolRTyCon wpredName++symbolRTyCon :: Symbol -> RTyCon+symbolRTyCon n = RTyCon (stringTyCon 'x' 42 $ symbolString n) [] def++-------------------------------------------------------------------------------------+-- | Instantiate `PVar` with `RTProp` -----------------------------------------------+-------------------------------------------------------------------------------------+-- | @replacePreds@ is the main function used to substitute an (abstract)+-- predicate with a concrete Ref, that is either an `RProp` or `RHProp`+-- type. The substitution is invoked to obtain the `SpecType` resulting+-- at /predicate application/ sites in 'Language.Haskell.Liquid.Constraint'.+-- The range of the `PVar` substitutions are /fresh/ or /true/ `RefType`.+-- That is, there are no further _quantified_ `PVar` in the target.+-------------------------------------------------------------------------------------+replacePreds :: String -> SpecType -> [(RPVar, SpecProp)] -> SpecType+-------------------------------------------------------------------------------------+replacePreds msg = foldl' go+ where+ go _ (_, RProp _ (RHole _)) = panic Nothing "replacePreds on RProp _ (RHole _)"+ go z (π, t) = substPred msg (π, t) z+++-- TODO: replace `replacePreds` with+-- instance SubsTy RPVar (Ref RReft SpecType) SpecType where+-- subt (pv, r) t = replacePreds "replacePred" t (pv, r)++-- replacePreds :: String -> SpecType -> [(RPVar, Ref Reft RefType)] -> SpecType+-- replacePreds msg = foldl' go+-- where go z (π, RProp t) = substPred msg (π, t) z+-- go z (π, RPropP r) = replacePVarReft (π, r) <$> z++-------------------------------------------------------------------------------+substPred :: String -> (RPVar, SpecProp) -> SpecType -> SpecType+-------------------------------------------------------------------------------++substPred _ (π, RProp ss (RVar a1 r1)) t@(RVar a2 r2)+ | isPredInReft && a1 == a2 = RVar a1 $ meetListWithPSubs πs ss r1 r2'+ | isPredInReft = panic Nothing ("substPred RVar Var Mismatch" ++ show (a1, a2))+ | otherwise = t+ where+ (r2', πs) = splitRPvar π r2+ isPredInReft = not $ null πs++substPred msg su@(π, _ ) (RApp c ts rs r)+ | null πs = t'+ | otherwise = substRCon msg su t' πs r2'+ where+ t' = RApp c (substPred msg su <$> ts) (substPredP msg su <$> rs) r+ (r2', πs) = splitRPvar π r++substPred msg (p, tp) (RAllP (q@(PV _ _ _ _)) t)+ | p /= q = RAllP q $ substPred msg (p, tp) t+ | otherwise = RAllP q t++substPred msg su (RAllT a t) = RAllT a (substPred msg su t)++substPred msg su@(π,_ ) (RFun x t t' r)+ | null πs = RFun x (substPred msg su t) (substPred msg su t') r+ | otherwise = {-meetListWithPSubs πs πt -}(RFun x t t' r')+ where (r', πs) = splitRPvar π r++substPred msg su (RRTy e r o t) = RRTy (mapSnd (substPred msg su) <$> e) r o (substPred msg su t)+substPred msg su (RAllE x t t') = RAllE x (substPred msg su t) (substPred msg su t')+substPred msg su (REx x t t') = REx x (substPred msg su t) (substPred msg su t')+substPred _ _ t = t++-- | Requires: @not $ null πs@+-- substRCon :: String -> (RPVar, SpecType) -> SpecType -> SpecType++substRCon msg (_, RProp ss t1@(RApp c1 ts1 rs1 r1)) t2@(RApp c2 ts2 rs2 _) πs r2'+ | rtc_tc c1 == rtc_tc c2 = RApp c1 ts rs $ meetListWithPSubs πs ss r1 r2'+ where+ ts = subst su $ safeZipWith (msg ++ ": substRCon") strSub ts1 ts2+ rs = subst su $ safeZipWith (msg ++ ": substRCon2") strSubR rs1' rs2'+ (rs1', rs2') = pad "substRCon" top rs1 rs2+ strSub r1 r2 = meetListWithPSubs πs ss r1 r2+ strSubR r1 r2 = meetListWithPSubsRef πs ss r1 r2++ su = mkSubst $ zipWith (\s1 s2 -> (s1, EVar s2)) (rvs t1) (rvs t2)++ rvs = foldReft (\_ r acc -> rvReft r : acc) []+ rvReft r = let Reft(s,_) = toReft r in s++substRCon msg su t _ _ = panic Nothing $ msg ++ " substRCon " ++ showpp (su, t)++pad _ f [] ys = (f <$> ys, ys)+pad _ f xs [] = (xs, f <$> xs)+pad msg _ xs ys+ | nxs == nys = (xs, ys)+ | otherwise = panic Nothing $ "pad: " ++ msg+ where+ nxs = length xs+ nys = length ys++substPredP _ su p@(RProp _ (RHole _))+ = panic Nothing ("PredType.substPredP1 called on invalid inputs: " ++ showpp (su, p))+substPredP msg su@(p, RProp ss _) (RProp s t)+ = RProp ss' $ substPred (msg ++ ": substPredP") su t+ where+ ss' = drop n ss ++ s+ n = length ss - length (freeArgsPs p t)+++splitRPvar pv (MkUReft x (Pr pvs) s) = (MkUReft x (Pr pvs') s, epvs)+ where+ (epvs, pvs') = partition (uPVar pv ==) pvs++-- TODO: rewrite using foldReft+freeArgsPs p (RVar _ r)+ = freeArgsPsRef p r+freeArgsPs p (RFun _ t1 t2 r)+ = nub $ freeArgsPsRef p r ++ freeArgsPs p t1 ++ freeArgsPs p t2+freeArgsPs p (RAllT _ t)+ = freeArgsPs p t+freeArgsPs p (RAllS _ t)+ = freeArgsPs p t+freeArgsPs p (RAllP p' t)+ | p == p' = []+ | otherwise = freeArgsPs p t+freeArgsPs p (RApp _ ts _ r)+ = nub $ freeArgsPsRef p r ++ concatMap (freeArgsPs p) ts+freeArgsPs p (RAllE _ t1 t2)+ = nub $ freeArgsPs p t1 ++ freeArgsPs p t2+freeArgsPs p (REx _ t1 t2)+ = nub $ freeArgsPs p t1 ++ freeArgsPs p t2+freeArgsPs p (RAppTy t1 t2 r)+ = nub $ freeArgsPsRef p r ++ freeArgsPs p t1 ++ freeArgsPs p t2+freeArgsPs _ (RExprArg _)+ = []+freeArgsPs p (RHole r)+ = freeArgsPsRef p r+freeArgsPs p (RRTy env r _ t)+ = nub $ concatMap (freeArgsPs p) (snd <$> env) ++ freeArgsPsRef p r ++ freeArgsPs p t++freeArgsPsRef p (MkUReft _ (Pr ps) _) = [x | (_, x, w) <- (concatMap pargs ps'), (EVar x) == w]+ where+ ps' = f <$> filter (uPVar p ==) ps+ f q = q {pargs = pargs q ++ drop (length (pargs q)) (pargs $ uPVar p)}++meetListWithPSubs πs ss r1 r2 = foldl' (meetListWithPSub ss r1) r2 πs++meetListWithPSubsRef πs ss r1 r2 = foldl' ((meetListWithPSubRef ss) r1) r2 πs++meetListWithPSub :: (Reftable r, PPrint t) => [(Symbol, RSort)]-> r -> r -> PVar t -> r+meetListWithPSub ss r1 r2 π+ | all (\(_, x, EVar y) -> x == y) (pargs π)+ = r2 `meet` r1+ | all (\(_, x, EVar y) -> x /= y) (pargs π)+ = r2 `meet` (subst su r1)+ | otherwise+ = panic Nothing $ "PredType.meetListWithPSub partial application to " ++ showpp π+ where+ su = mkSubst [(x, y) | (x, (_, _, y)) <- zip (fst <$> ss) (pargs π)]++meetListWithPSubRef _ (RProp _ (RHole _)) _ _ -- TODO: Is this correct?+ = panic Nothing "PredType.meetListWithPSubRef called with invalid input"+meetListWithPSubRef _ _ (RProp _ (RHole _)) _+ = panic Nothing "PredType.meetListWithPSubRef called with invalid input"+meetListWithPSubRef ss (RProp s1 r1) (RProp s2 r2) π+ | all (\(_, x, EVar y) -> x == y) (pargs π)+ = RProp s1 $ (subst su' r2) `meet` r1+ | all (\(_, x, EVar y) -> x /= y) (pargs π)+ = RProp s2 $ r2 `meet` (subst su r1)+ | otherwise+ = panic Nothing $ "PredType.meetListWithPSubRef partial application to " ++ showpp π+ where+ su = mkSubst [(x, y) | (x, (_, _, y)) <- zip (fst <$> ss) (pargs π)]+ su' = mkSubst [(x, EVar y) | (x, y) <- zip (fst <$> s2) (fst <$> s1)]+++----------------------------------------------------------------------------+-- | Interface: Modified CoreSyn.exprType due to predApp -------------------+----------------------------------------------------------------------------+predType :: Type+predType = symbolType predName++wpredName, predName :: Symbol+predName = "Pred"+wpredName = "WPred"++symbolType = TyVarTy . symbolTyVar+++substParg :: Functor f => (Symbol, F.Expr) -> f Predicate -> f Predicate+substParg (x, y) = fmap fp+ where+ fxy s = if (s == EVar x) then y else s+ fp = subvPredicate (\pv -> pv { pargs = mapThd3 fxy <$> pargs pv })++-------------------------------------------------------------------------------+----------------------------- Predicate Application --------------------------+-------------------------------------------------------------------------------+pappArity :: Int+pappArity = 7++pappSort :: Int -> Sort+pappSort n = mkFFunc (2 * n) $ [ptycon] ++ args ++ [boolSort]+ where+ ptycon = fAppTC predFTyCon $ FVar <$> [0..n-1]+ args = FVar <$> [n..(2*n-1)]+++predFTyCon = symbolFTycon $ dummyLoc predName
+ src/Language/Haskell/Liquid/Types/PrettyPrint.hs view
@@ -0,0 +1,331 @@+-- | This module contains a single function that converts a RType -> Doc+-- without using *any* simplifications.++{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE TupleSections #-}++module Language.Haskell.Liquid.Types.PrettyPrint+ ( -- * Printable RTypes+ OkRT+ -- * Printers+ , rtypeDoc+ , ppr_rtype++ -- * Printing Lists (TODO: move to fixpoint)+ , pprManyOrdered+ , pprintLongList+ , pprintSymbol++ ) where++import Prelude hiding (error)+import TypeRep hiding (maybeParen)+import ErrUtils (ErrMsg)+import HscTypes (SourceError)+import SrcLoc+import GHC (Name, Class)+import Var (Var)+import TyCon (TyCon)+import qualified Data.List as L -- (sort)+import qualified Data.HashMap.Strict as M+import Text.PrettyPrint.HughesPJ+import Language.Fixpoint.Misc+import Language.Haskell.Liquid.Misc+import Language.Haskell.Liquid.GHC.Misc+import Language.Fixpoint.Types hiding (Error, SrcSpan, Predicate)+import Language.Haskell.Liquid.Types hiding (sort)++--------------------------------------------------------------------------------+pprManyOrdered :: (PPrint a, Ord a) => Tidy -> String -> [a] -> [Doc]+--------------------------------------------------------------------------------+pprManyOrdered k msg = map ((text msg <+>) . pprintTidy k) . L.sort++--------------------------------------------------------------------------------+pprintLongList :: PPrint a => [a] -> Doc+--------------------------------------------------------------------------------+pprintLongList = brackets . vcat . map pprint+++--------------------------------------------------------------------------------+pprintSymbol :: Symbol -> Doc+--------------------------------------------------------------------------------+pprintSymbol x = char '‘' <> pprint x <> char '’'+++--------------------------------------------------------------------------------+-- | A whole bunch of PPrint instances follow ----------------------------------+--------------------------------------------------------------------------------+instance PPrint ErrMsg where+ pprintTidy _ = text . show++instance PPrint SourceError where+ pprintTidy _ = text . show++instance PPrint Var where+ pprintTidy _ = pprDoc++instance PPrint Name where+ pprintTidy _ = pprDoc++instance PPrint TyCon where+ pprintTidy _ = pprDoc++instance PPrint Type where+ pprintTidy _ = pprDoc -- . tidyType emptyTidyEnv -- WHY WOULD YOU DO THIS???++instance PPrint Class where+ pprintTidy _ = pprDoc++instance Show Predicate where+ show = showpp++instance (PPrint t) => PPrint (Annot t) where+ pprintTidy k (AnnUse t) = text "AnnUse" <+> pprintTidy k t+ pprintTidy k (AnnDef t) = text "AnnDef" <+> pprintTidy k t+ pprintTidy k (AnnRDf t) = text "AnnRDf" <+> pprintTidy k t+ pprintTidy _ (AnnLoc l) = text "AnnLoc" <+> pprDoc l++instance PPrint a => PPrint (AnnInfo a) where+ pprintTidy _ (AI m) = vcat $ map pprAnnInfoBinds $ M.toList m++instance PPrint a => Show (AnnInfo a) where+ show = showpp++pprAnnInfoBinds (l, xvs)+ = vcat $ map (pprAnnInfoBind . (l,)) xvs++pprAnnInfoBind (RealSrcSpan k, xv)+ = xd $$ pprDoc l $$ pprDoc c $$ pprint n $$ vd $$ text "\n\n\n"+ where+ l = srcSpanStartLine k+ c = srcSpanStartCol k+ (xd, vd) = pprXOT xv+ n = length $ lines $ render vd++pprAnnInfoBind (_, _)+ = empty++pprXOT (x, v) = (xd, pprint v)+ where+ xd = maybe (text "unknown") pprint x+--------------------------------------------------------------------------------+-- | Pretty Printing RefType ---------------------------------------------------+--------------------------------------------------------------------------------++-- Should just make this a @Pretty@ instance but its too damn tedious+-- to figure out all the constraints.++type OkRT c tv r = ( TyConable c+ , PPrint tv+ , PPrint c+ , PPrint r+ , Reftable r+ , Reftable (RTProp c tv ())+ , Reftable (RTProp c tv r)+ , RefTypable c tv ()+ , RefTypable c tv r+ , PPrint (RType c tv r)+ , PPrint (RType c tv ())+ )++--------------------------------------------------------------------------------+rtypeDoc :: (OkRT c tv r) => Tidy -> RType c tv r -> Doc+--------------------------------------------------------------------------------+rtypeDoc k = ppr_rtype (ppE k) TopPrec+ where+ ppE Lossy = ppEnvShort ppEnv+ ppE Full = ppEnv++--------------------------------------------------------------------------------+ppr_rtype :: (OkRT c tv r) => PPEnv -> Prec -> RType c tv r -> Doc+--------------------------------------------------------------------------------+ppr_rtype bb p t@(RAllT _ _)+ = ppr_forall bb p t+ppr_rtype bb p t@(RAllP _ _)+ = ppr_forall bb p t+ppr_rtype bb p t@(RAllS _ _)+ = ppr_forall bb p t+ppr_rtype _ _ (RVar a r)+ = ppTy r $ pprint a+ppr_rtype bb p t@(RFun _ _ _ r)+ = ppTy r $ maybeParen p FunPrec $ ppr_rty_fun bb empty t+ppr_rtype bb p (RApp c [t] rs r)+ | isList c+ = ppTy r $ brackets (ppr_rtype bb p t) <> ppReftPs bb p rs+ppr_rtype bb p (RApp c ts rs r)+ | isTuple c+ = ppTy r $ parens (intersperse comma (ppr_rtype bb p <$> ts)) <> ppReftPs bb p rs+ppr_rtype bb p (RApp c ts rs r)+ | isEmpty rsDoc && isEmpty tsDoc+ = ppTy r $ ppT c+ | otherwise+ = ppTy r $ parens $ ppT c <+> rsDoc <+> tsDoc+ where+ rsDoc = ppReftPs bb p rs+ tsDoc = hsep (ppr_rtype bb p <$> ts)+ ppT = ppTyConB bb++ppr_rtype bb p t@(REx _ _ _)+ = ppExists bb p t+ppr_rtype bb p t@(RAllE _ _ _)+ = ppAllExpr bb p t+ppr_rtype _ _ (RExprArg e)+ = braces $ pprint e+ppr_rtype bb p (RAppTy t t' r)+ = ppTy r $ ppr_rtype bb p t <+> ppr_rtype bb p t'+ppr_rtype bb p (RRTy e _ OCons t)+ = sep [braces (ppr_rsubtype bb p e) <+> "=>", ppr_rtype bb p t]+ppr_rtype bb p (RRTy e r o t)+ = sep [ppp (pprint o <+> ppe <+> pprint r), ppr_rtype bb p t]+ where+ ppe = (hsep $ punctuate comma (ppxt <$> e)) <+> dcolon+ ppp = \doc -> text "<<" <+> doc <+> text ">>"+ ppxt = \(x, t) -> pprint x <+> ":" <+> ppr_rtype bb p t+ppr_rtype _ _ (RHole r)+ = ppTy r $ text "_"++ppTyConB bb+ | ppShort bb = text . symbolString . dropModuleNames . symbol . render . ppTycon+ | otherwise = ppTycon++ppr_rsubtype bb p e+ = pprint_env <+> text "|-" <+> ppr_rtype bb p tl <+> "<:" <+> ppr_rtype bb p tr+ where+ (el, r) = (init e, last e)+ (env, l) = (init el, last el)+ tr = snd $ r+ tl = snd $ l+ pprint_bind (x, t) = pprint x <+> colon <> colon <+> ppr_rtype bb p t+ pprint_env = hsep $ punctuate comma (pprint_bind <$> env)++{- NUKE?+ppSpine (RAllT _ t) = text "RAllT" <+> parens (ppSpine t)+ppSpine (RAllP _ t) = text "RAllP" <+> parens (ppSpine t)+ppSpine (RAllS _ t) = text "RAllS" <+> parens (ppSpine t)+ppSpine (RAllE _ _ t) = text "RAllE" <+> parens (ppSpine t)+ppSpine (REx _ _ t) = text "REx" <+> parens (ppSpine t)+ppSpine (RFun _ i o _) = ppSpine i <+> text "->" <+> ppSpine o+ppSpine (RAppTy t t' _) = text "RAppTy" <+> parens (ppSpine t) <+> parens (ppSpine t')+ppSpine (RHole _) = text "RHole"+ppSpine (RApp c _ _ _) = text "RApp" <+> parens (pprint c)+ppSpine (RVar _ _) = text "RVar"+ppSpine (RExprArg _) = text "RExprArg"+ppSpine (RRTy _ _ _ _) = text "RRTy"++-}++-- | From GHC: TypeRep+maybeParen :: Prec -> Prec -> Doc -> Doc+maybeParen ctxt_prec inner_prec pretty+ | ctxt_prec < inner_prec = pretty+ | otherwise = parens pretty++-- ppExists :: (RefTypable p c tv (), RefTypable p c tv r) => Bool -> Prec -> RType p c tv r -> Doc+ppExists bb p t+ = text "exists" <+> brackets (intersperse comma [ppr_dbind bb TopPrec x t | (x, t) <- zs]) <> dot <> ppr_rtype bb p t'+ where (zs, t') = split [] t+ split zs (REx x t t') = split ((x,t):zs) t'+ split zs t = (reverse zs, t)++-- ppAllExpr :: (RefTypable p c tv (), RefTypable p c tv r) => Bool -> Prec -> RType p c tv r -> Doc+ppAllExpr bb p t+ = text "forall" <+> brackets (intersperse comma [ppr_dbind bb TopPrec x t | (x, t) <- zs]) <> dot <> ppr_rtype bb p t'+ where (zs, t') = split [] t+ split zs (RAllE x t t') = split ((x,t):zs) t'+ split zs t = (reverse zs, t)++ppReftPs _ _ rs+ | all isTauto rs = empty+ | not (ppPs ppEnv) = empty+ | otherwise = angleBrackets $ hsep $ punctuate comma $ ppr_ref <$> rs++-- ppr_dbind :: (RefTypable p c tv (), RefTypable p c tv r) => Bool -> Prec -> Symbol -> RType p c tv r -> Doc+ppr_dbind bb p x t+ | isNonSymbol x || (x == dummySymbol)+ = ppr_rtype bb p t+ | otherwise+ = pprint x <> colon <> ppr_rtype bb p t+++ppr_rty_fun bb prefix t+ = prefix <+> ppr_rty_fun' bb t++ppr_rty_fun' bb (RFun b t t' _)+ = ppr_dbind bb FunPrec b t <+> ppr_rty_fun bb arrow t'+ppr_rty_fun' bb t+ = ppr_rtype bb TopPrec t+++-- ppr_forall :: (RefTypable p c tv (), RefTypable p c tv r) => Bool -> Prec -> RType p c tv r -> Doc+ppr_forall :: (OkRT c tv r) => PPEnv -> Prec -> RType c tv r -> Doc+ppr_forall bb p t = maybeParen p FunPrec $ sep [+ ppr_foralls (ppPs bb) (ty_vars trep) (ty_preds trep) (ty_labels trep)+ , ppr_clss cls+ , ppr_rtype bb TopPrec t'+ ]+ where+ trep = toRTypeRep t+ (cls, t') = bkClass $ fromRTypeRep $ trep {ty_vars = [], ty_preds = [], ty_labels = []}++ ppr_foralls False _ _ _ = empty+ ppr_foralls _ [] [] [] = empty+ ppr_foralls True αs πs ss = text "forall" <+> dαs αs <+> dπs (ppPs bb) πs <+> ppr_symbols ss <> dot++ ppr_clss [] = empty+ ppr_clss cs = (parens $ hsep $ punctuate comma (uncurry (ppr_cls bb p) <$> cs)) <+> text "=>"++ dαs αs = sep $ pprint <$> αs++ -- dπs :: Bool -> [PVar a] -> Doc+ dπs _ [] = empty+ dπs False _ = empty+ dπs True πs = angleBrackets $ intersperse comma $ ppr_pvar_def bb p <$> πs++ppr_symbols :: [Symbol] -> Doc+ppr_symbols [] = empty+ppr_symbols ss = angleBrackets $ intersperse comma $ pprint <$> ss++ppr_cls bb p c ts+ = pp c <+> hsep (map (ppr_rtype bb p) ts)+ where+ pp | ppShort bb = text . symbolString . dropModuleNames . symbol . render . pprint+ | otherwise = pprint+++ppr_pvar_def :: (OkRT c tv ()) => PPEnv -> Prec -> PVar (RType c tv ()) -> Doc+ppr_pvar_def bb p (PV s t _ xts)+ = pprint s <+> dcolon <+> intersperse arrow dargs <+> ppr_pvar_kind bb p t+ where+ dargs = [ppr_pvar_sort bb p xt | (xt,_,_) <- xts]+++ppr_pvar_kind :: (OkRT c tv ()) => PPEnv -> Prec -> PVKind (RType c tv ()) -> Doc+ppr_pvar_kind bb p (PVProp t) = ppr_pvar_sort bb p t <+> arrow <+> ppr_name propConName+ppr_pvar_kind _ _ (PVHProp) = ppr_name hpropConName+ppr_name = text . symbolString++ppr_pvar_sort :: (OkRT c tv ()) => PPEnv -> Prec -> RType c tv () -> Doc+ppr_pvar_sort bb p t = ppr_rtype bb p t++ppr_ref :: (OkRT c tv r) => Ref (RType c tv ()) (RType c tv r) -> Doc+ppr_ref (RProp ss s) = ppRefArgs (fst <$> ss) <+> pprint s+-- ppr_ref (RProp ss s) = ppRefArgs (fst <$> ss) <+> pprint (fromMaybe mempty (stripRTypeBase s))++ppRefArgs :: [Symbol] -> Doc+ppRefArgs [] = empty+ppRefArgs ss = text "\\" <> hsep (ppRefSym <$> ss ++ [vv Nothing]) <+> text "->"++ppRefSym "" = text "_"+ppRefSym s = pprint s++dot = char '.'++instance (PPrint r, Reftable r) => PPrint (UReft r) where+ pprintTidy k (MkUReft r p _)+ --- | isTauto r = pprintTidy k p+ --- | isTauto p = pprintTidy k r+ | otherwise = pprintTidy k p <> text " & " <> pprintTidy k r++--------------------------------------------------------------------------------
+ src/Language/Haskell/Liquid/Types/RefType.hs view
@@ -0,0 +1,1145 @@+{-# LANGUAGE IncoherentInstances #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE NoMonomorphismRestriction #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE TypeSynonymInstances #-}+{-# LANGUAGE TupleSections #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE PatternGuards #-}++-- | Refinement Types. Mostly mirroring the GHC Type definition, but with+-- room for refinements of various sorts.++-- TODO: Desperately needs re-organization.+module Language.Haskell.Liquid.Types.RefType (++ -- * Functions for lifting Reft-values to Spec-values+ uTop, uReft, uRType, uRType', uRTypeGen, uPVar++ -- * Applying a solution to a SpecType+ , applySolution++ -- * Functions for decreasing arguments+ , isDecreasing, makeDecrType, makeNumEnv+ , makeLexRefa++ -- * Functions for manipulating `Predicate`s+ , pdVar+ , findPVar+ , freeTyVars, tyClasses, tyConName++ -- TODO: categorize these!+ , ofType, toType+ , rTyVar, rVar, rApp, rEx+ , symbolRTyVar+ , addTyConInfo+ , appRTyCon+ , typeSort, typeUniqueSymbol+ , strengthen+ , generalize, normalizePds+ , subts, subvPredicate, subvUReft+ , subsTyVar_meet, subsTyVar_meet', subsTyVar_nomeet+ , subsTyVars_nomeet, subsTyVars_meet+ , dataConMsReft, dataConReft+ , classBinds++ , isSizeable++ -- * Manipulating Refinements in RTypes+ , rTypeSortedReft+ , rTypeSort+ , shiftVV++ , mkDataConIdsTy+ , mkTyConInfo++ , meetable+ , strengthenRefTypeGen+ , strengthenDataConType++ , isBaseTy++ ) where++import Prelude hiding (error)+import WwLib+import FamInstEnv (emptyFamInstEnv)+import Var+import Kind+import GHC hiding (Located)+import DataCon+import qualified TyCon as TC+import TypeRep hiding (maybeParen, pprArrowChain)+import Type (splitFunTys, expandTypeSynonyms, substTyWith, isClassPred)+import TysWiredIn (listTyCon, intDataCon, trueDataCon, falseDataCon,+ intTyCon, charTyCon)++-- import Data.Monoid hiding ((<>))+import Data.Maybe (fromMaybe, isJust, fromJust)+import Data.Hashable+import qualified Data.HashMap.Strict as M+import qualified Data.HashSet as S+import qualified Data.List as L++import Control.Monad (void)+import Text.Printf+import Text.PrettyPrint.HughesPJ++import Language.Haskell.Liquid.Types.Errors+import Language.Haskell.Liquid.Types.PrettyPrint+import qualified Language.Fixpoint.Types as F+import Language.Fixpoint.Types hiding (shiftVV, Predicate)+import Language.Fixpoint.Types.Visitor (mapKVars)+import Language.Haskell.Liquid.Types hiding (R, DataConP (..), sort)++import Language.Haskell.Liquid.Types.Variance++import Language.Haskell.Liquid.Misc+import Language.Haskell.Liquid.Types.Names+import Language.Fixpoint.Misc+import Language.Haskell.Liquid.GHC.Misc (typeUniqueString, tvId, showPpr, stringTyVar, tyConTyVarsDef)++import Data.List (sort, foldl')+++strengthenDataConType (x, t) = (x, fromRTypeRep trep{ty_res = tres})+ where+ trep = toRTypeRep t+ tres = ty_res trep `strengthen` MkUReft (exprReft expr) mempty mempty+ xs = ty_binds trep+ as = ty_vars trep+ x' = symbol x+ expr | null xs && null as = EVar x'+ | null xs = mkEApp (dummyLoc x') []+ | otherwise = mkEApp (dummyLoc x') (EVar <$> xs)++pdVar v = Pr [uPVar v]++findPVar :: [PVar (RType c tv ())] -> UsedPVar -> PVar (RType c tv ())+findPVar ps p+ = PV name ty v (zipWith (\(_, _, e) (t, s, _) -> (t, s, e)) (pargs p) args)+ where PV name ty v args = fromMaybe (msg p) $ L.find ((== pname p) . pname) ps+ msg p = panic Nothing $ "RefType.findPVar" ++ showpp p ++ "not found"++-- | Various functions for converting vanilla `Reft` to `Spec`++uRType :: RType c tv a -> RType c tv (UReft a)+uRType = fmap uTop++uRType' :: RType c tv (UReft a) -> RType c tv a+uRType' = fmap ur_reft++uRTypeGen :: Reftable b => RType c tv a -> RType c tv b+uRTypeGen = fmap $ const mempty++uPVar :: PVar t -> UsedPVar+uPVar = void++uReft :: (Symbol, Expr) -> UReft Reft+uReft = uTop . Reft++uTop :: r -> UReft r+uTop r = MkUReft r mempty mempty++--------------------------------------------------------------------+-------------- (Class) Predicates for Valid Refinement Types -------+--------------------------------------------------------------------+++-- Monoid Instances ---------------------------------------------------------++instance ( SubsTy tv (RType c tv ()) (RType c tv ())+ , SubsTy tv (RType c tv ()) c+ , RefTypable c tv ()+ , RefTypable c tv r+ , OkRT c tv r+ , FreeVar c tv+ )+ => Monoid (RType c tv r) where+ mempty = panic Nothing "mempty: RType"+ mappend = strengthenRefType+++-- MOVE TO TYPES+instance ( SubsTy tv (RType c tv ()) c+ , OkRT c tv r+ , RefTypable c tv r+ , RefTypable c tv ()+ , FreeVar c tv+ , SubsTy tv (RType c tv ()) (RType c tv ()))+ => Monoid (RTProp c tv r) where+ mempty = panic Nothing "mempty: RTProp"++ mappend (RProp s1 (RHole r1)) (RProp s2 (RHole r2))+ | isTauto r1 = RProp s2 (RHole r2)+ | isTauto r2 = RProp s1 (RHole r1)+ | otherwise = RProp s1 $ RHole $ r1 `meet`+ (subst (mkSubst $ zip (fst <$> s2) (EVar . fst <$> s1)) r2)++ mappend (RProp s1 t1) (RProp s2 t2)+ | isTrivial t1 = RProp s2 t2+ | isTrivial t2 = RProp s1 t1+ | otherwise = RProp s1 $ t1 `strengthenRefType`+ (subst (mkSubst $ zip (fst <$> s2) (EVar . fst <$> s1)) t2)++instance ( OkRT c tv r+ , RefTypable c tv r+ , RefTypable c tv ()+ , FreeVar c tv+ , SubsTy tv (RType c tv ()) (RType c tv ())+ , SubsTy tv (RType c tv ()) c) => Reftable (RTProp c tv r) where+ isTauto (RProp _ (RHole r)) = isTauto r+ isTauto (RProp _ t) = isTrivial t+ top (RProp _ (RHole _)) = panic Nothing "RefType: Reftable top called on (RProp _ (RHole _))"+ top (RProp xs t) = RProp xs $ mapReft top t+ ppTy (RProp _ (RHole r)) d = ppTy r d+ ppTy (RProp _ _) _ = panic Nothing "RefType: Reftable ppTy in RProp"+ toReft = panic Nothing "RefType: Reftable toReft"+ params = panic Nothing "RefType: Reftable params for Ref"+ bot = panic Nothing "RefType: Reftable bot for Ref"+ ofReft = panic Nothing "RefType: Reftable ofReft for Ref"+++----------------------------------------------------------------------------+-- | Subable Instances -----------------------------------------------------+----------------------------------------------------------------------------++instance Subable (RRProp Reft) where+ syms (RProp ss (RHole r)) = (fst <$> ss) ++ syms r+ syms (RProp ss t) = (fst <$> ss) ++ syms t+++ subst su (RProp ss (RHole r)) = RProp (mapSnd (subst su) <$> ss) $ RHole $ subst su r+ subst su (RProp ss r) = RProp (mapSnd (subst su) <$> ss) $ subst su r+++ substf f (RProp ss (RHole r)) = RProp (mapSnd (substf f) <$> ss) $ RHole $ substf f r+ substf f (RProp ss r) = RProp (mapSnd (substf f) <$> ss) $ substf f r++ substa f (RProp ss (RHole r)) = RProp (mapSnd (substa f) <$> ss) $ RHole $ substa f r+ substa f (RProp ss r) = RProp (mapSnd (substa f) <$> ss) $ substa f r+++-------------------------------------------------------------------------------+-- | Reftable Instances -------------------------------------------------------+-------------------------------------------------------------------------------++instance (PPrint r, Reftable r) => Reftable (RType RTyCon RTyVar r) where+ isTauto = isTrivial+ ppTy = panic Nothing "ppTy RProp Reftable"+ toReft = panic Nothing "toReft on RType"+ params = panic Nothing "params on RType"+ bot = panic Nothing "bot on RType"+ ofReft = panic Nothing "ofReft on RType"++++-------------------------------------------------------------------------------+-- | RefTypable Instances -----------------------------------------------------+-------------------------------------------------------------------------------++-- MOVE TO TYPES+instance Fixpoint String where+ toFix = text++-- MOVE TO TYPES+instance Fixpoint Class where+ toFix = text . showPpr++-- MOVE TO TYPES+class FreeVar a v where+ freeVars :: a -> [v]++-- MOVE TO TYPES+instance FreeVar RTyCon RTyVar where+ freeVars = (RTV <$>) . tyConTyVarsDef . rtc_tc++-- MOVE TO TYPES+instance FreeVar LocSymbol Symbol where+ freeVars _ = []++-- Eq Instances ------------------------------------------------------++-- MOVE TO TYPES+instance (RefTypable c tv ()) => Eq (RType c tv ()) where+ (==) = eqRSort M.empty++eqRSort m (RAllP _ t) (RAllP _ t')+ = eqRSort m t t'+eqRSort m (RAllS _ t) (RAllS _ t')+ = eqRSort m t t'+eqRSort m (RAllP _ t) t'+ = eqRSort m t t'+eqRSort m (RAllT a t) (RAllT a' t')+ | a == a'+ = eqRSort m t t'+ | otherwise+ = eqRSort (M.insert a' a m) t t'+eqRSort m (RAllT _ t) t'+ = eqRSort m t t'+eqRSort m t (RAllT _ t')+ = eqRSort m t t'+eqRSort m (RFun _ t1 t2 _) (RFun _ t1' t2' _)+ = eqRSort m t1 t1' && eqRSort m t2 t2'+eqRSort m (RAppTy t1 t2 _) (RAppTy t1' t2' _)+ = eqRSort m t1 t1' && eqRSort m t2 t2'+eqRSort m (RApp c ts _ _) (RApp c' ts' _ _)+ = c == c' && length ts == length ts' && and (zipWith (eqRSort m) ts ts')+eqRSort m (RVar a _) (RVar a' _)+ = a == M.lookupDefault a' a' m+eqRSort _ (RHole _) _+ = True+eqRSort _ _ (RHole _)+ = True+eqRSort _ _ _+ = False++--------------------------------------------------------------------+-- | Wrappers for GHC Type Elements --------------------------------+--------------------------------------------------------------------++instance Eq Predicate where+ (==) = eqpd++eqpd (Pr vs) (Pr ws)+ = and $ (length vs' == length ws') : [v == w | (v, w) <- zip vs' ws']+ where vs' = sort vs+ ws' = sort ws+++instance Eq RTyVar where+ RTV α == RTV α' = tvId α == tvId α'++instance Ord RTyVar where+ compare (RTV α) (RTV α') = compare (tvId α) (tvId α')++instance Hashable RTyVar where+ hashWithSalt i (RTV α) = hashWithSalt i α++instance Ord RTyCon where+ compare x y = compare (rtc_tc x) (rtc_tc y)++instance Hashable RTyCon where+ hashWithSalt i = hashWithSalt i . rtc_tc++--------------------------------------------------------------------+---------------------- Helper Functions ----------------------------+--------------------------------------------------------------------++rVar = (`RVar` mempty) . RTV+rTyVar = RTV++symbolRTyVar = rTyVar . stringTyVar . symbolString++normalizePds t = addPds ps t'+ where (t', ps) = nlzP [] t++rPred = RAllP+rEx xts t = foldr (\(x, tx) t -> REx x tx t) t xts+rApp c = RApp (RTyCon c [] (mkTyConInfo c [] [] Nothing))++--- NV TODO : remove this code!!!++addPds ps (RAllT v t) = RAllT v $ addPds ps t+addPds ps t = foldl' (flip rPred) t ps++nlzP ps t@(RVar _ _ )+ = (t, ps)+nlzP ps (RFun b t1 t2 r)+ = (RFun b t1' t2' r, ps ++ ps1 ++ ps2)+ where (t1', ps1) = nlzP [] t1+ (t2', ps2) = nlzP [] t2+nlzP ps (RAppTy t1 t2 r)+ = (RAppTy t1' t2' r, ps ++ ps1 ++ ps2)+ where (t1', ps1) = nlzP [] t1+ (t2', ps2) = nlzP [] t2+nlzP ps (RAllT v t )+ = (RAllT v t', ps ++ ps')+ where (t', ps') = nlzP [] t+nlzP ps t@(RApp _ _ _ _)+ = (t, ps)+nlzP ps (RAllS _ t)+ = (t, ps)+nlzP ps (RAllP p t)+ = (t', [p] ++ ps ++ ps')+ where (t', ps') = nlzP [] t+nlzP ps t@(REx _ _ _)+ = (t, ps)+nlzP ps t@(RRTy _ _ _ t')+ = (t, ps ++ ps')+ where ps' = snd $ nlzP [] t'+nlzP ps t@(RAllE _ _ _)+ = (t, ps)+nlzP _ t+ = panic Nothing $ "RefType.nlzP: cannot handle " ++ show t++strengthenRefTypeGen, strengthenRefType ::+ ( RefTypable c tv ()+ , RefTypable c tv r+ , OkRT c tv r+ , FreeVar c tv+ , SubsTy tv (RType c tv ()) (RType c tv ())+ , SubsTy tv (RType c tv ()) c+ ) => RType c tv r -> RType c tv r -> RType c tv r++strengthenRefType_ ::+ ( RefTypable c tv ()+ , RefTypable c tv r+ -- , PPrint (RType c tv r)+ , OkRT c tv r+ , FreeVar c tv+ , SubsTy tv (RType c tv ()) (RType c tv ())+ , SubsTy tv (RType c tv ()) c+ ) => (RType c tv r -> RType c tv r -> RType c tv r)+ -> RType c tv r -> RType c tv r -> RType c tv r++strengthenRefTypeGen t1 t2 = strengthenRefType_ f t1 t2+ where+ f (RVar v1 r1) t = RVar v1 (r1 `meet` fromMaybe mempty (stripRTypeBase t))+ f t (RVar v1 r1) = RVar v1 (r1 `meet` fromMaybe mempty (stripRTypeBase t))+ f t1 t2 = panic Nothing $ printf "strengthenRefTypeGen on differently shaped types \nt1 = %s [shape = %s]\nt2 = %s [shape = %s]"+ (pprt_raw t1) (showpp (toRSort t1)) (pprt_raw t2) (showpp (toRSort t2))++pprt_raw :: (OkRT c tv r) => RType c tv r -> String+pprt_raw = render . rtypeDoc Full++-- NEWISH: with unifying type variables: causes big problems with TUPLES?+--strengthenRefType t1 t2 = maybe (errorstar msg) (strengthenRefType_ t1) (unifyShape t1 t2)+-- where msg = printf "strengthen on differently shaped reftypes \nt1 = %s [shape = %s]\nt2 = %s [shape = %s]"+-- (render t1) (render (toRSort t1)) (render t2) (render (toRSort t2))++-- OLD: without unifying type variables, but checking α-equivalence+strengthenRefType t1 t2+ | meetable t1 t2+ = strengthenRefType_ (\x _ -> x) t1 t2+ | otherwise+ = panic Nothing msg+ where+ msg = printf "strengthen on differently shaped reftypes \nt1 = %s [shape = %s]\nt2 = %s [shape = %s]"+ (showpp t1) (showpp (toRSort t1)) (showpp t2) (showpp (toRSort t2))++meetable :: (OkRT c tv r) => RType c tv r -> RType c tv r -> Bool+meetable t1 t2 = toRSort t1 == toRSort t2++strengthenRefType_ f (RAllT a1 t1) (RAllT a2 t2)+ = RAllT a1 $ strengthenRefType_ f t1 (subsTyVar_meet (a2, toRSort t, t) t2)+ where t = RVar a1 mempty++strengthenRefType_ f (RAllT a t1) t2+ = RAllT a $ strengthenRefType_ f t1 t2++strengthenRefType_ f t1 (RAllT a t2)+ = RAllT a $ strengthenRefType_ f t1 t2++strengthenRefType_ f (RAllP p1 t1) (RAllP _ t2)+ = RAllP p1 $ strengthenRefType_ f t1 t2++strengthenRefType_ f (RAllP p t1) t2+ = RAllP p $ strengthenRefType_ f t1 t2++strengthenRefType_ f t1 (RAllP p t2)+ = RAllP p $ strengthenRefType_ f t1 t2++strengthenRefType_ f (RAllS s t1) t2+ = RAllS s $ strengthenRefType_ f t1 t2++strengthenRefType_ f t1 (RAllS s t2)+ = RAllS s $ strengthenRefType_ f t1 t2++strengthenRefType_ f (RAllE x tx t1) (RAllE y ty t2) | x == y+ = RAllE x (strengthenRefType_ f tx ty) $ strengthenRefType_ f t1 t2++strengthenRefType_ f (RAllE x tx t1) t2+ = RAllE x tx $ strengthenRefType_ f t1 t2++strengthenRefType_ f t1 (RAllE x tx t2)+ = RAllE x tx $ strengthenRefType_ f t1 t2++strengthenRefType_ f (RAppTy t1 t1' r1) (RAppTy t2 t2' r2)+ = RAppTy t t' (r1 `meet` r2)+ where t = strengthenRefType_ f t1 t2+ t' = strengthenRefType_ f t1' t2'++strengthenRefType_ f (RFun x1 t1 t1' r1) (RFun x2 t2 t2' r2)+ = RFun x2 t t' (r1 `meet` r2)+ where t = strengthenRefType_ f t1 t2+ t' = strengthenRefType_ f (subst1 t1' (x1, EVar x2)) t2'++strengthenRefType_ f (RApp tid t1s rs1 r1) (RApp _ t2s rs2 r2)+ = RApp tid ts rs (r1 `meet` r2)+ where ts = zipWith (strengthenRefType_ f) t1s t2s+ rs = meets rs1 rs2+++strengthenRefType_ _ (RVar v1 r1) (RVar v2 r2) | v1 == v2+ = RVar v1 (r1 `meet` r2)+strengthenRefType_ f t1 t2+ = f t1 t2++meets :: (F.Reftable r) => [r] -> [r] -> [r]+meets [] rs = rs+meets rs [] = rs+meets rs rs'+ | length rs == length rs' = zipWith meet rs rs'+ | otherwise = panic Nothing "meets: unbalanced rs"+++strengthen :: Reftable r => RType c tv r -> r -> RType c tv r+strengthen (RApp c ts rs r) r' = RApp c ts rs (r `meet` r')+strengthen (RVar a r) r' = RVar a (r `meet` r')+strengthen (RFun b t1 t2 r) r' = RFun b t1 t2 (r `meet` r')+strengthen (RAppTy t1 t2 r) r' = RAppTy t1 t2 (r `meet` r')+strengthen t _ = t++++-------------------------------------------------------------------------+addTyConInfo :: (PPrint r, Reftable r)+ => (M.HashMap TyCon FTycon)+ -> (M.HashMap TyCon RTyCon)+ -> RRType r+ -> RRType r+-------------------------------------------------------------------------+addTyConInfo tce tyi = mapBot (expandRApp tce tyi)++-------------------------------------------------------------------------+expandRApp :: (PPrint r, Reftable r)+ => (M.HashMap TyCon FTycon)+ -> (M.HashMap TyCon RTyCon)+ -> RRType r+ -> RRType r+-------------------------------------------------------------------------+expandRApp tce tyi t@(RApp {}) = RApp rc' ts rs' r+ where+ RApp rc ts rs r = t+ rc' = appRTyCon tce tyi rc as+ pvs = rTyConPVs rc'+ rs' = applyNonNull rs0 (rtPropPV rc pvs) rs+ rs0 = rtPropTop <$> pvs+ n = length fVs+ fVs = tyConTyVarsDef $ rtc_tc rc+ as = choosen n ts (rVar <$> fVs)++ choosen 0 _ _ = []+ choosen i (x:xs) (_:ys) = x:choosen (i-1) xs ys+ choosen i [] (y:ys) = y:choosen (i-1) [] ys+ choosen _ _ _ = impossible Nothing "choosen: this cannot happen"++expandRApp _ _ t = t++rtPropTop pv = case ptype pv of+ PVProp t -> RProp xts $ ofRSort t+ PVHProp -> RProp xts $ mempty+ where+ xts = pvArgs pv++rtPropPV rc = safeZipWith msg mkRTProp+ where+ msg = "appRefts: " ++ showFix rc++mkRTProp pv (RProp ss (RHole r))+ = RProp ss $ (ofRSort $ pvType pv) `strengthen` r++mkRTProp pv (RProp ss t)+ | length (pargs pv) == length ss+ = RProp ss t+ | otherwise+ = RProp (pvArgs pv) t++pvArgs pv = [(s, t) | (t, s, _) <- pargs pv]+++appRTyCon tce tyi rc ts = RTyCon c ps' (rtc_info rc'')+ where+ c = rtc_tc rc+ ps' = subts (zip (RTV <$> αs) ts') <$> rTyConPVs rc'+ ts' = if null ts then rVar <$> βs else toRSort <$> ts+ rc' = M.lookupDefault rc c tyi+ αs = tyConTyVarsDef $ rtc_tc rc'+ βs = tyConTyVarsDef c+ rc'' = if isNumeric tce rc' then addNumSizeFun rc' else rc'+++-- RJ: The code of `isNumeric` is incomprehensible.+-- Please fix it to use intSort instead of intFTyCon+isNumeric tce c+ = fromMaybe+ (symbolFTycon . dummyLoc $ tyConName (rtc_tc c))+ (M.lookup (rtc_tc c) tce) == F.intFTyCon++addNumSizeFun c+ = c {rtc_info = (rtc_info c) {sizeFunction = Just EVar} }+++generalize :: (RefTypable c tv r) => RType c tv r -> RType c tv r+generalize t = mkUnivs (freeTyVars t) [] [] t++freeTyVars (RAllP _ t) = freeTyVars t+freeTyVars (RAllS _ t) = freeTyVars t+freeTyVars (RAllT α t) = freeTyVars t L.\\ [α]+freeTyVars (RFun _ t t' _) = freeTyVars t `L.union` freeTyVars t'+freeTyVars (RApp _ ts _ _) = L.nub $ concatMap freeTyVars ts+freeTyVars (RVar α _) = [α]+freeTyVars (RAllE _ tx t) = freeTyVars tx `L.union` freeTyVars t+freeTyVars (REx _ tx t) = freeTyVars tx `L.union` freeTyVars t+freeTyVars (RExprArg _) = []+freeTyVars (RAppTy t t' _) = freeTyVars t `L.union` freeTyVars t'+freeTyVars (RHole _) = []+freeTyVars (RRTy e _ _ t) = L.nub $ concatMap freeTyVars (t:(snd <$> e))+++tyClasses (RAllP _ t) = tyClasses t+tyClasses (RAllS _ t) = tyClasses t+tyClasses (RAllT _ t) = tyClasses t+tyClasses (RAllE _ _ t) = tyClasses t+tyClasses (REx _ _ t) = tyClasses t+tyClasses (RFun _ t t' _) = tyClasses t ++ tyClasses t'+tyClasses (RAppTy t t' _) = tyClasses t ++ tyClasses t'+tyClasses (RApp c ts _ _)+ | Just cl <- tyConClass_maybe $ rtc_tc c+ = [(cl, ts)]+ | otherwise+ = []+tyClasses (RVar _ _) = []+tyClasses (RRTy _ _ _ t) = tyClasses t+tyClasses (RHole _) = []+tyClasses t = panic Nothing ("RefType.tyClasses cannot handle" ++ show t)+++--------------------------------------------------------------------------------+-- TODO: Rewrite subsTyvars with Traversable+--------------------------------------------------------------------------------++subsTyVars_meet = subsTyVars True+subsTyVars_nomeet = subsTyVars False+subsTyVar_nomeet = subsTyVar False+subsTyVar_meet = subsTyVar True+subsTyVar_meet' (α, t) = subsTyVar_meet (α, toRSort t, t)++subsTyVars meet ats t = foldl' (flip (subsTyVar meet)) t ats+subsTyVar meet = subsFree meet S.empty++subsFree m s z (RAllS l t)+ = RAllS l (subsFree m s z t)+subsFree m s z@(α, τ,_) (RAllP π t)+ = RAllP (subt (α, τ) π) (subsFree m s z t)+subsFree m s z (RAllT α t)+ = RAllT α $ subsFree m (α `S.insert` s) z t+subsFree m s z@(_, _, _) (RFun x t t' r)+ = RFun x (subsFree m s z t) (subsFree m s z t') r+subsFree m s z@(α, τ, _) (RApp c ts rs r)+ = RApp (subt z' c) (subsFree m s z <$> ts) (subsFreeRef m s z <$> rs) r+ where z' = (α, τ) -- UNIFY: why instantiating INSIDE parameters?+subsFree meet s (α', _, t') t@(RVar α r)+ | α == α' && not (α `S.member` s)+ = if meet then t' `strengthen` r else t'+ | otherwise+ = t+subsFree m s z (RAllE x t t')+ = RAllE x (subsFree m s z t) (subsFree m s z t')+subsFree m s z (REx x t t')+ = REx x (subsFree m s z t) (subsFree m s z t')+subsFree m s z@(_, _, _) (RAppTy t t' r)+ = subsFreeRAppTy m s (subsFree m s z t) (subsFree m s z t') r+subsFree _ _ _ t@(RExprArg _)+ = t+subsFree m s z (RRTy e r o t)+ = RRTy (mapSnd (subsFree m s z) <$> e) r o (subsFree m s z t)+subsFree _ _ _ t@(RHole _)+ = t++subsFrees m s zs t = foldl' (flip(subsFree m s)) t zs++-- GHC INVARIANT: RApp is Type Application to something other than TYCon+subsFreeRAppTy m s (RApp c ts rs r) t' r'+ = mkRApp m s c (ts ++ [t']) rs r r'+subsFreeRAppTy _ _ t t' r'+ = RAppTy t t' r'++mkRApp m s c ts rs r r'+ | isFun c, [t1, t2] <- ts+ = RFun dummySymbol t1 t2 $ refAppTyToFun r'+ | otherwise+ = subsFrees m s zs $ RApp c ts rs $ r `meet` r' -- (refAppTyToApp r')+ where+ zs = [(tv, toRSort t, t) | (tv, t) <- zip (freeVars c) ts]++refAppTyToFun r+ | isTauto r = r+ | otherwise = panic Nothing "RefType.refAppTyToFun"++subsFreeRef _ _ (α', τ', _) (RProp ss (RHole r))+ = RProp (mapSnd (subt (α', τ')) <$> ss) (RHole r)+subsFreeRef m s (α', τ', t') (RProp ss t)+ = RProp (mapSnd (subt (α', τ')) <$> ss) $ subsFree m s (α', τ', fmap top t') t+++-------------------------------------------------------------------+------------------- Type Substitutions ----------------------------+-------------------------------------------------------------------++subts = flip (foldr subt)++instance SubsTy tv ty () where+ subt _ = id++instance SubsTy tv ty Reft where+ subt _ = id++instance (SubsTy tv ty ty) => SubsTy tv ty (PVKind ty) where+ subt su (PVProp t) = PVProp (subt su t)+ subt _ PVHProp = PVHProp++instance (SubsTy tv ty ty) => SubsTy tv ty (PVar ty) where+ subt su (PV n t v xts) = PV n (subt su t) v [(subt su t, x, y) | (t,x,y) <- xts]++instance SubsTy RTyVar RSort RTyCon where+ subt z c = RTyCon tc ps' i+ where+ tc = rtc_tc c+ ps' = subt z <$> rTyConPVs c+ i = rtc_info c++-- NOTE: This DOES NOT substitute at the binders+instance SubsTy RTyVar RSort PrType where+ subt (α, τ) = subsTyVar_meet (α, τ, ofRSort τ)++instance SubsTy RTyVar RSort SpecType where+ subt (α, τ) = subsTyVar_meet (α, τ, ofRSort τ)++instance SubsTy RTyVar RTyVar SpecType where+ subt (α, a) = subt (α, RVar a () :: RSort)+++instance SubsTy RTyVar RSort RSort where+ subt (α, τ) = subsTyVar_meet (α, τ, ofRSort τ)++-- Here the "String" is a Bare-TyCon. TODO: wrap in newtype+instance SubsTy Symbol BSort LocSymbol where+ subt _ t = t++instance SubsTy Symbol BSort BSort where+ subt (α, τ) = subsTyVar_meet (α, τ, ofRSort τ)++instance (SubsTy tv ty (UReft r), SubsTy tv ty (RType c tv ())) => SubsTy tv ty (RTProp c tv (UReft r)) where+ subt m (RProp ss (RHole p)) = RProp ((mapSnd (subt m)) <$> ss) $ RHole $ subt m p+ subt m (RProp ss t) = RProp ((mapSnd (subt m)) <$> ss) $ fmap (subt m) t++subvUReft :: (UsedPVar -> UsedPVar) -> UReft Reft -> UReft Reft+subvUReft f (MkUReft r p s) = MkUReft r (subvPredicate f p) s++subvPredicate :: (UsedPVar -> UsedPVar) -> Predicate -> Predicate+subvPredicate f (Pr pvs) = Pr (f <$> pvs)++---------------------------------------------------------------++ofType = ofType_ . expandTypeSynonyms++ofType_ (TyVarTy α)+ = rVar α+ofType_ (FunTy τ τ')+ = rFun dummySymbol (ofType_ τ) (ofType_ τ')+ofType_ (ForAllTy α τ)+ | isKindVar α+ = ofType_ τ+ | otherwise+ = RAllT (rTyVar α) $ ofType_ τ+ofType_ (TyConApp c τs)+ | Just (αs, τ) <- TC.synTyConDefn_maybe c+ = ofType_ $ substTyWith αs τs τ+ | otherwise+ = rApp c (ofType_ <$> filter (not . isKind) τs) [] mempty+ofType_ (AppTy t1 t2)+ = RAppTy (ofType_ t1) (ofType t2) mempty+ofType_ (LitTy x)+ = fromTyLit x+ where+ fromTyLit (NumTyLit _) = rApp intTyCon [] [] mempty+ fromTyLit (StrTyLit _) = rApp listTyCon [rApp charTyCon [] [] mempty] [] mempty++--------------------------------------------------------------------------------+-- | Converting to Fixpoint ----------------------------------------------------+--------------------------------------------------------------------------------+++instance Expression Var where+ expr = eVar++-- TODO: turn this into a map lookup?+dataConReft :: DataCon -> [Symbol] -> Reft+dataConReft c []+ | c == trueDataCon+ = predReft $ eProp vv_+ | c == falseDataCon+ = predReft $ PNot $ eProp vv_++dataConReft c [x]+ | c == intDataCon+ = symbolReft x -- OLD (vv_, [RConc (PAtom Eq (EVar vv_) (EVar x))])+dataConReft c _+ | not $ isBaseDataCon c+ = mempty+dataConReft c xs+ = exprReft dcValue -- OLD Reft (vv_, [RConc (PAtom Eq (EVar vv_) dcValue)])+ where+ dcValue+ | null xs && null (dataConUnivTyVars c)+ = EVar $ symbol c+ | otherwise+ = mkEApp (dummyLoc $ symbol c) (eVar <$> xs)++isBaseDataCon c = and $ isBaseTy <$> dataConOrigArgTys c ++ dataConRepArgTys c++isBaseTy (TyVarTy _) = True+isBaseTy (AppTy _ _) = False+isBaseTy (TyConApp _ ts) = and $ isBaseTy <$> ts+isBaseTy (FunTy _ _) = False+isBaseTy (ForAllTy _ _) = False+isBaseTy (LitTy _) = True+++dataConMsReft ty ys = subst su (rTypeReft (ignoreOblig $ ty_res trep))+ where+ trep = toRTypeRep ty+ xs = ty_binds trep+ ts = ty_args trep+ su = mkSubst $ [(x, EVar y) | ((x, _), y) <- zip (zip xs ts) ys]++---------------------------------------------------------------+---------------------- Embedding RefTypes ---------------------+---------------------------------------------------------------+-- TODO: remove toType, generalize typeSort+toType :: (Reftable r, PPrint r) => RRType r -> Type+toType (RFun _ t t' _)+ = FunTy (toType t) (toType t')+toType (RAllT (RTV α) t)+ = ForAllTy α (toType t)+toType (RAllP _ t)+ = toType t+toType (RAllS _ t)+ = toType t+toType (RVar (RTV α) _)+ = TyVarTy α+toType (RApp (RTyCon {rtc_tc = c}) ts _ _)+ = TyConApp c (toType <$> filter notExprArg ts)+ where+ notExprArg (RExprArg _) = False+ notExprArg _ = True+toType (RAllE _ _ t)+ = toType t+toType (REx _ _ t)+ = toType t+toType (RAppTy t (RExprArg _) _)+ = toType t+toType (RAppTy t t' _)+ = AppTy (toType t) (toType t')+toType t@(RExprArg _)+ = impossible Nothing $ "CANNOT HAPPEN: RefType.toType called with: " ++ show t+toType (RRTy _ _ _ t)+ = toType t+toType t+ = impossible Nothing $ "RefType.toType cannot handle: " ++ show t+++--------------------------------------------------------------------------------+-- | Annotations and Solutions -------------------------------------------------+--------------------------------------------------------------------------------++rTypeSortedReft :: (PPrint r, Reftable r) => TCEmb TyCon -> RRType r -> SortedReft+rTypeSortedReft emb t = RR (rTypeSort emb t) (rTypeReft t)++rTypeSort :: (PPrint r, Reftable r) => TCEmb TyCon -> RRType r -> Sort+rTypeSort tce = typeSort tce . toType++-------------------------------------------------------------------------------+applySolution :: (Functor f) => FixSolution -> f SpecType -> f SpecType+-------------------------------------------------------------------------------+applySolution = fmap . fmap . mapReft . appSolRefa+ where+ mapReft f (MkUReft (Reft (x, z)) p s) = MkUReft (Reft (x, f z)) p s+-- OLD appSolRefa _ ra@(RConc _) = ra+-- OLD appSolRefa s (RKvar k su) = RConc $ subst su $ M.lookupDefault PTop k s++appSolRefa s p = mapKVars f p+ where+ f k = Just $ M.lookupDefault PTop k s++-------------------------------------------------------------------------------+shiftVV :: SpecType -> Symbol -> SpecType+-------------------------------------------------------------------------------+shiftVV t@(RApp _ ts rs r) vv'+ = t { rt_args = subst1 ts (rTypeValueVar t, EVar vv') }+ { rt_pargs = subst1 rs (rTypeValueVar t, EVar vv') }+ { rt_reft = (`F.shiftVV` vv') <$> r }++shiftVV t@(RFun _ _ _ r) vv'+ = t { rt_reft = (`F.shiftVV` vv') <$> r }++shiftVV t@(RAppTy _ _ r) vv'+ = t { rt_reft = (`F.shiftVV` vv') <$> r }++shiftVV t@(RVar _ r) vv'+ = t { rt_reft = (`F.shiftVV` vv') <$> r }++shiftVV t _+ = t -- errorstar $ "shiftVV: cannot handle " ++ showpp t+++------------------------------------------------------------------------+---------------- Auxiliary Stuff Used Elsewhere ------------------------+------------------------------------------------------------------------++-- MOVE TO TYPES+instance (Show tv, Show ty) => Show (RTAlias tv ty) where+ show (RTA n as xs t p _) =+ printf "type %s %s %s = %s -- defined at %s" (symbolString n)+ (unwords (show <$> as))+ (unwords (show <$> xs))+ (show t) (show p)++----------------------------------------------------------------+------------ From Old Fixpoint ---------------------------------+----------------------------------------------------------------++typeUniqueSymbol :: Type -> Symbol+typeUniqueSymbol = symbol . typeUniqueString++typeSort :: TCEmb TyCon -> Type -> Sort+typeSort tce τ@(ForAllTy _ _)+ = typeSortForAll tce τ+typeSort tce t@(FunTy _ _)+ = typeSortFun tce t+typeSort tce (TyConApp c τs)+ = fAppTC (tyConFTyCon tce c) (typeSort tce <$> τs)+typeSort tce (AppTy t1 t2)+ = fApp (typeSort tce t1) [typeSort tce t2]+typeSort _ τ+ = FObj $ typeUniqueSymbol τ++tyConFTyCon tce c = fromMaybe (symbolFTycon $ dummyLoc $ tyConName c) (M.lookup c tce)++typeSortForAll tce τ+ = genSort $ typeSort tce tbody+ where genSort t = foldl (flip FAbs) (sortSubst su t) [0..n-1]+ (as, tbody) = splitForAllTys τ+ su = M.fromList $ zip sas (FVar <$> [0..])+ sas = (typeUniqueSymbol . TyVarTy) <$> as+ n = length as++tyConName c+ | listTyCon == c = listConName+ | TC.isTupleTyCon c = tupConName+ | otherwise = symbol c++typeSortFun tce t -- τ1 τ2+ = mkFFunc 0 sos+ where sos = typeSort tce <$> τs+ τs = grabArgs [] t++grabArgs τs (FunTy τ1 τ2)+ | not $ isClassPred τ1 = grabArgs (τ1:τs) τ2+ | otherwise = grabArgs τs τ2+grabArgs τs τ = reverse (τ:τs)+++mkDataConIdsTy (dc, t) = [ expandProductType x t | x <- dataConImplicitIds dc]++expandProductType x t+ | ofType (varType x) == toRSort t = (x, t)+ | otherwise = (x, t')+ where t' = fromRTypeRep $ trep {ty_binds = xs', ty_args = ts', ty_refts = rs'}+ τs = fst $ splitFunTys $ toType t+ trep = toRTypeRep t+ (xs', ts', rs') = unzip3 $ concatMap mkProductTy $ zip4 τs (ty_binds trep) (ty_args trep) (ty_refts trep)++mkProductTy (τ, x, t, r) = maybe [(x, t, r)] f $ deepSplitProductType_maybe menv τ+ where f = ((<$>) ((dummySymbol, , mempty) . ofType)) . third4+ menv = (emptyFamInstEnv, emptyFamInstEnv)++-----------------------------------------------------------------------------------------+-- | Binders generated by class predicates, typically for constraining tyvars (e.g. FNum)+-----------------------------------------------------------------------------------------++classBinds (RApp c ts _ _)+ | isFracCls c+ = [(rTyVarSymbol a, trueSortedReft FFrac) | (RVar a _) <- ts]+ | isNumCls c+ = [(rTyVarSymbol a, trueSortedReft FNum) | (RVar a _) <- ts]+classBinds _+ = []++rTyVarSymbol (RTV α) = typeUniqueSymbol $ TyVarTy α++-----------------------------------------------------------------------------------------+--------------------------- Termination Predicates --------------------------------------+-----------------------------------------------------------------------------------------++makeNumEnv = concatMap go+ where+ go (RApp c ts _ _) | isNumCls c || isFracCls c = [ a | (RVar a _) <- ts]+ go _ = []++isDecreasing autoenv _ (RApp c _ _ _)+ = isJust (sizeFunction (rtc_info c)) -- user specified size or+ || isSizeable autoenv tc+ where tc = rtc_tc c+isDecreasing _ cenv (RVar v _)+ = v `elem` cenv+isDecreasing _ _ _+ = False++makeDecrType autoenv = mkDType autoenv [] []++mkDType autoenv xvs acc [(v, (x, t))]+ = (x, ) $ t `strengthen` tr+ where+ tr = uTop $ Reft (vv, pOr (r:acc))+ r = cmpLexRef xvs (v', vv, f)+ v' = symbol v+ f = mkDecrFun autoenv t+ vv = "vvRec"++mkDType autoenv xvs acc ((v, (x, t)):vxts)+ = mkDType autoenv ((v', x, f):xvs) (r:acc) vxts+ where+ r = cmpLexRef xvs (v', x, f)+ v' = symbol v+ f = mkDecrFun autoenv t+++mkDType _ _ _ _+ = panic Nothing "RefType.mkDType called on invalid input"++isSizeable :: S.HashSet TyCon -> TyCon -> Bool+isSizeable autoenv tc = S.member tc autoenv -- TC.isAlgTyCon tc -- && TC.isRecursiveTyCon tc++mkDecrFun autoenv (RApp c _ _ _)+ | Just f <- sizeFunction $ rtc_info c+ = f+ | isSizeable autoenv $ rtc_tc c+ = \v -> F.mkEApp lenLocSymbol [F.EVar v]+mkDecrFun _ (RVar _ _)+ = EVar+mkDecrFun _ _+ = panic Nothing "RefType.mkDecrFun called on invalid input"++cmpLexRef vxs (v, x, g)+ = pAnd $ (PAtom Lt (g x) (g v)) : (PAtom Ge (g x) zero)+ : [PAtom Eq (f y) (f z) | (y, z, f) <- vxs]+ ++ [PAtom Ge (f y) zero | (y, _, f) <- vxs]+ where zero = ECon $ I 0++makeLexRefa es' es = uTop $ Reft (vv, PIff (EVar vv) $ pOr rs)+ where+ rs = makeLexReft [] [] es es'+ vv = "vvRec"++makeLexReft _ acc [] []+ = acc+makeLexReft old acc (e:es) (e':es')+ = makeLexReft ((e,e'):old) (r:acc) es es'+ where+ r = pAnd $ (PAtom Lt e' e)+ : (PAtom Ge e' zero)+ : [PAtom Eq o' o | (o,o') <- old]+ ++ [PAtom Ge o' zero | (_,o') <- old]+ zero = ECon $ I 0+makeLexReft _ _ _ _+ = panic Nothing "RefType.makeLexReft on invalid input"++--------------------------------------------------------------------------------+mkTyConInfo :: TyCon -> VarianceInfo -> VarianceInfo -> (Maybe (Symbol -> Expr)) -> TyConInfo+mkTyConInfo c usertyvar userprvariance f+ = TyConInfo (if null usertyvar then defaulttyvar else usertyvar) userprvariance f+ where+ defaulttyvar = makeTyConVariance c+++makeTyConVariance :: TyCon -> VarianceInfo+makeTyConVariance c = varSignToVariance <$> tvs+ where+ tvs = tyConTyVarsDef c++ varsigns = if TC.isTypeSynonymTyCon c+ then go True (fromJust $ TC.synTyConRhs_maybe c)+ else L.nub $ concatMap goDCon $ TC.tyConDataCons c++ varSignToVariance v = case filter (\p -> showPpr (fst p) == showPpr v) varsigns of+ [] -> Invariant+ [(_, b)] -> if b then Covariant else Contravariant+ _ -> Bivariant+++ goDCon dc = concatMap (go True) (DataCon.dataConOrigArgTys dc)++ go pos (ForAllTy _ t) = go pos t+ go pos (TyVarTy v) = [(v, pos)]+ go pos (AppTy t1 t2) = go pos t1 ++ go pos t2+ go pos (TyConApp c' ts)+ | c == c'+ = []++-- NV fix that: what happens if we have mutually recursive data types?+-- now just provide "default" Bivariant for mutually rec types.+-- but there should be a finer solution+ | mutuallyRecursive c c'+ = concat $ zipWith (goTyConApp pos) (repeat Bivariant) ts+ | otherwise+ = concat $ zipWith (goTyConApp pos) (makeTyConVariance c') ts++ go pos (FunTy t1 t2) = go (not pos) t1 ++ go pos t2+ go _ (LitTy _) = []++ goTyConApp _ Invariant _ = []+ goTyConApp pos Bivariant t = goTyConApp pos Contravariant t ++ goTyConApp pos Covariant t+ goTyConApp pos Covariant t = go pos t+ goTyConApp pos Contravariant t = go (not pos) t++ mutuallyRecursive c c' = c `S.member` (dataConsOfTyCon c')+++dataConsOfTyCon :: TyCon -> S.HashSet TyCon+dataConsOfTyCon c = mconcat $ go <$> [t | dc <- TC.tyConDataCons c, t <- DataCon.dataConOrigArgTys dc]+ where+ go (ForAllTy _ t) = go t+ go (TyVarTy _) = S.empty+ go (AppTy t1 t2) = go t1 `S.union` go t2+ go (TyConApp c ts) = S.insert c $ mconcat $ go <$> ts+ go (FunTy t1 t2) = go t1 `S.union` go t2+ go (LitTy _) = S.empty++--------------------------------------------------------------------------------+-- | Printing Refinement Types -------------------------------------------------+--------------------------------------------------------------------------------++-- MOVE TO TYPES+instance (SubsTy Symbol (RType c Symbol ()) c, TyConable c, Reftable r, PPrint r, PPrint c, FreeVar c Symbol, SubsTy Symbol (RType c Symbol ()) (RType c Symbol ())) => RefTypable c Symbol r where+ ppRType = ppr_rtype ppEnv++-- MOVE TO TYPES+instance (Reftable r, PPrint r) => RefTypable RTyCon RTyVar r where+ ppRType = ppr_rtype ppEnv++instance Show RTyVar where+ show = showpp++instance PPrint (UReft r) => Show (UReft r) where+ show = showpp++instance (RefTypable c tv r) => PPrint (RType c tv r) where+ pprintTidy _ = ppRType TopPrec++instance PPrint (RType c tv r) => Show (RType c tv r) where+ show = showpp++instance PPrint (RTProp c tv r) => Show (RTProp c tv r) where+ show = showpp++instance PPrint REnv where+ pprintTidy k re = text "RENV" $+$+ pprintTidy k (reLocal re)
+ src/Language/Haskell/Liquid/Types/Specifications.hs view
@@ -0,0 +1,10 @@+-- | This module contains the LH specifications (assumes) for+-- various imported modules.++module Language.Haskell.Liquid.Types.Specifications (specAnchor) where++++-- | Gross hack, to force dependency and loading of module.+specAnchor :: Int+specAnchor = 7
+ src/Language/Haskell/Liquid/Types/Strata.hs view
@@ -0,0 +1,69 @@+{-# LANGUAGE TypeSynonymInstances #-}+{-# LANGUAGE FlexibleInstances #-}++module Language.Haskell.Liquid.Types.Strata (+ SubStratum(..)+ , solveStrata+ , (<:=)+ ) where++import Prelude hiding (error)+++import Language.Fixpoint.Types (Symbol)+import Language.Haskell.Liquid.Types hiding (Def, Loc)++s1 <:= s2+ | any (==SDiv) s1 && any (==SFin) s2 = False+ | otherwise = True++solveStrata = go True [] []+ where go False solved _ [] = solved+ go True solved acc [] = go False solved [] $ {-traceShow ("OLD \n" ++ showMap solved acc ) $ -} subsS solved <$> acc+ go mod solved acc (([], _):ls) = go mod solved acc ls+ go mod solved acc ((_, []):ls) = go mod solved acc ls+ go mod solved acc (l:ls) | allSVars l = go mod solved (l:acc) ls+ | noSVar l = go mod solved acc ls+ | noUpdate l = go mod solved (l:acc) ls+ | otherwise = go True (solve l ++ solved) (l:acc) ls+++allSVars (xs, ys) = all isSVar $ xs ++ ys+noSVar (xs, ys) = all (not . isSVar) (xs ++ ys)+noUpdate (xs, ys) = (not $ updateFin(xs, ys)) && (not $ updateDiv (xs, ys))++updateFin (xs, ys) = any (==SFin) ys && any isSVar xs+updateDiv (xs, ys) = any isSVar ys && any (==SDiv) xs++solve (xs, ys)+ | any (== SDiv) xs = [(l, SDiv) | SVar l <- ys]+ | any (== SFin) ys = [(l, SFin) | SVar l <- xs]+ | otherwise = []+++class SubStratum a where+ subS :: (Symbol, Stratum) -> a -> a+ subsS :: [(Symbol, Stratum)] -> a -> a++ subsS su x = foldr subS x su++instance SubStratum Stratum where+ subS (x, s) (SVar y) | x == y = s+ | otherwise = (SVar y)+ subS _ s = s+++instance (SubStratum a, SubStratum b) => SubStratum (a, b) where+ subS su (x, y) = (subS su x, subS su y)++instance (SubStratum a) => SubStratum [a] where+ subS su xs = subS su <$> xs++instance SubStratum (Annot SpecType) where+ subS su (AnnUse t) = AnnUse $ subS su t+ subS su (AnnDef t) = AnnDef $ subS su t+ subS su (AnnRDf t) = AnnRDf $ subS su t+ subS _ (AnnLoc s) = AnnLoc s++instance SubStratum SpecType where+ subS su t = (\r -> r {ur_strata = subS su (ur_strata r)}) <$> t
+ src/Language/Haskell/Liquid/Types/Variance.hs view
@@ -0,0 +1,16 @@+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE DeriveGeneric #-}++module Language.Haskell.Liquid.Types.Variance ( Variance(..), VarianceInfo ) where++import Prelude hiding (error)+import Control.DeepSeq+import Data.Typeable+import Data.Data+import GHC.Generics++type VarianceInfo = [Variance]+data Variance = Invariant | Bivariant | Contravariant | Covariant+ deriving (Data, Typeable, Show, Generic)++instance NFData Variance
+ src/Language/Haskell/Liquid/Types/Visitors.hs view
@@ -0,0 +1,143 @@+{-# LANGUAGE NoMonomorphismRestriction #-}+{-# LANGUAGE TypeSynonymInstances #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE TupleSections #-}+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE ScopedTypeVariables #-}+++module Language.Haskell.Liquid.Types.Visitors (++ -- * visitors+ CBVisitable (..)++ ) where++import Prelude hiding (error)+import DataCon+import Literal+import CoreSyn++import Var++import Data.List (foldl', (\\), delete)++import qualified Data.HashSet as S+import Language.Fixpoint.Misc+import Language.Haskell.Liquid.GHC.Misc ()+++------------------------------------------------------------------------------+-------------------------------- A CoreBind Visitor --------------------------+------------------------------------------------------------------------------++-- TODO: syb-shrinkage++class CBVisitable a where+ freeVars :: S.HashSet Var -> a -> [Var]+ readVars :: a -> [Var]+ letVars :: a -> [Var]+ literals :: a -> [Literal]++instance CBVisitable [CoreBind] where+ freeVars env cbs = (sortNub xs) \\ ys+ where xs = concatMap (freeVars env) cbs+ ys = concatMap bindings cbs++ readVars = concatMap readVars+ letVars = concatMap letVars+ literals = concatMap literals++instance CBVisitable CoreBind where+ freeVars env (NonRec x e) = freeVars (extendEnv env [x]) e+ freeVars env (Rec xes) = concatMap (freeVars env') es+ where (xs,es) = unzip xes+ env' = extendEnv env xs++ readVars (NonRec _ e) = readVars e+ readVars (Rec xes) = concat [x `delete` nubReadVars e |(x, e) <- xes]+ where nubReadVars = sortNub . readVars++ letVars (NonRec x e) = x : letVars e+ letVars (Rec xes) = xs ++ concatMap letVars es+ where+ (xs, es) = unzip xes++ literals (NonRec _ e) = literals e+ literals (Rec xes) = concatMap literals $ map snd xes++instance CBVisitable (Expr Var) where+ freeVars = exprFreeVars+ readVars = exprReadVars+ letVars = exprLetVars+ literals = exprLiterals++exprFreeVars = go+ where+ go env (Var x) = if x `S.member` env then [] else [x]+ go env (App e a) = (go env e) ++ (go env a)+ go env (Lam x e) = go (extendEnv env [x]) e+ go env (Let b e) = (freeVars env b) ++ (go (extendEnv env (bindings b)) e)+ go env (Tick _ e) = go env e+ go env (Cast e _) = go env e+ go env (Case e x _ cs) = (go env e) ++ (concatMap (freeVars (extendEnv env [x])) cs)+ go _ _ = []++exprReadVars = go+ where+ go (Var x) = [x]+ go (App e a) = concatMap go [e, a]+ go (Lam _ e) = go e+ go (Let b e) = readVars b ++ go e+ go (Tick _ e) = go e+ go (Cast e _) = go e+ go (Case e _ _ cs) = (go e) ++ (concatMap readVars cs)+ go _ = []++exprLetVars = go+ where+ go (Var _) = []+ go (App e a) = concatMap go [e, a]+ go (Lam x e) = x : go e+ go (Let b e) = letVars b ++ go e+ go (Tick _ e) = go e+ go (Cast e _) = go e+ go (Case e x _ cs) = x : go e ++ concatMap letVars cs+ go _ = []++exprLiterals = go+ where+ go (Lit l) = [l]+ go (App e a) = concatMap go [e, a]+ go (Let b e) = literals b ++ go e+ go (Lam _ e) = go e+ go (Tick _ e) = go e+ go (Cast e _) = go e+ go (Case e _ _ cs) = (go e) ++ (concatMap literals cs)+ go _ = []+++instance CBVisitable (Alt Var) where+ freeVars env (a, xs, e) = freeVars env a ++ freeVars (extendEnv env xs) e+ readVars (_,_, e) = readVars e+ letVars (_,xs,e) = xs ++ letVars e+ literals (c,_, e) = literals c ++ literals e+++instance CBVisitable AltCon where+ freeVars _ (DataAlt dc) = dataConImplicitIds dc+ freeVars _ _ = []+ readVars _ = []+ letVars _ = []+ literals (LitAlt l) = [l]+ literals _ = []++++extendEnv = foldl' (flip S.insert)++bindings (NonRec x _)+ = [x]+bindings (Rec xes )+ = map fst xes
+ src/Language/Haskell/Liquid/UX/ACSS.hs view
@@ -0,0 +1,267 @@+-- | Formats Haskell source code as HTML with CSS and Mouseover Type Annotations+module Language.Haskell.Liquid.UX.ACSS (+ hscolour+ , hsannot+ , AnnMap (..)+ , breakS+ , srcModuleName+ , Status (..)+ ) where++import Prelude hiding (error)++import Language.Haskell.HsColour.Anchors+import Language.Haskell.HsColour.Classify as Classify+import Language.Haskell.HsColour.HTML (renderAnchors, escape)+import qualified Language.Haskell.HsColour.CSS as CSS++import Data.Either (partitionEithers)+import Data.Maybe (fromMaybe)+import qualified Data.HashMap.Strict as M+import Data.List (find, isPrefixOf, findIndex, elemIndices, intercalate)+import Data.Char (isSpace)+import Text.Printf+import Language.Haskell.Liquid.GHC.Misc+import Language.Haskell.Liquid.Types.Errors (panic, impossible)++data AnnMap = Ann {+ types :: M.HashMap Loc (String, String) -- ^ Loc -> (Var, Type)+ , errors :: [(Loc, Loc, String)] -- ^ List of error intervals+ , status :: !Status+ }++data Status = Safe | Unsafe | Error | Crash+ deriving (Eq, Ord, Show)++data Annotation = A {+ typ :: Maybe String -- ^ type string+ , err :: Maybe String -- ^ error string+ , lin :: Maybe (Int, Int) -- ^ line number, total width of lines i.e. max (length (show lineNum))+ } deriving (Show)+++-- | Formats Haskell source code using HTML and mouse-over annotations+hscolour :: Bool -- ^ Whether to include anchors.+ -> Bool -- ^ Whether input document is literate haskell or not+ -> String -- ^ Haskell source code, Annotations as comments at end+ -> String -- ^ Coloured Haskell source code.++hscolour anchor lhs = hsannot anchor Nothing lhs . splitSrcAndAnns++type CommentTransform = Maybe (String -> [(TokenType, String)])++-- | Formats Haskell source code using HTML and mouse-over annotations+hsannot :: Bool -- ^ Whether to include anchors.+ -> CommentTransform -- ^ Function to refine comment tokens+ -> Bool -- ^ Whether input document is literate haskell or not+ -> (String, AnnMap) -- ^ Haskell Source, Annotations+ -> String -- ^ Coloured Haskell source code.++hsannot anchor tx False z = hsannot' Nothing anchor tx z+hsannot anchor tx True (s, m) = concatMap chunk $ litSpans $ joinL $ classify $ inlines s+ where chunk (Code c, l) = hsannot' (Just l) anchor tx (c, m)+ chunk (Lit c , _) = c++litSpans :: [Lit] -> [(Lit, Loc)]+litSpans lits = zip lits $ spans lits+ where spans = tokenSpans Nothing . map unL++hsannot' baseLoc anchor tx =+ CSS.pre+ . (if anchor then concatMap (renderAnchors renderAnnotToken)+ . insertAnnotAnchors+ else concatMap renderAnnotToken)+ . annotTokenise baseLoc tx++-- | annotTokenise is absurdly slow: O(#tokens x #errors)++annotTokenise :: Maybe Loc -> CommentTransform -> (String, AnnMap) -> [(TokenType, String, Annotation)]+annotTokenise baseLoc tx (src, annm) = zipWith (\(x,y) z -> (x,y,z)) toks annots+ where+ toks = tokeniseWithCommentTransform tx src+ spans = tokenSpans baseLoc $ map snd toks+ annots = fmap (spanAnnot linWidth annm) spans+ linWidth = length $ show $ length $ lines src++spanAnnot w (Ann ts es _) span = A t e b+ where+ t = fmap snd (M.lookup span ts)+ e = fmap (\_ -> "ERROR") $ find (span `inRange`) [(x,y) | (x,y,_) <- es]+ b = spanLine w span++spanLine w (L (l, c))+ | c == 1 = Just (l, w)+ | otherwise = Nothing++inRange (L (l0, c0)) (L (l, c), L (l', c'))+ = l <= l0 && c <= c0 && l0 <= l' && c0 < c'++tokeniseWithCommentTransform :: Maybe (String -> [(TokenType, String)]) -> String -> [(TokenType, String)]+tokeniseWithCommentTransform Nothing = tokenise+tokeniseWithCommentTransform (Just f) = concatMap (expand f) . tokenise+ where expand f (Comment, s) = f s+ expand _ z = [z]++tokenSpans :: Maybe Loc -> [String] -> [Loc]+tokenSpans = scanl plusLoc . fromMaybe (L (1, 1))++plusLoc :: Loc -> String -> Loc+plusLoc (L (l, c)) s+ = case '\n' `elemIndices` s of+ [] -> L (l, (c + n))+ is -> L ((l + length is), (n - maximum is))+ where n = length s++renderAnnotToken :: (TokenType, String, Annotation) -> String+renderAnnotToken (x, y, a) = renderLinAnnot (lin a)+ $ renderErrAnnot (err a)+ $ renderTypAnnot (typ a)+ $ CSS.renderToken (x, y)++++renderTypAnnot (Just ann) s = printf "<a class=annot href=\"#\"><span class=annottext>%s</span>%s</a>" (escape ann) s+renderTypAnnot Nothing s = s++renderErrAnnot (Just _) s = printf "<span class=hs-error>%s</span>" s+renderErrAnnot Nothing s = s++renderLinAnnot (Just d) s = printf "<span class=hs-linenum>%s: </span>%s" (lineString d) s+renderLinAnnot Nothing s = s++lineString (i, w) = (replicate (w - (length is)) ' ') ++ is+ where is = show i++{- Example Annotation:+<a class=annot href="#"><span class=annottext>x#agV:Int -> {VV_int:Int | (0 <= VV_int),(x#agV <= VV_int)}</span>+<span class='hs-definition'>NOWTRYTHIS</span></a>+-}+++insertAnnotAnchors :: [(TokenType, String, a)] -> [Either String (TokenType, String, a)]+insertAnnotAnchors toks+ = stitch (zip toks' toks) $ insertAnchors toks'+ where toks' = [(x,y) | (x,y,_) <- toks]++stitch :: Eq b => [(b, c)] -> [Either a b] -> [Either a c]+stitch xys ((Left a) : rest)+ = (Left a) : stitch xys rest+stitch ((x,y):xys) ((Right x'):rest)+ | x == x'+ = (Right y) : stitch xys rest+ | otherwise+ = panic Nothing "stitch"+stitch _ []+ = []+stitch _ _+ = impossible Nothing "stitch: cannot happen"++splitSrcAndAnns :: String -> (String, AnnMap)+splitSrcAndAnns s =+ let ls = lines s in+ case findIndex (breakS ==) ls of+ Nothing -> (s, Ann M.empty [] Safe)+ Just i -> (src, ann)+ where (codes, _:mname:annots) = splitAt i ls+ ann = annotParse mname $ dropWhile isSpace $ unlines annots+ src = unlines codes++srcModuleName :: String -> String+srcModuleName = fromMaybe "Main" . tokenModule . tokenise++tokenModule toks+ = do i <- findIndex ((Keyword, "module") ==) toks+ let (_, toks') = splitAt (i+2) toks+ j <- findIndex ((Space ==) . fst) toks'+ let (toks'', _) = splitAt j toks'+ return $ concatMap snd toks''++breakS = "MOUSEOVER ANNOTATIONS"++annotParse :: String -> String -> AnnMap+annotParse mname s = Ann (M.fromList ts) [(x,y,"") | (x,y) <- es] Safe+ where+ (ts, es) = partitionEithers $ parseLines mname 0 $ lines s+++parseLines _ _ []+ = []++parseLines mname i ("":ls)+ = parseLines mname (i+1) ls++parseLines mname i (_:_:l:c:"0":l':c':rest')+ = Right (L (line, col), L (line', col')) : parseLines mname (i + 7) rest'+ where line = (read l) :: Int+ col = (read c) :: Int+ line' = (read l') :: Int+ col' = (read c') :: Int++parseLines mname i (x:f:l:c:n:rest)+ | f /= mname+ = parseLines mname (i + 5 + num) rest'+ | otherwise+ = Left (L (line, col), (x, anns)) : parseLines mname (i + 5 + num) rest'+ where line = (read l) :: Int+ col = (read c) :: Int+ num = (read n) :: Int+ anns = intercalate "\n" $ take num rest+ rest' = drop num rest++parseLines _ i _+ = panic Nothing $ "Error Parsing Annot Input on Line: " ++ show i++instance Show AnnMap where+ show (Ann ts es _ ) = "\n\n" ++ (concatMap ppAnnotTyp $ M.toList ts)+ ++ (concatMap ppAnnotErr [(x,y) | (x,y,_) <- es])++ppAnnotTyp (L (l, c), (x, s)) = printf "%s\n%d\n%d\n%d\n%s\n\n\n" x l c (length $ lines s) s+ppAnnotErr (L (l, c), L (l', c')) = printf " \n%d\n%d\n0\n%d\n%d\n\n\n\n" l c l' c'+++---------------------------------------------------------------------------------+---- Code for Dealing With LHS, stolen from Language.Haskell.HsColour.HsColour --+---------------------------------------------------------------------------------++-- | Separating literate files into code\/comment chunks.+data Lit = Code {unL :: String} | Lit {unL :: String} deriving (Show)++-- Re-implementation of 'lines', for better efficiency (but decreased laziness).+-- Also, importantly, accepts non-standard DOS and Mac line ending characters.+-- And retains the trailing '\n' character in each resultant string.+inlines :: String -> [String]+inlines s = lines' s id+ where+ lines' [] acc = [acc []]+ lines' ('\^M':'\n':s) acc = acc ['\n'] : lines' s id -- DOS+ lines' ('\n':s) acc = acc ['\n'] : lines' s id -- Unix+ lines' (c:s) acc = lines' s (acc . (c:))+++-- | The code for classify is largely stolen from Language.Preprocessor.Unlit.+classify :: [String] -> [Lit]+classify [] = []+classify (x:xs) | "\\begin{code}"`isPrefixOf`x+ = Lit x: allProg "code" xs+classify (x:xs) | "\\begin{spec}"`isPrefixOf`x+ = Lit x: allProg "spec" xs+classify (('>':x):xs) = Code ('>':x) : classify xs+classify (x:xs) = Lit x: classify xs+++allProg name = go+ where+ end = "\\end{" ++ name ++ "}"+ go [] = [] -- Should give an error message,+ -- but I have no good position information.+ go (x:xs) | end `isPrefixOf `x+ = Lit x: classify xs+ go (x:xs) = Code x: go xs+++-- | Join up chunks of code\/comment that are next to each other.+joinL :: [Lit] -> [Lit]+joinL [] = []+joinL (Code c:Code c2:xs) = joinL (Code (c++c2):xs)+joinL (Lit c :Lit c2 :xs) = joinL (Lit (c++c2):xs)+joinL (any:xs) = any: joinL xs
+ src/Language/Haskell/Liquid/UX/Annotate.hs view
@@ -0,0 +1,451 @@+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE TupleSections #-}+{-# LANGUAGE NoMonomorphismRestriction #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TypeSynonymInstances #-}+{-# LANGUAGE FlexibleInstances #-}++{- LIQUID "--diffcheck" @-}++---------------------------------------------------------------------------+-- | This module contains the code that uses the inferred types to generate+-- 1. HTMLized source with Inferred Types in mouseover annotations.+-- 2. Annotations files (e.g. for vim/emacs)+-- 3. JSON files for the web-demo etc.+---------------------------------------------------------------------------+++module Language.Haskell.Liquid.UX.Annotate (specAnchor, mkOutput, annotate) where++import Prelude hiding (error)+import GHC ( SrcSpan (..)+ , srcSpanStartCol+ , srcSpanEndCol+ , srcSpanStartLine+ , srcSpanEndLine)+import Text.PrettyPrint.HughesPJ hiding (first)+import GHC.Exts (groupWith, sortWith)++import Data.Char (isSpace)+import Data.Function (on)+import Data.List (sortBy)+import Data.Maybe (mapMaybe)++import Data.Aeson+import Control.Arrow hiding ((<+>))+-- import Control.Applicative ((<$>))+import Control.Monad (when, forM_)++import System.Exit (ExitCode (..))+import System.FilePath (takeFileName, dropFileName, (</>))+import System.Directory (findExecutable, copyFile)+import Text.Printf (printf)+import qualified Data.List as L+import qualified Data.Vector as V+import qualified Data.ByteString.Lazy as B+import qualified Data.Text as T+import qualified Data.HashMap.Strict as M+import qualified Language.Haskell.Liquid.UX.ACSS as ACSS+import Language.Haskell.HsColour.Classify+import Language.Fixpoint.Utils.Files+import Language.Fixpoint.Misc+import Language.Haskell.Liquid.GHC.Misc+import Language.Fixpoint.Types hiding (Error, Loc, Constant (..), Located (..))+import Language.Haskell.Liquid.Misc+import Language.Haskell.Liquid.Types.PrettyPrint+import Language.Haskell.Liquid.Types.RefType++import Language.Haskell.Liquid.UX.Errors ()+import Language.Haskell.Liquid.UX.Tidy+import Language.Haskell.Liquid.Types hiding (Located(..), Def(..))+import Language.Haskell.Liquid.Types.Specifications++++-- | @output@ creates the pretty printed output+--------------------------------------------------------------------------------------------+mkOutput :: Config -> ErrorResult -> FixSolution -> AnnInfo (Annot SpecType) -> Output Doc+--------------------------------------------------------------------------------------------+mkOutput cfg res sol anna+ = O { o_vars = Nothing+ , o_errors = []+ , o_types = toDoc <$> annTy+ , o_templs = toDoc <$> annTmpl+ , o_bots = mkBots annTy+ , o_result = res+ }+ where+ annTmpl = closeAnnots anna+ annTy = tidySpecType Lossy <$> applySolution sol annTmpl+ toDoc = rtypeDoc tidy+ tidy = if shortNames cfg then Lossy else Full++-- | @annotate@ actually renders the output to files+-------------------------------------------------------------------+annotate :: Config -> FilePath -> Output Doc -> IO ()+-------------------------------------------------------------------+annotate cfg srcF out+ = do generateHtml srcF tpHtmlF tplAnnMap+ generateHtml srcF tyHtmlF typAnnMap+ writeFile vimF $ vimAnnot cfg annTyp+ B.writeFile jsonF $ encode typAnnMap+ when showWarns $ forM_ bots (printf "WARNING: Found false in %s\n" . showPpr)+ where+ tplAnnMap = mkAnnMap cfg res annTpl+ typAnnMap = mkAnnMap cfg res annTyp+ annTpl = o_templs out+ annTyp = o_types out+ res = o_result out+ bots = o_bots out+ tyHtmlF = extFileName Html srcF+ tpHtmlF = extFileName Html $ extFileName Cst srcF+ _annF = extFileName Annot srcF+ jsonF = extFileName Json srcF+ vimF = extFileName Vim srcF+ showWarns = not $ nowarnings cfg++mkBots (AI m) = [ src | (src, (Just _, t) : _) <- sortBy (compare `on` fst) $ M.toList m+ , isFalse (rTypeReft t) ]++writeFilesOrStrings :: FilePath -> [Either FilePath String] -> IO ()+writeFilesOrStrings tgtFile = mapM_ $ either (`copyFile` tgtFile) (tgtFile `appendFile`)++generateHtml srcF htmlF annm+ = do src <- readFile srcF+ let lhs = isExtFile LHs srcF+ let body = {-# SCC "hsannot" #-} ACSS.hsannot False (Just tokAnnot) lhs (src, annm)+ cssFile <- getCssPath+ copyFile cssFile (dropFileName htmlF </> takeFileName cssFile)+ renderHtml lhs htmlF srcF (takeFileName cssFile) body++renderHtml True = renderPandoc+renderHtml False = renderDirect++-------------------------------------------------------------------------+-- | Pandoc HTML Rendering (for lhs + markdown source) ------------------+-------------------------------------------------------------------------++renderPandoc htmlFile srcFile css body+ = do renderFn <- maybe renderDirect renderPandoc' <$> findExecutable "pandoc"+ renderFn htmlFile srcFile css body++renderPandoc' pandocPath htmlFile srcFile css body+ = do _ <- writeFile mdFile $ pandocPreProc body+ ec <- executeShellCommand "pandoc" cmd+ writeFilesOrStrings htmlFile [Right (cssHTML css)]+ checkExitCode cmd ec+ where mdFile = extFileName Mkdn srcFile+ cmd = pandocCmd pandocPath mdFile htmlFile++checkExitCode _ (ExitSuccess) = return ()+checkExitCode cmd (ExitFailure n) = panic Nothing $ "cmd: " ++ cmd ++ " failure code " ++ show n++pandocCmd pandocPath mdFile htmlFile+ = printf "%s -f markdown -t html %s > %s" pandocPath mdFile htmlFile++pandocPreProc = T.unpack+ . strip beg code+ . strip end code+ . strip beg spec+ . strip end spec+ . T.pack+ where+ beg, end, code, spec :: String+ beg = "begin"+ end = "end"+ code = "code"+ spec = "spec"+ strip x y = T.replace (T.pack $ printf "\\%s{%s}" x y) T.empty+ -- stripBcode = T.replace (T.pack "\\begin{code}") T.empty+ -- stripEcode = T.replace (T.pack "\\end{code}") T.empty+ -- stripBspec = T.replace (T.pack "\\begin{code}") T.empty+ -- stripEspec = T.replace (T.pack "\\end{code}") T.empty+++++-------------------------------------------------------------------------+-- | Direct HTML Rendering (for non-lhs/markdown source) ----------------+-------------------------------------------------------------------------++-- More or less taken from hscolour++renderDirect htmlFile srcFile css body+ = writeFile htmlFile $! (top'n'tail full srcFile css $! body)+ where full = True -- False -- TODO: command-line-option++-- | @top'n'tail True@ is used for standalone HTML,+-- @top'n'tail False@ for embedded HTML++top'n'tail True title css = (htmlHeader title css ++) . (++ htmlClose)+top'n'tail False _ _ = id++-- Use this for standalone HTML++htmlHeader title css = unlines+ [ "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\">"+ , "<html>"+ , "<head>"+ , "<title>" ++ title ++ "</title>"+ , "</head>"+ , cssHTML css+ , "<body>"+ , "<hr>"+ , "Put mouse over identifiers to see inferred types"+ ]++htmlClose = "\n</body>\n</html>"++cssHTML css = unlines+ [ "<head>"+ , "<link type='text/css' rel='stylesheet' href='"++ css ++ "' />"+ , "</head>"+ ]++------------------------------------------------------------------------------+-- | Building Annotation Maps ------------------------------------------------+------------------------------------------------------------------------------++-- | This function converts our annotation information into that which+-- is required by `Language.Haskell.Liquid.ACSS` to generate mouseover+-- annotations.++mkAnnMap :: Config -> ErrorResult -> AnnInfo Doc -> ACSS.AnnMap+mkAnnMap cfg res ann = ACSS.Ann (mkAnnMapTyp cfg ann) (mkAnnMapErr res) (mkStatus res)++mkStatus (Safe) = ACSS.Safe+mkStatus (Unsafe _) = ACSS.Unsafe+mkStatus (Crash _ _) = ACSS.Error++++mkAnnMapErr (Unsafe ls) = mapMaybe cinfoErr ls+mkAnnMapErr (Crash ls _) = mapMaybe cinfoErr ls+mkAnnMapErr _ = []++cinfoErr e = case pos e of+ RealSrcSpan l -> Just (srcSpanStartLoc l, srcSpanEndLoc l, showpp e)+ _ -> Nothing+++-- mkAnnMapTyp :: (RefTypable a c tv r, RefTypable a c tv (), PPrint tv, PPrint a) =>Config-> AnnInfo (RType a c tv r) -> M.HashMap Loc (String, String)+mkAnnMapTyp cfg z = M.fromList $ map (first srcSpanStartLoc) $ mkAnnMapBinders cfg z++mkAnnMapBinders cfg (AI m)+ = map (second bindStr . head . sortWith (srcSpanEndCol . fst))+ $ groupWith (lineCol . fst) locBinds+ where+ locBinds = [ (l, x) | (RealSrcSpan l, x:_) <- M.toList m, oneLine l]+ bindStr (x, v) = (maybe "_" (symbolString . shorten . symbol) x, render v)+ shorten = if shortNames cfg then dropModuleNames else id++closeAnnots :: AnnInfo (Annot SpecType) -> AnnInfo SpecType+closeAnnots = closeA . filterA . collapseA++closeA a@(AI m) = cf <$> a+ where+ cf (AnnLoc l) = case m `mlookup` l of+ [(_, AnnUse t)] -> t+ [(_, AnnDef t)] -> t+ [(_, AnnRDf t)] -> t+ _ -> panic Nothing $ "malformed AnnInfo: " ++ showPpr l+ cf (AnnUse t) = t+ cf (AnnDef t) = t+ cf (AnnRDf t) = t++filterA (AI m) = AI (M.filter ff m)+ where+ ff [(_, AnnLoc l)] = l `M.member` m+ ff _ = True++collapseA (AI m) = AI (fmap pickOneA m)++pickOneA xas = case (rs, ds, ls, us) of+ (x:_, _, _, _) -> [x]+ (_, x:_, _, _) -> [x]+ (_, _, x:_, _) -> [x]+ (_, _, _, x:_) -> [x]+ (_, _, _, _ ) -> [ ]+ where+ rs = [x | x@(_, AnnRDf _) <- xas]+ ds = [x | x@(_, AnnDef _) <- xas]+ ls = [x | x@(_, AnnLoc _) <- xas]+ us = [x | x@(_, AnnUse _) <- xas]++------------------------------------------------------------------------------+-- | Tokenizing Refinement Type Annotations in @-blocks ----------------------+------------------------------------------------------------------------------++-- | The token used for refinement symbols inside the highlighted types in @-blocks.+refToken = Keyword++-- | The top-level function for tokenizing @-block annotations. Used to+-- tokenize comments by ACSS.+tokAnnot s+ = case trimLiquidAnnot s of+ Just (l, body, r) -> [(refToken, l)] ++ tokBody body ++ [(refToken, r)]+ Nothing -> [(Comment, s)]++trimLiquidAnnot ('{':'-':'@':ss)+ | drop (length ss - 3) ss == "@-}"+ = Just (liquidBegin, take (length ss - 3) ss, liquidEnd)+trimLiquidAnnot _+ = Nothing++tokBody s+ | isData s = tokenise s+ | isType s = tokenise s+ | isIncl s = tokenise s+ | isMeas s = tokenise s+ | otherwise = tokeniseSpec s++isMeas = spacePrefix "measure"+isData = spacePrefix "data"+isType = spacePrefix "type"+isIncl = spacePrefix "include"++{-@ spacePrefix :: String -> s:String -> Bool / [len s] @-}+spacePrefix :: String -> String -> Bool+spacePrefix str s@(c:cs)+ | isSpace c = spacePrefix str cs+ | otherwise = take (length str) s == str+spacePrefix _ _ = False+++tokeniseSpec :: String -> [(TokenType, String)]+tokeniseSpec str = {- traceShow ("tokeniseSpec: " ++ str) $ -} tokeniseSpec' str++tokeniseSpec' = tokAlt . chopAltDBG -- [('{', ':'), ('|', '}')]+ where+ tokAlt (s:ss) = tokenise s ++ tokAlt' ss+ tokAlt _ = []+ tokAlt' (s:ss) = (refToken, s) : tokAlt ss+ tokAlt' _ = []++chopAltDBG y = {- traceShow ("chopAlts: " ++ y) $ -}+ filter (/= "") $ concatMap (chopAlts [("{", ":"), ("|", "}")])+ $ chopAlts [("<{", "}>"), ("{", "}")] y+++++------------------------------------------------------------------------+-- | JSON: Annotation Data Types ---------------------------------------+------------------------------------------------------------------------++data Assoc k a = Asc (M.HashMap k a)+type AnnTypes = Assoc Int (Assoc Int Annot1)+type AnnErrors = [(Loc, Loc, String)]+data Annot1 = A1 { ident :: String+ , ann :: String+ , row :: Int+ , col :: Int+ }++------------------------------------------------------------------------+-- | Creating Vim Annotations ------------------------------------------+------------------------------------------------------------------------++vimAnnot :: Config -> AnnInfo Doc -> String+vimAnnot cfg = L.intercalate "\n" . map vimBind . mkAnnMapBinders cfg++vimBind (sp, (v, ann)) = printf "%d:%d-%d:%d::%s" l1 c1 l2 c2 (v ++ " :: " ++ show ann)+ where+ l1 = srcSpanStartLine sp+ c1 = srcSpanStartCol sp+ l2 = srcSpanEndLine sp+ c2 = srcSpanEndCol sp++------------------------------------------------------------------------+-- | JSON Instances ----------------------------------------------------+------------------------------------------------------------------------++instance ToJSON ACSS.Status where+ toJSON ACSS.Safe = "safe"+ toJSON ACSS.Unsafe = "unsafe"+ toJSON ACSS.Error = "error"+ toJSON ACSS.Crash = "crash"++instance ToJSON Annot1 where+ toJSON (A1 i a r c) = object [ "ident" .= i+ , "ann" .= a+ , "row" .= r+ , "col" .= c+ ]++instance ToJSON Loc where+ toJSON (L (l, c)) = object [ "line" .= toJSON l+ , "column" .= toJSON c ]++instance ToJSON AnnErrors where+ toJSON errs = Array $ V.fromList $ fmap toJ errs+ where+ toJ (l,l',s) = object [ "start" .= toJSON l+ , "stop" .= toJSON l'+ , "message" .= toJSON s ]++instance (Show k, ToJSON a) => ToJSON (Assoc k a) where+ toJSON (Asc kas) = object [ tshow k .= toJSON a | (k, a) <- M.toList kas ]+ where+ tshow = T.pack . show++instance ToJSON ACSS.AnnMap where+ toJSON a = object [ "types" .= toJSON (annTypes a)+ , "errors" .= toJSON (ACSS.errors a)+ , "status" .= toJSON (ACSS.status a)+ ]++annTypes :: ACSS.AnnMap -> AnnTypes+annTypes a = grp [(l, c, ann1 l c x s) | (l, c, x, s) <- binders]+ where+ ann1 l c x s = A1 x s l c+ grp = L.foldl' (\m (r,c,x) -> ins r c x m) (Asc M.empty)+ binders = [(l, c, x, s) | (L (l, c), (x, s)) <- M.toList $ ACSS.types a]++ins r c x (Asc m) = Asc (M.insert r (Asc (M.insert c x rm)) m)+ where+ Asc rm = M.lookupDefault (Asc M.empty) r m++--------------------------------------------------------------------------------+-- | LH Related Stuff ----------------------------------------------------------+--------------------------------------------------------------------------------++{-@ LIQUID "--diffcheck" @-}++{-@ type ListNE a = {v:[a] | 0 < len v} @-}+{-@ type ListN a N = {v:[a] | len v == N} @-}+{-@ type ListXs a Xs = ListN a {len Xs} @-}++{-@ assume GHC.Exts.sortWith :: Ord b => (a -> b) -> xs:[a] -> ListXs a xs @-}+{-@ assume GHC.Exts.groupWith :: Ord b => (a -> b) -> [a] -> [ListNE a] @-}++{- junkProp :: ListNE Int @-}+-- junkProp :: [Int]+-- junkProp = [ 8 ]++--------------------------------------------------------------------------------+-- | A Little Unit Test --------------------------------------------------------+--------------------------------------------------------------------------------++_anns :: AnnTypes+_anns = i [(5, i [( 14, A1 { ident = "foo"+ , ann = "int -> int"+ , row = 5+ , col = 14+ })+ ]+ )+ ,(9, i [( 22, A1 { ident = "map"+ , ann = "(a -> b) -> [a] -> [b]"+ , row = 9+ , col = 22+ })+ ,( 28, A1 { ident = "xs"+ , ann = "[b]"+ , row = 9+ , col = 28+ })+ ])+ ]++i = Asc . M.fromList
+ src/Language/Haskell/Liquid/UX/CTags.hs view
@@ -0,0 +1,73 @@+{-# LANGUAGE TupleSections #-}+-- | This module contains the code for generating "tags" for constraints+-- based on their source, i.e. the top-level binders under which the+-- constraint was generated. These tags are used by fixpoint to+-- prioritize constraints by the "source-level" function.++module Language.Haskell.Liquid.UX.CTags (+ -- * Type for constraint tags+ TagKey, TagEnv++ -- * Default tag value+ , defaultTag++ -- * Constructing @TagEnv@+ , makeTagEnv++ -- * Accessing @TagEnv@+ , getTag, memTagEnv++) where++import Var+import CoreSyn+import Prelude hiding (error)++import qualified Data.HashSet as S+import qualified Data.HashMap.Strict as M+import qualified Data.Graph as G++import Language.Fixpoint.Types (Tag)+import Language.Haskell.Liquid.Types.Visitors (freeVars)+import Language.Haskell.Liquid.Misc (mapSnd)++-- | The @TagKey@ is the top-level binder, and @Tag@ is a singleton Int list++type TagKey = Var+type TagEnv = M.HashMap TagKey Tag++-- TODO: use the "callgraph" SCC to do this numbering.++defaultTag :: Tag+defaultTag = [0]++memTagEnv :: TagKey -> TagEnv -> Bool+memTagEnv = M.member++makeTagEnv :: [CoreBind] -> TagEnv+makeTagEnv = M.map (:[]) . callGraphRanks . makeCallGraph++-- makeTagEnv = M.fromList . (`zip` (map (:[]) [1..])). L.sort . map fst . concatMap bindEqns++getTag :: TagKey -> TagEnv -> Tag+getTag = M.lookupDefault defaultTag++------------------------------------------------------------------------------------------------------++type CallGraph = [(Var, [Var])] -- caller-callee pairs++callGraphRanks :: CallGraph -> M.HashMap Var Int+-- callGraphRanks cg = traceShow ("CallGraph Ranks: " ++ show cg) $ callGraphRanks' cg++callGraphRanks = M.fromList . concat . index . mkScc+ where mkScc cg = G.stronglyConnComp [(u, u, vs) | (u, vs) <- cg]+ index = zipWith (\i -> map (, i) . G.flattenSCC) [1..]++makeCallGraph :: [CoreBind] -> CallGraph+makeCallGraph cbs = mapSnd calls `fmap` xes+ where xes = concatMap bindEqns cbs+ xs = S.fromList $ map fst xes+ calls = filter (`S.member` xs) . freeVars S.empty++bindEqns (NonRec x e) = [(x, e)]+bindEqns (Rec xes) = xes
+ src/Language/Haskell/Liquid/UX/CmdLine.hs view
@@ -0,0 +1,433 @@+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE NoMonomorphismRestriction #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TupleSections #-}+{-# LANGUAGE TypeSynonymInstances #-}+{-# OPTIONS_GHC -fno-cse #-}++{-@ LIQUID "--diff" @-}++-- | This module contains all the code needed to output the result which+-- is either: `SAFE` or `WARNING` with some reasonable error message when+-- something goes wrong. All forms of errors/exceptions should go through+-- here. The idea should be to report the error, the source position that+-- causes it, generate a suitable .json file and then exit.++module Language.Haskell.Liquid.UX.CmdLine (+ -- * Get Command Line Configuration+ getOpts, mkOpts, defConfig++ -- * Update Configuration With Pragma+ , withPragmas++ -- * Exit Function+ , exitWithResult++ -- * Diff check mode+ , diffcheck++) where++import Prelude hiding (error)++import Control.Monad+import Data.Maybe++import System.Directory+import System.Exit+import System.Environment++import System.Console.CmdArgs.Explicit+import System.Console.CmdArgs.Implicit hiding (Loud)+import System.Console.CmdArgs.Text++import Data.List (nub)+++import System.FilePath (dropFileName, isAbsolute,+ takeDirectory, (</>))++import Language.Fixpoint.Types.Config hiding (Config, linear, elimStats,+ getOpts, cores, minPartSize,+ maxPartSize, newcheck, eliminate)+import Language.Fixpoint.Utils.Files+import Language.Fixpoint.Misc+import Language.Fixpoint.Types.Names+import Language.Fixpoint.Types hiding (Error, Result, saveQuery)+import Language.Haskell.Liquid.UX.Annotate+import Language.Haskell.Liquid.GHC.Misc+import Language.Haskell.Liquid.Misc+import Language.Haskell.Liquid.Types.PrettyPrint+import Language.Haskell.Liquid.Types hiding (config, name, typ)++++import Text.Parsec.Pos (newPos)+import Text.PrettyPrint.HughesPJ hiding (Mode)++++---------------------------------------------------------------------------------+-- Config Magic Numbers----------------------------------------------------------+---------------------------------------------------------------------------------++defaultMaxParams :: Int+defaultMaxParams = 2++---------------------------------------------------------------------------------+-- Parsing Command Line----------------------------------------------------------+---------------------------------------------------------------------------------+config :: Mode (CmdArgs Config)+config = cmdArgsMode $ Config {+ files+ = def &= typ "TARGET"+ &= args+ &= typFile++ , idirs+ = def &= typDir+ &= help "Paths to Spec Include Directory "++ , fullcheck+ = def+ &= help "Full Checking: check all binders (DEFAULT)"++ , diffcheck+ = def+ &= help "Incremental Checking: only check changed binders"++ , higherorder+ = def+ &= help "Allow higher order binders into the logic"++ , linear+ = def+ &= help "Use uninterpreted integer multiplication and division"++ , saveQuery+ = def &= help "Save fixpoint query to file (slow)"++ , binders+ = def &= help "Check a specific set of binders"++ , noPrune+ = def &= help "Disable prunning unsorted Predicates"+ &= name "no-prune-unsorted"++ , notermination+ = def &= help "Disable Termination Check"+ &= name "no-termination-check"++ , autoproofs+ = def &= help "Automatically construct proofs from axioms"+ &= name "auto-proofs"++ , nowarnings+ = def &= help "Don't display warnings, only show errors"+ &= name "no-warnings"++ , trustinternals+ = def &= help "Trust all ghc auto generated code"+ &= name "trust-internals"++ , nocaseexpand+ = def &= help "Don't expand the default case in a case-expression"+ &= name "no-case-expand"+ , strata+ = def &= help "Enable Strata Analysis"++ , notruetypes+ = def &= help "Disable Trueing Top Level Types"+ &= name "no-true-types"++ , totality+ = def &= help "Check totality"++ , cores+ = def &= help "Use m cores to solve logical constraints"++ , minPartSize+ = defaultMinPartSize &= help "If solving on multiple cores, ensure that partitions are of at least m size"++ , maxPartSize+ = defaultMaxPartSize &= help ("If solving on multiple cores, once there are as many partitions " +++ "as there are cores, don't merge partitions if they will exceed this " +++ "size. Overrides the minpartsize option.")++ , smtsolver+ = def &= help "Name of SMT-Solver"++ , newcheck+ = True &= help "New fixpoint check"++ , noCheckUnknown+ = def &= explicit+ &= name "no-check-unknown"+ &= help "Don't complain about specifications for unexported and unused values "++ , maxParams+ = defaultMaxParams &= help "Restrict qualifier mining to those taking at most `m' parameters (2 by default)"++ , shortNames+ = def &= name "short-names"+ &= help "Print shortened names, i.e. drop all module qualifiers."++ , shortErrors+ = def &= name "short-errors"+ &= help "Don't show long error messages, just line numbers."++ , cabalDir+ = def &= name "cabal-dir"+ &= help "Find and use .cabal to add paths to sources for imported files"++ , ghcOptions+ = def &= name "ghc-option"+ &= typ "OPTION"+ &= help "Pass this option to GHC"++ , cFiles+ = def &= name "c-files"+ &= typ "OPTION"+ &= help "Tell GHC to compile and link against these files"++ , eliminate+ = def &= name "eliminate"+ &= help "Use experimental 'eliminate' feature"++ , port+ = defaultPort+ &= name "port"+ &= help "Port at which lhi should listen"++ , exactDC+ = def &= help "Exact Type for Data Constructors"+ &= name "exact-data-cons"++ , scrapeImports+ = False &= help "Scrape qualifiers from imported specifications"+ &= name "scrape-imports"+ &= explicit++ , scrapeUsedImports+ = False &= help "Scrape qualifiers from used, imported specifications"+ &= name "scrape-used-imports"+ &= explicit++ , elimStats+ = False &= name "elimStats"+ &= help "Print eliminate stats"++ } &= verbosity+ &= program "liquid"+ &= help "Refinement Types for Haskell"+ &= summary copyright+ &= details [ "LiquidHaskell is a Refinement Type based verifier for Haskell"+ , ""+ , "To check a Haskell file foo.hs, type:"+ , " liquid foo.hs "+ ]++defaultPort :: Int+defaultPort = 3000++getOpts :: [String] -> IO Config+getOpts as = do+ cfg0 <- envCfg+ cfg1 <- mkOpts =<< cmdArgsRun'+ config { modeValue = (modeValue config) { cmdArgsValue = cfg0 } }+ as+ cfg <- fixConfig cfg1+ whenNormal $ putStrLn copyright+ withSmtSolver cfg+++cmdArgsRun' :: Mode (CmdArgs a) -> [String] -> IO a+cmdArgsRun' md as+ = case parseResult of+ Left e -> putStrLn (helpMsg e) >> exitFailure+ Right a -> cmdArgsApply a+ where+ helpMsg e = showText defaultWrap $ helpText [e] HelpFormatDefault md+ parseResult = process md as -- <$> getArgs++--------------------------------------------------------------------------------+withSmtSolver :: Config -> IO Config+--------------------------------------------------------------------------------+withSmtSolver cfg =+ case smtsolver cfg of+ Just _ -> return cfg+ Nothing -> do smts <- mapM findSmtSolver [Z3, Cvc4, Mathsat]+ case catMaybes smts of+ (s:_) -> return (cfg {smtsolver = Just s})+ _ -> panic Nothing noSmtError+ where+ noSmtError = "LiquidHaskell requires an SMT Solver, i.e. z3, cvc4, or mathsat to be installed."++findSmtSolver :: SMTSolver -> IO (Maybe SMTSolver)+findSmtSolver smt = maybe Nothing (const $ Just smt) <$> findExecutable (show smt)++fixConfig :: Config -> IO Config+fixConfig cfg = do+ pwd <- getCurrentDirectory+ cfg <- canonicalizePaths pwd cfg+ return $ fixDiffCheck cfg++-- | Attempt to canonicalize all `FilePath's in the `Config' so we don't have+-- to worry about relative paths.+canonicalizePaths :: FilePath -> Config -> IO Config+canonicalizePaths pwd cfg = do+ tgt <- canonicalizePath pwd+ isdir <- doesDirectoryExist tgt+ is <- mapM (canonicalize tgt isdir) $ idirs cfg+ cs <- mapM (canonicalize tgt isdir) $ cFiles cfg+ return $ cfg { idirs = is, cFiles = cs }++canonicalize :: FilePath -> Bool -> FilePath -> IO FilePath+canonicalize tgt isdir f+ | isAbsolute f = return f+ | isdir = canonicalizePath (tgt </> f)+ | otherwise = canonicalizePath (takeDirectory tgt </> f)++fixDiffCheck :: Config -> Config+fixDiffCheck cfg = cfg { diffcheck = diffcheck cfg && not (fullcheck cfg) }++envCfg = do so <- lookupEnv "LIQUIDHASKELL_OPTS"+ case so of+ Nothing -> return defConfig+ Just s -> parsePragma $ envLoc s+ where+ envLoc = Loc l l+ l = newPos "ENVIRONMENT" 0 0++copyright = "LiquidHaskell Copyright 2009-15 Regents of the University of California. All Rights Reserved.\n"++mkOpts :: Config -> IO Config+mkOpts cfg+ = do let files' = sortNub $ files cfg+ id0 <- getIncludeDir+ return $ cfg { files = files' }+ { idirs = -- NOTE: not convinced we should add the file's directory+ -- to the search path+ (dropFileName <$> files') +++ [id0 </> gHC_VERSION, id0] ++ idirs cfg }+ -- tests fail if you flip order of idirs'++---------------------------------------------------------------------------------------+-- | Updating options+---------------------------------------------------------------------------------------++---------------------------------------------------------------------------------------+withPragmas :: Config -> FilePath -> [Located String] -> IO Config+---------------------------------------------------------------------------------------+withPragmas cfg fp ps = foldM withPragma cfg ps >>= canonicalizePaths fp++withPragma :: Config -> Located String -> IO Config+withPragma c s = withArgs [val s] $ cmdArgsRun+ config { modeValue = (modeValue config) { cmdArgsValue = c } }+ --(c `mappend`) <$> parsePragma s++parsePragma :: Located String -> IO Config+parsePragma = withPragma defConfig+ --withArgs [val s] $ cmdArgsRun config++defConfig :: Config+defConfig = Config { files = def+ , idirs = def+ , newcheck = True+ , fullcheck = def+ , linear = def+ , higherorder = def+ , diffcheck = def+ , saveQuery = def+ , binders = def+ , noCheckUnknown = def+ , notermination = def+ , autoproofs = def+ , nowarnings = def+ , trustinternals = def+ , nocaseexpand = def+ , strata = def+ , notruetypes = def+ , totality = def+ , noPrune = def+ , exactDC = def+ , cores = def+ , minPartSize = defaultMinPartSize+ , maxPartSize = defaultMaxPartSize+ , maxParams = defaultMaxParams+ , smtsolver = def+ , shortNames = def+ , shortErrors = def+ , cabalDir = def+ , ghcOptions = def+ , cFiles = def+ , eliminate = def+ , port = defaultPort+ , scrapeImports = False+ , scrapeUsedImports = False+ , elimStats = False+ }+++------------------------------------------------------------------------+-- | Exit Function -----------------------------------------------------+------------------------------------------------------------------------++------------------------------------------------------------------------+exitWithResult :: Config -> FilePath -> Output Doc -> IO (Output Doc)+------------------------------------------------------------------------+exitWithResult cfg target out+ = do {-# SCC "annotate" #-} annotate cfg target out+ donePhase Loud "annotate"+ writeCheckVars $ o_vars out+ cr <- resultWithContext r+ writeResult cfg (colorResult r) cr+ writeFile (extFileName Result target) (showFix cr)+ return $ out { o_result = r }+ where+ r = o_result out `addErrors` o_errors out+++resultWithContext :: ErrorResult -> IO (FixResult CError)+resultWithContext = mapM errorWithContext+++writeCheckVars Nothing = return ()+writeCheckVars (Just []) = colorPhaseLn Loud "Checked Binders: None" ""+writeCheckVars (Just ns) = colorPhaseLn Loud "Checked Binders:" "" >> forM_ ns (putStrLn . symbolString . dropModuleNames . symbol)++type CError = CtxError Doc -- SpecType++writeResult :: Config -> Moods -> FixResult CError -> IO ()+writeResult cfg c = mapM_ (writeDoc c) . zip [0..] . resDocs tidy+ where+ tidy = if shortErrors cfg then Lossy else Full+ writeDoc c (i, d) = writeBlock c i $ lines $ render d+ writeBlock _ _ [] = return ()+ writeBlock c 0 ss = forM_ ss (colorPhaseLn c "")+ writeBlock _ _ ss = forM_ ("\n" : ss) putStrLn+++resDocs :: Tidy -> FixResult CError -> [Doc]+resDocs _ Safe = [text "RESULT: SAFE"]+resDocs k (Crash xs s) = text "RESULT: ERROR" : text s : pprManyOrdered k "" (errToFCrash <$> xs)+resDocs k (Unsafe xs) = text "RESULT: UNSAFE" : pprManyOrdered k "" (nub xs)++errToFCrash :: CtxError a -> CtxError a+errToFCrash ce = ce { ctErr = tx $ ctErr ce}+ where+ tx (ErrSubType l m g t t') = ErrFCrash l m g t t'+ tx e = e++{-+ TODO: Never used, do I need to exist?+reportUrl = text "Please submit a bug report at: https://github.com/ucsd-progsys/liquidhaskell" -}+++addErrors r [] = r+addErrors Safe errs = Unsafe errs+addErrors (Unsafe xs) errs = Unsafe (xs ++ errs)+addErrors r _ = r++instance Fixpoint (FixResult CError) where+ toFix = vcat . resDocs Full
+ src/Language/Haskell/Liquid/UX/Config.hs view
@@ -0,0 +1,75 @@+-----------------------------------------------------------------------------+-- | Command Line Config Options --------------------------------------------+-----------------------------------------------------------------------------+++{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE DeriveGeneric #-}++module Language.Haskell.Liquid.UX.Config (++ -- * Configuration Options+ Config (..)+ , HasConfig (..)+ , hasOpt+ ) where++import Prelude hiding (error)++import Data.Serialize ( Serialize )+import Language.Fixpoint.Types.Config hiding (Config)+import Data.Typeable (Typeable)+import Data.Generics (Data)+import GHC.Generics++-- NOTE: adding strictness annotations breaks the help message+data Config = Config {+ files :: [FilePath] -- ^ source files to check+ , idirs :: [FilePath] -- ^ path to directory for including specs+ , newcheck :: Bool -- ^ new liquid-fixpoint sort check+ , diffcheck :: Bool -- ^ check subset of binders modified (+ dependencies) since last check+ , linear :: Bool -- ^ uninterpreted integer multiplication and division+ , higherorder :: Bool -- ^ allow higher order binders into the logic+ , fullcheck :: Bool -- ^ check all binders (overrides diffcheck)+ , saveQuery :: Bool -- ^ save fixpoint query+ , binders :: [String] -- ^ set of binders to check+ , noCheckUnknown :: Bool -- ^ whether to complain about specifications for unexported and unused values+ , notermination :: Bool -- ^ disable termination check+ , autoproofs :: Bool -- ^ automatically construct proofs from axioms+ , nowarnings :: Bool -- ^ disable warnings output (only show errors)+ , trustinternals :: Bool -- ^ type all internal variables with true+ , nocaseexpand :: Bool -- ^ disable case expand+ , strata :: Bool -- ^ enable strata analysis+ , notruetypes :: Bool -- ^ disable truing top level types+ , totality :: Bool -- ^ check totality in definitions+ , noPrune :: Bool -- ^ disable prunning unsorted Refinements+ , cores :: Maybe Int -- ^ number of cores used to solve constraints+ , minPartSize :: Int -- ^ Minimum size of a partition+ , maxPartSize :: Int -- ^ Maximum size of a partition. Overrides minPartSize+ , maxParams :: Int -- ^ the maximum number of parameters to accept when mining qualifiers+ , smtsolver :: Maybe SMTSolver -- ^ name of smtsolver to use [default: try z3, cvc4, mathsat in order]+ , shortNames :: Bool -- ^ drop module qualifers from pretty-printed names.+ , shortErrors :: Bool -- ^ don't show subtyping errors and contexts.+ , cabalDir :: Bool -- ^ find and use .cabal file to include paths to sources for imported modules+ , ghcOptions :: [String] -- ^ command-line options to pass to GHC+ , cFiles :: [String] -- ^ .c files to compile and link against (for GHC)+ , eliminate :: Bool+ , port :: Int -- ^ port at which lhi should listen+ , exactDC :: Bool -- ^ Automatically generate singleton types for data constructors+ , scrapeImports :: Bool -- ^ scrape qualifiers from imported specifications+ , scrapeUsedImports :: Bool -- ^ scrape qualifiers from used, imported specifications+ , elimStats :: Bool -- ^ print eliminate stats+ } deriving (Generic, Data, Typeable, Show, Eq)++instance Serialize SMTSolver+instance Serialize Config+++class HasConfig t where+ getConfig :: t -> Config++hasOpt :: HasConfig t => t -> (Config -> Bool) -> Bool+hasOpt t f = f (getConfig t)++instance HasConfig Config where+ getConfig = id
+ src/Language/Haskell/Liquid/UX/DiffCheck.hs view
@@ -0,0 +1,488 @@+-- | This module contains the code for Incremental checking, which finds the+-- part of a target file (the subset of the @[CoreBind]@ that have been+-- modified since it was last checked, as determined by a diff against+-- a saved version of the file.++{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}++module Language.Haskell.Liquid.UX.DiffCheck (++ -- * Changed binders + Unchanged Errors+ DiffCheck (..)++ -- * Use previously saved info to generate DiffCheck target+ , slice++ -- * Use target binders to generate DiffCheck target+ , thin++ -- * Save current information for next time+ , saveResult++ )+ where++import Prelude hiding (error)++import Data.Aeson+import qualified Data.Text as T+import Data.Algorithm.Diff++import Data.Maybe (listToMaybe, mapMaybe, fromMaybe)+import Data.Hashable+import qualified Data.IntervalMap.FingerTree as IM+import CoreSyn hiding (sourceName)+import Name+import SrcLoc hiding (Located)+import Var+import qualified Data.HashSet as S+import qualified Data.HashMap.Strict as M+import qualified Data.List as L+import System.Directory (copyFile, doesFileExist)+import Language.Fixpoint.Types (FixResult (..), Located (..))+import Language.Fixpoint.Utils.Files+import Language.Haskell.Liquid.Types (ErrorResult, SpecType, GhcSpec (..), AnnInfo (..), DataConP (..), Output (..))+import Language.Haskell.Liquid.Misc (mkGraph)+import Language.Haskell.Liquid.GHC.Misc+import Language.Haskell.Liquid.Types.Visitors+import Language.Haskell.Liquid.UX.Errors ()+import Text.Parsec.Pos (sourceName, sourceLine, sourceColumn, SourcePos, newPos)+import Text.PrettyPrint.HughesPJ (text, render, Doc)+import Language.Haskell.Liquid.Types.Errors++import qualified Data.ByteString as B+import qualified Data.ByteString.Lazy as LB+++-------------------------------------------------------------------------+-- Data Types -----------------------------------------------------------+-------------------------------------------------------------------------++-- | Main type of value returned for diff-check.+data DiffCheck = DC { newBinds :: [CoreBind]+ , oldOutput :: !(Output Doc)+ , newSpec :: !GhcSpec+ }++-- | Variable definitions+data Def = D { start :: Int -- ^ line at which binder definition starts+ , end :: Int -- ^ line at which binder definition ends+ , binder :: Var -- ^ name of binder+ }+ deriving (Eq, Ord)++-- | Variable dependencies "call-graph"+type Deps = M.HashMap Var (S.HashSet Var)++-- | Map from saved-line-num ---> current-line-num+type LMap = IM.IntervalMap Int Int++-- | Intervals of line numbers that have been re-checked+type ChkItv = IM.IntervalMap Int ()++instance Show Def where+ show (D i j x) = showPpr x ++ " start: " ++ show i ++ " end: " ++ show j++++-------------------------------------------------------------------------+-- | `slice` returns a subset of the @[CoreBind]@ of the input `target`+-- file which correspond to top-level binders whose code has changed+-- and their transitive dependencies.+-------------------------------------------------------------------------+slice :: FilePath -> [CoreBind] -> GhcSpec -> IO (Maybe DiffCheck)+-------------------------------------------------------------------------+slice target cbs sp = ifM (doesFileExist savedFile)+ doDiffCheck+ (return Nothing)+ where+ savedFile = extFileName Saved target+ doDiffCheck = sliceSaved target savedFile cbs sp++sliceSaved :: FilePath -> FilePath -> [CoreBind] -> GhcSpec -> IO (Maybe DiffCheck)+sliceSaved target savedFile coreBinds spec+ = do (is, lm) <- lineDiff target savedFile+ result <- loadResult target+ return $ sliceSaved' is lm (DC coreBinds result spec)++sliceSaved' :: [Int] -> LMap -> DiffCheck -> Maybe DiffCheck+sliceSaved' is lm (DC coreBinds result spec)+ | globalDiff is spec = Nothing+ | otherwise = Just $ DC cbs' res' sp'+ where+ cbs' = thinWith sigs coreBinds $ diffVars is dfs+ sigs = S.fromList $ M.keys sigm+ sigm = sigVars is spec+ res' = adjustOutput lm cm result+ cm = checkedItv chDfs+ dfs = coreDefs coreBinds ++ specDefs spec+ chDfs = coreDefs cbs'+ sp' = assumeSpec sigm spec++-- Add the specified signatures for vars-with-preserved-sigs,+-- whose bodies have been pruned from [CoreBind] into the "assumes"+assumeSpec :: M.HashMap Var (Located SpecType) -> GhcSpec -> GhcSpec+assumeSpec sigm sp = sp { asmSigs = M.toList $ M.union sigm assm }+ where+ assm = M.fromList $ asmSigs sp+ -- sigm' = trace ("INCCHECK: sigm = " ++ show zs) sigm+ -- zs = M.keys sigm++diffVars :: [Int] -> [Def] -> [Var]+diffVars ls defs' = -- tracePpr ("INCCHECK: diffVars lines = " ++ show ls ++ " defs= " ++ show defs) $+ go (L.sort ls) defs+ where+ defs = L.sort defs'+ go _ [] = []+ go [] _ = []+ go (i:is) (d:ds)+ | i < start d = go is (d:ds)+ | i > end d = go (i:is) ds+ | otherwise = binder d : go (i:is) ds++sigVars :: [Int] -> GhcSpec -> M.HashMap Var (Located SpecType)+sigVars ls sp = M.fromList $ filter (ok . snd) $ specSigs sp+ where+ ok = not . isDiff ls++globalDiff :: [Int] -> GhcSpec -> Bool+globalDiff lines spec = measDiff || invsDiff || dconsDiff+ where+ measDiff = any (isDiff lines) (snd <$> meas spec)+ invsDiff = any (isDiff lines) (invariants spec)+ dconsDiff = any (isDiff lines) (dloc . snd <$> dconsP spec)+ dloc dc = Loc (dc_loc dc) (dc_locE dc) ()++isDiff :: [Int] -> Located a -> Bool+isDiff lines x = any hits lines+ where+ hits i = line x <= i && i <= lineE x++-------------------------------------------------------------------------+-- | @thin@ returns a subset of the @[CoreBind]@ given which correspond+-- to those binders that depend on any of the @Var@s provided.+-------------------------------------------------------------------------+thin :: [CoreBind] -> [Var] -> [CoreBind]+-------------------------------------------------------------------------+thin = thinWith S.empty++thinWith :: S.HashSet Var -> [CoreBind] -> [Var] -> [CoreBind]+thinWith sigs cbs xs = filterBinds cbs ys+ where+ ys = calls `S.union` calledBy+ calls = txClosure (coreDeps cbs) sigs (S.fromList xs)+ calledBy = dependsOn (coreDeps cbs) xs++coreDeps :: [CoreBind] -> Deps+coreDeps bs = mkGraph $ calls ++ calls'+ where+ calls = concatMap deps bs+ calls' = [(y, x) | (x, y) <- calls]+ deps b = [(x, y) | x <- bindersOf b+ , y <- freeVars S.empty b]+-- Given a call graph, and a list of vars, this function checks all functions+-- to see if they call any of the functions in the vars list. If any do, then+-- they must also be rechecked.+dependsOn :: Deps -> [Var] -> S.HashSet Var+dependsOn cg vars = S.fromList results+ where+ preds = map S.member vars+ filteredMaps = M.filter <$> preds <*> pure cg+ results = map fst $ M.toList $ M.unions filteredMaps++txClosure :: Deps -> S.HashSet Var -> S.HashSet Var -> S.HashSet Var+txClosure d sigs xs = go S.empty xs+ where+ next = S.unions . fmap deps . S.toList+ deps x = M.lookupDefault S.empty x d+ go seen new+ | S.null new = seen+ | otherwise = let seen' = S.union seen new+ new' = next new `S.difference` seen'+ new'' = new' `S.difference` sigs+ in go seen' new''++++-------------------------------------------------------------------------+filterBinds :: [CoreBind] -> S.HashSet Var -> [CoreBind]+-------------------------------------------------------------------------+filterBinds cbs ys = filter f cbs+ where+ f (NonRec x _) = x `S.member` ys+ f (Rec xes) = any (`S.member` ys) $ fst <$> xes+++-------------------------------------------------------------------------+specDefs :: GhcSpec -> [Def]+-------------------------------------------------------------------------+specDefs = map def . specSigs+ where+ def (x, t) = D (line t) (lineE t) x++specSigs :: GhcSpec -> [(Var, Located SpecType)]+specSigs sp = tySigs sp ++ asmSigs sp ++ ctors sp++-------------------------------------------------------------------------+coreDefs :: [CoreBind] -> [Def]+-------------------------------------------------------------------------+coreDefs cbs = L.sort [D l l' x | b <- cbs+ , x <- bindersOf b+ , isGoodSrcSpan (getSrcSpan x)+ , (l, l') <- coreDef b]+coreDef b = meetSpans b eSp vSp+ where+ eSp = lineSpan b $ catSpans b $ bindSpans b+ vSp = lineSpan b $ catSpans b $ getSrcSpan <$> bindersOf b+++-------------------------------------------------------------------------+-- | `meetSpans` cuts off the start-line to be no less than the line at which+-- the binder is defined. Without this, i.e. if we ONLY use the ticks and+-- spans appearing inside the definition of the binder (i.e. just `eSp`)+-- then the generated span can be WAY before the actual definition binder,+-- possibly due to GHC INLINE pragmas or dictionaries OR ...+-- for an example: see the "INCCHECK: Def" generated by+-- liquid -d benchmarks/bytestring-0.9.2.1/Data/ByteString.hs+-- where `spanEnd` is a single line function around 1092 but where+-- the generated span starts mysteriously at 222 where Data.List is imported.++meetSpans _ Nothing _+ = []+meetSpans _ (Just (l,l')) Nothing+ = [(l, l')]+meetSpans _ (Just (l,l')) (Just (m,_))+ = [(max l m, l')]++lineSpan _ (RealSrcSpan sp) = Just (srcSpanStartLine sp, srcSpanEndLine sp)+lineSpan _ _ = Nothing++catSpans b [] = panic Nothing $ "DIFFCHECK: catSpans: no spans found for " ++ showPpr b+catSpans b xs = foldr combineSrcSpans noSrcSpan [x | x@(RealSrcSpan z) <- xs, bindFile b == srcSpanFile z]++bindFile (NonRec x _) = varFile x+bindFile (Rec xes) = varFile $ fst $ head xes++varFile b = case getSrcSpan b of+ RealSrcSpan z -> srcSpanFile z+ _ -> panic Nothing $ "DIFFCHECK: getFile: no file found for: " ++ showPpr b+++bindSpans (NonRec x e) = getSrcSpan x : exprSpans e+bindSpans (Rec xes) = map getSrcSpan xs ++ concatMap exprSpans es+ where+ (xs, es) = unzip xes++exprSpans (Tick t e)+ | isJunkSpan sp = exprSpans e+ | otherwise = [sp]+ where+ sp = tickSrcSpan t++exprSpans (Var x) = [getSrcSpan x]+exprSpans (Lam x e) = getSrcSpan x : exprSpans e+exprSpans (App e a) = exprSpans e ++ exprSpans a+exprSpans (Let b e) = bindSpans b ++ exprSpans e+exprSpans (Cast e _) = exprSpans e+exprSpans (Case e x _ cs) = getSrcSpan x : exprSpans e ++ concatMap altSpans cs+exprSpans _ = []++altSpans (_, xs, e) = map getSrcSpan xs ++ exprSpans e++isJunkSpan (RealSrcSpan _) = False+isJunkSpan _ = True++-------------------------------------------------------------------------+-- | Diff Interface -----------------------------------------------------+-------------------------------------------------------------------------+++-- | `lineDiff new old` compares the contents of `src` with `dst`+-- and returns the lines of `src` that are different.+-------------------------------------------------------------------------+lineDiff :: FilePath -> FilePath -> IO ([Int], LMap)+-------------------------------------------------------------------------+lineDiff new old = lineDiff' <$> getLines new <*> getLines old+ where+ getLines = fmap lines . readFile++lineDiff' :: [String] -> [String] -> ([Int], LMap)+lineDiff' new old = (changedLines, lm)+ where+ changedLines = diffLines 1 diffLineCount+ lm = foldr setShift IM.empty $ diffShifts diffLineCount+ diffLineCount = fmap length <$> getGroupedDiff new old++-- | Identifies lines that have changed+diffLines :: Int -- ^ Starting line+ -> [Diff Int] -- ^ List of lengths of diffs+ -> [Int] -- ^ List of changed line numbers+diffLines _ [] = []+diffLines curr (Both lnsUnchgd _ : d) = diffLines toSkip d+ where toSkip = curr + lnsUnchgd+diffLines curr (First lnsChgd : d) = [curr..(toTake-1)] ++ diffLines toTake d+ where toTake = curr + lnsChgd+diffLines curr (_ : d) = diffLines curr d++diffShifts :: [Diff Int] -> [(Int, Int, Int)]+diffShifts = go 1 1+ where+ go old new (Both n _ : d) = (old, old + n - 1, new - old) : go (old + n)+ (new + n)+ d+ go old new (Second n : d) = go (old + n) new d+ go old new (First n : d) = go old (new + n) d+ go _ _ [] = []++instance Functor Diff where+ fmap f (First x) = First (f x)+ fmap f (Second x) = Second (f x)+ fmap f (Both x y) = Both (f x) (f y)++-- | @save@ creates an .saved version of the @target@ file, which will be+-- used to find what has changed the /next time/ @target@ is checked.+-------------------------------------------------------------------------+saveResult :: FilePath -> Output Doc -> IO ()+-------------------------------------------------------------------------+saveResult target res+ = do copyFile target saveF+ B.writeFile errF $ LB.toStrict $ encode res+ where+ saveF = extFileName Saved target+ errF = extFileName Cache target++-------------------------------------------------------------------------+loadResult :: FilePath -> IO (Output Doc)+-------------------------------------------------------------------------+loadResult f = ifM (doesFileExist jsonF) out (return mempty)+ where+ jsonF = extFileName Cache f+ out = (fromMaybe mempty . decode . LB.fromStrict) <$> B.readFile jsonF++-------------------------------------------------------------------------+adjustOutput :: LMap -> ChkItv -> Output Doc -> Output Doc+-------------------------------------------------------------------------+adjustOutput lm cm o = mempty { o_types = adjustTypes lm cm (o_types o) }+ { o_result = adjustResult lm cm (o_result o) }++adjustTypes :: LMap -> ChkItv -> AnnInfo a -> AnnInfo a+adjustTypes lm cm (AI m) = AI $ M.fromList+ [(sp', v) | (sp, v) <- M.toList m+ , Just sp' <- [adjustSrcSpan lm cm sp]]++adjustResult :: LMap -> ChkItv -> ErrorResult -> ErrorResult+adjustResult lm cm (Unsafe es) = errorsResult Unsafe $ adjustErrors lm cm es+adjustResult lm cm (Crash es z) = errorsResult (`Crash` z) $ adjustErrors lm cm es+adjustResult _ _ r = r++errorsResult :: ([a] -> FixResult b) -> [a] -> FixResult b+errorsResult _ [] = Safe+errorsResult f es = f es++adjustErrors :: LMap -> ChkItv -> [TError a] -> [TError a]+adjustErrors lm cm = mapMaybe adjustError+ where+ adjustError (ErrSaved sp m) = (`ErrSaved` m) <$> adjustSrcSpan lm cm sp+ adjustError e = Just e++-------------------------------------------------------------------------+adjustSrcSpan :: LMap -> ChkItv -> SrcSpan -> Maybe SrcSpan+-------------------------------------------------------------------------+adjustSrcSpan lm cm sp+ = do sp' <- adjustSpan lm sp+ if isCheckedSpan cm sp'+ then Nothing+ else Just sp'++isCheckedSpan cm (RealSrcSpan sp) = isCheckedRealSpan cm sp+isCheckedSpan _ _ = False+isCheckedRealSpan cm = not . null . (`IM.search` cm) . srcSpanStartLine++adjustSpan lm (RealSrcSpan rsp) = RealSrcSpan <$> adjustReal lm rsp+adjustSpan _ sp = Just sp+adjustReal lm rsp+ | Just δ <- getShift l1 lm = Just $ realSrcSpan f (l1 + δ) c1 (l2 + δ) c2+ | otherwise = Nothing+ where+ (f, l1, c1, l2, c2) = unpackRealSrcSpan rsp+ ++-- | @getShift lm old@ returns @Just δ@ if the line number @old@ shifts by @δ@+-- in the diff and returns @Nothing@ otherwise.+getShift :: Int -> LMap -> Maybe Int+getShift old = fmap snd . listToMaybe . IM.search old++-- | @setShift (lo, hi, δ) lm@ updates the interval map @lm@ appropriately+setShift :: (Int, Int, Int) -> LMap -> LMap+setShift (l1, l2, δ) = IM.insert (IM.Interval l1 l2) δ+++checkedItv :: [Def] -> ChkItv+checkedItv chDefs = foldr (`IM.insert` ()) IM.empty is+ where+ is = [IM.Interval l1 l2 | D l1 l2 _ <- chDefs]+++-------------------------------------------------------------------------+-- | Aeson instances ----------------------------------------------------+-------------------------------------------------------------------------++instance ToJSON SourcePos where+ toJSON p = object [ "sourceName" .= f+ , "sourceLine" .= l+ , "sourceColumn" .= c+ ]+ where+ f = sourceName p+ l = sourceLine p+ c = sourceColumn p++instance FromJSON SourcePos where+ parseJSON (Object v) = newPos <$> v .: "sourceName"+ <*> v .: "sourceLine"+ <*> v .: "sourceColumn"+ parseJSON _ = mempty++instance ToJSON ErrorResult where+ toJSON = genericToJSON defaultOptions+ toEncoding = genericToEncoding defaultOptions+instance FromJSON ErrorResult++instance ToJSON Doc where+ toJSON = String . T.pack . render++instance FromJSON Doc where+ parseJSON (String s) = return $ text $ T.unpack s+ parseJSON _ = mempty++instance (ToJSON k, ToJSON v) => ToJSON (M.HashMap k v) where+ toJSON = toJSON . M.toList++instance (Eq k, Hashable k, FromJSON k, FromJSON v) => FromJSON (M.HashMap k v) where+ parseJSON = fmap M.fromList . parseJSON++instance ToJSON a => ToJSON (AnnInfo a) where+ toJSON = genericToJSON defaultOptions+ toEncoding = genericToEncoding defaultOptions+instance FromJSON a => FromJSON (AnnInfo a)++instance ToJSON (Output Doc) where+ toJSON = genericToJSON defaultOptions+ toEncoding = genericToEncoding defaultOptions+instance FromJSON (Output Doc)+++line :: Located a -> Int+line = sourceLine . loc++lineE :: Located a -> Int+lineE = sourceLine . locE++-------------------------------------------------------------------------+---- Helper functions ---------------------------------------------------+-------------------------------------------------------------------------++ifM :: (Monad m) => m Bool -> m b -> m b -> m b+ifM b x y = b >>= \z -> if z then x else y
+ src/Language/Haskell/Liquid/UX/Errors.hs view
@@ -0,0 +1,108 @@+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE OverloadedStrings #-}++-- | This module contains the functions related to @Error@ type,+-- in particular, to @tidyError@ using a solution, and @pprint@ errors.++-- TODO: move this into Tidy.++module Language.Haskell.Liquid.UX.Errors+ ( -- * Cleanup an Error+ tidyError+ ) where++import Control.Arrow (second)+import qualified Data.HashMap.Strict as M+import qualified Data.HashSet as S+import Data.Hashable+import Data.Maybe (maybeToList)+import Language.Fixpoint.Types hiding (Error, SrcSpan, shiftVV)+import Language.Haskell.Liquid.Types.RefType+import Language.Haskell.Liquid.Transforms.Simplify+import Language.Haskell.Liquid.UX.Tidy+import Language.Haskell.Liquid.Types+import Language.Haskell.Liquid.Misc (single)++type Ctx = M.HashMap Symbol SpecType++------------------------------------------------------------------------+tidyError :: FixSolution -> Error -> Error+------------------------------------------------------------------------+tidyError sol+ = fmap (tidySpecType Full)+ . tidyErrContext sol+ . applySolution sol++tidyErrContext :: FixSolution -> Error -> Error+tidyErrContext _ e@(ErrSubType {})+ = e { ctx = c', tact = subst θ tA, texp = subst θ tE }+ where+ (θ, c') = tidyCtx xs $ ctx e+ xs = syms tA ++ syms tE+ tA = tact e+ tE = texp e++tidyErrContext _ e@(ErrAssType {})+ = e { ctx = c', cond = subst θ p }+ where+ m = ctx e+ (θ, c') = tidyCtx xs m+ xs = syms p+ p = cond e++tidyErrContext _ e+ = e++--------------------------------------------------------------------------------+tidyCtx :: [Symbol] -> Ctx -> (Subst, Ctx)+--------------------------------------------------------------------------------+tidyCtx xs m = (θ, M.fromList yts)+ where+ yts = [tBind x t | (x, t) <- xts]+ (θ, xts) = tidyTemps $ second stripReft <$> tidyREnv xs m+ tBind x t = (x', shiftVV t x') where x' = tidySymbol x+++stripReft :: SpecType -> SpecType+stripReft t = maybe t' (strengthen t') ro+ where+ (t', ro) = stripRType t++stripRType :: SpecType -> (SpecType, Maybe RReft)+stripRType st = (t', ro)+ where+ t' = fmap (const (uTop mempty)) t+ ro = stripRTypeBase t+ t = simplifyBounds st++tidyREnv :: [Symbol] -> Ctx -> [(Symbol, SpecType)]+tidyREnv xs m = [(x, t) | x <- xs', t <- maybeToList (M.lookup x m), ok t]+ where+ xs' = expandFix deps xs+ deps y = maybe [] (syms . rTypeReft) (M.lookup y m)+ ok = not . isFunTy++expandFix :: (Eq a, Hashable a) => (a -> [a]) -> [a] -> [a]+expandFix f = S.toList . go S.empty+ where+ go seen [] = seen+ go seen (x:xs)+ | x `S.member` seen = go seen xs+ | otherwise = go (S.insert x seen) (f x ++ xs)++tidyTemps :: (Subable t) => [(Symbol, t)] -> (Subst, [(Symbol, t)])+tidyTemps xts = (θ, [(txB x, txTy t) | (x, t) <- xts])+ where+ txB x = M.lookupDefault x x m+ txTy = subst θ+ m = M.fromList yzs+ θ = mkSubst [(y, EVar z) | (y, z) <- yzs]+ yzs = zip ys niceTemps+ ys = [ x | (x,_) <- xts, isTmpSymbol x]++niceTemps :: [Symbol]+niceTemps = mkSymbol <$> xs ++ ys+ where+ mkSymbol = symbol . ('?' :)+ xs = single <$> ['a' .. 'z']+ ys = ("a" ++) <$> [show n | n <- [0 ..]]
+ src/Language/Haskell/Liquid/UX/Tidy.hs view
@@ -0,0 +1,228 @@++{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE FlexibleInstances #-}++---------------------------------------------------------------------+-- | This module contains functions for cleaning up types before+-- they are rendered, e.g. in error messages or annoations,+-- and also some PPrint instances that rely upon tidying.+---------------------------------------------------------------------++module Language.Haskell.Liquid.UX.Tidy (++ -- * Tidying functions+ tidySpecType+ , tidySymbol++ -- * Tidyness tests+ , isTmpSymbol++ -- * Panic and Exit+ , panicError++ -- * Final result+ , Result (..)++ -- * MOVE TO TYPES+ , cinfoError+ ) where++import Prelude hiding (error)++import qualified Data.HashMap.Strict as M+import qualified Data.HashSet as S+import qualified Data.List as L+import qualified Data.Text as T+++import qualified Control.Exception as Ex++import Language.Haskell.Liquid.GHC.Misc (showPpr, stringTyVar)++import Language.Fixpoint.Types hiding (Result, SrcSpan, Error)+import Language.Haskell.Liquid.Types+import Language.Haskell.Liquid.Types.RefType (rVar, subsTyVars_meet)+import Language.Haskell.Liquid.Types.PrettyPrint++++++import Data.Generics (everywhere, mkT)+import Text.PrettyPrint.HughesPJ+++------------------------------------------------------------------------+-- | Converting Results To Answers -------------------------------------+------------------------------------------------------------------------++class Result a where+ result :: a -> FixResult UserError++instance Result UserError where+ result e = Crash [e] ""++instance Result [Error] where+ result es = Crash (e2u <$> es) ""++instance Result Error where+ result e = result [e] -- Crash [pprint e] ""++instance Result (FixResult Cinfo) where+ result = fmap (e2u . cinfoError)++e2u :: Error -> UserError+e2u = fmap ppSpecTypeErr++-- TODO: move to Types.hs+cinfoError :: Cinfo -> Error+cinfoError (Ci _ (Just e)) = e+cinfoError (Ci l _) = ErrOther l (text $ "Cinfo:" ++ showPpr l)++-------------------------------------------------------------------------+isTmpSymbol :: Symbol -> Bool+-------------------------------------------------------------------------+isTmpSymbol x = any (`isPrefixOfSym` x) [anfPrefix, tempPrefix, "ds_"]++-------------------------------------------------------------------------+tidySpecType :: Tidy -> SpecType -> SpecType+-------------------------------------------------------------------------+tidySpecType k = tidyValueVars+ . tidyDSymbols+ . tidySymbols+ . tidyLocalRefas k+ . tidyFunBinds+ . tidyTyVars++tidyValueVars :: SpecType -> SpecType+tidyValueVars = mapReft $ \u -> u { ur_reft = tidyVV $ ur_reft u }++tidyVV r@(Reft (va,_))+ | isJunk va = shiftVV r v'+ | otherwise = r+ where+ v' = if v `elem` xs then symbol ("v'" :: T.Text) else v+ v = symbol ("v" :: T.Text)+ xs = syms r+ isJunk = isPrefixOfSym "x"++tidySymbols :: SpecType -> SpecType+tidySymbols t = substa tidySymbol $ mapBind dropBind t+ where+ xs = S.fromList (syms t)+ dropBind x = if x `S.member` xs then tidySymbol x else nonSymbol+++tidyLocalRefas :: Tidy -> SpecType -> SpecType+tidyLocalRefas k = mapReft (txStrata . txReft' k)+ where+ txReft' Full = id+ txReft' Lossy = txReft+ txStrata (MkUReft r p l) = MkUReft r p (txStr l)+ txReft u = u { ur_reft = mapPredReft dropLocals $ ur_reft u }+ dropLocals = pAnd . filter (not . any isTmp . syms) . conjuncts+ isTmp x = any (`isPrefixOfSym` x) [anfPrefix, "ds_"]+ txStr = filter (not . isSVar)++tidyDSymbols :: SpecType -> SpecType+tidyDSymbols t = mapBind tx $ substa tx t+ where+ tx = bindersTx [x | x <- syms t, isTmp x]+ isTmp = (tempPrefix `isPrefixOfSym`)++tidyFunBinds :: SpecType -> SpecType+tidyFunBinds t = mapBind tx $ substa tx t+ where+ tx = bindersTx $ filter isTmpSymbol $ funBinds t++tidyTyVars :: SpecType -> SpecType+tidyTyVars t = subsTyVarsAll αβs t+ where+ αβs = zipWith (\α β -> (α, toRSort β, β)) αs βs+ αs = L.nub (tyVars t)+ βs = map (rVar . stringTyVar) pool+ pool = [[c] | c <- ['a'..'z']] ++ [ "t" ++ show i | i <- [1..]]+++bindersTx ds = \y -> M.lookupDefault y y m+ where+ m = M.fromList $ zip ds $ var <$> [1..]+ var = symbol . ('x' :) . show+++tyVars (RAllP _ t) = tyVars t+tyVars (RAllS _ t) = tyVars t+tyVars (RAllT α t) = α : tyVars t+tyVars (RFun _ t t' _) = tyVars t ++ tyVars t'+tyVars (RAppTy t t' _) = tyVars t ++ tyVars t'+tyVars (RApp _ ts _ _) = concatMap tyVars ts+tyVars (RVar α _) = [α]+tyVars (RAllE _ _ t) = tyVars t+tyVars (REx _ _ t) = tyVars t+tyVars (RExprArg _) = []+tyVars (RRTy _ _ _ t) = tyVars t+tyVars (RHole _) = []++subsTyVarsAll ats = go+ where+ abm = M.fromList [(a, b) | (a, _, RVar b _) <- ats]+ go (RAllT a t) = RAllT (M.lookupDefault a a abm) (go t)+ go t = subsTyVars_meet ats t+++funBinds (RAllT _ t) = funBinds t+funBinds (RAllP _ t) = funBinds t+funBinds (RAllS _ t) = funBinds t+funBinds (RFun b t1 t2 _) = b : funBinds t1 ++ funBinds t2+funBinds (RApp _ ts _ _) = concatMap funBinds ts+funBinds (RAllE b t1 t2) = b : funBinds t1 ++ funBinds t2+funBinds (REx b t1 t2) = b : funBinds t1 ++ funBinds t2+funBinds (RVar _ _) = []+funBinds (RRTy _ _ _ t) = funBinds t+funBinds (RAppTy t1 t2 _) = funBinds t1 ++ funBinds t2+funBinds (RExprArg _) = []+funBinds (RHole _) = []+++--------------------------------------------------------------------------------+-- | Show an Error, then crash+--------------------------------------------------------------------------------+panicError :: {-(?callStack :: CallStack) =>-} Error -> a+--------------------------------------------------------------------------------+panicError = Ex.throw++-- ^ This function is put in this module as+-- it depends on the Exception instance,+-- which depends on the PPrint instance,+-- which depends on tidySpecType.++--------------------------------------------------------------------------------+-- | Pretty Printing Error Messages --------------------------------------------+--------------------------------------------------------------------------------++-- | Need to put @PPrint Error@ instance here (instead of in Types),+-- as it depends on @PPrint SpecTypes@, which lives in this module.++instance PPrint (CtxError Doc) where+ pprintTidy k ce = ppError k (ctCtx ce) $ ctErr ce++instance PPrint (CtxError SpecType) where+ pprintTidy k ce = ppError k (ctCtx ce) $ ppSpecTypeErr <$> ctErr ce++instance PPrint Error where+ pprintTidy k = ppError k empty . fmap ppSpecTypeErr++ppSpecTypeErr :: SpecType -> Doc+ppSpecTypeErr = rtypeDoc Lossy+ . tidySpecType Lossy+ . fmap (everywhere (mkT noCasts))+ where+ noCasts (ECst x _) = x+ noCasts e = e++instance Show Error where+ show = showpp++instance Ex.Exception Error+instance Ex.Exception [Error]
− src/Language/Haskell/Liquid/Variance.hs
@@ -1,11 +0,0 @@-{-# LANGUAGE DeriveDataTypeable #-}--module Language.Haskell.Liquid.Variance (- Variance(..), VarianceInfo- ) where--import Data.Typeable-import Data.Data--type VarianceInfo = [Variance]-data Variance = Invariant | Bivariant | Contravariant | Covariant deriving (Data, Typeable, Show)
− src/Language/Haskell/Liquid/Visitors.hs
@@ -1,143 +0,0 @@-{-# LANGUAGE NoMonomorphismRestriction #-}-{-# LANGUAGE TypeSynonymInstances #-} -{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE TupleSections #-}-{-# LANGUAGE DeriveDataTypeable #-}-{-# LANGUAGE ScopedTypeVariables #-}---module Language.Haskell.Liquid.Visitors (- - -- * visitors - CBVisitable (..) -- ) where---import DataCon-import Literal-import CoreSyn--import Var--import Data.List (foldl', (\\), delete)--import qualified Data.HashSet as S-import Language.Fixpoint.Misc-import Language.Haskell.Liquid.GhcMisc ()------------------------------------------------------------------------------------------------------------------ A CoreBind Visitor ------------------------------------------------------------------------------------------------------------- TODO: syb-shrinkage--class CBVisitable a where- freeVars :: S.HashSet Var -> a -> [Var]- readVars :: a -> [Var] - letVars :: a -> [Var] - literals :: a -> [Literal]--instance CBVisitable [CoreBind] where- freeVars env cbs = (sortNub xs) \\ ys - where xs = concatMap (freeVars env) cbs - ys = concatMap bindings cbs- - readVars = concatMap readVars- letVars = concatMap letVars - literals = concatMap literals--instance CBVisitable CoreBind where- freeVars env (NonRec x e) = freeVars (extendEnv env [x]) e - freeVars env (Rec xes) = concatMap (freeVars env') es - where (xs,es) = unzip xes - env' = extendEnv env xs -- readVars (NonRec _ e) = readVars e- readVars (Rec xes) = concat [x `delete` nubReadVars e |(x, e) <- xes]- where nubReadVars = sortNub . readVars-- letVars (NonRec x e) = x : letVars e- letVars (Rec xes) = xs ++ concatMap letVars es- where - (xs, es) = unzip xes-- literals (NonRec _ e) = literals e- literals (Rec xes) = concatMap literals $ map snd xes--instance CBVisitable (Expr Var) where- freeVars = exprFreeVars- readVars = exprReadVars- letVars = exprLetVars- literals = exprLiterals--exprFreeVars = go - where - go env (Var x) = if x `S.member` env then [] else [x] - go env (App e a) = (go env e) ++ (go env a)- go env (Lam x e) = go (extendEnv env [x]) e- go env (Let b e) = (freeVars env b) ++ (go (extendEnv env (bindings b)) e)- go env (Tick _ e) = go env e- go env (Cast e _) = go env e- go env (Case e x _ cs) = (go env e) ++ (concatMap (freeVars (extendEnv env [x])) cs) - go _ _ = []--exprReadVars = go- where- go (Var x) = [x]- go (App e a) = concatMap go [e, a] - go (Lam _ e) = go e- go (Let b e) = readVars b ++ go e - go (Tick _ e) = go e- go (Cast e _) = go e- go (Case e _ _ cs) = (go e) ++ (concatMap readVars cs) - go _ = []--exprLetVars = go- where- go (Var _) = []- go (App e a) = concatMap go [e, a] - go (Lam x e) = x : go e- go (Let b e) = letVars b ++ go e - go (Tick _ e) = go e- go (Cast e _) = go e- go (Case e x _ cs) = x : go e ++ concatMap letVars cs- go _ = []--exprLiterals = go- where- go (Lit l) = [l]- go (App e a) = concatMap go [e, a] - go (Let b e) = literals b ++ go e - go (Lam _ e) = go e- go (Tick _ e) = go e- go (Cast e _) = go e- go (Case e _ _ cs) = (go e) ++ (concatMap literals cs) - go _ = []---instance CBVisitable (Alt Var) where- freeVars env (a, xs, e) = freeVars env a ++ freeVars (extendEnv env xs) e- readVars (_,_, e) = readVars e- letVars (_,xs,e) = xs ++ letVars e- literals (c,_, e) = literals c ++ literals e---instance CBVisitable AltCon where- freeVars _ (DataAlt dc) = dataConImplicitIds dc- freeVars _ _ = []- readVars _ = []- letVars _ = []- literals (LitAlt l) = [l]- literals _ = []----extendEnv = foldl' (flip S.insert)--bindings (NonRec x _) - = [x]-bindings (Rec xes ) - = map fst xes
src/Language/Haskell/Liquid/WiredIn.hs view
@@ -1,33 +1,78 @@-{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE OverloadedStrings #-} -module Language.Haskell.Liquid.WiredIn where+module Language.Haskell.Liquid.WiredIn+ ( propType+ , propTyCon+ , hpropTyCon+ , pdVarReft+ , wiredTyCons, wiredDataCons+ , wiredSortedSyms + -- | Constants for automatic proofs+ , dictionaryVar, dictionaryTyVar, dictionaryBind+ , proofTyConName, combineProofsName+ ) where++import Prelude hiding (error)+ import Language.Haskell.Liquid.Types-import Language.Haskell.Liquid.RefType-import Language.Haskell.Liquid.GhcMisc-import Language.Haskell.Liquid.Variance+import Language.Haskell.Liquid.Misc (mapSnd)+import Language.Haskell.Liquid.Types.RefType+import Language.Haskell.Liquid.GHC.Misc+import Language.Haskell.Liquid.Types.Variance+import Language.Haskell.Liquid.Types.PredType -import Language.Fixpoint.Names (hpropConName, propConName)++ import Language.Fixpoint.Types-import Language.Fixpoint.Misc (mapSnd) import BasicTypes import DataCon import TyCon import TysWiredIn -import Data.Monoid-import Control.Applicative+import TypeRep+import CoreSyn +++wiredSortedSyms = [(pappSym n, pappSort n) | n <- [1..pappArity]]+ ----------------------------------------------------------------------- -- | LH Primitive TyCons ---------------------------------------------- ----------------------------------------------------------------------- +dictionaryVar = stringVar "tmp_dictionary_var" (ForAllTy dictionaryTyVar $ TyVarTy dictionaryTyVar)+dictionaryTyVar = stringTyVar "da"+dictionaryBind = Rec [(v, Lam a $ App (Var v) (Type $ TyVarTy a))]+ where+ v = dictionaryVar+ a = dictionaryTyVar++++-----------------------------------------------------------------------+-- | LH Primitive TyCons ----------------------------------------------+-----------------------------------------------------------------------+++combineProofsName :: String+combineProofsName = "combineProofs"++proofTyConName :: Symbol+proofTyConName = "Proof"+ propTyCon, hpropTyCon :: TyCon-propTyCon = symbolTyCon 'w' 24 propConName-hpropTyCon = symbolTyCon 'w' 24 hpropConName +{- ATTENTION: Uniques should be different when defining TyCons+ otherwise the TyCons are equal and they will all resolve to+ bool in fixpoint, as propTyCon is a bool+ -}++propTyCon = symbolTyCon 'w' 25 propConName+hpropTyCon = symbolTyCon 'w' 26 hpropConName+ ----------------------------------------------------------------------- -- | LH Primitive Types ---------------------------------------------- -----------------------------------------------------------------------@@ -35,8 +80,6 @@ propType :: Reftable r => RRType r propType = RApp (RTyCon propTyCon [] defaultTyConInfo) [] [] mempty -- -------------------------------------------------------------------- ------ Predicate Types for WiredIns -------------------------------- --------------------------------------------------------------------@@ -50,13 +93,12 @@ wiredTyDataCons :: ([(TyCon, TyConP)] , [(DataCon, Located DataConP)]) wiredTyDataCons = (concat tcs, mapSnd dummyLoc <$> concat dcs) where- (tcs, dcs) = unzip l- l = [listTyDataCons] ++ map tupleTyDataCons [2..maxArity]+ (tcs, dcs) = unzip $ listTyDataCons : map tupleTyDataCons [2..maxArity] listTyDataCons :: ([(TyCon, TyConP)] , [(DataCon, DataConP)])-listTyDataCons = ( [(c, TyConP [(RTV tyv)] [p] [] [Covariant] [Covariant] (Just fsize))]- , [(nilDataCon, DataConP l0 [(RTV tyv)] [p] [] [] [] lt l0)- , (consDataCon, DataConP l0 [(RTV tyv)] [p] [] [] cargs lt l0)])+listTyDataCons = ( [(c, TyConP [RTV tyv] [p] [] [Covariant] [Covariant] (Just fsize))]+ , [(nilDataCon, DataConP l0 [RTV tyv] [p] [] [] [] lt l0)+ , (consDataCon, DataConP l0 [RTV tyv] [p] [] [] cargs lt l0)]) where l0 = dummyPos "LH.Bare.listTyDataCons" c = listTyCon@@ -67,11 +109,11 @@ xs = "xsListSelector" p = PV "p" (PVProp t) (vv Nothing) [(t, fld, EVar fld)] px = pdVarReft $ PV "p" (PVProp t) (vv Nothing) [(t, fld, EVar x)]- lt = rApp c [xt] [RPropP [] $ pdVarReft p] mempty+ lt = rApp c [xt] [rPropP [] $ pdVarReft p] mempty xt = rVar tyv- xst = rApp c [RVar (RTV tyv) px] [RPropP [] $ pdVarReft p] mempty+ xst = rApp c [RVar (RTV tyv) px] [rPropP [] $ pdVarReft p] mempty cargs = [(xs, xst), (x, xt)]- fsize = \x -> EApp (dummyLoc "len") [EVar x]+ fsize z = mkEApp (dummyLoc "len") [EVar z] tupleTyDataCons :: Int -> ([(TyCon, TyConP)] , [(DataCon, DataConP)]) tupleTyDataCons n = ( [(c, TyConP (RTV <$> tyvs) ps [] tyvarinfo pdvarinfo Nothing)]@@ -87,25 +129,25 @@ flds = mks "fld_Tuple" fld = "fld_Tuple" x1:xs = mks ("x_Tuple" ++ show n)- ps = mkps pnames (ta:ts) ((fld, EVar fld):(zip flds (EVar <$>flds)))+ ps = mkps pnames (ta:ts) ((fld, EVar fld) : zip flds (EVar <$> flds)) ups = uPVar <$> ps- pxs = mkps pnames (ta:ts) ((fld, EVar x1):(zip flds (EVar <$> xs)))- lt = rApp c (rVar <$> tyvs) (RPropP [] . pdVarReft <$> ups) mempty+ pxs = mkps pnames (ta:ts) ((fld, EVar x1) : zip flds (EVar <$> xs))+ lt = rApp c (rVar <$> tyvs) (rPropP [] . pdVarReft <$> ups) mempty xts = zipWith (\v p -> RVar (RTV v) (pdVarReft p)) tvs pxs- cargs = reverse $ (x1, rVar tv) : (zip xs xts)+ cargs = reverse $ (x1, rVar tv) : zip xs xts pnames = mks_ "p" mks x = (\i -> symbol (x++ show i)) <$> [1..n] mks_ x = (\i -> symbol (x++ show i)) <$> [2..n] -pdVarReft = (\p -> U mempty p mempty) . pdVar+pdVarReft = (\p -> MkUReft mempty p mempty) . pdVar mkps ns (t:ts) ((f,x):fxs) = reverse $ mkps_ ns ts fxs [(t, f, x)] []-mkps _ _ _ = error "Bare : mkps"+mkps _ _ _ = panic Nothing "Bare : mkps" mkps_ [] _ _ _ ps = ps mkps_ (n:ns) (t:ts) ((f, x):xs) args ps = mkps_ ns ts xs (a:args) (p:ps) where p = PV n (PVProp t) (vv Nothing) args a = (t, f, x)-mkps_ _ _ _ _ _ = error "Bare : mkps_"+mkps_ _ _ _ _ _ = panic Nothing "Bare : mkps_"
− src/Language/Haskell/Liquid/World.hs
@@ -1,23 +0,0 @@--- | This module contains various functions for operating on the @World@ type defined in--- Language.Haskell.Liquid.Types--module Language.Haskell.Liquid.World (- -- * Empty world- empty- ) where--import Data.Monoid-import Language.Haskell.Liquid.Types-import Language.Fixpoint.Misc--empty :: World t-empty = World []--sepConj :: World t -> World t -> World t-sepConj = errorstar "TODO:EFFECTS"--instance Monoid (World t) where- mempty = empty- mappend w1 w2 = sepConj w1 w2--
+ src/Liquid.hs view
@@ -0,0 +1,5 @@+import Language.Haskell.Liquid.Liquid (liquid)+import System.Environment (getArgs)++main :: IO a+main = liquid =<< getArgs
+ tests/crash/Assume.hs view
@@ -0,0 +1,5 @@+module Assume where++{-@ assume incr :: Int -> {v : Int | v == x} @-}+incr :: Int -> Int+incr x = x + 1
+ tests/crash/Assume1.hs view
@@ -0,0 +1,15 @@+a :: Int+a = 0++{-@ assume b :: { b : Int | a < b } @-}+b :: Int+b = 1++{-@+f :: a : Int -> { b : Int | a < b } -> ()+@-}+f :: Int -> Int -> ()+f _ _ = ()++g :: ()+g = f a b
+ tests/crash/Ast.hs view
@@ -0,0 +1,61 @@+-- FAILING TEST: this test SHOULD FAIL BUT DOESN'T+-- issue #519++{-# LANGUAGE DeriveFunctor #-}+module Main where++data AstIndex = IxExpr | IxType++{-@ measure isExprIndex @-}+isExprIndex :: AstIndex -> Bool+isExprIndex IxExpr = True+isExprIndex _ = False++{-@ measure isTypeIndex @-}+isTypeIndex :: AstIndex -> Bool+isTypeIndex IxType = True+isTypeIndex _ = False++data AstF f = Lit Int AstIndex+ | Var String AstIndex+ | App f f+ | Paren f++{-@+ data AstF f <ix :: AstIndex -> Prop>+ = Lit Int (i :: AstIndex<ix>)+ | Var String (i :: AstIndex<ix>)+ | App (fn :: f) (arg :: f)+ | Paren (ast :: f)+ @-}++{-@ type AstFE = AstF <{\ix -> isExprIndex ix}> @-}+{-@ type AstFT = AstF <{\ix -> isTypeIndex ix}> @-}+++-- Now lets tie the knot!++newtype Fix f = In { out :: f (Fix f) }++type Ast = Fix AstF++{-@ type AstE = Fix AstFE @-}+{-@ type AstT = Fix AstFT @-}++{-@ astExpr :: AstE @-}+astExpr :: Ast+astExpr = In (Lit 10 IxExpr) ++{-@ astType :: AstT @-}+astType :: Ast +astType = In (Lit 10 IxType)++{-@ app :: forall <p :: AstIndex -> Prop>. Fix (AstF p) -> Fix (AstF p) -> Fix (AstF p) @-}+app f x = In $ App f x++{-@ id1 :: forall <p :: AstIndex -> Prop>. Fix (AstF p) -> Fix (AstF p) @-}+id1 :: Fix AstF -> Fix AstF+id1 z = z++{-@ wrong :: AstT @-}+wrong = id1 astExpr
tests/crash/CyclicExprAlias2.hs view
@@ -1,6 +1,6 @@ module Test3 () where -{-@ expression CyclicC1 Q = (CyclicC2 Q) / (CyclicC3 Q) @-}+{-@ expression CyclicC1 Q = (CyclicC2 Q) && (CyclicC3 Q) @-} {-@ expression CyclicC2 Q = CyclicC1 Q @-} {-@ expression CyclicC3 Q = CyclicC1 Q @-}
+ tests/crash/Qualif.hs view
@@ -0,0 +1,10 @@+module RG where+data RGRef a+{-@ measure tv :: RGRef a -> a @-}+{-@ qualif TERMINALVALUE(r:RGRef a): (tv r) @-}+++data A+data B++{-@ qualif Foo(x:A, y:B): (x == y) @-}
+ tests/crash/T649.hs view
@@ -0,0 +1,34 @@+module Blank where++import Data.Word+import GHC.Ptr++{-@ class measure sizeOf :: forall a . Ptr a -> Int @-}+{-@+instance measure sizeOf :: (Ptr Data.Word.Word16) -> Int+sizeOf (Ptr x) = 2+@-}+{-@+instance measure sizeOf :: (Ptr Data.Word.Word32) -> Int+sizeOf (Ptr y) = 4+@-}++{- measure sizeOf :: forall a . Ptr a -> Int @-}++{- invariant {v:Ptr Word16 | sizeOf v = 2} @-}+{- invariant {v:Ptr Word32 | sizeOf v = 4} @-}++{-@+bar :: { p : Ptr Word32 | plen p >= (sizeOf p) }+ -> ()+@-}+bar :: Ptr Word32 -> ()+bar (Ptr unused) = ()++{-@+qux :: { p : Ptr Word32 | plen p >= 0 }+ -> ()+@-}+qux :: Ptr Word32 -> ()+qux (Ptr addr) = let x = Ptr addr in bar x+
+ tests/crash/errmsg-dc-num.hs view
@@ -0,0 +1,6 @@+module Boo where++{-@ data T = C { fldX :: Int } @-}+++data T = C { fldX :: Int, fldY :: Int }
+ tests/crash/errmsg-dc-type.hs view
@@ -0,0 +1,5 @@+module Boo where++{-@ data T = C { fldX :: Int, fldY :: Bool } @-}++data T = C { fldX :: Int, fldY :: Int }
+ tests/crash/errmsg-mismatch.hs view
@@ -0,0 +1,5 @@+module Boo where++{-@ incr :: Int -> Bool @-}+incr :: Int -> Int +incr x = x + 1
+ tests/crash/issue594.hs view
@@ -0,0 +1,7 @@+module Boo where++{-@ data X <q :: Int -> Int -> Prop> = X (x0 :: Int) (x1 :: Int<q x0>) @-} +data X = X Int Int ++{-@ data T <p :: Int -> Int -> Int -> Int -> Prop> = C { x :: Int, y :: Int, z :: X<p x y> } @-}+data T = C { x :: Int, y :: Int, z :: X }
+ tests/crash/predparams.hs view
@@ -0,0 +1,10 @@++-- ISSUE: this "crashes" without a decent source location+-- You can fix this with the signature `ide :: forall <p :: a -> Prop>. a<p> -> a<p>`+-- but it would be nice to have an error message that pinpoints the location.+-- https://github.com/ucsd-progsys/liquidhaskell/issues/655++module Ide where++{-@ ide :: a<p> -> a<p> @-}+ide x = x
+ tests/neg/AbsApp.hs view
@@ -0,0 +1,16 @@+-- FAILING TEST: This should be rejected if we wish to disallow applying+-- concrete refinements to non-refined types (e.g. Int) where they are currently+-- silently dropped.+-- issue #519++module Main where++{-@ id2 :: forall <p :: Int -> Prop>. Int<p> -> Int<p> @-}+id2 :: Int -> Int+id2 x = x++{-@ type Neg = Int<{\x -> x < 0}> @-}++{-@ three :: Neg @-}+three = id2 3+
+ tests/neg/Ast.hs view
@@ -0,0 +1,54 @@+-- FAILING TEST: this test SHOULD FAIL BUT DOESN'T+-- issue #519++{-# LANGUAGE DeriveFunctor #-}+module Main where++data AstIndex = IxExpr | IxType++{-@ measure isExprIndex @-}+isExprIndex :: AstIndex -> Bool+isExprIndex IxExpr = True+isExprIndex _ = False++{-@ measure isTypeIndex @-}+isTypeIndex :: AstIndex -> Bool+isTypeIndex IxType = True+isTypeIndex _ = False++data AstF f = Lit Int AstIndex+ | Var String AstIndex+ | App f f+ | Paren f++{-@+ data AstF f <ix :: AstIndex -> Prop>+ = Lit Int (i :: AstIndex<ix>)+ | Var String (i :: AstIndex<ix>)+ | App (fn :: f) (arg :: f)+ | Paren (ast :: f)+ @-}++{-@ type AstFE = AstF <{\ix -> isExprIndex ix}> @-}+{-@ type AstFT = AstF <{\ix -> isTypeIndex ix}> @-}+++-- Now lets tie the knot!++newtype Fix f = In { out :: f (Fix f) }++type Ast = Fix AstF++{-@ type AstE = Fix AstFE @-}+{-@ type AstT = Fix AstFT @-}++{-@ astExpr :: Fix (AstF <{\ix -> isExprIndex ix}>) @-}+astExpr :: Ast+astExpr = undefined ++{-@ id1 :: forall <p :: AstIndex -> Prop>. Fix (AstF <p>) -> Fix (AstF <p>) @-}+id1 :: Fix AstF -> Fix AstF+id1 z = z++{-@ wrong :: AstT @-}+wrong = id1 astExpr
+ tests/neg/BadHMeas.hs view
@@ -0,0 +1,5 @@++{-@ measure foo @-}+foo :: [(Int,Int)] -> Int+foo [] = 0+foo (a:as) = fst a + foo as
+ tests/neg/BigNum.hs view
@@ -0,0 +1,7 @@+module BigNum where++{-@ type Foo = { v : Integer | 0 <= v && v < 4611686018427387903 * 8 } @-}++{-@ f :: i : Foo -> { o : Foo | i < o } @-}+f :: Integer -> Integer+f i = i * 2
+ tests/neg/Books.hs view
@@ -0,0 +1,62 @@+{-# LANGUAGE CPP #-}++#define DISCOUNT_PERCENTAGE 2+#define BOOK_THRESHOLD 2++module Books where++calculateDiscount' :: Customer -> Int -> Int++---------------------------------------------------------------------------------------+-- 1. Define: Types of customers+---------------------------------------------------------------------------------------++data Customer = Vip | Reg deriving (Eq)++---------------------------------------------------------------------------------------+-- 2. Define: Discountable Customers and Discounts+---------------------------------------------------------------------------------------++{-@ inline customerGetsDiscount @-}+customerGetsDiscount :: Customer -> Int -> Bool+customerGetsDiscount c i = c == Vip && i >= BOOK_THRESHOLD++{-@ inline discount @-}+discount :: Int -> Int+discount bookCount = (bookCount - BOOK_THRESHOLD) * DISCOUNT_PERCENTAGE++{-@ type Discount i = {v:Int | v == discount i} @-}++---------------------------------------------------------------------------------------+-- 3. Policy: Only compute discounts for discountable customers+---------------------------------------------------------------------------------------++{-@ calculateDiscount' :: c:Customer -> i:{Int | customerGetsDiscount c i} -> Discount i @-}+calculateDiscount' c i = discount i++---------------------------------------------------------------------------------------+-- 4. Implement: Code to compute discounts, if suitable, is accepted+---------------------------------------------------------------------------------------++{-@ calculateDiscount :: Int -> Nat -> Nat @-}+calculateDiscount userId bookCount+ | getsDiscount = calculateDiscount' c bookCount+ | otherwise = 0+ where+ getsDiscount = customerGetsDiscount c bookCount+ c = customerType userId++---------------------------------------------------------------------------------------+-- 5. Buggy Implementation, with wrong check, is rejected+---------------------------------------------------------------------------------------++{-@ misCalculateDiscount :: Int -> Nat -> Nat @-}+misCalculateDiscount userId bookCount+ | getsDiscount = calculateDiscount' c bookCount+ | otherwise = 0+ where+ getsDiscount = c == Vip+ c = customerType userId++customerType :: Int -> Customer+customerType = undefined
+ tests/neg/FunSoundness.hs view
@@ -0,0 +1,9 @@+module FunSoundness where+++{-@ deadfun :: {v:a | false} -> a @-}+deadfun :: a -> a+deadfun x = x++bad = deadfun f + where f x = x
+ tests/neg/GADTs.hs view
@@ -0,0 +1,21 @@+{-# LANGUAGE GADTs #-}+{-# LANGUAGE KindSignatures #-}++module Blank where++data Some :: * -> * where+ SomeBool :: Bool -> Some Int+ SomeInt :: Int -> Some Int++{-@ measure isBool @-}+isBool :: Some Int -> Bool+isBool (SomeBool _) = True+isBool (SomeInt _) = False++{-@ type SomeBool = { v: Some Int | isBool v } @-}++{-@ a :: SomeBool @-}+a = SomeBool True++{-@ b :: SomeBool @-}+b = SomeInt 5
+ tests/neg/Gradual.hs view
@@ -0,0 +1,15 @@+module Gradual where+++{-@ unsafe :: {v:Int | ?? } -> Int -> (Int, Int) @-}+unsafe :: Int -> Int -> (Int, Int)+unsafe _ x = (bar1 x, bar2 x)+++{-@ bar1 :: {v:Int | v < 0} -> Int @-}+bar1 :: Int -> Int +bar1 x = x ++{-@ bar2 :: {v:Int | v = 0} -> Int @-}+bar2 :: Int -> Int +bar2 x = x
− tests/neg/PairMeasure0.hs
@@ -1,20 +0,0 @@-module Foo () where--{-@ measure getfst :: (a, b) -> a- getfst (x, y) = x- @-}--{-@ type Pair a b = {v0 : ({v:a | v = (getfst v0)}, b) | true } @-}-{-@ type OPList a b = [(Pair a b)]<\h -> {v: (Pair a b) | (getfst v) >= (getfst h)}> @-}-{-@ type OList a = [a]<\h -> {v: a | (v >= h)}> @-}----- This is Unsafe, as refinements in Predicate parameters (i.e., Pair a b)--- are lost, so application `getFsts` cannot be proven safe-{-@ getFsts :: OPList a b -> OList a @-}-getFsts :: [(a, b)] -> [a]-getFsts [] = [] -getFsts ((x,_) : xs) = x : getFsts xs---
tests/neg/Propability.hs view
@@ -1,7 +1,5 @@ module Propability where -{-@ LIQUID "--real" @-}- {-@ type Propability = {v:Double | ((0.0 <= v) && (v <= 1.0)) } @-} {-@ p :: Propability @-}
tests/neg/Propability0.hs view
@@ -7,8 +7,6 @@ snd :: Int -> Real -} -{-@ LIQUID "--real" @-}- {-@ type Propability = {v:Double | ((0.0 <= v) && (v <= 1.0)) } @-} {-@ p :: Propability @-}
tests/neg/StateConstraints.hs view
@@ -5,7 +5,7 @@ data ST s = ST {runState :: s -> s} -{-@ data ST s t <p :: s -> Prop, q :: s -> s -> Prop> = ST (runState :: x:s<p> -> s<q x>) @-}+{-@ data ST s <p :: s -> Prop, q :: s -> s -> Prop> = ST (runState :: x:s<p> -> s<q x>) @-} {-@ runState :: forall <p :: s -> Prop, q :: s -> s -> Prop>. ST <p, q> s -> x:s<p> -> s<q x> @-}
+ tests/neg/T602.hs view
@@ -0,0 +1,22 @@+module T602 where++-- UNSOUNDLY SAFE+{-@+class Fractional a => Foo a where+ foo :: { x : a | x /= 0 } -> a+@-}++-- UNSAFE+{-+class Fractional a => Foo a where+ foo :: { x : a | x /= 0.0 } -> a+@-}++class Fractional a => Foo a where+ foo :: a -> a++instance Foo Double where+ foo = id++example :: Double+example = foo 0.0
+ tests/neg/TermReal.hs view
@@ -0,0 +1,5 @@+module Main where++{-@ search :: { hi : Int | 0 < hi } -> Int @-}+search :: Int -> Int+search hi = search (hi `div` 2)
+ tests/neg/Variance1.hs view
@@ -0,0 +1,11 @@+import Data.Binary+++{-@+error :: { x : String | false } -> a+@-}++example :: Get ()+example = do+ _ <- return ()+ error "URK"
+ tests/neg/listne.hs view
@@ -0,0 +1,7 @@++{-@ type ListNE a = {v:[a] | 0 < len v} @-}++{-@ junkProp :: ListNE Int @-}+junkProp :: [Int]+junkProp = []+
tests/pos/Abs.hs view
@@ -3,10 +3,10 @@ absN :: (Num a, Ord a) => a -> a absN x = if x > 0 then x else (-x) -absI :: Int -> Int +absI :: Int -> Int absI x = if x > 0 then x else (-x) ---incI :: Int -> Int +--incI :: Int -> Int --incI = (+) 1 x0 = absN 4
tests/pos/Avg.hs view
@@ -1,8 +1,5 @@ module Avg where --{-@ LIQUID "--real" @-}- {-@ measure sumD :: [Double] -> Double sumD([]) = 0.0 sumD(x:xs) = x + (sumD xs)
+ tests/pos/Bar.hs view
@@ -0,0 +1,5 @@+module Bar where++import Foo++foo = bar
+ tests/pos/BinarySearch.hs view
@@ -0,0 +1,43 @@+{- | By Gabriel Gonzalez, from:+ http://www.haskellforall.com/2015/12/compile-time-memory-safety-using-liquid.html+-}++module BinarySearch (binarySearch) where++import Data.Vector as Vector++binarySearch :: Ord a => a -> Vector a -> Maybe Int+binarySearch x v =+ if Vector.length v == 0+ then Nothing+ else loop x v 0 (Vector.length v - 1)++midpoint :: Int -> Int -> Int+midpoint lo hi = (lo + hi) `div` 2++{-@+loop+ :: Ord a+ => x : a+ -> v : Vector a+ -> lo : { lo : Int | 0 <= lo && lo < vlen v }+ -> hi : { hi : Int | lo <= hi && hi < vlen v }+ -> Maybe Int+ / [hi - lo]+@-}+loop :: Ord a => a -> Vector a -> Int -> Int -> Maybe Int+loop x v lo hi = do+ let mid = lo + ((hi - lo) `div` 2) -- midpoint lo hi+ if x < v ! mid+ then do+ let hi' = mid - 1+ if lo <= hi'+ then loop x v lo hi'+ else Nothing+ else if v ! mid < x+ then do+ let lo' = mid + 1+ if lo' <= hi+ then loop x v lo' hi+ else Nothing+ else Just mid
+ tests/pos/Books.hs view
@@ -0,0 +1,50 @@+{-# LANGUAGE CPP #-}++#define DISCOUNT_PERCENTAGE 2+#define BOOK_THRESHOLD 2++module Books where++calculateDiscount' :: Customer -> Int -> Int++---------------------------------------------------------------------------------------+-- 1. Define: Types of customers+---------------------------------------------------------------------------------------++data Customer = Vip | Reg deriving (Eq)++---------------------------------------------------------------------------------------+-- 2. Define: Discountable Customers and Discounts+---------------------------------------------------------------------------------------++{-@ inline customerGetsDiscount @-}+customerGetsDiscount :: Customer -> Int -> Bool+customerGetsDiscount c i = c == Vip && i >= BOOK_THRESHOLD++{-@ inline discount @-}+discount :: Int -> Int+discount bookCount = (bookCount - BOOK_THRESHOLD) * DISCOUNT_PERCENTAGE++{-@ type Discount i = {v:Int | v == discount i} @-}++---------------------------------------------------------------------------------------+-- 3. Policy: Only compute discounts for discountable customers+---------------------------------------------------------------------------------------++{-@ calculateDiscount' :: c:Customer -> i:{Int | customerGetsDiscount c i} -> Discount i @-}+calculateDiscount' c i = discount i++---------------------------------------------------------------------------------------+-- 4. Implement: Code to compute discounts, if suitable, is accepted+---------------------------------------------------------------------------------------++{-@ calculateDiscount :: Int -> Nat -> Nat @-}+calculateDiscount userId bookCount+ | getsDiscount = calculateDiscount' c bookCount+ | otherwise = 0+ where+ getsDiscount = customerGetsDiscount c bookCount+ c = customerType userId++customerType :: Int -> Customer+customerType = undefined
tests/pos/Class.hs view
@@ -6,36 +6,45 @@ import Prelude hiding (sum, length, (!!), Functor(..)) import qualified Prelude as P -{-@ qualif Size(v:int, xs:a): v = (size xs) @-}+{-@ qualif Size(v:Int, xs:a): v = size xs @-} -{-@ data List a = Nil | Cons (hd::a) (tl::(List a)) @-}-data List a = Nil | Cons a (List a)+{-@ qualif Size(v:Int, xs:MList a): v = size xs @-} -{-@ length :: xs:List a -> {v:Nat | v = (size xs)} @-}-length :: List a -> Int-length Nil = 0-length (Cons x xs) = 1 + length xs+{-@ data MList a = Nil | Cons (hd::a) (tl::(MList a)) @-}+data MList a = Nil | Cons a (MList a) -{-@ (!!) :: xs:List a -> {v:Nat | v < (size xs)} -> a @-}-(!!) :: List a -> Int -> a+{-@ (!!) :: xs:MList a -> {v:Nat | v < (size xs)} -> a @-}+(!!) :: MList a -> Int -> a Nil !! i = liquidError "impossible" (Cons x _) !! 0 = x (Cons x xs) !! i = xs !! (i - 1) {-@ class measure size :: forall a. a -> Int @-}+ {-@ class Sized s where- size :: forall a. x:s a -> {v:Nat | v = (size x)}+ size :: forall a. x:s a -> {v:Nat | v = size x} @-} class Sized s where size :: s a -> Int -instance Sized List where- {-@ instance measure size :: List a -> Int+instance Sized MList where+ {-@ instance measure size :: MList a -> Int size (Nil) = 0- size (Cons x xs) = 1 + (size xs)+ size (Cons x xs) = 1 + size xs @-} size = length +{-@ length :: xs:MList a -> {v:Nat | v = size xs} @-}+length :: MList a -> Int+length Nil = 0+length (Cons x xs) = 1 + length xs++{-@ bob :: xs:MList a -> {v:Nat | v = size xs} @-}+bob :: MList a -> Int+bob = length+++ instance Sized [] where {-@ instance measure size :: [a] -> Int size ([]) = 0@@ -45,13 +54,13 @@ size (x:xs) = 1 + size xs {-@ class (Sized s) => Indexable s where- index :: forall a. x:s a -> {v:Nat | v < (size x)} -> a+ index :: forall a. x:s a -> {v:Nat | v < size x} -> a @-} class (Sized s) => Indexable s where index :: s a -> Int -> a -instance Indexable List where+instance Indexable MList where index = (!!) {-@ sum :: Indexable s => s Int -> Int @-}@@ -64,9 +73,9 @@ | otherwise = 0 -{-@ sumList :: List Int -> Int @-}-sumList :: List Int -> Int-sumList xs = go max 0+{-@ sumMList :: MList Int -> Int @-}+sumMList :: MList Int -> Int+sumMList xs = go max 0 where max = size xs go (d::Int) i@@ -74,8 +83,8 @@ | otherwise = 0 -{-@ x :: {v:List Int | (size v) = 3} @-}-x :: List Int+{-@ x :: {v:MList Int | (size v) = 3} @-}+x :: MList Int x = 1 `Cons` (2 `Cons` (3 `Cons` Nil)) foo = liquidAssert $ size (Cons 1 Nil) == size [1]
+ tests/pos/CountMonad.hs view
@@ -0,0 +1,70 @@+module Count () where++{-@ measure count :: Count a -> Int @-}++data Count a = Count a ++instance Functor Count where+ fmap = undefined +instance Applicative Count where+ pure = undefined+ (<*>) = undefined ++instance Monad Count where+{-@+instance Monad Count where + >>= :: forall <r :: Count a -> Prop, p :: Count b -> Prop, q :: Count b -> Prop>.+ {x::Count a <<r>>, y :: Count b <<p>> |- {v:Count b | count v == count x + count y} <: Count b <<q>>} + Count a <<r>> -> (a -> Count b<<p>>) -> Count b <<q>> ; + >> :: x:Count a -> y:Count b -> {v:Count b | count v == count x + count y}; + return :: a -> {v:Count a | count v == 0 } +@-}+ return x = let r = Count x in assertCount 0 (Count x) + (Count x) >>= f = let r = f x in assertCount (getCount (Count x) + getCount r) r + x >> y = assertCount (getCount x + getCount y) y+ fail = error++++{-@ assume assertCount :: i:Int -> x:Count a -> {v:Count a | v == x && count v == i } @-}+assertCount :: Int -> Count a -> Count a +assertCount _ x = x ++{-@ assume getCount :: x:Count a -> {v:Int | v == count x } @-} +getCount :: Count a -> Int +getCount _ = 0 +++{-@ assume incr :: a -> {v:Count a | count v == 1 } @-}+incr :: a -> Count a +incr = Count ++{-@ assume unit :: {v:Count () | count v == 0 } @-}+unit = Count ()++{-@ foo :: a -> {v:Count a | count v == 0 } @-}+foo :: a -> Count a +foo y = return y ++{-@ test1 :: {v:Count () | count v == 0 } @-}+test1 :: Count ()+test1 = do + unit+ unit+ unit++{-@ test2 :: {v:Count () | count v == 1 } @-}+test2 = do + unit+ y <- incr ()+ unit+ foo y + unit++{-@ test3 :: {v:Count () | count v == 2 } @-}+test3 = do + unit+ unit+ incr ()+ incr ()+ unit
+ tests/pos/DB00.hs view
@@ -0,0 +1,21 @@++{-@ LIQUID "--no-termination" @-}+{-@ LIQUID "totality" @-}++module DataBase (values) where++{-@ values :: forall <rr2 :: key -> val -> Prop>.+ k:key -> [Dict <rr2> key val] -> [val<rr2 k>] @-}+values :: key -> [Dict key val] -> [val]+values k = map (go k)+ where+ {-@ go :: forall <rr1 :: k -> v -> Prop>. + i:k -> Dict <rr1> k v -> v<rr1 i> @-}+ go k (D _ f) = f k++data Dict key val = D {ddom :: [key], dfun :: key -> val}++{-@ data Dict key val <rr :: key -> val -> Prop>+ = D ( ddom :: [key])+ ( dfun :: i:key -> val<rr i>)+ @-}
tests/pos/Even.hs view
@@ -1,9 +1,7 @@-module Even () where+module Even where -{-@ isEven, isOdd :: Nat -> Bool @-}-isEven :: Int -> Bool-isEven 0 = True-isEven n = isOdd $ n - 1+{-@ type Even = {v:Int | v mod 2 = 0} @-} -isOdd 0 = False-isOdd m = isEven $ m - 1+{-@ notEven :: Int -> Even @-}+notEven :: Int -> Int+notEven x = x * 2
+ tests/pos/GADTs.hs view
@@ -0,0 +1,21 @@+{-# LANGUAGE GADTs #-}+{-# LANGUAGE KindSignatures #-}++module Blank where++data Some :: * -> * where+ SomeBool :: Bool -> Some Int+ SomeInt :: Int -> Some Int++{-@ measure isBool @-}+isBool :: Some Int -> Bool+isBool (SomeBool _) = True+isBool (SomeInt _) = False++{-@ type SomeBool = { v: Some Int | isBool v } @-}++{-@ a :: SomeBool @-}+a = SomeBool True++{-@ b :: SomeBool @-}+b = SomeBool True
tests/pos/GhcSort1.hs view
@@ -25,12 +25,12 @@ | a `compare` b /= GT = ascending b (\ys -> as (a:ys)) bs 1 ascending a as bs _ = as [a]: sequences bs 0 - mergeAll [] = [] --this case cannot occur, though + mergeAll [] = [] --this case cannot occur, though mergeAll [x] = x mergeAll xs = mergeAll (mergePairs xs) -{-@ mergePairs :: Ord a - => xss:[(OList a)] +{-@ mergePairs :: Ord a+ => xss:[(OList a)] -> {v:[(OList a)] | (if ((len xss) > 1) then ((len v) < (len xss)) else ((len v) = (len xss) ))} @-} mergePairs :: Ord a => [[a]] -> [[a]]@@ -41,11 +41,11 @@ -- merge1 needs to be toplevel, -- to get applied transformRec tx -{-@ merge1 :: Ord a - => xs:(OList a) - -> ys:(OList a)- -> {v:(OList a) | (len v) = ((len xs) + (len ys))} - / [(len xs) + (len ys)] +{-@ merge1 :: Ord a+ => xs:OList a+ -> ys:OList a+ -> {v:OList a | len v == len xs + len ys}+ / [len xs + len ys] @-} merge1 :: Ord a => [a] -> [a] -> [a] merge1 (a:as') (b:bs')@@ -53,5 +53,3 @@ | otherwise = a:merge1 as' (b:bs') merge1 [] bs = bs merge1 as [] = as--
+ tests/pos/GoodHMeas.hs view
@@ -0,0 +1,10 @@+{-@ measure foo @-}+bar, foo :: [(Int,Int)] -> Int+foo [] = 0+foo (a:as) = fst a + foo as++{-@ fst :: xs:(a, b) -> {v:a | v == fst xs} @-}+++{-@ bar :: xs:[(Int, Int)] -> {v:Int | v == foo xs } @-}+bar x = foo x
+ tests/pos/Gradual.hs view
@@ -0,0 +1,13 @@+module Gradual where++{-@ safe :: {v:Int | ?? } -> (Int, Int) @-}+safe :: Int -> (Int, Int)+safe x = (bar1 x, bar2 x)++{-@ bar1 :: {v:Int | v < 0} -> Int @-}+bar1 :: Int -> Int +bar1 x = x ++{-@ bar2 :: {v:Int | v = 0} -> Int @-}+bar2 :: Int -> Int +bar2 x = x
+ tests/pos/LambdaDeBruijn.hs view
@@ -0,0 +1,87 @@+module LambdaDeBruijn where++{- Proving Termination of Parallel Substitutions,+ see § 3.2.2 of Dependent Types and Multi Monadic Effects in F*+ -}++import Language.Haskell.Liquid.Prelude++{-@ LIQUID "--totality" @-}++type Var = Int+{-@ type EVar = {v:Expr| isEVar v} @-}++type Subst = [(Var,Expr)]+{-@ type RenamingSubst = {su: [(Var,Expr)] | isRenaming su} @-}+++{- TODO: in the F* paper, substitutions are functions,+ can we have function representation with LH? -}+++data Typ++data Expr = EVar Var+ | ELam Typ Expr+ | EUnit+ | EApp Expr Expr+{-@ data Expr [elen] @-}+++{-@ type MEVar E SU = {v:Expr | (isEVar E && isRenaming SU) => (isEVar v) } @-}+++{-@ sub :: su:Subst -> v:Var -> {v:Expr | (isRenaming su) => (isEVar v) } @-}+sub [] v = EVar v+sub ((vx, x):su) v | v == vx = x+ | otherwise = sub su v+++{-@ subst :: e:Expr -> su:Subst -> MEVar e su+ / [if (isEVar e) then 0 else 1, if (isRenaming su) then 0 else 1, elen e] @-}++subst EUnit su = EUnit+subst (EVar v) su = sub su v+subst (EApp e1 e2) su = EApp (subst e1 su) (subst e2 su)++subst (ELam t e) su | isRenaming su =+ let su' = toRem $ (0, EVar 0): map (\i -> (i, subst (sub su (i-1)) $ incrsubst ())) [1..]+ in ELam t $ subst e su'++subst (ELam t e) su = -- | not $ isRenaming su+ let su' = (0, EVar 0): map (\i -> (i, subst (sub su (i-1)) $ incrsubst ())) [1..]+ in ELam t $ subst e su'++++{-- Helper functions and measure definitions --}++{-@ toRem :: [(Var, EVar)] -> RenamingSubst @-}+toRem :: Subst -> Subst+toRem [] = []+toRem ((x, y):sus) = (x, y):toRem sus++{-@ incrsubst :: () -> RenamingSubst @-}+incrsubst :: () -> Subst+incrsubst _ = toRem $ map (\i -> (i, EVar $ i+1)) [0..]++{-@ measure isEVar @-}+isEVar :: Expr -> Bool+isEVar (EVar _) = True+isEVar _ = False++{-@ measure isRenaming @-}+isRenaming :: Subst -> Bool+isRenaming (vx:sus) = isEVar (mysnd vx) && isRenaming sus+isRenaming [] = True++{-@ measure mysnd @-}+mysnd (_,y) = y++{-@ invariant {v:Expr | elen v >= 0 } @-}+{-@ measure elen @-}+elen :: Expr -> Int+elen EUnit = 0+elen (EVar v) = 0+elen (ELam _ e) = 1 + elen e+elen (EApp e1 e2) = 1 + elen e1 + elen e2
tests/pos/LambdaEval.hs view
@@ -46,15 +46,16 @@ elen(Snd e) = 1 + (elen e) @-} + {-@ invariant {v:Expr | (elen v) >= 0} @-} {-@ measure isValue :: Expr -> Prop-isValue (Const i) = true -isValue (Lam x e) = true +isValue (Const i) = true+isValue (Lam x e) = true isValue (Var x) = false isValue (App e1 e2) = false-isValue (Plus e1 e2) = false +isValue (Plus e1 e2) = false isValue (Fst e) = false isValue (Snd e) = false isValue (Pair e1 e2) = (isValue e1) && (isValue e2)
tests/pos/ListQSort-LType.hs view
@@ -2,9 +2,9 @@ import Language.Haskell.Liquid.Prelude -{-@ -data List [llen] a <p :: x0:a -> x1:a -> Prop> - = Nil +{-@+data List [llen] a <p :: x0:a -> x1:a -> Prop>+ = Nil | Cons (h :: a) (t :: List <p> (a <p h>)) @-} @@ -15,20 +15,21 @@ {-@ invariant {v:List a | (llen v) >= 0} @-} -{-@ qualif ZLLen(v:List a) : (llen(v) >= 0)@-}-{-@ qualif CmpLLen(v:List a, A:List b) : ((llen v) <= (llen A))@-}+{-@ qualif ZLLen(v:ListRange.List a) : (llen(v) >= 0)@-} +{-@ qualif CmpLLen(v:ListRange.List a, a:ListRange.List b) : (llen v <= llen a) @-}+ data List a = Nil | Cons a (List a) append k Nil ys = Cons k ys-append k (Cons x xs) ys = Cons x (append k xs ys) +append k (Cons x xs) ys = Cons x (append k xs ys) takeL x Nil = Nil takeL x (Cons y ys) = if (y<x) then Cons y (takeL x ys) else takeL x ys -{-@ takeGE :: Ord a - => x:a - -> xs:List a +{-@ takeGE :: Ord a+ => x:a+ -> xs:List a -> {v: (List {v:a | v >= x}) | ((llen v) <= (llen xs))} @-} takeGE x Nil = Nil takeGE x (Cons y ys) = if (y>=x) then Cons y (takeGE x ys) else takeGE x ys@@ -38,13 +39,13 @@ where xsle = quicksort (takeL x xs) xsge = quicksort (takeGE x xs) -chk y = - case y of +chk y =+ case y of Nil -> True- Cons x1 xs -> case xs of + Cons x1 xs -> case xs of Nil -> True Cons x2 xs2 -> liquidAssertB (x1 <= x2) && chk xs- + bar = quicksort $ mkList [1 .. 100] mkList :: Ord a => [a] -> List a
+ tests/pos/Merge1.hs view
@@ -0,0 +1,14 @@+module Merge1 where++{-@ merge1 :: Ord a+ => xs:[a]+ -> ys:[a]+ -> {v:[a] | len v == len xs + len ys}+ / [len xs + len ys]+ @-}+merge1 :: Ord a => [a] -> [a] -> [a]+merge1 (a:as') (b:bs')+ | a `compare` b == GT = b:merge1 (a:as') bs'+ | otherwise = a:merge1 as' (b:bs')+merge1 [] bs = bs+merge1 as [] = as
tests/pos/OrdList.hs view
@@ -1,5 +1,5 @@ module OrdList (- OrdList, + OrdList, nilOL, isNilOL, unitOL, appOL, consOL, snocOL, concatOL, concatOL', mapOL, fromOL, toOL, foldrOL, foldlOL ) where@@ -87,11 +87,12 @@ a `appOL` One b = Snoc a b a `appOL` b = Two a b -{-@ qualif Go(v:List a, xs:OrdList a, ys:List a): (len v) = (olen xs) + (len ys) @-}+{-@ qualif Go(v:[a], xs:OrdList a, ys:[a]): (len v) = (olen xs) + (len ys) @-} {-@ fromOL :: xs:OrdList a -> {v:[a] | (len v) = (olen xs)} @-} fromOL a = go a [] where+ {- go :: xs:_ -> acc:_ -> {v:[a] | len v = olen xs + len acc } -} go None acc = acc go (One a) acc = a : acc go (Cons a b) acc = a : go b acc@@ -126,6 +127,6 @@ foldlOL k z (Two b1 b2) = foldlOL k (foldlOL k z b1) b2 foldlOL k z (Many xs) = foldl k z xs -{-@ toOL :: xs:[a] -> OrdListN a {(len xs)} @-}+{-@ toOL :: xs:[a] -> OrdListN a {len xs} @-} toOL [] = None toOL xs = Many xs
tests/pos/PairMeasure0.hs view
@@ -1,5 +1,20 @@ module Foo () where -{-@ foo :: p:(a, b) -> {v:a | (v = (fst p))} @-}-foo (x, y) = x+{-@ measure getfst :: (a, b) -> a+ getfst (x, y) = x+ @-}++{-@ type Pair a b = {v0 : ({v:a | v = (getfst v0)}, b) | true } @-}+{-@ type OPList a b = [(Pair a b)]<\h -> {v: (Pair a b) | (getfst v) >= (getfst h)}> @-}+{-@ type OList a = [a]<\h -> {v: a | (v >= h)}> @-}+++-- This is Unsafe, as refinements in Predicate parameters (i.e., Pair a b)+-- are lost, so application `getFsts` cannot be proven safe+{-@ getFsts :: OPList a b -> OList a @-}+getFsts :: [(a, b)] -> [a]+getFsts [] = [] +getFsts ((x,_) : xs) = x : getFsts xs++
tests/pos/Product.hs view
@@ -1,4 +1,3 @@-{-@ LIQUID "--real" @-} {-@ LIQUID "--total" @-}
tests/pos/Propability.hs view
@@ -1,7 +1,5 @@ module Propability where -{-@ LIQUID "--real" @-}- {-@ type Propability = {v:Double | ((0.0 <= v) && (v <= 1.0)) } @-} {-@ p :: Propability @-}
tests/pos/RBTree-col-height.hs view
@@ -196,8 +196,8 @@ {-@ predicate Invs V = ((Inv1 V) && (Inv2 V) && (Inv3 V)) @-} {-@ predicate Inv1 V = (((isARB V) && (IsB V)) => (isRB V)) @-}-{-@ predicate Inv2 V = ((isRB v) => (isARB v)) @-}-{-@ predicate Inv3 V = 0 <= (bh v) @-}+{-@ predicate Inv2 V = ((isRB V) => (isARB V)) @-}+{-@ predicate Inv3 V = 0 <= (bh V) @-} {-@ invariant {v: Color | (v = R || v = B)} @-}
tests/pos/RBTree-color.hs view
@@ -178,7 +178,7 @@ {-@ predicate Invs V = ((Inv1 V) && (Inv2 V)) @-} {-@ predicate Inv1 V = (((isARB V) && (IsB V)) => (isRB V)) @-}-{-@ predicate Inv2 V = ((isRB v) => (isARB v)) @-}+{-@ predicate Inv2 V = ((isRB V) => (isARB V)) @-} {-@ invariant {v: Color | (v = R || v = B)} @-}
tests/pos/RBTree-height.hs view
@@ -167,7 +167,7 @@ {-@ invariant {v: RBTree a | (Invs v)} @-} {-@ predicate Invs V = (Inv3 V) @-}-{-@ predicate Inv3 V = 0 <= (bh v) @-}+{-@ predicate Inv3 V = 0 <= (bh V) @-} {-@ invariant {v: Color | (v = R || v = B)} @-}
tests/pos/RBTree.hs view
@@ -199,8 +199,8 @@ {-@ predicate Invs V = Inv1 V && Inv2 V && Inv3 V @-} {-@ predicate Inv1 V = (isARB V && IsB V) => isRB V @-}-{-@ predicate Inv2 V = isRB v => isARB v @-}-{-@ predicate Inv3 V = 0 <= bh v @-}+{-@ predicate Inv2 V = isRB V => isARB V @-}+{-@ predicate Inv3 V = 0 <= bh V @-} {-@ invariant {v: Color | v = R || v = B} @-} {-@ invariant {v: RBTree a | Invs v} @-}
tests/pos/RealProps.hs view
@@ -1,7 +1,6 @@-module Div where--{-@ LIQUID "--real" @-}+-- Issue overload-div-int-real #579 +module Div where {-@ type Valid = {v:Bool | ( (Prop v) <=> true ) } @-}
tests/pos/RealProps1.hs view
@@ -1,7 +1,7 @@-module Div where -{-@ LIQUID "--real" @-}+-- Issue overload-div-int-real #579 +module Div where {-@ type Valid = {v:Bool | ( (Prop v) <=> true ) } @-}
tests/pos/ResolvePred.hs view
@@ -1,4 +1,4 @@-module ResolvePred () where+module ResolvePred (myFold) where {-@ data L [llen] = C (h :: Int) (t :: L) | N @-} {-@ invariant {v:L | (llen v) >= 0} @-}
+ tests/pos/StructRec.hs view
@@ -0,0 +1,18 @@+module ListLen () where++{-@ autosize OList @-}++data OList a =+ Mt+ | Ln{h :: a, t :: OList a}++{-@ data OList a =+ Mt+ | Ln{h :: a, t :: OList {v:a | h <= v}} @-}++insert :: (Ord a) => a -> OList a -> OList a+insert y Mt = Ln y Mt+insert y (Ln x xs)+ | y <= x = Ln y (Ln x xs)+ | otherwise = Ln x (insert y xs)+
+ tests/pos/T531.hs view
@@ -0,0 +1,6 @@+module T531 where++{-@+data Foo = Foo { _getFoo :: Int }+@-}+data Foo = Foo { _getFoo :: Int }
+ tests/pos/T595.hs view
@@ -0,0 +1,29 @@+module Issue595 where++import Data.Vector++data Test = Test+ { vec :: Thing+ , x0 :: Bool+ }++type Thing = [()] -- Vector ()++{-@+data Test = Test+ { vec :: Thing+ , x0 :: { x0 : Bool | len vec < 1 ==> Prop x0 }+ }+@-}++-- The above data declaration should give us the following refined types+-- for the record selectors++{- vec :: x:Test -> {v:Thing | v = vec x} -}+{- x0 :: x:Test -> {v:Bool | v = x0 x && ((len (vec x) < 1) => Prop v) } -}++example :: Test -> ()+example t =+ if x0 t+ then ()+ else vec t !! 0
+ tests/pos/T595a.hs view
@@ -0,0 +1,12 @@+{-@ LIQUID "--totality" @-}++module T595a where++data Tree a = Nil | Tree { key :: a, l::Tree a, r :: Tree a}++{-@ data Tree a = Nil+ | Tree { key :: a+ , l :: Tree {v:a | v < key }+ , r :: Tree {v:a | key < v }+ }+ @-}
+ tests/pos/T598.hs view
@@ -0,0 +1,10 @@+{-# LANGUAGE DeriveGeneric #-}++import GHC.Generics (Generic)+import Control.DeepSeq (NFData(..))++data Point = Point+ { x :: Int+ } deriving (Generic)++instance NFData Point
+ tests/pos/Words.hs view
@@ -0,0 +1,5 @@+import Data.Word++{-@ foo :: {v:Word | v = 4} @-}+foo :: Word+foo = 4
+ tests/pos/Words1.hs view
@@ -0,0 +1,3 @@+import Data.Word++main = print (quotRem (4 :: Word8) 128)
+ tests/pos/anish1.hs view
@@ -0,0 +1,13 @@+module Test1 () where++inc :: Int -> Int+inc xoooo = xoooo + 1++test1 :: Int -> Int+test1 nine = let b = 0 <= nine in+ if b then+ let a = inc nine+ in+ div nine a+ else+ 1
+ tests/pos/csgordon_issue_296.hs view
@@ -0,0 +1,6 @@+module BadMeasureType where ++{-@ measure fwd_extends :: IO () -> IO () -> Prop @-}+{-@ assume fwd_extends_refl :: m:IO () -> {v:Bool | (fwd_extends m m)} @-}+fwd_extends_refl :: IO () -> Bool+fwd_extends_refl = undefined
+ tests/pos/dropwhile.hs view
@@ -0,0 +1,84 @@+{-@ LIQUID "--no-termination" @-}++module DropWhile where++import Language.Haskell.Liquid.Prelude+import Prelude hiding (head, dropWhile, (.), filter)++main :: IO ()+main =+ if head (dropWhile ((/=) 3) (1:::2:::3:::Emp)) == 3+ then return ()+ else liquidError "Not going to happen"++-------------------------------------------------------------------------------+-- | The `head` function returns a value that satisfies the abstract refinement+-------------------------------------------------------------------------------++{-@ head :: forall <p :: a -> Prop>. List <p> a -> a<p> @-}+head (x ::: _) = x++-------------------------------------------------------------------------------+-- | A List +-------------------------------------------------------------------------------++data List a = Emp | (:::) { hd :: a+ , tl :: List a }+infixr 5 :::++-------------------------------------------------------------------------------+-- | A list whose head satisfies an abstract refinement `p`+-------------------------------------------------------------------------------++-- in the below, `hd :: a<p>` means the "head" is a value of type `a` that+-- additionally, satisfies `p hd`.++{-@ data List a <p :: a -> Prop> = Emp+ | (:::) { hd :: a<p>+ , tl :: List a }+ @-}++-- | e.g. a list whose head equals `3`++{-@ type OneList = List <{\v -> v == 3}> Int @-}++{-@ one :: OneList @-}+one :: List Int+one = 3 ::: 2 ::: 1 ::: Emp++-------------------------------------------------------------------------------+-- | dropWhile some predicate `f` is not satisfied+-------------------------------------------------------------------------------++{-@ dropWhile :: forall <p :: a -> Prop, w :: a -> Bool -> Prop>.+ (Witness a p w) =>+ (x:a -> Bool<w x>) -> List a -> List <p> a+ @-}+dropWhile :: (a -> Bool) -> List a -> List a+dropWhile f (x:::xs)+ | not (f x) = x ::: xs+ | otherwise = dropWhile f xs+dropWhile f Emp = Emp++-- | This `witness` bound relates the predicate used in dropWhile++{-@ bound witness @-}+witness :: Eq a => (a -> Bool) -> (a -> Bool -> Bool) -> a -> Bool -> a -> Bool+witness p w = \ y b v -> (not b) ==> w y b ==> (v == y) ==> p v++{-@ measure tail :: forall a. { es : [a] | len es >= 1 } -> [a] @-}+tail :: [a] -> [a]+tail = undefined+-------------------------------------------------------------------------------+-- | Drop elements until you hit a `3`+-------------------------------------------------------------------------------++{-@ dropUntilOne' :: List Int -> OneList @-}+dropUntilOne' :: List Int -> List Int+dropUntilOne' = dropWhile (/= 3)++-- | Currently needed for the qual; should be made redundant by `--eliminate`++{-@ eqOne :: x:Int -> {v:Bool | Prop v <=> x /= 3} @-}+eqOne :: Int -> Bool+eqOne x = x /= 3
tests/pos/gadtEval.hs view
@@ -59,13 +59,13 @@ toBool _ = liquidError "impossible" -{-@ predicate TInt X = ((eType X) = TInt) @-}-{-@ predicate TBool X = ((eType X) = TBool) @-}+{-@ predicate IsTInt X = ((eType X) = TInt) @-}+{-@ predicate IsTBool X = ((eType X) = TBool) @-} {-@ type ValidExpr = {v: Expr | (isValid v)} @-}-{-@ type IntExpr = {v: Expr | ((isValue v) && (TInt v))} @-}-{-@ type BoolExpr = {v: Expr | ((isValue v) && (TBool v))} @-}+{-@ type IntExpr = {v: Expr | ((isValue v) && (IsTInt v))} @-}+{-@ type BoolExpr = {v: Expr | ((isValue v) && (IsTBool v))} @-} {-@ measure isValue :: Expr -> Prop@@ -86,6 +86,6 @@ isValid (I i) = true isValid (B b) = true isValid (Equal e1 e2) = (((eType e1) = (eType e2)) && (isValid e1) && (isValid e2))- isValid (Plus e1 e2) = ((TInt e1) && (TInt e2) && (isValid e1) && (isValid e2))+ isValid (Plus e1 e2) = ((IsTInt e1) && (IsTInt e2) && (isValid e1) && (isValid e2)) @-}
tests/pos/gimme.hs view
@@ -1,7 +1,8 @@ module Blank () where -{-@ qualif Gimme(v:a, n:b, acc:a): len v = n + 1 + len acc @-}+{- qualif Gimme(v:[a], n:int, acc:[a]): (len v == n + 1 + len acc) -} +{-@ gimme :: xs:[a] -> n:Int -> acc:[a] -> {v:[a] | len v = n + 1 + len acc} @-} gimme :: [a] -> Int -> [a] -> [a] gimme xs (-1) acc = acc gimme (x:xs) n acc = gimme xs (n-1) (x : acc)
+ tests/pos/hole-fun.hs view
@@ -0,0 +1,10 @@+module Zoo (test) where++inc :: Int -> Int +inc x = x + 1++{-@ app :: _ -> Nat -> Nat @-} +app :: (Int -> Int) -> Int -> Int+app f x = f x++test = app inc 7
+ tests/pos/idNat.hs view
@@ -0,0 +1,5 @@+module IdNat where ++{-@ nat :: Nat @-}+nat :: Int+nat = id 0 -- (id (id (id (id 0))))
+ tests/pos/idNat0.hs view
@@ -0,0 +1,8 @@+module IdNat where ++{-@ nat :: Nat @-}+nat :: Int+nat = idd 0 ++idd :: a -> a+idd = undefined
+ tests/pos/listqual.hs view
@@ -0,0 +1,10 @@+module ListQual (boo) where++{-@ qualif BadAppend(v:[a], xs:[a], ys:[a]): len v = len xs + len ys @-}++append [] ys = ys+append (x:xs) ys = x : append xs ys++{-@ boo :: {v:[Int] | len v = 2} @-}+boo :: [Int]+boo = append [1] [2]
+ tests/pos/nats.hs view
@@ -0,0 +1,5 @@+module Nats where ++{-@ nats :: [Nat] @-}+nats :: [Int]+nats = [1,2,3,4,5,6,7,8,9,10]
tests/pos/pair00.hs view
@@ -1,19 +1,28 @@-module Pair () where +module Pair () where {-@ LIQUID "--no-termination" @-}-import Language.Haskell.Liquid.Prelude +import Language.Haskell.Liquid.Prelude -incr x = (x, [x+1])-chk (x, [y]) = liquidAssertB (x <y) +incr z = (x, [x + 1])+ where+ x = choose z++incr z = (x, [x + 1])+ where+ x = choose z++chk (x, [y]) = liquidAssertB (x < y)+ prop = chk $ incr n- where n = choose 0+ where+ n = choose 0 incr2 x = (True, 9, x, 'o', x+1)-chk2 (_, _, x, _, y) = liquidAssertB (x <y) +chk2 (_, _, x, _, y) = liquidAssertB (x <y) prop2 = chk2 $ incr2 n where n = choose 0 incr3 x = (x, ( (0, x+1)))-chk3 (x, ((_, y))) = liquidAssertB (x <y) +chk3 (x, ((_, y))) = liquidAssertB (x <y) prop3 = chk3 (incr3 n) where n = choose 0
+ tests/pos/recursion0.hs view
@@ -0,0 +1,7 @@+module Main where++{-@ total :: Nat -> Nat @-}+total :: Int -> Int +total 0 = 0+total n = 1 + total (n-1)+
+ tests/pos/repeatHigherOrder.hs view
@@ -0,0 +1,24 @@+{-@ LIQUID "--no-termination" @-}++module Repeat where++import Prelude hiding (repeat, succ)+import Language.Haskell.Liquid.Prelude++repeat :: Int -> (a -> a) -> a -> a+goal :: Int -> Int+ +{-@ bound step @-}+step :: (a -> a -> Bool) -> (Int -> a -> Bool) -> Int -> a -> a -> Bool+step pf pr = \ i x x' -> pr (i - 1) x ==> pf x x' ==> pr i x'++{-@ repeat :: forall a <f :: a -> a -> Prop, r :: Int -> a -> Prop>.+ (Step a f r) =>+ n:Nat -> (y:a -> a<f y>) -> a<r 0> -> a<r n>+ @-}+repeat 0 _ x = x+repeat n f x = repeat (n - 1) f (f x)++{-@ goal :: n:Nat -> {r:Nat | n <= r} @-}+goal n = repeat n (+ 1) 0+
tests/pos/scanr.hs view
@@ -1,7 +1,7 @@ module Goo () where -{-@ assert scanrr :: forall a b. (a -> b -> b) -> b -> xs:[a] -> {v: [b] | len(v) = 1 + len(xs) } @-}-scanrr :: (a -> b -> b) -> b -> [a] -> [b]+{-@ scanrr :: (a -> b -> b) -> b -> xs:[a] -> {v: [b] | len v = 1 + len xs } @-}+-- scanrr :: (a -> b -> b) -> b -> [a] -> [b] scanrr _ q0 [] = [q0] scanrr f q0 (x:xs) = f x q : qs where qs@(q:_) = scanrr f q0 xs
tests/pos/test00-int.hs view
@@ -2,10 +2,6 @@ import Language.Haskell.Liquid.Prelude -{-@ qualif Zog(v:FooBar, x:FooBar): v = x + 29 @-}--data FooBar = Foo Int- x :: Int x = choose 0
tests/pos/test00.hs view
@@ -2,10 +2,6 @@ import Language.Haskell.Liquid.Prelude -{-@ qualif Zog(v:FooBar, x:FooBar): v = x + 29 @-}--data FooBar = Foo Int- x = choose 0 prop_abs :: Bool
tests/pos/testRec.hs view
@@ -1,35 +1,30 @@ module TestRec where -import Prelude hiding (map, foldl)+import Prelude hiding (foldl) -data L a = N | C a (L a)-{-@ -data L [llen] a = N | C (x::a) (xs::(L a))- @-}+data L a = N | C { hd :: a+ , tl :: L a } -{-@ measure llen :: (L a) -> Int- llen(N) = 0- llen(C x xs) = 1 + (llen xs)+{-@ data L [llen] a = N | C { hd :: a+ , tl :: L a } @-} -{-@map :: (a -> b) -> [a] -> [b]@-}-map f [] = []-map f (x:xs) = f x : map f xs- -bar = map id [1, 2]+{-@ invariant {v:L a | 0 <= llen v} @-} -{-@ Decrease go 2 @-}-rev xs = go [] xs- where go ack [] = ack- go ack (x:xs) = go (x:ack) xs+{-@ measure llen @-}+llen :: L a -> Int+llen N = 0+llen (C x xs) = 1 + llen xs -{-@ invariant {v:(L a) | ((llen v) >= 0)}@-}+reverse :: L a -> L a+reverse xs = go N xs+ where + {-@ go :: acc:_ -> xs:_ -> _ / [llen xs] @-}+ go acc N = acc+ go acc (C x xs) = go (C x acc) xs mapL f N = N mapL f (C x xs) = C (f x) (mapL f xs) --foldl f z [] = z-foldl f z (x:xs) = x `f` foldl f z xs
tests/pos/zipper0.hs view
@@ -11,7 +11,7 @@ {-@ type UListDif a N = {v:[a] | ((not (Set_mem N (listElts v))) && (Set_emp (listDup v)))} @-} {-@-data Stack a = Stack { focus :: a +data Stack a = Stack { focus :: a , up :: UListDif a focus , down :: UListDif a focus } @-}@@ -24,15 +24,15 @@ {-@ type UStack a = {v:Stack a |(Set_emp (Set_cap (listElts (getUp v)) (listElts (getDown v))))}@-} -{-@ measure getFocus :: forall a. (Stack a) -> a +{-@ measure getFocus :: forall a. (Stack a) -> a getFocus (Stack focus up down) = focus @-} -{-@ measure getUp :: forall a. (Stack a) -> [a] +{-@ measure getUp :: forall a. (Stack a) -> [a] getUp (Stack focus up down) = up @-} -{-@ measure getDown :: forall a. (Stack a) -> [a] +{-@ measure getDown :: forall a. (Stack a) -> [a] getDown (Stack focus up down) = down @-} @@ -50,12 +50,12 @@ {-@ focusUp :: UStack a -> UStack a @-} focusUp :: Stack a -> Stack a-focusUp (Stack t [] rs) = Stack x xs [] where (x:xs) = reverse (t:rs)+focusUp (Stack t [] rs) = Stack xiggety xs [] where (xiggety:xs) = reverse (t:rs) focusUp (Stack t (l:ls) rs) = Stack l ls (t:rs) {-@ focusDown :: UStack a -> UStack a @-} focusDown :: Stack a -> Stack a-focusDown = reverseStack . focusUp . reverseStack +focusDown = reverseStack . focusUp . reverseStack -- | reverse a stack: up becomes down and down becomes up. {-@ reverseStack :: UStack a -> UStack a @-}@@ -63,26 +63,7 @@ reverseStack (Stack t ls rs) = Stack t rs ls - -- TODO ASSUMES {-@ reverse :: {v:[a] | (Set_emp (listDup v))} -> {v:[a]|(Set_emp (listDup v))} @-} reverse :: [a] -> [a] reverse = undefined------------------
+ tests/pos/zipper000.hs view
@@ -0,0 +1,68 @@+module Zipper () where++import Prelude hiding (reverse)++import Data.Set++data Stack a = Stack { focus :: !a -- focused thing in this set+ , up :: [a] -- jokers to the left+ , down :: [a] } -- jokers to the right++{-@ type UListDif a N = {v:[a] | ((not (Set_mem N (listElts v))) && (Set_emp (listDup v)))} @-}++{-@+data Stack a = Stack { focus :: a+ , up :: UListDif a focus+ , down :: UListDif a focus }+@-}++{-@+ measure listDup :: [a] -> (Set a)+ listDup([]) = {v | Set_emp v }+ listDup(x:xs) = {v | v = if (Set_mem x (listElts xs)) then (Set_cup (Set_sng x) (listDup xs)) else (listDup xs) }+ @-}++{-@ type UStack a = {v:Stack a |(Set_emp (Set_cap (listElts (getUp v)) (listElts (getDown v))))}@-}++{-@ measure getFocus :: forall a. (Stack a) -> a+ getFocus (Stack focus up down) = focus+ @-}++{-@ measure getUp :: forall a. (Stack a) -> [a]+ getUp (Stack focus up down) = up+ @-}++{-@ measure getDown :: forall a. (Stack a) -> [a]+ getDown (Stack focus up down) = down+ @-}++-- QUALIFIERS+{-@ q :: x:a -> {v:[a] |(not (Set_mem x (listElts v)))} @-}+q :: a -> [a]+q = undefined+{-@ q1 :: x:a -> {v:[a] |(Set_mem x (listElts v))} @-}+q1 :: a -> [a]+q1 = undefined+{-@ q0 :: x:a -> {v:[a] |(Set_emp(listDup v))} @-}+q0 :: a -> [a]+q0 = undefined++{-@ focusUp :: UStack a -> UStack a @-}+focusUp :: Stack a -> Stack a+focusUp (Stack t [] rs) = Stack xiggety xs [] where (xiggety:xs) = reverse (t:rs)+focusUp (Stack t (l:ls) rs) = Stack l ls (t:rs)++{-@ reverse :: {v:[a] | Set_emp (listDup v)} -> {v:[a]|Set_emp (listDup v)} @-}+reverse :: [a] -> [a]+reverse = undefined++{-@ focusDown :: UStack a -> UStack a @-}+focusDown :: Stack a -> Stack a+focusDown = undefined+-- focusDown = reverseStack . focusUp . reverseStack++-- | reverse a stack: up becomes down and down becomes up.+{-@ reverseStack :: UStack a -> UStack a @-}+reverseStack :: Stack a -> Stack a+reverseStack = undefined+-- reverseStack (Stack t ls rs) = Stack t rs ls
tests/test.hs view
@@ -10,7 +10,6 @@ import qualified Control.Monad.State as State import Control.Monad.Trans.Class (lift) import Data.Char-import Data.Foldable (foldMap) import qualified Data.Functor.Compose as Functor import qualified Data.IntMap as IntMap import Data.Maybe (fromMaybe)@@ -31,16 +30,21 @@ import Test.Tasty.Ingredients.Rerun import Test.Tasty.Options import Test.Tasty.Runners+import Test.Tasty.Runners.AntXML+ import Text.Printf testRunner = rerunningTests [ listingTests- , combineReporters consoleTestReporter loggingTestReporter+ , combineReporters myConsoleReporter antXMLRunner+ , myConsoleReporter ] +myConsoleReporter = combineReporters consoleTestReporter loggingTestReporter main :: IO ()-main = run =<< tests+main = do unsetEnv "LIQUIDHASKELL_OPTS"+ run =<< tests where run = defaultMainWithIngredients [ testRunner@@ -48,8 +52,8 @@ , Option (Proxy :: Proxy LiquidOpts) , Option (Proxy :: Proxy SmtSolver) ] ]- tests = group "Tests" [ unitTests, benchTests ]+ -- tests = group "Tests" [ selfTests ] data SmtSolver = Z3 | CVC4 deriving (Show, Read, Eq, Ord, Typeable) instance IsOption SmtSolver where@@ -82,44 +86,52 @@ , testGroup "crash" <$> dirTests "tests/crash" [] (ExitFailure 2) , testGroup "parser/pos" <$> dirTests "tests/parser/pos" [] ExitSuccess , testGroup "error/crash" <$> dirTests "tests/error_messages/crash" [] (ExitFailure 2)+ , testGroup "eq_pos" <$> dirTests "tests/equationalproofs/pos" ["Axiomatize.hs"] ExitSuccess+ , testGroup "eq_neg" <$> dirTests "tests/equationalproofs/neg" ["Axiomatize.hs"] (ExitFailure 1) ] benchTests = group "Benchmarks" [- testGroup "text" <$> dirTests "benchmarks/text-0.11.2.3" textIgnored ExitSuccess- , testGroup "bytestring" <$> dirTests "benchmarks/bytestring-0.9.2.1" [] ExitSuccess- , testGroup "esop" <$> dirTests "benchmarks/esop2013-submission" ["Base0.hs"] ExitSuccess- , testGroup "vect-algs" <$> dirTests "benchmarks/vector-algorithms-0.5.4.2" [] ExitSuccess- , testGroup "hscolour" <$> dirTests "benchmarks/hscolour-1.20.0.0" [] ExitSuccess- , testGroup "icfp_pos" <$> dirTests "benchmarks/icfp15/pos" [] ExitSuccess- , testGroup "icfp_neg" <$> dirTests "benchmarks/icfp15/neg" ["RIO.hs", "DataBase.hs"] (ExitFailure 1)+ testGroup "text" <$> dirTests "benchmarks/text-0.11.2.3" textIgnored ExitSuccess+ , testGroup "bytestring" <$> dirTests "benchmarks/bytestring-0.9.2.1" [] ExitSuccess+ , testGroup "esop" <$> dirTests "benchmarks/esop2013-submission" ["Base0.hs"] ExitSuccess+ , testGroup "vect-algs" <$> dirTests "benchmarks/vector-algorithms-0.5.4.2" [] ExitSuccess+ , testGroup "hscolour" <$> dirTests "benchmarks/hscolour-1.20.0.0" ["HsColour.hs"] ExitSuccess+ , testGroup "icfp_pos" <$> dirTests "benchmarks/icfp15/pos" ["RIO.hs", "DataBase.hs"] ExitSuccess+ , testGroup "icfp_neg" <$> dirTests "benchmarks/icfp15/neg" ["RIO.hs", "DataBase.hs"] (ExitFailure 1) ] +selfTests+ = group "Self" [+ testGroup "liquid" <$> dirTests "src" [] ExitSuccess+ ]+ --------------------------------------------------------------------------- dirTests :: FilePath -> [FilePath] -> ExitCode -> IO [TestTree] --------------------------------------------------------------------------- dirTests root ignored code = do files <- walkDirectory root let tests = [ rel | f <- files, isTest f, let rel = makeRelative root f, rel `notElem` ignored ]- return $ mkTest code root <$> tests -- hs f code | f <- hs]+ return $ mkTest code root <$> tests isTest :: FilePath -> Bool-isTest f = takeExtension f == ".hs" -- `elem` [".hs", ".lhs"]+isTest f = takeExtension f == ".hs"+ || takeExtension f == ".lhs" --------------------------------------------------------------------------- mkTest :: ExitCode -> FilePath -> FilePath -> TestTree --------------------------------------------------------------------------- mkTest code dir file- = askOption $ \(smt :: SmtSolver) -> askOption $ \(opts :: LiquidOpts) -> testCase file $ do+ = askOption $ \(smt :: SmtSolver) -> askOption $ \(opts :: LiquidOpts) -> testCase file $ if test `elem` knownToFail smt then do printf "%s is known to fail with %s: SKIPPING" test (show smt) assertEqual "" True True else do createDirectoryIfMissing True $ takeDirectory log- liquid <- binPath "liquid"+ bin <- binPath "liquid" withFile log WriteMode $ \h -> do- let cmd = testCmd liquid dir file smt opts+ let cmd = testCmd bin dir file smt opts (_,_,_,ph) <- createProcess $ (shell cmd) {std_out = UseHandle h, std_err = UseHandle h} c <- waitForProcess ph renameFile log $ log <.> (if code == c then "pass" else "fail")@@ -130,20 +142,30 @@ test = dir </> file log = "tests/logs/cur" </> test <.> "log" -binPath pkgName = do +binPath pkgName = do testPath <- getExecutablePath- return $ (takeDirectory $ takeDirectory testPath) </> pkgName </> pkgName - -knownToFail CVC4 = [ "tests/pos/linspace.hs", "tests/pos/RealProps.hs", "tests/pos/RealProps1.hs", "tests/pos/initarray.hs"- , "tests/pos/maps.hs", "tests/pos/maps1.hs", "tests/neg/maps.hs"- , "tests/pos/Product.hs" ]-knownToFail Z3 = [ "tests/pos/linspace.hs" ]+ return $ (takeDirectory $ takeDirectory testPath) </> pkgName </> pkgName +knownToFail CVC4 = [ "tests/pos/linspace.hs"+ , "tests/pos/RealProps.hs"+ , "tests/pos/RealProps1.hs"+ , "tests/pos/initarray.hs"+ , "tests/pos/maps.hs"+ , "tests/pos/maps1.hs"+ , "tests/neg/maps.hs"+ , "tests/pos/Product.hs"+ , "tests/pos/Gradual.hs"+ ]++knownToFail Z3 = [ "tests/pos/linspace.hs"+ , "tests/pos/Gradual.hs"+ ]+ --------------------------------------------------------------------------- testCmd :: FilePath -> FilePath -> FilePath -> SmtSolver -> LiquidOpts -> String ----------------------------------------------------------------------------testCmd liquid dir file smt (LO opts)- = printf "cd %s && %s --verbose --smtsolver %s %s %s" dir liquid (show smt) file opts+testCmd bin dir file smt (LO opts)+ = printf "cd %s && %s --smtsolver %s %s %s" dir bin (show smt) file opts textIgnored = [ "Data/Text/Axioms.hs"@@ -188,14 +210,41 @@ group n xs = testGroup n <$> sequence xs +gitTimestamp :: IO String+gitTimestamp = do+ res <- readProcess "git" ["show", "--format=\"%ci\"", "--quiet"] []+ return $ filter notNoise res++gitEpochTimestamp :: IO String+gitEpochTimestamp = do+ res <- readProcess "git" ["show", "--format=\"%ct\"", "--quiet"] []+ return $ filter notNoise res++gitHash :: IO String+gitHash = do+ res <- readProcess "git" ["show", "--format=\"%H\"", "--quiet"] []+ return $ filter notNoise res++gitRef :: IO String+gitRef = do+ res <- readProcess "git" ["show", "--format=\"%d\"", "--quiet"] []+ return $ filter notNoise res++notNoise :: Char -> Bool+notNoise a = a /= '\"' && a /= '\n' && a /= '\r'++headerDelim :: String+headerDelim = take 80 $ repeat '-'+ ---------------------------------------------------------------------------------------- walkDirectory :: FilePath -> IO [FilePath] ---------------------------------------------------------------------------------------- walkDirectory root- = do (ds,fs) <- partitionM doesDirectoryExist . candidates =<< (getDirectoryContents root `catchIOError` const (return []))- (fs++) <$> concatMapM walkDirectory ds- where- candidates fs = [root </> f | f <- fs, not (isExtSeparator (head f))]+ = do -- RJ: delete root </> ".liquid"+ (ds,fs) <- partitionM doesDirectoryExist . candidates =<< (getDirectoryContents root `catchIOError` const (return []))+ (fs ++) <$> concatMapM walkDirectory ds+ where+ candidates fs = [root </> f | f <- fs, not (isExtSeparator (head f))] partitionM :: Monad m => (a -> m Bool) -> [a] -> m ([a],[a]) partitionM f = go [] []@@ -209,7 +258,7 @@ -- isDirectory = fmap Posix.isDirectory . Posix.getFileStatus concatMapM :: Applicative m => (a -> m [b]) -> [a] -> m [b]-concatMapM f [] = pure []+concatMapM _ [] = pure [] concatMapM f (x:xs) = (++) <$> f x <*> concatMapM f xs -- | Combine two @TestReporter@s into one.@@ -221,6 +270,7 @@ f1 <- run1 opts tree f2 <- run2 opts tree return $ \smap -> f1 smap >> f2 smap+combineReporters _ _ = error "combineReporters needs TestReporters" type Summary = [(String, Double, Bool)] @@ -280,10 +330,21 @@ host <- takeWhile (/='.') . takeWhile (not . isSpace) <$> readProcess "hostname" [] [] -- don't use the `time` package, major api differences between ghc 708 and 710 time <- head . lines <$> readProcess "date" ["+%Y-%m-%dT%H-%M-%S"] []+ -- build header+ ref <- gitRef+ timestamp <- gitTimestamp+ epochTime <- gitEpochTimestamp+ hash <- gitHash+ let hdr = unlines [ref ++ " : " ++ hash,+ "Timestamp: " ++ timestamp,+ "Epoch Timestamp: " ++ epochTime,+ headerDelim,+ "test, time(s), result"]+ let dir = "tests" </> "logs" </> host ++ "-" ++ time- let path = dir </> "summary.csv"- system $ "cp -r tests/logs/cur " ++ dir- writeFile path $ unlines- $ "test, time(s), result"+ let smry = "tests" </> "logs" </> "cur" </> "summary.csv"+ writeFile smry $ unlines+ $ hdr : map (\(n, t, r) -> printf "%s, %0.4f, %s" n t (show r)) summary+ system $ "cp -r tests/logs/cur " ++ dir (==0) <$> computeFailures smap