summaryrefslogtreecommitdiff
path: root/compiler/iface/TcIface.hs
diff options
context:
space:
mode:
authorEdward Z. Yang <ezyang@cs.stanford.edu>2017-02-10 00:38:34 -0800
committerEdward Z. Yang <ezyang@cs.stanford.edu>2017-02-26 16:03:13 -0800
commit923d7ca2d90c1cb9816d14768abdd2e46adcd5dd (patch)
tree943e3c0dfff8e9674bbd6252b98101e713d47e3e /compiler/iface/TcIface.hs
parent9603de6ac7a75ea7c620ce05e3c5f500bcaf5dd6 (diff)
downloadhaskell-923d7ca2d90c1cb9816d14768abdd2e46adcd5dd.tar.gz
Subtyping for roles in signatures.
Summary: This commit implements the plan in #13140: * Today, roles in signature files default to representational. Let's change the default to nominal, as this is the most flexible implementation side. If a client of the signature needs to coerce with a type, the signature can be adjusted to have more stringent requirements. * If a parameter is declared as nominal in a signature, it can be implemented by a data type which is actually representational. * When merging abstract data declarations, we take the smallest role for every parameter. The roles are considered fix once we specify the structure of an ADT. * Critically, abstract types are NOT injective, so we aren't allowed to make inferences like "if T a ~R T b, then a ~N b" based on the nominal role of a parameter in an abstract type (this would be unsound if the parameter ended up being phantom.) This restriction is similar to the restriction we have on newtypes. Signed-off-by: Edward Z. Yang <ezyang@cs.stanford.edu> Test Plan: validate Reviewers: simonpj, bgamari, austin, goldfire Subscribers: goldfire, thomie Differential Revision: https://phabricator.haskell.org/D3123
Diffstat (limited to 'compiler/iface/TcIface.hs')
-rw-r--r--compiler/iface/TcIface.hs26
1 files changed, 21 insertions, 5 deletions
diff --git a/compiler/iface/TcIface.hs b/compiler/iface/TcIface.hs
index ffe29c6ce7..d8461f364f 100644
--- a/compiler/iface/TcIface.hs
+++ b/compiler/iface/TcIface.hs
@@ -212,25 +212,41 @@ isAbstractIfaceDecl IfaceClass{ ifCtxt = [], ifSigs = [], ifATs = [] } = True
isAbstractIfaceDecl IfaceFamily{ ifFamFlav = IfaceAbstractClosedSynFamilyTyCon } = True
isAbstractIfaceDecl _ = False
+ifMaybeRoles :: IfaceDecl -> Maybe [Role]
+ifMaybeRoles IfaceData { ifRoles = rs } = Just rs
+ifMaybeRoles IfaceSynonym { ifRoles = rs } = Just rs
+ifMaybeRoles IfaceClass { ifRoles = rs } = Just rs
+ifMaybeRoles _ = Nothing
+
-- | Merge two 'IfaceDecl's together, preferring a non-abstract one. If
-- both are non-abstract we pick one arbitrarily (and check for consistency
-- later.)
mergeIfaceDecl :: IfaceDecl -> IfaceDecl -> IfaceDecl
mergeIfaceDecl d1 d2
- | isAbstractIfaceDecl d1 = d2
- | isAbstractIfaceDecl d2 = d1
+ -- TODO: need to merge roles
+ | isAbstractIfaceDecl d1 = d2 `withRolesFrom` d1
+ | isAbstractIfaceDecl d2 = d1 `withRolesFrom` d2
| IfaceClass{ ifSigs = ops1, ifMinDef = bf1 } <- d1
, IfaceClass{ ifSigs = ops2, ifMinDef = bf2 } <- d2
= let ops = nameEnvElts $
plusNameEnv_C mergeIfaceClassOp
(mkNameEnv [ (n, op) | op@(IfaceClassOp n _ _) <- ops1 ])
(mkNameEnv [ (n, op) | op@(IfaceClassOp n _ _) <- ops2 ])
- in d1 { ifSigs = ops
+ in d1 { ifSigs = ops
, ifMinDef = BF.mkOr [noLoc bf1, noLoc bf2]
- }
+ } `withRolesFrom` d2
-- It doesn't matter; we'll check for consistency later when
-- we merge, see 'mergeSignatures'
- | otherwise = d1
+ | otherwise = d1 `withRolesFrom` d2
+
+withRolesFrom :: IfaceDecl -> IfaceDecl -> IfaceDecl
+d1 `withRolesFrom` d2
+ | Just roles1 <- ifMaybeRoles d1
+ , Just roles2 <- ifMaybeRoles d2
+ = d1 { ifRoles = mergeRoles roles1 roles2 }
+ | otherwise = d1
+ where
+ mergeRoles roles1 roles2 = zipWith max roles1 roles2
mergeIfaceClassOp :: IfaceClassOp -> IfaceClassOp -> IfaceClassOp
mergeIfaceClassOp op1@(IfaceClassOp _ _ (Just _)) _ = op1