[Git][ghc/ghc][wip/t23703] Allow per constructor refinement of distinct-constructor-tables

Finley McIlwaine (@FinleyMcIlwaine) gitlab at gitlab.haskell.org
Tue Sep 12 17:50:55 UTC 2023



Finley McIlwaine pushed to branch wip/t23703 at Glasgow Haskell Compiler / GHC


Commits:
50648a3c by Finley McIlwaine at 2023-09-12T10:50:41-07:00
Allow per constructor refinement of distinct-constructor-tables

Introduce `-fno-distinct-constructor-tables`. A distinct constructor table
configuration is built from the combination of flags given, in order. For
example, to create distinct constructor tables for all constructors except for a
specific few named `C1`,..., `CN`, pass `-fdistinct-contructor-tables` followed
by `fno-distinct-constructor-tables=C1,...,CN`. To only generate distinct
constuctor tables for a few specific constructors and no others, just pass
`-fdistinct-constructor-tables=C1,...,CN`.

The various configuations of these flags is included in the dynflags
fingerprints, which should result in the expected recompilation logic.

Adds a test that checks for distinct tables for various given or omitted
constructors.

Updates CountDepsAst and CountDepsParser tests to account for new dependencies.

Fixes #23703

- - - - -


24 changed files:

- compiler/GHC/Driver/Config/Stg/Debug.hs
- compiler/GHC/Driver/DynFlags.hs
- compiler/GHC/Driver/Flags.hs
- compiler/GHC/Driver/Session.hs
- compiler/GHC/Iface/Recomp/Flags.hs
- compiler/GHC/Stg/Debug.hs
- + compiler/GHC/Stg/Debug/Types.hs
- compiler/ghc.cabal.in
- docs/users_guide/9.10.1-notes.rst
- docs/users_guide/debug-info.rst
- testsuite/tests/count-deps/CountDepsAst.stdout
- testsuite/tests/count-deps/CountDepsParser.stdout
- + testsuite/tests/rts/ipe/distinct-tables/ACon.out
- + testsuite/tests/rts/ipe/distinct-tables/AConBCon.out
- + testsuite/tests/rts/ipe/distinct-tables/BCon.out
- + testsuite/tests/rts/ipe/distinct-tables/CCon.out
- + testsuite/tests/rts/ipe/distinct-tables/Main.hs
- + testsuite/tests/rts/ipe/distinct-tables/Makefile
- + testsuite/tests/rts/ipe/distinct-tables/NoACon.out
- + testsuite/tests/rts/ipe/distinct-tables/NoBCon.out
- + testsuite/tests/rts/ipe/distinct-tables/NoBConCCon.out
- + testsuite/tests/rts/ipe/distinct-tables/NoCCon.out
- + testsuite/tests/rts/ipe/distinct-tables/X.hs
- + testsuite/tests/rts/ipe/distinct-tables/all.T


Changes:

=====================================
compiler/GHC/Driver/Config/Stg/Debug.hs
=====================================
@@ -10,5 +10,5 @@ import GHC.Driver.DynFlags
 initStgDebugOpts :: DynFlags -> StgDebugOpts
 initStgDebugOpts dflags = StgDebugOpts
   { stgDebug_infoTableMap = gopt Opt_InfoTableMap dflags
-  , stgDebug_distinctConstructorTables = gopt Opt_DistinctConstructorTables dflags
+  , stgDebug_distinctConstructorTables = distinctConstructorTables dflags
   }


=====================================
compiler/GHC/Driver/DynFlags.hs
=====================================
@@ -111,6 +111,7 @@ import GHC.Types.SrcLoc
 import GHC.Unit.Module
 import GHC.Unit.Module.Warnings
 import GHC.Utils.CliOption
+import GHC.Stg.Debug.Types (StgDebugDctConfig(..))
 import GHC.SysTools.Terminal ( stderrSupportsAnsiColors )
 import GHC.UniqueSubdir (uniqueSubdir)
 import GHC.Utils.Outputable
@@ -128,6 +129,7 @@ import Control.Monad.Trans.Class (lift)
 import Control.Monad.Trans.Except (ExceptT)
 import Control.Monad.Trans.Reader (ReaderT)
 import Control.Monad.Trans.Writer (WriterT)
+import qualified Data.Set as Set
 import Data.Word
 import System.IO
 import System.IO.Error (catchIOError)
@@ -136,8 +138,6 @@ import System.FilePath (normalise, (</>))
 import System.Directory
 import GHC.Foreign (withCString, peekCString)
 
-import qualified Data.Set as Set
-
 import qualified GHC.LanguageExtensions as LangExt
 
 -- -----------------------------------------------------------------------------
@@ -457,7 +457,11 @@ data DynFlags = DynFlags {
     -- 'Int' because it can be used to test uniques in decreasing order.
 
   -- | Temporary: CFG Edge weights for fast iterations
-  cfgWeights            :: Weights
+  cfgWeights            :: Weights,
+
+  -- | Configuration specifying which constructor names we should create
+  -- distinct info tables for
+  distinctConstructorTables :: StgDebugDctConfig
 }
 
 class HasDynFlags m where
@@ -702,7 +706,9 @@ defaultDynFlags mySettings =
 
         reverseErrors = False,
         maxErrors     = Nothing,
-        cfgWeights    = defaultWeights
+        cfgWeights    = defaultWeights,
+
+        distinctConstructorTables = None
       }
 
 type FatalMessager = String -> IO ()


=====================================
compiler/GHC/Driver/Flags.hs
=====================================
@@ -222,7 +222,6 @@ data GeneralFlag
    | Opt_FastLlvm                       -- hidden flag
    | Opt_NoTypeableBinds
 
-   | Opt_DistinctConstructorTables
    | Opt_InfoTableMap
    | Opt_InfoTableMapWithFallback
    | Opt_InfoTableMapWithStack
@@ -581,7 +580,6 @@ codeGenFlags = EnumSet.fromList
    , Opt_DoTagInferenceChecks
 
      -- Flags that affect debugging information
-   , Opt_DistinctConstructorTables
    , Opt_InfoTableMap
    , Opt_InfoTableMapWithStack
    , Opt_InfoTableMapWithFallback


=====================================
compiler/GHC/Driver/Session.hs
=====================================
@@ -261,6 +261,7 @@ import GHC.Utils.Outputable
 import GHC.Settings
 import GHC.CmmToAsm.CFG.Weight
 import GHC.Core.Opt.CallerCC
+import GHC.Stg.Debug.Types
 
 import GHC.SysTools.BaseDir ( expandToolDir, expandTopDir )
 
