1 | module Deriving.DepTyCheck.Gen.ForOneTypeCon.Impl
3 | import public Control.Monad.Error.Either
4 | import public Control.Monad.State
5 | import public Control.Monad.State.Tuple
6 | import public Control.Monad.Writer
8 | import public Deriving.DepTyCheck.Gen.ForOneTypeConRhs.Interface
9 | import public Deriving.DepTyCheck.Util.DeepConsApp
17 | isSimpleBindVar : TTImp -> Bool
18 | isSimpleBindVar $
IBindVar {} = True
19 | isSimpleBindVar _ = False
22 | canonicConsBody : DeriveBodyRhsForCon => DerivationClosure m => Elaboration m => NamesInfoInTypes => ConsRecs =>
23 | GenSignature -> Name -> Con -> m $
List Clause
24 | canonicConsBody sig name con = do
27 | let conFC = getFC con.type
30 | con <- normaliseCon con
33 | let (conRetTy, conRetTypeArgs) = unAppAny con.type
34 | let conRetTypeArgs = conRetTypeArgs <&> getExpr
37 | let Yes conRetTypeArgsLengthCorrect = conRetTypeArgs.length `decEq` sig.targetType.args.length
38 | | No _ => failAt conFC "INTERNAL ERROR: length of the return type does not equal to the type's arguments count"
40 | let conRetTypeArg : Fin sig.targetType.args.length -> TTImp
41 | conRetTypeArg idx = index' conRetTypeArgs $
rewrite conRetTypeArgsLengthCorrect in idx
44 | let conArgNames = fromList $
argName' <$> con.args
47 | let depOfGivs = dependeesOfGivens sig
56 | deepConsApps : Vect _ $
DeepConsAnalysisRes True <- for sig.givenParams.asVect $
\idx => do
57 | let argExpr = conRetTypeArg idx
58 | let (fns, errs) = runWriter {w=List String} $
analyseDeepConsApp True conArgNames argExpr
59 | when (not $
null errs) $
failAt conFC $
60 | "Argument #\{show idx} of \{show con.name} with given type arguments [\{showGivens sig}] is not supported, " ++
61 | "argument expression: \{show argExpr}, reason(s): \{joinBy "; " errs}"
63 | pure $
if not $
contains idx depOfGivs then fns else case fns of
64 | (
lst ** f)
=> (
map determineMustDecEqs <$> lst ** rewrite lengthMap {f=map determineMustDecEqs} lst in f)
65 | let allAppliedFreeNames = foldMap (SortedSet.fromList . map fst . fst) deepConsApps
66 | let badDecEqExpr : ConsDetermInfo -> Maybe TTImp
67 | badDecEqExpr (MustDecEqWith e) = whenT (not $
null $
(allVarNames' e `intersection` conArgNames) `difference` allAppliedFreeNames) e
68 | badDecEqExpr _ = Nothing
69 | for_ deepConsApps $
\(
vs ** _)
=> whenJust (foldAlt' vs $
badDecEqExpr . snd) $
\e => failAt conFC $
70 | "Unsupported constructor \{show con.name} with given type arguments [\{showGivens sig}] since it contains " ++
71 | "an undetermined non-constructor expression `\{show e}` as a given"
75 | let getAndInc : forall m. MonadState Nat m => m Nat
76 | getAndInc = get <* modify S
77 | let deceqedName : forall m. MonadState Nat m => Name -> m Name
79 | deceqedName name = pure $
UN $
Basic $
"to_be_deceqed^^" ++ show name ++ show !getAndInc
80 | ((givenConArgs, decEqedNames, _), bindExprs) <-
81 | runStateT (empty, [], 0) {stateType=(SortedSet Name, List (Either TTImp Name, Name), Nat)} {m} $
82 | for deepConsApps $
\(
appliedNames ** bindExprF)
=> do
83 | renamedAppliedNames <- for appliedNames.asVect $
\(name, typeDetermined) =>
84 | case typeDetermined of
85 | DeterminedByType => pure $
const implicitTrue
86 | NotDeterminedByType => if SortedSet.contains name !get
88 | substName <- deceqedName name
89 | modify $
(::) (Right name, substName)
90 | pure $
\alreadyMatchedRenames => bindVar $
if contains substName alreadyMatchedRenames then name else substName
91 | else modify (SortedSet.insert name) $> const (bindVar name)
92 | MustDecEqWith e => do
93 | substName <- deceqedName name
94 | modify $
(::) (Left e, substName)
95 | pure $
\alreadyMatchedRenames => if contains substName alreadyMatchedRenames then implicitTrue else bindVar substName
96 | let _ : Vect appliedNames.length $
SortedSet Name -> TTImp = renamedAppliedNames
97 | pure $
\alreadyMatchedRenames => bindExprF $
\idx => index idx renamedAppliedNames $
alreadyMatchedRenames
98 | let bindExprs = \alreadyMatchedRenames => bindExprs <&> \f => f alreadyMatchedRenames
101 | let conArgIdxs = SortedMap.fromList $
mapI con.args $
\idx, arg => (argName' arg, idx)
104 | givenConArgs <- for givenConArgs.asList $
\givenArgName => do
105 | let Just idx = lookup givenArgName conArgIdxs
106 | | Nothing => failAt conFC "INTERNAL ERROR: calculated given `\{show givenArgName}` is not found in an arguments list of the constructor"
112 | let deceqise : (lhs : Vect sig.givenParams.asList.length TTImp -> TTImp) -> (rhs : TTImp) -> Clause
113 | deceqise lhs rhs = step lhs empty $
orderLikeInCon decEqedNames where
115 | step : (withlhs : Vect sig.givenParams.asList.length TTImp -> TTImp) ->
116 | (alreadyMatchedRenames : SortedSet Name) ->
117 | (left : List (Either TTImp Name, Name)) ->
119 | step withlhs matched [] = PatClause EmptyFC .| withlhs (bindExprs matched) .| rhs
120 | step withlhs matched ((orig, renam)::rest) =
121 | WithClause EmptyFC (withlhs $
bindExprs matched) MW
122 | `(Decidable.Equality.decEq
~(var renam) ~(either id var orig))
125 | step ((.$ `(Prelude.Yes Builtin.Refl
)) . withlhs) (insert renam matched) rest
127 | PatClause EmptyFC .| withlhs (bindExprs matched) .$ `(Prelude.No
_) .| `(empty
)
131 | orderLikeInCon : Foldable f => f (Either TTImp Name, Name) -> List (Either TTImp Name, Name)
132 | orderLikeInCon = do
133 | let conArgNames = mapMaybe Arg.name con.args
134 | let conNameToIdx : SortedMap _ $
Fin conArgNames.length := fromList $
mapI conArgNames $
flip (,)
135 | let [AsInCon] Ord (Either TTImp Name, Name) where
136 | compare (Left _, _) (Right _, _) = LT
137 | compare (Right _, _) (Left _, _) = GT
138 | compare (Right origL, renL) (Right origR, renR) = comparing (lookup' conNameToIdx) origL origR <+> compare renL renR
139 | compare (Left _, renL) (Left _, renR) = compare renL renR
140 | Prelude.toList . foldl SortedSet.insert' (empty @{AsInCon})
143 | let fuelArg = "^cons_fuel^"
146 | [ deceqise (callCanonic sig name $
bindVar fuelArg) !(consGenExpr sig con .| fromList givenConArgs .| var fuelArg) ]
147 | ++ if all isSimpleBindVar $
bindExprs SortedSet.empty then [] else
149 | [ callCanonic sig name implicitTrue (replicate _ implicitTrue) .= `(empty
) ]