| ... |
... |
@@ -138,7 +138,7 @@ maybeSymCo NotSwapped co = co |
|
138
|
138
|
{- Note [Deep subsumption and WpSubType]
|
|
139
|
139
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
140
|
140
|
When making DeepSubsumption checks, we may end up with hard-to-spot identity wrappers.
|
|
141
|
|
-For example (#26255) suppose we have
|
|
|
141
|
+For example (#26349) suppose we have
|
|
142
|
142
|
(forall a. Eq a => a->a) -> Int <= (forall a. Eq a => a->a) -> Int
|
|
143
|
143
|
The two types are equal so we should certainly get an identity wrapper. But we'll get
|
|
144
|
144
|
tihs wrapper from `tcSubType`:
|
| ... |
... |
@@ -158,11 +158,11 @@ is not sound in general, so we'll end up retaining the lambdas. Two bad results |
|
158
|
158
|
may not be able to make a decent RULE at all, and will fail with "LHS of rule
|
|
159
|
159
|
is too complicated to desugar (#26255)
|
|
160
|
160
|
|
|
161
|
|
-It'd be nicest to solve the problem at source, by never generating those
|
|
|
161
|
+It'd be ideal to solve the problem at source, by never generating those
|
|
162
|
162
|
gruesome wrappers in the first place, but we can't do that because
|
|
163
|
163
|
|
|
164
|
|
-* The WpTyLam and WpTyApp are not introduced together in `tcSubType`, so we can't
|
|
165
|
|
- easily cancel them out. Even if we have
|
|
|
164
|
+* The WpTyLam and WpTyApp are introduced independently, not together, in `tcSubType`,
|
|
|
165
|
+ so we can't easily cancel them out. For example, even if we have
|
|
166
|
166
|
forall a. t1 <= forall a. t2
|
|
167
|
167
|
there is no guarantee that these are the "same" a. E.g.
|
|
168
|
168
|
forall a b. a -> b -> b <= forall x y. y -> x - >x
|
| ... |
... |
@@ -171,17 +171,23 @@ gruesome wrappers in the first place, but we can't do that because |
|
171
|
171
|
* We have not yet done constraint solving so we don't know what evidence will
|
|
172
|
172
|
end up in those WpLet bindings.
|
|
173
|
173
|
|
|
174
|
|
-TL;DR we must generate
|
|
175
|
|
-Here's our solution
|
|
|
174
|
+TL;DR we must generate the wrapper and then optimise it way if it turns out
|
|
|
175
|
+that it is a no-op. Here's our solution
|
|
176
|
176
|
|
|
177
|
177
|
(DSST1) Tag the wrappers generated from a subtype check with WpSubType. In normal
|
|
178
|
178
|
wrappers the binders of a WpTyLam or WpEvLam can scope over the "hole" of the
|
|
179
|
179
|
wrapper -- that is how we introduce type-lambdas and dictionary-lambda into the
|
|
180
|
180
|
terms! But in /subtype/ wrappers, these type/dictionary lambdas only scope over
|
|
181
|
|
- the WpTyApp and WpEvApp nodes in the /same/ wrapper. That is w
|
|
|
181
|
+ the WpTyApp and WpEvApp nodes in the /same/ wrapper. That is what justifies us
|
|
|
182
|
+ eta-reducing the type/dictionarly lambdas.
|
|
182
|
183
|
|
|
183
|
|
-(WpSubType wp) means the same as `wp`, but with the added promise that
|
|
184
|
|
-the binders in `wp` do not scope over the hole
|
|
|
184
|
+ In short, (WpSubType wp) means the same as `wp`, but with the added promise that
|
|
|
185
|
+ the binders in `wp` do not scope over the hole
|
|
|
186
|
+
|
|
|
187
|
+(DSST2) Avoid creating a WpSubType in the common WpHole case, using `mkWpSubType`.
|
|
|
188
|
+
|
|
|
189
|
+(DSST3) When desugaring, try eta-reduction on the payload of a WpSubType.
|
|
|
190
|
+ This is done in `GHC.HsToCore.Binds.dsHsWrapper` by the call to `optSubTypeHsWrapper`.
|
|
185
|
191
|
-}
|
|
186
|
192
|
|
|
187
|
193
|
-- We write wrap :: t1 ~> t2
|
| ... |
... |
@@ -190,7 +196,7 @@ data HsWrapper |
|
190
|
196
|
= WpHole -- The identity coercion
|
|
191
|
197
|
|
|
192
|
198
|
| WpSubType HsWrapper -- (WpSubType wp) Means the same as `wp`
|
|
193
|
|
- -- But see Note [WpSubType]
|
|
|
199
|
+ -- See Note [Deep subsumption and WpSubType] (DSST1)
|
|
194
|
200
|
|
|
195
|
201
|
| WpCompose HsWrapper HsWrapper
|
|
196
|
202
|
-- (wrap1 `WpCompose` wrap2)[e] = wrap1[ wrap2[ e ]]
|
| ... |
... |
@@ -299,6 +305,7 @@ mkWpFun w_arg w_res t1 t2 = WpFun w_arg w_res t1 t2 |
|
299
|
305
|
-- [Wrinkle: Typed Template Haskell] in Note [hasFixedRuntimeRep] in GHC.Tc.Utils.Concrete.
|
|
300
|
306
|
|
|
301
|
307
|
mkWpSubType :: HsWrapper -> HsWrapper
|
|
|
308
|
+-- See (DSST2) in Note [Deep subsumption and WpSubType]
|
|
302
|
309
|
mkWpSubType WpHole = WpHole
|
|
303
|
310
|
mkWpSubType (WpCast co) = WpCast co
|
|
304
|
311
|
mkWpSubType w = WpSubType w
|
| ... |
... |
@@ -393,7 +400,7 @@ hsWrapDictBinders wrap = go wrap |
|
393
|
400
|
go (w1 `WpCompose` w2) = go w1 `unionBags` go w2
|
|
394
|
401
|
go (WpFun _ w _ _) = go w
|
|
395
|
402
|
go WpHole = emptyBag
|
|
396
|
|
- go (WpSubType {}) = emptyBag -- See Note [WpSubType]
|
|
|
403
|
+ go (WpSubType {}) = emptyBag -- See Note [Deep subsumption and WpSubType]
|
|
397
|
404
|
go (WpCast {}) = emptyBag
|
|
398
|
405
|
go (WpEvApp {}) = emptyBag
|
|
399
|
406
|
go (WpTyLam {}) = emptyBag
|
| ... |
... |
@@ -420,9 +427,11 @@ collectHsWrapBinders wrap = go wrap [] |
|
420
|
427
|
|
|
421
|
428
|
|
|
422
|
429
|
optSubTypeHsWrapper :: HsWrapper -> HsWrapper
|
|
|
430
|
+-- This optimiser is used only on the payload of WpSubType
|
|
|
431
|
+-- It finds cases where the entire wrapper is a no-op
|
|
|
432
|
+-- See (DSST3) in Note [Deep subsumption and WpSubType]
|
|
423
|
433
|
optSubTypeHsWrapper wrap
|
|
424
|
|
- = -- pprTrace "optHsWrapper" (vcat [ text "in:" <+> ppr wrap, text "out:" <+> ppr (opt wrap) ]) $
|
|
425
|
|
- opt wrap
|
|
|
434
|
+ = opt wrap
|
|
426
|
435
|
where
|
|
427
|
436
|
opt :: HsWrapper -> HsWrapper
|
|
428
|
437
|
opt w = foldr (<.>) WpHole (opt1 w [])
|
| ... |
... |
@@ -436,18 +445,17 @@ optSubTypeHsWrapper wrap |
|
436
|
445
|
opt1 (WpCast co) ws = opt_co co ws
|
|
437
|
446
|
opt1 (WpEvLam ev) ws = opt_ev_lam ev ws
|
|
438
|
447
|
opt1 (WpTyLam tv) ws = opt_ty_lam tv ws
|
|
439
|
|
- opt1 (WpLet binds) ws = opt_let binds ws
|
|
|
448
|
+ opt1 (WpLet binds) ws = pushWpLet binds ws
|
|
440
|
449
|
opt1 (WpFun w1 w2 sty1 ty2) ws = mk_wp_fun (opt w1) (opt w2) sty1 ty2 ws
|
|
441
|
450
|
opt1 w@(WpTyApp {}) ws = w : ws
|
|
442
|
451
|
opt1 w@(WpEvApp {}) ws = w : ws
|
|
443
|
452
|
|
|
444
|
|
- ------------------
|
|
445
|
|
- opt_let b@(EvBinds bs) ws | isEmptyBag bs = ws
|
|
446
|
|
- | otherwise = WpLet b : ws
|
|
447
|
|
- opt_let (TcEvBinds {}) _ = pprPanic "optHsWrapper1" (ppr wrap)
|
|
448
|
|
-
|
|
449
|
453
|
-----------------
|
|
450
|
454
|
-- (WpTyLam a <+> WpTyApp a <+> w) = w
|
|
|
455
|
+ -- i.e. /\a. <hole> a --> <hole>
|
|
|
456
|
+ -- This is only valid if whatever fills the hole does not mention 'a'
|
|
|
457
|
+ -- But that's guaranteed in subtype-wrappers;
|
|
|
458
|
+ -- see (DSST1) in Note [Deep subsumption and WpSubType]
|
|
451
|
459
|
opt_ty_lam tv (WpTyApp ty : ws)
|
|
452
|
460
|
| Just tv' <- getTyVar_maybe ty
|
|
453
|
461
|
, tv==tv'
|
| ... |
... |
@@ -458,15 +466,12 @@ optSubTypeHsWrapper wrap |
|
458
|
466
|
opt_ty_lam tv (WpCast co : ws)
|
|
459
|
467
|
= opt_co (mkHomoForAllCo tv co) (opt_ty_lam tv ws)
|
|
460
|
468
|
|
|
461
|
|
- opt_ty_lam tv (WpLet bs : ws)
|
|
462
|
|
- | Just ws' <- pushWpLet bs ws
|
|
463
|
|
- = opt_ty_lam tv ws'
|
|
464
|
|
-
|
|
465
|
469
|
opt_ty_lam tv ws
|
|
466
|
470
|
= WpTyLam tv : ws
|
|
467
|
471
|
|
|
468
|
472
|
-----------------
|
|
469
|
473
|
-- (WpEvLam ev <+> WpEvAp ev <+> w) = w
|
|
|
474
|
+ -- Similar notes to WpTyLam
|
|
470
|
475
|
opt_ev_lam ev (WpEvApp ev_tm : ws)
|
|
471
|
476
|
| EvExpr (Var ev') <- ev_tm
|
|
472
|
477
|
, ev == ev'
|
| ... |
... |
@@ -481,9 +486,6 @@ optSubTypeHsWrapper wrap |
|
481
|
486
|
(mkNomReflCo ManyTy)
|
|
482
|
487
|
(mkRepReflCo (idType ev))
|
|
483
|
488
|
co
|
|
484
|
|
- opt_ev_lam ev (WpLet bs : ws)
|
|
485
|
|
- | Just ws' <- pushWpLet bs ws
|
|
486
|
|
- = opt_ev_lam ev ws'
|
|
487
|
489
|
|
|
488
|
490
|
opt_ev_lam ev ws
|
|
489
|
491
|
= WpEvLam ev : ws
|
| ... |
... |
@@ -505,48 +507,64 @@ optSubTypeHsWrapper wrap |
|
505
|
507
|
where
|
|
506
|
508
|
co_ify co1 co2 = opt_co (mk_wp_fun_co w co1 co2) ws
|
|
507
|
509
|
|
|
508
|
|
-pushWpLet :: TcEvBinds -> [HsWrapper] -> Maybe [HsWrapper]
|
|
|
510
|
+pushWpLet :: TcEvBinds -> [HsWrapper] -> [HsWrapper]
|
|
|
511
|
+-- See if we can transform
|
|
|
512
|
+-- WpLet binds <.> w1 <.> .. <.> wn --> w1' <.> .. <.> wn'
|
|
|
513
|
+-- by substitution.
|
|
|
514
|
+-- We do this just for the narrow case when
|
|
|
515
|
+-- - the `binds` are all just v=w, variables only
|
|
|
516
|
+-- - the wi are all WpTyApp, WpEvApp, or WpCast
|
|
|
517
|
+-- This is just enough to get us the eta-reductions that we seek
|
|
509
|
518
|
pushWpLet tc_ev_binds ws
|
|
510
|
|
- | EvBinds binds <- tc_ev_binds
|
|
511
|
|
- , Just env <- evBindIdSwizzle binds
|
|
512
|
|
- = go env ws
|
|
513
|
|
- | otherwise
|
|
514
|
|
- = Nothing
|
|
|
519
|
+ = case tc_ev_binds of
|
|
|
520
|
+ TcEvBinds {} -> pprPanic "pushWpLet" (ppr tc_ev_binds)
|
|
|
521
|
+ EvBinds binds
|
|
|
522
|
+ | isEmptyBag binds
|
|
|
523
|
+ -> ws
|
|
|
524
|
+ | Just env <- ev_bind_swizzle binds
|
|
|
525
|
+ -> case go env ws of
|
|
|
526
|
+ Just ws' -> ws'
|
|
|
527
|
+ Nothing -> bale_out
|
|
|
528
|
+ | otherwise
|
|
|
529
|
+ -> bale_out
|
|
515
|
530
|
where
|
|
|
531
|
+ bale_out = WpLet tc_ev_binds : ws
|
|
|
532
|
+
|
|
516
|
533
|
go :: IdEnv Id -> [HsWrapper] -> Maybe [HsWrapper]
|
|
517
|
534
|
go env (WpCast co : ws) = do { ws' <- go env ws
|
|
518
|
535
|
; return (WpCast co : ws') }
|
|
519
|
536
|
go env (WpTyApp ty : ws) = do { ws' <- go env ws
|
|
520
|
537
|
; return (WpTyApp ty : ws') }
|
|
521
|
538
|
go env (WpEvApp (EvExpr (Var v)) : ws)
|
|
522
|
|
- = do { v' <- swizzleId env v
|
|
|
539
|
+ = do { v' <- swizzle_id env v
|
|
523
|
540
|
; ws' <- go env ws
|
|
524
|
541
|
; return (WpEvApp (EvExpr (Var v')) : ws') }
|
|
525
|
542
|
|
|
526
|
543
|
go _ ws = case ws of
|
|
527
|
544
|
[] -> Just []
|
|
528
|
|
- (_:_) -> Nothing -- Could not fully eliminate it
|
|
|
545
|
+ (_:_) -> Nothing -- Could not fully eliminate the WpLet
|
|
529
|
546
|
|
|
530
|
|
-swizzleId :: IdEnv Id -> Id -> Maybe Id
|
|
531
|
|
--- Nothing <=> ran out of fuel
|
|
532
|
|
--- Shoul
|
|
533
|
|
-swizzleId env v = go 100 v
|
|
534
|
|
- where
|
|
535
|
|
- go :: Int -> EvId -> Maybe EvId
|
|
536
|
|
- go fuel v
|
|
537
|
|
- | fuel == 0 = Nothing
|
|
538
|
|
- | Just v' <- lookupVarEnv env v = go (fuel-1) v'
|
|
539
|
|
- | otherwise = Just v
|
|
540
|
|
-
|
|
541
|
|
-evBindIdSwizzle :: Bag EvBind -> Maybe (IdEnv Id)
|
|
542
|
|
-evBindIdSwizzle evbs = foldl' do_one (Just emptyVarEnv) evbs
|
|
543
|
|
- where
|
|
544
|
|
- do_one :: Maybe (IdEnv Id) -> EvBind -> Maybe (IdEnv Id)
|
|
545
|
|
- do_one Nothing _ = Nothing
|
|
546
|
|
- do_one (Just swizzle) (EvBind {eb_lhs = bndr, eb_rhs = rhs})
|
|
547
|
|
- = case rhs of
|
|
548
|
|
- EvExpr (Var v) -> Just (extendVarEnv swizzle bndr v)
|
|
549
|
|
- _ -> Nothing
|
|
|
547
|
+ swizzle_id :: IdEnv Id -> Id -> Maybe Id
|
|
|
548
|
+ -- Nothing <=> ran out of fuel
|
|
|
549
|
+ -- This is just belt and braces; we should never build bottom evidence
|
|
|
550
|
+ swizzle_id env v = go 100 v
|
|
|
551
|
+ where
|
|
|
552
|
+ go :: Int -> EvId -> Maybe EvId
|
|
|
553
|
+ go fuel v
|
|
|
554
|
+ | fuel == 0 = Nothing
|
|
|
555
|
+ | Just v' <- lookupVarEnv env v = go (fuel-1) v'
|
|
|
556
|
+ | otherwise = Just v
|
|
|
557
|
+
|
|
|
558
|
+ ev_bind_swizzle :: Bag EvBind -> Maybe (IdEnv Id)
|
|
|
559
|
+ -- Succeeds only if the bindings are all var-to-var bindings
|
|
|
560
|
+ ev_bind_swizzle evbs = foldl' do_one (Just emptyVarEnv) evbs
|
|
|
561
|
+ where
|
|
|
562
|
+ do_one :: Maybe (IdEnv Id) -> EvBind -> Maybe (IdEnv Id)
|
|
|
563
|
+ do_one Nothing _ = Nothing
|
|
|
564
|
+ do_one (Just swizzle) (EvBind {eb_lhs = bndr, eb_rhs = rhs})
|
|
|
565
|
+ = case rhs of
|
|
|
566
|
+ EvExpr (Var v) -> Just (extendVarEnv swizzle bndr v)
|
|
|
567
|
+ _ -> Nothing
|
|
550
|
568
|
|
|
551
|
569
|
{-
|
|
552
|
570
|
************************************************************************
|