
Vladislav Zavialov pushed to branch wip/int-index/data-namespace-specifier at Glasgow Haskell Compiler / GHC Commits: 75581dc4 by Vladislav Zavialov at 2025-05-12T16:19:44+03:00 Rename ieNameWrapper to ieLIEWrappedName - - - - - 5e1622f6 by Vladislav Zavialov at 2025-05-12T18:32:40+03:00 Comments for the BadImportAvailTyCon case - - - - - d193cd14 by Vladislav Zavialov at 2025-05-15T15:39:44+03:00 Documentation edits - - - - - bbd4f1e2 by Vladislav Zavialov at 2025-05-16T01:16:52+03:00 Rewrite import suggestions - - - - - 14 changed files: - compiler/GHC/Hs/ImpExp.hs - compiler/GHC/Tc/Errors/Ppr.hs - compiler/GHC/Tc/Errors/Types.hs - compiler/GHC/Types/Hint.hs - compiler/GHC/Types/Hint/Ppr.hs - docs/users_guide/exts/explicit_namespaces.rst - testsuite/tests/rename/should_compile/T22581d.stdout - testsuite/tests/rename/should_compile/T25899d.stdout - testsuite/tests/rename/should_fail/T22581a.stderr - testsuite/tests/rename/should_fail/T22581b.stderr - + testsuite/tests/rename/should_fail/T25899f.hs - + testsuite/tests/rename/should_fail/T25899f.stderr - + testsuite/tests/rename/should_fail/T25899f_helper.hs - testsuite/tests/rename/should_fail/all.T Changes: ===================================== compiler/GHC/Hs/ImpExp.hs ===================================== @@ -255,15 +255,15 @@ type instance XXIE (GhcPass _) = DataConCantHappen type instance Anno (LocatedA (IE (GhcPass p))) = SrcSpanAnnA -ieNameWrapper :: IE (GhcPass p) -> LIEWrappedName (GhcPass p) -ieNameWrapper (IEVar _ n _) = n -ieNameWrapper (IEThingAbs _ n _) = n -ieNameWrapper (IEThingWith _ n _ _ _) = n -ieNameWrapper (IEThingAll _ n _) = n -ieNameWrapper _ = panic "ieNameWrapper failed pattern match!" +ieLIEWrappedName :: IE (GhcPass p) -> LIEWrappedName (GhcPass p) +ieLIEWrappedName (IEVar _ n _) = n +ieLIEWrappedName (IEThingAbs _ n _) = n +ieLIEWrappedName (IEThingWith _ n _ _ _) = n +ieLIEWrappedName (IEThingAll _ n _) = n +ieLIEWrappedName _ = panic "ieLIEWrappedName failed pattern match!" ieName :: IE (GhcPass p) -> IdP (GhcPass p) -ieName = lieWrappedName . ieNameWrapper +ieName = lieWrappedName . ieLIEWrappedName ieNames :: IE (GhcPass p) -> [IdP (GhcPass p)] ieNames (IEVar _ (L _ n) _) = [ieWrappedName n] ===================================== compiler/GHC/Tc/Errors/Ppr.hs ===================================== @@ -3294,19 +3294,46 @@ instance Diagnostic TcRnMessage where TcRnImportLookup (ImportLookupBad k _ is ie exts) -> let mod_name = moduleName $ is_mod is occ = rdrNameOcc $ ieName ie - could_remove kw = [ImportSuggestion occ $ CouldRemoveImportItemKeyword mod_name kw] + could_change_item item_suggestion = + [useExtensionInOrderTo empty LangExt.ExplicitNamespaces | suggest_ext] ++ + [ ImportSuggestion occ $ + CouldChangeImportItem mod_name item_suggestion ] + where + suggest_ext + | ile_explicit_namespaces exts = False -- extension already on + | otherwise = + case item_suggestion of + -- ImportItemRemove* -> False + ImportItemRemoveType{} -> False + ImportItemRemoveData{} -> False + ImportItemRemovePattern{} -> False + ImportItemRemoveSubordinateType{} -> False + ImportItemRemoveSubordinateData{} -> False + -- ImportItemAdd* -> True + ImportItemAddType{} -> True in case k of - BadImportAvailVar -> could_remove ImportItemUnwantedKeywordType + BadImportAvailVar -> could_change_item ImportItemRemoveType BadImportNotExported suggs -> suggs BadImportAvailTyCon - | isSymOcc occ -> -- type operators always require the 'type' keyword - [useExtensionInOrderTo empty LangExt.ExplicitNamespaces | not (ile_explicit_namespaces exts) ] - ++ [ ImportSuggestion occ $ CouldAddTypeKeyword mod_name ] - | otherwise -> - case unLoc (ieNameWrapper ie) of - IEData{} -> could_remove ImportItemUnwantedKeywordData - IEPattern{} -> could_remove ImportItemUnwantedKeywordPattern - _ -> noHints + -- BadImportAvailTyCon means a name is available in the TcCls namespace + -- but name resolution could not use it. Possible reasons for that: + -- 1. Case (TyOp) `import M ((#))` or `import M (data (#))` + -- The user tried to import a type operator without using the `type` keyword, + -- or using a different keyword. Suggested fix: add 'type'. + -- 2. Case (DataKw) `import M (data T)` + -- The user tried to import a non-operator type constructor, but mistakenly + -- used the `data` keyword, which restricted the lookup to the value namespace. + -- Suggested fix: remove 'data'; no need to add 'type' for non-operators. + -- 3. Case (PatternKw) `import M (pattern T)` + -- Same as the (DataKw) case, mutatis mutandis. + -- Any other case would not have resulted in BadImportAvailTyCon. + | isSymOcc occ -> could_change_item ImportItemAddType -- Case (TyOp) + | otherwise -> -- Non-operator cases + case unLoc (ieLIEWrappedName ie) of + IEData{} -> could_change_item ImportItemRemoveData -- Case (DataKw) + IEPattern{} -> could_change_item ImportItemRemovePattern -- Case (PatternKw) + _ -> panic "diagnosticHints: unexpected BadImportAvailTyCon" + BadImportAvailDataCon par -> [ ImportSuggestion occ $ ImportDataCon { ies_suggest_import_from = Just mod_name @@ -3315,8 +3342,10 @@ instance Diagnostic TcRnMessage where , ies_suggest_data_keyword = ile_explicit_namespaces exts , ies_parent = par } ] BadImportNotExportedSubordinates{} -> noHints - BadImportNonTypeSubordinates{} -> noHints - BadImportNonDataSubordinates{} -> noHints + BadImportNonTypeSubordinates _ nontype1 -> + could_change_item (ImportItemRemoveSubordinateType (nameOccName . greName <$> nontype1)) + BadImportNonDataSubordinates _ nondata1 -> + could_change_item (ImportItemRemoveSubordinateData (nameOccName . greName <$> nondata1)) TcRnImportLookup{} -> noHints TcRnUnusedImport{} ===================================== compiler/GHC/Tc/Errors/Types.hs ===================================== @@ -5841,9 +5841,9 @@ data BadImportKind | BadImportNotExportedSubordinates !GlobalRdrElt (NonEmpty FastString) -- | Incorrect @type@ keyword when importing subordinates that aren't types. | BadImportNonTypeSubordinates !GlobalRdrElt (NonEmpty GlobalRdrElt) - -- | Incorrect @type@ keyword when importing something which isn't a type. - | BadImportNonDataSubordinates !GlobalRdrElt (NonEmpty GlobalRdrElt) -- | Incorrect @data@ keyword when importing something which isn't a term. + | BadImportNonDataSubordinates !GlobalRdrElt (NonEmpty GlobalRdrElt) + -- | Incorrect @type@ keyword when importing something which isn't a type. | BadImportAvailVar deriving Generic ===================================== compiler/GHC/Types/Hint.hs ===================================== @@ -5,7 +5,7 @@ module GHC.Types.Hint ( , AvailableBindings(..) , InstantiationSuggestion(..) , LanguageExtensionHint(..) - , ImportItemUnwantedKeyword(..) + , ImportItemSuggestion(..) , ImportSuggestion(..) , HowInScope(..) , SimilarName(..) @@ -538,10 +538,13 @@ instance Outputable AssumedDerivingStrategy where -- replacing <MyStr> as necessary.) data InstantiationSuggestion = InstantiationSuggestion !ModuleName !Module -data ImportItemUnwantedKeyword = - ImportItemUnwantedKeywordType - | ImportItemUnwantedKeywordData - | ImportItemUnwantedKeywordPattern +data ImportItemSuggestion = + ImportItemRemoveType + | ImportItemRemoveData + | ImportItemRemovePattern + | ImportItemRemoveSubordinateType (NE.NonEmpty OccName) + | ImportItemRemoveSubordinateData (NE.NonEmpty OccName) + | ImportItemAddType -- | Suggest how to fix an import. data ImportSuggestion @@ -549,10 +552,8 @@ data ImportSuggestion = CouldImportFrom (NE.NonEmpty (Module, ImportedModsVal)) -- | Some module exports what we want, but we are explicitly hiding it. | CouldUnhideFrom (NE.NonEmpty (Module, ImportedModsVal)) - -- | The module exports what we want, but it isn't in the requested namespace. - | CouldRemoveImportItemKeyword ModuleName ImportItemUnwantedKeyword - -- | The module exports what we want, but it's a type and we have @ExplicitNamespaces@ on. - | CouldAddTypeKeyword ModuleName + -- | The module exports what we want, but the import item requires modification. + | CouldChangeImportItem ModuleName ImportItemSuggestion -- | Suggest importing a data constructor to bring it into scope | ImportDataCon -- | Where to suggest importing the 'DataCon' from. ===================================== compiler/GHC/Types/Hint/Ppr.hs ===================================== @@ -340,27 +340,39 @@ pprImportSuggestion occ_name (CouldUnhideFrom mods) [ quotes (ppr mod) <+> parens (text "at" <+> ppr (imv_span imv)) | (mod,imv) <- NE.toList mods ]) -pprImportSuggestion occ_name (CouldAddTypeKeyword mod) - = vcat [ text "Add the" <+> quotes (text "type") - <+> text "keyword to the import statement:" - , nest 2 $ text "import" - <+> ppr mod - <+> parens_sp (text "type" <+> pprPrefixOcc occ_name) - ] +pprImportSuggestion occ_name (CouldChangeImportItem mod kw) + = case kw of + ImportItemRemoveType -> remove "type" + ImportItemRemoveData -> remove "data" + ImportItemRemovePattern -> remove "pattern" + ImportItemRemoveSubordinateType nontype1 -> remove_subordinate "type" (NE.toList nontype1) + ImportItemRemoveSubordinateData nondata1 -> remove_subordinate "data" (NE.toList nondata1) + ImportItemAddType -> add "type" where parens_sp d = parens (space <> d <> space) -pprImportSuggestion occ_name (CouldRemoveImportItemKeyword mod kw) - = vcat [ text "Remove the" <+> quotes (text kw_str) - <+> text "keyword from the import statement:" - , nest 2 $ text "import" - <+> ppr mod - <+> parens_sp (pprPrefixOcc occ_name) ] - where - parens_sp d = parens (space <> d <> space) - kw_str = case kw of - ImportItemUnwantedKeywordType -> "type" - ImportItemUnwantedKeywordData -> "data" - ImportItemUnwantedKeywordPattern -> "pattern" + remove kw = + vcat [ text "Remove the" <+> quotes (text kw) + <+> text "keyword from the import statement:" + , nest 2 $ text "import" <+> ppr mod <+> import_list ] + where + import_list = parens_sp (pprPrefixOcc occ_name) + add kw = + vcat [ text "Add the" <+> quotes (text kw) + <+> text "keyword to the import statement:" + , nest 2 $ text "import" <+> ppr mod <+> import_list ] + where + import_list = parens_sp (text kw <+> pprPrefixOcc occ_name) + remove_subordinate kw sub_occs = + vcat [ text "Remove the" <+> quotes (text kw) + <+> text "keyword" <> plural sub_occs + <+> text "from the subordinate import item" <> plural sub_occs <> colon + , nest 2 $ text "import" <+> ppr mod <+> import_list ] + where + parent_item + | isSymOcc occ_name = text "type" <+> pprPrefixOcc occ_name + | otherwise = pprPrefixOcc occ_name + import_list = parens_sp (parent_item <+> sub_import_list) + sub_import_list = parens_sp (hsep (punctuate comma (map pprPrefixOcc sub_occs))) pprImportSuggestion dc_occ (ImportDataCon { ies_suggest_import_from = Nothing , ies_parent = parent_occ} ) = text "Import the data constructor" <+> quotes (ppr dc_occ) <+> ===================================== docs/users_guide/exts/explicit_namespaces.rst ===================================== @@ -1,17 +1,25 @@ .. _explicit-namespaces: Explicit namespaces in import/export -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +------------------------------------ .. extension:: ExplicitNamespaces - :shortdesc: Allow use of the keyword ``type`` to specify the namespace of - entries in imports and exports. + :shortdesc: Allow use of the ``type`` and ``data`` keywords to specify the namespace of + entries in import/export lists and in other contexts. :implied by: :extension:`TypeOperators`, :extension:`TypeFamilies` :since: 7.6.1 :status: Included in :extension:`GHC2024` - Enable use of explicit namespaces in module export lists, patterns, and expressions. + Enable use of explicit namespace specifiers ``type`` and ``data`` + in import declarations, module export lists, fixity declarations, + and warning/deprecation pragmas; as well as the ``type`` namespace + specifier in expressions and patterns. + +The ``type`` keyword in import/export lists +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**Since:** GHC 7.6 In an import or export list, such as :: @@ -51,17 +59,69 @@ import and export lists: The extension :extension:`ExplicitNamespaces` is implied by :extension:`TypeOperators` and (for some reason) by :extension:`TypeFamilies`. -In addition, you can prefix the name of a data constructor in an import or -export list with the keyword ``data``, to allow the import or export of a data -constructor without its parent type constructor (see :ref:`patsyn-impexp`). +The ``data`` keyword in import/export lists +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Furthermore, :extension:`ExplicitNamespaces` permits the use of the ``type`` -keyword in patterns and expressions:: +**Since:** GHC 9.14 - f (type t) x = ... -- in a pattern - r = f (type Integer) 10 -- in an expression +In an import or export list, such as :: -This is used in conjunction with :extension:`RequiredTypeArguments`. + module M( T ) where ... + import N( T ) + ... + +the entity ``T`` refers to a *type constructor*, even if there is also a data +constructor or pattern synonym of the same name. + +For a concrete example, consider the declaration ``data Proxy t = Proxy`` +and the following imports: :: + + import Data.Proxy (Proxy(Proxy)) -- imports both constructors + import Data.Proxy (Proxy(..)) -- imports both constructors + import Data.Proxy (Proxy) -- imports the type constructor only + import Data.Proxy (type Proxy) -- imports the type constructor only + +However, how would one import only the data constructor? There are two options: :: + + import Data.Proxy (data Proxy) -- imports the data constructor only + import Data.Proxy (pattern Proxy) -- imports the data constructor only + +The ``data`` keyword enables the import or export a data constructor without its +parent type constructor. + +The ``pattern`` keyword does the same, with only a few differences: + +* Required compiler versions and flags + + - ``pattern`` is provided by the :extension:`PatternSynonyms` extension and requires GHC ≥7.8 + - ``data`` is enabled by :extension:`ExplicitNamespaces` and requires GHC ≥9.14 + + See :ref:`patsyn-impexp`. + +* Restrictions on use + + - ``pattern`` is restricted to top-level imports of pattern synonyms and data + constructors: :: + + import N (pattern P) -- ok (top-level) + import N (T(pattern P)) -- error (subordinate) + import N (pattern f) -- error (term or field selector) + + - ``data`` is also permitted in subordinate import/export lists, and is + applicable to term declarations (functions and constants) and field + selectors: :: + + import N (data P) -- ok (top-level) + import N (T(data P)) -- ok (subordinate) + import N (data f) -- ok (term or field selector) + +The ``data`` keyword is preferred over ``pattern`` in import/export lists unless +there is a need to support older GHC versions. + +Explicit namespaces in fixity declarations and warning/deprecation pragmas +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**Since:** GHC 9.10 When :extension:`ExplicitNamespaces` is enabled, it is possible to use the ``type`` and ``data`` keywords to specify the namespace of the name used in @@ -79,9 +139,9 @@ type-level and term-level operators: :: Similarly, it can be used in pragmas to deprecate only one name in a namespace: :: - data Solo = MkSolo + data Solo a = MkSolo a - pattern Solo = MkSolo + pattern Solo x = MkSolo x {-# DEPRECATED data Solo "Use `MkSolo` instead" #-} type family Head xs where @@ -94,3 +154,16 @@ Similarly, it can be used in pragmas to deprecate only one name in a namespace: It is considered bad practice to use a fixity signature, ``WARNING`` pragma, or ``DEPRECATED`` pragma for a type-level name without an explicit ``type`` namespace, and doing so will become an error in a future version of GHC. + +The ``type`` keyword in expressions and patterns +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**Since:** GHC 9.10 + +Furthermore, :extension:`ExplicitNamespaces` permits the use of the ``type`` +keyword in patterns and expressions:: + + f (type t) x = ... -- in a pattern + r = f (type Integer) 10 -- in an expression + +This is used in conjunction with :extension:`RequiredTypeArguments`. ===================================== testsuite/tests/rename/should_compile/T22581d.stdout ===================================== @@ -2,4 +2,7 @@ In the import of ‘Data.Functor.Product’: a data type called ‘Product’ is exported, but its subordinate item ‘Pair’ is not in the type namespace. + Suggested fix: + Remove the ‘type’ keyword from the subordinate import item: + import Data.Functor.Product ( Product ( Pair ) ) ===================================== testsuite/tests/rename/should_compile/T25899d.stdout ===================================== @@ -2,6 +2,9 @@ In the import of ‘GHC.Generics’: a class called ‘Generic’ is exported, but its subordinate item ‘Rep’ is not in the data namespace. + Suggested fix: + Remove the ‘data’ keyword from the subordinate import item: + import GHC.Generics ( Generic ( Rep ) ) <interactive>:3:22: error: [GHC-56449] In the import of ‘GHC.Generics’: ===================================== testsuite/tests/rename/should_fail/T22581a.stderr ===================================== @@ -2,4 +2,7 @@ T22581a.hs:5:24: error: [GHC-51433] In the import of ‘T22581a_helper’: a data type called ‘T’ is exported, but its subordinate item ‘MkT’ is not in the type namespace. + Suggested fix: + Remove the ‘type’ keyword from the subordinate import item: + import T22581a_helper ( T ( MkT ) ) ===================================== testsuite/tests/rename/should_fail/T22581b.stderr ===================================== @@ -2,6 +2,9 @@ T22581b.hs:5:24: error: [GHC-51433] In the import of ‘T22581b_helper’: a data type called ‘T’ is exported, but its subordinate item ‘MkT1’ is not in the type namespace. + Suggested fix: + Remove the ‘type’ keyword from the subordinate import item: + import T22581b_helper ( T ( MkT1 ) ) T22581b.hs:5:24: error: [GHC-10237] In the import of ‘T22581b_helper’: ===================================== testsuite/tests/rename/should_fail/T25899f.hs ===================================== @@ -0,0 +1,8 @@ +{-# LANGUAGE ExplicitNamespaces #-} + +module T25899f where + +import T25899f_helper + ( T(type X, Y, type Z) + , type (#)(data F, G, data H) + ) ===================================== testsuite/tests/rename/should_fail/T25899f.stderr ===================================== @@ -0,0 +1,16 @@ +T25899f.hs:6:5: error: [GHC-51433] + In the import of ‘T25899f_helper’: + a data type called ‘T’ is exported, + but its subordinate items ‘X’, ‘Z’ are not in the type namespace. + Suggested fix: + Remove the ‘type’ keywords from the subordinate import items: + import T25899f_helper ( T ( X, Z ) ) + +T25899f.hs:7:5: error: [GHC-46557] + In the import of ‘T25899f_helper’: + a class called ‘(#)’ is exported, + but its subordinate items ‘F’, ‘H’ are not in the data namespace. + Suggested fix: + Remove the ‘data’ keywords from the subordinate import items: + import T25899f_helper ( type (#) ( F, H ) ) + ===================================== testsuite/tests/rename/should_fail/T25899f_helper.hs ===================================== @@ -0,0 +1,10 @@ +{-# LANGUAGE TypeFamilies #-} + +module T25899f_helper where + +data T = X | Y | Z + +class a # b where + type F a b + type G a b + type H a b ===================================== testsuite/tests/rename/should_fail/all.T ===================================== @@ -245,3 +245,4 @@ test('T25991b2', [extra_files(['T25991b_helper.hs'])], multimod_compile_fail, [' test('T25899e1', normal, compile_fail, ['']) test('T25899e2', normal, compile_fail, ['']) test('T25899e3', [extra_files(['T25899e_helper.hs'])], multimod_compile_fail, ['T25899e3', '-v0']) +test('T25899f', [extra_files(['T25899f_helper.hs'])], multimod_compile_fail, ['T25899f', '-v0']) View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/b5da2ac8e2e4cee89643696f91cb23d... -- View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/b5da2ac8e2e4cee89643696f91cb23d... You're receiving this email because of your account on gitlab.haskell.org.