diff options
-rw-r--r-- | compiler/backpack/RnModIface.hs | 4 | ||||
-rw-r--r-- | compiler/iface/TcIface.hs | 86 | ||||
-rw-r--r-- | compiler/typecheck/TcBackpack.hs | 34 | ||||
-rw-r--r-- | compiler/typecheck/TcRnDriver.hs | 9 | ||||
-rw-r--r-- | compiler/typecheck/TcRnMonad.hs | 5 | ||||
-rw-r--r-- | compiler/typecheck/TcRnTypes.hs | 7 | ||||
-rw-r--r-- | compiler/types/TyCon.hs | 8 | ||||
-rw-r--r-- | testsuite/tests/backpack/should_compile/all.T | 2 | ||||
-rw-r--r-- | testsuite/tests/backpack/should_compile/bkp48.bkp | 23 | ||||
-rw-r--r-- | testsuite/tests/backpack/should_compile/bkp48.stderr | 22 | ||||
-rw-r--r-- | testsuite/tests/backpack/should_compile/bkp49.bkp | 7 | ||||
-rw-r--r-- | testsuite/tests/backpack/should_compile/bkp49.stderr | 4 | ||||
-rw-r--r-- | testsuite/tests/backpack/should_fail/all.T | 1 | ||||
-rw-r--r-- | testsuite/tests/backpack/should_fail/bkpfail42.bkp | 10 | ||||
-rw-r--r-- | testsuite/tests/backpack/should_fail/bkpfail42.stderr | 12 |
15 files changed, 185 insertions, 49 deletions
diff --git a/compiler/backpack/RnModIface.hs b/compiler/backpack/RnModIface.hs index ea3eb54b2a..b7d4623bef 100644 --- a/compiler/backpack/RnModIface.hs +++ b/compiler/backpack/RnModIface.hs @@ -466,7 +466,7 @@ rnIfaceDecl d@IfaceClass{} = do , ifSigs = sigs } rnIfaceDecl d@IfaceAxiom{} = do - name <- rnIfaceGlobal (ifName d) + name <- rnIfaceImplicit (ifName d) tycon <- rnIfaceTyCon (ifTyCon d) ax_branches <- mapM rnIfaceAxBranch (ifAxBranches d) return d { ifName = name @@ -497,7 +497,7 @@ rnIfaceDecl d@IfacePatSyn{} = do rnIfaceFamTyConFlav :: Rename IfaceFamTyConFlav rnIfaceFamTyConFlav (IfaceClosedSynFamilyTyCon (Just (n, axs))) - = IfaceClosedSynFamilyTyCon . Just <$> ((,) <$> rnIfaceGlobal n + = IfaceClosedSynFamilyTyCon . Just <$> ((,) <$> rnIfaceImplicit n <*> mapM rnIfaceAxBranch axs) rnIfaceFamTyConFlav flav = pure flav diff --git a/compiler/iface/TcIface.hs b/compiler/iface/TcIface.hs index d5cc860b64..feb4ecbf86 100644 --- a/compiler/iface/TcIface.hs +++ b/compiler/iface/TcIface.hs @@ -7,6 +7,7 @@ Type checking of type signatures in interface files -} {-# LANGUAGE CPP #-} +{-# LANGUAGE NondecreasingIndentation #-} module TcIface ( tcLookupImported_maybe, @@ -204,6 +205,7 @@ typecheckIface iface isAbstractIfaceDecl :: IfaceDecl -> Bool isAbstractIfaceDecl IfaceData{ ifCons = IfAbstractTyCon _ } = True isAbstractIfaceDecl IfaceClass{ ifCtxt = [], ifSigs = [], ifATs = [] } = True +isAbstractIfaceDecl IfaceFamily{ ifFamFlav = IfaceAbstractClosedSynFamilyTyCon } = True isAbstractIfaceDecl _ = False -- | Merge two 'IfaceDecl's together, preferring a non-abstract one. If @@ -276,7 +278,7 @@ typecheckIfacesForMerging mod ifaces tc_env_var = ignore_prags <- goptM Opt_IgnoreInterfacePragmas -- Build the initial environment -- NB: Don't include dfuns here, because we don't want to - -- serialize them out. See Note [Bogus DFun renamings] + -- serialize them out. See Note [Bogus DFun renamings] in RnModIface let mk_decl_env decls = mkOccEnv [ (getOccName decl, decl) | decl <- decls @@ -295,13 +297,15 @@ typecheckIfacesForMerging mod ifaces tc_env_var = -- OK, now typecheck each ModIface using this environment details <- forM ifaces $ \iface -> do - -- DO NOT load these decls into the mutable variable: we did - -- that already! - decls <- loadDecls ignore_prags (mi_decls iface) - let type_env = mkNameEnv decls + -- See Note [The implicit TypeEnv] + type_env <- fixM $ \type_env -> do + setImplicitEnvM type_env $ do + decls <- loadDecls ignore_prags (mi_decls iface) + return (mkNameEnv decls) -- But note that we use this type_env to typecheck references to DFun -- in 'IfaceInst' - insts <- mapM (tcIfaceInstWithDFunTypeEnv type_env) (mi_insts iface) + setImplicitEnvM type_env $ do + insts <- mapM tcIfaceInst (mi_insts iface) fam_insts <- mapM tcIfaceFamInst (mi_fam_insts iface) rules <- tcIfaceRules ignore_prags (mi_rules iface) anns <- tcIfaceAnnotations (mi_anns iface) @@ -333,10 +337,14 @@ typecheckIfaceForInstantiate nsubst iface = (text "typecheckIfaceForInstantiate") (mi_boot iface) nsubst $ do ignore_prags <- goptM Opt_IgnoreInterfacePragmas - decls <- loadDecls ignore_prags (mi_decls iface) - let type_env = mkNameEnv decls + -- See Note [The implicit TypeEnv] + type_env <- fixM $ \type_env -> do + setImplicitEnvM type_env $ do + decls <- loadDecls ignore_prags (mi_decls iface) + return (mkNameEnv decls) -- See Note [Bogus DFun renamings] - insts <- mapM (tcIfaceInstWithDFunTypeEnv type_env) (mi_insts iface) + setImplicitEnvM type_env $ do + insts <- mapM tcIfaceInst (mi_insts iface) fam_insts <- mapM tcIfaceFamInst (mi_fam_insts iface) rules <- tcIfaceRules ignore_prags (mi_rules iface) anns <- tcIfaceAnnotations (mi_anns iface) @@ -351,6 +359,33 @@ typecheckIfaceForInstantiate nsubst iface = , md_exports = exports } +-- Note [The implicit TypeEnv] +-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +-- As described in 'typecheckIfacesForMerging', the splendid innovation +-- of signature merging is to rewrite all Names in each of the signatures +-- we are merging together to a pre-merged structure; this is the key +-- ingredient that lets us solve some problems when merging type +-- synonyms. +-- +-- However in the case of DFuns and CoAxioms, this strategy goes +-- *too far*. In particular, the reference to a DFun or CoAxiom in +-- an instance declaration or closed type family (respectively) will +-- refer to the merged declaration. However, checkBootDeclM only +-- ever looks at the embedded structure when performing its comparison; +-- by virtue of the fact that everything's been pointed to the merged +-- declaration, you'll never notice there's a difference even if there +-- is one. +-- +-- The solution is, for reference to implicit entities, we go straight +-- for the local TypeEnv corresponding to the entities from this particular +-- signature; this logic is in 'tcIfaceImplicit'. +-- +-- There is also some fixM business because families need to refer to +-- coercion axioms, which are all in the big pile of decls. I didn't +-- feel like untangling first so the fixM is a convenient way to get things +-- where they need to be. +-- + {- ************************************************************************ * * @@ -858,25 +893,7 @@ tcIfaceInst (IfaceClsInst { ifDFun = dfun_name, ifOFlag = oflag , ifInstCls = cls, ifInstTys = mb_tcs , ifInstOrph = orph }) = do { dfun <- forkM (text "Dict fun" <+> ppr dfun_name) $ - tcIfaceExtId dfun_name - ; let mb_tcs' = map (fmap ifaceTyConName) mb_tcs - ; return (mkImportedInstance cls mb_tcs' dfun_name dfun oflag orph) } - --- | Typecheck an 'IfaceClsInst', but rather than using 'tcIfaceGlobal', --- resolve the 'ifDFun' using a passed in 'TypeEnv'. --- --- Why do we do it this way? See Note [Bogus DFun renamings] -tcIfaceInstWithDFunTypeEnv :: TypeEnv -> IfaceClsInst -> IfL ClsInst -tcIfaceInstWithDFunTypeEnv tenv - (IfaceClsInst { ifDFun = dfun_name, ifOFlag = oflag - , ifInstCls = cls, ifInstTys = mb_tcs - , ifInstOrph = orph }) - = do { dfun <- case lookupTypeEnv tenv dfun_name of - Nothing -> pprPanic "tcIfaceInstWithDFunTypeEnv" - (ppr dfun_name $$ ppr tenv) - Just (AnId dfun) -> return dfun - Just tything -> pprPanic "tcIfaceInstWithDFunTypeEnv" - (ppr dfun_name <+> ppr tything) + fmap tyThingId (tcIfaceImplicit dfun_name) ; let mb_tcs' = map (fmap ifaceTyConName) mb_tcs ; return (mkImportedInstance cls mb_tcs' dfun_name dfun oflag orph) } @@ -1618,7 +1635,7 @@ tcIfaceTyCon (IfaceTyCon name info) IsPromoted -> promoteDataCon $ tyThingDataCon thing } tcIfaceCoAxiom :: Name -> IfL (CoAxiom Branched) -tcIfaceCoAxiom name = do { thing <- tcIfaceGlobal name +tcIfaceCoAxiom name = do { thing <- tcIfaceImplicit name ; return (tyThingCoAxiom thing) } tcIfaceDataCon :: Name -> IfL DataCon @@ -1633,6 +1650,17 @@ tcIfaceExtId name = do { thing <- tcIfaceGlobal name AnId id -> return id _ -> pprPanic "tcIfaceExtId" (ppr name$$ ppr thing) } +-- See Note [The implicit TypeEnv] +tcIfaceImplicit :: Name -> IfL TyThing +tcIfaceImplicit n = do + lcl_env <- getLclEnv + case if_implicits_env lcl_env of + Nothing -> tcIfaceGlobal n + Just tenv -> + case lookupTypeEnv tenv n of + Nothing -> pprPanic "tcIfaceInst" (ppr n $$ ppr tenv) + Just tything -> return tything + {- ************************************************************************ * * diff --git a/compiler/typecheck/TcBackpack.hs b/compiler/typecheck/TcBackpack.hs index 00e38249ea..5c61871155 100644 --- a/compiler/typecheck/TcBackpack.hs +++ b/compiler/typecheck/TcBackpack.hs @@ -135,6 +135,8 @@ checkHsigIface tcg_env gr sig_iface dfun_names = map getName sig_insts check_export name -- Skip instances, we'll check them later + -- TODO: Actually this should never happen, because DFuns are + -- never exported... | name `elem` dfun_names = return () -- See if we can find the type directly in the hsig ModDetails -- TODO: need to special case wired in names @@ -559,23 +561,23 @@ mergeSignatures hsmod lcl_iface0 = do tcg_env <- (\x -> foldM x tcg_env infos) $ \tcg_env (iface, details) -> do - -- For every TyThing in the type environment, compare it for - -- compatibility with the merged environment, but skip - -- DFunIds and implicit TyThings. - let check_ty sig_thing - -- We'll check these with the parent - | isImplicitTyThing sig_thing - = return () - -- These aren't in the type environment; checked - -- when merging instances - | AnId id <- sig_thing - , isDFunId id - = return () - | Just thing <- lookupTypeEnv type_env (getName sig_thing) - = checkHsigDeclM iface sig_thing thing + let check_export name + | Just sig_thing <- lookupTypeEnv (md_types details) name + = case lookupTypeEnv type_env (getName sig_thing) of + Just thing -> checkHsigDeclM iface sig_thing thing + Nothing -> panic "mergeSignatures: check_export" + -- Oops! We're looking for this export but it's + -- not actually in the type environment of the signature's + -- ModDetails. + -- + -- NB: This case happens because the we're iterating + -- over the union of all exports, so some interfaces + -- won't have everything. Note that md_exports is nonsense + -- (it's the same as exports); maybe we should fix this + -- eventually. | otherwise - = panic "mergeSignatures check_ty" - mapM_ check_ty (typeEnvElts (md_types details)) + = return () + mapM_ check_export (map availName exports) -- Note [Signature merging instances] -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/compiler/typecheck/TcRnDriver.hs b/compiler/typecheck/TcRnDriver.hs index 4c44eecfd9..aac872a0ec 100644 --- a/compiler/typecheck/TcRnDriver.hs +++ b/compiler/typecheck/TcRnDriver.hs @@ -1066,6 +1066,8 @@ checkBootTyCon is_boot tc1 tc2 = ASSERT(tc1 == tc2) let eqFamFlav OpenSynFamilyTyCon OpenSynFamilyTyCon = True eqFamFlav (DataFamilyTyCon {}) (DataFamilyTyCon {}) = True + -- This case only happens for hsig merging: + eqFamFlav AbstractClosedSynFamilyTyCon AbstractClosedSynFamilyTyCon = True eqFamFlav AbstractClosedSynFamilyTyCon (ClosedSynFamilyTyCon {}) = True eqFamFlav (ClosedSynFamilyTyCon {}) AbstractClosedSynFamilyTyCon = True eqFamFlav (ClosedSynFamilyTyCon ax1) (ClosedSynFamilyTyCon ax2) @@ -1077,8 +1079,11 @@ checkBootTyCon is_boot tc1 tc2 in -- check equality of roles, family flavours and injectivity annotations check (roles1 == roles2) roles_msg `andThenCheck` - check (eqFamFlav fam_flav1 fam_flav2) empty `andThenCheck` - check (injInfo1 == injInfo2) empty + check (eqFamFlav fam_flav1 fam_flav2) + (ifPprDebug $ + text "Family flavours" <+> ppr fam_flav1 <+> text "and" <+> ppr fam_flav2 <+> + text "do not match") `andThenCheck` + check (injInfo1 == injInfo2) (text "Injectivities do not match") | isAlgTyCon tc1 && isAlgTyCon tc2 , Just env <- eqVarBndrs emptyRnEnv2 (tyConTyVars tc1) (tyConTyVars tc2) diff --git a/compiler/typecheck/TcRnMonad.hs b/compiler/typecheck/TcRnMonad.hs index 8c117f0936..817989e5eb 100644 --- a/compiler/typecheck/TcRnMonad.hs +++ b/compiler/typecheck/TcRnMonad.hs @@ -124,6 +124,7 @@ module TcRnMonad( failIfM, forkM_maybe, forkM, + setImplicitEnvM, withException, @@ -1670,6 +1671,7 @@ mkIfLclEnv mod loc boot if_loc = loc, if_boot = boot, if_nsubst = Nothing, + if_implicits_env = Nothing, if_tv_env = emptyFsEnv, if_id_env = emptyFsEnv } @@ -1800,6 +1802,9 @@ forkM doc thing_inside -- pprPanic "forkM" doc Just r -> r) } +setImplicitEnvM :: TypeEnv -> IfL a -> IfL a +setImplicitEnvM tenv m = updLclEnv (\lcl -> lcl { if_implicits_env = Just tenv }) m + {- Note [Masking exceptions in forkM_maybe] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/compiler/typecheck/TcRnTypes.hs b/compiler/typecheck/TcRnTypes.hs index 6d902b32e0..c938adffd4 100644 --- a/compiler/typecheck/TcRnTypes.hs +++ b/compiler/typecheck/TcRnTypes.hs @@ -321,6 +321,13 @@ data IfLclEnv if_nsubst :: Maybe NameShape, + -- This field is used to make sure "implicit" declarations + -- (anything that cannot be exported in mi_exports) get + -- wired up correctly in typecheckIfacesForMerging. Most + -- of the time it's @Nothing@. See Note [The implicit TypeEnv] + -- in TcIface. + if_implicits_env :: Maybe TypeEnv, + if_tv_env :: FastStringEnv TyVar, -- Nested tyvar bindings if_id_env :: FastStringEnv Id -- Nested id binding } diff --git a/compiler/types/TyCon.hs b/compiler/types/TyCon.hs index ec2f5d5a09..36149187c6 100644 --- a/compiler/types/TyCon.hs +++ b/compiler/types/TyCon.hs @@ -997,6 +997,14 @@ data FamTyConFlav -- | Built-in type family used by the TypeNats solver | BuiltInSynFamTyCon BuiltInSynFamily +instance Outputable FamTyConFlav where + ppr (DataFamilyTyCon n) = text "data family" <+> ppr n + ppr OpenSynFamilyTyCon = text "open type family" + ppr (ClosedSynFamilyTyCon Nothing) = text "closed type family" + ppr (ClosedSynFamilyTyCon (Just coax)) = text "closed type family" <+> ppr coax + ppr AbstractClosedSynFamilyTyCon = text "abstract closed type family" + ppr (BuiltInSynFamTyCon _) = text "built-in type family" + {- Note [Closed type families] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * In an open type family you can add new instances later. This is the diff --git a/testsuite/tests/backpack/should_compile/all.T b/testsuite/tests/backpack/should_compile/all.T index 3525a8521f..33d0357988 100644 --- a/testsuite/tests/backpack/should_compile/all.T +++ b/testsuite/tests/backpack/should_compile/all.T @@ -39,3 +39,5 @@ test('bkp44', normal, backpack_compile, ['']) test('bkp45', normal, backpack_compile, ['']) test('bkp46', normal, backpack_compile, ['']) test('bkp47', normal, backpack_compile, ['']) +test('bkp48', normal, backpack_compile, ['']) +test('bkp49', normal, backpack_compile, ['']) diff --git a/testsuite/tests/backpack/should_compile/bkp48.bkp b/testsuite/tests/backpack/should_compile/bkp48.bkp new file mode 100644 index 0000000000..d48d0359d2 --- /dev/null +++ b/testsuite/tests/backpack/should_compile/bkp48.bkp @@ -0,0 +1,23 @@ +{-# LANGUAGE TypeFamilies #-} +unit p where + signature A where + type family K a where .. + +unit q where + signature A where + type family K a where + K a = Int + +unit r where + dependency p[A=<A>] + dependency q[A=<A>] + +unit i where + module A where + type family K a where + K a = Int + +unit m where + dependency r[A=i:A] + dependency p[A=i:A] + dependency q[A=i:A] diff --git a/testsuite/tests/backpack/should_compile/bkp48.stderr b/testsuite/tests/backpack/should_compile/bkp48.stderr new file mode 100644 index 0000000000..ae6c7fc575 --- /dev/null +++ b/testsuite/tests/backpack/should_compile/bkp48.stderr @@ -0,0 +1,22 @@ +[1 of 5] Processing p + [1 of 1] Compiling A[sig] ( p/A.hsig, nothing ) +[2 of 5] Processing q + [1 of 1] Compiling A[sig] ( q/A.hsig, nothing ) +[3 of 5] Processing r + [1 of 1] Compiling A[sig] ( r/A.hsig, nothing ) +[4 of 5] Processing i + Instantiating i + [1 of 1] Compiling A ( i/A.hs, bkp48.out/i/A.o ) +[5 of 5] Processing m + Instantiating m + [1 of 3] Including r[A=i:A] + Instantiating r[A=i:A] + [1 of 2] Including p[A=i:A] + Instantiating p[A=i:A] + [1 of 1] Compiling A[sig] ( p/A.hsig, bkp48.out/p/p-CtJxD03mJqIIVJzOga8l4X/A.o ) + [2 of 2] Including q[A=i:A] + Instantiating q[A=i:A] + [1 of 1] Compiling A[sig] ( q/A.hsig, bkp48.out/q/q-CtJxD03mJqIIVJzOga8l4X/A.o ) + [1 of 1] Compiling A[sig] ( r/A.hsig, bkp48.out/r/r-CtJxD03mJqIIVJzOga8l4X/A.o ) + [2 of 3] Including p[A=i:A] + [3 of 3] Including q[A=i:A] diff --git a/testsuite/tests/backpack/should_compile/bkp49.bkp b/testsuite/tests/backpack/should_compile/bkp49.bkp new file mode 100644 index 0000000000..b8f6e0097e --- /dev/null +++ b/testsuite/tests/backpack/should_compile/bkp49.bkp @@ -0,0 +1,7 @@ +unit p where + signature A where + data T + instance Eq T +unit q where + dependency p[A=<A>] + signature A (T) where diff --git a/testsuite/tests/backpack/should_compile/bkp49.stderr b/testsuite/tests/backpack/should_compile/bkp49.stderr new file mode 100644 index 0000000000..d8f64f0657 --- /dev/null +++ b/testsuite/tests/backpack/should_compile/bkp49.stderr @@ -0,0 +1,4 @@ +[1 of 2] Processing p + [1 of 1] Compiling A[sig] ( p/A.hsig, nothing ) +[2 of 2] Processing q + [1 of 1] Compiling A[sig] ( q/A.hsig, nothing ) diff --git a/testsuite/tests/backpack/should_fail/all.T b/testsuite/tests/backpack/should_fail/all.T index c24fa25f3b..ff171d38f6 100644 --- a/testsuite/tests/backpack/should_fail/all.T +++ b/testsuite/tests/backpack/should_fail/all.T @@ -37,3 +37,4 @@ test('bkpfail38', normal, backpack_compile_fail, ['']) test('bkpfail39', expect_broken(13068), backpack_compile_fail, ['']) test('bkpfail40', normal, backpack_compile_fail, ['']) test('bkpfail41', normal, backpack_compile_fail, ['']) +test('bkpfail42', normal, backpack_compile_fail, ['']) diff --git a/testsuite/tests/backpack/should_fail/bkpfail42.bkp b/testsuite/tests/backpack/should_fail/bkpfail42.bkp new file mode 100644 index 0000000000..8face3f3be --- /dev/null +++ b/testsuite/tests/backpack/should_fail/bkpfail42.bkp @@ -0,0 +1,10 @@ +{-# LANGUAGE TypeFamilies #-} +unit p where + signature A where + type family F a where + F a = Bool +unit q where + dependency p[A=<A>] + signature A where + type family F a where + F a = Int diff --git a/testsuite/tests/backpack/should_fail/bkpfail42.stderr b/testsuite/tests/backpack/should_fail/bkpfail42.stderr new file mode 100644 index 0000000000..734832ff4b --- /dev/null +++ b/testsuite/tests/backpack/should_fail/bkpfail42.stderr @@ -0,0 +1,12 @@ +[1 of 2] Processing p + [1 of 1] Compiling A[sig] ( p/A.hsig, nothing ) +[2 of 2] Processing q + [1 of 1] Compiling A[sig] ( q/A.hsig, nothing ) + +bkpfail42.bkp:9:9: error: + Type constructor âFâ has conflicting definitions in the module + and its hsig file + Main module: type family F a :: * + where [a] F a = GHC.Types.Int + Hsig file: type family F a :: * + where [a] F a = GHC.Types.Bool |