1 | module Core.UnifyState
3 | import Core.Context.Log
5 | import Core.Normalise
8 | import Libraries.Data.IntMap
9 | import Libraries.Data.NameMap
10 | import Libraries.Data.WithDefault
12 | import Libraries.Data.SnocList.HasLength
17 | data Constraint : Type where
20 | MkConstraint : {vars : _} ->
22 | (withLazy : Bool) ->
23 | (env : Env Term vars) ->
24 | (x : NF vars) -> (y : NF vars) ->
27 | Resolved : Constraint
34 | data PolyConstraint : Type where
35 | MkPolyConstraint : {vars : _} ->
36 | FC -> Env Term vars ->
37 | (arg : Term vars) ->
38 | (expty : NF vars) ->
39 | (argty : NF vars) -> PolyConstraint
55 | Eq DelayReason where
56 | CaseBlock == CaseBlock = True
57 | Ambiguity == Ambiguity = True
58 | RecordUpdate == RecordUpdate = True
59 | Rewrite == Rewrite = True
60 | LazyDelay == LazyDelay = True
64 | Ord DelayReason where
65 | compare x y = compare (tag x) (tag y)
70 | tag : DelayReason -> Int
75 | tag RecordUpdate = 4
80 | constructor MkUState
81 | holes : IntMap (FC, Name)
83 | guesses : IntMap (FC, Name)
85 | currentHoles : IntMap (FC, Name)
86 | delayedHoles : IntMap (FC, Name)
91 | constraints : IntMap Constraint
96 | polyConstraints : List PolyConstraint
98 | dotConstraints : List (Name, DotReason, Constraint)
100 | nextConstraint : Int
101 | delayedElab : List (DelayReason, Int, NameMap (), Core ClosedTerm)
110 | initUState : UState
111 | initUState = MkUState
114 | , currentHoles = empty
115 | , delayedHoles = empty
116 | , constraints = empty
118 | , polyConstraints = []
119 | , dotConstraints = []
121 | , nextConstraint = 0
127 | data UST : Type where
130 | resetNextVar : {auto u : Ref UST UState} ->
132 | resetNextVar = update UST { nextName := 0 }
136 | genName : {auto c : Ref Ctxt Defs} ->
137 | {auto u : Ref UST UState} ->
138 | String -> Core Name
140 | = do ust <- get UST
141 | put UST ({ nextName $= (+1) } ust)
142 | n <- inCurrentNS (MN str (nextName ust))
147 | genMVName : {auto c : Ref Ctxt Defs} ->
148 | {auto u : Ref UST UState} ->
150 | genMVName (UN str) = genName (displayUserName str)
151 | genMVName (MN str _) = genName str
153 | = do ust <- get UST
154 | put UST ({ nextName $= (+1) } ust)
155 | mn <- inCurrentNS (MN (show n) (nextName ust))
160 | genVarName : {auto c : Ref Ctxt Defs} ->
161 | {auto u : Ref UST UState} ->
162 | String -> Core Name
164 | = do ust <- get UST
165 | put UST ({ nextName $= (+1) } ust)
166 | pure (MN str (nextName ust))
170 | genCaseName : {auto c : Ref Ctxt Defs} ->
171 | {auto u : Ref UST UState} ->
172 | String -> Core Name
174 | = do ust <- get UST
175 | put UST ({ nextName $= (+1) } ust)
176 | inCurrentNS (CaseBlock root (nextName ust))
179 | genWithName : {auto c : Ref Ctxt Defs} ->
180 | {auto u : Ref UST UState} ->
181 | String -> Core Name
183 | = do ust <- get UST
184 | put UST ({ nextName $= (+1) } ust)
185 | inCurrentNS (WithBlock root (nextName ust))
187 | addHoleName : {auto u : Ref UST UState} ->
188 | FC -> Name -> Int -> Core ()
189 | addHoleName fc n i = update UST { holes $= insert i (fc, n),
190 | currentHoles $= insert i (fc, n) }
192 | addGuessName : {auto u : Ref UST UState} ->
193 | FC -> Name -> Int -> Core ()
194 | addGuessName fc n i = update UST { guesses $= insert i (fc, n) }
197 | removeHole : {auto u : Ref UST UState} ->
199 | removeHole n = update UST { holes $= delete n,
200 | currentHoles $= delete n,
201 | delayedHoles $= delete n }
204 | removeHoleName : {auto c : Ref Ctxt Defs} ->
205 | {auto u : Ref UST UState} ->
208 | = do defs <- get Ctxt
209 | whenJust (getNameID n defs.gamma) removeHole
212 | addNoSolve : {auto u : Ref UST UState} ->
214 | addNoSolve i = update UST { noSolve $= insert i () }
217 | removeNoSolve : {auto u : Ref UST UState} ->
219 | removeNoSolve i = update UST { noSolve $= delete i }
222 | saveHoles : {auto u : Ref UST UState} ->
223 | Core (IntMap (FC, Name))
225 | = do ust <- get UST
226 | put UST ({ currentHoles := empty } ust)
227 | pure (currentHoles ust)
230 | restoreHoles : {auto u : Ref UST UState} ->
231 | IntMap (FC, Name) -> Core ()
232 | restoreHoles hs = update UST { currentHoles := hs }
235 | removeGuess : {auto u : Ref UST UState} ->
237 | removeGuess n = update UST { guesses $= delete n }
241 | getHoles : {auto u : Ref UST UState} ->
242 | Core (IntMap (FC, Name))
243 | getHoles = holes <$> get UST
247 | getGuesses : {auto u : Ref UST UState} ->
248 | Core (IntMap (FC, Name))
249 | getGuesses = guesses <$> get UST
254 | getCurrentHoles : {auto u : Ref UST UState} ->
255 | Core (IntMap (FC, Name))
256 | getCurrentHoles = currentHoles <$> get UST
259 | isHole : {auto u : Ref UST UState} ->
261 | isHole i = isJust . lookup i <$> getHoles
264 | isCurrentHole : {auto u : Ref UST UState} ->
266 | isCurrentHole i = isJust . lookup i <$> getCurrentHoles
269 | setConstraint : {auto u : Ref UST UState} ->
270 | Int -> Constraint -> Core ()
271 | setConstraint cid c = update UST { constraints $= insert cid c }
274 | deleteConstraint : {auto u : Ref UST UState} ->
276 | deleteConstraint cid = update UST { constraints $= delete cid }
279 | addConstraint : {auto u : Ref UST UState} ->
280 | {auto c : Ref Ctxt Defs} ->
281 | Constraint -> Core Int
282 | addConstraint constr
283 | = do ust <- get UST
284 | let cid = nextConstraint ust
285 | put UST ({ constraints $= insert cid constr,
286 | nextConstraint := cid+1 } ust)
290 | addDot : {vars : _} ->
291 | {auto c : Ref Ctxt Defs} ->
292 | {auto u : Ref UST UState} ->
293 | FC -> Env Term vars -> Name -> Term vars -> DotReason -> Term vars ->
295 | addDot fc env dotarg x reason y
296 | = do defs <- get Ctxt
297 | xnf <- nf defs env x
298 | ynf <- nf defs env y
299 | update UST { dotConstraints $= ((dotarg, reason, MkConstraint fc False env xnf ynf) ::) }
302 | addPolyConstraint : {vars : _} ->
303 | {auto u : Ref UST UState} ->
304 | FC -> Env Term vars -> Term vars -> NF vars -> NF vars ->
306 | addPolyConstraint fc env arg x@(NApp _ (NMeta {}) _) y
307 | = update UST { polyConstraints $= ((MkPolyConstraint fc env arg x y) ::) }
308 | addPolyConstraint fc env arg x y
311 | mkLocal : {wkns : SnocList Name} -> FC -> Binder (Term vars) -> Term (wkns <>> x :: (vars ++ done))
312 | mkLocal fc b = Local fc (Just (isLet b)) _ (mkIsVarChiply (mkHasLength wkns))
314 | mkConstantAppArgs : {vars : _} ->
315 | Bool -> FC -> Env Term vars ->
316 | (wkns : SnocList Name) ->
317 | List (Term (wkns <>> (vars ++ done)))
318 | mkConstantAppArgs lets fc [] wkns = []
319 | mkConstantAppArgs {done} {vars = x :: xs} lets fc (b :: env) wkns
320 | = let rec = mkConstantAppArgs {done} lets fc env (wkns :< x) in
321 | if lets || not (isLet b)
322 | then mkLocal fc b :: rec
325 | mkConstantAppArgsSub : {vars : _} ->
326 | Bool -> FC -> Env Term vars ->
327 | Thin smaller vars ->
328 | (wkns : SnocList Name) ->
329 | List (Term (wkns <>> (vars ++ done)))
330 | mkConstantAppArgsSub lets fc [] p wkns = []
331 | mkConstantAppArgsSub {done} {vars = x :: xs}
332 | lets fc (b :: env) Refl wkns
333 | = mkConstantAppArgs lets fc env (wkns :< x)
334 | mkConstantAppArgsSub {done} {vars = x :: xs}
335 | lets fc (b :: env) (Drop p) wkns
336 | = mkConstantAppArgsSub lets fc env p (wkns :< x)
337 | mkConstantAppArgsSub {done} {vars = x :: xs}
338 | lets fc (b :: env) (Keep p) wkns
339 | = let rec = mkConstantAppArgsSub {done} lets fc env p (wkns :< x) in
340 | if lets || not (isLet b)
341 | then mkLocal fc b :: rec
344 | mkConstantAppArgsOthers : {vars : _} ->
345 | Bool -> FC -> Env Term vars ->
346 | Thin smaller vars ->
347 | (wkns : SnocList Name) ->
348 | List (Term (wkns <>> (vars ++ done)))
349 | mkConstantAppArgsOthers lets fc [] p wkns = []
350 | mkConstantAppArgsOthers {done} {vars = x :: xs}
351 | lets fc (b :: env) Refl wkns
352 | = mkConstantAppArgsOthers lets fc env Refl (wkns :< x)
353 | mkConstantAppArgsOthers {done} {vars = x :: xs}
354 | lets fc (b :: env) (Keep p) wkns
355 | = mkConstantAppArgsOthers lets fc env p (wkns :< x)
356 | mkConstantAppArgsOthers {done} {vars = x :: xs}
357 | lets fc (b :: env) (Drop p) wkns
358 | = let rec = mkConstantAppArgsOthers {done} lets fc env p (wkns :< x) in
359 | if lets || not (isLet b)
360 | then mkLocal fc b :: rec
364 | applyTo : {vars : _} ->
365 | FC -> Term vars -> Env Term vars -> Term vars
367 | = let args = reverse (mkConstantAppArgs {done = Scope.empty} False fc env [<]) in
368 | apply fc tm (rewrite sym (appendNilRightNeutral vars) in args)
371 | applyToFull : {vars : _} ->
372 | FC -> Term vars -> Env Term vars -> Term vars
373 | applyToFull fc tm env
374 | = let args = reverse (mkConstantAppArgs {done = Scope.empty} True fc env [<]) in
375 | apply fc tm (rewrite sym (appendNilRightNeutral vars) in args)
378 | applyToSub : {vars : _} ->
379 | FC -> Term vars -> Env Term vars ->
380 | Thin smaller vars -> Term vars
381 | applyToSub fc tm env sub
382 | = let args = reverse (mkConstantAppArgsSub {done = Scope.empty} True fc env sub [<]) in
383 | apply fc tm (rewrite sym (appendNilRightNeutral vars) in args)
386 | applyToOthers : {vars : _} ->
387 | FC -> Term vars -> Env Term vars ->
388 | Thin smaller vars -> Term vars
389 | applyToOthers fc tm env sub
390 | = let args = reverse (mkConstantAppArgsOthers {done = Scope.empty} True fc env sub [<]) in
391 | apply fc tm (rewrite sym (appendNilRightNeutral vars) in args)
399 | newMetaLets : {vars : _} ->
400 | {auto c : Ref Ctxt Defs} ->
401 | {auto u : Ref UST UState} ->
403 | Env Term vars -> Name -> Term vars -> Def ->
405 | Core (Int, Term vars)
406 | newMetaLets {vars} fc rig env n ty def nocyc lets
407 | = do let hty = if lets then abstractFullEnvType fc env ty
408 | else abstractEnvType fc env ty
409 | let hole = { noCycles := nocyc }
410 | (newDef fc n rig Scope.empty hty (specified Public) def)
411 | log "unify.meta" 5 $
"Adding new meta " ++ show (n, fc, rig)
412 | logTerm "unify.meta" 10 ("New meta type " ++ show n) hty
413 | idx <- addDef n hole
414 | addHoleName fc n idx
415 | pure (idx, Meta fc n idx envArgs)
417 | envArgs : List (Term vars)
418 | envArgs = let args = reverse (mkConstantAppArgs {done = Scope.empty} lets fc env [<]) in
419 | rewrite sym (appendNilRightNeutral vars) in args
422 | newMeta : {vars : _} ->
423 | {auto c : Ref Ctxt Defs} ->
424 | {auto u : Ref UST UState} ->
426 | Env Term vars -> Name -> Term vars -> Def ->
428 | Core (Int, Term vars)
429 | newMeta fc r env n ty def cyc = newMetaLets fc r env n ty def cyc False
431 | mkConstant : {vars : _} ->
432 | FC -> Env Term vars -> Term vars -> ClosedTerm
433 | mkConstant fc [] tm = tm
436 | mkConstant {vars = x :: _} fc (b :: env) tm
437 | = let ty = binderType b in
438 | mkConstant fc env (Bind fc x (Lam fc (multiplicity b) Explicit ty) tm)
444 | newConstant : {vars : _} ->
445 | {auto u : Ref UST UState} ->
446 | {auto c : Ref Ctxt Defs} ->
447 | FC -> RigCount -> Env Term vars ->
448 | (tm : Term vars) -> (ty : Term vars) ->
449 | (constrs : List Int) ->
451 | newConstant {vars} fc rig env tm ty constrs
452 | = do let def = mkConstant fc env tm
453 | let defty = abstractFullEnvType fc env ty
454 | cn <- genName "postpone"
455 | let guess = newDef fc cn rig Scope.empty defty (specified Public)
456 | (Guess def (length env) constrs)
457 | log "unify.constant" 5 $
"Adding new constant " ++ show (cn, fc, rig)
458 | logTerm "unify.constant" 10 ("New constant type " ++ show cn) defty
459 | idx <- addDef cn guess
460 | addGuessName fc cn idx
461 | pure (Meta fc cn idx envArgs)
463 | envArgs : List (Term vars)
464 | envArgs = let args = reverse (mkConstantAppArgs {done = Scope.empty} True fc env [<]) in
465 | rewrite sym (appendNilRightNeutral vars) in args
471 | newSearch : {vars : _} ->
472 | {auto c : Ref Ctxt Defs} ->
473 | {auto u : Ref UST UState} ->
474 | FC -> RigCount -> Nat -> Name ->
475 | Env Term vars -> Name -> Term vars -> Core (Int, Term vars)
476 | newSearch {vars} fc rig depth def env n ty
477 | = do let hty = abstractEnvType fc env ty
478 | let hole = newDef fc n rig Scope.empty hty (specified Public) (BySearch rig depth def)
479 | log "unify.search" 10 $
"Adding new search " ++ show fc ++ " " ++ show n
480 | logTermNF "unify.search" 10 "New search type" Env.empty hty
481 | idx <- addDef n hole
482 | addGuessName fc n idx
483 | pure (idx, Meta fc n idx envArgs)
485 | envArgs : List (Term vars)
486 | envArgs = let args = reverse (mkConstantAppArgs {done = Scope.empty} False fc env [<]) in
487 | rewrite sym (appendNilRightNeutral vars) in args
491 | newDelayed : {vars : _} ->
492 | {auto u : Ref UST UState} ->
493 | {auto c : Ref Ctxt Defs} ->
495 | Env Term vars -> Name ->
496 | (ty : Term vars) -> Core (Int, Term vars)
497 | newDelayed {vars} fc rig env n ty
498 | = do let hty = abstractEnvType fc env ty
499 | let hole = newDef fc n rig Scope.empty hty (specified Public) Delayed
500 | idx <- addDef n hole
501 | log "unify.delay" 10 $
"Added delayed elaborator " ++ show (n, idx)
502 | addHoleName fc n idx
503 | pure (idx, Meta fc n idx envArgs)
505 | envArgs : List (Term vars)
506 | envArgs = let args = reverse (mkConstantAppArgs {done = Scope.empty} False fc env [<]) in
507 | rewrite sym (appendNilRightNeutral vars) in args
510 | tryErrorUnify : {auto c : Ref Ctxt Defs} ->
511 | {auto u : Ref UST UState} ->
512 | {default False unResolve : Bool} ->
513 | Core a -> Core (Either Error a)
515 | = do ust <- get UST
517 | catch (do res <- elab
520 | (\err => do put UST ust
521 | err <- ifThenElse unResolve toFullNames pure err
523 | put Ctxt ({ timings := timings defs' } defs)
527 | tryUnify : {auto c : Ref Ctxt Defs} ->
528 | {auto u : Ref UST UState} ->
529 | Core a -> Core a -> Core a
530 | tryUnify elab1 elab2
531 | = do Right ok <- tryErrorUnify elab1
532 | | Left err => elab2
536 | handleUnify : {auto c : Ref Ctxt Defs} ->
537 | {auto u : Ref UST UState} ->
538 | {default False unResolve : Bool} ->
539 | Core a -> (Error -> Core a) -> Core a
540 | handleUnify elab1 elab2
541 | = do Right ok <- tryErrorUnify {unResolve} elab1
542 | | Left err => elab2 err
548 | addDelayedHoleName : {auto u : Ref UST UState} ->
549 | (Int, (FC, Name)) -> Core ()
550 | addDelayedHoleName (idx, h) = update UST { delayedHoles $= insert idx h }
553 | checkDelayedHoles : {auto u : Ref UST UState} ->
556 | = do ust <- get UST
557 | let hs = toList (delayedHoles ust)
558 | if (not (isNil hs))
559 | then do pure (Just (UnsolvedHoles (map snd hs)))
566 | checkValidHole : {auto c : Ref Ctxt Defs} ->
567 | {auto u : Ref UST UState} ->
568 | Int -> (Int, (FC, Name)) -> Core ()
569 | checkValidHole base (idx, (fc, n))
570 | = when (idx >= base) $
571 | do defs <- get Ctxt
572 | Just gdef <- lookupCtxtExact (Resolved idx) (gamma defs)
573 | | Nothing => pure ()
574 | case definition gdef of
576 | do defs <- get Ctxt
577 | Just ty <- lookupTyExact n (gamma defs)
578 | | Nothing => pure ()
579 | throw (CantSolveGoal fc (gamma defs) Env.empty ty Nothing)
580 | Guess tm envb (con :: _) =>
582 | let Just c = lookup con (constraints ust)
583 | | Nothing => pure ()
585 | MkConstraint fc l env x y =>
586 | do put UST ({ guesses := empty } ust)
587 | empty <- clearDefs defs
588 | xnf <- quote empty env x
589 | ynf <- quote empty env y
590 | throw (CantSolveEq fc (gamma defs) env xnf ynf)
592 | _ => traverse_ checkRef !(traverse getFullName
593 | ((keys (getRefs (Resolved (-
1)) (type gdef)))))
595 | checkRef : Name -> Core ()
597 | = throw (GenericMsg fc
598 | ("Hole cannot depend on an unbound implicit " ++ show n))
599 | checkRef _ = pure ()
607 | checkUserHolesAfter : {auto u : Ref UST UState} ->
608 | {auto c : Ref Ctxt Defs} ->
609 | Int -> Bool -> Core ()
610 | checkUserHolesAfter base now
611 | = do gs_map <- getGuesses
612 | let gs = toList gs_map
613 | log "unify.unsolved" 10 $
"Unsolved guesses " ++ show gs
614 | List.traverse_ (checkValidHole base) gs
615 | hs_map <- getCurrentHoles
616 | let hs = toList hs_map
617 | let hs' = if any isUserName (map (snd . snd) hs)
619 | when (now && not (isNil hs')) $
620 | throw (UnsolvedHoles (map snd (nubBy nameEq hs)))
623 | traverse_ addDelayedHoleName hs'
625 | nameEq : (a, b, Name) -> (a, b, Name) -> Bool
626 | nameEq (_, _, x) (_, _, y) = x == y
629 | checkUserHoles : {auto u : Ref UST UState} ->
630 | {auto c : Ref Ctxt Defs} ->
632 | checkUserHoles = checkUserHolesAfter 0
635 | checkNoGuards : {auto u : Ref UST UState} ->
636 | {auto c : Ref Ctxt Defs} ->
638 | checkNoGuards = checkUserHoles False
641 | dumpHole : {auto u : Ref UST UState} ->
642 | {auto c : Ref Ctxt Defs} ->
643 | LogTopic -> Nat -> (hole : Int) -> Core ()
645 | = do ust <- get UST
647 | case !(lookupCtxtExact (Resolved hole) (gamma defs)) of
649 | Just gdef => case (definition gdef, type gdef) of
650 | (Guess tm envb constraints, ty) =>
651 | do logString s.topic n $
652 | "!" ++ show !(getFullName (Resolved hole)) ++ " : "
653 | ++ show !(toFullNames !(normaliseHoles defs Env.empty ty))
655 | ++ show !(normaliseHoles defs Env.empty tm)
657 | traverse_ dumpConstraint constraints
659 | logString s.topic n $
660 | "?" ++ show (fullname gdef) ++ " : "
661 | ++ show !(normaliseHoles defs Env.empty ty)
662 | ++ if implbind p then " (ImplBind)" else ""
663 | ++ if invertible gdef then " (Invertible)" else ""
664 | (BySearch _ _ _, ty) =>
665 | logString s.topic n $
666 | "Search " ++ show hole ++ " : " ++
667 | show !(toFullNames !(normaliseHoles defs Env.empty ty))
668 | (PMDef _ args t _ _, ty) =>
670 | "Solved: " ++ show hole ++ " : " ++
671 | show !(normalise defs Env.empty ty) ++
672 | " = " ++ show !(normalise defs Env.empty (Ref emptyFC Func (Resolved hole)))
675 | "Bound: " ++ show hole ++ " : " ++
676 | show !(normalise defs Env.empty ty)
679 | "Delayed elaborator : " ++
680 | show !(normalise defs Env.empty ty)
683 | dumpConstraint : Int -> Core ()
685 | = do ust <- get UST
687 | case lookup cid (constraints ust) of
689 | Just Resolved => logString s.topic n "\tResolved"
690 | Just (MkConstraint _ lazy env x y) =>
691 | do logString s.topic n $
692 | "\t " ++ show !(toFullNames !(quote defs env x))
693 | ++ " =?= " ++ show !(toFullNames !(quote defs env y))
694 | empty <- clearDefs defs
696 | "\t from " ++ show !(toFullNames !(quote empty env x))
697 | ++ " =?= " ++ show !(toFullNames !(quote empty env y))
698 | ++ if lazy then "\n\t(lazy allowed)" else ""
701 | dumpConstraints : {auto u : Ref UST UState} ->
702 | {auto c : Ref Ctxt Defs} ->
703 | LogTopic -> (verbosity : Nat) -> (all : Bool) -> Core ()
704 | dumpConstraints s n all
705 | = do ust <- get UST
707 | when !(logging s n) $
do
708 | let hs = toList (guesses ust) ++
709 | toList (if all then holes ust else currentHoles ust)
710 | unless (isNil hs) $
711 | do logString s.topic n "--- CONSTRAINTS AND HOLES ---"
712 | traverse_ (dumpHole s n) (map fst hs)