0 | module Language.Reflection.Compat.TypeInfo
4 | import Data.SortedMap
5 | import Data.SortedSet
7 | import public Language.Reflection.Compat.Constr
8 | import public Language.Reflection.Expr
10 | import public Syntax.IHateParens.SortedSet
19 | typeCon : TypeInfo -> Con
20 | typeCon ti = MkCon ti.name ti.args type
24 | (.decl) : TypeInfo -> Decl
26 | iData Public ti.name tySig [] conITys
28 | tySig = piAll type ti.args
29 | conITys = (.iTy) <$> ti.cons
37 | allInvolvedTypes : Elaboration m => (minimalRig : Count) -> TypeInfo -> m $
List TypeInfo
38 | allInvolvedTypes minimalRig ti = toList <$> go [ti] empty where
39 | go : (left : List TypeInfo) -> (curr : SortedMap Name TypeInfo) -> m $
SortedMap Name TypeInfo
41 | let (c::left) = filter (not . isJust . lookup' curr . name) left
43 | let next = insert c.name c curr
44 | args <- atRig M0 $
join <$> for c.args typesOfArg
45 | cons <- join <$> for c.tyCons typesOfCon
46 | assert_total $
go (args ++ cons ++ left) next
48 | atRig : Count -> m (List a) -> m (List a)
49 | atRig rig act = if rig >= minimalRig then act else pure []
51 | typesOfExpr : TTImp -> m $
List TypeInfo
52 | typesOfExpr expr = map (mapMaybe id) $
for (allVarNames expr) $
catch . getInfo'
54 | typesOfArg : Arg -> m $
List TypeInfo
55 | typesOfArg arg = atRig arg.count $
typesOfExpr arg.type
57 | typesOfCon : Con -> m $
List TypeInfo
58 | typesOfCon con = [| atRig M0 (typesOfExpr con.type) ++ (join <$> for con.args typesOfArg) |]
62 | ensureTyArgsNamed : Elaboration m => (ty : TypeInfo) -> m $
AllTyArgsNamed ty
63 | ensureTyArgsNamed ty = do
64 | let Yes prf = areAllTyArgsNamed ty
65 | | No _ => fail "Type info for type `\{ty.name}` contains unnamed arguments"
69 | (.argNames) : (ti : TypeInfo) -> (0 tiN : AllTyArgsNamed ti) => List Name
70 | (.argNames) ti = argNames ti.args @{tiN.tyArgsNamed}
76 | normaliseCons : Elaboration m => TypeInfo -> m TypeInfo
77 | normaliseCons ty = for ty.cons normaliseCon <&> \cons' => {cons := cons'} ty
84 | record NamesInfoInTypes where
86 | types : ListMap Name TypeInfo
87 | cons : ListMap Name (TypeInfo, Con)
88 | namesInTypes : ListMap TypeInfo $
SortedSet Name
90 | lookupByType : NamesInfoInTypes => Name -> Maybe $
SortedSet Name
91 | lookupByType @{tyi} = lookup' tyi.types >=> lookup' tyi.namesInTypes
93 | lookupByCon : NamesInfoInTypes => Name -> Maybe $
SortedSet Name
94 | lookupByCon @{tyi} = concatMap @{Deep} lookupByType . Prelude.toList . concatMap allVarNames' . conSubexprs . snd <=< lookup' tyi.cons
96 | typeByCon : NamesInfoInTypes => Con -> Maybe TypeInfo
97 | typeByCon @{tyi} = map fst . lookup' tyi.cons . name
100 | lookupType : NamesInfoInTypes => Name -> Maybe TypeInfo
101 | lookupType @{tyi} = lookup' tyi.types
104 | lookupCon : NamesInfoInTypes => Name -> Maybe Con
105 | lookupCon @{tyi} n = snd <$> lookup n tyi.cons
106 | <|> typeCon <$> lookup n tyi.types
109 | knownTypes : NamesInfoInTypes => ListMap Name TypeInfo
110 | knownTypes @{tyi} = tyi.types
116 | resolveNamesUniquely : NamesInfoInTypes => (freeNames : SortedSet Name) -> TTImp -> Either (Name, SortedSet Name) TTImp
117 | resolveNamesUniquely @{tyi} freeNames = do
118 | let allConsideredNames = keySet tyi.types `union` keySet tyi.cons
119 | let reverseNamesMap = concatMap (uncurry SortedMap.singleton) $
allConsideredNames.asList >>= \n => allNameSuffixes n <&> (, SortedSet.singleton n)
121 | v@(IVar fc n) => if contains n freeNames then id else do
122 | let Just resolvedAlts = lookup n reverseNamesMap | Nothing => id
123 | let [resolved] = Prelude.toList resolvedAlts
124 | | _ => const $
Left (n, resolvedAlts)
125 | const $
pure $
IVar fc resolved
129 | [TypeInfoEqByName] Eq TypeInfo where
130 | (==) = (==) `on` name
133 | [TypeInfoOrdByName] Ord TypeInfo using TypeInfoEqByName where
134 | compare = comparing name
137 | Semigroup NamesInfoInTypes where
138 | Names ts cs nit <+> Names ts' cs' nit' = Names (ts `mergeLeft` ts') (cs `mergeLeft` cs') (nit <+> nit')
140 | Monoid NamesInfoInTypes where
141 | neutral = let _ = TypeInfoEqByName
142 | in Names empty empty empty
145 | hasNameInsideDeep : NamesInfoInTypes => Name -> TTImp -> Bool
146 | hasNameInsideDeep @{tyi} nm = hasInside empty . allVarNames where
148 | hasInside : (visited : SortedSet Name) -> (toLook : List Name) -> Bool
149 | hasInside visited [] = False
150 | hasInside visited (curr::rest) = if curr == nm then True else do
151 | let new = if contains curr visited then [] else maybe [] Prelude.toList $
lookupByType curr
153 | assert_total $
hasInside (insert curr visited) (new ++ rest)
156 | isRecursive : NamesInfoInTypes => (con : Con) -> {default Nothing containingType : Maybe TypeInfo} -> Bool
157 | isRecursive con = case the (Maybe TypeInfo) $
containingType <|> typeByCon con of
158 | Just containingType => any (hasNameInsideDeep containingType.name) $
conSubexprs con
163 | isRecursiveConstructor : NamesInfoInTypes => Name -> Maybe Bool
164 | isRecursiveConstructor @{tyi} n = lookup' tyi.cons n <&> \(ty, con) => isRecursive {containingType=Just ty} con
167 | enrichNamesInfoInTypes : Elaboration m => List TypeInfo -> NamesInfoInTypes -> m NamesInfoInTypes
168 | enrichNamesInfoInTypes [] tyi = pure tyi
169 | enrichNamesInfoInTypes (ti::rest) tyi = do
170 | ti <- normaliseCons ti
171 | let subes = concatMap allVarNames' $
subexprs ti
172 | new <- map join $
for (Prelude.toList subes) $
\n =>
173 | if isNothing $
lookupByType n
174 | then map toList $
catch $
getInfo' n
176 | let next = { types $= insert ti.name ti
177 | , namesInTypes $= insert ti subes
178 | , cons $= mergeLeft $
fromList $
ti.cons <&> \con => (con.name, ti, con)
180 | assert_total $
enrichNamesInfoInTypes (new ++ rest) next
182 | subexprs : TypeInfo -> List TTImp
183 | subexprs ty = map type ty.args ++ (ty.cons >>= conSubexprs)
186 | getNamesInfoInTypes : Elaboration m => TypeInfo -> m NamesInfoInTypes
187 | getNamesInfoInTypes ty = enrichNamesInfoInTypes [ty] neutral
190 | getNamesInfoInTypes' : Elaboration m => TTImp -> m NamesInfoInTypes
191 | getNamesInfoInTypes' expr = do
192 | let varsFirstOrder = allVarNames expr
193 | varsSecondOrder <- map concat $
for varsFirstOrder $
\n => do
195 | pure $
SortedSet.insert n $
flip concatMap ns $
\(n', ty) => insert n' $
allVarNames' ty
196 | tys <- map (mapMaybe id) $
for (Prelude.toList varsSecondOrder) $
catch . getInfo'
197 | concat <$> Prelude.for tys getNamesInfoInTypes