0 | module Idris.Elab.Implementation
6 | import Idris.REPL.Opts
9 | import TTImp.BindImplicits
10 | import TTImp.Elab.Check
12 | import TTImp.ProcessDecls
14 | import TTImp.TTImp.Functor
18 | import Control.Monad.State
19 | import Libraries.Data.ANameMap
20 | import Libraries.Data.NameMap
24 | constructorBindName : Name
25 | constructorBindName = UN (Basic "__con")
28 | replaceSep : String -> String
29 | replaceSep = pack . map toForward . unpack
31 | toForward : Char -> Char
32 | toForward '\\' = '/'
36 | mkImplName : FC -> Name -> List RawImp -> Name
38 | = DN (show n ++ " implementation at " ++ replaceSep (show fc))
39 | (UN $
Basic ("__Impl_" ++ show n ++ "_" ++
40 | showSep "_" (map show ps)))
42 | bindConstraints : FC -> PiInfo RawImp ->
43 | List (Maybe Name, RawImp) -> RawImp -> RawImp
44 | bindConstraints fc p [] ty = ty
45 | bindConstraints fc p ((n, ty) :: rest) sc
46 | = IPi fc top p n ty (bindConstraints fc p rest sc)
48 | bindImpls : List (AddFC (ImpParameter' RawImp)) -> RawImp -> RawImp
49 | bindImpls [] ty = ty
50 | bindImpls (binder :: rest) sc
51 | = IPi binder.fc binder.rig binder.val.info (Just binder.nameVal) binder.val.boundType (bindImpls rest sc)
53 | addDefaults : FC -> Name ->
54 | (params : List (Name, RawImp)) ->
55 | (allMethods : List Name) ->
56 | (defaults : List (Name, List ImpClause)) ->
58 | (List ImpDecl, List Name)
59 | addDefaults fc impName params allms defs body
60 | = let missing = dropGot allms body in
61 | extendBody [] missing body
63 | specialiseMeth : Name -> (Name, RawImp)
64 | specialiseMeth n = (n, INamedApp fc (IVar fc n) constructorBindName (IVar fc impName))
67 | extendBody : List Name -> List Name -> List ImpDecl ->
68 | (List ImpDecl, List Name)
69 | extendBody ms [] body = (body, ms)
70 | extendBody ms (n :: ns) body
71 | = case lookup n defs of
72 | Nothing => extendBody (n :: ms) ns body
85 | let mupdates = params ++ map specialiseMeth allms
86 | cs' = map (substNamesClause [] mupdates) cs in
88 | (IDef fc n (map (substLocClause fc) cs') :: body)
91 | dropGot : List Name -> List ImpDecl -> List Name
93 | dropGot ms (IDef _ n _ :: ds)
94 | = dropGot (filter (/= n) ms) ds
95 | dropGot ms (_ :: ds) = dropGot ms ds
97 | getMethImps : {vars : _} ->
98 | {auto c : Ref Ctxt Defs} ->
99 | Env Term vars -> Term vars ->
100 | Core (List (Name, RigCount, Maybe RawImp, RawImp))
101 | getMethImps env (Bind fc x (Pi fc' c Implicit ty) sc)
102 | = do rty <- map (map rawName) $
unelabNoSugar env ty
103 | ts <- getMethImps (Pi fc' c Implicit ty :: env) sc
104 | pure ((x, c, Nothing, rty) :: ts)
105 | getMethImps env (Bind fc x (Pi fc' c (DefImplicit def) ty) sc)
106 | = do rty <- map (map rawName) $
unelabNoSugar env ty
107 | rdef <- map (map rawName) $
unelabNoSugar env def
108 | ts <- getMethImps (Pi fc' c (DefImplicit def) ty :: env) sc
109 | pure ((x, c, Just rdef, rty) :: ts)
110 | getMethImps env tm = pure []
113 | elabImplementation : {vars : _} ->
114 | {auto c : Ref Ctxt Defs} ->
115 | {auto u : Ref UST UState} ->
116 | {auto s : Ref Syn SyntaxInfo} ->
117 | {auto m : Ref MD Metadata} ->
118 | {auto o : Ref ROpts REPLOpts} ->
119 | FC -> Visibility -> List FnOpt -> Pass ->
120 | Env Term vars -> NestedNames vars ->
121 | (implicits : List (AddFC (ImpParameter' RawImp))) ->
122 | (constraints : List (Maybe Name, RawImp)) ->
124 | (ps : List RawImp) ->
125 | (namedimpl : Bool) ->
126 | (implName : Name) ->
127 | (nusing : List Name) ->
128 | Maybe (List ImpDecl) ->
131 | elabImplementation {vars} ifc vis opts_in pass env nest is cons iname ps named impName_in nusing mbody
134 | let impName_nest = mapNestedName nest impName_in
135 | impName <- inCurrentNS impName_nest
140 | let varsList = toList vars
141 | inames <- lookupCtxtName iname (gamma defs)
142 | let [cndata] = concatMap (\n => lookupName n (ifaces syn))
144 | | ns => ambiguousName vfc iname (map fst ns)
145 | let cn : Name = fst cndata
146 | let cdata : IFaceInfo = snd cndata
148 | Just ity <- lookupTyExact cn (gamma defs)
149 | | Nothing => undefinedName vfc cn
150 | Just conty <- lookupTyExact (iconstructor cdata) (gamma defs)
151 | | Nothing => undefinedName vfc (iconstructor cdata)
153 | let impsp = nub (concatMap findIBinds ps ++
154 | concatMap findIBinds (map snd cons))
156 | logTerm "elab.implementation" 3 ("Found interface " ++ show cn) ity
157 | log "elab.implementation" 3 $
158 | "\n with params: " ++ show (params cdata)
159 | ++ "\n specialised to: " ++ show ps
160 | ++ "\n and parents: " ++ show (parents cdata)
161 | ++ "\n using implicits: " ++ show impsp
162 | ++ "\n and methods: " ++ show (map val (methods cdata)) ++ "\n"
163 | ++ "\nConstructor: " ++ show (iconstructor cdata) ++ "\n"
164 | logTerm "elab.implementation" 3 "Constructor type: " conty
165 | log "elab.implementation" 5 $
"Making implementation " ++ show impName
172 | let opts = if named
174 | else [Inline, Hint True]
176 | let initTy = bindImpls is $
bindConstraints vfc AutoImplicit cons
177 | (apply (IVar vfc iname) ps)
178 | let paramBinds = if !isUnboundImplicits
179 | then findBindableNames True varsList [] initTy
181 | let impTy = doBind paramBinds initTy
184 | = IClaim (MkFCVal vfc $
MkIClaimData top vis opts (Mk [EmptyFC, NoFC impName] impTy))
186 | log "elab.implementation" 5 $
"Implementation type: " ++ show impTy
189 | when (typePass pass) $
do
190 | gdefm <- lookupCtxtExactI impName (gamma defs)
192 | Nothing => processDecl [] nest env impTyDecl
194 | Just (tidx,gdef) =>
197 | let None = definition gdef
198 | | _ => throw (AlreadyDefined vfc impName)
199 | (ty,_) <- elabTerm tidx InType [] nest env
200 | (IBindHere vfc (PI erased) impTy)
201 | (Just (gType vfc u))
202 | let fullty = abstractFullEnvType vfc env ty
203 | ok <- convert defs Env.empty fullty (type gdef)
204 | unless ok $
do logTermNF "elab.implementation" 1 "Previous" Env.empty (type gdef)
205 | logTermNF "elab.implementation" 1 "Now" Env.empty fullty
206 | throw (CantConvert (getFC impTy) (gamma defs) Env.empty fullty (type gdef))
210 | when (defPass pass) $
211 | whenJust mbody $
\body_in => do
213 | Just impTyc <- lookupTyExact impName (gamma defs)
214 | | Nothing => throw (InternalError ("Can't happen, can't find type of " ++ show impName))
215 | methImps <- getMethImps Env.empty impTyc
216 | log "elab.implementation" 3 $
"Bind implicits to each method: " ++ show methImps
219 | let (body, missing)
220 | = addDefaults vfc impName
221 | (zip (params cdata) ps)
222 | (map (dropNS . (.nameVal)) (methods cdata))
223 | (defaults cdata) body_in
225 | log "elab.implementation" 5 $
"Added defaults: body is " ++ show body
226 | log "elab.implementation" 5 $
"Missing methods: " ++ show missing
227 | when (not (isNil missing)) $
228 | throw (GenericMsg ifc ("Missing methods in " ++ show iname ++ ": "
229 | ++ showSep ", " (map show missing)))
233 | let hs = openHints defs
234 | log "elab.implementation" 10 $
"Open hints: " ++ (show (impName :: nusing))
235 | traverse_ (\n => do n' <- checkUnambig vfc n
236 | addOpenHint n') nusing
240 | fns <- topMethTypes [] impName methImps impsp
241 | (implParams cdata) (params cdata)
242 | (map (.nameVal) (methods cdata))
244 | traverse_ (processDecl [] nest env) (map mkTopMethDecl fns)
247 | let mtops = map (fst . snd) fns
248 | let con = iconstructor cdata
249 | let ilhs = impsApply (IVar EmptyFC impName)
250 | (map (\(x, _) => (x, IBindVar vfc x)) methImps)
254 | let fldTys = getFieldArgs !(normaliseHoles defs Env.empty conty)
255 | log "elab.implementation" 5 $
"Field types " ++ show fldTys
256 | let irhs = apply (autoImpsApply (IVar vfc con) $
map (const (ISearch vfc 500)) (parents cdata))
257 | (map (mkMethField methImps fldTys) fns)
258 | let impFn = IDef vfc impName [PatClause vfc ilhs irhs]
259 | log "elab.implementation" 5 $
"Implementation record: " ++ show impFn
263 | when named $
addOpenHint impName
267 | setFlag vfc impName BlockedHint
271 | names' <- traverse applyEnv (impName :: mtops)
272 | let nest' = { names $= (names' ++) } nest
274 | traverse_ (processDecl [] nest' env) [impFn]
275 | unsetFlag vfc impName BlockedHint
277 | setFlag vfc impName TCInline
279 | setFlag vfc impName (SetTotal PartialOK)
285 | let upds = map methNameUpdate fns
286 | body' <- traverse (updateBody upds) body
288 | log "elab.implementation" 10 $
"Implementation body: " ++ show body'
289 | traverse_ (processDecl [] nest' env) body'
292 | traverse_ (addTransform impName upds) (methods cdata)
296 | unsetFlag vfc impName TCInline
303 | vfc = virtualiseFC ifc
306 | Core (Name, (Maybe Name, List (Var vars), FC -> NameType -> Term vars))
308 | = do n' <- resolveName n
309 | pure (Resolved n', (Nothing, reverse (allVars env),
310 | \fn, nt => applyToFull vfc
311 | (Ref vfc nt (Resolved n')) env))
315 | getFieldArgs : Term vs -> List (Name, List (Name, RigCount, PiInfo RawImp))
316 | getFieldArgs (Bind _ x (Pi _ _ _ ty) sc)
317 | = (x, getArgs ty) :: getFieldArgs sc
319 | getArgs : Term vs' -> List (Name, RigCount, PiInfo RawImp)
320 | getArgs (Bind _ x (Pi _ c p _) sc)
321 | = (x, c, forgetDef p) :: getArgs sc
323 | getFieldArgs _ = []
325 | impsApply : RawImp -> List (Name, RawImp) -> RawImp
326 | impsApply fn [] = fn
327 | impsApply fn ((n, arg) :: ns)
328 | = impsApply (INamedApp vfc fn n arg) ns
330 | autoImpsApply : RawImp -> List RawImp -> RawImp
331 | autoImpsApply f [] = f
332 | autoImpsApply f (x :: xs) = autoImpsApply (IAutoApp (getFC f) f x) xs
334 | mkLam : List (Name, RigCount, PiInfo RawImp) -> RawImp -> RawImp
336 | mkLam ((x, c, p) :: xs) tm
337 | = ILam EmptyFC c p (Just x) (Implicit vfc False) (mkLam xs tm)
339 | applyTo : RawImp -> List (Name, RigCount, PiInfo RawImp) -> RawImp
341 | applyTo tm ((x, c, Explicit) :: xs)
342 | = applyTo (IApp EmptyFC tm (IVar EmptyFC x)) xs
343 | applyTo tm ((x, c, AutoImplicit) :: xs)
344 | = applyTo (INamedApp EmptyFC tm x (IVar EmptyFC x)) xs
345 | applyTo tm ((x, c, Implicit) :: xs)
346 | = applyTo (INamedApp EmptyFC tm x (IVar EmptyFC x)) xs
347 | applyTo tm ((x, c, DefImplicit _) :: xs)
348 | = applyTo (INamedApp EmptyFC tm x (IVar EmptyFC x)) xs
353 | mkMethField : List (Name, a) ->
354 | List (Name, List (Name, RigCount, PiInfo RawImp)) ->
355 | (Name, Name, List (String, String), RigCount, Maybe TotalReq, RawImp) -> RawImp
356 | mkMethField methImps fldTys (topn, n, upds, c, treq, ty)
357 | = let argns = map applyUpdate (maybe [] id (lookup (dropNS topn) fldTys))
358 | imps = map fst methImps in
363 | (applyTo (IVar EmptyFC n) argns)
364 | (map (\n => (n, IVar vfc n)) imps))
366 | applyUpdate : (Name, RigCount, PiInfo RawImp) ->
367 | (Name, RigCount, PiInfo RawImp)
368 | applyUpdate (UN (Basic n), c, p)
369 | = maybe (UN (Basic n), c, p) (\n' => (UN (Basic n'), c, p)) (lookup n upds)
372 | methName : Name -> Name
373 | methName (NS _ n) = methName n
376 | (UN $
Basic (show n ++ "_" ++ show iname ++ "_" ++
377 | (if named then show impName_in else "") ++
378 | showSep "_" (map show ps)))
380 | applyCon : Name -> Name -> Core (Name, RawImp)
382 | = do mn <- inCurrentNS (methName n)
383 | pure (dropNS n, IVar vfc mn)
385 | bindImps : List (Name, RigCount, Maybe RawImp, RawImp) -> RawImp -> RawImp
386 | bindImps [] ty = ty
387 | bindImps ((n, c, Just def, t) :: ts) ty
388 | = IPi vfc c (DefImplicit def) (Just n) t (bindImps ts ty)
389 | bindImps ((n, c, Nothing, t) :: ts) ty
390 | = IPi vfc c Implicit (Just n) t (bindImps ts ty)
395 | topMethType : List (Name, RawImp) ->
396 | Name -> List (Name, RigCount, Maybe RawImp, RawImp) ->
397 | List String -> List Name -> List Name -> List Name ->
399 | Core ((Name, Name, List (String, String), RigCount, Maybe TotalReq, RawImp),
400 | List (Name, RawImp))
401 | topMethType methupds impName methImps impsp imppnames pnames allmeths meth
404 | n <- inCurrentNS (methName meth.nameVal)
405 | let varsList = toList vars
410 | let upds' = !(traverse (applyCon impName) allmeths)
411 | let mty_in = substNames varsList upds' meth.val
412 | let (upds, mty_in) = runState [] (renameIBinds impsp (findImplicits mty_in) mty_in)
416 | let mty_in = substNames varsList methupds mty_in
421 | = substBindVars varsList
422 | (map (\n => (n, Implicit vfc False)) imppnames)
425 | = substNames varsList (zip pnames ps) mty_iparams
426 | log "elab.implementation" 5 $
"Substitute implicits " ++ show imppnames ++
427 | " parameters " ++ show (zip pnames ps) ++
428 | " " ++ show mty_in ++ " is " ++
431 | let mbase = bindImps methImps $
432 | bindConstraints vfc AutoImplicit cons $
434 | let ibound = findImplicits mbase
436 | mty <- bindTypeNamesUsed ifc ibound varsList mbase
438 | log "elab.implementation" 3 $
439 | "Method " ++ show meth.nameVal ++ " ==> " ++
440 | show n ++ " : " ++ show mty
441 | log "elab.implementation" 3 $
" (initially " ++ show mty_in ++ ")"
442 | log "elab.implementation" 5 $
"Updates " ++ show methupds
443 | log "elab.implementation" 5 $
"From " ++ show mbase
444 | log "elab.implementation" 3 $
"Name updates " ++ show upds
445 | log "elab.implementation" 3 $
"Param names: " ++ show pnames
446 | log "elab.implementation" 10 $
"Used names " ++ show ibound
447 | let ibinds = map fst methImps
448 | let methupds' = if isNil ibinds then []
449 | else [(n, impsApply (IVar vfc n)
450 | (map (\x => (x, IBindVar vfc x)) ibinds))]
452 | pure ((meth.nameVal, n, upds, meth.rig, meth.totReq, mty), methupds')
454 | topMethTypes : List (Name, RawImp) ->
455 | Name -> List (Name, RigCount, Maybe RawImp, RawImp) ->
457 | List Name -> List Name -> List Name ->
459 | Core (List (Name, Name, List (String, String), RigCount, Maybe TotalReq, RawImp))
460 | topMethTypes upds impName methImps impsp imppnames pnames allmeths [] = pure []
461 | topMethTypes upds impName methImps impsp imppnames pnames allmeths (m :: ms)
462 | = do (m', newupds) <- topMethType upds impName methImps impsp imppnames pnames allmeths m
463 | ms' <- topMethTypes (newupds ++ upds) impName methImps impsp imppnames pnames allmeths ms
466 | mkTopMethDecl : (Name, Name, List (String, String), RigCount, Maybe TotalReq, RawImp) -> ImpDecl
467 | mkTopMethDecl (mn, n, upds, c, treq, mty)
468 | = do let opts = if isJust $
findTotality opts_in
470 | else maybe opts_in (\t => Totality t :: opts_in) treq
471 | IClaim $
MkFCVal vfc $
MkIClaimData c vis opts $
Mk [EmptyFC, NoFC n] mty
475 | methNameUpdate : (Name, Name, t) -> (Name, Name)
476 | methNameUpdate (UN mn, fn, _) = (UN mn, fn)
477 | methNameUpdate (NS _ mn, fn, p) = methNameUpdate (mn, fn, p)
478 | methNameUpdate (mn, fn, p) = (UN (Basic $
nameRoot mn), fn)
481 | findMethName : List (Name, Name) -> FC -> Name -> Core Name
482 | findMethName ns fc n
483 | = case lookup n ns of
484 | Nothing => throw (GenericMsg fc
485 | (show n ++ " is not a method of " ++
489 | updateApp : List (Name, Name) -> RawImp -> Core RawImp
490 | updateApp ns (IVar fc n)
491 | = do n' <- findMethName ns fc n
493 | updateApp ns (IApp fc f arg)
494 | = do f' <- updateApp ns f
495 | pure (IApp fc f' arg)
496 | updateApp ns (IWithApp fc f arg)
497 | = do f' <- updateApp ns f
498 | pure (IWithApp fc f' arg)
499 | updateApp ns (IAutoApp fc f arg)
500 | = do f' <- updateApp ns f
501 | pure (IAutoApp fc f' arg)
502 | updateApp ns (INamedApp fc f x arg)
503 | = do f' <- updateApp ns f
504 | pure (INamedApp fc f' x arg)
506 | = throw (GenericMsg (getFC tm) "Invalid method definition")
508 | updateClause : List (Name, Name) -> ImpClause ->
510 | updateClause ns (PatClause fc lhs rhs)
511 | = do lhs' <- updateApp ns lhs
512 | pure (PatClause fc lhs' rhs)
513 | updateClause ns (WithClause fc lhs rig wval prf flags cs)
514 | = do lhs' <- updateApp ns lhs
515 | cs' <- traverse (updateClause ns) cs
516 | pure (WithClause fc lhs' rig wval prf flags cs')
517 | updateClause ns (ImpossibleClause fc lhs)
518 | = do lhs' <- updateApp ns lhs
519 | pure (ImpossibleClause fc lhs')
521 | updateBody : List (Name, Name) -> ImpDecl -> Core ImpDecl
522 | updateBody ns (IDef fc n cs)
523 | = do cs' <- traverse (updateClause ns) cs
524 | n' <- findMethName ns fc n
525 | log "ide-mode.highlight" 1 $
show (n, n', fc)
526 | pure (IDef fc n' cs')
528 | = throw (GenericMsg (getFC e)
529 | "Implementation body can only contain definitions")
531 | addTransform : Name -> List (Name, Name) ->
534 | addTransform iname ns meth
535 | = do log "elab.implementation" 3 $
536 | "Adding transform for " ++ show meth.nameVal ++ " : " ++ show meth.val ++
537 | "\n\tfor " ++ show iname ++ " in " ++ show ns
538 | let lhs = INamedApp vfc (IVar vfc meth.name.val)
539 | constructorBindName
541 | let Just mname = lookup (dropNS meth.nameVal) ns
542 | | Nothing => pure ()
543 | let rhs = IVar vfc mname
544 | log "elab.implementation" 5 $
show lhs ++ " ==> " ++ show rhs
546 | (processDecl [] nest env
547 | (ITransform vfc (UN $
Basic (show meth.nameVal ++ " " ++ show iname)) lhs rhs))
549 | log "elab.implementation" 5 $
"Can't add transform " ++
550 | show lhs ++ " ==> " ++ show rhs ++
551 | "\n\t" ++ show err)