[commit: ghc] master: Detect levity-polymorphic uses of unsafeCoerce# (e40db7b)
git at git.haskell.org
git at git.haskell.org
Wed Dec 13 12:57:18 UTC 2017
Repository : ssh://git@git.haskell.org/ghc
On branch : master
Link : http://ghc.haskell.org/trac/ghc/changeset/e40db7b1676627f5291b463405338e7b69fa3f69/ghc
>---------------------------------------------------------------
commit e40db7b1676627f5291b463405338e7b69fa3f69
Author: Simon Peyton Jones <simonpj at microsoft.com>
Date: Wed Dec 13 10:46:26 2017 +0000
Detect levity-polymorphic uses of unsafeCoerce#
This bug was shown up by Trac #14561. The deguarer carefully
detects unsaturated and levity-polymorphic uses of primops,
but not of things like unsafeCoerce#.
The fix is simple: see Note [Levity-polymorphic Ids] in Id.
>---------------------------------------------------------------
e40db7b1676627f5291b463405338e7b69fa3f69
compiler/basicTypes/Id.hs | 26 +++++++++++++++++++---
compiler/deSugar/DsExpr.hs | 3 ++-
testsuite/tests/polykinds/T14561.hs | 18 +++++++++++++++
.../T5472.stdout => polykinds/T14561.stderr} | 0
testsuite/tests/polykinds/all.T | 1 +
5 files changed, 44 insertions(+), 4 deletions(-)
diff --git a/compiler/basicTypes/Id.hs b/compiler/basicTypes/Id.hs
index 63ca38c..fbece0e 100644
--- a/compiler/basicTypes/Id.hs
+++ b/compiler/basicTypes/Id.hs
@@ -119,7 +119,8 @@ module Id (
import GhcPrelude
import DynFlags
-import CoreSyn ( CoreRule, isStableUnfolding, evaldUnfolding, Unfolding( NoUnfolding ) )
+import CoreSyn ( CoreRule, isStableUnfolding, evaldUnfolding,
+ isCompulsoryUnfolding, Unfolding( NoUnfolding ) )
import IdInfo
import BasicTypes
@@ -519,7 +520,8 @@ hasNoBinding id = case Var.idDetails id of
PrimOpId _ -> True -- See Note [Primop wrappers]
FCallId _ -> True
DataConWorkId dc -> isUnboxedTupleCon dc || isUnboxedSumCon dc
- _ -> False
+ _ -> isCompulsoryUnfolding (idUnfolding id)
+ -- See Note [Levity-polymorphic Ids]
isImplicitId :: Id -> Bool
-- ^ 'isImplicitId' tells whether an 'Id's info is implied by other
@@ -541,7 +543,25 @@ isImplicitId id
idIsFrom :: Module -> Id -> Bool
idIsFrom mod id = nameIsLocalOrFrom mod (idName id)
-{-
+{- Note [Levity-polymorphic Ids]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Some levity-polymorphic Ids must be applied and and inlined, not left
+un-saturated. Example:
+ unsafeCoerceId :: forall r1 r2 (a::TYPE r1) (b::TYPE r2). a -> b
+
+This has a compulsory unfolding because we can't lambda-bind those
+arguments. But the compulsory unfolding may leave levity-polymorphic
+lambdas if it is not applied to enough arguments; e.g. (Trac #14561)
+ bad :: forall (a :: TYPE r). a -> a
+ bad = unsafeCoerce#
+
+The desugar has special magic to detect such cases: DsExpr.badUseOfLevPolyPrimop.
+And we want that magic to apply to levity-polymorphic compulsory-inline things.
+The easiest way to do this is for hasNoBinding to return True of all things
+that have compulsory unfolding. A very Ids with a compulsory unfolding also
+have a binding, but it does not harm to say they don't here, and its a very
+simple way to fix Trac #14561.
+
Note [Primop wrappers]
~~~~~~~~~~~~~~~~~~~~~~
Currently hasNoBinding claims that PrimOpIds don't have a curried
diff --git a/compiler/deSugar/DsExpr.hs b/compiler/deSugar/DsExpr.hs
index 635a9c6..2f3739e 100644
--- a/compiler/deSugar/DsExpr.hs
+++ b/compiler/deSugar/DsExpr.hs
@@ -260,7 +260,8 @@ ds_expr _ (HsLit lit) = dsLit (convertLit lit)
ds_expr _ (HsOverLit lit) = dsOverLit lit
ds_expr _ (HsWrap co_fn e)
- = do { e' <- ds_expr True e
+ = do { e' <- ds_expr True e -- This is the one place where we recurse to
+ -- ds_expr (passing True), rather than dsExpr
; wrap' <- dsHsWrapper co_fn
; dflags <- getDynFlags
; let wrapped_e = wrap' e'
diff --git a/testsuite/tests/polykinds/T14561.hs b/testsuite/tests/polykinds/T14561.hs
new file mode 100644
index 0000000..f528e7c
--- /dev/null
+++ b/testsuite/tests/polykinds/T14561.hs
@@ -0,0 +1,18 @@
+{-# LANGUAGE TypeInType #-}
+{-# LANGUAGE RankNTypes #-}
+{-# LANGUAGE PolyKinds #-}
+{-# LANGUAGE MagicHash #-}
+
+module T14561 where
+
+import GHC.Types
+import GHC.Prim
+
+badId :: forall (a :: TYPE r). a -> a
+badId = unsafeCoerce#
+-- Un-saturated application of a levity-polymorphic
+-- function that must be eta-expanded
+
+goodId :: forall (a :: Type). a -> a
+goodId = unsafeCoerce#
+-- But this one is OK
diff --git a/testsuite/tests/deSugar/should_run/T5472.stdout b/testsuite/tests/polykinds/T14561.stderr
similarity index 100%
copy from testsuite/tests/deSugar/should_run/T5472.stdout
copy to testsuite/tests/polykinds/T14561.stderr
diff --git a/testsuite/tests/polykinds/all.T b/testsuite/tests/polykinds/all.T
index 8a03e89..8d0abff 100644
--- a/testsuite/tests/polykinds/all.T
+++ b/testsuite/tests/polykinds/all.T
@@ -180,4 +180,5 @@ test('T14520', normal, compile_fail, [''])
test('T11203', normal, compile_fail, [''])
test('T14555', normal, compile_fail, [''])
test('T14563', normal, compile_fail, [''])
+test('T14561', normal, compile_fail, [''])
More information about the ghc-commits
mailing list