[Git][ghc/ghc][wip/fabu/T25014-mistakenly-accepted-parent] compiler: refactors renamer lookup for sub binder occurences

Fabricio Nascimento (@fabu) gitlab at gitlab.haskell.org
Wed Jul 3 12:38:21 UTC 2024



Fabricio Nascimento pushed to branch wip/fabu/T25014-mistakenly-accepted-parent at Glasgow Haskell Compiler / GHC


Commits:
9f244423 by Fabricio de Sousa Nascimento at 2024-07-03T21:36:42+09:00
compiler: refactors renamer lookup for sub binder occurences

Refactors lookupSubBndrOcc_helper into two functions that separately
deal with lookup for type classes and export lists. Removes the
Semigroup instance of DisambigInfo in favor of directly filtering
the GRE occurences, the refactored logic also fix and issue with
a program with multiple references being incorrectly accepted

Fix #25014

- - - - -


15 changed files:

- compiler/GHC/Rename/Env.hs
- compiler/GHC/Tc/Gen/Export.hs
- compiler/GHC/Types/Name/Reader.hs
- + testsuite/tests/rename/T25014/Ambig1.hs
- + testsuite/tests/rename/T25014/Ambig2.hs
- + testsuite/tests/rename/T25014/T25014a.hs
- + testsuite/tests/rename/T25014/T25014a.stderr
- + testsuite/tests/rename/T25014/T25014b.hs
- + testsuite/tests/rename/T25014/T25014b.stderr
- + testsuite/tests/rename/T25014/T25014c.hs
- + testsuite/tests/rename/T25014/T25014c.stderr
- + testsuite/tests/rename/T25014/T25014d.hs
- + testsuite/tests/rename/T25014/T25014d.stderr
- + testsuite/tests/rename/T25014/T25014e.hs
- + testsuite/tests/rename/T25014/all.T


Changes:

