diff options
author | Richard Eisenberg <rae@cs.brynmawr.edu> | 2016-12-14 21:37:43 -0500 |
---|---|---|
committer | Richard Eisenberg <rae@cs.brynmawr.edu> | 2017-01-19 10:31:52 -0500 |
commit | e7985ed23ddc68b6a2e4af753578dc1d9e8ab4c9 (patch) | |
tree | ba8c4016e218710f8165db92d4b4c10e5559245a /compiler/stgSyn | |
parent | 38374caa9d6e1373d1b9d335d0f99f3664931fd9 (diff) | |
download | haskell-e7985ed23ddc68b6a2e4af753578dc1d9e8ab4c9.tar.gz |
Update levity polymorphism
This commit implements the proposal in
https://github.com/ghc-proposals/ghc-proposals/pull/29 and
https://github.com/ghc-proposals/ghc-proposals/pull/35.
Here are some of the pieces of that proposal:
* Some of RuntimeRep's constructors have been shortened.
* TupleRep and SumRep are now parameterized over a list of RuntimeReps.
* This
means that two types with the same kind surely have the same
representation.
Previously, all unboxed tuples had the same kind, and thus the fact
above was
false.
* RepType.typePrimRep and friends now return a *list* of PrimReps. These
functions can now work successfully on unboxed tuples. This change is
necessary because we allow abstraction over unboxed tuple types and so
cannot
always handle unboxed tuples specially as we did before.
* We sometimes have to create an Id from a PrimRep. I thus split PtrRep
* into
LiftedRep and UnliftedRep, so that the created Ids have the right
strictness.
* The RepType.RepType type was removed, as it didn't seem to help with
* much.
* The RepType.repType function is also removed, in favor of typePrimRep.
* I have waffled a good deal on whether or not to keep VoidRep in
TyCon.PrimRep. In the end, I decided to keep it there. PrimRep is *not*
represented in RuntimeRep, and typePrimRep will never return a list
including
VoidRep. But it's handy to have in, e.g., ByteCodeGen and friends. I can
imagine another design choice where we have a PrimRepV type that is
PrimRep
with an extra constructor. That seemed to be a heavier design, though,
and I'm
not sure what the benefit would be.
* The last, unused vestiges of # (unliftedTypeKind) have been removed.
* There were several pretty-printing bugs that this change exposed;
* these are fixed.
* We previously checked for levity polymorphism in the types of binders.
* But we
also must exclude levity polymorphism in function arguments. This is
hard to check
for, requiring a good deal of care in the desugarer. See Note [Levity
polymorphism
checking] in DsMonad.
* In order to efficiently check for levity polymorphism in functions, it
* was necessary
to add a new bit of IdInfo. See Note [Levity info] in IdInfo.
* It is now safe for unlifted types to be unsaturated in Core. Core Lint
* is updated
accordingly.
* We can only know strictness after zonking, so several checks around
* strictness
in the type-checker (checkStrictBinds, the check for unlifted variables
under a ~
pattern) have been moved to the desugarer.
* Along the way, I improved the treatment of unlifted vs. banged
* bindings. See
Note [Strict binds checks] in DsBinds and #13075.
* Now that we print type-checked source, we must be careful to print
* ConLikes correctly.
This is facilitated by a new HsConLikeOut constructor to HsExpr.
Particularly troublesome
are unlifted pattern synonyms that get an extra void# argument.
* Includes a submodule update for haddock, getting rid of #.
* New testcases:
typecheck/should_fail/StrictBinds
typecheck/should_fail/T12973
typecheck/should_run/StrictPats
typecheck/should_run/T12809
typecheck/should_fail/T13105
patsyn/should_fail/UnliftedPSBind
typecheck/should_fail/LevPolyBounded
typecheck/should_compile/T12987
typecheck/should_compile/T11736
* Fixed tickets:
#12809
#12973
#11736
#13075
#12987
* This also adds a test case for #13105. This test case is
* "compile_fail" and
succeeds, because I want the testsuite to monitor the error message.
When #13105 is fixed, the test case will compile cleanly.
Diffstat (limited to 'compiler/stgSyn')
-rw-r--r-- | compiler/stgSyn/CoreToStg.hs | 33 | ||||
-rw-r--r-- | compiler/stgSyn/StgLint.hs | 34 | ||||
-rw-r--r-- | compiler/stgSyn/StgSyn.hs | 18 |
3 files changed, 46 insertions, 39 deletions
diff --git a/compiler/stgSyn/CoreToStg.hs b/compiler/stgSyn/CoreToStg.hs index 5531d31d30..dcb923afea 100644 --- a/compiler/stgSyn/CoreToStg.hs +++ b/compiler/stgSyn/CoreToStg.hs @@ -472,16 +472,25 @@ coreToStgExpr (Let bind body) = do coreToStgExpr e = pprPanic "coreToStgExpr" (ppr e) mkStgAltType :: Id -> [CoreAlt] -> AltType -mkStgAltType bndr alts = case repType (idType bndr) of - UnaryRep rep_ty -> case tyConAppTyCon_maybe rep_ty of - Just tc | isUnliftedTyCon tc -> PrimAlt tc - | isAbstractTyCon tc -> look_for_better_tycon - | isAlgTyCon tc -> AlgAlt tc - | otherwise -> ASSERT2( _is_poly_alt_tycon tc, ppr tc ) - PolyAlt - Nothing -> PolyAlt - MultiRep slots -> MultiValAlt (length slots) +mkStgAltType bndr alts + | isUnboxedTupleType bndr_ty || isUnboxedSumType bndr_ty + = MultiValAlt (length prim_reps) -- always use MultiValAlt for unboxed tuples + + | otherwise + = case prim_reps of + [LiftedRep] -> case tyConAppTyCon_maybe (unwrapType bndr_ty) of + Just tc + | isAbstractTyCon tc -> look_for_better_tycon + | isAlgTyCon tc -> AlgAlt tc + | otherwise -> ASSERT2( _is_poly_alt_tycon tc, ppr tc ) + PolyAlt + Nothing -> PolyAlt + [unlifted] -> PrimAlt unlifted + not_unary -> MultiValAlt (length not_unary) where + bndr_ty = idType bndr + prim_reps = typePrimRep bndr_ty + _is_poly_alt_tycon tc = isFunTyCon tc || isPrimTyCon tc -- "Any" is lifted but primitive @@ -650,8 +659,7 @@ coreToStgArgs (arg : args) = do -- Non-type argument arg_ty = exprType arg stg_arg_ty = stgArgType stg_arg bad_args = (isUnliftedType arg_ty && not (isUnliftedType stg_arg_ty)) - || (map typePrimRep (repTypeArgs arg_ty) - /= map typePrimRep (repTypeArgs stg_arg_ty)) + || (typePrimRep arg_ty /= typePrimRep stg_arg_ty) -- In GHCi we coerce an argument of type BCO# (unlifted) to HValue (lifted), -- and pass it to a function expecting an HValue (arg_ty). This is ok because -- we can treat an unlifted value as lifted. But the other way round @@ -802,7 +810,8 @@ mkStgRhs' con_updateable rhs_fvs bndr binder_info rhs | StgConApp con args _ <- unticked_rhs , not (con_updateable con args) = -- CorePrep does this right, but just to make sure - ASSERT(not (isUnboxedTupleCon con || isUnboxedSumCon con)) + ASSERT2( not (isUnboxedTupleCon con || isUnboxedSumCon con) + , ppr bndr $$ ppr con $$ ppr args) StgRhsCon noCCS con args | otherwise = StgRhsClosure noCCS binder_info diff --git a/compiler/stgSyn/StgLint.hs b/compiler/stgSyn/StgLint.hs index 0dba8d8359..e31e7ae015 100644 --- a/compiler/stgSyn/StgLint.hs +++ b/compiler/stgSyn/StgLint.hs @@ -196,21 +196,19 @@ lintStgExpr (StgCase scrut bndr alts_type alts) = runMaybeT $ do in_scope <- MaybeT $ liftM Just $ case alts_type of - AlgAlt tc -> check_bndr tc >> return True - PrimAlt tc -> check_bndr tc >> return True + AlgAlt tc -> check_bndr (tyConPrimRep tc) >> return True + PrimAlt rep -> check_bndr [rep] >> return True MultiValAlt _ -> return False -- Binder is always dead in this case PolyAlt -> return True MaybeT $ addInScopeVars [bndr | in_scope] $ lintStgAlts alts scrut_ty where - scrut_ty = idType bndr - UnaryRep scrut_rep = repType scrut_ty -- Not used if scrutinee is unboxed tuple or sum - check_bndr tc = case tyConAppTyCon_maybe scrut_rep of - Just bndr_tc -> checkL (tc == bndr_tc) bad_bndr - Nothing -> addErrL bad_bndr + scrut_ty = idType bndr + scrut_reps = typePrimRep scrut_ty + check_bndr reps = checkL (scrut_reps == reps) bad_bndr where - bad_bndr = mkDefltMsg bndr tc + bad_bndr = mkDefltMsg bndr reps lintStgAlts :: [StgAlt] -> Type -- Type of scrutinee @@ -418,20 +416,18 @@ stgEqType :: Type -> Type -> Bool -- Fundamentally this is a losing battle because of unsafeCoerce stgEqType orig_ty1 orig_ty2 - = gos (repType orig_ty1) (repType orig_ty2) + = gos (typePrimRep orig_ty1) (typePrimRep orig_ty2) where - gos :: RepType -> RepType -> Bool - gos (MultiRep slots1) (MultiRep slots2) - = slots1 == slots2 - gos (UnaryRep ty1) (UnaryRep ty2) = go ty1 ty2 - gos _ _ = False + gos :: [PrimRep] -> [PrimRep] -> Bool + gos [_] [_] = go orig_ty1 orig_ty2 + gos reps1 reps2 = reps1 == reps2 go :: UnaryType -> UnaryType -> Bool go ty1 ty2 | Just (tc1, tc_args1) <- splitTyConApp_maybe ty1 , Just (tc2, tc_args2) <- splitTyConApp_maybe ty2 , let res = if tc1 == tc2 - then equalLength tc_args1 tc_args2 && and (zipWith (gos `on` repType) tc_args1 tc_args2) + then equalLength tc_args1 tc_args2 && and (zipWith (gos `on` typePrimRep) tc_args1 tc_args2) else -- TyCons don't match; but don't bleat if either is a -- family TyCon because a coercion might have made it -- equal to something else @@ -462,10 +458,10 @@ _mkCaseAltMsg _alts = ($$) (text "In some case alternatives, type of alternatives not all same:") (Outputable.empty) -- LATER: ppr alts -mkDefltMsg :: Id -> TyCon -> MsgDoc -mkDefltMsg bndr tc - = ($$) (text "Binder of a case expression doesn't match type of scrutinee:") - (ppr bndr $$ ppr (idType bndr) $$ ppr tc) +mkDefltMsg :: Id -> [PrimRep] -> MsgDoc +mkDefltMsg bndr reps + = ($$) (text "Binder of a case expression doesn't match representation of scrutinee:") + (ppr bndr $$ ppr (idType bndr) $$ ppr reps) mkFunAppMsg :: Type -> [Type] -> StgExpr -> MsgDoc mkFunAppMsg fun_ty arg_tys expr diff --git a/compiler/stgSyn/StgSyn.hs b/compiler/stgSyn/StgSyn.hs index 64c8448421..48e836cc56 100644 --- a/compiler/stgSyn/StgSyn.hs +++ b/compiler/stgSyn/StgSyn.hs @@ -62,7 +62,7 @@ import PprCore ( {- instances -} ) import PrimOp ( PrimOp, PrimCall ) import TyCon ( PrimRep(..), TyCon ) import Type ( Type ) -import RepType ( typePrimRep ) +import RepType ( typePrimRep1 ) import Unique ( Unique ) import Util @@ -104,10 +104,10 @@ isDllConApp dflags this_mod con args = isDllName dflags this_mod (dataConName con) || any is_dll_arg args | otherwise = False where - -- NB: typePrimRep is legit because any free variables won't have + -- NB: typePrimRep1 is legit because any free variables won't have -- unlifted type (there are no unlifted things at top level) is_dll_arg :: StgArg -> Bool - is_dll_arg (StgVarArg v) = isAddrRep (typePrimRep (idType v)) + is_dll_arg (StgVarArg v) = isAddrRep (typePrimRep1 (idType v)) && isDllName dflags this_mod (idName v) is_dll_arg _ = False @@ -124,9 +124,10 @@ isDllConApp dflags this_mod con args -- $WT1 = T1 Int (Coercion (Refl Int)) -- The coercion argument here gets VoidRep isAddrRep :: PrimRep -> Bool -isAddrRep AddrRep = True -isAddrRep PtrRep = True -isAddrRep _ = False +isAddrRep AddrRep = True +isAddrRep LiftedRep = True +isAddrRep UnliftedRep = True +isAddrRep _ = False -- | Type of an @StgArg@ -- @@ -533,10 +534,11 @@ type GenStgAlt bndr occ GenStgExpr bndr occ) -- ...right-hand side. data AltType - = PolyAlt -- Polymorphic (a type variable) + = PolyAlt -- Polymorphic (a lifted type variable) | MultiValAlt Int -- Multi value of this arity (unboxed tuple or sum) + -- the arity could indeed be 1 for unary unboxed tuple | AlgAlt TyCon -- Algebraic data type; the AltCons will be DataAlts - | PrimAlt TyCon -- Primitive data type; the AltCons will be LitAlts + | PrimAlt PrimRep -- Primitive data type; the AltCons (if any) will be LitAlts {- ************************************************************************ |