0 | module Deriving.DepTyCheck.Util.DeepConsApp
2 | import public Control.Monad.Writer.Interface
4 | import public Data.Fin.Split
5 | import public Data.List.Ex
6 | import public Data.List.Map
7 | import public Data.List.Set
8 | import public Data.SortedSet
9 | import public Data.Vect.Ex
11 | import public Language.Reflection.Compat.TypeInfo
13 | import Deriving.Show
16 | %language ElabReflection
19 | data ConsDetermInfo = DeterminedByType | NotDeterminedByType | MustDecEqWith TTImp
22 | ShowConsDetermInfo : Show ConsDetermInfo
23 | ShowConsDetermInfo = %runElab derive
26 | Cast Bool ConsDetermInfo where
27 | cast True = DeterminedByType
28 | cast False = NotDeterminedByType
31 | Cast ConsDetermInfo Bool where
32 | cast DeterminedByType = True
33 | cast NotDeterminedByType = False
34 | cast $
MustDecEqWith {} = False
37 | determineMustDecEqs : ConsDetermInfo -> ConsDetermInfo
38 | determineMustDecEqs DeterminedByType = DeterminedByType
39 | determineMustDecEqs NotDeterminedByType = NotDeterminedByType
40 | determineMustDecEqs $
MustDecEqWith {} = DeterminedByType
43 | Semigroup ConsDetermInfo where
44 | x@(MustDecEqWith {}) <+> MustDecEqWith {} = x
45 | MustDecEqWith {} <+> DeterminedByType = DeterminedByType
46 | DeterminedByType <+> MustDecEqWith {} = DeterminedByType
47 | DeterminedByType <+> DeterminedByType = DeterminedByType
48 | NotDeterminedByType <+> x = x
49 | x <+> NotDeterminedByType = x
52 | Monoid ConsDetermInfo where
53 | neutral = NotDeterminedByType
56 | BindExprFun : Nat -> Type
57 | BindExprFun n = (bindExpr : Fin n -> TTImp) -> TTImp
60 | DeepConsAnalysisRes : (collectConsDetermInfo : Bool) -> Type
61 | DeepConsAnalysisRes False = List Name
62 | DeepConsAnalysisRes True = (appliedFreeNames : List (Name, ConsDetermInfo) ** BindExprFun appliedFreeNames.length)
64 | MaybeConsDetermInfo : Bool -> Type
65 | MaybeConsDetermInfo True = ConsDetermInfo
66 | MaybeConsDetermInfo False = Unit
78 | analyseDeepConsApp : NamesInfoInTypes =>
79 | MonadWriter (List String) m =>
80 | (collectConsDetermInfo : Bool) ->
81 | (freeNames : SortedSet Name) ->
82 | (analysedExpr : TTImp) ->
83 | m $
DeepConsAnalysisRes collectConsDetermInfo
84 | analyseDeepConsApp ccdi freeNames = pass . map (, nub) . isD where
86 | isD : TTImp -> m $
DeepConsAnalysisRes ccdi
90 | let (IVar _ lhsName, args) = unAppAny e
91 | | (IType {} , _) => pure $
noFree e
92 | | (IPrimVal {}, _) => pure $
noFree e
93 | | _ => bad "not an application to a variable"
96 | let False = contains lhsName freeNames && null args
97 | | True => pure $
if ccdi then (
[(lhsName, neutral)] ** \f => f FZ)
else [lhsName]
100 | let Just (conArgs, conType) = lookupCon lhsName <&> \con => (con.args, con.type)
101 | | Nothing => pure $
if ccdi then (
[(MN (show e) 0, MustDecEqWith e)] ** \f => f FZ)
else []
104 | typeDetermInfo : Vect conArgs.length $
MaybeConsDetermInfo ccdi <-
105 | if ccdi then assert_total $
typeDeterminedArgs conArgs conType else pure neutral
107 | let Just typeDetermInfo = reorder typeDetermInfo
108 | | Nothing => bad "INTERNAL ERROR: cannot reorder formal determ info along with a call to a constructor"
111 | deepArgs <- for (args.asVect `zip` typeDetermInfo) $
112 | \(anyApp, typeDetermined) => do
113 | subResult <- isD $
assert_smaller e $
getExpr anyApp
114 | let subResult = if ccdi then mapSnd (<+> typeDetermined) `mapLstDPair` subResult else subResult
115 | pure (anyApp, subResult)
118 | pure $
foldl (mergeApp _) (noFree $
var lhsName) deepArgs
121 | noFree : TTImp -> DeepConsAnalysisRes ccdi
122 | noFree e = if ccdi then (
[] ** const e)
else []
124 | bad : String -> m $
DeepConsAnalysisRes ccdi
125 | bad msg = tell [msg] $> noFree implicitTrue
129 | mergeApp : (ccdi : _) -> DeepConsAnalysisRes ccdi -> (AnyApp, DeepConsAnalysisRes ccdi) -> DeepConsAnalysisRes ccdi
130 | mergeApp False namesL (_, namesR) = namesL ++ namesR
131 | mergeApp True (
namesL ** bindL)
(anyApp, (
namesR ** bindR)
) = MkDPair (namesL ++ namesR) $
\bindNames => do
132 | let bindNames : Fin (namesL.length + namesR.length) -> _ := rewrite sym $
lengthConcat namesL namesR in bindNames
133 | let lhs = bindL $
bindNames . indexSum . Left
134 | let rhs = bindR $
bindNames . indexSum . Right
135 | reAppAny1 lhs $
const rhs `mapExpr` anyApp
137 | mapLstDPair : (a -> b) -> (x : List a ** BindExprFun x.length) -> (x : List b ** BindExprFun x.length)
138 | mapLstDPair f (
lst ** d)
= (
map f lst ** rewrite lengthMap {f} lst in d)
141 | typeDeterminedArgs : (args : List Arg) -> (type : TTImp) -> m $
Vect args.length ConsDetermInfo
142 | typeDeterminedArgs args type = do
143 | let conArgNames = fromList $
mapI args $
\idx, arg => (argName' arg, idx)
144 | determined <- analyseDeepConsApp False (SortedSet.keySet conArgNames) type
145 | let determined = mapMaybe (lookup' conArgNames) determined
146 | pure $
map cast $
presenceVect $
fromList determined
148 | reorder : {formalArgs : List Arg} -> {apps : List AnyApp} -> Vect formalArgs.length a -> Maybe $
Vect apps.length a
149 | reorder xs = reorder' (fromList formalArgs `zip` xs) apps where
150 | reorder' : Vect n (Arg, a) -> (apps : List AnyApp) -> Maybe $
Vect apps.length a
151 | reorder' xs [] = if isJust $
find ((== ExplicitArg) . piInfo . fst) xs
152 | then Nothing else Just []
153 | reorder' [] (_::_) = Nothing
154 | reorder' xs@(_::_) (a::as) = do
155 | let searchFun : Arg -> Bool
156 | searchFun = case a of
157 | PosApp _ => (== ExplicitArg) . piInfo
158 | NamedApp nm _ => \na => isImplicit na.piInfo && na.name == Just nm
159 | AutoApp _ => (== AutoImplicit) . piInfo
160 | WithApp _ => const False
161 | let Just i = findIndex (searchFun . fst) xs
162 | | Nothing => Nothing
163 | let restxs = deleteAt i xs
164 | (snd (index i xs) ::) <$> reorder' restxs as