diff options
author | Ryan Scott <ryan.gl.scott@gmail.com> | 2018-10-01 12:05:12 -0400 |
---|---|---|
committer | Ryan Scott <ryan.gl.scott@gmail.com> | 2018-10-01 12:05:12 -0400 |
commit | a57fa24746421c0e13d0c09b72cbabea3622779f (patch) | |
tree | efa4ad972bfbc380088bec97f8df9bbb92a4e40e | |
parent | 309438e948359a0ae71ffac4a41ebcd855cf5657 (diff) | |
download | haskell-a57fa24746421c0e13d0c09b72cbabea3622779f.tar.gz |
Quantify class variables first in associated families' kinds
Summary:
Previously, `kcLHsQTyVars` would always quantify class-bound
variables invisibly in the kinds of associated types, resulting in
#15591. We counteract this by explicitly passing the class-bound
variables to `kcLHsQTyVars` and quantifying over the ones that are
mentioned in the associated type such that (1) they are specified,
and (2) they come before other kind variables.
See `Note [Kind variable ordering for associated types]`.
Test Plan: make test TEST=T15591
Reviewers: goldfire, simonpj, bgamari
Reviewed By: simonpj
Subscribers: rwbarton, carter
GHC Trac Issues: #15591
Differential Revision: https://phabricator.haskell.org/D5159
-rw-r--r-- | compiler/typecheck/TcHsType.hs | 82 | ||||
-rw-r--r-- | compiler/typecheck/TcTyClsDecls.hs | 57 | ||||
-rw-r--r-- | docs/users_guide/glasgow_exts.rst | 12 | ||||
-rw-r--r-- | testsuite/tests/ghci/scripts/T15591.hs | 10 | ||||
-rw-r--r-- | testsuite/tests/ghci/scripts/T15591.script | 4 | ||||
-rw-r--r-- | testsuite/tests/ghci/scripts/T15591.stdout | 2 | ||||
-rwxr-xr-x | testsuite/tests/ghci/scripts/all.T | 1 |
7 files changed, 138 insertions, 30 deletions
diff --git a/compiler/typecheck/TcHsType.hs b/compiler/typecheck/TcHsType.hs index a9d6d46344..4b755e4086 100644 --- a/compiler/typecheck/TcHsType.hs +++ b/compiler/typecheck/TcHsType.hs @@ -1514,10 +1514,13 @@ tcWildCardBinders wc_names thing_inside kcLHsQTyVars :: Name -- ^ of the thing being checked -> TyConFlavour -- ^ What sort of 'TyCon' is being checked -> Bool -- ^ True <=> the decl being checked has a CUSK + -> [(Name, TyVar)] -- ^ If the thing being checked is associated + -- with a class, this is the class's scoped + -- type variables. Empty otherwise. -> LHsQTyVars GhcRn -> TcM Kind -- ^ The result kind -> TcM TcTyCon -- ^ A suitably-kinded TcTyCon -kcLHsQTyVars name flav cusk +kcLHsQTyVars name flav cusk parent_tv_prs user_tyvars@(HsQTvs { hsq_ext = HsQTvsRn { hsq_implicit = kv_ns , hsq_dependent = dep_names } , hsq_explicit = hs_tvs }) thing_inside @@ -1532,7 +1535,16 @@ kcLHsQTyVars name flav cusk ; let tc_binders_unzonked = zipWith mk_tc_binder hs_tvs tc_tvs ; dvs <- zonkTcTypeAndSplitDepVars (mkSpecForAllTys scoped_kvs $ mkTyConKind tc_binders_unzonked res_kind) - ; qkvs <- quantifyTyVars emptyVarSet dvs + ; let -- Any type variables bound by the parent class that are specified + -- in this declaration (associated with the class). We single + -- these out because we want to bind these first in this + -- declaration's kind. + -- See Note [Kind variable ordering for associated types]. + reused_from_parent_tv_prs = + filter (\(_, tv) -> tv `elemDVarSet` dv_kvs dvs + || tv `elemDVarSet` dv_tvs dvs) parent_tv_prs + reused_from_parent_tvs = map snd reused_from_parent_tv_prs + ; qkvs <- quantifyTyVars (mkVarSet reused_from_parent_tvs) dvs -- don't call tcGetGlobalTyCoVars. For associated types, it gets the -- tyvars from the enclosing class -- but that's wrong. We *do* want -- to quantify over those tyvars. @@ -1553,21 +1565,37 @@ kcLHsQTyVars name flav cusk scoped_kvs ; reportFloatingKvs name flav all_tc_tvs unmentioned_kvs - ; let final_binders = map (mkNamedTyConBinder Inferred) qkvs - ++ map (mkNamedTyConBinder Specified) scoped_kvs + ; let all_scoped_kvs = reused_from_parent_tvs ++ scoped_kvs + final_binders = map (mkNamedTyConBinder Inferred) qkvs + ++ map (mkNamedTyConBinder Specified) all_scoped_kvs ++ tc_binders + all_tv_prs = reused_from_parent_tv_prs ++ + mkTyVarNamePairs (scoped_kvs ++ tc_tvs) tycon = mkTcTyCon name (ppr user_tyvars) final_binders res_kind - (mkTyVarNamePairs (scoped_kvs ++ tc_tvs)) - flav + all_tv_prs flav -- the tvs contain the binders already -- in scope from an enclosing class, but -- re-adding tvs to the env't doesn't cause -- harm ; traceTc "kcLHsQTyVars: cusk" $ - vcat [ ppr name, ppr kv_ns, ppr hs_tvs, ppr dep_names - , ppr tc_tvs, ppr (mkTyConKind final_binders res_kind) - , ppr qkvs, ppr final_binders ] + vcat [ text "name" <+> ppr name + , text "kv_ns" <+> ppr kv_ns + , text "hs_tvs" <+> ppr hs_tvs + , text "dep_names" <+> ppr dep_names + , text "scoped_kvs" <+> ppr scoped_kvs + , text "reused_from_parent_tv_prs" + <+> ppr reused_from_parent_tv_prs + , text "tc_tvs" <+> ppr tc_tvs + , text "res_kind" <+> ppr res_kind + , text "dvs" <+> ppr dvs + , text "qkvs" <+> ppr qkvs + , text "all_scoped_kvs" <+> ppr all_scoped_kvs + , text "tc_binders" <+> ppr tc_binders + , text "final_binders" <+> ppr final_binders + , text "mkTyConKind final_binders res_kind" + <+> ppr (mkTyConKind final_binders res_kind) + , text "all_tv_prs" <+> ppr all_tv_prs ] ; return tycon } @@ -1601,7 +1629,7 @@ kcLHsQTyVars name flav cusk | otherwise = mkAnonTyConBinder tv -kcLHsQTyVars _ _ _ (XLHsQTyVars _) _ = panic "kcLHsQTyVars" +kcLHsQTyVars _ _ _ _ (XLHsQTyVars _) _ = panic "kcLHsQTyVars" kcLHsQTyVarBndrs :: Bool -- True <=> bump the TcLevel when bringing vars into scope -> Bool -- True <=> Default un-annotated tyvar @@ -1685,6 +1713,40 @@ See Note [Associated type tyvar names] in Class and We must do the same for family instance decls, where the in-scope variables may be bound by the enclosing class instance decl. Hence the use of tcImplicitQTKBndrs in tcFamTyPats. + +Note [Kind variable ordering for associated types] +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +What should be the kind of `T` in the following example? (#15591) + + class C (a :: Type) where + type T (x :: f a) + +As per Note [Ordering of implicit variables] in RnTypes, we want to quantify +the kind variables in left-to-right order of first occurrence in order to +support visible kind application. But we cannot perform this analysis on just +T alone, since its variable `a` actually occurs /before/ `f` if you consider +the fact that `a` was previously bound by the parent class `C`. That is to say, +the kind of `T` should end up being: + + T :: forall a f. f a -> Type + +(It wouldn't necessarily be /wrong/ if the kind ended up being, say, +forall f a. f a -> Type, but that would not be as predictable for users of +visible kind application.) + +In contrast, if `T` were redefined to be a top-level type family, like `T2` +below: + + type family T2 (x :: f (a :: Type)) + +Then `a` first appears /after/ `f`, so the kind of `T2` should be: + + T2 :: forall f a. f a -> Type + +In order to make this distinction, we need to know (in kcLHsQTyVars) which +type variables have been bound by the parent class (if there is one). With +the class-bound variables in hand, we can ensure that we always quantify +these first. -} diff --git a/compiler/typecheck/TcTyClsDecls.hs b/compiler/typecheck/TcTyClsDecls.hs index 8419b90465..ae64f084b0 100644 --- a/compiler/typecheck/TcTyClsDecls.hs +++ b/compiler/typecheck/TcTyClsDecls.hs @@ -73,6 +73,7 @@ import BasicTypes import qualified GHC.LanguageExtensions as LangExt import Control.Monad +import Control.Monad.Zip import Data.List import Data.List.NonEmpty ( NonEmpty(..) ) import qualified Data.Set as Set @@ -630,11 +631,12 @@ getInitialKind :: TyClDecl GhcRn -> TcM [TcTyCon] getInitialKind decl@(ClassDecl { tcdLName = L _ name, tcdTyVars = ktvs, tcdATs = ats }) = do { let cusk = hsDeclHasCusk decl - ; tycon <- kcLHsQTyVars name ClassFlavour cusk ktvs $ + ; tycon <- kcLHsQTyVars name ClassFlavour cusk [] ktvs $ return constraintKind + ; let parent_tv_prs = tcTyConScopedTyVars tycon -- See Note [Don't process associated types in kcLHsQTyVars] - ; inner_tcs <- tcExtendNameTyVarEnv (tcTyConScopedTyVars tycon) $ - getFamDeclInitialKinds (Just cusk) ats + ; inner_tcs <- tcExtendNameTyVarEnv parent_tv_prs $ + getFamDeclInitialKinds (Just (cusk, parent_tv_prs)) ats ; return (tycon : inner_tcs) } getInitialKind decl@(DataDecl { tcdLName = L _ name @@ -642,7 +644,8 @@ getInitialKind decl@(DataDecl { tcdLName = L _ name , tcdDataDefn = HsDataDefn { dd_kindSig = m_sig , dd_ND = new_or_data } }) = do { tycon <- - kcLHsQTyVars name (newOrDataToFlavour new_or_data) (hsDeclHasCusk decl) ktvs $ + kcLHsQTyVars name (newOrDataToFlavour new_or_data) + (hsDeclHasCusk decl) [] ktvs $ case m_sig of Just ksig -> tcLHsKindSig (DataKindCtxt name) ksig Nothing -> return liftedTypeKind @@ -655,7 +658,8 @@ getInitialKind (FamDecl { tcdFam = decl }) getInitialKind decl@(SynDecl { tcdLName = L _ name , tcdTyVars = ktvs , tcdRhs = rhs }) - = do { tycon <- kcLHsQTyVars name TypeSynonymFlavour (hsDeclHasCusk decl) ktvs $ + = do { tycon <- kcLHsQTyVars name TypeSynonymFlavour (hsDeclHasCusk decl) + [] ktvs $ case kind_annotation rhs of Nothing -> newMetaKindVar Just ksig -> tcLHsKindSig (TySynKindCtxt name) ksig @@ -671,20 +675,31 @@ getInitialKind (DataDecl _ (L _ _) _ _ (XHsDataDefn _)) = panic "getInitialKind" getInitialKind (XTyClDecl _) = panic "getInitialKind" --------------------------------- -getFamDeclInitialKinds :: Maybe Bool -- if assoc., CUSKness of assoc. class - -> [LFamilyDecl GhcRn] - -> TcM [TcTyCon] -getFamDeclInitialKinds mb_cusk decls - = mapM (addLocM (getFamDeclInitialKind mb_cusk)) decls - -getFamDeclInitialKind :: Maybe Bool -- if assoc., CUSKness of assoc. class - -> FamilyDecl GhcRn - -> TcM TcTyCon -getFamDeclInitialKind mb_cusk decl@(FamilyDecl { fdLName = L _ name - , fdTyVars = ktvs - , fdResultSig = L _ resultSig - , fdInfo = info }) - = do { tycon <- kcLHsQTyVars name flav cusk ktvs $ +getFamDeclInitialKinds + :: Maybe (Bool, [(Name, TyVar)]) + -- ^ If this family declaration is associated with a class, this is + -- @'Just' (cusk, cls_tv_prs)@, where @cusk@ indicates the CUSKness of + -- the associated class and @cls_tv_prs@ contains the class's scoped + -- type variables. + -> [LFamilyDecl GhcRn] + -> TcM [TcTyCon] +getFamDeclInitialKinds mb_parent_info decls + = mapM (addLocM (getFamDeclInitialKind mb_parent_info)) decls + +getFamDeclInitialKind + :: Maybe (Bool, [(Name, TyVar)]) + -- ^ If this family declaration is associated with a class, this is + -- @'Just' (cusk, cls_tv_prs)@, where @cusk@ indicates the CUSKness of + -- the associated class and @cls_tv_prs@ contains the class's scoped + -- type variables. + -> FamilyDecl GhcRn + -> TcM TcTyCon +getFamDeclInitialKind mb_parent_info + decl@(FamilyDecl { fdLName = L _ name + , fdTyVars = ktvs + , fdResultSig = L _ resultSig + , fdInfo = info }) + = do { tycon <- kcLHsQTyVars name flav cusk parent_tv_prs ktvs $ case resultSig of KindSig _ ki -> tcLHsKindSig ctxt ki TyVarSig _ (L _ (KindedTyVar _ _ ki)) -> tcLHsKindSig ctxt ki @@ -695,7 +710,9 @@ getFamDeclInitialKind mb_cusk decl@(FamilyDecl { fdLName = L _ name | otherwise -> newMetaKindVar ; return tycon } where - cusk = famDeclHasCusk mb_cusk decl + (mb_cusk, mb_parent_tv_prs) = munzip mb_parent_info + cusk = famDeclHasCusk mb_cusk decl + parent_tv_prs = mb_parent_tv_prs `orElse` [] flav = case info of DataFamily -> DataFamilyFlavour (isJust mb_cusk) OpenTypeFamily -> OpenTypeFamilyFlavour (isJust mb_cusk) diff --git a/docs/users_guide/glasgow_exts.rst b/docs/users_guide/glasgow_exts.rst index 4fd6f1b2af..1664dbc571 100644 --- a/docs/users_guide/glasgow_exts.rst +++ b/docs/users_guide/glasgow_exts.rst @@ -10711,6 +10711,18 @@ Here are the details: In the kind of ``F``, the left-to-right ordering of ``j``, ``k``, and ``l`` is preserved. + If a family declaration is associated with a class, then class-bound + variables always come first in the kind of the family. For instance: :: + + class C (a :: Type) where + type T (x :: f a) + -- T :: forall a f. f a -> Type + + Contrast this with the kind of the following top-level family declaration: :: + + type family T2 (x :: f a) + -- T2 :: forall f a. f a -> Type + .. _implicit-parameters: Implicit parameters diff --git a/testsuite/tests/ghci/scripts/T15591.hs b/testsuite/tests/ghci/scripts/T15591.hs new file mode 100644 index 0000000000..eccf628eed --- /dev/null +++ b/testsuite/tests/ghci/scripts/T15591.hs @@ -0,0 +1,10 @@ +{-# LANGUAGE PolyKinds #-} +{-# LANGUAGE TypeFamilies #-} +module Foo where + +import Data.Kind + +type family T1 (x :: f (a :: Type)) + +class C (a :: Type) where + type T2 (x :: f a) diff --git a/testsuite/tests/ghci/scripts/T15591.script b/testsuite/tests/ghci/scripts/T15591.script new file mode 100644 index 0000000000..0afd32e1e6 --- /dev/null +++ b/testsuite/tests/ghci/scripts/T15591.script @@ -0,0 +1,4 @@ +:load T15591 +:set -fprint-explicit-foralls +:kind T1 +:kind T2 diff --git a/testsuite/tests/ghci/scripts/T15591.stdout b/testsuite/tests/ghci/scripts/T15591.stdout new file mode 100644 index 0000000000..28dbd49dc1 --- /dev/null +++ b/testsuite/tests/ghci/scripts/T15591.stdout @@ -0,0 +1,2 @@ +T1 :: forall (f :: * -> *) a. f a -> * +T2 :: forall a (f :: * -> *). f a -> * diff --git a/testsuite/tests/ghci/scripts/all.T b/testsuite/tests/ghci/scripts/all.T index 290c274a94..dcc4855ab4 100755 --- a/testsuite/tests/ghci/scripts/all.T +++ b/testsuite/tests/ghci/scripts/all.T @@ -284,3 +284,4 @@ test('T15259', normal, ghci_script, ['T15259.script']) test('T15341', normal, ghci_script, ['T15341.script']) test('T15568', normal, ghci_script, ['T15568.script']) test('T15325', normal, ghci_script, ['T15325.script']) +test('T15591', normal, ghci_script, ['T15591.script']) |