summaryrefslogtreecommitdiff
path: root/compiler/iface
diff options
context:
space:
mode:
authorSimon Peyton Jones <simonpj@microsoft.com>2018-11-28 16:06:15 +0000
committerSimon Peyton Jones <simonpj@microsoft.com>2018-11-29 17:27:40 +0000
commit2257a86daa72db382eb927df12a718669d5491f8 (patch)
tree74bc33c17a5c898764be09eb6a9cb33572e91b2d /compiler/iface
parent79d5427e1f9de02c0b171bf5db46b6b49c6f85e3 (diff)
downloadhaskell-2257a86daa72db382eb927df12a718669d5491f8.tar.gz
Taming the Kind Inference Monster
My original goal was (Trac #15809) to move towards using level numbers as the basis for deciding which type variables to generalise, rather than searching for the free varaibles of the environment. However it has turned into a truly major refactoring of the kind inference engine. Let's deal with the level-numbers part first: * Augment quantifyTyVars to calculate the type variables to quantify using level numbers, and compare the result with the existing approach. That is; no change in behaviour, just a WARNing if the two approaches give different answers. * To do this I had to get the level number right when calling quantifyTyVars, and this entailed a bit of care, especially in the code for kind-checking type declarations. * However, on the way I was able to eliminate or simplify a number of calls to solveEqualities. This work is incomplete: I'm not /using/ level numbers yet. When I subsequently get rid of any remaining WARNings in quantifyTyVars, that the level-number answers differ from the current answers, then I can rip out the current "free vars of the environment" stuff. Anyway, this led me into deep dive into kind inference for type and class declarations, which is an increasingly soggy part of GHC. Richard already did some good work recently in commit 5e45ad10ffca1ad175b10f6ef3327e1ed8ba25f3 Date: Thu Sep 13 09:56:02 2018 +0200 Finish fix for #14880. The real change that fixes the ticket is described in Note [Naughty quantification candidates] in TcMType. but I kept turning over stones. So this patch has ended up with a pretty significant refactoring of that code too. Kind inference for types and classes ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * Major refactoring in the way we generalise the inferred kind of a TyCon, in kcTyClGroup. Indeed, I made it into a new top-level function, generaliseTcTyCon. Plus a new Note to explain it Note [Inferring kinds for type declarations]. * We decided (Trac #15592) not to treat class type variables specially when dealing with Inferred/Specified/Required for associated types. That simplifies things quite a bit. I also rewrote Note [Required, Specified, and Inferred for types] * Major refactoring of the crucial function kcLHsQTyVars: I split it into kcLHsQTyVars_Cusk and kcLHsQTyVars_NonCusk because the two are really quite different. The CUSK case is almost entirely rewritten, and is much easier because of our new decision not to treat the class variables specially * I moved all the error checks from tcTyClTyVars (which was a bizarre place for it) into generaliseTcTyCon and/or the CUSK case of kcLHsQTyVars. Now tcTyClTyVars is extremely simple. * I got rid of all the all the subtleties in tcImplicitTKBndrs. Indeed now there is no difference between tcImplicitTKBndrs and kcImplicitTKBndrs; there is now a single bindImplicitTKBndrs. Same for kc/tcExplicitTKBndrs. None of them monkey with level numbers, nor build implication constraints. scopeTyVars is gone entirely, as is kcLHsQTyVarBndrs. It's vastly simpler. I found I could get rid of kcLHsQTyVarBndrs entirely, in favour of the bnew bindExplicitTKBndrs. Quantification ~~~~~~~~~~~~~~ * I now deal with the "naughty quantification candidates" of the previous patch in candidateQTyVars, rather than in quantifyTyVars; see Note [Naughty quantification candidates] in TcMType. I also killed off closeOverKindsCQTvs in favour of the same strategy that we use for tyCoVarsOfType: namely, close over kinds at the occurrences. And candidateQTyVars no longer needs a gbl_tvs argument. * Passing the ContextKind, rather than the expected kind itself, to tc_hs_sig_type_and_gen makes it easy to allocate the expected result kind (when we are in inference mode) at the right level. Type families ~~~~~~~~~~~~~~ * I did a major rewrite of the impenetrable tcFamTyPats. The result is vastly more comprehensible. * I got rid of kcDataDefn entirely, quite a big function. * I re-did the way that checkConsistentFamInst works, so that it allows alpha-renaming of invisible arguments. * The interaction of kind signatures and family instances is tricky. Type families: see Note [Apparently-nullary families] Data families: see Note [Result kind signature for a data family instance] and Note [Eta-reduction for data families] * The consistent instantation of an associated type family is tricky. See Note [Checking consistent instantiation] and Note [Matching in the consistent-instantation check] in TcTyClsDecls. It's now checked in TcTyClsDecls because that is when we have the relevant info to hand. * I got tired of the compromises in etaExpandFamInst, so I did the job properly by adding a field cab_eta_tvs to CoAxBranch. See Coercion.etaExpandCoAxBranch. tcInferApps and friends ~~~~~~~~~~~~~~~~~~~~~~~ * I got rid of the mysterious and horrible ClsInstInfo argument to tcInferApps, checkExpectedKindX, and various checkValid functions. It was horrible! * I got rid of [Type] result of tcInferApps. This list was used only in tcFamTyPats, when checking the LHS of a type instance; and if there is a cast in the middle, the list is meaningless. So I made tcInferApps simpler, and moved the complexity (not much) to tcInferApps. Result: tcInferApps is now pretty comprehensible again. * I refactored the many function in TcMType that instantiate skolems. Smaller things * I rejigged the error message in checkValidTelescope; I think it's quite a bit better now. * checkValidType was not rejecting constraints in a kind signature forall (a :: Eq b => blah). blah2 That led to further errors when we then do an ambiguity check. So I make checkValidType reject it more aggressively. * I killed off quantifyConDecl, instead calling kindGeneralize directly. * I fixed an outright bug in tyCoVarsOfImplic, where we were not colleting the tyvar of the kind of the skolems * Renamed ClsInstInfo to AssocInstInfo, and made it into its own data type * Some fiddling around with pretty-printing of family instances which was trickier than I thought. I wanted wildcards to print as plain "_" in user messages, although they each need a unique identity in the CoAxBranch. Some other oddments * Refactoring around the trace messages from reportUnsolved. * A bit of extra tc-tracing in TcHsSyn.commitFlexi This patch fixes a raft of bugs, and includes tests for them. * #14887 * #15740 * #15764 * #15789 * #15804 * #15817 * #15870 * #15874 * #15881
Diffstat (limited to 'compiler/iface')
-rw-r--r--compiler/iface/IfaceSyn.hs47
-rw-r--r--compiler/iface/MkIface.hs33
-rw-r--r--compiler/iface/TcIface.hs22
3 files changed, 62 insertions, 40 deletions
diff --git a/compiler/iface/IfaceSyn.hs b/compiler/iface/IfaceSyn.hs
index 2e63fbc22f..1bf4ca9c81 100644
--- a/compiler/iface/IfaceSyn.hs
+++ b/compiler/iface/IfaceSyn.hs
@@ -211,12 +211,13 @@ data IfaceAT = IfaceAT -- See Class.ClassATItem
-- This is just like CoAxBranch
-data IfaceAxBranch = IfaceAxBranch { ifaxbTyVars :: [IfaceTvBndr]
- , ifaxbCoVars :: [IfaceIdBndr]
- , ifaxbLHS :: IfaceAppArgs
- , ifaxbRoles :: [Role]
- , ifaxbRHS :: IfaceType
- , ifaxbIncomps :: [BranchIndex] }
+data IfaceAxBranch = IfaceAxBranch { ifaxbTyVars :: [IfaceTvBndr]
+ , ifaxbEtaTyVars :: [IfaceTvBndr]
+ , ifaxbCoVars :: [IfaceIdBndr]
+ , ifaxbLHS :: IfaceAppArgs
+ , ifaxbRoles :: [Role]
+ , ifaxbRHS :: IfaceType
+ , ifaxbIncomps :: [BranchIndex] }
-- See Note [Storing compatibility] in CoAxiom
data IfaceConDecls
@@ -556,11 +557,19 @@ pprAxBranch :: SDoc -> IfaceAxBranch -> SDoc
-- The TyCon might be local (just an OccName), or this might
-- be a branch for an imported TyCon, so it would be an ExtName
-- So it's easier to take an SDoc here
+--
+-- This function is used
+-- to print interface files,
+-- in debug messages
+-- in :info F for GHCi, which goes via toConToIfaceDecl on the family tycon
+-- For user error messages we use Coercion.pprCoAxiom and friends
pprAxBranch pp_tc (IfaceAxBranch { ifaxbTyVars = tvs
+ , ifaxbCoVars = _cvs
, ifaxbLHS = pat_tys
, ifaxbRHS = rhs
, ifaxbIncomps = incomps })
- = hang ppr_binders 2 (hang pp_lhs 2 (equals <+> ppr rhs))
+ = WARN( not (null _cvs), pp_tc $$ ppr _cvs )
+ hang ppr_binders 2 (hang pp_lhs 2 (equals <+> ppr rhs))
$+$
nest 2 maybe_incomps
where
@@ -890,10 +899,9 @@ pprIfaceDecl ss (IfaceId { ifName = var, ifType = ty,
pprIfaceDecl _ (IfaceAxiom { ifName = name, ifTyCon = tycon
, ifAxBranches = branches })
- = hang (text "axiom" <+> ppr name <> dcolon)
+ = hang (text "axiom" <+> ppr name <+> dcolon)
2 (vcat $ map (pprAxBranch (ppr tycon)) branches)
-
pprCType :: Maybe CType -> SDoc
pprCType Nothing = Outputable.empty
pprCType (Just cType) = text "C type:" <+> ppr cType
@@ -1073,13 +1081,14 @@ instance Outputable IfaceRule where
ppr (IfaceRule { ifRuleName = name, ifActivation = act, ifRuleBndrs = bndrs,
ifRuleHead = fn, ifRuleArgs = args, ifRuleRhs = rhs,
ifRuleOrph = orph })
- = sep [hsep [pprRuleName name,
- if isOrphan orph then text "[orphan]" else Outputable.empty,
- ppr act,
- text "forall" <+> pprIfaceBndrs bndrs],
- nest 2 (sep [ppr fn <+> sep (map pprParendIfaceExpr args),
- text "=" <+> ppr rhs])
- ]
+ = sep [ hsep [ pprRuleName name
+ , if isOrphan orph then text "[orphan]" else Outputable.empty
+ , ppr act
+ , pp_foralls ]
+ , nest 2 (sep [ppr fn <+> sep (map pprParendIfaceExpr args),
+ text "=" <+> ppr rhs]) ]
+ where
+ pp_foralls = ppUnless (null bndrs) $ forAllLit <+> pprIfaceBndrs bndrs <> dot
instance Outputable IfaceClsInst where
ppr (IfaceClsInst { ifDFun = dfun_id, ifOFlag = flag
@@ -1856,13 +1865,14 @@ instance Binary IfaceAT where
return (IfaceAT dec defs)
instance Binary IfaceAxBranch where
- put_ bh (IfaceAxBranch a1 a2 a3 a4 a5 a6) = do
+ put_ bh (IfaceAxBranch a1 a2 a3 a4 a5 a6 a7) = do
put_ bh a1
put_ bh a2
put_ bh a3
put_ bh a4
put_ bh a5
put_ bh a6
+ put_ bh a7
get bh = do
a1 <- get bh
a2 <- get bh
@@ -1870,7 +1880,8 @@ instance Binary IfaceAxBranch where
a4 <- get bh
a5 <- get bh
a6 <- get bh
- return (IfaceAxBranch a1 a2 a3 a4 a5 a6)
+ a7 <- get bh
+ return (IfaceAxBranch a1 a2 a3 a4 a5 a6 a7)
instance Binary IfaceConDecls where
put_ bh IfAbstractTyCon = putByte bh 0
diff --git a/compiler/iface/MkIface.hs b/compiler/iface/MkIface.hs
index e3d1b824be..acd6c46bb6 100644
--- a/compiler/iface/MkIface.hs
+++ b/compiler/iface/MkIface.hs
@@ -22,6 +22,7 @@ module MkIface (
RecompileRequired(..), recompileRequired,
mkIfaceExports,
+ coAxiomToIfaceDecl,
tyThingToIfaceDecl -- Converting things to their Iface equivalents
) where
@@ -1634,18 +1635,16 @@ coAxBranchToIfaceBranch tc lhs_s
-- use this one for standalone branches without incompatibles
coAxBranchToIfaceBranch' :: TyCon -> CoAxBranch -> IfaceAxBranch
coAxBranchToIfaceBranch' tc (CoAxBranch { cab_tvs = tvs, cab_cvs = cvs
+ , cab_eta_tvs = eta_tvs
, cab_lhs = lhs
, cab_roles = roles, cab_rhs = rhs })
- = IfaceAxBranch { ifaxbTyVars = toIfaceTvBndrs tidy_tvs
- , ifaxbCoVars = map toIfaceIdBndr cvs
- , ifaxbLHS = tidyToIfaceTcArgs env1 tc lhs
- , ifaxbRoles = roles
- , ifaxbRHS = tidyToIfaceType env1 rhs
- , ifaxbIncomps = [] }
- where
- (env1, tidy_tvs) = tidyVarBndrs emptyTidyEnv tvs
- -- Don't re-bind in-scope tyvars
- -- See Note [CoAxBranch type variables] in CoAxiom
+ = IfaceAxBranch { ifaxbTyVars = toIfaceTvBndrs tvs
+ , ifaxbCoVars = map toIfaceIdBndr cvs
+ , ifaxbEtaTyVars = toIfaceTvBndrs eta_tvs
+ , ifaxbLHS = toIfaceTcArgs tc lhs
+ , ifaxbRoles = roles
+ , ifaxbRHS = toIfaceType rhs
+ , ifaxbIncomps = [] }
-----------------
tyConToIfaceDecl :: TidyEnv -> TyCon -> (TidyEnv, IfaceDecl)
@@ -1708,6 +1707,7 @@ tyConToIfaceDecl env tycon
(tc_env1, tc_binders) = tidyTyConBinders env (tyConBinders tycon)
tc_tyvars = binderVars tc_binders
if_binders = toIfaceTyCoVarBinders tc_binders
+ -- No tidying of the binders; they are already tidy
if_res_kind = tidyToIfaceType tc_env1 (tyConResKind tycon)
if_syn_type ty = tidyToIfaceType tc_env1 ty
if_res_var = getOccFS `fmap` tyConFamilyResVar_maybe tycon
@@ -1718,19 +1718,16 @@ tyConToIfaceDecl env tycon
(tidyToIfaceTcArgs tc_env1 tc ty)
Nothing -> IfNoParent
- to_if_fam_flav OpenSynFamilyTyCon = IfaceOpenSynFamilyTyCon
+ to_if_fam_flav OpenSynFamilyTyCon = IfaceOpenSynFamilyTyCon
+ to_if_fam_flav AbstractClosedSynFamilyTyCon = IfaceAbstractClosedSynFamilyTyCon
+ to_if_fam_flav (DataFamilyTyCon {}) = IfaceDataFamilyTyCon
+ to_if_fam_flav (BuiltInSynFamTyCon {}) = IfaceBuiltInSynFamTyCon
+ to_if_fam_flav (ClosedSynFamilyTyCon Nothing) = IfaceClosedSynFamilyTyCon Nothing
to_if_fam_flav (ClosedSynFamilyTyCon (Just ax))
= IfaceClosedSynFamilyTyCon (Just (axn, ibr))
where defs = fromBranches $ coAxiomBranches ax
ibr = map (coAxBranchToIfaceBranch' tycon) defs
axn = coAxiomName ax
- to_if_fam_flav (ClosedSynFamilyTyCon Nothing)
- = IfaceClosedSynFamilyTyCon Nothing
- to_if_fam_flav AbstractClosedSynFamilyTyCon = IfaceAbstractClosedSynFamilyTyCon
- to_if_fam_flav (DataFamilyTyCon {}) = IfaceDataFamilyTyCon
- to_if_fam_flav (BuiltInSynFamTyCon {}) = IfaceBuiltInSynFamTyCon
-
-
ifaceConDecls (NewTyCon { data_con = con }) = IfNewTyCon (ifaceConDecl con)
ifaceConDecls (DataTyCon { data_cons = cons }) = IfDataTyCon (map ifaceConDecl cons)
diff --git a/compiler/iface/TcIface.hs b/compiler/iface/TcIface.hs
index 34bcdb7cd5..29893ca319 100644
--- a/compiler/iface/TcIface.hs
+++ b/compiler/iface/TcIface.hs
@@ -857,17 +857,24 @@ tc_ax_branches if_branches = foldlM tc_ax_branch [] if_branches
tc_ax_branch :: [CoAxBranch] -> IfaceAxBranch -> IfL [CoAxBranch]
tc_ax_branch prev_branches
- (IfaceAxBranch { ifaxbTyVars = tv_bndrs, ifaxbCoVars = cv_bndrs
+ (IfaceAxBranch { ifaxbTyVars = tv_bndrs
+ , ifaxbEtaTyVars = eta_tv_bndrs
+ , ifaxbCoVars = cv_bndrs
, ifaxbLHS = lhs, ifaxbRHS = rhs
, ifaxbRoles = roles, ifaxbIncomps = incomps })
= bindIfaceTyConBinders_AT
(map (\b -> Bndr (IfaceTvBndr b) (NamedTCB Inferred)) tv_bndrs) $ \ tvs ->
-- The _AT variant is needed here; see Note [CoAxBranch type variables] in CoAxiom
bindIfaceIds cv_bndrs $ \ cvs -> do
- { tc_lhs <- tcIfaceAppArgs lhs
- ; tc_rhs <- tcIfaceType rhs
- ; let br = CoAxBranch { cab_loc = noSrcSpan
+ { tc_lhs <- tcIfaceAppArgs lhs
+ ; tc_rhs <- tcIfaceType rhs
+ ; eta_tvs <- bindIfaceTyVars eta_tv_bndrs return
+ ; this_mod <- getIfModule
+ ; let loc = mkGeneralSrcSpan (fsLit "module " `appendFS`
+ moduleNameFS (moduleName this_mod))
+ br = CoAxBranch { cab_loc = loc
, cab_tvs = binderVars tvs
+ , cab_eta_tvs = eta_tvs
, cab_cvs = cvs
, cab_lhs = tc_lhs
, cab_roles = roles
@@ -1768,6 +1775,13 @@ bindIfaceTyVar (occ,kind) thing_inside
; tyvar <- mk_iface_tyvar name kind
; extendIfaceTyVarEnv [tyvar] (thing_inside tyvar) }
+bindIfaceTyVars :: [IfaceTvBndr] -> ([TyVar] -> IfL a) -> IfL a
+bindIfaceTyVars [] thing_inside = thing_inside []
+bindIfaceTyVars (bndr:bndrs) thing_inside
+ = bindIfaceTyVar bndr $ \tv ->
+ bindIfaceTyVars bndrs $ \tvs ->
+ thing_inside (tv : tvs)
+
mk_iface_tyvar :: Name -> IfaceKind -> IfL TyVar
mk_iface_tyvar name ifKind
= do { kind <- tcIfaceType ifKind