0 | module TTImp.ProcessRecord
4 | import Core.UnifyState
6 | import Idris.REPL.Opts
9 | import TTImp.BindImplicits
10 | import TTImp.Elab.Check
12 | import TTImp.TTImp.Functor
13 | import TTImp.TTImp.Traversals
17 | import Libraries.Data.WithDefault
26 | killHole : RawImp -> RawImp
27 | killHole (IHole fc str) = Implicit fc True
31 | projVis : Visibility -> Visibility
32 | projVis Public = Public
35 | elabRecord : {vars : _} ->
36 | {auto c : Ref Ctxt Defs} ->
37 | {auto m : Ref MD Metadata} ->
38 | {auto u : Ref UST UState} ->
39 | {auto s : Ref Syn SyntaxInfo} ->
40 | {auto o : Ref ROpts REPLOpts} ->
41 | List ElabOpt -> FC -> Env Term vars ->
42 | NestedNames vars -> Maybe String ->
43 | WithDefault Visibility Private ->
46 | (params : List ImpParameter) ->
47 | (opts : List DataOpt) ->
51 | elabRecord {vars} eopts fc env nest newns def_vis mbtot tn_in params0 opts conName_in fields
52 | = do tn <- inCurrentNS tn_in
53 | conName <- inCurrentNS conName_in
54 | params <- preElabAsData tn
55 | log "declare.record.parameters" 100 $
56 | unlines ("New list of parameters:" :: map ((" " ++) . displayParam) params)
57 | elabAsData tn conName params
59 | Just conty <- lookupTyExact conName (gamma defs)
60 | | Nothing => throw (InternalError ("Adding " ++ show tn ++ "failed"))
63 | whenJust mbtot $
\tot => do
64 | log "declare.record" 5 $
"setting totality flag for " ++ show tn
65 | setFlag fc tn (SetTotal tot)
69 | Nothing => elabGetters tn conName params 0 [] Env.empty conty
71 | do let cns = currentNS defs
72 | let nns = nestedNS defs
73 | extendNS (mkNamespace ns)
75 | elabGetters tn conName params 0 [] Env.empty conty
78 | update Ctxt { currentNS := cns,
79 | nestedNS := newns :: nns }
83 | displayParam : ImpParameter -> String
85 | = withPiInfo binder.val.info "\{showCount binder.rig}\{show binder.name.val} : \{show binder.val.boundType}"
87 | paramTelescope : List ImpParameter -> List (AddFC $
WithRig $
WithMName (PiBindData RawImp))
88 | paramTelescope params = map jname params
90 | jname : ImpParameter
91 | -> (AddFC $
WithRig $
WithMName (PiBindData RawImp))
94 | jname binder = Mk [EmptyFC, erased, Just binder.name] $
{info := Implicit} binder.val
96 | fname : IField -> Name
97 | fname field = field.name.val
99 | farg : IField -> AddFC (WithRig $
WithMName (PiBindData RawImp))
100 | farg field = Mk [virtualiseFC field.fc, field.rig, Just field.name] field.val
102 | mkTy : List (AddFC $
WithRig $
WithMName (PiBindData RawImp)) -> RawImp -> RawImp
104 | mkTy (bind :: args) ret
105 | = IPi bind.fc bind.rig bind.val.info (map val bind.mName) bind.val.boundType (mkTy args ret)
107 | recTy : (tn : Name) ->
108 | (params : List ImpParameter) ->
110 | recTy tn params = apply (IVar (virtualiseFC fc) tn) (map (\binder => (binder.name.val, IVar EmptyFC binder.name.val, binder.val.info)) params)
113 | apply : RawImp -> List (Name, RawImp, PiInfo RawImp) -> RawImp
115 | apply f ((n, arg, Explicit) :: xs) = apply (IApp (getFC f) f arg) xs
116 | apply f ((n, arg, _ ) :: xs) = apply (INamedApp (getFC f) f n arg) xs
118 | paramNames : List ImpParameter -> List Name
119 | paramNames params = map (.name.val) params
121 | mkDataTy : FC -> List ImpParameter -> RawImp
122 | mkDataTy fc [] = IType fc
123 | mkDataTy fc (binder :: ps) = IPi fc binder.rig binder.val.info (Just binder.name.val) binder.val.boundType (mkDataTy fc ps)
125 | nestDrop : Core (List (Name, Nat))
127 | = do let assoc = map (\ (n, (_, ns, _)) => (n, length ns)) (names nest)
128 | traverse (\ (n, ns) => pure (!(toFullNames n), ns)) assoc
137 | preElabAsData : (tn : Name) ->
138 | Core (List ImpParameter)
140 | = do let fc = virtualiseFC fc
141 | let dataTy = IBindHere fc (PI erased) !(bindTypeNames fc [] (toList vars) (mkDataTy fc params0))
144 | when (isNothing !(lookupTyExact tn (gamma defs))) $
do
145 | let dt = MkImpLater fc tn dataTy
146 | log "declare.record" 10 $
"Pre-declare record data type: \{show dt}"
147 | processDecl [] nest env (IData fc def_vis mbtot dt)
149 | Just ty <- lookupTyExact tn (gamma defs)
150 | | Nothing => throw (InternalError "Missing data type \{show tn}, despite having just declared it!")
151 | log "declare.record" 20 "Obtained type: \{show ty}"
152 | (
_ ** (tyenv, ty))
<- dropLeadingPis vars ty Env.empty
153 | ty <- unelabNest (NoSugar True) !nestDrop tyenv ty
154 | log "declare.record.parameters" 30 "Unelaborated type: \{show ty}"
155 | params <- getParameters [<] ty
156 | addMissingNames ([<] <>< map (\x => x.name) params0 ) params []
164 | dropLeadingPis : {vs : _} -> (vars : Scope) -> Term vs -> Env Term vs ->
165 | Core (vars' : Scope ** (Env Term vars', Term vars'))
166 | dropLeadingPis [] ty env
167 | = do unless (null vars) $
168 | logC "declare.record.parameters" 60 $
pure $
unlines
169 | [ "We elaborated \{show tn} in a non-empty local context."
170 | , " Dropped: \{show vars}"
171 | , " Remaining type: \{show !(toFullNames ty)}"
173 | pure (
_ ** (env, ty))
174 | dropLeadingPis (var :: vars) (Bind fc n b@(Pi {}) ty) env
175 | = dropLeadingPis vars ty (b :: env)
176 | dropLeadingPis _ ty _ = throw (InternalError "Malformed record type \{show ty}")
179 | SnocList (WithRig $
WithMName $
PiBindData RawImp) ->
180 | RawImp' KindedName ->
181 | Core (SnocList (WithRig $
WithMName $
PiBindData RawImp))
182 | getParameters acc (IPi fc rig pinfo mnm argTy retTy)
183 | = let clean = mapTTImp killHole . map fullName in
184 | getParameters (acc :< (Mk [rig, map NoFC mnm] (MkPiBindData (map clean pinfo) (clean argTy)))) retTy
185 | getParameters acc (IType _) = pure acc
186 | getParameters acc ty = throw (InternalError "Malformed record type \{show ty}")
189 | SnocList (WithFC Name) ->
190 | SnocList (WithRig $
WithMName $
PiBindData RawImp) ->
191 | List ImpParameter ->
192 | Core (List ImpParameter)
193 | addMissingNames (nms :< nm) (tele :< rest) acc
194 | = addMissingNames nms tele (Mk [rest.rig, nm] rest.val :: acc)
195 | addMissingNames [<] tele acc
196 | = do tele <- flip Core.traverseSnocList tele $
\ rest =>
198 | Nothing => throw (InternalError "Some names have disappeared?! \{show rest.val}")
199 | Just nm => pure (Mk [rest.rig, nm] rest.val)
200 | unless (null tele) $
201 | log "declare.record.parameters" 50 $
202 | unlines ( "Decided to bind the following extra parameters:"
203 | :: map ((" " ++) . displayParam) (tele <>> []))
204 | pure (tele <>> acc)
206 | addMissingNames nms [<] acc
207 | = throw (InternalError "Some arguments have disappeared")
210 | elabAsData : (tn : Name) ->
211 | (conName : Name) ->
212 | (params : List ImpParameter) ->
214 | elabAsData tn cname params
215 | = do let fc = virtualiseFC fc
216 | let conty = mkTy (paramTelescope params) $
217 | mkTy (map farg fields) (recTy tn params)
218 | let boundNames = paramNames params ++ map fname fields ++ (toList vars)
219 | let con = Mk [virtualiseFC fc, NoFC cname]
220 | !(bindTypeNames fc [] boundNames conty)
221 | let dt = MkImpData fc tn Nothing opts [con]
222 | log "declare.record" 5 $
"Record data type " ++ show dt
223 | processDecl [] nest env (IData fc def_vis mbtot dt)
225 | countExp : Term vs -> Nat
226 | countExp (Bind _ _ (Pi _ _ Explicit _) sc) = S (countExp sc)
227 | countExp (Bind _ _ (Pi {}) sc) = countExp sc
235 | elabGetters : {vs : _} ->
237 | (conName : Name) ->
238 | (params : List ImpParameter) ->
240 | List (Name, RawImp) ->
243 | Env Term vs -> Term vs ->
245 | elabGetters tn con params done upds tyenv (Bind bfc n b@(Pi _ rc imp ty_chk) sc)
246 | = let rig = if isErased rc then erased else top
247 | isVis = projVis (collapseDefault def_vis)
248 | paramNames = map (\x => x.name.val) params
249 | in if (n `elem` paramNames) || (n `elem` vars)
250 | then elabGetters tn con params
251 | (if imp == Explicit && not (n `elem` vars)
252 | then S done else done)
253 | upds (b :: tyenv) sc
255 | do let fldNameStr = nameRoot n
256 | let unName = UN $
Basic fldNameStr
257 | rfNameNS <- inCurrentNS (UN $
Field fldNameStr)
258 | unNameNS <- inCurrentNS unName
260 | ty <- unelabNest (NoSugar False) !nestDrop tyenv ty_chk
261 | let ty' = substNames (toList vars) upds $
map rawName ty
262 | log "declare.record.field" 5 $
"Field type: " ++ show ty'
263 | let rname = MN "rec" 0
266 | projTy <- bindTypeNames fc []
267 | (paramNames ++ map fname fields ++ toList vars) $
268 | mkTy (paramTelescope params) $
269 | IPi bfc top Explicit (Just rname) (recTy tn params) ty'
270 | let fc' = virtualiseFC fc
271 | let mkProjClaim = \ nm =>
272 | let ty = Mk [fc', MkFCVal fc' nm] projTy
273 | in IClaim (MkFCVal bfc (MkIClaimData rig isVis [Inline] ty))
275 | log "declare.record.projection.claim" 5 $
276 | "Projection " ++ show rfNameNS ++ ": " ++ show projTy
277 | processDecl [] nest env (mkProjClaim rfNameNS)
281 | = apply (IVar bfc con)
282 | (replicate done (Implicit bfc True) ++
283 | (if imp == Explicit
284 | then [IBindVar fc' unName]
286 | (replicate (countExp sc) (Implicit bfc True)))
287 | let lhs = IApp bfc (IVar bfc rfNameNS)
288 | (if imp == Explicit
290 | else INamedApp bfc lhs_exp unName
291 | (IBindVar bfc unName))
292 | let rhs = IVar fc' unName
297 | (lhs, rhs) <- etaExpandImplicits fc' ty' lhs rhs
299 | log "declare.record.projection.clause" 5 $
"Projection " ++ show lhs ++ " = " ++ show rhs
300 | processDecl [] nest env
301 | (IDef bfc rfNameNS [PatClause bfc lhs rhs])
304 | when !isPrefixRecordProjections $
do
307 | log "declare.record.projection.prefix" 5 $
308 | "Prefix projection " ++ show unNameNS ++ " : " ++ show projTy
309 | processDecl [] nest env (mkProjClaim unNameNS)
312 | let lhs = IVar bfc unNameNS
313 | let rhs = IVar bfc rfNameNS
314 | log "declare.record.projection.prefix" 5 $
315 | "Prefix projection " ++ show lhs ++ " = " ++ show rhs
316 | processDecl [] nest env
317 | (IDef bfc unNameNS [PatClause bfc lhs rhs])
328 | prefix_flag <- isPrefixRecordProjections
329 | let upds' = if prefix_flag
330 | then (n, IApp bfc (IVar bfc unNameNS) (IVar bfc rname)) :: upds
331 | else (n, IApp bfc (IVar bfc rfNameNS) (IVar bfc rname)) :: upds
333 | elabGetters tn con params
334 | (if imp == Explicit
335 | then S done else done)
336 | upds' (b :: tyenv) sc
338 | elabGetters tn con _ done upds _ _ = pure ()
341 | processRecord : {vars : _} ->
342 | {auto c : Ref Ctxt Defs} ->
343 | {auto m : Ref MD Metadata} ->
344 | {auto u : Ref UST UState} ->
345 | {auto s : Ref Syn SyntaxInfo} ->
346 | {auto o : Ref ROpts REPLOpts} ->
347 | List ElabOpt -> NestedNames vars ->
348 | Env Term vars -> Maybe String ->
349 | WithDefault Visibility Private -> Maybe TotalReq ->
350 | ImpRecord -> Core ()
351 | processRecord eopts nest env newns def_vis mbtot rec@(MkWithData _ $
MkImpRecord header body)
352 | = elabRecord eopts rec.fc env nest newns def_vis mbtot header.name.val header.val body.opts body.name.val body.val