summaryrefslogtreecommitdiff
path: root/compiler/hsSyn
diff options
context:
space:
mode:
authorSimon Peyton Jones <simonpj@microsoft.com>2016-04-20 12:56:40 +0100
committerSimon Peyton Jones <simonpj@microsoft.com>2016-04-20 14:28:34 +0100
commit353d8ae6fafe117a1cac4adf6f029a5baccc2780 (patch)
tree9a55b083e597b0d2d614639a54c85b0119384bd2 /compiler/hsSyn
parent7319b80a2cdffdfac8586946d0c7b0fdc8d77dae (diff)
downloadhaskell-353d8ae6fafe117a1cac4adf6f029a5baccc2780.tar.gz
SCC analysis for instances as well as types/classes
This big patch is in pursuit of Trac #11348. It is largely the work of Alex Veith (thank you!), with some follow-up simplification and refactoring from Simon PJ. The main payload is described in RnSource Note [Dependency analysis of type, class, and instance decls] which is pretty detailed. * There is a new data type HsDecls.TyClGroup, for a strongly connected component of type/class/instance/role decls. The hs_instds field of HsGroup disappears, in consequence This forces some knock-on changes, including a minor haddock submodule update Smaller, weakly-related things * I found that both the renamer and typechecker were building an identical env for RoleAnnots, so I put common code for RoleAnnotEnv in RnEnv. * I found that tcInstDecls1 had very clumsy error handling, so I put it together into TcInstDcls.doClsInstErrorChecks
Diffstat (limited to 'compiler/hsSyn')
-rw-r--r--compiler/hsSyn/HsDecls.hs302
-rw-r--r--compiler/hsSyn/HsUtils.hs21
2 files changed, 186 insertions, 137 deletions
diff --git a/compiler/hsSyn/HsDecls.hs b/compiler/hsSyn/HsDecls.hs
index 82a78fe5cd..dfcb6c16b7 100644
--- a/compiler/hsSyn/HsDecls.hs
+++ b/compiler/hsSyn/HsDecls.hs
@@ -22,7 +22,8 @@ module HsDecls (
-- ** Class or type declarations
TyClDecl(..), LTyClDecl,
- TyClGroup(..), tyClGroupConcat, mkTyClGroup,
+ TyClGroup(..), mkTyClGroup, emptyTyClGroup,
+ tyClGroupTyClDecls, tyClGroupInstDecls, tyClGroupRoleDecls,
isClassDecl, isDataDecl, isSynDecl, tcdName,
isFamilyDecl, isTypeFamilyDecl, isDataFamilyDecl,
isOpenTypeFamilyInfo, isClosedTypeFamilyInfo,
@@ -79,7 +80,7 @@ module HsDecls (
resultVariableName,
-- * Grouping
- HsGroup(..), emptyRdrGroup, emptyRnGroup, appendGroups
+ HsGroup(..), emptyRdrGroup, emptyRnGroup, appendGroups, hsGroupInstDecls
) where
@@ -166,14 +167,11 @@ data HsGroup id
hs_splcds :: [LSpliceDecl id],
hs_tyclds :: [TyClGroup id],
- -- A list of mutually-recursive groups
- -- No family-instances here; they are in hs_instds
+ -- A list of mutually-recursive groups;
+ -- This includes `InstDecl`s as well;
-- Parser generates a singleton list;
-- renamer does dependency analysis
- hs_instds :: [LInstDecl id],
- -- Both class and family instance declarations in here
-
hs_derivds :: [LDerivDecl id],
hs_fixds :: [LFixitySig id],
@@ -195,7 +193,10 @@ emptyGroup, emptyRdrGroup, emptyRnGroup :: HsGroup a
emptyRdrGroup = emptyGroup { hs_valds = emptyValBindsIn }
emptyRnGroup = emptyGroup { hs_valds = emptyValBindsOut }
-emptyGroup = HsGroup { hs_tyclds = [], hs_instds = [],
+hsGroupInstDecls :: HsGroup id -> [LInstDecl id]
+hsGroupInstDecls = (=<<) group_instds . hs_tyclds
+
+emptyGroup = HsGroup { hs_tyclds = [],
hs_derivds = [],
hs_fixds = [], hs_defds = [], hs_annds = [],
hs_fords = [], hs_warnds = [], hs_ruleds = [], hs_vects = [],
@@ -209,7 +210,6 @@ appendGroups
hs_valds = val_groups1,
hs_splcds = spliceds1,
hs_tyclds = tyclds1,
- hs_instds = instds1,
hs_derivds = derivds1,
hs_fixds = fixds1,
hs_defds = defds1,
@@ -223,7 +223,6 @@ appendGroups
hs_valds = val_groups2,
hs_splcds = spliceds2,
hs_tyclds = tyclds2,
- hs_instds = instds2,
hs_derivds = derivds2,
hs_fixds = fixds2,
hs_defds = defds2,
@@ -238,7 +237,6 @@ appendGroups
hs_valds = val_groups1 `plusHsValBinds` val_groups2,
hs_splcds = spliceds1 ++ spliceds2,
hs_tyclds = tyclds1 ++ tyclds2,
- hs_instds = instds1 ++ instds2,
hs_derivds = derivds1 ++ derivds2,
hs_fixds = fixds1 ++ fixds2,
hs_annds = annds1 ++ annds2,
@@ -268,7 +266,6 @@ instance OutputableBndr name => Outputable (HsDecl name) where
instance OutputableBndr name => Outputable (HsGroup name) where
ppr (HsGroup { hs_valds = val_decls,
hs_tyclds = tycl_decls,
- hs_instds = inst_decls,
hs_derivds = deriv_decls,
hs_fixds = fix_decls,
hs_warnds = deprec_decls,
@@ -285,8 +282,8 @@ instance OutputableBndr name => Outputable (HsGroup name) where
if isEmptyValBinds val_decls
then Nothing
else Just (ppr val_decls),
- ppr_ds (tyClGroupConcat tycl_decls),
- ppr_ds inst_decls,
+ ppr_ds (tyClGroupTyClDecls tycl_decls),
+ ppr_ds (tyClGroupInstDecls tycl_decls),
ppr_ds deriv_decls,
ppr_ds foreign_decls]
where
@@ -318,14 +315,12 @@ instance OutputableBndr name => Outputable (SpliceDecl name) where
{-
************************************************************************
* *
-\subsection[SynDecl]{@data@, @newtype@ or @type@ (synonym) type declaration}
+ Type and class declarations
* *
************************************************************************
- --------------------------------
- THE NAMING STORY
- --------------------------------
-
+Note [The Naming story]
+~~~~~~~~~~~~~~~~~~~~~~~
Here is the story about the implicit names that go with type, class,
and instance decls. It's a bit tricky, so pay attention!
@@ -530,22 +525,6 @@ data TyClDecl name
deriving (Typeable)
deriving instance (DataId id) => Data (TyClDecl id)
- -- This is used in TcTyClsDecls to represent
- -- strongly connected components of decls
- -- No familiy instances in here
- -- The role annotations must be grouped with their decls for the
- -- type-checker to infer roles correctly
-data TyClGroup name
- = TyClGroup { group_tyclds :: [LTyClDecl name]
- , group_roles :: [LRoleAnnotDecl name] }
- deriving (Typeable)
-deriving instance (DataId id) => Data (TyClGroup id)
-
-tyClGroupConcat :: [TyClGroup name] -> [LTyClDecl name]
-tyClGroupConcat = concatMap group_tyclds
-
-mkTyClGroup :: [LTyClDecl name] -> TyClGroup name
-mkTyClGroup decls = TyClGroup { group_tyclds = decls, group_roles = [] }
-- Simple classifiers for TyClDecl
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -677,9 +656,14 @@ instance OutputableBndr name
<+> pprFundeps (map unLoc fds)
instance OutputableBndr name => Outputable (TyClGroup name) where
- ppr (TyClGroup { group_tyclds = tyclds, group_roles = roles })
+ ppr (TyClGroup { group_tyclds = tyclds
+ , group_roles = roles
+ , group_instds = instds
+ }
+ )
= ppr tyclds $$
- ppr roles
+ ppr roles $$
+ ppr instds
pp_vanilla_decl_head :: OutputableBndr name
=> Located name
@@ -698,73 +682,165 @@ pprTyClDeclFlavour (DataDecl { tcdDataDefn = HsDataDefn { dd_ND = nd } })
= ppr nd
+{- Note [Complete user-supplied kind signatures]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+We kind-check declarations differently if they have a complete, user-supplied
+kind signature (CUSK). This is because we can safely generalise a CUSKed
+declaration before checking all of the others, supporting polymorphic recursion.
+See ghc.haskell.org/trac/ghc/wiki/GhcKinds/KindInference#Proposednewstrategy
+and #9200 for lots of discussion of how we got here.
+
+A declaration has a CUSK if we can know its complete kind without doing any
+inference, at all. Here are the rules:
+
+ - A class or datatype is said to have a CUSK if and only if all of its type
+variables are annotated. Its result kind is, by construction, Constraint or *
+respectively.
+
+ - A type synonym has a CUSK if and only if all of its type variables and its
+RHS are annotated with kinds.
+
+ - A closed type family is said to have a CUSK if and only if all of its type
+variables and its return type are annotated.
+
+ - An open type family always has a CUSK -- unannotated type variables (and
+return type) default to *.
+
+ - Additionally, if -XTypeInType is on, then a data definition with a top-level
+ :: must explicitly bind all kind variables to the right of the ::.
+ See test dependent/should_compile/KindLevels, which requires this case.
+ (Naturally, any kind variable mentioned before the :: should not be bound
+ after it.)
+-}
+
+
+{- *********************************************************************
+* *
+ TyClGroup
+ Strongly connected components of
+ type, class, instance, and role declarations
+* *
+********************************************************************* -}
+
+{- Note [TyClGroups and dependency analysis]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+A TyClGroup represents a strongly connected components of type/class/instance
+decls, together with the role annotations for the type/class declarations.
+
+The hs_tyclds :: [TyClGroup] field of a HsGroup is a dependency-order
+sequence of strongly-connected components.
+
+Invariants
+ * The type and class declarations, group_tyclds, may depend on each
+ other, or earlier TyClGroups, but not on later ones
+
+ * The role annotations, group_roles, are role-annotations for some or
+ all of the types and classes in group_tyclds (only).
+
+ * The instance declarations, group_instds, may (and usually will)
+ depend on group_tyclds, or on earlier TyClGroups, but not on later
+ ones.
+
+See Note [Dependency analsis of type, class, and instance decls]
+in RnSource for more info.
+-}
+
+data TyClGroup name -- See Note [TyClGroups and dependency analysis]
+ = TyClGroup { group_tyclds :: [LTyClDecl name]
+ , group_roles :: [LRoleAnnotDecl name]
+ , group_instds :: [LInstDecl name] }
+ deriving (Typeable)
+deriving instance (DataId id) => Data (TyClGroup id)
+
+emptyTyClGroup :: TyClGroup name
+emptyTyClGroup = TyClGroup [] [] []
+
+tyClGroupTyClDecls :: [TyClGroup name] -> [LTyClDecl name]
+tyClGroupTyClDecls = concatMap group_tyclds
+
+tyClGroupInstDecls :: [TyClGroup name] -> [LInstDecl name]
+tyClGroupInstDecls = concatMap group_instds
+
+tyClGroupRoleDecls :: [TyClGroup name] -> [LRoleAnnotDecl name]
+tyClGroupRoleDecls = concatMap group_roles
+
+mkTyClGroup :: [LTyClDecl name] -> [LInstDecl name] -> TyClGroup name
+mkTyClGroup decls instds = TyClGroup
+ { group_tyclds = decls
+ , group_roles = []
+ , group_instds = instds
+ }
+
+
+
{- *********************************************************************
* *
Data and type family declarations
* *
********************************************************************* -}
--- Note [FamilyResultSig]
--- ~~~~~~~~~~~~~~~~~~~~~~
---
--- This data type represents the return signature of a type family. Possible
--- values are:
---
--- * NoSig - the user supplied no return signature:
--- type family Id a where ...
---
--- * KindSig - the user supplied the return kind:
--- type family Id a :: * where ...
---
--- * TyVarSig - user named the result with a type variable and possibly
--- provided a kind signature for that variable:
--- type family Id a = r where ...
--- type family Id a = (r :: *) where ...
---
--- Naming result of a type family is required if we want to provide
--- injectivity annotation for a type family:
--- type family Id a = r | r -> a where ...
---
--- See also: Note [Injectivity annotation]
+{- Note [FamilyResultSig]
+~~~~~~~~~~~~~~~~~~~~~~~~~
--- Note [Injectivity annotation]
--- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
---
--- A user can declare a type family to be injective:
---
--- type family Id a = r | r -> a where ...
---
--- * The part after the "|" is called "injectivity annotation".
--- * "r -> a" part is called "injectivity condition"; at the moment terms
--- "injectivity annotation" and "injectivity condition" are synonymous
--- because we only allow a single injectivity condition.
--- * "r" is the "LHS of injectivity condition". LHS can only contain the
--- variable naming the result of a type family.
-
--- * "a" is the "RHS of injectivity condition". RHS contains space-separated
--- type and kind variables representing the arguments of a type
--- family. Variables can be omitted if a type family is not injective in
--- these arguments. Example:
--- type family Foo a b c = d | d -> a c where ...
---
--- Note that:
--- a) naming of type family result is required to provide injectivity
--- annotation
--- b) for associated types if the result was named then injectivity annotation
--- is mandatory. Otherwise result type variable is indistinguishable from
--- associated type default.
---
--- It is possible that in the future this syntax will be extended to support
--- more complicated injectivity annotations. For example we could declare that
--- if we know the result of Plus and one of its arguments we can determine the
--- other argument:
---
--- type family Plus a b = (r :: Nat) | r a -> b, r b -> a where ...
---
--- Here injectivity annotation would consist of two comma-separated injectivity
--- conditions.
---
--- See also Note [Injective type families] in TyCon
+This data type represents the return signature of a type family. Possible
+values are:
+
+ * NoSig - the user supplied no return signature:
+ type family Id a where ...
+
+ * KindSig - the user supplied the return kind:
+ type family Id a :: * where ...
+
+ * TyVarSig - user named the result with a type variable and possibly
+ provided a kind signature for that variable:
+ type family Id a = r where ...
+ type family Id a = (r :: *) where ...
+
+ Naming result of a type family is required if we want to provide
+ injectivity annotation for a type family:
+ type family Id a = r | r -> a where ...
+
+See also: Note [Injectivity annotation]
+
+Note [Injectivity annotation]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+A user can declare a type family to be injective:
+
+ type family Id a = r | r -> a where ...
+
+ * The part after the "|" is called "injectivity annotation".
+ * "r -> a" part is called "injectivity condition"; at the moment terms
+ "injectivity annotation" and "injectivity condition" are synonymous
+ because we only allow a single injectivity condition.
+ * "r" is the "LHS of injectivity condition". LHS can only contain the
+ variable naming the result of a type family.
+
+ * "a" is the "RHS of injectivity condition". RHS contains space-separated
+ type and kind variables representing the arguments of a type
+ family. Variables can be omitted if a type family is not injective in
+ these arguments. Example:
+ type family Foo a b c = d | d -> a c where ...
+
+Note that:
+ (a) naming of type family result is required to provide injectivity
+ annotation
+ (b) for associated types if the result was named then injectivity annotation
+ is mandatory. Otherwise result type variable is indistinguishable from
+ associated type default.
+
+It is possible that in the future this syntax will be extended to support
+more complicated injectivity annotations. For example we could declare that
+if we know the result of Plus and one of its arguments we can determine the
+other argument:
+
+ type family Plus a b = (r :: Nat) | r a -> b, r b -> a where ...
+
+Here injectivity annotation would consist of two comma-separated injectivity
+conditions.
+
+See also Note [Injective type families] in TyCon
+-}
type LFamilyResultSig name = Located (FamilyResultSig name)
data FamilyResultSig name = -- see Note [FamilyResultSig]
@@ -859,38 +935,6 @@ resultVariableName :: FamilyResultSig a -> Maybe a
resultVariableName (TyVarSig sig) = Just $ hsLTyVarName sig
resultVariableName _ = Nothing
-{-
-Note [Complete user-supplied kind signatures]
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-We kind-check declarations differently if they have a complete, user-supplied
-kind signature (CUSK). This is because we can safely generalise a CUSKed
-declaration before checking all of the others, supporting polymorphic recursion.
-See ghc.haskell.org/trac/ghc/wiki/GhcKinds/KindInference#Proposednewstrategy
-and #9200 for lots of discussion of how we got here.
-
-A declaration has a CUSK if we can know its complete kind without doing any
-inference, at all. Here are the rules:
-
- - A class or datatype is said to have a CUSK if and only if all of its type
-variables are annotated. Its result kind is, by construction, Constraint or *
-respectively.
-
- - A type synonym has a CUSK if and only if all of its type variables and its
-RHS are annotated with kinds.
-
- - A closed type family is said to have a CUSK if and only if all of its type
-variables and its return type are annotated.
-
- - An open type family always has a CUSK -- unannotated type variables (and
-return type) default to *.
-
- - Additionally, if -XTypeInType is on, then a data definition with a top-level
- :: must explicitly bind all kind variables to the right of the ::.
- See test dependent/should_compile/KindLevels, which requires this case.
- (Naturally, any kind variable mentioned before the :: should not be bound
- after it.)
--}
-
instance (OutputableBndr name) => Outputable (FamilyDecl name) where
ppr = pprFamilyDecl TopLevel
diff --git a/compiler/hsSyn/HsUtils.hs b/compiler/hsSyn/HsUtils.hs
index 8ac7e24f8d..35f146b55e 100644
--- a/compiler/hsSyn/HsUtils.hs
+++ b/compiler/hsSyn/HsUtils.hs
@@ -80,6 +80,7 @@ module HsUtils(
hsLTyClDeclBinders, hsTyClForeignBinders, hsPatSynBinders,
hsForeignDeclsBinders, hsGroupBinders, hsDataFamInstBinders,
+ hsDataDefnBinders,
-- Collecting implicit binders
lStmtsImplicits, hsValBindsImplicits, lPatImplicits
@@ -883,18 +884,21 @@ So in mkSelectorBinds in DsUtils, we want just m,n as the variables bound.
hsGroupBinders :: HsGroup Name -> [Name]
hsGroupBinders (HsGroup { hs_valds = val_decls, hs_tyclds = tycl_decls,
- hs_instds = inst_decls, hs_fords = foreign_decls })
+ hs_fords = foreign_decls })
= collectHsValBinders val_decls
- ++ hsTyClForeignBinders tycl_decls inst_decls foreign_decls
+ ++ hsTyClForeignBinders tycl_decls foreign_decls
-hsTyClForeignBinders :: [TyClGroup Name] -> [LInstDecl Name]
- -> [LForeignDecl Name] -> [Name]
+hsTyClForeignBinders :: [TyClGroup Name]
+ -> [LForeignDecl Name]
+ -> [Name]
-- We need to look at instance declarations too,
-- because their associated types may bind data constructors
-hsTyClForeignBinders tycl_decls inst_decls foreign_decls
- = map unLoc (hsForeignDeclsBinders foreign_decls)
- ++ getSelectorNames (foldMap (foldMap hsLTyClDeclBinders . group_tyclds) tycl_decls
- `mappend` foldMap hsLInstDeclBinders inst_decls)
+hsTyClForeignBinders tycl_decls foreign_decls
+ = map unLoc (hsForeignDeclsBinders foreign_decls)
+ ++ getSelectorNames
+ (foldMap (foldMap hsLTyClDeclBinders . group_tyclds) tycl_decls
+ `mappend`
+ foldMap (foldMap hsLInstDeclBinders . group_instds) tycl_decls)
where
getSelectorNames :: ([Located Name], [LFieldOcc Name]) -> [Name]
getSelectorNames (ns, fs) = map unLoc ns ++ map (selectorFieldOcc.unLoc) fs
@@ -902,6 +906,7 @@ hsTyClForeignBinders tycl_decls inst_decls foreign_decls
-------------------
hsLTyClDeclBinders :: Located (TyClDecl name) -> ([Located name], [LFieldOcc name])
-- ^ Returns all the /binding/ names of the decl. The first one is
+
-- guaranteed to be the name of the decl. The first component
-- represents all binding names except record fields; the second
-- represents field occurrences. For record fields mentioned in