|
1
|
1
|
-- (c) The University of Glasgow 2006
|
|
2
|
2
|
{-# LANGUAGE CPP #-}
|
|
3
|
3
|
|
|
4
|
|
-module GHC.Core.Coercion.Opt( optCoProgram, optCoRefl )
|
|
5
|
|
-where
|
|
|
4
|
+module GHC.Core.Coercion.Opt( optCoProgram, optCoRefl ) where
|
|
6
|
5
|
|
|
7
|
6
|
import GHC.Prelude
|
|
8
|
7
|
|
| ... |
... |
@@ -28,7 +27,6 @@ import GHC.Data.Pair |
|
28
|
27
|
import GHC.Data.TrieMap
|
|
29
|
28
|
|
|
30
|
29
|
import GHC.Utils.Outputable
|
|
31
|
|
-import GHC.Utils.Constants (debugIsOn)
|
|
32
|
30
|
import GHC.Utils.Misc
|
|
33
|
31
|
import GHC.Utils.Panic
|
|
34
|
32
|
|
| ... |
... |
@@ -195,44 +193,50 @@ We use the following invariants: |
|
195
|
193
|
%* *
|
|
196
|
194
|
%********************************************************************* -}
|
|
197
|
195
|
|
|
198
|
|
-optCoProgram :: CoreProgram -> CoreProgram
|
|
|
196
|
+optCoProgram :: Bool -- True <=> do extra checks/tracking
|
|
|
197
|
+ -> CoreProgram -> CoreProgram
|
|
199
|
198
|
-- Apply optCoercion to all coercions in /expressions/
|
|
200
|
199
|
-- There may also be coercions in /types/ but we `optCoProgram` doesn't
|
|
201
|
200
|
-- look at them; they are typically fewer and smaller, and it doesn't seem
|
|
202
|
201
|
-- worth the cost of traversing and rebuilding all the types in the program.
|
|
203
|
|
-optCoProgram binds
|
|
|
202
|
+optCoProgram do_checks binds
|
|
204
|
203
|
= map go binds
|
|
205
|
204
|
where
|
|
206
|
|
- go (NonRec b r) = NonRec b (optCoExpr in_scope r)
|
|
207
|
|
- go (Rec prs) = Rec (mapSnd (optCoExpr in_scope) prs)
|
|
|
205
|
+ go (NonRec b r) = NonRec b (optCoExpr (do_checks, in_scope) r)
|
|
|
206
|
+ go (Rec prs) = Rec (mapSnd (optCoExpr (do_checks, in_scope)) prs)
|
|
|
207
|
+
|
|
208
|
208
|
in_scope = mkInScopeSetList (bindersOfBinds binds)
|
|
209
|
209
|
-- Put all top-level binders into scope; it is possible to have
|
|
210
|
210
|
-- forward references. See Note [Glomming] in GHC.Core.Opt.OccurAnal
|
|
211
|
211
|
|
|
212
|
|
-optCoExpr :: InScopeSet -> CoreExpr -> CoreExpr
|
|
213
|
|
-optCoExpr _ e@(Var {}) = e
|
|
214
|
|
-optCoExpr _ e@(Lit {}) = e
|
|
215
|
|
-optCoExpr _ e@(Type {}) = e
|
|
|
212
|
+optCoExpr :: (Bool, InScopeSet) -> CoreExpr -> CoreExpr
|
|
|
213
|
+optCoExpr !_ e@(Var {}) = e
|
|
|
214
|
+optCoExpr _ e@(Lit {}) = e
|
|
|
215
|
+optCoExpr _ e@(Type {}) = e
|
|
216
|
216
|
optCoExpr is (App e1 e2) = App (optCoExpr is e1) (optCoExpr is e2)
|
|
217
|
|
-optCoExpr is (Lam b e) = Lam b (optCoExpr (is `extendInScopeSet` b) e)
|
|
|
217
|
+optCoExpr is (Lam b e) = Lam b (optCoExpr (is `add_bndr` b) e)
|
|
218
|
218
|
optCoExpr is (Coercion co) = Coercion (optCo is co)
|
|
219
|
219
|
optCoExpr is (Cast e co) = Cast (optCoExpr is e) (optCo is co)
|
|
220
|
220
|
optCoExpr is (Tick t e) = Tick t (optCoExpr is e)
|
|
221
|
|
-optCoExpr is (Let (NonRec b r) e) = Let (NonRec b (optCoExpr is r))
|
|
222
|
|
- (optCoExpr (is `extendInScopeSet` b) e)
|
|
223
|
|
-optCoExpr is (Let (Rec prs) e) = Let (Rec (mapSnd (optCoExpr is') prs))
|
|
224
|
|
- (optCoExpr is' e)
|
|
225
|
|
- where
|
|
226
|
|
- is' = is `extendInScopeSetList` map fst prs
|
|
227
|
|
-optCoExpr is (Case e b ty alts) = Case (optCoExpr is e) b ty
|
|
228
|
|
- (map (optCoAlt (is `extendInScopeSet` b)) alts)
|
|
|
221
|
+optCoExpr is (Let (NonRec b r) e) = Let (NonRec b (optCoExpr is r))
|
|
|
222
|
+ (optCoExpr (is `add_bndr` b) e)
|
|
|
223
|
+optCoExpr is (Let (Rec prs) e) = Let (Rec (mapSnd (optCoExpr is') prs))
|
|
|
224
|
+ (optCoExpr is' e)
|
|
|
225
|
+ where
|
|
|
226
|
+ is' = is `add_bndrs` map fst prs
|
|
|
227
|
+optCoExpr is (Case e b ty alts) = Case (optCoExpr is e) b ty (map do_alt alts)
|
|
|
228
|
+ where
|
|
|
229
|
+ is' = is `add_bndr` b
|
|
|
230
|
+ do_alt (Alt k bs e) = Alt k bs (optCoExpr (is' `add_bndrs` bs) e)
|
|
229
|
231
|
|
|
230
|
|
-optCo :: InScopeSet -> Coercion -> Coercion
|
|
231
|
|
-optCo is co = optCoercion (mkEmptySubst is) co
|
|
|
232
|
+add_bndr :: (Bool, InScopeSet) -> Var -> (Bool, InScopeSet)
|
|
|
233
|
+add_bndr (do_checks, is) b = (do_checks, is `extendInScopeSet` b)
|
|
232
|
234
|
|
|
233
|
|
-optCoAlt :: InScopeSet -> CoreAlt -> CoreAlt
|
|
234
|
|
-optCoAlt is (Alt k bs e)
|
|
235
|
|
- = Alt k bs (optCoExpr (is `extendInScopeSetList` bs) e)
|
|
|
235
|
+add_bndrs :: (Bool, InScopeSet) -> [Var] -> (Bool, InScopeSet)
|
|
|
236
|
+add_bndrs (do_checks, is) bs = (do_checks, is `extendInScopeSetList` bs)
|
|
|
237
|
+
|
|
|
238
|
+optCo :: (Bool, InScopeSet) -> Coercion -> Coercion
|
|
|
239
|
+optCo (do_checks, is) co = optCoercionChecking do_checks (mkEmptySubst is) co
|
|
236
|
240
|
|
|
237
|
241
|
|
|
238
|
242
|
{- **********************************************************************
|
| ... |
... |
@@ -260,8 +264,8 @@ optCoAlt is (Alt k bs e) |
|
260
|
264
|
optCoRefl :: Bool -> Subst -> Coercion -> Coercion
|
|
261
|
265
|
-- See Note [optCoRefl]
|
|
262
|
266
|
optCoRefl check_stuff subst in_co
|
|
263
|
|
- | isEmptyTCvSubst subst = in_co
|
|
264
|
|
- | not check_stuff = opt_co_refl subst in_co
|
|
|
267
|
+ | not check_stuff
|
|
|
268
|
+ = opt_co_refl subst in_co
|
|
265
|
269
|
| otherwise -- Do expensive checks
|
|
266
|
270
|
= let out_co = opt_co_refl subst in_co
|
|
267
|
271
|
(Pair in_l in_r) = coercionKind in_co
|
| ... |
... |
@@ -271,22 +275,29 @@ optCoRefl check_stuff subst in_co |
|
271
|
275
|
in_co' = substCo subst in_co
|
|
272
|
276
|
in_sz = coercionSize in_co'
|
|
273
|
277
|
out_sz = coercionSize out_co
|
|
274
|
|
- in if not ((in_l' `eqType` out_l) && (in_r' `eqType` out_r))
|
|
275
|
|
- then pprTrace "Yikes: optReflCo changes type"
|
|
276
|
|
- (vcat [ text "in_l':" <+> ppr in_l'
|
|
277
|
|
- , text "in_r':" <+> ppr in_r'
|
|
278
|
|
- , text "out_l:" <+> ppr out_l
|
|
279
|
|
- , text "out_r:" <+> ppr out_r
|
|
280
|
|
- , text "in_co:" <+> ppr in_co
|
|
281
|
|
- , text "out_co:" <+> ppr out_co ]) $
|
|
282
|
|
- out_co
|
|
283
|
|
- else if out_sz < in_sz
|
|
284
|
|
- then pprTrace "optCoRefl: size reduction:"
|
|
285
|
|
- (vcat [ int in_sz <+> text "-->" <+> int out_sz
|
|
286
|
|
- , text "in_co':" <+> ppr in_co'
|
|
287
|
|
- , text "out_co:" <+> ppr out_co ]) $
|
|
288
|
|
- out_co
|
|
289
|
|
- else out_co
|
|
|
278
|
+
|
|
|
279
|
+ details = setPprDebug False $
|
|
|
280
|
+ vcat [ text "in_l':" <+> ppr in_l'
|
|
|
281
|
+ , text "in_r':" <+> ppr in_r'
|
|
|
282
|
+ , text "out_l:" <+> ppr out_l
|
|
|
283
|
+ , text "out_r:" <+> ppr out_r
|
|
|
284
|
+ , text "in_co:" <+> ppr in_co
|
|
|
285
|
+ , text "out_co:" <+> ppr out_co ]
|
|
|
286
|
+
|
|
|
287
|
+ in pprTraceWhen (not ((in_l' `eqTypeIgnoringMultiplicity` out_l) &&
|
|
|
288
|
+ (in_r' `eqTypeIgnoringMultiplicity` out_r)))
|
|
|
289
|
+ "Yikes: optReflCo changes type" details $
|
|
|
290
|
+
|
|
|
291
|
+ pprTraceWhen (out_sz > in_sz)
|
|
|
292
|
+ "Yikes: optReflCo makes coercion bigger"
|
|
|
293
|
+ (vcat [ int in_sz <+> text "-->" <+> int out_sz
|
|
|
294
|
+ , whenPprDebug details ]) $
|
|
|
295
|
+
|
|
|
296
|
+ pprTraceWhen (in_sz > out_sz)
|
|
|
297
|
+ "optCoRefl: size reduction:"
|
|
|
298
|
+ (vcat [ int in_sz <+> text "-->" <+> int out_sz
|
|
|
299
|
+ , whenPprDebug details ])
|
|
|
300
|
+ out_co
|
|
290
|
301
|
|
|
291
|
302
|
opt_co_refl :: Subst -> InCoercion -> OutCoercion
|
|
292
|
303
|
opt_co_refl subst co = go co
|
| ... |
... |
@@ -308,16 +319,18 @@ opt_co_refl subst co = go co |
|
308
|
319
|
go (HoleCo h) = HoleCo $!! go_hole h
|
|
309
|
320
|
go (SymCo co) = mkSymCo $!! go co
|
|
310
|
321
|
go (KindCo co) = mkKindCo $!! go co
|
|
311
|
|
- go (SubCo co) = mkSubCo $!! go co
|
|
|
322
|
+ go (SubCo co) = mkSubCo $!! (let co' = go co in
|
|
|
323
|
+ if isReflexiveCo co' && not (isReflCo co')
|
|
|
324
|
+ then pprTrace "yuike" (ppr co $$ ppr co') co'
|
|
|
325
|
+ else co')
|
|
312
|
326
|
go (SelCo n co) = mkSelCo n $!! go co
|
|
313
|
|
- go (LRCo n co) = mkLRCo n $!! go co
|
|
314
|
|
- go (AppCo co1 co2) = mkAppCo $!! go co1 $!! go co2
|
|
315
|
|
- go (InstCo co1 co2) = mkInstCo $!! go co1 $!! go co2
|
|
|
327
|
+ go (LRCo n co) = mkLRCo n $!! go co
|
|
|
328
|
+ go (AppCo co1 co2) = mkAppCo $!! go co1 $!! go co2
|
|
|
329
|
+ go (InstCo co1 co2) = mkInstCo $!! go co1 $!! go co2
|
|
316
|
330
|
go (FunCo r afl afr com coa cor) = mkFunCo2 r afl afr
|
|
317
|
331
|
$!! go com $!! go coa $!! go cor
|
|
318
|
332
|
go (TyConAppCo r tc cos) = mkTyConAppCo r tc $!! go_s cos
|
|
319
|
|
- go (UnivCo p r lt rt cos) = mkUnivCo p $!! (go_s cos) $!! r
|
|
320
|
|
- $!! (go_ty lt) $!! (go_ty rt)
|
|
|
333
|
+ go (UnivCo p r lt rt cos) = optUnivCo p $!! go_s cos $!! r $!! go_ty lt $!! go_ty rt
|
|
321
|
334
|
go (AxiomCo ax cos) = mkAxiomCo ax $!! (go_s cos)
|
|
322
|
335
|
|
|
323
|
336
|
go (ForAllCo v vl vr mco co) = mkForAllCo v' vl vr
|
| ... |
... |
@@ -354,25 +367,53 @@ opt_co_refl subst co = go co |
|
354
|
367
|
data GobbleState = GS OutCoercion (TypeMap GobbleState)
|
|
355
|
368
|
-- The map is keyed by OutType
|
|
356
|
369
|
|
|
|
370
|
+optUnivCo :: UnivCoProvenance -> [Coercion]
|
|
|
371
|
+ -> Role -> Type -> Type -> Coercion
|
|
|
372
|
+optUnivCo prov cos role lty rty
|
|
|
373
|
+ | lty `eqTypeIgnoringMultiplicity` rty
|
|
|
374
|
+ -- We only Lint multiplicities in the output of the typechecker, as
|
|
|
375
|
+ -- described in Note [Linting linearity] in GHC.Core.Lint. This means
|
|
|
376
|
+ -- we can use 'eqTypeIgnoringMultiplicity' instead of 'eqType' below.
|
|
|
377
|
+ --
|
|
|
378
|
+ -- In particular, this gets rid of 'SubMultProv' coercions that were
|
|
|
379
|
+ -- introduced for typechecking multiplicities of data constructors, as
|
|
|
380
|
+ -- described in Note [Typechecking data constructors] in GHC.Tc.Gen.Head.
|
|
|
381
|
+ = mkReflCo role lty
|
|
|
382
|
+
|
|
|
383
|
+ | otherwise
|
|
|
384
|
+ = UnivCo { uco_prov = prov, uco_role = role
|
|
|
385
|
+ , uco_lty = lty, uco_rty = rty
|
|
|
386
|
+ , uco_deps = cos }
|
|
|
387
|
+
|
|
357
|
388
|
{- **********************************************************************
|
|
358
|
389
|
%* *
|
|
359
|
390
|
optCoercion
|
|
360
|
391
|
%* *
|
|
361
|
392
|
%********************************************************************* -}
|
|
362
|
393
|
|
|
363
|
|
-optCoercion :: Subst -> Coercion -> NormalCo
|
|
|
394
|
+optCoercionChecking :: Bool -> Subst -> Coercion -> NormalCo
|
|
364
|
395
|
-- ^ optCoercion applies a substitution to a coercion,
|
|
365
|
396
|
-- *and* optimises it to reduce its size
|
|
366
|
397
|
-- The substitution is a vestige of an earlier era, when the coercion optimiser
|
|
367
|
398
|
-- was called by the Simplifier; now it is always empty
|
|
368
|
399
|
-- But I have not removed it in case we ever want it back.
|
|
369
|
|
-optCoercion env co
|
|
370
|
|
- | debugIsOn
|
|
371
|
|
- = let out_co = opt_co1 lc NotSwapped co
|
|
372
|
|
- (Pair in_ty1 in_ty2, in_role) = coercionKindRole co
|
|
|
400
|
+optCoercionChecking do_checks subst in_co
|
|
|
401
|
+ | not do_checks
|
|
|
402
|
+ = optCoercion1 subst in_co
|
|
|
403
|
+
|
|
|
404
|
+ | otherwise
|
|
|
405
|
+ = let out_co = optCoercion1 subst in_co
|
|
|
406
|
+
|
|
|
407
|
+ (Pair in_ty1 in_ty2, in_role) = coercionKindRole in_co
|
|
373
|
408
|
(Pair out_ty1 out_ty2, out_role) = coercionKindRole out_co
|
|
374
|
409
|
|
|
375
|
|
- details = vcat [ text "in_co:" <+> ppr co
|
|
|
410
|
+ in_co' = substCo subst in_co
|
|
|
411
|
+ Pair in_ty1' in_ty2' = coercionKind in_co'
|
|
|
412
|
+
|
|
|
413
|
+ in_size = coercionSize in_co'
|
|
|
414
|
+ out_size = coercionSize out_co
|
|
|
415
|
+
|
|
|
416
|
+ details = vcat [ text "in_co:" <+> ppr in_co
|
|
376
|
417
|
, text "in_ty1:" <+> ppr in_ty1
|
|
377
|
418
|
, text "in_ty2:" <+> ppr in_ty2
|
|
378
|
419
|
, text "out_co:" <+> ppr out_co
|
| ... |
... |
@@ -382,22 +423,34 @@ optCoercion env co |
|
382
|
423
|
, text "out_role:" <+> ppr out_role
|
|
383
|
424
|
]
|
|
384
|
425
|
in
|
|
385
|
|
- warnPprTrace (not (isReflCo out_co) && isReflexiveCo out_co)
|
|
386
|
|
- "optCoercion: reflexive but not refl" details $
|
|
|
426
|
+ -- Check that the type isn't changed
|
|
|
427
|
+ pprTraceWhen (not ((in_ty1' `eqTypeIgnoringMultiplicity` out_ty1) &&
|
|
|
428
|
+ (in_ty2' `eqTypeIgnoringMultiplicity` out_ty2)))
|
|
|
429
|
+ "optCoercion changes type!!!" details $
|
|
|
430
|
+
|
|
387
|
431
|
-- The coercion optimiser should usually optimise
|
|
388
|
432
|
-- co:ty~ty --> Refl ty
|
|
389
|
433
|
-- But given a silly `newtype N = MkN N`, the axiom has type (N ~ N),
|
|
390
|
434
|
-- and so that can trigger this warning (e.g. test str002).
|
|
391
|
435
|
-- Maybe we should optimise that coercion to (Refl N), but it
|
|
392
|
436
|
-- just doesn't seem worth the bother
|
|
393
|
|
- out_co
|
|
|
437
|
+ pprTraceWhen (not (isReflCo out_co) && isReflexiveCo out_co)
|
|
|
438
|
+ "optCoercion: reflexive but not refl" details $
|
|
394
|
439
|
|
|
395
|
|
- | otherwise
|
|
396
|
|
- = opt_co1 lc NotSwapped co
|
|
397
|
|
- where
|
|
398
|
|
- lc = mkSubstLiftingContext env
|
|
399
|
|
--- ppr_one cv = ppr cv <+> dcolon <+> ppr (coVarKind cv)
|
|
|
440
|
+ -- Show a trace if the coercion shrinks
|
|
|
441
|
+ pprTraceWhen (in_size > out_size)
|
|
|
442
|
+ "optCoercion:size reduction"
|
|
|
443
|
+ (vcat [ int in_size <+> text "-->" <+> int out_size
|
|
|
444
|
+ , whenPprDebug $ -- Show details with -dppr-debug
|
|
|
445
|
+ setPprDebug False $
|
|
|
446
|
+ details ]) $
|
|
|
447
|
+ out_co
|
|
400
|
448
|
|
|
|
449
|
+optCoercion1 :: Subst -> Coercion -> NormalCo
|
|
|
450
|
+-- Starting point for the coercion optimiser: does no checking
|
|
|
451
|
+-- but initialises the substitution and calls opt_co1
|
|
|
452
|
+optCoercion1 subst co
|
|
|
453
|
+ = opt_co1 (mkSubstLiftingContext subst) NotSwapped co
|
|
401
|
454
|
|
|
402
|
455
|
type NormalCo = Coercion
|
|
403
|
456
|
-- Invariants:
|
| ... |
... |
@@ -791,19 +844,7 @@ opt_univ env sym prov deps role ty1 ty2 |
|
791
|
844
|
deps' = map (opt_co1 env sym) deps
|
|
792
|
845
|
(ty1'', ty2'') = swapSym sym (ty1', ty2')
|
|
793
|
846
|
in
|
|
794
|
|
- -- We only Lint multiplicities in the output of the typechecker, as
|
|
795
|
|
- -- described in Note [Linting linearity] in GHC.Core.Lint. This means
|
|
796
|
|
- -- we can use 'eqTypeIgnoringMultiplicity' instead of 'eqType' below.
|
|
797
|
|
- --
|
|
798
|
|
- -- In particular, this gets rid of 'SubMultProv' coercions that were
|
|
799
|
|
- -- introduced for typechecking multiplicities of data constructors, as
|
|
800
|
|
- -- described in Note [Typechecking data constructors] in GHC.Tc.Gen.Head.
|
|
801
|
|
- if ty1'' `eqTypeIgnoringMultiplicity` ty2''
|
|
802
|
|
- then mkReflCo role ty2''
|
|
803
|
|
- else
|
|
804
|
|
- UnivCo { uco_prov = prov, uco_role = role
|
|
805
|
|
- , uco_lty = ty1'', uco_rty = ty2''
|
|
806
|
|
- , uco_deps = deps' }
|
|
|
847
|
+ optUnivCo prov deps' role ty1'' ty2''
|
|
807
|
848
|
|
|
808
|
849
|
{-
|
|
809
|
850
|
opt_univ env PhantomProv cvs _r ty1 ty2
|