summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Peyton Jones <simonpj@microsoft.com>2016-03-23 15:37:50 +0000
committerSimon Peyton Jones <simonpj@microsoft.com>2016-03-23 15:39:13 +0000
commitdb9e4eb4e3fe916df7a69da1b211083ad6068aff (patch)
tree52f1d9bcdbdee5dbfb19e053e435a905b42983a6
parent7d5ff3d36946d99ba4691344e04dd0328b2c1ef2 (diff)
downloadhaskell-db9e4eb4e3fe916df7a69da1b211083ad6068aff.tar.gz
Move DFunUnfolding generation to TcInstDcls
The desugarer had a fragile case to generate the Unfolding for a DFun. This patch moves the unfolding generation to TcInstDcls, where all the pieces are to hand. Fixes Trac #11742
-rw-r--r--compiler/deSugar/DsBinds.hs21
-rw-r--r--compiler/typecheck/TcInstDcls.hs42
-rw-r--r--testsuite/tests/roles/should_compile/T8958.stderr13
-rw-r--r--testsuite/tests/simplCore/should_compile/T11742.hs8
-rw-r--r--testsuite/tests/simplCore/should_compile/all.T1
5 files changed, 52 insertions, 33 deletions
diff --git a/compiler/deSugar/DsBinds.hs b/compiler/deSugar/DsBinds.hs
index 5bd31a7900..1c281927a9 100644
--- a/compiler/deSugar/DsBinds.hs
+++ b/compiler/deSugar/DsBinds.hs
@@ -49,7 +49,6 @@ import Id
import MkId(proxyHashId)
import Class
import Name
-import IdInfo ( IdDetails(..) )
import VarSet
import Rules
import VarEnv
@@ -350,9 +349,6 @@ makeCorePair dflags gbl_id is_default_method dict_arity rhs
| is_default_method -- Default methods are *always* inlined
= (gbl_id `setIdUnfolding` mkCompulsoryUnfolding rhs, rhs)
- | DFunId is_newtype <- idDetails gbl_id
- = (mk_dfun_w_stuff is_newtype, rhs)
-
| otherwise
= case inlinePragmaSpec inline_prag of
EmptyInlineSpec -> (gbl_id, rhs)
@@ -376,23 +372,6 @@ makeCorePair dflags gbl_id is_default_method dict_arity rhs
= pprTrace "makeCorePair: arity missing" (ppr gbl_id) $
(gbl_id `setIdUnfolding` mkInlineUnfolding Nothing rhs, rhs)
- -- See Note [ClassOp/DFun selection] in TcInstDcls
- -- See Note [Single-method classes] in TcInstDcls
- mk_dfun_w_stuff is_newtype
- | is_newtype
- = gbl_id `setIdUnfolding` mkInlineUnfolding (Just 0) rhs
- `setInlinePragma` alwaysInlinePragma { inl_sat = Just 0 }
- | otherwise
- = gbl_id `setIdUnfolding` mkDFunUnfolding dfun_bndrs dfun_constr dfun_args
- `setInlinePragma` dfunInlinePragma
- (dfun_bndrs, dfun_body) = collectBinders (simpleOptExpr rhs)
- (dfun_con, dfun_args) = collectArgs dfun_body
- dfun_constr | Var id <- dfun_con
- , DataConWorkId con <- idDetails id
- = con
- | otherwise = pprPanic "makeCorePair: dfun" (ppr rhs)
-
-
dictArity :: [Var] -> Arity
-- Don't count coercion variables in arity
dictArity dicts = count isId dicts
diff --git a/compiler/typecheck/TcInstDcls.hs b/compiler/typecheck/TcInstDcls.hs
index de309d55e9..de27b94e9f 100644
--- a/compiler/typecheck/TcInstDcls.hs
+++ b/compiler/typecheck/TcInstDcls.hs
@@ -33,7 +33,9 @@ import TcDeriv
import TcEnv
import TcHsType
import TcUnify
+import CoreSyn ( Expr(..), mkApps, mkVarApps, mkLams )
import MkCore ( nO_METHOD_BINDING_ERROR_ID )
+import CoreUnfold ( mkInlineUnfolding, mkDFunUnfolding )
import Type
import TcEvidence
import TyCon
@@ -847,8 +849,7 @@ tcInstDecl2 (InstInfo { iSpec = ispec, iBinds = ibinds })
-- con_app_tys = MkD ty1 ty2
-- con_app_scs = MkD ty1 ty2 sc1 sc2
-- con_app_args = MkD ty1 ty2 sc1 sc2 op1 op2
- con_app_tys = wrapId (mkWpTyApps inst_tys)
- (dataConWrapId dict_constr)
+ con_app_tys = wrapId (mkWpTyApps inst_tys) (dataConWrapId dict_constr)
-- NB: We *can* have covars in inst_tys, in the case of
-- promoted GADT constructors.
@@ -860,17 +861,19 @@ tcInstDecl2 (InstInfo { iSpec = ispec, iBinds = ibinds })
inst_tv_tys = mkTyVarTys inst_tyvars
arg_wrapper = mkWpEvVarApps dfun_ev_vars <.> mkWpTyApps inst_tv_tys
- -- Do not inline the dfun; instead give it a magic DFunFunfolding
+ is_newtype = isNewTyCon class_tc
+ dfun_id_w_prags = addDFunPrags dfun_id dict_constr is_newtype
+ inst_tyvars dfun_ev_vars inst_tys sc_meth_ids
dfun_spec_prags
- | isNewTyCon class_tc = SpecPrags []
+ | is_newtype = SpecPrags []
+ | otherwise = SpecPrags spec_inst_prags
-- Newtype dfuns just inline unconditionally,
-- so don't attempt to specialise them
- | otherwise
- = SpecPrags spec_inst_prags
export = ABE { abe_wrap = idHsWrapper
- , abe_poly = dfun_id
- , abe_mono = self_dict, abe_prags = dfun_spec_prags }
+ , abe_poly = dfun_id_w_prags
+ , abe_mono = self_dict
+ , abe_prags = dfun_spec_prags }
-- NB: see Note [SPECIALISE instance pragmas]
main_bind = AbsBinds { abs_tvs = inst_tyvars
, abs_ev_vars = dfun_ev_vars
@@ -884,6 +887,29 @@ tcInstDecl2 (InstInfo { iSpec = ispec, iBinds = ibinds })
dfun_id = instanceDFunId ispec
loc = getSrcSpan dfun_id
+addDFunPrags :: DFunId -> DataCon -> Bool
+ -> [TyVar] -> [Id] -> [Type]
+ -> [Id] -> DFunId
+-- DFuns need a special Unfolding and InlinePrag
+-- See Note [ClassOp/DFun selection]
+-- and Note [Single-method classes]
+-- It's easiest to create those unfoldings right here, where
+-- have all the pieces in hand, even though we are messing with
+-- Core at this point, which the typechecker doesn't usually do
+addDFunPrags dfun_id dict_con is_newtype dfun_tvs dfun_evs inst_tys sc_meth_ids
+ | is_newtype
+ = dfun_id `setIdUnfolding` mkInlineUnfolding (Just 0) con_app
+ `setInlinePragma` alwaysInlinePragma { inl_sat = Just 0 }
+ | otherwise
+ = dfun_id `setIdUnfolding` mkDFunUnfolding dfun_bndrs dict_con dict_args
+ `setInlinePragma` dfunInlinePragma
+ where
+ dfun_bndrs = dfun_tvs ++ dfun_evs
+ dict_args = map Type inst_tys ++
+ [mkVarApps (Var id) dfun_bndrs | id <- sc_meth_ids]
+ con_app = mkLams dfun_bndrs $
+ mkApps (Var (dataConWrapId dict_con)) dict_args
+
wrapId :: HsWrapper -> id -> HsExpr id
wrapId wrapper id = mkHsWrap wrapper (HsVar (noLoc id))
diff --git a/testsuite/tests/roles/should_compile/T8958.stderr b/testsuite/tests/roles/should_compile/T8958.stderr
index 9b4e2d911c..e7a86e5004 100644
--- a/testsuite/tests/roles/should_compile/T8958.stderr
+++ b/testsuite/tests/roles/should_compile/T8958.stderr
@@ -62,16 +62,21 @@ T8958.$trModule
AbsBinds [a] []
{Exports: [T8958.$fRepresentationala <= $dRepresentational
wrap: <>]
- Exported types: T8958.$fRepresentationala
+ Exported types: T8958.$fRepresentationala [InlPrag=[ALWAYS] CONLIKE]
:: forall a. Representational a
- [LclIdX[DFunId], Str=DmdType]
+ [LclIdX[DFunId],
+ Str=DmdType,
+ Unf=DFun: \ (@ a[ssk]) -> T8958.C:Representational TYPE: a[ssk]]
Binds: $dRepresentational = T8958.C:Representational @ a
Evidence: [EvBinds{}]}
AbsBinds [a] []
{Exports: [T8958.$fNominala <= $dNominal
wrap: <>]
- Exported types: T8958.$fNominala :: forall a. Nominal a
- [LclIdX[DFunId], Str=DmdType]
+ Exported types: T8958.$fNominala [InlPrag=[ALWAYS] CONLIKE]
+ :: forall a. Nominal a
+ [LclIdX[DFunId],
+ Str=DmdType,
+ Unf=DFun: \ (@ a[ssk]) -> T8958.C:Nominal TYPE: a[ssk]]
Binds: $dNominal = T8958.C:Nominal @ a
Evidence: [EvBinds{}]}
diff --git a/testsuite/tests/simplCore/should_compile/T11742.hs b/testsuite/tests/simplCore/should_compile/T11742.hs
new file mode 100644
index 0000000000..e0a7333c57
--- /dev/null
+++ b/testsuite/tests/simplCore/should_compile/T11742.hs
@@ -0,0 +1,8 @@
+{-# LANGUAGE Strict #-}
+
+module Foo where
+
+data Foo = Foo
+
+instance Eq Foo where
+ (==) Foo Foo = True
diff --git a/testsuite/tests/simplCore/should_compile/all.T b/testsuite/tests/simplCore/should_compile/all.T
index 52cdea756d..9d88237b66 100644
--- a/testsuite/tests/simplCore/should_compile/all.T
+++ b/testsuite/tests/simplCore/should_compile/all.T
@@ -230,3 +230,4 @@ test('T11155',
['$MAKE -s --no-print-directory T11155'])
test('T11232', normal, compile, ['-O2'])
test('T11562', normal, compile, ['-O2'])
+test('T11742', normal, compile, ['-O2'])