Vladislav Zavialov pushed to branch wip/int-index/enforce-namespaces at Glasgow Haskell Compiler / GHC
Commits:
-
b313d5f4
by Vladislav Zavialov at 2025-05-08T01:34:50+03:00
20 changed files:
- compiler/GHC/Rename/Names.hs
- compiler/GHC/Tc/Errors/Ppr.hs
- compiler/GHC/Tc/Errors/Types.hs
- + testsuite/tests/rename/should_compile/T25983a.hs
- testsuite/tests/rename/should_compile/T25983.stderr → testsuite/tests/rename/should_compile/T25983a.stderr
- + testsuite/tests/rename/should_compile/T25983b.hs
- + testsuite/tests/rename/should_compile/T25983b.stderr
- + testsuite/tests/rename/should_compile/T25983c.hs
- + testsuite/tests/rename/should_compile/T25983c.stderr
- testsuite/tests/rename/should_compile/T25983.hs → testsuite/tests/rename/should_compile/T25983d.hs
- + testsuite/tests/rename/should_compile/T25983d.stderr
- + testsuite/tests/rename/should_compile/T25983e.hs
- + testsuite/tests/rename/should_compile/T25983e.stderr
- + testsuite/tests/rename/should_compile/T25983f.hs
- + testsuite/tests/rename/should_compile/T25983f.stderr
- + testsuite/tests/rename/should_compile/T25983g.hs
- + testsuite/tests/rename/should_compile/T25983g.stderr
- testsuite/tests/rename/should_compile/T25984a.stderr
- testsuite/tests/rename/should_compile/all.T
- testsuite/tests/rename/should_fail/T9006.stderr
Changes:
... | ... | @@ -1268,7 +1268,7 @@ filterImports hsc_env iface decl_spec (Just (want_hiding, L l import_items)) |
1268 | 1268 | warning_msg (BadImportW ie sub) = do
|
1269 | 1269 | -- 'BadImportW' is only constructed below in 'bad_import_w', in
|
1270 | 1270 | -- the 'EverythingBut' case, so here we assume a 'hiding' clause.
|
1271 | - (reason : _) <- badImportItemErr iface decl_spec ie sub all_avails
|
|
1271 | + (reason :| _) <- badImportItemErr iface decl_spec ie sub all_avails
|
|
1272 | 1272 | pure (TcRnDodgyImports (DodgyImportsHiding reason))
|
1273 | 1273 | warning_msg (DeprecatedExport n w) =
|
1274 | 1274 | pure $ TcRnPragmaWarning
|
... | ... | @@ -1281,14 +1281,14 @@ filterImports hsc_env iface decl_spec (Just (want_hiding, L l import_items)) |
1281 | 1281 | run_lookup def m = case m of
|
1282 | 1282 | Failed err -> do
|
1283 | 1283 | msgs <- lookup_err_msgs err
|
1284 | - mapM_ addErr [TcRnImportLookup msg | msg <- msgs]
|
|
1284 | + forM_ msgs $ \msg -> addErr (TcRnImportLookup msg)
|
|
1285 | 1285 | return def
|
1286 | 1286 | Succeeded a -> return a
|
1287 | 1287 | |
1288 | 1288 | lookup_err_msgs err = case err of
|
1289 | 1289 | BadImport ie sub -> badImportItemErr iface decl_spec ie sub all_avails
|
1290 | - IllegalImport -> pure [ImportLookupIllegal]
|
|
1291 | - QualImportError rdr -> pure [ImportLookupQualified rdr]
|
|
1290 | + IllegalImport -> pure $ NE.singleton ImportLookupIllegal
|
|
1291 | + QualImportError rdr -> pure $ NE.singleton (ImportLookupQualified rdr)
|
|
1292 | 1292 | |
1293 | 1293 | -- For each import item, we convert its RdrNames to Names,
|
1294 | 1294 | -- and at the same time compute all the GlobalRdrElt corresponding
|
... | ... | @@ -1642,7 +1642,7 @@ lookupChildren :: [GlobalRdrElt] |
1642 | 1642 | -> ( [LookupChildError] -- The ones for which the lookup failed
|
1643 | 1643 | , [LocatedA GlobalRdrElt] )
|
1644 | 1644 | -- (lookupChildren all_kids rdr_items) maps each rdr_item to its
|
1645 | --- corresponding Name all_kids, if the former exists
|
|
1645 | +-- corresponding Name in all_kids, if the former exists
|
|
1646 | 1646 | -- The matching is done by FastString, not OccName, so that
|
1647 | 1647 | -- Cls( meth, AssocTy )
|
1648 | 1648 | -- will correctly find AssocTy among the all_kids of Cls, even though
|
... | ... | @@ -1652,20 +1652,34 @@ lookupChildren all_kids rdr_items = (fails, successes) |
1652 | 1652 | where
|
1653 | 1653 | mb_xs = map do_one rdr_items
|
1654 | 1654 | fails = [ err | Failed err <- mb_xs ]
|
1655 | - successes = [ ok | Succeeded oks <- mb_xs, ok <- oks ]
|
|
1655 | + successes = [ ok | Succeeded oks <- mb_xs, ok <- NE.toList oks ]
|
|
1656 | 1656 | |
1657 | - do_one :: LIEWrappedName GhcPs -> MaybeErr LookupChildError [LocatedA GlobalRdrElt]
|
|
1657 | + do_one :: LIEWrappedName GhcPs -> MaybeErr LookupChildError (NonEmpty (LocatedA GlobalRdrElt))
|
|
1658 | 1658 | do_one item@(L l r) =
|
1659 | 1659 | case r of
|
1660 | - IEName{} | notNull val_gs -> Succeeded [L l g | g <- val_gs]
|
|
1661 | - IEName{} | notNull typ_gs -> Succeeded [L l g | g <- typ_gs]
|
|
1662 | - IEType{} | notNull typ_gs -> Succeeded [L l g | g <- typ_gs]
|
|
1663 | - IEType{} | (g:_) <- val_gs -> Failed $ LookupChildNonType item g
|
|
1664 | - _ -> Failed $ LookupChildNotFound item
|
|
1660 | + IEName{}
|
|
1661 | + -- IEName (unadorned name) places no restriction on the namespace of
|
|
1662 | + -- the imported entity, so we look in both `val_gres` and `typ_gres`.
|
|
1663 | + -- In case of conflict (punning), the value namespace takes priority.
|
|
1664 | + -- See Note [Prioritise the value namespace in subordinate import lists]
|
|
1665 | + | (gre:gres) <- val_gres -> Succeeded $ fmap (L l) (gre:|gres)
|
|
1666 | + | (gre:gres) <- typ_gres -> Succeeded $ fmap (L l) (gre:|gres)
|
|
1667 | + | otherwise -> Failed $ LookupChildNotFound item
|
|
1668 | + |
|
1669 | + IEType{}
|
|
1670 | + -- IEType ('type' namespace specifier) restricts the lookup to the
|
|
1671 | + -- type namespace, i.e. to `typ_gres`. In case of failure, we check
|
|
1672 | + -- `val_gres` to produce a more helpful error message.
|
|
1673 | + | (gre:gres) <- typ_gres -> Succeeded $ fmap (L l) (gre:|gres)
|
|
1674 | + | (gre:_) <- val_gres -> Failed $ LookupChildNonType item gre
|
|
1675 | + | otherwise -> Failed $ LookupChildNotFound item
|
|
1676 | + |
|
1677 | + IEPattern{} -> panic "lookupChildren: IEPattern" -- Never happens (invalid syntax)
|
|
1678 | + IEDefault{} -> panic "lookupChildren: IEDefault" -- Never happens (invalid syntax)
|
|
1665 | 1679 | where
|
1666 | 1680 | fs = (occNameFS . rdrNameOcc . ieWrappedName) r
|
1667 | - gs = fromMaybe [] (lookupFsEnv kid_env fs)
|
|
1668 | - (val_gs, typ_gs) = partition (isValNameSpace . greNameSpace) gs
|
|
1681 | + gres = fromMaybe [] (lookupFsEnv kid_env fs)
|
|
1682 | + (val_gres, typ_gres) = partition (isValNameSpace . greNameSpace) gres
|
|
1669 | 1683 | |
1670 | 1684 | -- See Note [Children for duplicate record fields]
|
1671 | 1685 | kid_env :: FastStringEnv [GlobalRdrElt]
|
... | ... | @@ -1673,6 +1687,38 @@ lookupChildren all_kids rdr_items = (fails, successes) |
1673 | 1687 | [(occNameFS (occName x), [x]) | x <- all_kids]
|
1674 | 1688 | |
1675 | 1689 | |
1690 | +{- Note [Prioritise the value namespace in subordinate import lists]
|
|
1691 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
1692 | +Consider this program that defines a class that has both an associated type
|
|
1693 | +named (#) and a method named (#)
|
|
1694 | + |
|
1695 | + module M_assoc where
|
|
1696 | + class C a b where
|
|
1697 | + type a # b
|
|
1698 | + (#) :: a -> b -> ()
|
|
1699 | + module N_assoc where
|
|
1700 | + import M_assoc( C((#)) )
|
|
1701 | + |
|
1702 | +In the import declaration, when we see the unadorned name (#) in the subordinate
|
|
1703 | +import list of C, which children should we bring into scope? Our options are:
|
|
1704 | + |
|
1705 | + a) only the method (#)
|
|
1706 | + b) only the associated type (#)
|
|
1707 | + c) both the method and the associated type
|
|
1708 | + |
|
1709 | +To follow the precedent established by top-level items, we go with option (a).
|
|
1710 | +Indeed, consider a slightly different program
|
|
1711 | + |
|
1712 | + module M_top where
|
|
1713 | + type family a # b
|
|
1714 | + a # b = ()
|
|
1715 | + module N_top where
|
|
1716 | + import M_top( (#) )
|
|
1717 | + |
|
1718 | +Here the import brings only the function (#) into scope, and one has to say
|
|
1719 | +`type (#)` to get the type family.
|
|
1720 | +-}
|
|
1721 | + |
|
1676 | 1722 | -------------------------------
|
1677 | 1723 | |
1678 | 1724 | {-
|
... | ... | @@ -2331,27 +2377,31 @@ badImportItemErr |
2331 | 2377 | :: ModIface -> ImpDeclSpec -> IE GhcPs
|
2332 | 2378 | -> IsSubordinateError
|
2333 | 2379 | -> [AvailInfo]
|
2334 | - -> TcRn [ImportLookupReason] -- non-empty
|
|
2380 | + -> TcRn (NonEmpty ImportLookupReason)
|
|
2335 | 2381 | badImportItemErr iface decl_spec ie sub avails = do
|
2336 | 2382 | patsyns_enabled <- xoptM LangExt.PatternSynonyms
|
2337 | 2383 | expl_ns_enabled <- xoptM LangExt.ExplicitNamespaces
|
2384 | + let import_lookup_bad :: BadImportKind -> ImportLookupReason
|
|
2385 | + import_lookup_bad k = ImportLookupBad k iface decl_spec ie patsyns_enabled
|
|
2338 | 2386 | dflags <- getDynFlags
|
2339 | 2387 | hsc_env <- getTopEnv
|
2340 | 2388 | let rdr_env = mkGlobalRdrEnv
|
2341 | 2389 | $ gresFromAvails hsc_env (Just imp_spec) all_avails
|
2342 | - pure [ImportLookupBad k iface decl_spec ie patsyns_enabled | k <- importErrorKind dflags rdr_env expl_ns_enabled ]
|
|
2390 | + pure $ fmap import_lookup_bad (importErrorKind dflags rdr_env expl_ns_enabled)
|
|
2343 | 2391 | where
|
2392 | + importErrorKind :: DynFlags -> GlobalRdrEnv -> Bool -> NonEmpty BadImportKind
|
|
2344 | 2393 | importErrorKind dflags rdr_env expl_ns_enabled
|
2345 | 2394 | | any checkIfTyCon avails = case sub of
|
2346 | - IsNotSubordinate -> [BadImportAvailTyCon expl_ns_enabled]
|
|
2395 | + IsNotSubordinate -> NE.singleton (BadImportAvailTyCon expl_ns_enabled)
|
|
2347 | 2396 | IsSubordinateError { subordinate_err_parent = gre
|
2348 | 2397 | , subordinate_err_unavailable = unavailable
|
2349 | 2398 | , subordinate_err_nontype = nontype }
|
2350 | - -> [BadImportNotExportedSubordinates gre unavailable | notNull unavailable] ++
|
|
2351 | - [BadImportNonTypeSubordinates gre nontype | notNull nontype ]
|
|
2352 | - | any checkIfVarName avails = [BadImportAvailVar]
|
|
2353 | - | Just con <- find checkIfDataCon avails = [BadImportAvailDataCon (availOccName con)]
|
|
2354 | - | otherwise = [BadImportNotExported suggs]
|
|
2399 | + -> NE.fromList $ catMaybes $
|
|
2400 | + [ fmap (BadImportNotExportedSubordinates gre) (NE.nonEmpty unavailable)
|
|
2401 | + , fmap (BadImportNonTypeSubordinates gre) (NE.nonEmpty nontype) ]
|
|
2402 | + | any checkIfVarName avails = NE.singleton BadImportAvailVar
|
|
2403 | + | Just con <- find checkIfDataCon avails = NE.singleton (BadImportAvailDataCon (availOccName con))
|
|
2404 | + | otherwise = NE.singleton (BadImportNotExported suggs)
|
|
2355 | 2405 | where
|
2356 | 2406 | suggs = similar_suggs ++ fieldSelectorSuggestions rdr_env rdr
|
2357 | 2407 | what_look = case sub of
|
... | ... | @@ -119,6 +119,7 @@ import GHC.Data.List.SetOps ( nubOrdBy ) |
119 | 119 | import GHC.Data.Maybe
|
120 | 120 | import GHC.Data.Pair
|
121 | 121 | import GHC.Settings.Constants (mAX_TUPLE_SIZE, mAX_CTUPLE_SIZE)
|
122 | +import GHC.Utils.Lexeme
|
|
122 | 123 | import GHC.Utils.Misc
|
123 | 124 | import GHC.Utils.Outputable
|
124 | 125 | import GHC.Utils.Panic
|
... | ... | @@ -5886,24 +5887,35 @@ pprImportLookup = \case |
5886 | 5887 | where
|
5887 | 5888 | tycon_occ = rdrNameOcc $ ieName ie
|
5888 | 5889 | tycon = parenSymOcc tycon_occ (ppr tycon_occ)
|
5889 | - BadImportNotExportedSubordinates gre unavailable ->
|
|
5890 | + BadImportNotExportedSubordinates gre unavailable1 ->
|
|
5890 | 5891 | withContext
|
5891 | 5892 | [ what <+> text "called" <+> parent_name <+> text "is exported, but it does not export"
|
5892 | 5893 | , text "any" <+> what_children <+> text "called" <+> unavailable_names <> dot
|
5893 | 5894 | ]
|
5894 | 5895 | where
|
5896 | + unavailable = NE.toList unavailable1
|
|
5895 | 5897 | parent_name = (quotes . pprPrefixOcc . nameOccName . gre_name) gre
|
5896 | 5898 | unavailable_names = pprWithCommas (quotes . ppr) unavailable
|
5897 | - (what, what_children) = case greInfo gre of
|
|
5898 | - IAmTyCon ClassFlavour -> (text "a class", text "class methods or associated types")
|
|
5899 | - IAmTyCon _ -> (text "a data type", text "constructors or record fields")
|
|
5900 | - _ -> (text "an item", text "children")
|
|
5901 | - BadImportNonTypeSubordinates gre nontype ->
|
|
5899 | + any_names p = any (p . unpackFS) unavailable
|
|
5900 | + what = case greInfo gre of
|
|
5901 | + IAmTyCon ClassFlavour -> text "a class"
|
|
5902 | + IAmTyCon _ -> text "a data type"
|
|
5903 | + _ -> text "an item"
|
|
5904 | + what_children = unquotedListWith "or" $ case greInfo gre of
|
|
5905 | + IAmTyCon ClassFlavour ->
|
|
5906 | + [text "class methods" | any_names okVarOcc ] ++
|
|
5907 | + [text "associated types" | any_names okTcOcc ]
|
|
5908 | + IAmTyCon _ ->
|
|
5909 | + [text "constructors" | any_names okConOcc ] ++
|
|
5910 | + [text "record fields" | any_names okVarOcc ]
|
|
5911 | + _ -> [text "children"]
|
|
5912 | + BadImportNonTypeSubordinates gre nontype1 ->
|
|
5902 | 5913 | withContext
|
5903 | 5914 | [ what <+> text "called" <+> parent_name <+> text "is exported,"
|
5904 | 5915 | , sep [ text "but its subordinate" <+> "item" <> plural nontype <+> nontype_names
|
5905 | 5916 | , isOrAre nontype <+> "not in the type namespace." ] ]
|
5906 | 5917 | where
|
5918 | + nontype = NE.toList nontype1
|
|
5907 | 5919 | parent_name = (quotes . pprPrefixOcc . nameOccName . gre_name) gre
|
5908 | 5920 | nontype_names = pprWithCommas (quotes . pprPrefixOcc . nameOccName . gre_name) nontype
|
5909 | 5921 | what = case greInfo gre of
|
... | ... | @@ -5837,9 +5837,9 @@ data BadImportKind |
5837 | 5837 | -- @import Data.Maybe (Just)@ instead of @import Data.Maybe (Maybe(Just))@
|
5838 | 5838 | | BadImportAvailDataCon OccName
|
5839 | 5839 | -- | The parent does not export the given children.
|
5840 | - | BadImportNotExportedSubordinates !GlobalRdrElt [FastString]
|
|
5840 | + | BadImportNotExportedSubordinates !GlobalRdrElt (NonEmpty FastString)
|
|
5841 | 5841 | -- | Incorrect @type@ keyword when importing subordinates that aren't types.
|
5842 | - | BadImportNonTypeSubordinates !GlobalRdrElt [GlobalRdrElt]
|
|
5842 | + | BadImportNonTypeSubordinates !GlobalRdrElt (NonEmpty GlobalRdrElt)
|
|
5843 | 5843 | -- | Incorrect @type@ keyword when importing something which isn't a type.
|
5844 | 5844 | | BadImportAvailVar
|
5845 | 5845 | deriving Generic
|
1 | +{-# OPTIONS -Wdodgy-imports #-}
|
|
2 | + |
|
3 | +module T25983a where
|
|
4 | + |
|
5 | +import Prelude hiding (Bool(X,Y)) |
1 | -T25983.hs:5:24: warning: [GHC-10237] [-Wdodgy-imports (in -Wextra)]
|
|
1 | +T25983a.hs:5:24: warning: [GHC-10237] [-Wdodgy-imports (in -Wextra)]
|
|
2 | 2 | In the import of ‘Prelude’:
|
3 | 3 | a data type called ‘Bool’ is exported, but it does not export
|
4 | - any constructors or record fields called ‘X’.
|
|
4 | + any constructors called ‘X’, ‘Y’.
|
|
5 | 5 |
1 | +{-# OPTIONS -Wdodgy-imports #-}
|
|
2 | + |
|
3 | +module T25983b where
|
|
4 | + |
|
5 | +import Prelude hiding (Bool(fld1,fld2)) |
1 | +T25983b.hs:5:24: warning: [GHC-10237] [-Wdodgy-imports (in -Wextra)]
|
|
2 | + In the import of ‘Prelude’:
|
|
3 | + a data type called ‘Bool’ is exported, but it does not export
|
|
4 | + any record fields called ‘fld1’, ‘fld2’.
|
|
5 | + |
1 | +{-# OPTIONS -Wdodgy-imports #-}
|
|
2 | + |
|
3 | +module T25983c where
|
|
4 | + |
|
5 | +import Prelude hiding (Bool(X,Y,fld1,fld2)) |
1 | +T25983c.hs:5:24: warning: [GHC-10237] [-Wdodgy-imports (in -Wextra)]
|
|
2 | + In the import of ‘Prelude’:
|
|
3 | + a data type called ‘Bool’ is exported, but it does not export
|
|
4 | + any constructors or record fields called ‘X’, ‘Y’, ‘fld1’, ‘fld2’.
|
|
5 | + |
1 | 1 | {-# OPTIONS -Wdodgy-imports #-}
|
2 | 2 | |
3 | -module T25983 where
|
|
3 | +module T25983d where
|
|
4 | 4 | |
5 | -import Prelude hiding (Bool(X)) |
|
5 | +import Prelude hiding (Num((#))) |
1 | +T25983d.hs:5:24: warning: [GHC-10237] [-Wdodgy-imports (in -Wextra)]
|
|
2 | + In the import of ‘Prelude’:
|
|
3 | + a class called ‘Num’ is exported, but it does not export
|
|
4 | + any class methods or associated types called ‘#’.
|
|
5 | + |
1 | +{-# OPTIONS -Wdodgy-imports #-}
|
|
2 | + |
|
3 | +module T25983e where
|
|
4 | + |
|
5 | +import Prelude hiding (Num(f,g)) |
1 | +T25983e.hs:5:24: warning: [GHC-10237] [-Wdodgy-imports (in -Wextra)]
|
|
2 | + In the import of ‘Prelude’:
|
|
3 | + a class called ‘Num’ is exported, but it does not export
|
|
4 | + any class methods called ‘f’, ‘g’.
|
|
5 | + |
1 | +{-# OPTIONS -Wdodgy-imports #-}
|
|
2 | + |
|
3 | +module T25983f where
|
|
4 | + |
|
5 | +import Prelude hiding (Num(F,G)) |
1 | +T25983f.hs:5:24: warning: [GHC-10237] [-Wdodgy-imports (in -Wextra)]
|
|
2 | + In the import of ‘Prelude’:
|
|
3 | + a class called ‘Num’ is exported, but it does not export
|
|
4 | + any associated types called ‘F’, ‘G’.
|
|
5 | + |
1 | +{-# OPTIONS -Wdodgy-imports #-}
|
|
2 | + |
|
3 | +module T25983g where
|
|
4 | + |
|
5 | +import Prelude hiding (Num(F,G,f,g)) |
1 | +T25983g.hs:5:24: warning: [GHC-10237] [-Wdodgy-imports (in -Wextra)]
|
|
2 | + In the import of ‘Prelude’:
|
|
3 | + a class called ‘Num’ is exported, but it does not export
|
|
4 | + any class methods or associated types called ‘F’, ‘G’, ‘f’, ‘g’.
|
|
5 | + |
1 | 1 | T25984a.hs:5:31: warning: [GHC-10237] [-Wdodgy-imports (in -Wextra)]
|
2 | 2 | In the import of ‘T25984a_helper’:
|
3 | 3 | a data type called ‘H’ is exported, but it does not export
|
4 | - any constructors or record fields called ‘C’.
|
|
4 | + any constructors called ‘C’.
|
|
5 | 5 |
... | ... | @@ -233,5 +233,11 @@ test('T25182', [extra_files(['ReExportTuples.hs'])], multimod_compile, ['T25182' |
233 | 233 | test('T22581c', [extra_files(['T22581c_helper.hs'])], multimod_compile, ['T22581c', '-v0'])
|
234 | 234 | test('T22581d', combined_output, ghci_script, ['T22581d.script'])
|
235 | 235 | test('T25991a', [extra_files(['T25991a_helper.hs'])], multimod_compile, ['T25991a', '-v0'])
|
236 | -test('T25983', normal, compile, [''])
|
|
236 | +test('T25983a', normal, compile, [''])
|
|
237 | +test('T25983b', normal, compile, [''])
|
|
238 | +test('T25983c', normal, compile, [''])
|
|
239 | +test('T25983d', normal, compile, [''])
|
|
240 | +test('T25983e', normal, compile, [''])
|
|
241 | +test('T25983f', normal, compile, [''])
|
|
242 | +test('T25983g', normal, compile, [''])
|
|
237 | 243 | test('T25984a', [extra_files(['T25984a_helper.hs'])], multimod_compile, ['T25984a', '-v0']) |
1 | 1 | T9006.hs:3:16: error: [GHC-10237]
|
2 | 2 | In the import of ‘T9006a’:
|
3 | 3 | a data type called ‘T’ is exported, but it does not export
|
4 | - any constructors or record fields called ‘T’.
|
|
4 | + any constructors called ‘T’.
|
|
5 | 5 |