[GHC] #16008: GHC HEAD type family regression involving invisible arguments

#16008: GHC HEAD type family regression involving invisible arguments -------------------------------------+------------------------------------- Reporter: RyanGlScott | Owner: (none) Type: bug | Status: new Priority: highest | Milestone: 8.8.1 Component: Compiler | Version: 8.7 (Type checker) | Keywords: TypeFamilies, | Operating System: Unknown/Multiple TypeInType | Architecture: | Type of failure: GHC rejects Unknown/Multiple | valid program Test Case: | Blocked By: Blocking: | Related Tickets: Differential Rev(s): | Wiki Page: -------------------------------------+------------------------------------- The following code compiles on GHC 8.0.2 through 8.6.2: {{{#!hs {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeInType #-} module Bug where import Data.Kind class C k where type S :: k -> Type data D :: Type -> Type data SD :: forall a. D a -> Type instance C (D a) where type S = SD }}} But fails to compile on GHC HEAD (commit 73cce63f33ee80f5095085141df9313ac70d1cfa): {{{ $ ~/Software/ghc2/inplace/bin/ghc-stage2 Bug.hs [1 of 1] Compiling Bug ( Bug.hs, Bug.o ) Bug.hs:15:3: error: • Type indexes must match class instance head Expected: S @(D a) Actual: S @(D a1) • In the type instance declaration for ‘S’ In the instance declaration for ‘C (D a)’ | 15 | type S = SD | ^^^^^^^^^^^ }}} This regression prevents [https://cs.brynmawr.edu/~rae/papers/2018/stitch/stitch.tar.gz the stitch library] from compiling. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/16008 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#16008: GHC HEAD type family regression involving invisible arguments -------------------------------------+------------------------------------- Reporter: RyanGlScott | Owner: (none) Type: bug | Status: new Priority: highest | Milestone: 8.8.1 Component: Compiler (Type | Version: 8.7 checker) | Keywords: TypeFamilies, Resolution: | TypeInType Operating System: Unknown/Multiple | Architecture: Type of failure: GHC rejects | Unknown/Multiple valid program | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by RyanGlScott): A workaround is to manually give `SD` a kind ascription: {{{#!hs instance C (D a) where type S = (SD :: D a -> Type) }}} -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/16008#comment:1 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#16008: GHC HEAD type family regression involving invisible arguments -------------------------------------+------------------------------------- Reporter: RyanGlScott | Owner: (none) Type: bug | Status: new Priority: highest | Milestone: 8.8.1 Component: Compiler (Type | Version: 8.7 checker) | Keywords: TypeFamilies, Resolution: | TypeInType Operating System: Unknown/Multiple | Architecture: Type of failure: GHC rejects | Unknown/Multiple valid program | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by RyanGlScott): I haven't confirmed this yet, but I believe the culprit is [http://git.haskell.org/ghc.git/blob/c77fbd94cc60301e5696b75cda44adb07da19a6a... this part] of `tcTyFamInstEqnGuts`: {{{#!hs tc_lhs | null hs_pats -- See Note [Apparently-nullary families] = do { (args, rhs_kind) <- tcInstTyBinders $ splitPiTysInvisibleN (tyConArity fam_tc) (tyConKind fam_tc) ; return (mkTyConApp fam_tc args, rhs_kind) } | otherwise = tcFamTyPats fam_tc mb_clsinfo hs_pats }}} In the `null hs_pats` case, we are calling `tcInstTyBinders`, but that doesn't take the class-bound variables (in `mb_clsinfo`) into account! Some evidence which supports this theory: 1. The `otherwise` case (when the type family takes at least one argument) //does// take `mb_clsinfo` into account. You can see for yourself that this code works correctly by observing that this variant of the original program typechecks: {{{#!hs {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeInType #-} module Bug where import Data.Kind class C k where type S z :: k -> Type data D :: Type -> Type data SD :: forall a. D a -> Type instance C (D a) where type S z = SD }}} 2. Before commit 2257a86daa72db382eb927df12a718669d5491f8 (`Taming the Kind Inference Monster`), which introduced this regression, the code that corresponded to `tc_lhs` was this: {{{#!hs kcTyFamEqnRhs mb_clsinfo rhs_hs_ty lhs_ki = do { -- It's still possible the lhs_ki has some foralls. Instantiate these away. (new_pats, insted_lhs_ki) <- instantiateTyUntilN mb_kind_env 0 lhs_ki }}} This code uses a function which is aware of the class-bound variables (`mb_kind_env`). -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/16008#comment:2 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#16008: GHC HEAD type family regression involving invisible arguments -------------------------------------+------------------------------------- Reporter: RyanGlScott | Owner: (none) Type: bug | Status: new Priority: highest | Milestone: 8.8.1 Component: Compiler (Type | Version: 8.7 checker) | Keywords: TypeFamilies, Resolution: | TypeInType Operating System: Unknown/Multiple | Architecture: Type of failure: GHC rejects | Unknown/Multiple valid program | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by RyanGlScott): The following patch makes the original program compile again: {{{#!diff diff --git a/compiler/typecheck/Inst.hs b/compiler/typecheck/Inst.hs index 284d6a95d3..991f7eb859 100644 --- a/compiler/typecheck/Inst.hs +++ b/compiler/typecheck/Inst.hs @@ -487,18 +487,19 @@ no longer cut it, but it seems fine for now. -- | Instantantiate the TyConBinders of a forall type, -- given its decomposed form (tvs, ty) tcInstTyBinders :: HasDebugCallStack - => ([TyCoBinder], TcKind) -- ^ The type (forall bs. ty) + => Maybe (VarEnv Kind) + -> ([TyCoBinder], TcKind) -- ^ The type (forall bs. ty) -> TcM ([TcType], TcKind) -- ^ Instantiated bs, substituted ty -- Takes a pair because that is what splitPiTysInvisible returns -- See also Note [Bidirectional type checking] -tcInstTyBinders (bndrs, ty) +tcInstTyBinders mb_kind_info (bndrs, ty) | null bndrs -- It's fine for bndrs to be empty e.g. = return ([], ty) -- Check that (Maybe :: forall {k}. k->*), -- and see the call to instTyBinders in checkExpectedKind -- A user bug to be reported as such; it is not a compiler crash! | otherwise - = do { (subst, args) <- mapAccumLM (tcInstTyBinder Nothing) empty_subst bndrs + = do { (subst, args) <- mapAccumLM (tcInstTyBinder mb_kind_info) empty_subst bndrs ; ty' <- zonkTcType (substTy subst ty) -- Why zonk the result? So that tcTyVar can -- obey (IT6) of Note [The tcType invariant] in TcHsType diff --git a/compiler/typecheck/TcHsType.hs b/compiler/typecheck/TcHsType.hs index 3b36281d4a..39f26949ae 100644 --- a/compiler/typecheck/TcHsType.hs +++ b/compiler/typecheck/TcHsType.hs @@ -1021,7 +1021,7 @@ checkExpectedKindX pp_hs_ty ty act_kind exp_kind let n_exp_invis_bndrs = invisibleTyBndrCount exp_kind n_act_invis_bndrs = invisibleTyBndrCount act_kind n_to_inst = n_act_invis_bndrs - n_exp_invis_bndrs - ; (new_args, act_kind') <- tcInstTyBinders (splitPiTysInvisibleN n_to_inst act_kind) + ; (new_args, act_kind') <- tcInstTyBinders Nothing (splitPiTysInvisibleN n_to_inst act_kind) ; let origin = TypeEqOrigin { uo_actual = act_kind' , uo_expected = exp_kind @@ -1133,7 +1133,7 @@ tcTyVar mode name -- Could be a tyvar, a tycon, or a datacon | otherwise = do { let tc_arity = tyConArity tc ; tc_kind <- zonkTcType (tyConKind tc) - ; (tc_args, kind) <- tcInstTyBinders (splitPiTysInvisibleN tc_arity tc_kind) + ; (tc_args, kind) <- tcInstTyBinders Nothing (splitPiTysInvisibleN tc_arity tc_kind) -- Instantiate enough invisible arguments -- to saturate the family TyCon diff --git a/compiler/typecheck/TcTyClsDecls.hs b/compiler/typecheck/TcTyClsDecls.hs index 877166dfd5..0700f94202 100644 --- a/compiler/typecheck/TcTyClsDecls.hs +++ b/compiler/typecheck/TcTyClsDecls.hs @@ -1895,13 +1895,17 @@ tcTyFamInstEqnGuts fam_tc mb_clsinfo imp_vars exp_bndrs hs_pats hs_rhs_ty ; return (qtvs, pats, rhs_ty) } where tc_lhs | null hs_pats -- See Note [Apparently-nullary families] - = do { (args, rhs_kind) <- tcInstTyBinders $ + = do { (args, rhs_kind) <- tcInstTyBinders mb_kind_env $ splitPiTysInvisibleN (tyConArity fam_tc) (tyConKind fam_tc) ; return (mkTyConApp fam_tc args, rhs_kind) } | otherwise = tcFamTyPats fam_tc mb_clsinfo hs_pats + mb_kind_env = case mb_clsinfo of + NotAssociated -> Nothing + InClsInst{ai_inst_env = kind_env} -> Just kind_env + {- Note [Apparently-nullary families] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Consider diff --git a/testsuite/tests/indexed-types/should_fail/T9160.stderr b/testsuite/tests/indexed-types/should_fail/T9160.stderr index e918013f67..14f204191e 100644 --- a/testsuite/tests/indexed-types/should_fail/T9160.stderr +++ b/testsuite/tests/indexed-types/should_fail/T9160.stderr @@ -1,7 +1,7 @@ -T9160.hs:19:3: error: - • Type indexes must match class instance head - Expected: F @* - Actual: F @(* -> *) - • In the type instance declaration for ‘F’ +T9160.hs:19:12: error: + • Expecting one more argument to ‘Maybe’ + Expected a type, but ‘Maybe’ has kind ‘* -> *’ + • In the type ‘Maybe’ + In the type instance declaration for ‘F’ In the instance declaration for ‘C (a :: *)’ }}} As you can see, there is one existing test (`T9160`) whose expected stderr changed, but the new error message arguably makes as much sense as the previous one. (For what it's worth, that new error message used to be the expected stderr before commit https://ghc.haskell.org/trac/ghc/changeset/2257a86daa72db382eb927df12a718669... landed.) -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/16008#comment:3 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#16008: GHC HEAD type family regression involving invisible arguments -------------------------------------+------------------------------------- Reporter: RyanGlScott | Owner: (none) Type: bug | Status: new Priority: highest | Milestone: 8.8.1 Component: Compiler (Type | Version: 8.7 checker) | Keywords: TypeFamilies, Resolution: | TypeInType Operating System: Unknown/Multiple | Architecture: Type of failure: GHC rejects | Unknown/Multiple valid program | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by goldfire): I know Simon strongly disliked that `Maybe (VarEnv Kind)` getting too far from TcTyClsDecls. Could you just add a call to `addConsistencyConstraints` to `tc_lhs`? I also think that the new `checkExpectedKind` from Phab:D5229 will fix this handily. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/16008#comment:4 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#16008: GHC HEAD type family regression involving invisible arguments -------------------------------------+------------------------------------- Reporter: RyanGlScott | Owner: (none) Type: bug | Status: patch Priority: highest | Milestone: 8.8.1 Component: Compiler (Type | Version: 8.7 checker) | Keywords: TypeFamilies, Resolution: | TypeInType Operating System: Unknown/Multiple | Architecture: Type of failure: GHC rejects | Unknown/Multiple valid program | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Phab:D5435 Wiki Page: | -------------------------------------+------------------------------------- Changes (by RyanGlScott): * status: new => patch * differential: => Phab:D5435 Comment: Oh wow, I was not aware of `checkConsistencyConstraints`! That's a much cleaner solution, and better yet, it doesn't cause any existing tests to change their expected output. I've submitted a patch as Phab:D5435. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/16008#comment:5 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#16008: GHC HEAD type family regression involving invisible arguments
-------------------------------------+-------------------------------------
Reporter: RyanGlScott | Owner: (none)
Type: bug | Status: patch
Priority: highest | Milestone: 8.8.1
Component: Compiler (Type | Version: 8.7
checker) | Keywords: TypeFamilies,
Resolution: | TypeInType
Operating System: Unknown/Multiple | Architecture:
Type of failure: GHC rejects | Unknown/Multiple
valid program | Test Case:
Blocked By: | Blocking:
Related Tickets: | Differential Rev(s): Phab:D5435
Wiki Page: |
-------------------------------------+-------------------------------------
Comment (by Ryan Scott

#16008: GHC HEAD type family regression involving invisible arguments -------------------------------------+------------------------------------- Reporter: RyanGlScott | Owner: (none) Type: bug | Status: closed Priority: highest | Milestone: 8.8.1 Component: Compiler (Type | Version: 8.7 checker) | Keywords: TypeFamilies, Resolution: fixed | TypeInType Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: GHC rejects | Test Case: valid program | typecheck/should_compile/T16008 Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Phab:D5435 Wiki Page: | -------------------------------------+------------------------------------- Changes (by RyanGlScott): * status: patch => closed * testcase: => typecheck/should_compile/T16008 * resolution: => fixed -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/16008#comment:7 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler
participants (1)
-
GHC