@@ -1796,6 +1797,10 @@ dynamic_flags_deps = [
         -- Caller-CC
   , make_ord_flag defGhcFlag "fprof-callers"
          (HasArg setCallerCcFilters)
+  , make_ord_flag defGhcFlag "fdistinct-constructor-tables"
+      (OptPrefix setDistinctConstructorTables)
+  , make_ord_flag defGhcFlag "fno-distinct-constructor-tables"
+      (OptPrefix unSetDistinctConstructorTables)
         ------ Compiler flags -----------------------------------------------
 
   , make_ord_flag defGhcFlag "fasm"             (NoArg (setObjBackend ncgBackend))
@@ -2477,7 +2482,6 @@ fFlagsDeps = [
   flagSpec "cmm-thread-sanitizer"             Opt_CmmThreadSanitizer,
   flagSpec "split-sections"                   Opt_SplitSections,
   flagSpec "break-points"                     Opt_InsertBreakpoints,
-  flagSpec "distinct-constructor-tables"      Opt_DistinctConstructorTables,
   flagSpec "info-table-map"                   Opt_InfoTableMap,
   flagSpec "info-table-map-with-stack"        Opt_InfoTableMapWithStack,
   flagSpec "info-table-map-with-fallback"     Opt_InfoTableMapWithFallback
@@ -3310,6 +3314,39 @@ setCallerCcFilters arg =
     Right filt -> upd $ \d -> d { callerCcFilters = filt : callerCcFilters d }
     Left err -> addErr err
 
+setDistinctConstructorTables :: String -> DynP ()
+setDistinctConstructorTables arg = do
+  let cs = parseDistinctConstructorTablesArg arg
+  upd $ \d ->
+    d { distinctConstructorTables =
+        (distinctConstructorTables d) `dctConfigPlus` cs
+      }
+
+unSetDistinctConstructorTables :: String -> DynP ()
+unSetDistinctConstructorTables arg = do
+  let cs = parseDistinctConstructorTablesArg arg
+  upd $ \d ->
+    d { distinctConstructorTables =
+        (distinctConstructorTables d) `dctConfigMinus` cs
+      }
+
+-- | Parse a string of comma-separated constructor names into a 'Set' of
+-- 'String's with one entry per constructor.
+parseDistinctConstructorTablesArg :: String -> Set.Set String
+parseDistinctConstructorTablesArg =
+      -- Ensure we insert the last constructor name built by the fold, if not
+      -- empty
+      uncurry insertNonEmpty
+    . foldr go ("", Set.empty)
+  where
+    go :: Char -> (String, Set.Set String) -> (String, Set.Set String)
+    go ',' (cur, acc) = ("", Set.insert cur acc)
+    go c   (cur, acc) = (c : cur, acc)
+
+    insertNonEmpty :: String -> Set.Set String -> Set.Set String
+    insertNonEmpty "" = id
+    insertNonEmpty cs = Set.insert cs
+
 setMainIs :: String -> DynP ()
 setMainIs arg
   | x:_ <- main_fn, isLower x  -- The arg looked like "Foo.Bar.baz"


=====================================
compiler/GHC/Iface/Recomp/Flags.hs
=====================================
@@ -68,7 +68,7 @@ fingerprintDynFlags hsc_env this_mod nameio =
           map (`gopt` dflags) [Opt_Ticky, Opt_Ticky_Allocd, Opt_Ticky_LNE, Opt_Ticky_Dyn_Thunk, Opt_Ticky_Tag]
 
         -- Other flags which affect code generation
-        codegen = map (`gopt` dflags) (EnumSet.toList codeGenFlags)
+        codegen = (map (`gopt` dflags) (EnumSet.toList codeGenFlags), distinctConstructorTables)
 
         flags = ((mainis, safeHs, lang, cpp), (paths, prof, ticky, codegen, debugLevel, callerCcFilters))
 


=====================================
compiler/GHC/Stg/Debug.hs
=====================================
@@ -1,9 +1,13 @@
-{-# LANGUAGE TupleSections #-}
+{-# LANGUAGE RecordWildCards #-}
+{-# LANGUAGE TupleSections   #-}
 
 -- This module contains functions which implement
 -- the -finfo-table-map and -fdistinct-constructor-tables flags
 module GHC.Stg.Debug
   ( StgDebugOpts(..)
+  , StgDebugDctConfig(..)
+  , dctConfigPlus
+  , dctConfigMinus
   , collectDebugInformation
   ) where
 
@@ -16,11 +20,14 @@ import GHC.Types.Tickish
 import GHC.Core.DataCon
 import GHC.Types.IPE
 import GHC.Unit.Module
-import GHC.Types.Name   ( getName, getOccName, occNameFS, nameSrcSpan)
+import GHC.Types.Name   ( getName, getOccName, occNameFS, nameSrcSpan, occName, occNameString)
 import GHC.Data.FastString
+import GHC.Stg.Debug.Types
 
 import Control.Monad (when)
 import Control.Monad.Trans.Reader
+import Data.Set (Set)
+import qualified Data.Set as Set
 import GHC.Utils.Monad.State.Strict
 import Control.Monad.Trans.Class
 import GHC.Types.Unique.Map
@@ -29,13 +36,6 @@ import Control.Applicative
 import qualified Data.List.NonEmpty as NE
 import Data.List.NonEmpty (NonEmpty(..))
 
-data SpanWithLabel = SpanWithLabel RealSrcSpan LexicalFastString
-
-data StgDebugOpts = StgDebugOpts
-  { stgDebug_infoTableMap              :: !Bool
-  , stgDebug_distinctConstructorTables :: !Bool
-  }
-
 data R = R { rOpts :: StgDebugOpts, rModLocation :: ModLocation, rSpan :: Maybe SpanWithLabel }
 
 type M a = ReaderT R (State InfoTableProvMap) a
@@ -160,10 +160,11 @@ numberDataCon dc _ | isUnboxedTupleDataCon dc = return NoNumber
 numberDataCon dc _ | isUnboxedSumDataCon dc = return NoNumber
 numberDataCon dc ts = do
   opts <- asks rOpts
-  if stgDebug_distinctConstructorTables opts then do
-    -- -fdistinct-constructor-tables is enabled. Add an entry to the data
-    -- constructor map for this occurence of the data constructor with a unique
-    -- number and a src span
+  if shouldMakeDistinctTable opts dc then do
+    -- -fdistinct-constructor-tables is enabled and we do want to make distinct
+    -- tables for this constructor. Add an entry to the data constructor map for
+    -- this occurence of the data constructor with a unique number and a src
+    -- span
     env <- lift get
     mcc <- asks rSpan
     let
@@ -188,7 +189,8 @@ numberDataCon dc ts = do
       Nothing -> NoNumber
       Just res -> Numbered (fst (NE.head res))
   else do
-    -- -fdistinct-constructor-tables is not enabled
+    -- -fdistinct-constructor-tables is not enabled, or we do not want to make
+    -- distinct tables for this specific constructor
     return NoNumber
 
 selectTick :: [StgTickish] -> Maybe (RealSrcSpan, LexicalFastString)
@@ -198,6 +200,20 @@ selectTick = foldl' go Nothing
     go _   (SourceNote rss d) = Just (rss, d)
     go acc _                  = acc
 
+-- | Descide whether a distinct info table should be made for a usage of a data
+-- constructor. We only want to do this if -fdistinct-constructor-tables was
+-- given and this constructor name was given, or no constructor names were
+-- given.
+shouldMakeDistinctTable :: StgDebugOpts -> DataCon -> Bool
+shouldMakeDistinctTable StgDebugOpts{..} dc =
+    case stgDebug_distinctConstructorTables of
+      All -> True
+      Only these -> Set.member dcStr these
+      AllExcept these -> Set.notMember dcStr these
+      None -> False
+  where
+    dcStr = occNameString . occName $ dataConName dc
+
 {-
 Note [Mapping Info Tables to Source Positions]
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


=====================================
compiler/GHC/Stg/Debug/Types.hs
=====================================
@@ -0,0 +1,102 @@
+module GHC.Stg.Debug.Types where
+
+import GHC.Prelude
+
+import GHC.Data.FastString
+import GHC.Types.SrcLoc
+import GHC.Utils.Binary (Binary)
+import qualified GHC.Utils.Binary as B
+
+import Data.Set (Set)
+import qualified Data.Set as Set
+
+data SpanWithLabel = SpanWithLabel RealSrcSpan LexicalFastString
+
+data StgDebugOpts = StgDebugOpts
+  { stgDebug_infoTableMap              :: !Bool
+  , stgDebug_distinctConstructorTables :: !StgDebugDctConfig
+  }
+
+-- | Configuration describing which constructors should be given distinct info
+-- tables for each usage.
+data StgDebugDctConfig =
+    -- | Create distinct constructor tables for each usage of any data
+    -- constructor.
+    --
+    -- This is the behavior if just @-fdistinct-constructor-tables@ is supplied.
+    All
+
+    -- | Create distinct constructor tables for each usage of only these data
+    -- constructors.
+    --
+    -- This is the behavior if @-fdistinct-constructor-tables=C1,...,CN@ is
+    -- supplied.
+  | Only !(Set String)
+
+    -- | Create distinct constructor tables for each usage of any data
+    -- constructor except these ones.
+    --
+    -- This is the behavior if @-fdistinct-constructor-tables@ and
+    -- @-fno-distinct-constructor-tables=C1,...,CN@ is given.
+  | AllExcept !(Set String)
+
+    -- | Do not create distinct constructor tables for any data constructor.
+    --
+    -- This is the behavior if no @-fdistinct-constructor-tables@ is given (or
+    -- @-fno-distinct-constructor-tables@ is given).
+  | None
+
+-- | Necessary for 'StgDebugDctConfig' to be included in the dynflags
+-- fingerprint
+instance Binary StgDebugDctConfig where
+  put_ bh All = B.putByte bh 0
+  put_ bh (Only cs) = do
+    B.putByte bh 1
+    B.put_ bh cs
+  put_ bh (AllExcept cs) = do
+    B.putByte bh 2
+    B.put_ bh cs
+  put_ bh None = B.putByte bh 3
+
+  get bh = do
+    h <- B.getByte bh
+    case h of
+      0 -> pure All
+      1 -> Only <$> B.get bh
+      2 -> AllExcept <$> B.get bh
+      _ -> pure None
+
+-- | Given a distinct constructor tables configuration and a set of constructor
+-- names that we want to generate distinct info tables for, create a new
+-- configuration which includes those constructors.
+--
+-- If the given set is empty, that means the user has entered
+-- @-fdistinct-constructor-tables@ with no constructor names specified, and
+-- therefore we consider that an 'All' configuration.
+dctConfigPlus :: StgDebugDctConfig -> Set String -> StgDebugDctConfig
+dctConfigPlus cfg cs
+    | Set.null cs = All
+    | otherwise =
+        case cfg of
+          All -> All
+          Only cs' -> Only $ Set.union cs' cs
+          AllExcept cs' -> AllExcept $ Set.difference cs' cs
+          None -> Only cs
+
+-- | Given a distinct constructor tables configuration and a set of constructor
+-- names that we /do not/ want to generate distinct info tables for, create a
+-- new configuration which excludes those constructors.
+--
+-- If the given set is empty, that means the user has entered
+-- @-fno-distinct-constructor-tables@ with no constructor names specified, and
+-- therefore we consider that a 'None' configuration.
+dctConfigMinus :: StgDebugDctConfig -> Set String -> StgDebugDctConfig
+dctConfigMinus cfg cs
+    | Set.null cs = None
+    | otherwise =
+        case cfg of
+          All -> AllExcept cs
+          Only cs' -> Only $ Set.difference cs' cs
+          AllExcept cs' -> AllExcept $ Set.union cs' cs
+          None -> None
+


=====================================
compiler/ghc.cabal.in
=====================================
@@ -649,6 +649,7 @@ Library
         GHC.Stg.BcPrep
         GHC.Stg.CSE
         GHC.Stg.Debug
+        GHC.Stg.Debug.Types
         GHC.Stg.FVs
         GHC.Stg.Lift
         GHC.Stg.Lift.Analysis


=====================================
docs/users_guide/9.10.1-notes.rst
=====================================
@@ -54,6 +54,18 @@ Compiler
 - Defaulting plugins can now propose solutions to entangled sets of type variables. This allows defaulting
   of multi-parameter type classes. See :ghc-ticket:`23832`.
 
+- The :ghc-flag:`-fdistinct-constructor-tables
+  <-fdistinct-constructor-tables=⟨cs⟩>` flag may now be provided with a list of
+  constructor names for which distinct info tables should be generated. This
+  avoids the default behavior of generating a distinct info table for *every*
+  usage of *every* constructor, which often results in more information than is
+  desired and significantly increases the size of executables.
+
+- The :ghc-flag:`-fno-distinct-constructor-tables
+  <-fno-distinct-constructor-tables=⟨cs⟩>` flag is introduced, which allows
+  users to refine the set of constructors for which distinct info tables should
+  be generated.
+
 GHCi
 ~~~~
 


=====================================
docs/users_guide/debug-info.rst
=====================================
@@ -368,7 +368,8 @@ to a source location. This lookup table is generated by using the ``-finfo-table
     an info table to an approximate source position of where that
     info table statically originated from. If you
     also want more precise information about constructor info tables then you
-    should also use :ghc-flag:`-fdistinct-constructor-tables`.
+    should also use :ghc-flag:`-fdistinct-constructor-tables
+    <-fdistinct-constructor-tables=⟨cs⟩>`.
 
     The :ghc-flag:`-finfo-table-map` flag will increase the binary size by quite
     a lot, depending on how big your project is. For compiling a project the
@@ -451,7 +452,7 @@ to a source location. This lookup table is generated by using the ``-finfo-table
     from the info table map and decrease the size of executables with info table
     profiling information.
 
-.. ghc-flag:: -fdistinct-constructor-tables
+.. ghc-flag:: -fdistinct-constructor-tables=⟨cs⟩
     :shortdesc: Generate a fresh info table for each usage
                 of a data constructor.
     :type: dynamic
@@ -465,6 +466,41 @@ to a source location. This lookup table is generated by using the ``-finfo-table
     each info table will correspond to the usage of a data constructor rather
     than the data constructor itself.
 
+    :since: 9.10
+
+    The entries in the info table map resulting from this flag may significantly
+    increase the size of executables. However, generating distinct info tables
+    for *every* usage of *every* data constructor often results in more
+    information than necessary. Instead, we would like to generate these
+    distinct tables for some specific constructors. To do this, the names of the
+    constructors we are interested in may be supplied to this flag in a
+    comma-separated list. If no constructor names are supplied (i.e. just
+    ``-fdistinct-constructor-tables`` is given) then fresh info tables will be
+    generated for every usage of every constructor.
+
+    For example, to only generate distinct info tables for the ``Just`` and
+    ``Right`` constructors, use ``-fdistinct-constructor-tables=Just,Right``.
+
+.. ghc-flag:: -fno-distinct-constructor-tables=⟨cs⟩
+    :shortdesc: Avoid generating a fresh info table for each usage of a data
+                constructor.
+    :type: dynamic
+    :category: debugging
+
+    :since: 9.10
+
+    Use this flag to refine the set of data constructors for which distinct info
+    tables are generated (as specified by
+    :ghc-flag:`-fdistinct-constructor-tables
+    <-fdistinct-constructor-tables=⟨cs⟩>`).
+    If no constructor names are given
+    (i.e. just ``-fno-distinct-constructor-tables`` is given) then no distinct
+    info tables will be generated for any usages of any data constructors.
+
+    For example, to generate distinct constructor tables for all data
+    constructors except those named ``MyConstr``, pass both
+    ``-fdistinct-constructor-tables`` and
+    ``-fno-distinct-constructor-tables=MyConstr``.
 
 Querying the Info Table Map
 ---------------------------


=====================================
testsuite/tests/count-deps/CountDepsAst.stdout
=====================================
@@ -118,6 +118,7 @@ GHC.Runtime.Heap.Layout
 GHC.Settings
 GHC.Settings.Config
 GHC.Settings.Constants
+GHC.Stg.Debug.Types
 GHC.Stg.InferTags.TagSig
 GHC.StgToCmm.Types
 GHC.SysTools.Terminal


=====================================
testsuite/tests/count-deps/CountDepsParser.stdout
=====================================
@@ -132,6 +132,7 @@ GHC.Runtime.Heap.Layout
 GHC.Settings
 GHC.Settings.Config
 GHC.Settings.Constants
+GHC.Stg.Debug.Types
 GHC.Stg.InferTags.TagSig
 GHC.StgToCmm.Types
 GHC.SysTools.Terminal


=====================================
testsuite/tests/rts/ipe/distinct-tables/ACon.out
=====================================
@@ -0,0 +1,13 @@
+InfoProv {ipName = "ACon_Main_0_con_info", ipDesc = "2", ipTyDesc = "A", ipLabel = "cafA1", ipMod = "Main", ipSrcFile = "", ipSrcSpan = "30:1-15"}
+InfoProv {ipName = "ACon_Main_1_con_info", ipDesc = "2", ipTyDesc = "A", ipLabel = "cafA2", ipMod = "Main", ipSrcFile = "", ipSrcSpan = "31:1-15"}
+InfoProv {ipName = "BCon_con_info", ipDesc = "2", ipTyDesc = "", ipLabel = "", ipMod = "Main", ipSrcFile = "", ipSrcSpan = ""}
+InfoProv {ipName = "BCon_con_info", ipDesc = "2", ipTyDesc = "", ipLabel = "", ipMod = "Main", ipSrcFile = "", ipSrcSpan = ""}
+InfoProv {ipName = "CCon_con_info", ipDesc = "2", ipTyDesc = "", ipLabel = "", ipMod = "Main", ipSrcFile = "", ipSrcSpan = ""}
+InfoProv {ipName = "CCon_con_info", ipDesc = "2", ipTyDesc = "", ipLabel = "", ipMod = "Main", ipSrcFile = "", ipSrcSpan = ""}
+InfoProv {ipName = "ACon_Main_3_con_info", ipDesc = "2", ipTyDesc = "A", ipLabel = "main", ipMod = "Main", ipSrcFile = "", ipSrcSpan = "13:17-35"}
+InfoProv {ipName = "ACon_Main_0_con_info", ipDesc = "2", ipTyDesc = "X", ipLabel = "cafXA", ipMod = "Main", ipSrcFile = "", ipSrcSpan = "37:1-17"}
+InfoProv {ipName = "ACon_X_0_con_info", ipDesc = "2", ipTyDesc = "X", ipLabel = "cafXA1", ipMod = "X", ipSrcFile = "", ipSrcSpan = "6:1-16"}
+InfoProv {ipName = "ACon_X_1_con_info", ipDesc = "2", ipTyDesc = "X", ipLabel = "cafXA2", ipMod = "X", ipSrcFile = "", ipSrcSpan = "7:1-16"}
+InfoProv {ipName = "ACon_Main_1_con_info", ipDesc = "2", ipTyDesc = "X", ipLabel = "main", ipMod = "Main", ipSrcFile = "", ipSrcSpan = "17:17-37"}
+InfoProv {ipName = "BCon_con_info", ipDesc = "2", ipTyDesc = "", ipLabel = "", ipMod = "Main", ipSrcFile = "", ipSrcSpan = ""}
+InfoProv {ipName = "CCon_con_info", ipDesc = "2", ipTyDesc = "", ipLabel = "", ipMod = "Main", ipSrcFile = "", ipSrcSpan = ""}


=====================================
testsuite/tests/rts/ipe/distinct-tables/AConBCon.out
=====================================
@@ -0,0 +1,13 @@
+InfoProv {ipName = "ACon_Main_0_con_info", ipDesc = "2", ipTyDesc = "A", ipLabel = "cafA1", ipMod = "Main", ipSrcFile = "", ipSrcSpan = "30:1-15"}
+InfoProv {ipName = "ACon_Main_1_con_info", ipDesc = "2", ipTyDesc = "A", ipLabel = "cafA2", ipMod = "Main", ipSrcFile = "", ipSrcSpan = "31:1-15"}
+InfoProv {ipName = "BCon_Main_0_con_info", ipDesc = "2", ipTyDesc = "B", ipLabel = "cafB1", ipMod = "Main", ipSrcFile = "", ipSrcSpan = "32:1-18"}
+InfoProv {ipName = "BCon_Main_1_con_info", ipDesc = "2", ipTyDesc = "B", ipLabel = "cafB2", ipMod = "Main", ipSrcFile = "", ipSrcSpan = "33:1-18"}
+InfoProv {ipName = "CCon_con_info", ipDesc = "2", ipTyDesc = "", ipLabel = "", ipMod = "Main", ipSrcFile = "", ipSrcSpan = ""}
+InfoProv {ipName = "CCon_con_info", ipDesc = "2", ipTyDesc = "", ipLabel = "", ipMod = "Main", ipSrcFile = "", ipSrcSpan = ""}
+InfoProv {ipName = "ACon_Main_3_con_info", ipDesc = "2", ipTyDesc = "A", ipLabel = "main", ipMod = "Main", ipSrcFile = "", ipSrcSpan = "13:17-35"}
+InfoProv {ipName = "ACon_Main_0_con_info", ipDesc = "2", ipTyDesc = "X", ipLabel = "cafXA", ipMod = "Main", ipSrcFile = "", ipSrcSpan = "37:1-17"}
+InfoProv {ipName = "ACon_X_0_con_info", ipDesc = "2", ipTyDesc = "X", ipLabel = "cafXA1", ipMod = "X", ipSrcFile = "", ipSrcSpan = "6:1-16"}
+InfoProv {ipName = "ACon_X_1_con_info", ipDesc = "2", ipTyDesc = "X", ipLabel = "cafXA2", ipMod = "X", ipSrcFile = "", ipSrcSpan = "7:1-16"}
+InfoProv {ipName = "ACon_Main_1_con_info", ipDesc = "2", ipTyDesc = "X", ipLabel = "main", ipMod = "Main", ipSrcFile = "", ipSrcSpan = "17:17-37"}
+InfoProv {ipName = "BCon_Main_3_con_info", ipDesc = "2", ipTyDesc = "B", ipLabel = "main", ipMod = "Main", ipSrcFile = "", ipSrcSpan = "18:17-38"}
+InfoProv {ipName = "CCon_con_info", ipDesc = "2", ipTyDesc = "", ipLabel = "", ipMod = "Main", ipSrcFile = "", ipSrcSpan = ""}


=====================================
testsuite/tests/rts/ipe/distinct-tables/BCon.out
=====================================
@@ -0,0 +1,13 @@
+InfoProv {ipName = "ACon_con_info", ipDesc = "2", ipTyDesc = "", ipLabel = "", ipMod = "Main", ipSrcFile = "", ipSrcSpan = ""}
+InfoProv {ipName = "ACon_con_info", ipDesc = "2", ipTyDesc = "", ipLabel = "", ipMod = "Main", ipSrcFile = "", ipSrcSpan = ""}
+InfoProv {ipName = "BCon_Main_0_con_info", ipDesc = "2", ipTyDesc = "B", ipLabel = "cafB1", ipMod = "Main", ipSrcFile = "", ipSrcSpan = "32:1-18"}
+InfoProv {ipName = "BCon_Main_1_con_info", ipDesc = "2", ipTyDesc = "B", ipLabel = "cafB2", ipMod = "Main", ipSrcFile = "", ipSrcSpan = "33:1-18"}
+InfoProv {ipName = "CCon_con_info", ipDesc = "2", ipTyDesc = "", ipLabel = "", ipMod = "Main", ipSrcFile = "", ipSrcSpan = ""}
+InfoProv {ipName = "CCon_con_info", ipDesc = "2", ipTyDesc = "", ipLabel = "", ipMod = "Main", ipSrcFile = "", ipSrcSpan = ""}
+InfoProv {ipName = "ACon_con_info", ipDesc = "2", ipTyDesc = "", ipLabel = "", ipMod = "Main", ipSrcFile = "", ipSrcSpan = ""}
+InfoProv {ipName = "ACon_con_info", ipDesc = "2", ipTyDesc = "", ipLabel = "", ipMod = "X", ipSrcFile = "", ipSrcSpan = ""}
+InfoProv {ipName = "ACon_con_info", ipDesc = "2", ipTyDesc = "", ipLabel = "", ipMod = "X", ipSrcFile = "", ipSrcSpan = ""}
+InfoProv {ipName = "ACon_con_info", ipDesc = "2", ipTyDesc = "", ipLabel = "", ipMod = "X", ipSrcFile = "", ipSrcSpan = ""}
+InfoProv {ipName = "ACon_con_info", ipDesc = "2", ipTyDesc = "", ipLabel = "", ipMod = "X", ipSrcFile = "", ipSrcSpan = ""}
+InfoProv {ipName = "BCon_Main_3_con_info", ipDesc = "2", ipTyDesc = "B", ipLabel = "main", ipMod = "Main", ipSrcFile = "", ipSrcSpan = "18:17-38"}
+InfoProv {ipName = "CCon_con_info", ipDesc = "2", ipTyDesc = "", ipLabel = "", ipMod = "Main", ipSrcFile = "", ipSrcSpan = ""}


=====================================
testsuite/tests/rts/ipe/distinct-tables/CCon.out
=====================================
@@ -0,0 +1,13 @@
+InfoProv {ipName = "ACon_con_info", ipDesc = "2", ipTyDesc = "", ipLabel = "", ipMod = "Main", ipSrcFile = "", ipSrcSpan = ""}
+InfoProv {ipName = "ACon_con_info", ipDesc = "2", ipTyDesc = "", ipLabel = "", ipMod = "Main", ipSrcFile = "", ipSrcSpan = ""}
+InfoProv {ipName = "BCon_con_info", ipDesc = "2", ipTyDesc = "", ipLabel = "", ipMod = "Main", ipSrcFile = "", ipSrcSpan = ""}
+InfoProv {ipName = "BCon_con_info", ipDesc = "2", ipTyDesc = "", ipLabel = "", ipMod = "Main", ipSrcFile = "", ipSrcSpan = ""}
+InfoProv {ipName = "CCon_Main_0_con_info", ipDesc = "2", ipTyDesc = "C", ipLabel = "cafC1", ipMod = "Main", ipSrcFile = "", ipSrcSpan = "34:1-27"}
+InfoProv {ipName = "CCon_Main_1_con_info", ipDesc = "2", ipTyDesc = "C", ipLabel = "cafC2", ipMod = "Main", ipSrcFile = "", ipSrcSpan = "35:1-27"}
+InfoProv {ipName = "ACon_con_info", ipDesc = "2", ipTyDesc = "", ipLabel = "", ipMod = "Main", ipSrcFile = "", ipSrcSpan = ""}
+InfoProv {ipName = "ACon_con_info", ipDesc = "2", ipTyDesc = "", ipLabel = "", ipMod = "X", ipSrcFile = "", ipSrcSpan = ""}
+InfoProv {ipName = "ACon_con_info", ipDesc = "2", ipTyDesc = "", ipLabel = "", ipMod = "X", ipSrcFile = "", ipSrcSpan = ""}
+InfoProv {ipName = "ACon_con_info", ipDesc = "2", ipTyDesc = "", ipLabel = "", ipMod = "X", ipSrcFile = "", ipSrcSpan = ""}
+InfoProv {ipName = "ACon_con_info", ipDesc = "2", ipTyDesc = "", ipLabel = "", ipMod = "X", ipSrcFile = "", ipSrcSpan = ""}
+InfoProv {ipName = "BCon_con_info", ipDesc = "2", ipTyDesc = "", ipLabel = "", ipMod = "Main", ipSrcFile = "", ipSrcSpan = ""}
+InfoProv {ipName = "CCon_Main_2_con_info", ipDesc = "2", ipTyDesc = "C", ipLabel = "main", ipMod = "Main", ipSrcFile = "", ipSrcSpan = "19:34-38"}


=====================================
testsuite/tests/rts/ipe/distinct-tables/Main.hs
=====================================
@@ -0,0 +1,37 @@
+module Main where
+
+import GHC.InfoProv
+import qualified X
+
+main = do
+    printIp =<< whereFrom cafA1
+    printIp =<< whereFrom cafA2
+    printIp =<< whereFrom cafB1
+    printIp =<< whereFrom cafB2
+    printIp =<< whereFrom cafC1
+    printIp =<< whereFrom cafC2
+    printIp =<< whereFrom (ACon ())
+    printIp =<< whereFrom cafXA
+    printIp =<< whereFrom X.cafXA1
+    printIp =<< whereFrom X.cafXA2
+    printIp =<< whereFrom (X.ACon ())
+    printIp =<< whereFrom (BCon cafA1)
+    printIp =<< whereFrom (CCon (cafA1, BCon (ACon ())))
+  where
+    -- Get rid of the src file path since it makes test output difficult to diff
+    -- on Windows
+    printIp = print . stripIpSrc
+    stripIpSrc (Just ip) = ip { ipSrcFile = "" }
+
+data A = ACon ()
+data B = BCon A
+data C = CCon (A, B)
+
+cafA1 = ACon ()
+cafA2 = ACon ()
+cafB1 = BCon cafA1
+cafB2 = BCon cafA2
+cafC1 = CCon (cafA1, cafB1)
+cafC2 = CCon (cafA2, cafB2)
+
+cafXA = X.ACon ()


=====================================
testsuite/tests/rts/ipe/distinct-tables/Makefile
=====================================
@@ -0,0 +1,33 @@
+TOP=../../../..
+include $(TOP)/mk/boilerplate.mk
+include $(TOP)/mk/test.mk
+
+# This test runs ghc with various combinations of
+# -f{no-}distinct-constructor-tables for different constructors and checks that
+# whereFrom finds (or fails to find) their provenance appropriately.
+
+distinct_tables:
+	@$$TEST_HC $$TEST_HC_OPTS -finfo-table-map -fdistinct-constructor-tables=ACon Main.hs ; \
+	ACon="$$(./Main)" ; \
+	$$TEST_HC $$TEST_HC_OPTS -finfo-table-map -fdistinct-constructor-tables=BCon Main.hs ; \
+	BCon="$$(./Main)" ; \
+	$$TEST_HC $$TEST_HC_OPTS -finfo-table-map -fdistinct-constructor-tables=CCon Main.hs ; \
+	CCon="$$(./Main)" ; \
+	$$TEST_HC $$TEST_HC_OPTS -finfo-table-map -fdistinct-constructor-tables=ACon,BCon Main.hs ; \
+	AConBCon="$$(./Main)" ; \
+	$$TEST_HC $$TEST_HC_OPTS -finfo-table-map -fdistinct-constructor-tables -fno-distinct-constructor-tables=ACon Main.hs ; \
+	NoACon="$$(./Main)" ; \
+	$$TEST_HC $$TEST_HC_OPTS -finfo-table-map -fdistinct-constructor-tables -fno-distinct-constructor-tables=BCon Main.hs ; \
+	NoBCon="$$(./Main)" ; \
+	$$TEST_HC $$TEST_HC_OPTS -finfo-table-map -fdistinct-constructor-tables -fno-distinct-constructor-tables=CCon Main.hs ; \
+	NoCCon="$$(./Main)" ; \
+	$$TEST_HC $$TEST_HC_OPTS -finfo-table-map -fdistinct-constructor-tables -fno-distinct-constructor-tables=BCon,CCon Main.hs ; \
+	NoBConCCon="$$(./Main)" ; \
+	echo "$$ACon" | diff --strip-trailing-cr ACon.out - && \
+	echo "$$BCon" | diff --strip-trailing-cr BCon.out - && \
+	echo "$$CCon" | diff --strip-trailing-cr CCon.out - && \
+	echo "$$AConBCon" | diff --strip-trailing-cr AConBCon.out - && \
+	echo "$$NoACon" | diff --strip-trailing-cr NoACon.out - && \
+	echo "$$NoBCon" | diff --strip-trailing-cr NoBCon.out - && \
+	echo "$$NoCCon" | diff --strip-trailing-cr NoCCon.out - && \
+	echo "$$NoBConCCon" | diff --strip-trailing-cr NoBConCCon.out -


=====================================
testsuite/tests/rts/ipe/distinct-tables/NoACon.out
=====================================
@@ -0,0 +1,13 @@
+InfoProv {ipName = "ACon_con_info", ipDesc = "2", ipTyDesc = "", ipLabel = "", ipMod = "Main", ipSrcFile = "", ipSrcSpan = ""}
+InfoProv {ipName = "ACon_con_info", ipDesc = "2", ipTyDesc = "", ipLabel = "", ipMod = "Main", ipSrcFile = "", ipSrcSpan = ""}
+InfoProv {ipName = "BCon_Main_0_con_info", ipDesc = "2", ipTyDesc = "B", ipLabel = "cafB1", ipMod = "Main", ipSrcFile = "", ipSrcSpan = "32:1-18"}
+InfoProv {ipName = "BCon_Main_1_con_info", ipDesc = "2", ipTyDesc = "B", ipLabel = "cafB2", ipMod = "Main", ipSrcFile = "", ipSrcSpan = "33:1-18"}
+InfoProv {ipName = "CCon_Main_0_con_info", ipDesc = "2", ipTyDesc = "C", ipLabel = "cafC1", ipMod = "Main", ipSrcFile = "", ipSrcSpan = "34:1-27"}
+InfoProv {ipName = "CCon_Main_1_con_info", ipDesc = "2", ipTyDesc = "C", ipLabel = "cafC2", ipMod = "Main", ipSrcFile = "", ipSrcSpan = "35:1-27"}
+InfoProv {ipName = "ACon_con_info", ipDesc = "2", ipTyDesc = "", ipLabel = "", ipMod = "Main", ipSrcFile = "", ipSrcSpan = ""}
+InfoProv {ipName = "ACon_con_info", ipDesc = "2", ipTyDesc = "", ipLabel = "", ipMod = "X", ipSrcFile = "", ipSrcSpan = ""}
+InfoProv {ipName = "ACon_con_info", ipDesc = "2", ipTyDesc = "", ipLabel = "", ipMod = "X", ipSrcFile = "", ipSrcSpan = ""}
+InfoProv {ipName = "ACon_con_info", ipDesc = "2", ipTyDesc = "", ipLabel = "", ipMod = "X", ipSrcFile = "", ipSrcSpan = ""}
+InfoProv {ipName = "ACon_con_info", ipDesc = "2", ipTyDesc = "", ipLabel = "", ipMod = "X", ipSrcFile = "", ipSrcSpan = ""}
+InfoProv {ipName = "BCon_Main_3_con_info", ipDesc = "2", ipTyDesc = "B", ipLabel = "main", ipMod = "Main", ipSrcFile = "", ipSrcSpan = "18:17-38"}
+InfoProv {ipName = "CCon_Main_2_con_info", ipDesc = "2", ipTyDesc = "C", ipLabel = "main", ipMod = "Main", ipSrcFile = "", ipSrcSpan = "19:34-38"}


=====================================
testsuite/tests/rts/ipe/distinct-tables/NoBCon.out
=====================================
@@ -0,0 +1,13 @@
+InfoProv {ipName = "ACon_Main_0_con_info", ipDesc = "2", ipTyDesc = "A", ipLabel = "cafA1", ipMod = "Main", ipSrcFile = "", ipSrcSpan = "30:1-15"}
+InfoProv {ipName = "ACon_Main_1_con_info", ipDesc = "2", ipTyDesc = "A", ipLabel = "cafA2", ipMod = "Main", ipSrcFile = "", ipSrcSpan = "31:1-15"}
+InfoProv {ipName = "BCon_con_info", ipDesc = "2", ipTyDesc = "", ipLabel = "", ipMod = "Main", ipSrcFile = "", ipSrcSpan = ""}
+InfoProv {ipName = "BCon_con_info", ipDesc = "2", ipTyDesc = "", ipLabel = "", ipMod = "Main", ipSrcFile = "", ipSrcSpan = ""}
+InfoProv {ipName = "CCon_Main_0_con_info", ipDesc = "2", ipTyDesc = "C", ipLabel = "cafC1", ipMod = "Main", ipSrcFile = "", ipSrcSpan = "34:1-27"}
+InfoProv {ipName = "CCon_Main_1_con_info", ipDesc = "2", ipTyDesc = "C", ipLabel = "cafC2", ipMod = "Main", ipSrcFile = "", ipSrcSpan = "35:1-27"}
+InfoProv {ipName = "ACon_Main_3_con_info", ipDesc = "2", ipTyDesc = "A", ipLabel = "main", ipMod = "Main", ipSrcFile = "", ipSrcSpan = "13:17-35"}
+InfoProv {ipName = "ACon_Main_0_con_info", ipDesc = "2", ipTyDesc = "X", ipLabel = "cafXA", ipMod = "Main", ipSrcFile = "", ipSrcSpan = "37:1-17"}
+InfoProv {ipName = "ACon_X_0_con_info", ipDesc = "2", ipTyDesc = "X", ipLabel = "cafXA1", ipMod = "X", ipSrcFile = "", ipSrcSpan = "6:1-16"}
+InfoProv {ipName = "ACon_X_1_con_info", ipDesc = "2", ipTyDesc = "X", ipLabel = "cafXA2", ipMod = "X", ipSrcFile = "", ipSrcSpan = "7:1-16"}
+InfoProv {ipName = "ACon_Main_1_con_info", ipDesc = "2", ipTyDesc = "X", ipLabel = "main", ipMod = "Main", ipSrcFile = "", ipSrcSpan = "17:17-37"}
+InfoProv {ipName = "BCon_con_info", ipDesc = "2", ipTyDesc = "", ipLabel = "", ipMod = "Main", ipSrcFile = "", ipSrcSpan = ""}
+InfoProv {ipName = "CCon_Main_2_con_info", ipDesc = "2", ipTyDesc = "C", ipLabel = "main", ipMod = "Main", ipSrcFile = "", ipSrcSpan = "19:34-38"}


=====================================
testsuite/tests/rts/ipe/distinct-tables/NoBConCCon.out
=====================================
@@ -0,0 +1,13 @@
+InfoProv {ipName = "ACon_Main_0_con_info", ipDesc = "2", ipTyDesc = "A", ipLabel = "cafA1", ipMod = "Main", ipSrcFile = "", ipSrcSpan = "30:1-15"}
+InfoProv {ipName = "ACon_Main_1_con_info", ipDesc = "2", ipTyDesc = "A", ipLabel = "cafA2", ipMod = "Main", ipSrcFile = "", ipSrcSpan = "31:1-15"}
+InfoProv {ipName = "BCon_con_info", ipDesc = "2", ipTyDesc = "", ipLabel = "", ipMod = "Main", ipSrcFile = "", ipSrcSpan = ""}
+InfoProv {ipName = "BCon_con_info", ipDesc = "2", ipTyDesc = "", ipLabel = "", ipMod = "Main", ipSrcFile = "", ipSrcSpan = ""}
+InfoProv {ipName = "CCon_con_info", ipDesc = "2", ipTyDesc = "", ipLabel = "", ipMod = "Main", ipSrcFile = "", ipSrcSpan = ""}
+InfoProv {ipName = "CCon_con_info", ipDesc = "2", ipTyDesc = "", ipLabel = "", ipMod = "Main", ipSrcFile = "", ipSrcSpan = ""}
+InfoProv {ipName = "ACon_Main_3_con_info", ipDesc = "2", ipTyDesc = "A", ipLabel = "main", ipMod = "Main", ipSrcFile = "", ipSrcSpan = "13:17-35"}
+InfoProv {ipName = "ACon_Main_0_con_info", ipDesc = "2", ipTyDesc = "X", ipLabel = "cafXA", ipMod = "Main", ipSrcFile = "", ipSrcSpan = "37:1-17"}
+InfoProv {ipName = "ACon_X_0_con_info", ipDesc = "2", ipTyDesc = "X", ipLabel = "cafXA1", ipMod = "X", ipSrcFile = "", ipSrcSpan = "6:1-16"}
+InfoProv {ipName = "ACon_X_1_con_info", ipDesc = "2", ipTyDesc = "X", ipLabel = "cafXA2", ipMod = "X", ipSrcFile = "", ipSrcSpan = "7:1-16"}
+InfoProv {ipName = "ACon_Main_1_con_info", ipDesc = "2", ipTyDesc = "X", ipLabel = "main", ipMod = "Main", ipSrcFile = "", ipSrcSpan = "17:17-37"}
+InfoProv {ipName = "BCon_con_info", ipDesc = "2", ipTyDesc = "", ipLabel = "", ipMod = "Main", ipSrcFile = "", ipSrcSpan = ""}
+InfoProv {ipName = "CCon_con_info", ipDesc = "2", ipTyDesc = "", ipLabel = "", ipMod = "Main", ipSrcFile = "", ipSrcSpan = ""}


=====================================
testsuite/tests/rts/ipe/distinct-tables/NoCCon.out
=====================================
@@ -0,0 +1,13 @@
+InfoProv {ipName = "ACon_Main_0_con_info", ipDesc = "2", ipTyDesc = "A", ipLabel = "cafA1", ipMod = "Main", ipSrcFile = "", ipSrcSpan = "30:1-15"}
+InfoProv {ipName = "ACon_Main_1_con_info", ipDesc = "2", ipTyDesc = "A", ipLabel = "cafA2", ipMod = "Main", ipSrcFile = "", ipSrcSpan = "31:1-15"}
+InfoProv {ipName = "BCon_Main_0_con_info", ipDesc = "2", ipTyDesc = "B", ipLabel = "cafB1", ipMod = "Main", ipSrcFile = "", ipSrcSpan = "32:1-18"}
+InfoProv {ipName = "BCon_Main_1_con_info", ipDesc = "2", ipTyDesc = "B", ipLabel = "cafB2", ipMod = "Main", ipSrcFile = "", ipSrcSpan = "33:1-18"}
+InfoProv {ipName = "CCon_con_info", ipDesc = "2", ipTyDesc = "", ipLabel = "", ipMod = "Main", ipSrcFile = "", ipSrcSpan = ""}
+InfoProv {ipName = "CCon_con_info", ipDesc = "2", ipTyDesc = "", ipLabel = "", ipMod = "Main", ipSrcFile = "", ipSrcSpan = ""}
+InfoProv {ipName = "ACon_Main_3_con_info", ipDesc = "2", ipTyDesc = "A", ipLabel = "main", ipMod = "Main", ipSrcFile = "", ipSrcSpan = "13:17-35"}
+InfoProv {ipName = "ACon_Main_0_con_info", ipDesc = "2", ipTyDesc = "X", ipLabel = "cafXA", ipMod = "Main", ipSrcFile = "", ipSrcSpan = "37:1-17"}
+InfoProv {ipName = "ACon_X_0_con_info", ipDesc = "2", ipTyDesc = "X", ipLabel = "cafXA1", ipMod = "X", ipSrcFile = "", ipSrcSpan = "6:1-16"}
+InfoProv {ipName = "ACon_X_1_con_info", ipDesc = "2", ipTyDesc = "X", ipLabel = "cafXA2", ipMod = "X", ipSrcFile = "", ipSrcSpan = "7:1-16"}
+InfoProv {ipName = "ACon_Main_1_con_info", ipDesc = "2", ipTyDesc = "X", ipLabel = "main", ipMod = "Main", ipSrcFile = "", ipSrcSpan = "17:17-37"}
+InfoProv {ipName = "BCon_Main_3_con_info", ipDesc = "2", ipTyDesc = "B", ipLabel = "main", ipMod = "Main", ipSrcFile = "", ipSrcSpan = "18:17-38"}
+InfoProv {ipName = "CCon_con_info", ipDesc = "2", ipTyDesc = "", ipLabel = "", ipMod = "Main", ipSrcFile = "", ipSrcSpan = ""}


=====================================
testsuite/tests/rts/ipe/distinct-tables/X.hs
=====================================
@@ -0,0 +1,7 @@
+module X where
+
+-- A type with the same constructor name as 'Main.ACon'
+data X = ACon ()
+
+cafXA1 = ACon ()
+cafXA2 = ACon ()


=====================================
testsuite/tests/rts/ipe/distinct-tables/all.T
=====================================
@@ -0,0 +1,21 @@
+test(
+    'distinct_tables',
+    [
+        extra_files([
+            # Source files
+            'Main.hs',
+            'X.hs',
+
+            # Expected output files
+            'ACon.out',
+            'BCon.out',
+            'CCon.out',
+            'AConBCon.out',
+            'NoACon.out',
+            'NoBCon.out',
+            'NoCCon.out',
+            'NoBConCCon.out'
+        ]),
+        ignore_stdout
+        ]
+    , makefile_test, [])



View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/50648a3c29079bb64477f7b8112eeec3c23cdaff

-- 
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/50648a3c29079bb64477f7b8112eeec3c23cdaff
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/20230912/773d1f42/attachment-0001.html>


More information about the ghc-commits mailing list