Skip to content

Commit 46119b4

Browse files
committed
Pass around shared map of solved existentials
1 parent d484a58 commit 46119b4

File tree

2 files changed

+64
-52
lines changed

2 files changed

+64
-52
lines changed

parser-typechecker/src/Unison/PrintError.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1107,7 +1107,7 @@ renderCompilerBug env _src bug = mconcat $ case bug of
11071107

11081108
renderContext ::
11091109
(Var v, Ord loc) => Env -> C.Context v loc -> Pretty (AnnotatedText a)
1110-
renderContext env ctx@(C.Context es) =
1110+
renderContext env ctx@(C.Context es _) =
11111111
" Γ\n "
11121112
<> intercalateMap "\n " (showElem ctx . fst) (reverse es)
11131113
where

parser-typechecker/src/Unison/Typechecker/Context.hs

Lines changed: 63 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -377,7 +377,7 @@ topLevelComponent = TopLevelComponent . fmap (over _2 removeSyntheticTypeVars)
377377
-- generalize types stored in the notes.
378378
substituteSolved ::
379379
(Var v, Ord loc) =>
380-
[Element v loc] ->
380+
Map v (Monotype v loc) ->
381381
InfoNote v loc ->
382382
InfoNote v loc
383383
substituteSolved ctx (SolvedBlank b v t) =
@@ -473,7 +473,7 @@ scope' p (ErrorNote cause path) = ErrorNote cause (path `mappend` pure p)
473473
scope :: PathElement v loc -> M v loc a -> M v loc a
474474
scope p (MT m) = MT \ppe pmcSwitch datas effects env -> mapErrors (scope' p) (m ppe pmcSwitch datas effects env)
475475

476-
newtype Context v loc = Context [(Element v loc, Info v loc)]
476+
data Context v loc = Context [(Element v loc, Info v loc)] (Map v (Monotype v loc))
477477

478478
data Info v loc = Info
479479
{ existentialVars :: Set v, -- set of existentials seen so far
@@ -484,14 +484,25 @@ data Info v loc = Info
484484
}
485485

486486
-- | The empty context
487-
context0 :: Context v loc
488-
context0 = Context []
487+
context0 :: Ord v => Context v loc
488+
context0 = Context [] mempty
489+
490+
context :: Ord v => [(Element v loc, Info v loc)] -> Context v loc
491+
context elems = Context elems (computeSolvedExistentials (fst <$> elems))
492+
493+
computeSolvedExistentials :: Ord a => [Element a loc] -> Map a (Monotype a loc)
494+
computeSolvedExistentials elems =
495+
elems & mapMaybe (\case
496+
Solved _ v t -> Just (v, t)
497+
_ -> Nothing
498+
)
499+
& Map.fromList
489500

490501
occursAnn :: (Var v) => (Ord loc) => TypeVar v loc -> Context v loc -> Bool
491-
occursAnn v (Context eis) = any p es
502+
occursAnn v (Context eis solved) = any p es
492503
where
493504
es = fst <$> eis
494-
p (Ann _ ty) = v `Set.member` ABT.freeVars (applyCtx es ty)
505+
p (Ann _ ty) = v `Set.member` ABT.freeVars (applyCtx solved ty)
495506
p _ = False
496507

497508
-- | Focuses on the first element in the list that satisfies the predicate.
@@ -505,38 +516,38 @@ focusAt p xs = go [] xs
505516
-- | Delete from the end of this context up to and including
506517
-- the given `Element`. Returns `Nothing` if the element is not found.
507518
retract0 :: (Var v, Ord loc) => Element v loc -> Context v loc -> Maybe (Context v loc, [Element v loc])
508-
retract0 e (Context ctx) = case focusAt (\(e', _) -> e' == e) ctx of
519+
retract0 e (Context ctx _) = case focusAt (\(e', _) -> e' == e) ctx of
509520
Just (discarded, _, remaining) ->
510521
-- note: no need to recompute used variables; any suffix of the
511522
-- context snoc list is also a valid context
512-
Just (Context remaining, map fst discarded)
523+
Just (context remaining, map fst discarded)
513524
Nothing -> Nothing
514525

515526
-- | Adds a marker to the end of the context, runs the `body` and then discards
516527
-- from the end of the context up to and including the marker. Returns the result
517528
-- of `body` and the discarded context (not including the marker), respectively.
518529
-- Freshened `markerHint` is used to create the marker.
519-
markThenRetract :: (Var v, Ord loc) => v -> M v loc a -> M v loc (a, [Element v loc])
530+
markThenRetract :: (Var v, Ord loc) => v -> M v loc a -> M v loc (a, [Element v loc], Map v (Monotype v loc))
520531
markThenRetract hint body =
521532
markThenCallWithRetract hint \retract -> adjustNotes do
522533
r <- body
523-
ctx <- retract
524-
pure ((r, ctx), substituteSolved ctx)
534+
(ctx, solved) <- retract
535+
pure ((r, ctx, solved), substituteSolved solved)
525536

526537
markThenRetract0 :: (Var v, Ord loc) => v -> M v loc a -> M v loc ()
527538
markThenRetract0 markerHint body = () <$ markThenRetract markerHint body
528539

529540
markThenCallWithRetract ::
530541
(Var v, Ord loc) =>
531542
v ->
532-
(M v loc [Element v loc] -> M v loc a) ->
543+
(M v loc ([Element v loc], Map v (Monotype v loc)) -> M v loc a) ->
533544
M v loc a
534545
markThenCallWithRetract hint k = do
535546
v <- freshenVar hint
536547
extendContext (Marker v)
537548
k (doRetract (Marker v))
538549
where
539-
doRetract :: (Var v, Ord loc) => Element v loc -> M v loc [Element v loc]
550+
doRetract :: (Var v, Ord loc) => Element v loc -> M v loc ([Element v loc], Map v (Monotype v loc))
540551
doRetract e = do
541552
ctx <- getContext
542553
case retract0 e ctx of
@@ -554,7 +565,7 @@ markThenCallWithRetract hint k = do
554565
inst = apply ctx
555566
Foldable.traverse_ go (solved ++ unsolved)
556567
setContext t
557-
pure discarded
568+
pure (discarded, computeSolvedExistentials discarded)
558569

559570
-- unsolved' :: Context v loc -> [(B.Blank loc, v)]
560571
-- unsolved' (Context ctx) = [(b,v) | (Existential b v, _) <- ctx]
@@ -570,11 +581,11 @@ breakAt ::
570581
Element v loc ->
571582
Context v loc ->
572583
Maybe (Context v loc, Element v loc, [Element v loc])
573-
breakAt m (Context xs) =
584+
breakAt m (Context xs _) =
574585
case focusAt (\(e, _) -> e === m) xs of
575586
Just (r, m, l) ->
576587
-- l is a suffix of xs and is already a valid context
577-
Just (Context l, fst m, map fst r)
588+
Just (context l, fst m, map fst r)
578589
Nothing -> Nothing
579590
where
580591
Existential _ v === Existential _ v2 | v == v2 = True
@@ -649,7 +660,7 @@ appendContext = traverse_ extendContext
649660
markRetained :: (Var v, Ord loc) => Set v -> M v loc ()
650661
markRetained keep = setContext . marks =<< getContext
651662
where
652-
marks (Context eis) = Context (fmap mark eis)
663+
marks (Context eis _) = context (fmap mark eis)
653664
mark (Existential B.Blank v, i)
654665
| v `Set.member` keep = (Var (TypeVar.Existential B.Retain v), i)
655666
mark (Solved B.Blank v t, i)
@@ -747,14 +758,14 @@ wellformedType c t = case t of
747758

748759
-- | Return the `Info` associated with the last element of the context, or the zero `Info`.
749760
info :: (Ord v) => Context v loc -> Info v loc
750-
info (Context []) = Info mempty mempty mempty mempty mempty
751-
info (Context ((_, i) : _)) = i
761+
info (Context [] _) = Info mempty mempty mempty mempty mempty
762+
info (Context ((_, i) : _) _) = i
752763

753764
-- | Add an element onto the end of this `Context`. Takes `O(log N)` time,
754765
-- including updates to the accumulated `Info` value.
755766
-- Fail if the new context is not well formed (see Figure 7 of paper).
756767
extend' :: (Var v) => Element v loc -> Context v loc -> Either (CompilerBug v loc) (Context v loc)
757-
extend' e c@(Context ctx) = Context . (: ctx) . (e,) <$> i'
768+
extend' e c@(Context ctx _) = context . (: ctx) . (e,) <$> i'
758769
where
759770
Info es ses us uas vs = info c
760771
-- see figure 7
@@ -946,8 +957,8 @@ apply :: (Var v, Ord loc) => Context v loc -> Type v loc -> Type v loc
946957
apply ctx = apply' (solvedExistentials . info $ ctx)
947958

948959
-- | Replace any existentials with their solution in the context (given as a list of elements)
949-
applyCtx :: (Var v, Ord loc) => [Element v loc] -> Type v loc -> Type v loc
950-
applyCtx elems = apply' $ Map.fromList [(v, sa) | Solved _ v sa <- elems]
960+
applyCtx :: (Var v, Ord loc) => Map v (Monotype v loc) -> Type v loc -> Type v loc
961+
applyCtx = apply'
951962

952963
apply' :: (Var v, Ord loc) => Map v (Monotype v loc) -> Type v loc -> Type v loc
953964
apply' _ t | Set.null (Type.freeVars t) = t
@@ -1107,16 +1118,14 @@ synthesizeTop ::
11071118
M v loc (Type v loc)
11081119
synthesizeTop tm = do
11091120
(ty, want) <- synthesize tm
1110-
ctx <- getContext
1111-
want <- substAndDefaultWanted want (out ctx)
1121+
ctx@(Context es solved) <- getContext
1122+
want <- substAndDefaultWanted want (fst <$> es) solved
11121123
when (not $ null want) . failWith $ do
11131124
AbilityCheckFailure
11141125
[]
11151126
(Type.flattenEffects . snd =<< want)
11161127
ctx
11171128
applyM ty
1118-
where
1119-
out (Context es) = fmap fst es
11201129

11211130
-- | Synthesize the type of the given term, updating the context in
11221131
-- the process. Also collect wanted abilities.
@@ -1222,11 +1231,11 @@ synthesizeWanted (Term.Let1Top' top binding e) = do
12221231
pure (t, want)
12231232
synthesizeWanted (Term.LetRecNamed' [] body) = synthesizeWanted body
12241233
synthesizeWanted (Term.LetRecTop' isTop letrec) = do
1225-
((t, want), ctx2) <- markThenRetract (Var.named "let-rec-marker") $ do
1234+
((t, want), ctx2, solved2) <- markThenRetract (Var.named "let-rec-marker") $ do
12261235
e <- annotateLetRecBindings isTop letrec
12271236
synthesize e
1228-
want <- substAndDefaultWanted want ctx2
1229-
pure (generalizeExistentials ctx2 t, want)
1237+
want <- substAndDefaultWanted want ctx2 solved2
1238+
pure (generalizeExistentials ctx2 solved2 t, want)
12301239
synthesizeWanted (Term.Handle' h body) = do
12311240
-- To synthesize a handle block, we first synthesize the handler h,
12321241
-- then push its allowed abilities onto the current ambient set when
@@ -1403,10 +1412,10 @@ synthesizeBinding top binding = do
14031412
else
14041413
if top
14051414
then do
1406-
ctx <- retract
1407-
pure ((generalizeExistentials ctx tb, []), substituteSolved ctx)
1415+
(ctx, solved) <- retract
1416+
pure ((generalizeExistentials ctx solved tb, []), substituteSolved solved)
14081417
else do
1409-
ctx <- retract
1418+
(ctx, solved) <- retract
14101419
-- Note: this is conservative about what we avoid
14111420
-- generalizing. Right now only TDNR causes variables to be
14121421
-- retained. It might be possible to make this happen for any
@@ -1423,7 +1432,7 @@ synthesizeBinding top binding = do
14231432
| Solved b _ sa <- ctx,
14241433
retain b,
14251434
TypeVar.Existential _ v <-
1426-
Set.toList . ABT.freeVars . applyCtx ctx $ Type.getPolytype sa
1435+
Set.toList . ABT.freeVars . applyCtx solved $ Type.getPolytype sa
14271436
]
14281437
keep = Set.fromList (erecs ++ srecs)
14291438
p (Existential _ v)
@@ -1433,8 +1442,8 @@ synthesizeBinding top binding = do
14331442
(repush, discard) = partitionEithers $ fmap p ctx
14341443
appendContext repush
14351444
markRetained keep
1436-
let tf = generalizeExistentials discard (applyCtx ctx tb)
1437-
pure ((tf, []), substituteSolved ctx)
1445+
let tf = generalizeExistentials discard (computeSolvedExistentials discard) (applyCtx solved tb)
1446+
pure ((tf, []), substituteSolved solved)
14381447

14391448
getDataConstructorsAtType :: forall v loc. (Ord loc, Var v) => Type v loc -> M v loc (EnumeratedConstructors (TypeVar v loc) v loc)
14401449
getDataConstructorsAtType t0 = do
@@ -1856,7 +1865,7 @@ annotateLetRecBindings isTop letrec =
18561865
annotateLetRecBindings' useUserAnnotations = do
18571866
(bindings, body) <- letrec freshenVar
18581867
let vs = map fst bindings
1859-
((bindings, bindingTypes), ctx2) <- markThenRetract Var.inferOther $ do
1868+
((bindings, bindingTypes), ctx2, solved2) <- markThenRetract Var.inferOther $ do
18601869
let f (v, binding) = case binding of
18611870
-- If user has provided an annotation, we use that
18621871
Term.Ann' e t | useUserAnnotations -> do
@@ -1891,7 +1900,7 @@ annotateLetRecBindings isTop letrec =
18911900
-- compute generalized types `gt1, gt2 ...` for each binding `b1, b2...`;
18921901
-- add annotations `v1 : gt1, v2 : gt2 ...` to the context
18931902
let bindingArities = Term.arity <$> bindings
1894-
gen bindingType _arity = generalizeExistentials ctx2 bindingType
1903+
gen bindingType _arity = generalizeExistentials ctx2 solved2 bindingType
18951904
bindingTypesGeneralized = zipWith gen bindingTypes bindingArities
18961905
annotations = zipWith Ann vs bindingTypesGeneralized
18971906
appendContext annotations
@@ -2067,12 +2076,12 @@ forcedData ty = Type.freeVars ty
20672076

20682077
-- | Apply the context to the input type, then convert any unsolved existentials
20692078
-- to universals.
2070-
generalizeExistentials :: (Var v, Ord loc) => [Element v loc] -> Type v loc -> Type v loc
2071-
generalizeExistentials ctx ty0 = generalizeP pred ctx ty
2079+
generalizeExistentials :: (Var v, Ord loc) => [Element v loc] -> Map v (Monotype v loc) -> Type v loc -> Type v loc
2080+
generalizeExistentials ctx solved ty0 = generalizeP pred ctx solved ty
20722081
where
20732082
gens = Set.fromList $ mapMaybe (fmap snd . existentialP) ctx
20742083

2075-
ty = discardCovariant gens $ applyCtx ctx ty0
2084+
ty = discardCovariant gens $ applyCtx solved ty0
20762085
fvs = Type.freeVars ty
20772086

20782087
pred e
@@ -2086,9 +2095,10 @@ generalizeP ::
20862095
(Ord loc) =>
20872096
(Element v loc -> Maybe (TypeVar v loc, v)) ->
20882097
[Element v loc] ->
2098+
Map v (Monotype v loc) ->
20892099
Type v loc ->
20902100
Type v loc
2091-
generalizeP p ctx0 ty = foldr gen (applyCtx ctx0 ty) ctx
2101+
generalizeP p ctx0 solved ty = foldr gen (applyCtx solved ty) ctx
20922102
where
20932103
ctx = mapMaybe p ctx0
20942104

@@ -2127,12 +2137,12 @@ checkScoped ::
21272137
M v loc (Type v loc, Wanted v loc)
21282138
checkScoped e (Type.Forall' body) = do
21292139
v <- ABT.freshen body freshenTypeVar
2130-
((ty, want), pop) <- markThenRetract v $ do
2140+
((ty, want), pop, popSolved) <- markThenRetract v $ do
21312141
x <- extendUniversal v
21322142
let e' = Term.substTypeVar (ABT.variable body) (universal' () x) e
21332143
checkScoped e' (ABT.bindInheritAnnotation body (universal' () x))
2134-
want <- substAndDefaultWanted want pop
2135-
pure (generalizeP variableP pop ty, want)
2144+
want <- substAndDefaultWanted want pop popSolved
2145+
pure (generalizeP variableP pop popSolved ty, want)
21362146
checkScoped e t = do
21372147
t <- existentializeArrows t
21382148
(t,) <$> check e t
@@ -2154,8 +2164,9 @@ markThenRetractWanted ::
21542164
v ->
21552165
M v loc (Wanted v loc) ->
21562166
M v loc (Wanted v loc)
2157-
markThenRetractWanted v m =
2158-
markThenRetract v m >>= uncurry substAndDefaultWanted
2167+
markThenRetractWanted v m = do
2168+
(a, es, solved) <- markThenRetract v m
2169+
substAndDefaultWanted a es solved
21592170

21602171
-- This function handles merging two sets of wanted abilities, along
21612172
-- with some pruning of the set. This means that coalescing a list
@@ -2261,9 +2272,10 @@ substAndDefaultWanted ::
22612272
(Ord loc) =>
22622273
Wanted v loc ->
22632274
[Element v loc] ->
2275+
Map v (Monotype v loc) ->
22642276
M v loc (Wanted v loc)
2265-
substAndDefaultWanted want ctx
2266-
| want <- (fmap . fmap) (applyCtx ctx) want,
2277+
substAndDefaultWanted want ctx solved
2278+
| want <- (fmap . fmap) (applyCtx solved) want,
22672279
want <- filter q want,
22682280
repush <- filter keep ctx =
22692281
appendContext repush *> coalesceWanted want []
@@ -3292,14 +3304,14 @@ synthesizeClosed' abilities term = do
32923304
-- save current context, for restoration when done
32933305
ctx0 <- getContext
32943306
setContext context0
3295-
(t, ctx) <- markThenRetract (Var.named "start") $ do
3307+
(t, ctx, solved) <- markThenRetract (Var.named "start") $ do
32963308
-- retract will cause notes to be written out for
32973309
-- any `Blank`-tagged existentials passing out of scope
32983310
(t, want) <- synthesize term
32993311
scope (InSynthesize term) $
33003312
t <$ subAbilities want abilities
33013313
setContext ctx0 -- restore the initial context
3302-
pure $ generalizeExistentials ctx t
3314+
pure $ generalizeExistentials ctx solved t
33033315

33043316
-- Check if the given typechecking action succeeds.
33053317
succeeds :: M v loc a -> TotalM v loc Bool
@@ -3380,7 +3392,7 @@ instance (Var v) => Show (Element v loc) where
33803392
show (Marker v) = "|" ++ Text.unpack (Var.name v) ++ "|"
33813393

33823394
instance (Ord loc, Var v) => Show (Context v loc) where
3383-
show ctx@(Context es) = "Γ\n " ++ (intercalate "\n " . map (showElem ctx . fst)) (reverse es)
3395+
show ctx@(Context es _) = "Γ\n " ++ (intercalate "\n " . map (showElem ctx . fst)) (reverse es)
33843396
where
33853397
showElem _ctx (Var v) = case v of
33863398
TypeVar.Universal x -> "@" <> show x

0 commit comments

Comments
 (0)