=====================================
compiler/GHC/Rename/Env.hs
=====================================
@@ -32,7 +32,8 @@ module GHC.Rename.Env (
         getUpdFieldLbls,
 
         ChildLookupResult(..),
-        lookupSubBndrOcc_helper,
+        lookupSubBndrOccOnTypeClass,
+        lookupSubBndrOccOnExportList,
 
         HsSigCtxt(..), lookupLocalTcNames, lookupSigOccRn, lookupSigOccRnN,
         lookupSigCtxtOccRn,
@@ -113,7 +114,6 @@ import Data.Either      ( partitionEithers )
 import Data.Function    ( on )
 import Data.List        ( find, partition, groupBy, sortBy )
 import qualified Data.List.NonEmpty as NE
-import qualified Data.Semigroup as Semi
 import System.IO.Unsafe ( unsafePerformIO )
 
 {-
@@ -677,109 +677,200 @@ disambiguation anyway, because `x` is an original name, and
 lookupGlobalOccRn will find it.
 -}
 
--- | Used in export lists to lookup the children.
-lookupSubBndrOcc_helper :: Bool -> DeprecationWarnings
-                        -> Name
-                        -> RdrName -- ^ thing we are looking up
+-- Find all the things the 'RdrName' maps to,
+-- and pick the one with the right 'Parent' 'Name'.
+lookupSubBndrOcc :: DeprecationWarnings
+                 -> Name     -- ^ Parent
+                 -> SDoc
+                 -> RdrName  -- ^ thing we are looking up
+                 -> RnM (Either NotInScopeError Name)
+lookupSubBndrOcc warn_if_deprec the_parent doc rdr_name =
+  lookupExactOrOrig rdr_name (Right . greName) $
+    -- This happens for built-in classes, for example T24452c
+    do { child <- lookupSubBndrOccOnTypeClass warn_if_deprec the_parent rdr_name what_lkup
+       ; return $ case child of
+           FoundChild g       -> Right (greName g)
+           NameNotFound       -> Left (UnknownSubordinate doc)
+           IncorrectParent {} -> Left (UnknownSubordinate doc) }
+       -- See [Mismatched class methods and associated type families]
+       -- in TcInstDecls.
+  where
+    what_lkup = LookupChild { wantedParent        = the_parent
+                            , lookupDataConFirst  = False
+                            , prioritiseParent    = True -- See T23664.
+                            }
+
+{- NOTE [ Differences in name lookup for Export List and Type Classes ]
+
+Even though the logic to lookup in the export list and instance methods
+for type classes share some common behavior (see Note [childGREPriority])
+they differ on how they report errors. Unifying those in a single method
+caused some subtle issue (see #24452, #25014).
+
+For example on exports lists, you could export a name for a different parent
+in the case of (pattern synonyms) while for type classes the parent must match
+so names with different parents should be report as an error.
+-}
+lookupSubBndrOccOnTypeClass :: DeprecationWarnings
+                        -> Name        -- ^ Parent
+                        -> RdrName     -- ^ thing we are looking up
                         -> LookupChild -- ^ how to look it up (e.g. which
                                        -- 'NameSpace's to look in)
                         -> RnM ChildLookupResult
-lookupSubBndrOcc_helper must_have_parent warn_if_deprec parent rdr_name how_lkup
-  | isUnboundName parent
-    -- Avoid an error cascade
-  = return (FoundChild (mkUnboundGRERdr rdr_name))
+lookupSubBndrOccOnTypeClass warn_if_deprec parent rdr_name how_lkup =
+  if isUnboundName parent
+    -- Avoid an error cascade, see Note [ Unbound vs Ambiguous Names ]
+  then return (FoundChild (mkUnboundGRERdr rdr_name))
+  else do
+    traceTc "lookupSubBndrOccOnTypeClass" (vcat [])
+    (picked_gres, original_gres) <- lookupSubBndrOcc_helper parent rdr_name how_lkup
+    case picked_gres of
+      NoOccurrence -> do
+        no_matching_parent_error parent rdr_name original_gres
+      NoParentOccurrence _ -> do
+        -- This unique occurrence will have no parent, and thus can't match the parent
+        -- we are looking for.
+        no_matching_parent_error parent rdr_name original_gres
+      MatchingParentOccurrence g -> do
+        mark_used_found_child warn_if_deprec g
+      AmbiguousOccurrence _ -> do
+        -- It is more helpful to tell the user that the ambiguous matches
+        -- are for a wrong parent, then that there is a name clash,
+        -- see (#24452). Also since `gres` is NonEmpty and is a sub-list
+        -- of `original_gres` we are sure the original list is NonEmpty.
+        make_incorrect_parent_error parent rdr_name (NE.fromList original_gres)
+{-# INLINEABLE lookupSubBndrOccOnTypeClass #-}
 
-  | otherwise = do
+-- | Used in export lists to lookup the children.
+lookupSubBndrOccOnExportList :: DeprecationWarnings
+                        -> Name        -- ^ Parent
+                        -> RdrName     -- ^ thing we are looking up
+                        -> LookupChild -- ^ how to look it up (e.g. which
+                                       -- 'NameSpace's to look in)
+                        -> RnM ChildLookupResult
+lookupSubBndrOccOnExportList warn_if_deprec parent rdr_name how_lkup =
+  if isUnboundName parent
+    -- Avoid an error cascade, see Note [ Unbound vs Ambiguous Names ]
+  then return (FoundChild (mkUnboundGRERdr rdr_name))
+  else do
+    traceTc "lookupSubBndrOccOnExportList" (vcat [])
+    (picked_gres, original_gres) <- lookupSubBndrOcc_helper parent rdr_name how_lkup
+    case picked_gres of
+      NoOccurrence -> do
+        no_matching_parent_error parent rdr_name original_gres
+      NoParentOccurrence g -> do
+        mark_used_found_child warn_if_deprec g
+      MatchingParentOccurrence g -> do
+        mark_used_found_child warn_if_deprec g
+      AmbiguousOccurrence gres -> do
+        gres_name_clash_error rdr_name gres -- it seems odd this is used here too
+{-# INLINEABLE lookupSubBndrOccOnExportList #-}
+
+-- Used to lookup names on GRE for export lists and type classes
+lookupSubBndrOcc_helper :: Name    -- Parent
+            -> RdrName          -- ^ thing we are looking up
+            -> LookupChild      -- ^ how to look it up (e.g. which
+                                -- 'NameSpace's to look in)
+            -> RnM (DisambigInfo, [GlobalRdrEltX GREInfo])
+lookupSubBndrOcc_helper parent rdr_name how_lkup = do
   gre_env <- getGlobalRdrEnv
   let original_gres = lookupGRE gre_env (LookupChildren (rdrNameOcc rdr_name) how_lkup)
       picked_gres = pick_gres original_gres
   -- The remaining GREs are things that we *could* export here.
-  -- Note that this includes things which have `NoParent`;
-  -- those are sorted in `checkPatSynParent`.
-  traceTc "parent" (ppr parent)
-  traceTc "lookupExportChild must_have_parent:" (ppr must_have_parent)
+  -- Note that this includes things which have 'NoParent';
+  -- those are sorted in 'checkPatSynParent'.
   traceTc "lookupExportChild original_gres:" (ppr original_gres)
   traceTc "lookupExportChild picked_gres:" (ppr picked_gres)
-  case picked_gres of
-    NoOccurrence ->
-      noMatchingParentErr original_gres
-    UniqueOccurrence g ->
-      if must_have_parent
-      then noMatchingParentErr original_gres
-      else checkFld g
-    DisambiguatedOccurrence g ->
-      checkFld g
-    AmbiguousOccurrence gres ->
-      if must_have_parent
-        -- It is more helpful to tell the user that the ambiguous matches
-        -- are for a wrong parent, then that there is a name clash,
-        -- see (#24452). Also since `gres` is NonEmpty and is a sub-list
-        -- of `original_gres` we are sure the original list is NonEmpty.
-      then mkIncorrectParentErr (NE.fromList original_gres)
-      else mkNameClashErr gres
-    where
-        checkFld :: GlobalRdrElt -> RnM ChildLookupResult
-        checkFld g = do
-          addUsedGRE warn_if_deprec g
-          return $ FoundChild g
-
-        -- Called when we find no matching GREs after disambiguation but
-        -- there are three situations where this happens.
-        -- 1. There were none to begin with.
-        -- 2. None of the matching ones were the parent but
-        --  a. They were from an overloaded record field so we can report
-        --     a better error.
-        --  b. The original lookup was actually ambiguous.
-        --     For example, the case where overloading is off and two
-        --     record fields are in scope from different record
-        --     constructors, neither of which is the parent.
-        noMatchingParentErr :: [GlobalRdrElt] -> RnM ChildLookupResult
-        noMatchingParentErr original_gres = do
-          traceRn "noMatchingParentErr" (ppr original_gres)
-          dup_fields_ok <- xoptM LangExt.DuplicateRecordFields
-          case original_gres of
-            []  -> return NameNotFound
-            [g] -> mkIncorrectParentErr (NE.fromList [g])
-            gss@(g:gss'@(_:_)) ->
-              if dup_fields_ok && all isRecFldGRE gss
-              then mkIncorrectParentErr (NE.fromList gss)
-              else mkNameClashErr $ g NE.:| gss'
-
-        mkIncorrectParentErr :: NE.NonEmpty GlobalRdrElt -> RnM ChildLookupResult
-        mkIncorrectParentErr gres = return $ IncorrectParent parent (NE.head gres)
-                                      [p | x <- NE.toList gres, ParentIs p <- [greParent x]]
-
-        mkNameClashErr :: NE.NonEmpty GlobalRdrElt -> RnM ChildLookupResult
-        mkNameClashErr gres = do
-          addNameClashErrRn rdr_name gres
-          return (FoundChild (NE.head gres))
-
-        pick_gres :: [GlobalRdrElt] -> DisambigInfo
-        -- For Unqual, find GREs that are in scope qualified or unqualified
-        -- For Qual,   find GREs that are in scope with that qualification
-        pick_gres gres
-          | isUnqual rdr_name
-          = mconcat (map right_parent gres)
-          | otherwise
-          = mconcat (map right_parent (pickGREs rdr_name gres))
-
-        right_parent :: GlobalRdrElt -> DisambigInfo
-        right_parent gre
-          = case greParent gre of
-              ParentIs cur_parent
-                 | parent == cur_parent -> DisambiguatedOccurrence gre
-                 | otherwise            -> NoOccurrence
-              NoParent                  -> UniqueOccurrence gre
-{-# INLINEABLE lookupSubBndrOcc_helper #-}
+  return (picked_gres, original_gres)
+  where
+    -- We are looking for a single matching parent occurrences, and multiple of those
+    -- occurrences should be presented as an ambiguous error. After that, we are satisfied
+    -- with a single NoParentOccurrence. If there are no occurences whatsoever we will report
+    -- NoOccurence.
+    --
+    -- To report the most precise error, we either report matching parent conflicts or no parent conflicts
+    -- but never both together.
+    pick_gres :: [GlobalRdrElt] -> DisambigInfo
+    pick_gres gres
+        | length matching_parent_gres == 1 = MatchingParentOccurrence $ head matching_parent_gres
+        | length no_parent_gres == 1 = NoParentOccurrence $ head no_parent_gres
+        | null no_parent_gres && null matching_parent_gres = NoOccurrence
+        | not $ null matching_parent_gres = AmbiguousOccurrence (NE.fromList matching_parent_gres)
+        | otherwise = AmbiguousOccurrence (NE.fromList no_parent_gres) -- which cannot be empty due to the above 2 conditions
+      where
+        resolved_gres = resolve_gres rdr_name gres
+        (matching_parent_gres, no_parent_gres) = partition_gres resolved_gres
+
+    -- foldr preserves the order of the errors as they appear in the source
+    partition_gres :: [DisambigInfo] -> ([GlobalRdrElt], [GlobalRdrElt])
+    partition_gres = foldr (flip separate_gres) ([], [])
+
+    -- We prefer disambiguated then unique occurrences, so we separate then so we can decide based on those
+    -- occurrences separately.
+    separate_gres :: ([GlobalRdrElt], [GlobalRdrElt]) -> DisambigInfo -> ([GlobalRdrElt], [GlobalRdrElt])
+    separate_gres (matching_parent_gres, no_parent_gres) (MatchingParentOccurrence g) = (g:matching_parent_gres, no_parent_gres)
+    separate_gres (matching_parent_gres, no_parent_gres) (NoParentOccurrence g) = (matching_parent_gres, g:no_parent_gres)
+    separate_gres acc _ = acc
+
+    -- For Unqual, find GREs that are in scope qualified or unqualified
+    -- For Qual,   find GREs that are in scope with that qualification
+    resolve_gres :: RdrName -> [GlobalRdrElt] -> [DisambigInfo]
+    resolve_gres rdr_name gres
+      | isUnqual rdr_name  = map right_parent gres
+      | otherwise = map right_parent (pickGREs rdr_name gres)
+
+    right_parent :: GlobalRdrElt -> DisambigInfo
+    right_parent gre
+      = case greParent gre of
+          ParentIs cur_parent
+              | parent == cur_parent -> MatchingParentOccurrence gre
+              | otherwise            -> NoOccurrence
+          NoParent                   -> NoParentOccurrence gre
+
+-- Called when we find no matching GREs after disambiguation but
+-- there are three situations where this happens.
+-- 1. There were none to begin with.
+-- 2. None of the matching ones were the parent but
+--  a. They were from an overloaded record field so we can report
+--     a better error.
+--  b. The original lookup was actually ambiguous.
+--     For example, the case where overloading is off and two
+--     record fields are in scope from different record
+--     constructors, neither of which is the parent.
+no_matching_parent_error :: Name -> RdrName -> [GlobalRdrEltX GREInfo] -> RnM ChildLookupResult
+no_matching_parent_error parent rdr_name original_gres = do
+  traceRn "no_matching_parent_error" (ppr original_gres)
+  dup_fields_ok <- xoptM LangExt.DuplicateRecordFields
+  case original_gres of
+    []  -> return NameNotFound
+    [g] -> make_incorrect_parent_error parent rdr_name (NE.fromList [g])
+    gss@(g:gss'@(_:_)) ->
+      if dup_fields_ok && all isRecFldGRE gss
+      then make_incorrect_parent_error parent rdr_name (NE.fromList gss)
+      else gres_name_clash_error rdr_name $ g NE.:| gss'
+
+gres_name_clash_error :: RdrName -> NE.NonEmpty GlobalRdrElt -> RnM ChildLookupResult
+gres_name_clash_error rdr_name gres = do
+  addNameClashErrRn rdr_name gres
+  return (FoundChild (NE.head gres))
+
+make_incorrect_parent_error :: Name -> RdrName -> NE.NonEmpty (GlobalRdrEltX info) -> RnM ChildLookupResult
+make_incorrect_parent_error parent rdr_name gres = return $ IncorrectParent parent (mkUnboundGRERdr rdr_name)
+                              [p | x <- NE.toList gres, ParentIs p <- [greParent x]]
+
+mark_used_found_child :: DeprecationWarnings -> GlobalRdrElt -> RnM ChildLookupResult
+mark_used_found_child warn_if_deprec g = do
+  addUsedGRE warn_if_deprec g
+  return $ FoundChild g
 
 -- | This domain specific datatype is used to record why we decided it was
 -- possible that a GRE could be exported with a parent.
 data DisambigInfo
        = NoOccurrence
           -- ^ The GRE could not be found, or it has the wrong parent.
-       | UniqueOccurrence GlobalRdrElt
+       | NoParentOccurrence GlobalRdrElt
           -- ^ The GRE has no parent. It could be a pattern synonym.
-       | DisambiguatedOccurrence GlobalRdrElt
+       | MatchingParentOccurrence GlobalRdrElt
           -- ^ The parent of the GRE is the correct parent.
        | AmbiguousOccurrence (NE.NonEmpty GlobalRdrElt)
           -- ^ The GRE is ambiguous.
@@ -790,31 +881,10 @@ data DisambigInfo
 
 instance Outputable DisambigInfo where
   ppr NoOccurrence = text "NoOccurrence"
-  ppr (UniqueOccurrence gre) = text "UniqueOccurrence:" <+> ppr gre
-  ppr (DisambiguatedOccurrence gre) = text "DiambiguatedOccurrence:" <+> ppr gre
+  ppr (NoParentOccurrence gre) = text "UniqueOccurrence:" <+> ppr gre
+  ppr (MatchingParentOccurrence gre) = text "MatchingParentOccurence:" <+> ppr gre
   ppr (AmbiguousOccurrence gres)    = text "Ambiguous:" <+> ppr gres
 
-instance Semi.Semigroup DisambigInfo where
-  -- These are the key lines: we prefer disambiguated occurrences to other
-  -- names.
-  _ <> DisambiguatedOccurrence g' = DisambiguatedOccurrence g'
-  DisambiguatedOccurrence g' <> _ = DisambiguatedOccurrence g'
-
-  NoOccurrence <> m = m
-  m <> NoOccurrence = m
-  UniqueOccurrence g <> UniqueOccurrence g'
-    = AmbiguousOccurrence $ g NE.:| [g']
-  UniqueOccurrence g <> AmbiguousOccurrence gs
-    = AmbiguousOccurrence (g `NE.cons` gs)
-  AmbiguousOccurrence gs <> UniqueOccurrence g'
-    = AmbiguousOccurrence (g' `NE.cons` gs)
-  AmbiguousOccurrence gs <> AmbiguousOccurrence gs'
-    = AmbiguousOccurrence (gs Semi.<> gs')
-
-instance Monoid DisambigInfo where
-  mempty = NoOccurrence
-  mappend = (Semi.<>)
-
 -- Lookup SubBndrOcc can never be ambiguous
 --
 -- Records the result of looking up a child.
@@ -835,28 +905,6 @@ instance Outputable ChildLookupResult where
     = text "IncorrectParent"
       <+> hsep [ppr p, ppr $ greName g, ppr ns]
 
-lookupSubBndrOcc :: DeprecationWarnings
-                 -> Name     -- Parent
-                 -> SDoc
-                 -> RdrName
-                 -> RnM (Either NotInScopeError Name)
--- ^ Find all the things the 'RdrName' maps to,
--- and pick the one with the right 'Parent' 'Name'.
-lookupSubBndrOcc warn_if_deprec the_parent doc rdr_name =
-  lookupExactOrOrig rdr_name (Right . greName) $
-    -- This happens for built-in classes, see mod052 for example
-    do { child <- lookupSubBndrOcc_helper True warn_if_deprec the_parent rdr_name what_lkup
-       ; return $ case child of
-           FoundChild g       -> Right (greName g)
-           NameNotFound       -> Left (UnknownSubordinate doc)
-           IncorrectParent {} -> Left (UnknownSubordinate doc) }
-       -- See [Mismatched class methods and associated type families]
-       -- in TcInstDecls.
-  where
-    what_lkup = LookupChild { wantedParent        = the_parent
-                            , lookupDataConFirst  = False
-                            , prioritiseParent    = True -- See T23664.
-                            }
 {-
 Note [Family instance binders]
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


=====================================
compiler/GHC/Tc/Gen/Export.hs
=====================================
@@ -698,8 +698,8 @@ lookupChildrenExport spec_parent rdr_items = mapAndReportM doOne rdr_items
                   , prioritiseParent   = False -- See T11970.
                   }
 
-                -- Do not report export list declaration deprecations
-          name <-  lookupSubBndrOcc_helper False ExportDeprecationWarnings
+          -- Do not report export list declaration deprecations
+          name <-  lookupSubBndrOccOnExportList ExportDeprecationWarnings
                         spec_parent bareName what_lkup
           traceRn "lookupChildrenExport" (ppr name)
           -- Default to data constructors for slightly better error


=====================================
compiler/GHC/Types/Name/Reader.hs
=====================================
@@ -1265,13 +1265,15 @@ greIsRelevant which_gres ns gre
 {- Note [childGREPriority]
 ~~~~~~~~~~~~~~~~~~~~~~~~~~
 There are currently two places in the compiler where we look up GlobalRdrElts
-which have a given Parent. These are the two calls to lookupSubBndrOcc_helper:
+which have a given Parent.
 
-  A. Looking up children in an export item, e.g.
+  A. lookupSubBndrOccOnExportList looks up children in an export item, e.g.
 
        module M ( T(MkT, D) ) where { data T = MkT; data D = D }
 
-  B. Looking up binders in a class or instance declaration, e.g.
+  B. lookupSubBndrOccOnTypeClass looks up binders in a class or
+     instance declaration, e.g.
+
      the operator +++ in the fixity declaration:
 
        class C a where { type (+++) :: a -> a ->; infixl 6 +++ }


=====================================
testsuite/tests/rename/T25014/Ambig1.hs
=====================================
@@ -0,0 +1,5 @@
+-- A module that is ambiguous with Ambig2
+{-# LANGUAGE TypeFamilies #-}
+module Ambig1 where
+  data family T a
+  data instance T Bool = MkT


=====================================
testsuite/tests/rename/T25014/Ambig2.hs
=====================================
@@ -0,0 +1,5 @@
+-- A module that is ambiguous with Ambig1
+{-# LANGUAGE TypeFamilies #-}
+module Ambig2 where
+  import Ambig1 (T)
+  data instance T Int = MkT


=====================================
testsuite/tests/rename/T25014/T25014a.hs
=====================================
@@ -0,0 +1,5 @@
+-- Should not compile as it is unclear what gets exported
+module T25014a (T(MkT)) where
+  import Ambig1 (T(MkT))
+  import Ambig2 (T(MkT))
+  data S
\ No newline at end of file


=====================================
testsuite/tests/rename/T25014/T25014a.stderr
=====================================
@@ -0,0 +1,10 @@
+T25014a.hs:2:17: [GHC-87543]
+     Ambiguous occurrence ‘MkT’.
+      It could refer to
+         either ‘Ambig1.MkT’,
+                imported from ‘Ambig1’ at T25014a.hs:3:18-23
+                (and originally defined at Ambig1.hs:5:26-28),
+             or ‘Ambig2.MkT’,
+                imported from ‘Ambig2’ at T25014a.hs:4:18-23
+                (and originally defined at Ambig2.hs:5:25-27).
+     In the export: T(MkT)
\ No newline at end of file


=====================================
testsuite/tests/rename/T25014/T25014b.hs
=====================================
@@ -0,0 +1,4 @@
+-- Should not compile trying to export a missing name
+module T25014b (A (foo)) where
+
+data A


=====================================
testsuite/tests/rename/T25014/T25014b.stderr
=====================================
@@ -0,0 +1,3 @@
+T25014b.hs:2:17: [GHC-76037]
+     Not in scope: ‘foo’
+     In the export: A(foo)
\ No newline at end of file


=====================================
testsuite/tests/rename/T25014/T25014c.hs
=====================================
@@ -0,0 +1,8 @@
+-- Should not compile trying to export a missing name
+module T25014c (A (foo)) where
+
+data A
+
+data B = B {
+  foo :: Int
+}


=====================================
testsuite/tests/rename/T25014/T25014c.stderr
=====================================
@@ -0,0 +1,4 @@
+T25014c.hs:2:17: [GHC-45510]
+     Term variable ‘foo’ cannot be used here
+        (term variables cannot be promoted)
+     In the export: A(foo)
\ No newline at end of file


=====================================
testsuite/tests/rename/T25014/T25014d.hs
=====================================
@@ -0,0 +1,6 @@
+-- Should not compile trying to export a name with the wrong parent
+module T25014b (A (foo)) where
+
+data A
+
+foo = 1


=====================================
testsuite/tests/rename/T25014/T25014d.stderr
=====================================
@@ -0,0 +1,4 @@
+T25014d.hs:2:17: [GHC-88993]
+     The type constructor ‘A’ is not the parent of the identifier ‘foo’.
+      Identifiers can only be exported with their parent type constructor.
+     In the export: A(foo)
\ No newline at end of file


=====================================
testsuite/tests/rename/T25014/T25014e.hs
=====================================
@@ -0,0 +1,6 @@
+-- Should compile as A.foo matches parent
+module T25014b (A (foo)) where
+
+data A = A {
+  foo :: Int
+}


=====================================
testsuite/tests/rename/T25014/all.T
=====================================
@@ -0,0 +1,5 @@
+test('T25014a', [extra_files(['Ambig1.hs', 'Ambig2.hs'])], multimod_compile_fail, ['T25014a','-v0'])
+test('T25014b', [], compile_fail, [''])
+test('T25014c', [], compile_fail, [''])
+test('T25014d', [], compile_fail, [''])
+test('T25014e', [], compile, [''])
\ No newline at end of file



View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/9f244423a30a07ec7c45527691e7deaaf6747cac

-- 
This project does not include diff previews in email notifications.
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/9f244423a30a07ec7c45527691e7deaaf6747cac
You're receiving this email because of your account on gitlab.haskell.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/ghc-commits/attachments/20240703/27d02097/attachment-0001.html>


More information about the ghc-commits mailing list