[Git][ghc/ghc][wip/21101] Improve error messages for invalid record wildcards
by Sasha Bogicevic (@Bogicevic) 20 Jul '26
by Sasha Bogicevic (@Bogicevic) 20 Jul '26
20 Jul '26
Sasha Bogicevic pushed to branch wip/21101 at Glasgow Haskell Compiler / GHC
Commits:
65fbb50d by Sasha Bogicevic at 2026-07-20T09:44:56+02:00
Improve error messages for invalid record wildcards
Record wildcard hints are now shown in more contexts and include
constructor arity; matching with `..` on a fieldless constructor
now produces a dedicated error message.
Fixes #21101
- - - - -
17 changed files:
- + changelog.d/21101
- compiler/GHC/Hs/Utils.hs
- compiler/GHC/Rename/Env.hs
- compiler/GHC/Rename/Names.hs
- compiler/GHC/Rename/Pat.hs
- compiler/GHC/Tc/Errors/Ppr.hs
- compiler/GHC/Tc/Errors/Types.hs
- compiler/GHC/Types/GREInfo.hs
- compiler/GHC/Types/Hint.hs
- compiler/GHC/Types/Hint/Ppr.hs
- + testsuite/tests/rename/should_fail/T21101.hs
- + testsuite/tests/rename/should_fail/T21101.stderr
- testsuite/tests/rename/should_fail/T9815.stderr
- testsuite/tests/rename/should_fail/T9815b.stderr
- testsuite/tests/rename/should_fail/T9815bghci.stderr
- testsuite/tests/rename/should_fail/T9815ghci.stderr
- testsuite/tests/rename/should_fail/all.T
Changes:
=====================================
changelog.d/21101
=====================================
@@ -0,0 +1,8 @@
+section: compiler
+synopsis: Improve error messages and hints for invalid record wildcards
+description:
+ Record wildcard hints are now shown in more contexts and include
+ constructor arity; matching with ``..`` on a fieldless constructor
+ now produces a dedicated error message.
+mrs: !8673
+issues: #21101
=====================================
compiler/GHC/Hs/Utils.hs
=====================================
@@ -1613,8 +1613,8 @@ hsConDeclsBinders in the following format:
with its record fields, in the form of a list of Int indices into...
- IntMap FieldOcc, an IntMap of record fields.
-(In actual fact, we use [(ConRdrName, Maybe [Located Int])], with Nothing indicating
-that the constructor has unlabelled fields: see Note [Local constructor info in the renamer]
+(In actual fact, we use [(ConRdrName, Either VisArity [Located Int])], with Left n indicating
+that the constructor has n unlabelled arguments: see Note [Local constructor info in the renamer]
in GHC.Types.GREInfo.)
This allows us to do the following (see GHC.Rename.Names.getLocalNonValBinders.new_tc):
@@ -1635,7 +1635,7 @@ Other relevant test cases: rnfail015.
-- See Note [Collecting record fields in data declarations].
data LConsWithFields p =
LConsWithFields
- { consWithFieldIndices :: [(LocatedA (IdP (GhcPass p)), Maybe [Located Int])]
+ { consWithFieldIndices :: [(LocatedA (IdP (GhcPass p)), Either VisArity [Located Int])]
, consFields :: IntMap (LFieldOcc (GhcPass p))
}
@@ -1675,16 +1675,15 @@ hsConDeclsBinders cons = go emptyFieldIndices cons
LConsWithFields ns fs = go seen' rs
get_flds_h98 :: FieldIndices p -> HsConDeclH98Details (GhcPass p)
- -> (Maybe [Located Int], FieldIndices p)
- get_flds_h98 seen (RecCon _ flds) = first Just $ get_flds seen flds
- get_flds_h98 seen (PrefixCon _ []) = (Just [], seen)
- get_flds_h98 seen _ = (Nothing, seen)
+ -> (Either VisArity [Located Int], FieldIndices p)
+ get_flds_h98 seen (RecCon _ flds) = first Right $ get_flds seen flds
+ get_flds_h98 seen (PrefixCon _ args) = (Left (length args), seen)
+ get_flds_h98 seen (InfixCon {}) = (Left 2, seen)
get_flds_gadt :: FieldIndices p -> HsConDeclGADTDetails (GhcPass p)
- -> (Maybe [Located Int], FieldIndices p)
- get_flds_gadt seen (RecConGADT _ flds) = first Just $ get_flds seen flds
- get_flds_gadt seen (PrefixConGADT _ []) = (Just [], seen)
- get_flds_gadt seen _ = (Nothing, seen)
+ -> (Either VisArity [Located Int], FieldIndices p)
+ get_flds_gadt seen (RecConGADT _ flds) = first Right $ get_flds seen flds
+ get_flds_gadt seen (PrefixConGADT _ args) = (Left (length args), seen)
get_flds :: FieldIndices p -> LocatedA [LHsConDeclRecField (GhcPass p)]
-> ([Located Int], FieldIndices p)
=====================================
compiler/GHC/Rename/Env.hs
=====================================
@@ -423,7 +423,12 @@ lookupConstructorInfo qcon@(WithUserRdr _ con_name)
= do { info <- lookupGREInfo_GRE con_name
; case info of
IAmConLike con_info -> return con_info
- UnboundGRE -> return $ ConInfo (ConIsData []) ConHasPositionalArgs
+ UnboundGRE -> return $ ConInfo (ConIsData []) (ConHasPositionalArgs 0)
+ -- NB: it's OK to use the dummy value of '0' for the constructor arity:
+ -- we only use this information for 'TcRnIllegalWildcardsInConstructor',
+ -- which is an error we don't emit when the constructor is unbound.
+ -- See GHC.Rename.Pat.rnHsRecFields.rn_dotdot.
+
IAmTyCon {} -> failIllegalTyCon WL_ConLike qcon
_ -> pprPanic "lookupConstructorInfo: not a ConLike" $
vcat [ text "name:" <+> ppr con_name ]
=====================================
compiler/GHC/Rename/Names.hs
=====================================
@@ -71,7 +71,7 @@ import GHC.Types.FieldLabel
import GHC.Types.Hint
import GHC.Types.SourceFile
import GHC.Types.SrcLoc as SrcLoc
-import GHC.Types.Basic ( TyConFlavour (..), convImportLevel )
+import GHC.Types.Basic (TyConFlavour (..), convImportLevel, VisArity)
import GHC.Types.Id
import GHC.Types.PkgQual
import GHC.Types.GREInfo (ConInfo(..), ConFieldInfo (..), ConLikeInfo (ConIsData))
@@ -875,15 +875,16 @@ getLocalNonValBinders fixity_env
--
-- The information we needed was all set up for us:
-- see Note [Collecting record fields in data declarations] in GHC.Hs.Utils.
- mk_fld_env :: [(Name, Maybe [Located Int])] -> IntMap FieldLabel
+ mk_fld_env :: [(Name, Either VisArity [Located Int])] -> IntMap FieldLabel
-> [(ConLikeName, ConInfo)]
mk_fld_env names flds =
[ (DataConName con, ConInfo (ConIsData (map fst names)) fld_info)
- | (con, mb_fl_indxs) <- names
- , let fld_info = case fmap (map ((flds IntMap.!) . unLoc)) mb_fl_indxs of
- Nothing -> ConHasPositionalArgs
- Just [] -> ConIsNullary
- Just (fld:flds) -> ConHasRecordFields $ fld NE.:| flds ]
+ | (con, con_fl_indxs) <- names
+ , let fld_info = case fmap (map ((flds IntMap.!) . unLoc)) con_fl_indxs of
+ Left 0 -> ConIsNullary
+ Left arity -> ConHasPositionalArgs arity
+ Right [] -> ConIsNullary
+ Right (fld:flds) -> ConHasRecordFields $ fld NE.:| flds ]
new_assoc :: DuplicateRecordFields -> FieldSelectors -> LInstDecl GhcPs
-> RnM [GlobalRdrElt]
@@ -939,10 +940,10 @@ getLocalNonValBinders fixity_env
-- Add errors if a constructor has a duplicate record field.
add_dup_fld_errs :: IntMap FieldLabel
- -> (Name, Maybe [Located Int])
+ -> (Name, Either VisArity [Located Int])
-> IOEnv (Env TcGblEnv TcLclEnv) ()
- add_dup_fld_errs all_flds (con, mb_con_flds)
- | Just con_flds <- mb_con_flds
+ add_dup_fld_errs all_flds (con, con_flds_or_arity)
+ | Right con_flds <- con_flds_or_arity
, let (_, dups) = removeDups (comparing unLoc) con_flds
= for_ dups $ \ dup_flds ->
-- Report the error at the location of the second occurrence
=====================================
compiler/GHC/Rename/Pat.hs
=====================================
@@ -874,7 +874,10 @@ rnHsRecFields ctxt mk_arg (HsRecFields { rec_flds = flds, rec_dotdot = dotdot })
; checkErr dd_flag (needFlagDotDot ctxt)
; (rdr_env, lcl_env) <- getRdrEnvs
; conInfo <- lookupConstructorInfo qcon
- ; when (conFieldInfo conInfo == ConHasPositionalArgs) (addErr (TcRnIllegalWildcardsInConstructor con))
+ ; case conFieldInfo conInfo of
+ ConHasPositionalArgs nbArgs ->
+ addErr $ TcRnIllegalWildcardsInConstructor (toRecordFieldPart ctxt) con nbArgs
+ _ -> return ()
; let present_flds = mkOccSet $ map rdrNameOcc (getFieldRdrs flds)
-- For constructor uses (but not patterns)
=====================================
compiler/GHC/Tc/Errors/Ppr.hs
=====================================
@@ -357,12 +357,12 @@ instance Diagnostic TcRnMessage where
-> mkSimpleDecorated $ vcat [text "Illegal view pattern: " <+> ppr pat]
TcRnCharLiteralOutOfRange c
-> mkSimpleDecorated $ text "character literal out of range: '\\" <> char c <> char '\''
- TcRnIllegalWildcardsInConstructor con
+ TcRnIllegalWildcardsInConstructor ctx con _
-> mkSimpleDecorated $
- vcat [ text "Illegal `{..}' notation for constructor" <+> quotes (ppr con)
- , nest 2 (text "Record wildcards may not be used for constructors with unlabelled fields.")
- , nest 2 (text "Possible fix: Remove the `{..}' and add a match for each field of the constructor.")
- ]
+ text "The data constructor" <+> quotes (ppr con)
+ <+> text "does not have named record fields, so the record"
+ <+> pprRecordFieldPart ctx
+ <+> quotes (ppr con <> text "{..}") <+> text "is invalid."
TcRnIgnoringAnnotations anns
-> mkSimpleDecorated $
text "Ignoring ANN annotation" <> plural anns <> comma
@@ -2791,8 +2791,12 @@ instance Diagnostic TcRnMessage where
-> [suggestExtension LangExt.ViewPatterns]
TcRnCharLiteralOutOfRange{}
-> noHints
- TcRnIllegalWildcardsInConstructor{}
- -> noHints
+ TcRnIllegalWildcardsInConstructor ctx con arity
+ -> case ctx of
+ RecordFieldPattern{} -> [ SuggestEmptyRecordBraces con
+ , SuggestExplicitConstructorArguments con arity
+ ]
+ _ -> [SuggestExplicitConstructorArguments con arity]
TcRnIgnoringAnnotations{}
-> noHints
TcRnAnnotationInSafeHaskell
=====================================
compiler/GHC/Tc/Errors/Types.hs
=====================================
@@ -818,17 +818,35 @@ data TcRnMessage where
TcRnNegativeNumTypeLiteral :: IntegralLit GhcRn -> TcRnMessage
{-| TcRnIllegalWildcardsInConstructor is an error that occurs whenever
- the record wildcards '..' are used inside a constructor without labeled fields.
+ the record wildcards '..' are used with a constructor whose fields are
+ positional (unlabelled). The 'RecordFieldPart' field records whether
+ the wildcards occurred in a record construction (an expression) or in
+ a record pattern, so that the message and its suggested fixes can be
+ worded accordingly. Constructors with no fields at all do not trigger
+ this error: since GHC proposal 496 ("Nullary record wildcards"),
+ @C {..}@ is legal for nullary constructors.
+ Example(s):
- Examples(s): None
+ data D = D Int Bool
+
+ f :: D -> ()
+ f D{..} = () -- record pattern
+
+ g :: D
+ g = D{..} -- record construction
Test cases:
rename/should_fail/T9815.hs
rename/should_fail/T9815b.hs
rename/should_fail/T9815ghci.hs
rename/should_fail/T9815bghci.hs
+ rename/should_fail/T21101.hs
-}
- TcRnIllegalWildcardsInConstructor :: !Name -> TcRnMessage
+ TcRnIllegalWildcardsInConstructor
+ :: !RecordFieldPart -- ^ context in which the constructor application occurs
+ -> !Name -- ^ name of the constructor
+ -> !VisArity -- ^ arity of the constructor
+ -> TcRnMessage
{-| TcRnIgnoringAnnotations is a warning that occurs when the source code
contains annotation pragmas but the platform in use does not support an
=====================================
compiler/GHC/Types/GREInfo.hs
=====================================
@@ -244,14 +244,14 @@ instance NFData ConLikeInfo where
-- See Note [Local constructor info in the renamer]
data ConFieldInfo
= ConHasRecordFields (NonEmpty FieldLabel)
- | ConHasPositionalArgs
+ | ConHasPositionalArgs !VisArity
| ConIsNullary
deriving stock Eq
deriving Data
instance NFData ConFieldInfo where
rnf ConIsNullary = ()
- rnf ConHasPositionalArgs = ()
+ rnf (ConHasPositionalArgs arity) = rnf arity
rnf (ConHasRecordFields flds) = rnf flds
mkConInfo :: ConLikeInfo -> VisArity -> [FieldLabel] -> ConInfo
@@ -259,9 +259,9 @@ mkConInfo con_ty n flds =
ConInfo { conLikeInfo = con_ty
, conFieldInfo = mkConFieldInfo n flds }
-mkConFieldInfo :: Arity -> [FieldLabel] -> ConFieldInfo
+mkConFieldInfo :: VisArity -> [FieldLabel] -> ConFieldInfo
mkConFieldInfo 0 _ = ConIsNullary
-mkConFieldInfo _ fields = maybe ConHasPositionalArgs ConHasRecordFields
+mkConFieldInfo arity fields = maybe (ConHasPositionalArgs arity) ConHasRecordFields
$ NonEmpty.nonEmpty fields
conInfoFields :: ConInfo -> [FieldLabel]
@@ -269,7 +269,7 @@ conInfoFields = conFieldInfoFields . conFieldInfo
conFieldInfoFields :: ConFieldInfo -> [FieldLabel]
conFieldInfoFields (ConHasRecordFields fields) = NonEmpty.toList fields
-conFieldInfoFields ConHasPositionalArgs = []
+conFieldInfoFields (ConHasPositionalArgs _) = []
conFieldInfoFields ConIsNullary = []
instance Outputable ConInfo where
@@ -284,7 +284,7 @@ instance Outputable ConLikeInfo where
instance Outputable ConFieldInfo where
ppr ConIsNullary = text "ConIsNullary"
- ppr ConHasPositionalArgs = text "ConHasPositionalArgs"
+ ppr (ConHasPositionalArgs arity) = text "ConHasPositionalArgs" <+> braces (ppr arity)
ppr (ConHasRecordFields fieldLabels) =
text "ConHasRecordFields" <+> braces (ppr fieldLabels)
=====================================
compiler/GHC/Types/Hint.hs
=====================================
@@ -45,7 +45,7 @@ import GHC.Types.InlinePragma (ActivationGhc)
import GHC.Types.Name (Name, NameSpace, OccName (occNameFS), isSymOcc, nameOccName)
import GHC.Types.Name.Reader (RdrName (Unqual), ImpDeclSpec, GlobalRdrElt)
import GHC.Types.SrcLoc (SrcSpan)
-import GHC.Types.Basic (RuleName)
+import GHC.Types.Basic (RuleName, VisArity)
import GHC.Parser.Errors.Basic
import GHC.Utils.Outputable
import GHC.Data.FastString (fsLit)
@@ -548,6 +548,23 @@ data GhcHint
| SuggestUpgradeForSemaphoreVersionMismatch !SemaphoreUpgradeTarget !Int
-- ^ The 'Int' is the required protocol version.
+ {-| Suggest replacing a record wildcard pattern @C {..}@ with @C {}@,
+ which matches a constructor without binding its fields.
+
+ Triggered by 'GHC.Tc.Errors.Types.TcRnIllegalWildcardsInConstructor'
+ in a record pattern.
+ -}
+ | SuggestEmptyRecordBraces !Name
+
+ {-| Suggest applying a constructor directly to its arguments instead
+ of record syntax, for constructors without labelled fields.
+
+ Triggered by 'GHC.Tc.Errors.Types.TcRnIllegalWildcardsInConstructor'
+ in a record construction and record patterns.
+ The 'VisArity' is the number of positional arguments of the constructor.
+ -}
+ | SuggestExplicitConstructorArguments !Name !VisArity
+
-- | What the user should upgrade to resolve an @-jsem@ semaphore
-- protocol version mismatch.
data SemaphoreUpgradeTarget
=====================================
compiler/GHC/Types/Hint/Ppr.hs
=====================================
@@ -345,6 +345,12 @@ instance Outputable GhcHint where
text "The jobserver uses a newer semaphore protocol than this GHC."
$$ (text "Upgrade GHC to a version that supports semaphore protocol v"
<> int required <> text " to resolve this.")
+ SuggestEmptyRecordBraces con
+ -> text "Use" <+> quotes (ppr con <> text "{}") <+> text "instead,"
+ <+> text "which matches" <+> quotes (ppr con) <+> text "regardless of its fields"
+ SuggestExplicitConstructorArguments con nbArgs
+ -> text "Apply" <+> quotes (ppr con) <+> text "to its"
+ <+> speakNOf nbArgs (text "argument")
perhapsAsPat :: SDoc
perhapsAsPat = text "Perhaps you meant an as-pattern, which must not be surrounded by whitespace"
=====================================
testsuite/tests/rename/should_fail/T21101.hs
=====================================
@@ -0,0 +1,7 @@
+{-# LANGUAGE RecordWildCards #-}
+module T21101 where
+
+data D = D Int Bool
+
+f :: D -> ()
+f D{..} = ()
=====================================
testsuite/tests/rename/should_fail/T21101.stderr
=====================================
@@ -0,0 +1,6 @@
+T21101.hs:7:3: error: [GHC-47217]
+ The data constructor ‘D’ does not have named record fields, so the record pattern ‘D{..}’ is invalid.
+ Suggested fixes:
+ • Use ‘D{}’ instead, which matches ‘D’ regardless of its fields
+ • Apply ‘D’ to its two arguments
+
=====================================
testsuite/tests/rename/should_fail/T9815.stderr
=====================================
@@ -1,5 +1,4 @@
-
T9815.hs:6:13: error: [GHC-47217]
- Illegal `{..}' notation for constructor ‘N’
- Record wildcards may not be used for constructors with unlabelled fields.
- Possible fix: Remove the `{..}' and add a match for each field of the constructor.
+ The data constructor ‘N’ does not have named record fields, so the record construction ‘N{..}’ is invalid.
+ Suggested fix: Apply ‘N’ to its one argument
+
=====================================
testsuite/tests/rename/should_fail/T9815b.stderr
=====================================
@@ -1,5 +1,4 @@
-
T9815.hs:6:13: error: [GHC-47217]
- Illegal `{..}' notation for constructor ‘N’
- Record wildcards may not be used for constructors with unlabelled fields.
- Possible fix: Remove the `{..}' and add a match for each field of the constructor.
+ The data constructor ‘N’ does not have named record fields, so the record construction ‘N{..}’ is invalid.
+ Suggested fix: Apply ‘N’ to its one argument
+
=====================================
testsuite/tests/rename/should_fail/T9815bghci.stderr
=====================================
@@ -1,5 +1,4 @@
+<interactive>:5:7: error: [GHC-47217]
+ The data constructor ‘Arg’ does not have named record fields, so the record construction ‘Arg{..}’ is invalid.
+ Suggested fix: Apply ‘Arg’ to its two arguments
-<interactive>:5:7: [GHC-47217]
- Illegal `{..}' notation for constructor ‘Arg’
- Record wildcards may not be used for constructors with unlabelled fields.
- Possible fix: Remove the `{..}' and add a match for each field of the constructor.
=====================================
testsuite/tests/rename/should_fail/T9815ghci.stderr
=====================================
@@ -1,5 +1,4 @@
+<interactive>:3:7: error: [GHC-47217]
+ The data constructor ‘Data.Semigroup.Arg’ does not have named record fields, so the record construction ‘Data.Semigroup.Arg{..}’ is invalid.
+ Suggested fix: Apply ‘Data.Semigroup.Arg’ to its two arguments
-<interactive>:3:7: [GHC-47217]
- Illegal `{..}' notation for constructor ‘Data.Semigroup.Arg’
- Record wildcards may not be used for constructors with unlabelled fields.
- Possible fix: Remove the `{..}' and add a match for each field of the constructor.
=====================================
testsuite/tests/rename/should_fail/all.T
=====================================
@@ -186,6 +186,7 @@ test('T18138', normal, compile_fail, [''])
test('T20147', normal, compile_fail, [''])
test('RnEmptyStatementGroup1', normal, compile_fail, [''])
test('RnImplicitBindInMdoNotation', normal, compile_fail, [''])
+test('T21101', normal, compile_fail, [''])
test('T21605a', normal, compile_fail, [''])
test('T21605b', normal, compile_fail, [''])
test('T21605c', normal, compile_fail, [''])
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/65fbb50db6b06cc924c53a3b9bb1a6a…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/65fbb50db6b06cc924c53a3b9bb1a6a…
You're receiving this email because of your account on gitlab.haskell.org. Manage all notifications: https://gitlab.haskell.org/-/profile/notifications | Help: https://gitlab.haskell.org/help
1
0
[Git][ghc/ghc][wip/9.14.2-backports] 3 commits: Make the order of usages deterministic
by Zubin (@wz1000) 20 Jul '26
by Zubin (@wz1000) 20 Jul '26
20 Jul '26
Zubin pushed to branch wip/9.14.2-backports at Glasgow Haskell Compiler / GHC
Commits:
2a285613 by Ian-Woo Kim at 2026-07-20T13:16:54+05:30
Make the order of usages deterministic
It has been observed that the ordering of usages can be non-determinstic
in parallel builds. Therefore, this contribution introduces sorting of
usages based on a platform- and race-independent sorting criterion.
Resolves #26877.
Co-authored-by: Wolfgang Jeltsch <wolfgang(a)well-typed.com>
(cherry picked from commit d216412babfd5b5746365f0686ec370fb0892ec7)
- - - - -
0b75a0c4 by Wolfgang Jeltsch at 2026-07-20T13:16:54+05:30
Change the descriptions of two existing changelog entries
The descriptions now describe the changes in a user-friendly manner, as
opposed to describing the contributions that led to these changes in a
developer-friendly manner.
(cherry picked from commit 8e1cc105acae69b1fabd1a9b89e2d1823861f518)
- - - - -
4955f0ca by Andrea Vezzosi at 2026-07-20T13:16:54+05:30
[Fix #27287] preserve ModBreaks in ModIface
(cherry picked from commit 4396a6f2a4c7799908e1e0b88a218a51d063fdca)
- - - - -
26 changed files:
- + changelog.d/deterministic-usage-order
- changelog.d/more-efficient-home-unit-imports-finding
- compiler/GHC/ByteCode/Breakpoints.hs
- compiler/GHC/ByteCode/Types.hs
- compiler/GHC/Driver/Main.hs
- compiler/GHC/HsToCore/Breakpoints.hs
- + compiler/GHC/HsToCore/Breakpoints/Types.hs
- compiler/GHC/HsToCore/Usage.hs
- compiler/GHC/Iface/Load.hs
- compiler/GHC/Iface/Make.hs
- compiler/GHC/Iface/Recomp.hs
- compiler/GHC/Linker/Types.hs
- compiler/GHC/Runtime/Interpreter.hs
- compiler/GHC/Unit/Module/Deps.hs
- compiler/GHC/Unit/Module/ModGuts.hs
- compiler/GHC/Unit/Module/ModIface.hs
- compiler/GHC/Unit/Module/WholeCoreBindings.hs
- compiler/GHC/Utils/Binary.hs
- compiler/ghc.cabal.in
- testsuite/tests/count-deps/CountDepsAst.stdout
- testsuite/tests/count-deps/CountDepsParser.stdout
- testsuite/tests/ghci/scripts/ListTuplePunsPpr.stdout
- testsuite/tests/ghci/should_run/Makefile
- + testsuite/tests/ghci/should_run/T27287.hs
- + testsuite/tests/ghci/should_run/T27287.stdout
- testsuite/tests/ghci/should_run/all.T
Changes:
=====================================
changelog.d/deterministic-usage-order
=====================================
@@ -0,0 +1,8 @@
+section: compiler
+synopsis: Make the order of usages deterministic
+issues: #26877
+mrs: !15484
+description: {
+ The order in which usages appear in interface files is now
+ deterministic.
+}
=====================================
changelog.d/more-efficient-home-unit-imports-finding
=====================================
@@ -3,13 +3,10 @@ synopsis: Introduce a cache of home module name providers
issues: #27055
mrs: !15888
description: {
- This contribution optimizes the algorithm for finding out which home
- unit provides the module that a certain import declaration refers
- to. The previous approach has been to simply search all home units
- in no particular order. This change introduces a cache that allows
- for efficiently determining those complete home units that provide a
- certain module name and changes the module-finding algorithm such
- that it searches these units before the other home units. This leads
- to significant performance improvements in situations where there
- are lots of home units.
+ For finding out which home unit provides the module that a certain
+ import declaration refers to, we now use a better algorithm. The
+ previous approach was to simply search all home units in no
+ particular order. The new algorithm first searches those complete
+ home units that provide a certain module name, before searching the
+ other home units.
}
=====================================
compiler/GHC/ByteCode/Breakpoints.hs
=====================================
@@ -40,7 +40,7 @@ import Control.DeepSeq
import Data.IntMap.Strict (IntMap)
import qualified Data.IntMap.Strict as IM
-import GHC.HsToCore.Breakpoints
+import GHC.HsToCore.Breakpoints.Types
import GHC.Iface.Syntax
import GHC.Unit.Module (Module)
=====================================
compiler/GHC/ByteCode/Types.hs
=====================================
@@ -42,7 +42,7 @@ import GHC.Types.Name.Env
import GHC.Utils.Outputable
import GHC.Builtin.PrimOps
import GHC.Types.SptEntry
-import GHC.HsToCore.Breakpoints
+import GHC.HsToCore.Breakpoints.Types
import GHC.ByteCode.Breakpoints
import GHCi.Message
import GHCi.RemoteTypes
@@ -305,4 +305,3 @@ instance Outputable UnlinkedBCO where
= sep [text "BCO", ppr nm, text "with",
ppr (sizeFlatBag lits), text "lits",
ppr (sizeFlatBag ptrs), text "ptrs" ]
-
=====================================
compiler/GHC/Driver/Main.hs
=====================================
@@ -693,7 +693,7 @@ hsc_typecheck keep_rn mod_summary mb_rdr_module = do
Nothing -> hscParse' mod_summary
tc_result0 <- tcRnModule' mod_summary keep_rn' hpm
if hsc_src == HsigFile
- then do (iface, _) <- liftIO $ hscSimpleIface hsc_env Nothing tc_result0 mod_summary
+ then do (iface, _) <- liftIO $ hscSimpleIface hsc_env Nothing Nothing tc_result0 mod_summary
ioMsgMaybe $ hoistTcRnMessage $
tcRnMergeSignatures hsc_env hpm tc_result0 iface
else return tc_result0
@@ -871,7 +871,7 @@ hscRecompStatus
-- we will decide if we need them or not.
bc_linkable <- checkByteCode checked_iface mod_summary (homeMod_bytecode old_linkable)
obj_linkable <- liftIO $ checkObjects lcl_dflags (homeMod_object old_linkable) mod_summary
- trace_if (hsc_logger hsc_env) (vcat [text "BCO linkable", nest 2 (ppr bc_linkable), text "Object Linkable", ppr obj_linkable])
+ trace_if (hsc_logger hsc_env) (vcat [text "BCO linkable", nest 2 (ppr bc_linkable), text "Object Linkable", nest 2 (ppr obj_linkable)])
let just_bc = justBytecode <$> bc_linkable
just_o = justObjects <$> obj_linkable
@@ -1018,12 +1018,13 @@ compile_for_interpreter hsc_env use =
-- | Assemble 'WholeCoreBindings' if the interface contains Core bindings.
iface_core_bindings :: ModIface -> ModLocation -> Maybe WholeCoreBindings
iface_core_bindings iface wcb_mod_location =
- mi_simplified_core <&> \(IfaceSimplifiedCore bindings foreign') ->
+ mi_simplified_core <&> \(IfaceSimplifiedCore bindings wcb_modBreaks foreign') ->
WholeCoreBindings {
wcb_bindings = bindings,
wcb_module = mi_module,
wcb_mod_location,
- wcb_foreign = foreign'
+ wcb_foreign = foreign',
+ wcb_modBreaks
}
where
ModIface {mi_module, mi_simplified_core} = iface
@@ -1161,11 +1162,11 @@ compileWholeCoreBindings hsc_env type_env wcb = do
gen_bytecode core_binds stubs foreign_files = do
let cgi_guts = CgInteractiveGuts wcb_module core_binds
(typeEnvTyCons type_env) stubs foreign_files
- Nothing []
+ wcb_modBreaks []
trace_if logger (text "Generating ByteCode for" <+> ppr wcb_module)
generateByteCode hsc_env cgi_guts wcb_mod_location
- WholeCoreBindings {wcb_module, wcb_mod_location, wcb_foreign} = wcb
+ WholeCoreBindings {wcb_module, wcb_mod_location, wcb_foreign, wcb_modBreaks} = wcb
logger = hsc_logger hsc_env
@@ -1292,7 +1293,8 @@ hscDesugarAndSimplify summary (FrontendTypecheck tc_result) tc_warnings mb_old_h
liftIO $ hscTidy hsc_env simplified_guts
(iface, _details) <- liftIO $
- hscSimpleIface hsc_env (Just $ cg_binds cg_guts) tc_result summary
+ hscSimpleIface hsc_env (Just $ cg_binds cg_guts)
+ (cg_modBreaks cg_guts) tc_result summary
liftIO $ hscMaybeWriteIface logger dflags True iface mb_old_hash (ms_location summary)
@@ -1307,7 +1309,7 @@ hscDesugarAndSimplify summary (FrontendTypecheck tc_result) tc_warnings mb_old_h
-- and generate a simple interface.
_ -> do
(iface, _details) <- liftIO $
- hscSimpleIface hsc_env Nothing tc_result summary
+ hscSimpleIface hsc_env Nothing Nothing tc_result summary
liftIO $ hscMaybeWriteIface logger dflags True iface mb_old_hash (ms_location summary)
@@ -1886,17 +1888,19 @@ hscSimplify' plugins ds_result = do
-- generates interface files. See Note [simpleTidyPgm - mkBootModDetailsTc]
hscSimpleIface :: HscEnv
-> Maybe CoreProgram
+ -> Maybe ModBreaks
-> TcGblEnv
-> ModSummary
-> IO (ModIface, ModDetails)
-hscSimpleIface hsc_env mb_core_program tc_result summary
- = runHsc hsc_env $ hscSimpleIface' mb_core_program tc_result summary
+hscSimpleIface hsc_env mb_core_program mb_modBreaks tc_result summary
+ = runHsc hsc_env $ hscSimpleIface' mb_core_program mb_modBreaks tc_result summary
hscSimpleIface' :: Maybe CoreProgram
+ -> Maybe ModBreaks
-> TcGblEnv
-> ModSummary
-> Hsc (ModIface, ModDetails)
-hscSimpleIface' mb_core_program tc_result summary = do
+hscSimpleIface' mb_core_program mb_modBreaks tc_result summary = do
hsc_env <- getHscEnv
logger <- getLogger
details <- liftIO $ mkBootModDetailsTc logger tc_result
@@ -1904,7 +1908,7 @@ hscSimpleIface' mb_core_program tc_result summary = do
new_iface
<- {-# SCC "MkFinalIface" #-}
liftIO $
- mkIfaceTc hsc_env safe_mode details summary mb_core_program tc_result
+ mkIfaceTc hsc_env safe_mode details summary mb_core_program mb_modBreaks tc_result
-- And the answer is ...
liftIO $ dumpIfaceStats hsc_env
return (new_iface, details)
=====================================
compiler/GHC/HsToCore/Breakpoints.hs
=====================================
@@ -15,7 +15,7 @@
-- See Note [ModBreaks vs InternalModBreaks] and Note [Breakpoint identifiers]
module GHC.HsToCore.Breakpoints
( -- * ModBreaks
- mkModBreaks, ModBreaks(..)
+ mkModBreaks, ModBreaks(..), modBreaks_locs
-- ** Re-exports BreakpointId
, BreakpointId(..), BreakTickIndex
@@ -25,46 +25,12 @@ import GHC.Prelude
import Data.Array
import GHC.HsToCore.Ticks (Tick (..))
+import GHC.HsToCore.Breakpoints.Types
import GHC.Data.SizedSeq
-import GHC.Types.SrcLoc (SrcSpan)
-import GHC.Types.Name (OccName)
-import GHC.Types.Tickish (BreakTickIndex, BreakpointId(..))
import GHC.Unit.Module (Module)
import GHC.Utils.Outputable
import Data.List (intersperse)
-
---------------------------------------------------------------------------------
--- ModBreaks
---------------------------------------------------------------------------------
-
--- | All the information about the source-relevant breakpoints for a module
---
--- This information is constructed once during desugaring (with `mkModBreaks`)
--- from breakpoint ticks and fixed/unchanged from there on forward. It could be
--- exported as an abstract datatype because it should never be updated after
--- construction, only queried.
---
--- The arrays can be indexed using the int in the corresponding 'BreakpointId'
--- (i.e. the 'BreakpointId' whose 'Module' matches the 'Module' corresponding
--- to these 'ModBreaks') with the accessors 'modBreaks_locs', 'modBreaks_vars',
--- and 'modBreaks_decls'.
-data ModBreaks
- = ModBreaks
- { modBreaks_locs :: !(Array BreakTickIndex SrcSpan)
- -- ^ An array giving the source span of each breakpoint.
- , modBreaks_vars :: !(Array BreakTickIndex [OccName])
- -- ^ An array giving the names of the free variables at each breakpoint.
- , modBreaks_decls :: !(Array BreakTickIndex [String])
- -- ^ An array giving the names of the declarations enclosing each breakpoint.
- -- See Note [Field modBreaks_decls]
- , modBreaks_ccs :: !(Array BreakTickIndex (String, String))
- -- ^ Array pointing to cost centre info for each breakpoint;
- -- actual 'CostCentre' allocation is done at link-time.
- , modBreaks_module :: !Module
- -- ^ The module to which this ModBreaks is associated.
- -- We also cache this here for internal sanity checks.
- }
-
+import GHC.Utils.Binary (BinSrcSpan(BinSrcSpan))
-- | Initialize memory for breakpoint data that is shared between the bytecode
-- generator and the interpreter.
--
@@ -91,7 +57,7 @@ mkModBreaks interpreterProfiled modl extendedMixEntries
]
| otherwise = listArray (0, -1) []
in ModBreaks
- { modBreaks_locs = locsTicks
+ { modBreaks_locs_ = fmap BinSrcSpan locsTicks
, modBreaks_vars = varsTicks
, modBreaks_decls = declsTicks
, modBreaks_ccs = ccs
=====================================
compiler/GHC/HsToCore/Breakpoints/Types.hs
=====================================
@@ -0,0 +1,81 @@
+{-# LANGUAGE RecordWildCards #-}
+
+-- | Information attached to Breakpoints generated from Ticks
+--
+-- The breakpoint information stored in 'ModBreaks' is generated during
+-- desugaring from the ticks annotating the source expressions.
+--
+-- This information can be queried per-breakpoint using the 'BreakpointId'
+-- datatype, which indexes tick-level breakpoint information.
+--
+-- 'ModBreaks' and 'BreakpointId's are not to be confused with
+-- 'InternalModBreaks' and 'InternalBreakId's. The latter are constructed
+-- during bytecode generation and can be found in 'GHC.ByteCode.Breakpoints'.
+--
+-- See Note [ModBreaks vs InternalModBreaks] and Note [Breakpoint identifiers]
+module GHC.HsToCore.Breakpoints.Types
+ ( -- * ModBreaks
+ ModBreaks(..), modBreaks_locs
+
+ -- ** Re-exports BreakpointId
+ , BreakpointId(..), BreakTickIndex
+ ) where
+
+import GHC.Prelude
+import Data.Array
+
+import GHC.Types.SrcLoc (SrcSpan)
+import GHC.Types.Name (OccName)
+import GHC.Types.Tickish (BreakTickIndex, BreakpointId(..))
+import GHC.Unit.Module (Module)
+import Data.Coerce
+import GHC.Utils.Binary (BinSrcSpan(..), Binary(..))
+import Control.DeepSeq
+
+--------------------------------------------------------------------------------
+-- ModBreaks
+--------------------------------------------------------------------------------
+
+-- | All the information about the source-relevant breakpoints for a module
+--
+-- This information is constructed once during desugaring (with `mkModBreaks`)
+-- from breakpoint ticks and fixed/unchanged from there on forward. It could be
+-- exported as an abstract datatype because it should never be updated after
+-- construction, only queried.
+--
+-- The arrays can be indexed using the int in the corresponding 'BreakpointId'
+-- (i.e. the 'BreakpointId' whose 'Module' matches the 'Module' corresponding
+-- to these 'ModBreaks') with the accessors 'modBreaks_locs', 'modBreaks_vars',
+-- and 'modBreaks_decls'.
+data ModBreaks
+ = ModBreaks
+ { modBreaks_locs_ :: !(Array BreakTickIndex BinSrcSpan)
+ -- ^ An array giving the source span of each breakpoint.
+ , modBreaks_vars :: !(Array BreakTickIndex [OccName])
+ -- ^ An array giving the names of the free variables at each breakpoint.
+ , modBreaks_decls :: !(Array BreakTickIndex [String])
+ -- ^ An array giving the names of the declarations enclosing each breakpoint.
+ -- See Note [Field modBreaks_decls]
+ , modBreaks_ccs :: !(Array BreakTickIndex (String, String))
+ -- ^ Array pointing to cost centre info for each breakpoint;
+ -- actual 'CostCentre' allocation is done at link-time.
+ , modBreaks_module :: !Module
+ -- ^ The module to which this ModBreaks is associated.
+ -- We also cache this here for internal sanity checks.
+ }
+
+modBreaks_locs :: ModBreaks -> Array BreakTickIndex SrcSpan
+modBreaks_locs = coerce . modBreaks_locs_
+
+instance Binary ModBreaks where
+ get bh = ModBreaks <$> get bh <*> get bh <*> get bh <*> get bh <*> get bh
+
+ put_ bh ModBreaks {..} =
+ put_ bh modBreaks_locs_
+ *> put_ bh modBreaks_vars
+ *> put_ bh modBreaks_decls
+ *> put_ bh modBreaks_ccs
+ *> put_ bh modBreaks_module
+
+instance NFData ModBreaks where
+ rnf (ModBreaks a b c d e) = rnf a `seq` rnf b `seq` rnf c `seq` rnf d `seq` rnf e
\ No newline at end of file
=====================================
compiler/GHC/HsToCore/Usage.hs
=====================================
@@ -73,6 +73,8 @@ data UsageConfig = UsageConfig
{ uc_safe_implicit_imps_req :: !Bool -- ^ Are all implicit imports required to be safe for this Safe Haskell mode?
}
+-- | Build the list of 'Usage's that drive recompilation checking.
+-- The resulting list is deterministically sorted.
mkUsageInfo :: UsageConfig -> Plugins -> FinderCache -> UnitEnv
-> Module -> ImportedMods -> [ImportUserSpec] -> NameSet
-> [FilePath] -> [(Module, Fingerprint)] -> [Linkable] -> PkgsLoaded
@@ -100,10 +102,10 @@ mkUsageInfo uc plugins fc unit_env
}
| (mod, hash) <- merged ]
++ object_usages
- usages `seqList` return usages
- -- seq the list of Usages returned: occasionally these
- -- don't get evaluated for a while and we can end up hanging on to
- -- the entire collection of Ifaces.
+ usages `seqList` return (sortBy stableUsageCmp usages)
+ -- The use of 'seqList' is important because occasionally the returned list
+ -- is not evaluated for a while, so that with too much laziness here we
+ -- could end up hanging on to the entire collection of 'Iface's.
{- Note [Plugin dependencies]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
=====================================
compiler/GHC/Iface/Load.hs
=====================================
@@ -62,6 +62,8 @@ import GHC.Iface.Rename
import GHC.Iface.Env
import GHC.Iface.Errors as Iface_Errors
+import GHC.HsToCore.Breakpoints.Types (modBreaks_locs)
+
import GHC.Tc.Errors.Types
import GHC.Tc.Utils.Monad
@@ -112,6 +114,7 @@ import GHC.Unit.Env
import GHC.Data.Maybe
import Control.Monad
+import qualified Data.Foldable as Foldable
import Data.Map ( toList )
import System.FilePath
import System.Directory
@@ -1159,9 +1162,11 @@ pprModIface unit_state iface
, vcat [ppr ver $$ nest 2 (ppr decl) | (ver,decl) <- mi_decls iface]
, case mi_simplified_core iface of
Nothing -> empty
- Just (IfaceSimplifiedCore eds fs) ->
+ Just (IfaceSimplifiedCore eds mbs fs) ->
vcat [ text "extra decls:"
$$ nest 2 (vcat ([ppr bs | bs <- eds]))
+ , text "mod breaks:"
+ $$ nest 2 (ppr $ Foldable.toList . modBreaks_locs <$> mbs)
, text "foreign stubs:"
$$ nest 2 (ppr fs)
]
=====================================
compiler/GHC/Iface/Make.hs
=====================================
@@ -34,6 +34,7 @@ import GHC.Iface.Syntax
import GHC.Iface.Recomp
import GHC.Iface.Load
import GHC.Iface.Ext.Fields
+import GHC.HsToCore.Breakpoints.Types (ModBreaks)
import GHC.CoreToIface
@@ -122,11 +123,12 @@ mkPartialIface hsc_env core_prog mod_details mod_summary import_decls
, mg_safe_haskell = safe_mode
, mg_trust_pkg = self_trust
, mg_docs = docs
+ , mg_modBreaks = modBreaks
}
= do
self_recomp <- traverse (mkSelfRecomp hsc_env this_mod (ms_hs_hash mod_summary)) usages
return $ mkIface_ hsc_env this_mod core_prog hsc_src deps rdr_env import_decls fix_env warns self_trust
- safe_mode self_recomp docs mod_details
+ safe_mode self_recomp docs mod_details modBreaks
-- | Fully instantiate an interface. Adds fingerprints and potentially code
-- generator produced information.
@@ -228,9 +230,10 @@ mkIfaceTc :: HscEnv
-> ModDetails -- gotten from mkBootModDetails, probably
-> ModSummary
-> Maybe CoreProgram
+ -> Maybe ModBreaks
-> TcGblEnv -- Usages, deprecations, etc
-> IO ModIface
-mkIfaceTc hsc_env safe_mode mod_details mod_summary mb_program
+mkIfaceTc hsc_env safe_mode mod_details mod_summary mb_program mb_modBreaks
tc_result@TcGblEnv{ tcg_mod = this_mod,
tcg_src = hsc_src,
tcg_imports = imports,
@@ -258,6 +261,7 @@ mkIfaceTc hsc_env safe_mode mod_details mod_summary mb_program
(imp_trust_own_pkg imports) safe_mode self_recomp
docs
mod_details
+ mb_modBreaks
mkFullIface hsc_env partial_iface Nothing Nothing NoStubs []
@@ -302,6 +306,7 @@ mkIface_ :: HscEnv -> Module -> CoreProgram -> HscSource
-> Maybe IfaceSelfRecomp
-> Maybe Docs
-> ModDetails
+ -> Maybe ModBreaks
-> PartialModIface
mkIface_ hsc_env
this_mod core_prog hsc_src deps rdr_env import_decls fix_env src_warns
@@ -319,15 +324,17 @@ mkIface_ hsc_env
-- only at the TypeEnv. The previous Tidy phase has
-- put exactly the info into the TypeEnv that we want
-- to expose in the interface
-
+ modBreaks
= do
let home_unit = hsc_home_unit hsc_env
semantic_mod = homeModuleNameInstantiation home_unit (moduleName this_mod)
entities = typeEnvElts type_env
show_linear_types = xopt LangExt.LinearTypes (hsc_dflags hsc_env)
- simplified_core = if gopt Opt_WriteIfSimplifiedCore dflags then Just (IfaceSimplifiedCore [ toIfaceTopBind b | b <- core_prog ] emptyIfaceForeign)
- else Nothing
+ simplified_core =
+ if gopt Opt_WriteIfSimplifiedCore dflags
+ then Just (IfaceSimplifiedCore [ toIfaceTopBind b | b <- core_prog ] modBreaks emptyIfaceForeign)
+ else Nothing
decls = [ tyThingToIfaceDecl show_linear_types entity
| entity <- entities,
let name = getName entity,
=====================================
compiler/GHC/Iface/Recomp.hs
=====================================
@@ -1208,7 +1208,7 @@ addFingerprints hsc_env iface0 = do
sorted_extra_decls :: Maybe IfaceSimplifiedCore
sorted_extra_decls = mi_simplified_core iface0 <&> \simpl_core ->
- IfaceSimplifiedCore (sortOn binding_key (mi_sc_extra_decls simpl_core)) (mi_sc_foreign simpl_core)
+ IfaceSimplifiedCore (sortOn binding_key (mi_sc_extra_decls simpl_core)) (mi_sc_modBreaks simpl_core) (mi_sc_foreign simpl_core)
-- The interface hash depends on:
-- - the ABI hash, plus
=====================================
compiler/GHC/Linker/Types.hs
=====================================
@@ -47,6 +47,7 @@ module GHC.Linker.Types
, linkableFilterByteCode
, linkableFilterNative
, partitionLinkables
+ , linkableAllBCOs
)
where
@@ -352,6 +353,17 @@ linkableIsNativeCodeOnly l = all isNativeCode (NE.toList (linkableParts l))
linkableBCOs :: Linkable -> [CompiledByteCode]
linkableBCOs l = [ cbc | BCOs cbc <- NE.toList (linkableParts l) ]
+linkableAllBCOs :: Linkable -> [CompiledByteCode]
+linkableAllBCOs l = mapMaybe bcos $ NE.toList (linkableParts l)
+ where
+ -- Note: explicit match on all constructors to trigger warning when new ones are introduced.
+ bcos (BCOs bco) = Just bco
+ bcos (LazyBCOs bco _fs) = Just bco -- TODO: _fs ?
+ bcos DotA{} = Nothing
+ bcos DotDLL{} = Nothing
+ bcos CoreBindings{} = Nothing
+ bcos DotO{} = Nothing
+
-- | List the native linkable parts (.o/.so/.dll) of a linkable
linkableNativeParts :: Linkable -> [LinkablePart]
linkableNativeParts l = NE.filter isNativeCode (linkableParts l)
=====================================
compiler/GHC/Runtime/Interpreter.hs
=====================================
@@ -737,7 +737,7 @@ getModBreaks :: HomeModInfo -> Maybe InternalModBreaks
getModBreaks hmi
| Just linkable <- homeModInfoByteCode hmi,
-- The linkable may have 'DotO's as well; only consider BCOs. See #20570.
- [cbc] <- linkableBCOs linkable
+ [cbc] <- linkableAllBCOs linkable
= bc_breaks cbc
| otherwise
= Nothing -- probably object code
=====================================
compiler/GHC/Unit/Module/Deps.hs
=====================================
@@ -2,6 +2,9 @@
{-# LANGUAGE PatternSynonyms #-}
{-# LANGUAGE ExplicitNamespaces #-}
{-# LANGUAGE DerivingVia #-}
+
+{-# OPTIONS_GHC -Wwarn=incomplete-record-selectors #-}
+
-- | Dependencies and Usage of a module
module GHC.Unit.Module.Deps
( Dependencies(dep_direct_mods
@@ -19,6 +22,7 @@ module GHC.Unit.Module.Deps
, noDependencies
, pprDeps
, Usage (..)
+ , stableUsageCmp
, HomeModImport (..)
, HomeModImportedAvails (..)
, ImportAvails (..)
@@ -45,6 +49,7 @@ import GHC.Utils.Fingerprint
import GHC.Utils.Binary
import GHC.Utils.Outputable
+import Data.Function (on)
import Data.List (sortBy, sort, partition)
import Data.Set (Set)
import qualified Data.Set as Set
@@ -464,6 +469,42 @@ instance Binary Usage where
return UsageHomeModuleInterface { usg_mod_name = mod, usg_unit_id = uid, usg_iface_hash = hash }
i -> error ("Binary.get(Usage): " ++ show i)
+-- | Compares 'Usage's by constructor and, if the constructors are the same, by
+-- identifying strings, to achieve a predictable ordering.
+stableUsageCmp :: Usage -> Usage -> Ordering
+stableUsageCmp
+ usage1@UsagePackageModule {}
+ usage2@UsagePackageModule {}
+ = (compare `on` usg_mod) usage1 usage2
+stableUsageCmp
+ usage1@UsageHomeModule {}
+ usage2@UsageHomeModule {}
+ = (compare `on` Module <$> usg_unit_id <*> usg_mod_name) usage1 usage2
+stableUsageCmp
+ usage1@UsageFile {}
+ usage2@UsageFile {}
+ = (lexicalCompareFS `on` usg_file_path) usage1 usage2
+stableUsageCmp
+ usage1@UsageHomeModuleInterface {}
+ usage2@UsageHomeModuleInterface {}
+ = (compare `on` Module <$> usg_unit_id <*> usg_mod_name) usage1 usage2
+stableUsageCmp
+ usage1@UsageMergedRequirement {}
+ usage2@UsageMergedRequirement {}
+ = (compare `on` usg_mod) usage1 usage2
+stableUsageCmp
+ usage1
+ usage2
+ = (compare `on` constructorIndex) usage1 usage2
+ where
+
+ constructorIndex :: Usage -> Int
+ constructorIndex UsagePackageModule {} = 0
+ constructorIndex UsageHomeModule {} = 1
+ constructorIndex UsageFile {} = 2
+ constructorIndex UsageHomeModuleInterface {} = 3
+ constructorIndex UsageMergedRequirement {} = 4
+
-- | Records the imports that we depend on from a home module,
-- for recompilation checking.
--
=====================================
compiler/GHC/Unit/Module/ModGuts.hs
=====================================
@@ -7,7 +7,7 @@ where
import GHC.Prelude
-import GHC.HsToCore.Breakpoints
+import GHC.HsToCore.Breakpoints.Types
import GHC.ForeignSrcLang
import GHC.Hs
=====================================
compiler/GHC/Unit/Module/ModIface.hs
=====================================
@@ -127,6 +127,8 @@ import GHC.Iface.Flags
import GHC.Iface.Ext.Fields
import GHC.Iface.Recomp.Types
+import GHC.HsToCore.Breakpoints.Types
+
import GHC.Unit
import GHC.Unit.Module.Deps
import GHC.Unit.Module.Warnings
@@ -425,6 +427,8 @@ data IfaceSimplifiedCore = IfaceSimplifiedCore {
-- ^ Extra variable definitions which are **NOT** exposed but when
-- combined with mi_decls allows us to restart code generation.
-- See Note [Interface Files with Core Definitions] and Note [Interface File with Core: Sharing RHSs]
+ , mi_sc_modBreaks :: Maybe ModBreaks
+ -- ^ If breakpoints are present in @mi_sc_extra_decls@ this field provides this field provides the metadata required by the bytecode debugger.
, mi_sc_foreign :: IfaceForeign
-- ^ Foreign stubs and files to supplement 'mi_extra_decls_'.
-- See Note [Foreign stubs and TH bytecode linking]
@@ -754,14 +758,16 @@ instance Binary IfaceAbiHashes where
}
instance Binary IfaceSimplifiedCore where
- put_ bh (IfaceSimplifiedCore eds fs) = do
+ put_ bh (IfaceSimplifiedCore eds mbs fs) = do
put_ bh eds
+ put_ bh mbs
put_ bh fs
get bh = do
eds <- get bh
+ mbs <- get bh
fs <- get bh
- return (IfaceSimplifiedCore eds fs)
+ return (IfaceSimplifiedCore eds mbs fs)
emptyPartialModIface :: Module -> PartialModIface
emptyPartialModIface mod
@@ -870,7 +876,7 @@ instance NFData IfaceModInfo where
instance NFData IfaceSimplifiedCore where
- rnf (IfaceSimplifiedCore eds fs) = rnf eds `seq` rnf fs
+ rnf (IfaceSimplifiedCore eds mbs fs) = rnf eds `seq` rnf mbs `seq` rnf fs
instance NFData IfaceAbiHashes where
rnf (IfaceAbiHashes a1 a2 a3 a4 a5 a6)
=====================================
compiler/GHC/Unit/Module/WholeCoreBindings.hs
=====================================
@@ -9,6 +9,7 @@ import GHC.Cmm.CLabel
import GHC.Driver.DynFlags (DynFlags (targetPlatform), initSDocContext)
import GHC.ForeignSrcLang (ForeignSrcLang (..))
import GHC.Iface.Syntax
+import GHC.HsToCore.Breakpoints.Types (ModBreaks)
import GHC.Prelude
import GHC.Types.ForeignStubs
import GHC.Unit.Module.Location
@@ -127,6 +128,7 @@ the object files.
data WholeCoreBindings = WholeCoreBindings
{ wcb_bindings :: [IfaceBindingX IfaceMaybeRhs IfaceTopBndrInfo] -- ^ serialised tidied core bindings.
+ , wcb_modBreaks :: Maybe ModBreaks -- ^ if @wcb_bindings@ contains breakpoints, this field provides the metadata required by the bytecode debugger.
, wcb_module :: Module -- ^ The module which the bindings are for
, wcb_mod_location :: ModLocation -- ^ The location where the sources reside.
-- | Stubs for foreign declarations and files added via
=====================================
compiler/GHC/Utils/Binary.hs
=====================================
@@ -1919,6 +1919,7 @@ instance Binary UnhelpfulSpanReason where
_ -> UnhelpfulOther <$> get bh
newtype BinSrcSpan = BinSrcSpan { unBinSrcSpan :: SrcSpan }
+ deriving newtype NFData
-- See Note [Source Location Wrappers]
instance Binary BinSrcSpan where
=====================================
compiler/ghc.cabal.in
=====================================
@@ -574,6 +574,7 @@ Library
GHC.HsToCore.Arrows
GHC.HsToCore.Binds
GHC.HsToCore.Breakpoints
+ GHC.HsToCore.Breakpoints.Types
GHC.HsToCore.Coverage
GHC.HsToCore.Docs
GHC.HsToCore.Errors.Ppr
=====================================
testsuite/tests/count-deps/CountDepsAst.stdout
=====================================
@@ -105,6 +105,7 @@ GHC.Hs.Pat
GHC.Hs.Specificity
GHC.Hs.Type
GHC.Hs.Utils
+GHC.HsToCore.Breakpoints.Types
GHC.Iface.Errors.Types
GHC.Iface.Ext.Fields
GHC.Iface.Flags
=====================================
testsuite/tests/count-deps/CountDepsParser.stdout
=====================================
@@ -109,6 +109,7 @@ GHC.Hs.Pat
GHC.Hs.Specificity
GHC.Hs.Type
GHC.Hs.Utils
+GHC.HsToCore.Breakpoints.Types
GHC.HsToCore.Errors.Types
GHC.HsToCore.Pmc.Solver.Types
GHC.Iface.Errors.Types
=====================================
testsuite/tests/ghci/scripts/ListTuplePunsPpr.stdout
=====================================
@@ -24,9 +24,9 @@ instance Monad Solo -- Defined in ‘GHC.Internal.Base’
instance Bounded a => Bounded (Solo a)
-- Defined in ‘GHC.Internal.Enum’
instance Enum a => Enum (Solo a) -- Defined in ‘GHC.Internal.Enum’
-instance Read a => Read (Solo a) -- Defined in ‘GHC.Internal.Read’
instance Eq a => Eq (Solo a) -- Defined in ‘GHC.Internal.Classes’
instance Ord a => Ord (Solo a) -- Defined in ‘GHC.Internal.Classes’
+instance Read a => Read (Solo a) -- Defined in ‘GHC.Internal.Read’
instance Show a => Show (Solo a) -- Defined in ‘GHC.Internal.Show’
instance Monoid a => Monoid (Solo a)
-- Defined in ‘GHC.Internal.Base’
=====================================
testsuite/tests/ghci/should_run/Makefile
=====================================
@@ -13,3 +13,7 @@ TopEnvIface:
# Second compilation starts from interface files, but still can print "a"
"$(TEST_HC)" $(TEST_HC_OPTS_INTERACTIVE) TopEnvIface -v1 -e "a" -e ":q" -fwrite-if-simplified-core -fwrite-interface
+T27287:
+ "$(TEST_HC)" $(TEST_HC_OPTS_INTERACTIVE) T27287.hs -v1 -fno-hide-source-paths -e ":q" -fwrite-if-simplified-core -fwrite-interface
+ # Second compilation starts from interface files, but still can print "a"
+ "$(TEST_HC)" $(TEST_HC_OPTS_INTERACTIVE) T27287.hs -v1 -fno-hide-source-paths -e ":break T27287 5" -e ":q" -fwrite-if-simplified-core -fwrite-interface
=====================================
testsuite/tests/ghci/should_run/T27287.hs
=====================================
@@ -0,0 +1,6 @@
+module T27287 where
+
+myfun :: String -> String
+myfun xs = case reverse xs of
+ [] -> "empty"
+ xy -> xy
=====================================
testsuite/tests/ghci/should_run/T27287.stdout
=====================================
@@ -0,0 +1,6 @@
+[1 of 1] Compiling T27287 ( T27287.hs, interpreted )[main]
+Ok, one module loaded.
+Leaving GHCi.
+Ok, one module loaded.
+Breakpoint 0 activated at T27287.hs:5:9-15
+Leaving GHCi.
=====================================
testsuite/tests/ghci/should_run/all.T
=====================================
@@ -8,6 +8,7 @@ test('ghcirun002', just_ghci, compile_and_run, [''])
test('ghcirun003', just_ghci, compile_and_run, [''])
test('T2589', just_ghci, compile_and_run, [''])
test('T2881', just_ghci, compile_and_run, [''])
+test('T27287', [just_ghci, combined_output], makefile_test, [])
test('T3171',
[when(opsys('mingw32'),skip),
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/8d5a1f45431300f3eb59d768877b5a…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/8d5a1f45431300f3eb59d768877b5a…
You're receiving this email because of your account on gitlab.haskell.org. Manage all notifications: https://gitlab.haskell.org/-/profile/notifications | Help: https://gitlab.haskell.org/help
1
0
[Git][ghc/ghc][wip/9.14.2-backports] 6 commits: Avoid mkTick in Core Prep breaking ANF
by Zubin (@wz1000) 20 Jul '26
by Zubin (@wz1000) 20 Jul '26
20 Jul '26
Zubin pushed to branch wip/9.14.2-backports at Glasgow Haskell Compiler / GHC
Commits:
13a52ca3 by sheaf at 2026-07-20T13:12:14+05:30
Avoid mkTick in Core Prep breaking ANF
As discovered in #27182, mkTick can break ANF. This patch introduces a
variant of mkTick that skips the single optimisation that could break
ANF. This is preferrable over switching to the raw Tick constructor,
as the latter may introduce spurious cost centres in profiling reports.
This is a temporary measure until we more thoroughly refactor how
mkTick works (see #27141).
See Note [mkTick breaks ANF] in GHC.CoreToStg.Prep.
Fixes #27182
(cherry picked from commit f9bcfac2e92457128f5c82dea181edcd0baf7eef)
- - - - -
289f1eb1 by sheaf at 2026-07-20T13:12:14+05:30
Don't drop ticks around variables of type `IO ()`
GHC.Core.Utils.mkTick is responsible for placing a tick on a Core
expression. It contains logic for dropping SCCs (non-counting profiling
ticks) around non-function variables, as such variables cannot
meaningfully contribute to profiles. However, the logic for what counts
as a function was incorrect: it used `isFunTy` which returns 'False' for
types such as 'IO ()' where the function arrow is hidden under a
newtype.
We now use 'mightBeFunTy' instead of 'isFunTy'. This ensures we don't
drop ticks in cases we aren't sure.
On the way, we improve the documentation of 'isFunTy', 'isPiTy' and
'mightBeFunTy', and update the latter's implementation to consistently
handle unary classes.
Fixes #27225
-------------------------
Metric Decrease:
T5642
-------------------------
(cherry picked from commit ce01ccb625514a09e76aded549691da4dfe87de7)
- - - - -
d1ad134c by sheaf at 2026-07-20T13:12:14+05:30
Avoid mkTick in Core Prep breaking ANF (part II)
Hotfix for 2f9579765f55b3920ceb2e04995ff41a9d0e2d4e fixing a small
oversight in the call to tickTickedExpr from mkTick, in which we
improperly recursively called mkTick without passing on the preserve_anf
flag.
Fixes #27386
(cherry picked from commit 473b97ebc742305f56e30d5b1bbf95b7681312f0)
- - - - -
df973ff7 by Ian-Woo Kim at 2026-07-20T13:12:14+05:30
Make the order of usages deterministic
It has been observed that the ordering of usages can be non-determinstic
in parallel builds. Therefore, this contribution introduces sorting of
usages based on a platform- and race-independent sorting criterion.
Resolves #26877.
Co-authored-by: Wolfgang Jeltsch <wolfgang(a)well-typed.com>
(cherry picked from commit d216412babfd5b5746365f0686ec370fb0892ec7)
- - - - -
72d595e5 by Wolfgang Jeltsch at 2026-07-20T13:12:14+05:30
Change the descriptions of two existing changelog entries
The descriptions now describe the changes in a user-friendly manner, as
opposed to describing the contributions that led to these changes in a
developer-friendly manner.
(cherry picked from commit 8e1cc105acae69b1fabd1a9b89e2d1823861f518)
- - - - -
8d5a1f45 by Andrea Vezzosi at 2026-07-20T13:12:14+05:30
[Fix #27287] preserve ModBreaks in ModIface
(cherry picked from commit 4396a6f2a4c7799908e1e0b88a218a51d063fdca)
- - - - -
44 changed files:
- + changelog.d/T27182.md
- + changelog.d/T27225
- + changelog.d/T27386
- + changelog.d/deterministic-usage-order
- changelog.d/more-efficient-home-unit-imports-finding
- compiler/GHC/ByteCode/Breakpoints.hs
- compiler/GHC/ByteCode/Types.hs
- compiler/GHC/Core/Opt/Arity.hs
- compiler/GHC/Core/Type.hs
- compiler/GHC/Core/Utils.hs
- compiler/GHC/CoreToStg/Prep.hs
- compiler/GHC/Driver/Main.hs
- compiler/GHC/HsToCore/Breakpoints.hs
- + compiler/GHC/HsToCore/Breakpoints/Types.hs
- compiler/GHC/HsToCore/Usage.hs
- compiler/GHC/Iface/Load.hs
- compiler/GHC/Iface/Make.hs
- compiler/GHC/Iface/Recomp.hs
- compiler/GHC/Linker/Types.hs
- compiler/GHC/Runtime/Interpreter.hs
- compiler/GHC/Types/RepType.hs
- compiler/GHC/Unit/Module/Deps.hs
- compiler/GHC/Unit/Module/ModGuts.hs
- compiler/GHC/Unit/Module/ModIface.hs
- compiler/GHC/Unit/Module/WholeCoreBindings.hs
- compiler/GHC/Utils/Binary.hs
- compiler/ghc.cabal.in
- testsuite/tests/count-deps/CountDepsAst.stdout
- testsuite/tests/count-deps/CountDepsParser.stdout
- testsuite/tests/ghci/should_run/Makefile
- + testsuite/tests/ghci/should_run/T27287.hs
- + testsuite/tests/ghci/should_run/T27287.stdout
- testsuite/tests/ghci/should_run/all.T
- + testsuite/tests/profiling/should_compile/T27182.hs
- + testsuite/tests/profiling/should_compile/T27386.hs
- testsuite/tests/profiling/should_compile/all.T
- + testsuite/tests/profiling/should_run/T27225.hs
- + testsuite/tests/profiling/should_run/T27225.stdout
- + testsuite/tests/profiling/should_run/T27225b.hs
- + testsuite/tests/profiling/should_run/T27225b.stdout
- testsuite/tests/profiling/should_run/all.T
- testsuite/tests/profiling/should_run/caller-cc/CallerCc1.prof.sample
- testsuite/tests/profiling/should_run/callstack001.stdout
- testsuite/tests/profiling/should_run/scc001.prof.sample
The diff was not included because it is too large.
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/883a75bd123f85bdb4cd2762244750…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/883a75bd123f85bdb4cd2762244750…
You're receiving this email because of your account on gitlab.haskell.org. Manage all notifications: https://gitlab.haskell.org/-/profile/notifications | Help: https://gitlab.haskell.org/help
1
0
[Git][ghc/ghc][wip/az/exactprint-annotation-rationalisation] 44 commits: Coercion optimisation: avoid double-Sym for InstCo
by Alan Zimmerman (@alanz) 19 Jul '26
by Alan Zimmerman (@alanz) 19 Jul '26
19 Jul '26
Alan Zimmerman pushed to branch wip/az/exactprint-annotation-rationalisation at Glasgow Haskell Compiler / GHC
Commits:
722236dd by sheaf at 2026-07-18T08:48:31-04:00
Coercion optimisation: avoid double-Sym for InstCo
Ticket #27374 pointed out an issue with GHC.Core.Coercion.Opt.optCoercion's
handling of InstCo: it contravened (LC2) in Note [The LiftingContext in optCoercion]
because it applied the ambient 'sym' to a coercion that was then added
to the lifting context substitution.
Fixes #27374
Co-authored-by: Simon Jakobi <simon.jakobi(a)gmail.com>
- - - - -
ff70fc75 by sheaf at 2026-07-18T08:48:31-04:00
Coercion optimisation: avoid exponential behaviour
The change to coercion optimisation of 'InstCo' in the previous commit
introduces exponential behaviour to the coercion optimiser. To avoid
this, this commit provides a way to push in 'Sym' of an already-optimised
coercion: GHC.Core.Coercion.Opt.mkDeepSymCo.
See Note [Pushing Sym without re-optimising] in GHC.Core.Coercion.Opt.
- - - - -
dfef27f0 by Duncan Coutts at 2026-07-18T08:49:12-04:00
Move THREADED_RTS-conditional struct members to end of Capability
Accessing members of the Capability struct from CMM code rely on
accessor macros. (The macros are generated by deriveConstants).
These macros have a single definition. This means that the offsets of
all struct members must *not* vary based on THREADED_RTS vs
!THREADED_RTS. This requires that any struct members that are
conditional on THREADED_RTS must occur after the unconditional struct
members. Hence we move all the ones that are conditional on
THREADED_RTS to the end.
Add a deriveConstants entry for the iomgr member of the Capability
struct, which was the motivation for this change.
Add warning messages to help our future selves. Debugging this took me
a couple hours in gdb!
- - - - -
c254e022 by Duncan Coutts at 2026-07-18T08:49:12-04:00
Make the IOManager API use CapIOManager rather than Capability
This makes the API somewhat more self-contained and more consistent.
Now the IOManager API and each of the backends takes just the I/O
manager structure. Previously we had a bit of a mixture, depending on
whether the function needed access to the Capability or just the
CapIOManager.
We still need access to the cap, so we introduce a back reference to
reach the capability, via iomgr->cap.
Convert all uses in select and poll backends, but not win32 ones.
Convert callers in the scheduler and elsewhere.
Also convert the three CMM primops that call IOManager APIs. They just
need to use Capability_iomgr(MyCapability()).
- - - - -
4f3d8f31 by Duncan Coutts at 2026-07-18T08:49:12-04:00
Split posix/MIO.c out of posix/Signals.c
The MIO I/O manager was secretly living inside the Signals file.
Now it gets its own file, like any other self-respecting I/O manager.
- - - - -
52ce04a9 by Duncan Coutts at 2026-07-18T08:49:12-04:00
Rationalise some scheduler run queue utilities
Move them all to the same place in the file.
Make some static that were used only internally.
Also remove a redundant assignment after calling truncateRunQueue that
is already done within truncateRunQueue.
- - - - -
75bbdebc by Duncan Coutts at 2026-07-18T08:49:12-04:00
Rename initIOManager{AfterFork} to {re}startIOManager
These are more accurate names, since these actions happen after
initialisation and are really about starting (or restarting) background
threads.
- - - - -
724c0517 by Duncan Coutts at 2026-07-18T08:49:12-04:00
Free per-cap I/O managers during shutdown and forkProcess
Historically this was not strictly necessary. The select and win32
legacy I/O managers did not maintain any dynamically allocated
resources. The new poll one does (an auxillary table), and so this
should be freed.
After forkProcess, all threads get deleted. This includes threads
waiting on I/O or timers. So as of this patch, resetting the I/O
manager is just about tidying things up. For example, for the poll
I/O manager this will reset the size of the AIOP table (which
otherwise grows but never shrinks).
In future however the re-initialising will become neeecessary for
functionality, since some I/O managers will need to re-initialise
wakeup fds that are set CLOEXEC.
- - - - -
c007d122 by Duncan Coutts at 2026-07-18T08:49:12-04:00
Add a TODO to the MIO I/O manager
The direction of travel is to make I/O managers per-capability and have
all their state live in the struct CapIOManager. The MIO I/O manager
however still has a number of global variables.
It's not obvious how handle these globals however.
- - - - -
b65ab7b3 by Duncan Coutts at 2026-07-18T08:49:12-04:00
Add a FIXME note in the Poll I/O manager
- - - - -
daf2bd6f by Duncan Coutts at 2026-07-18T08:49:12-04:00
Add missing updateRemembSetPushClosure in poll I/O manager
For the non-moving GC.
- - - - -
e33ca830 by Duncan Coutts at 2026-07-18T08:49:12-04:00
Minor doc improvement to struct StgAsyncIOOp member outcome
Mention the enumeration names, as well as their numeric values. The rest
of the code uses the enum names.
- - - - -
4edd2579 by Duncan Coutts at 2026-07-18T08:49:12-04:00
Minor doc improvements for StgTSOBlockInfo
Clarify that certain union members are used only by certain legacy
I/O managers. Hopefully we will be able to remove these at some point.
- - - - -
536bedbb by Duncan Coutts at 2026-07-18T08:49:12-04:00
Avoid exporting various win32-specific rts symbols
The BeginPrivate.h / EndPrivate.h scheme works perfectly well on
Windows, but all of the rts/win32/*.h files were not using it.
- - - - -
8139b5ac by Duncan Coutts at 2026-07-18T08:49:12-04:00
Remove wakeupIOManager, ioManagerWakeup and setIOManagerWakeupFd
We no longer need wakeupIOManager for the threaded RTS case, so we can
remove it and the bits only needed to support it. This includes the
pipe/eventfd fd shared between the RTS and the in-library I/O manager
used for waking up the I/O manager thread. The pipe/eventfd still
exists, but it no longer has to be communicated to the RTS, since the
RTS no longer needs to use it.
So we remove the RTS API export setIOManagerWakeupFd, and remove uses of
it within the I/O managers in ghc-internal.
- - - - -
74fe7c66 by Duncan Coutts at 2026-07-18T08:49:12-04:00
Add a new interruptIOManager API for the I/O managers
It will be used to interrupt awaitCompletedTimeoutsOrIO. Also update the
return type and docs for awaitCompletedTimeoutsOrIO to have it return
false when it gets interrupted, and have no useful post condition in
that case.
- - - - -
38792843 by Duncan Coutts at 2026-07-18T08:49:13-04:00
Add interruptIOManager support for select I/O manager
Uses the FdWakup mechanism.
- - - - -
2f3b00aa by Duncan Coutts at 2026-07-18T08:49:13-04:00
Add interruptIOManager support for poll I/O manager
Uses the FdWakup mechanism.
A quirk we have to cope with is that we now need to poll one more fd --
the wakeup_fd_r -- but this fd has no corresponding entry in the
aiop_table. This is awkward since we have set up our aiop_poll_table to
be an auxilliary table with matching indicies.
The solution this patch uses (and described in the comments) is to have
two tables: struct pollfd *aiop_poll_table, *full_poll_table;
and to have the aiop_poll_table alias the tail of the full_poll_table.
The head entry in the full_poll_table is the extra fd. So we poll the
full_poll_table, while the aiop_poll_table still has matching indicies
with the aiop_table.
Hurrah for C aliasing rules.
- - - - -
cee50131 by Duncan Coutts at 2026-07-18T08:49:13-04:00
Add interruptIOManager support for win32 legacy I/O manager
And remove unused related helper resetAbandonRequestWait. It is not
called because the event is created in auto-reset mode, so never needs
to be reset manually.
- - - - -
cf453143 by Duncan Coutts at 2026-07-18T08:49:13-04:00
Note lack of interruptIOManager support for WinIO I/O manager
Though there's a plausible design, we can't sanely test it at the moment
due to related WinIO bugs. Filed as issue #27403.
- - - - -
1b74a0ad by Duncan Coutts at 2026-07-18T08:49:13-04:00
Be more explicit about enum IOReadOrWrite values, and type within cmm
Belt and braces.
- - - - -
b388d093 by Brian McKenna at 2026-07-18T17:51:50-04:00
Ignore ticks in the pattern-match term oracle
The term-oracle in the pattern-match checker is keyed by a canonical
form of the scrutinee, computed by `makeDictsCoherent`. That canonical
form was tick-sensitive: two occurrences of an otherwise identical
expression that happened to carry different ticks were treated as
distinct values, breaking long-distance information.
This shows up in practice under `-finfo-table-map`, because the
desugarer wraps every record-selector use site in a `SourceNote`
carrying that site's span. For example:
data Box = Box { unBox :: Maybe Int }
f b = case unBox b of
Nothing -> 0
Just _ -> let Just x = unBox b in x
The two `unBox b` expressionss carry different SourceNote spans, the
pattern-match checker sees them as different, the long-distance
information from the outer `Just _` branch never reaches the
let-pattern, and `Just x = unBox b` is wrongly reported as
non-exhaustive.
We now strip all ticks in `makeDictsCoherent`. This is documented as
Wrinkle (UD1) of Note [Unique dictionaries in the TmOracle CoreMap].
Fixes #27314
- - - - -
c23e1acb by Mrjtjmn at 2026-07-18T17:52:45-04:00
Add explanations for unsolved Typeable constraints
This commit adds explanations for unsolved 'Typeable' constraints.
GHC will now provide additional explanations for an unsolved constraint
of the form 'Typeable ty', explain why GHC did not solve Typeable constraint.
e.g.:
- 'ty' is a polymorphic type (e.g. forall a. a -> a)
- 'ty' is a qualified type (e.g. Eq Int => Int)
- 'ty' is an unboxed sum type
- 'ty' is an unreduced type family application
- 'ty' whose kind is not typeable
Fixes #26532
- - - - -
86456d69 by Alan Zimmerman at 2026-07-19T10:54:15+01:00
EPA: Keep decls together in ClassDecl
Similar to 1718230f4d3d19d8c49c0e5d496cb0fb6f399528 for HsValBindsLR,
this commit updates ClassDecl so that it no longer splits out the
assorted `LHsDecl GhcPs` until the renamer.
It does this by inserting a type family (separate from the classic TTG one) for this.
So
data TyClDecl
...
| ClassDecl {
...
tcdDecls :: XClassDecls pass
with
type instance XClassDecls GhcPs = [LHsDecl GhcPs]
type instance XClassDecls GhcRn = ClassDeclX GhcRn
type instance XClassDecls GhcTc = ClassDeclX GhcTc
data ClassDeclX pass
= ClassDeclX { tcdSigs :: [LSig pass], -- ^ Methods' signatures
tcdMeths :: LHsBinds pass, -- ^ Default methods
tcdATs :: [LFamilyDecl pass], -- ^ Associated types;
tcdATDefs :: [LTyFamDefltDecl pass], -- ^ Associated type defaults
tcdDocs :: [LDocDecl pass] -- ^ Haddock docs
}
- - - - -
1624043b by Alan Zimmerman at 2026-07-19T10:54:15+01:00
EPA: ClsInstDecl as list in GhcPs
- - - - -
5809dfcb by Alan Zimmerman at 2026-07-19T10:54:15+01:00
EPA: Remove LocatedP from OverlapMode
- - - - -
527ec7f5 by Alan Zimmerman at 2026-07-19T10:54:15+01:00
EPA: Remove LocatedP from CType
- - - - -
15ca9289 by Alan Zimmerman at 2026-07-19T10:54:15+01:00
EPA: Remove LocatedP, last use in WarningTxt
- - - - -
b99877e4 by Alan Zimmerman at 2026-07-19T10:54:15+01:00
EPA: Remove LocatedE from WarningCategory
- - - - -
0a301727 by Alan Zimmerman at 2026-07-19T10:54:15+01:00
EPA: Remove LocateE from XCImport and XCExport
- - - - -
e6220788 by Alan Zimmerman at 2026-07-19T10:54:15+01:00
EPA: Remove LocatedE from HsRecFields dot
- - - - -
7407d80c by Alan Zimmerman at 2026-07-19T10:54:15+01:00
EPA: Remove LocatedE completely, last usage for pats
- - - - -
5d2f5ea2 by Alan Zimmerman at 2026-07-19T10:54:15+01:00
EPA: Remove AnnList (EpToken "where") usages
This is moving toward removing the parameter from AnnList completely
- - - - -
6309ee9e by Alan Zimmerman at 2026-07-19T10:54:15+01:00
EPA remove AnnList (EpToken "rec") usages
- - - - -
796adadc by Alan Zimmerman at 2026-07-19T10:54:15+01:00
EPA: Remove last parameterised AnnList usage (EpaLocation)
Also remove the parameter
- - - - -
795b41a6 by Alan Zimmerman at 2026-07-19T10:54:15+01:00
TTG: Add extension points to BooleanFormula
They are currently unused, but will be used for exact print annotations next
- - - - -
5e268d04 by Alan Zimmerman at 2026-07-19T10:54:15+01:00
EPA: Remove LocatedBC / SrcSpanBF
- - - - -
56d5ec59 by Alan Zimmerman at 2026-07-19T10:54:15+01:00
EPA: remove unused addTrailingAnnToL. Squash appropriately
- - - - -
56bc2e75 by Alan Zimmerman at 2026-07-19T10:54:15+01:00
EPS: Remove NoEpTok/NoEpUniTok, using an unhelpful SrcSpan instead
Also introduce helper functions noEpTok and noEpUniTok to serve
as simple replacements in code inserting an token annotation without
location information.
- - - - -
754645b9 by Alan Zimmerman at 2026-07-19T21:09:43+01:00
EPA: Some haddock processing tweaks
- - - - -
dfbb9032 by Alan Zimmerman at 2026-07-19T21:09:43+01:00
Some haddock exactprint tests
- - - - -
3f23ad9c by Alan Zimmerman at 2026-07-19T21:09:43+01:00
EPA: When adding comments honour trailing anns
- - - - -
c8d69c1a by Alan Zimmerman at 2026-07-19T21:09:43+01:00
EPA: Uses Parsers.parseModule for exactprint tests
This is the advertised way to parse for use for exact printing in the
ghc-exactprint library, make sure we test using it.
- - - - -
20e322c4 by Alan Zimmerman at 2026-07-19T21:09:43+01:00
EPA Fix HsCmdDo exact print with comments
TODO: add test based on proc-do-complex-four-out.hs
- - - - -
143 changed files:
- + changelog.d/T26532
- + changelog.d/T27314.md
- + changelog.d/T27374
- compiler/GHC/Builtin/Utils.hs
- compiler/GHC/Core/Class.hs
- compiler/GHC/Core/Coercion/Opt.hs
- compiler/GHC/CoreToIface.hs
- compiler/GHC/Data/BooleanFormula.hs
- compiler/GHC/Hs.hs
- compiler/GHC/Hs/Binds.hs
- compiler/GHC/Hs/Decls.hs
- compiler/GHC/Hs/Decls/Overlap.hs
- compiler/GHC/Hs/Dump.hs
- compiler/GHC/Hs/Expr.hs
- compiler/GHC/Hs/Instances.hs
- compiler/GHC/Hs/Pat.hs
- compiler/GHC/Hs/Stats.hs
- compiler/GHC/Hs/Utils.hs
- compiler/GHC/HsToCore/Docs.hs
- compiler/GHC/HsToCore/Pmc/Solver.hs
- compiler/GHC/HsToCore/Quote.hs
- compiler/GHC/Iface/Ext/Ast.hs
- compiler/GHC/Iface/Syntax.hs
- compiler/GHC/Iface/Warnings.hs
- compiler/GHC/IfaceToCore.hs
- compiler/GHC/Parser.y
- compiler/GHC/Parser/Annotation.hs
- compiler/GHC/Parser/PostProcess.hs
- compiler/GHC/Parser/PostProcess/Haddock.hs
- compiler/GHC/Rename/Module.hs
- compiler/GHC/Rename/Names.hs
- compiler/GHC/Rename/Pat.hs
- compiler/GHC/Tc/Deriv.hs
- compiler/GHC/Tc/Errors.hs
- compiler/GHC/Tc/Errors/Ppr.hs
- compiler/GHC/Tc/Errors/Types.hs
- compiler/GHC/Tc/Instance/Typeable.hs
- compiler/GHC/Tc/TyCl.hs
- compiler/GHC/Tc/TyCl/Class.hs
- compiler/GHC/Tc/TyCl/Instance.hs
- compiler/GHC/Tc/Utils/Env.hs
- compiler/GHC/Tc/Utils/Instantiate.hs
- compiler/GHC/ThToHs.hs
- compiler/GHC/Types/ForeignCall.hs
- compiler/GHC/Unit/Module/Warnings.hs
- compiler/Language/Haskell/Syntax/Binds.hs
- compiler/Language/Haskell/Syntax/BooleanFormula.hs
- compiler/Language/Haskell/Syntax/Decls.hs
- compiler/Language/Haskell/Syntax/Extension.hs
- libraries/ghc-internal/src/GHC/Internal/Event/Control.hs
- libraries/ghc-internal/src/GHC/Internal/Event/Manager.hs
- libraries/ghc-internal/src/GHC/Internal/Event/TimerManager.hs
- rts/Capability.c
- rts/Capability.h
- rts/IOManager.c
- rts/IOManager.h
- rts/IOManagerInternals.h
- rts/PrimOps.cmm
- rts/RaiseAsync.c
- rts/RtsStartup.c
- rts/RtsSymbols.c
- rts/Schedule.c
- rts/Schedule.h
- rts/include/rts/IOInterface.h
- rts/include/rts/storage/Closures.h
- rts/include/rts/storage/TSO.h
- rts/posix/FdWakeup.h
- + rts/posix/MIO.c
- + rts/posix/MIO.h
- rts/posix/Poll.c
- rts/posix/Poll.h
- rts/posix/Select.c
- rts/posix/Select.h
- rts/posix/Signals.c
- rts/posix/Signals.h
- rts/posix/Timeout.c
- rts/posix/Timeout.h
- rts/rts.cabal
- rts/win32/AsyncMIO.c
- rts/win32/AsyncMIO.h
- rts/win32/AsyncWinIO.h
- rts/win32/AwaitEvent.c
- rts/win32/AwaitEvent.h
- rts/win32/ConsoleHandler.h
- rts/win32/MIOManager.h
- rts/win32/ThrIOManager.h
- rts/win32/WorkQueue.h
- rts/win32/veh_excn.h
- + testsuite/tests/corelint/T27374.hs
- testsuite/tests/corelint/all.T
- testsuite/tests/ghc-api/T25121_status.stdout
- testsuite/tests/ghc-api/exactprint/T22919.stderr
- testsuite/tests/ghc-api/exactprint/Test20239.stderr
- testsuite/tests/ghc-api/exactprint/ZeroWidthSemi.stderr
- testsuite/tests/haddock/haddock_examples/haddock.Test.stderr
- testsuite/tests/haddock/should_compile_flag_haddock/T17544.stderr
- testsuite/tests/haddock/should_compile_flag_haddock/T17544_kw.stderr
- testsuite/tests/haddock/should_compile_flag_haddock/T24221.stderr
- testsuite/tests/module/mod185.stderr
- testsuite/tests/parser/should_compile/DumpParsedAst.stderr
- testsuite/tests/parser/should_compile/DumpParsedAstComments.stderr
- testsuite/tests/parser/should_compile/DumpRenamedAst.stderr
- testsuite/tests/parser/should_compile/DumpSemis.stderr
- testsuite/tests/parser/should_compile/DumpTypecheckedAst.stderr
- testsuite/tests/parser/should_compile/KindSigs.stderr
- testsuite/tests/parser/should_compile/T14189.stderr
- testsuite/tests/parser/should_compile/T15279.stderr
- testsuite/tests/parser/should_compile/T15323.stderr
- testsuite/tests/parser/should_compile/T20452.stderr
- testsuite/tests/parser/should_compile/T20718.stderr
- testsuite/tests/parser/should_compile/T20718b.stderr
- testsuite/tests/parser/should_compile/T20846.stderr
- testsuite/tests/parser/should_compile/T23315/T23315.stderr
- + testsuite/tests/pmcheck/should_compile/T27314.hs
- testsuite/tests/pmcheck/should_compile/all.T
- testsuite/tests/printer/AnnotationNoListTuplePuns.stdout
- + testsuite/tests/printer/Haddock1.hs
- + testsuite/tests/printer/Haddock1.hs.ast1
- testsuite/tests/printer/Makefile
- testsuite/tests/printer/T18791.stderr
- testsuite/tests/printer/Test20297.stdout
- testsuite/tests/printer/Test24533.stdout
- testsuite/tests/printer/all.T
- testsuite/tests/typecheck/should_fail/T15067.stderr
- + testsuite/tests/typecheck/should_fail/T26532.hs
- + testsuite/tests/typecheck/should_fail/T26532.stderr
- testsuite/tests/typecheck/should_fail/T9858b.stderr
- testsuite/tests/typecheck/should_fail/TcStaticPointersFail02.stderr
- testsuite/tests/typecheck/should_fail/all.T
- utils/check-exact/ExactPrint.hs
- utils/check-exact/Main.hs
- utils/check-exact/Parsers.hs
- utils/check-exact/Transform.hs
- utils/check-exact/Utils.hs
- utils/deriveConstants/Main.hs
- utils/haddock/haddock-api/src/Haddock/Backends/Hoogle.hs
- utils/haddock/haddock-api/src/Haddock/Backends/LaTeX.hs
- utils/haddock/haddock-api/src/Haddock/Backends/Xhtml/Decl.hs
- utils/haddock/haddock-api/src/Haddock/Convert.hs
- utils/haddock/haddock-api/src/Haddock/GhcUtils.hs
- utils/haddock/haddock-api/src/Haddock/Interface/Create.hs
- utils/haddock/haddock-api/src/Haddock/Interface/Rename.hs
- utils/haddock/haddock-api/src/Haddock/Types.hs
The diff was not included because it is too large.
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/96504da1fae52081d74a5f96b515e6…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/96504da1fae52081d74a5f96b515e6…
You're receiving this email because of your account on gitlab.haskell.org. Manage all notifications: https://gitlab.haskell.org/-/profile/notifications | Help: https://gitlab.haskell.org/help
1
0
[Git][ghc/ghc][wip/az/epa-tidy-locatedxxx-8] 24 commits: Coercion optimisation: avoid double-Sym for InstCo
by Alan Zimmerman (@alanz) 19 Jul '26
by Alan Zimmerman (@alanz) 19 Jul '26
19 Jul '26
Alan Zimmerman pushed to branch wip/az/epa-tidy-locatedxxx-8 at Glasgow Haskell Compiler / GHC
Commits:
722236dd by sheaf at 2026-07-18T08:48:31-04:00
Coercion optimisation: avoid double-Sym for InstCo
Ticket #27374 pointed out an issue with GHC.Core.Coercion.Opt.optCoercion's
handling of InstCo: it contravened (LC2) in Note [The LiftingContext in optCoercion]
because it applied the ambient 'sym' to a coercion that was then added
to the lifting context substitution.
Fixes #27374
Co-authored-by: Simon Jakobi <simon.jakobi(a)gmail.com>
- - - - -
ff70fc75 by sheaf at 2026-07-18T08:48:31-04:00
Coercion optimisation: avoid exponential behaviour
The change to coercion optimisation of 'InstCo' in the previous commit
introduces exponential behaviour to the coercion optimiser. To avoid
this, this commit provides a way to push in 'Sym' of an already-optimised
coercion: GHC.Core.Coercion.Opt.mkDeepSymCo.
See Note [Pushing Sym without re-optimising] in GHC.Core.Coercion.Opt.
- - - - -
dfef27f0 by Duncan Coutts at 2026-07-18T08:49:12-04:00
Move THREADED_RTS-conditional struct members to end of Capability
Accessing members of the Capability struct from CMM code rely on
accessor macros. (The macros are generated by deriveConstants).
These macros have a single definition. This means that the offsets of
all struct members must *not* vary based on THREADED_RTS vs
!THREADED_RTS. This requires that any struct members that are
conditional on THREADED_RTS must occur after the unconditional struct
members. Hence we move all the ones that are conditional on
THREADED_RTS to the end.
Add a deriveConstants entry for the iomgr member of the Capability
struct, which was the motivation for this change.
Add warning messages to help our future selves. Debugging this took me
a couple hours in gdb!
- - - - -
c254e022 by Duncan Coutts at 2026-07-18T08:49:12-04:00
Make the IOManager API use CapIOManager rather than Capability
This makes the API somewhat more self-contained and more consistent.
Now the IOManager API and each of the backends takes just the I/O
manager structure. Previously we had a bit of a mixture, depending on
whether the function needed access to the Capability or just the
CapIOManager.
We still need access to the cap, so we introduce a back reference to
reach the capability, via iomgr->cap.
Convert all uses in select and poll backends, but not win32 ones.
Convert callers in the scheduler and elsewhere.
Also convert the three CMM primops that call IOManager APIs. They just
need to use Capability_iomgr(MyCapability()).
- - - - -
4f3d8f31 by Duncan Coutts at 2026-07-18T08:49:12-04:00
Split posix/MIO.c out of posix/Signals.c
The MIO I/O manager was secretly living inside the Signals file.
Now it gets its own file, like any other self-respecting I/O manager.
- - - - -
52ce04a9 by Duncan Coutts at 2026-07-18T08:49:12-04:00
Rationalise some scheduler run queue utilities
Move them all to the same place in the file.
Make some static that were used only internally.
Also remove a redundant assignment after calling truncateRunQueue that
is already done within truncateRunQueue.
- - - - -
75bbdebc by Duncan Coutts at 2026-07-18T08:49:12-04:00
Rename initIOManager{AfterFork} to {re}startIOManager
These are more accurate names, since these actions happen after
initialisation and are really about starting (or restarting) background
threads.
- - - - -
724c0517 by Duncan Coutts at 2026-07-18T08:49:12-04:00
Free per-cap I/O managers during shutdown and forkProcess
Historically this was not strictly necessary. The select and win32
legacy I/O managers did not maintain any dynamically allocated
resources. The new poll one does (an auxillary table), and so this
should be freed.
After forkProcess, all threads get deleted. This includes threads
waiting on I/O or timers. So as of this patch, resetting the I/O
manager is just about tidying things up. For example, for the poll
I/O manager this will reset the size of the AIOP table (which
otherwise grows but never shrinks).
In future however the re-initialising will become neeecessary for
functionality, since some I/O managers will need to re-initialise
wakeup fds that are set CLOEXEC.
- - - - -
c007d122 by Duncan Coutts at 2026-07-18T08:49:12-04:00
Add a TODO to the MIO I/O manager
The direction of travel is to make I/O managers per-capability and have
all their state live in the struct CapIOManager. The MIO I/O manager
however still has a number of global variables.
It's not obvious how handle these globals however.
- - - - -
b65ab7b3 by Duncan Coutts at 2026-07-18T08:49:12-04:00
Add a FIXME note in the Poll I/O manager
- - - - -
daf2bd6f by Duncan Coutts at 2026-07-18T08:49:12-04:00
Add missing updateRemembSetPushClosure in poll I/O manager
For the non-moving GC.
- - - - -
e33ca830 by Duncan Coutts at 2026-07-18T08:49:12-04:00
Minor doc improvement to struct StgAsyncIOOp member outcome
Mention the enumeration names, as well as their numeric values. The rest
of the code uses the enum names.
- - - - -
4edd2579 by Duncan Coutts at 2026-07-18T08:49:12-04:00
Minor doc improvements for StgTSOBlockInfo
Clarify that certain union members are used only by certain legacy
I/O managers. Hopefully we will be able to remove these at some point.
- - - - -
536bedbb by Duncan Coutts at 2026-07-18T08:49:12-04:00
Avoid exporting various win32-specific rts symbols
The BeginPrivate.h / EndPrivate.h scheme works perfectly well on
Windows, but all of the rts/win32/*.h files were not using it.
- - - - -
8139b5ac by Duncan Coutts at 2026-07-18T08:49:12-04:00
Remove wakeupIOManager, ioManagerWakeup and setIOManagerWakeupFd
We no longer need wakeupIOManager for the threaded RTS case, so we can
remove it and the bits only needed to support it. This includes the
pipe/eventfd fd shared between the RTS and the in-library I/O manager
used for waking up the I/O manager thread. The pipe/eventfd still
exists, but it no longer has to be communicated to the RTS, since the
RTS no longer needs to use it.
So we remove the RTS API export setIOManagerWakeupFd, and remove uses of
it within the I/O managers in ghc-internal.
- - - - -
74fe7c66 by Duncan Coutts at 2026-07-18T08:49:12-04:00
Add a new interruptIOManager API for the I/O managers
It will be used to interrupt awaitCompletedTimeoutsOrIO. Also update the
return type and docs for awaitCompletedTimeoutsOrIO to have it return
false when it gets interrupted, and have no useful post condition in
that case.
- - - - -
38792843 by Duncan Coutts at 2026-07-18T08:49:13-04:00
Add interruptIOManager support for select I/O manager
Uses the FdWakup mechanism.
- - - - -
2f3b00aa by Duncan Coutts at 2026-07-18T08:49:13-04:00
Add interruptIOManager support for poll I/O manager
Uses the FdWakup mechanism.
A quirk we have to cope with is that we now need to poll one more fd --
the wakeup_fd_r -- but this fd has no corresponding entry in the
aiop_table. This is awkward since we have set up our aiop_poll_table to
be an auxilliary table with matching indicies.
The solution this patch uses (and described in the comments) is to have
two tables: struct pollfd *aiop_poll_table, *full_poll_table;
and to have the aiop_poll_table alias the tail of the full_poll_table.
The head entry in the full_poll_table is the extra fd. So we poll the
full_poll_table, while the aiop_poll_table still has matching indicies
with the aiop_table.
Hurrah for C aliasing rules.
- - - - -
cee50131 by Duncan Coutts at 2026-07-18T08:49:13-04:00
Add interruptIOManager support for win32 legacy I/O manager
And remove unused related helper resetAbandonRequestWait. It is not
called because the event is created in auto-reset mode, so never needs
to be reset manually.
- - - - -
cf453143 by Duncan Coutts at 2026-07-18T08:49:13-04:00
Note lack of interruptIOManager support for WinIO I/O manager
Though there's a plausible design, we can't sanely test it at the moment
due to related WinIO bugs. Filed as issue #27403.
- - - - -
1b74a0ad by Duncan Coutts at 2026-07-18T08:49:13-04:00
Be more explicit about enum IOReadOrWrite values, and type within cmm
Belt and braces.
- - - - -
b388d093 by Brian McKenna at 2026-07-18T17:51:50-04:00
Ignore ticks in the pattern-match term oracle
The term-oracle in the pattern-match checker is keyed by a canonical
form of the scrutinee, computed by `makeDictsCoherent`. That canonical
form was tick-sensitive: two occurrences of an otherwise identical
expression that happened to carry different ticks were treated as
distinct values, breaking long-distance information.
This shows up in practice under `-finfo-table-map`, because the
desugarer wraps every record-selector use site in a `SourceNote`
carrying that site's span. For example:
data Box = Box { unBox :: Maybe Int }
f b = case unBox b of
Nothing -> 0
Just _ -> let Just x = unBox b in x
The two `unBox b` expressionss carry different SourceNote spans, the
pattern-match checker sees them as different, the long-distance
information from the outer `Just _` branch never reaches the
let-pattern, and `Just x = unBox b` is wrongly reported as
non-exhaustive.
We now strip all ticks in `makeDictsCoherent`. This is documented as
Wrinkle (UD1) of Note [Unique dictionaries in the TmOracle CoreMap].
Fixes #27314
- - - - -
c23e1acb by Mrjtjmn at 2026-07-18T17:52:45-04:00
Add explanations for unsolved Typeable constraints
This commit adds explanations for unsolved 'Typeable' constraints.
GHC will now provide additional explanations for an unsolved constraint
of the form 'Typeable ty', explain why GHC did not solve Typeable constraint.
e.g.:
- 'ty' is a polymorphic type (e.g. forall a. a -> a)
- 'ty' is a qualified type (e.g. Eq Int => Int)
- 'ty' is an unboxed sum type
- 'ty' is an unreduced type family application
- 'ty' whose kind is not typeable
Fixes #26532
- - - - -
86456d69 by Alan Zimmerman at 2026-07-19T10:54:15+01:00
EPA: Keep decls together in ClassDecl
Similar to 1718230f4d3d19d8c49c0e5d496cb0fb6f399528 for HsValBindsLR,
this commit updates ClassDecl so that it no longer splits out the
assorted `LHsDecl GhcPs` until the renamer.
It does this by inserting a type family (separate from the classic TTG one) for this.
So
data TyClDecl
...
| ClassDecl {
...
tcdDecls :: XClassDecls pass
with
type instance XClassDecls GhcPs = [LHsDecl GhcPs]
type instance XClassDecls GhcRn = ClassDeclX GhcRn
type instance XClassDecls GhcTc = ClassDeclX GhcTc
data ClassDeclX pass
= ClassDeclX { tcdSigs :: [LSig pass], -- ^ Methods' signatures
tcdMeths :: LHsBinds pass, -- ^ Default methods
tcdATs :: [LFamilyDecl pass], -- ^ Associated types;
tcdATDefs :: [LTyFamDefltDecl pass], -- ^ Associated type defaults
tcdDocs :: [LDocDecl pass] -- ^ Haddock docs
}
- - - - -
92 changed files:
- + changelog.d/T26532
- + changelog.d/T27314.md
- + changelog.d/T27374
- compiler/GHC/Core/Coercion/Opt.hs
- compiler/GHC/Hs/Decls.hs
- compiler/GHC/Hs/Instances.hs
- compiler/GHC/Hs/Stats.hs
- compiler/GHC/Hs/Utils.hs
- compiler/GHC/HsToCore/Docs.hs
- compiler/GHC/HsToCore/Pmc/Solver.hs
- compiler/GHC/HsToCore/Quote.hs
- compiler/GHC/Iface/Ext/Ast.hs
- compiler/GHC/Parser/PostProcess.hs
- compiler/GHC/Parser/PostProcess/Haddock.hs
- compiler/GHC/Rename/Module.hs
- compiler/GHC/Tc/Errors.hs
- compiler/GHC/Tc/Errors/Ppr.hs
- compiler/GHC/Tc/Errors/Types.hs
- compiler/GHC/Tc/Instance/Typeable.hs
- compiler/GHC/Tc/TyCl.hs
- compiler/GHC/Tc/TyCl/Class.hs
- compiler/GHC/ThToHs.hs
- compiler/Language/Haskell/Syntax/Binds.hs
- compiler/Language/Haskell/Syntax/Decls.hs
- compiler/Language/Haskell/Syntax/Extension.hs
- libraries/ghc-internal/src/GHC/Internal/Event/Control.hs
- libraries/ghc-internal/src/GHC/Internal/Event/Manager.hs
- libraries/ghc-internal/src/GHC/Internal/Event/TimerManager.hs
- rts/Capability.c
- rts/Capability.h
- rts/IOManager.c
- rts/IOManager.h
- rts/IOManagerInternals.h
- rts/PrimOps.cmm
- rts/RaiseAsync.c
- rts/RtsStartup.c
- rts/RtsSymbols.c
- rts/Schedule.c
- rts/Schedule.h
- rts/include/rts/IOInterface.h
- rts/include/rts/storage/Closures.h
- rts/include/rts/storage/TSO.h
- rts/posix/FdWakeup.h
- + rts/posix/MIO.c
- + rts/posix/MIO.h
- rts/posix/Poll.c
- rts/posix/Poll.h
- rts/posix/Select.c
- rts/posix/Select.h
- rts/posix/Signals.c
- rts/posix/Signals.h
- rts/posix/Timeout.c
- rts/posix/Timeout.h
- rts/rts.cabal
- rts/win32/AsyncMIO.c
- rts/win32/AsyncMIO.h
- rts/win32/AsyncWinIO.h
- rts/win32/AwaitEvent.c
- rts/win32/AwaitEvent.h
- rts/win32/ConsoleHandler.h
- rts/win32/MIOManager.h
- rts/win32/ThrIOManager.h
- rts/win32/WorkQueue.h
- rts/win32/veh_excn.h
- + testsuite/tests/corelint/T27374.hs
- testsuite/tests/corelint/all.T
- testsuite/tests/haddock/haddock_examples/haddock.Test.stderr
- testsuite/tests/haddock/should_compile_flag_haddock/T17544.stderr
- testsuite/tests/haddock/should_compile_flag_haddock/T17544_kw.stderr
- testsuite/tests/parser/should_compile/DumpRenamedAst.stderr
- testsuite/tests/parser/should_compile/DumpSemis.stderr
- testsuite/tests/parser/should_compile/T20452.stderr
- + testsuite/tests/pmcheck/should_compile/T27314.hs
- testsuite/tests/pmcheck/should_compile/all.T
- testsuite/tests/printer/Test24533.stdout
- testsuite/tests/typecheck/should_fail/T15067.stderr
- + testsuite/tests/typecheck/should_fail/T26532.hs
- + testsuite/tests/typecheck/should_fail/T26532.stderr
- testsuite/tests/typecheck/should_fail/T9858b.stderr
- testsuite/tests/typecheck/should_fail/TcStaticPointersFail02.stderr
- testsuite/tests/typecheck/should_fail/all.T
- utils/check-exact/ExactPrint.hs
- utils/check-exact/Utils.hs
- utils/deriveConstants/Main.hs
- utils/haddock/haddock-api/src/Haddock/Backends/Hoogle.hs
- utils/haddock/haddock-api/src/Haddock/Backends/LaTeX.hs
- utils/haddock/haddock-api/src/Haddock/Backends/Xhtml/Decl.hs
- utils/haddock/haddock-api/src/Haddock/Convert.hs
- utils/haddock/haddock-api/src/Haddock/GhcUtils.hs
- utils/haddock/haddock-api/src/Haddock/Interface/Create.hs
- utils/haddock/haddock-api/src/Haddock/Interface/Rename.hs
- utils/haddock/haddock-api/src/Haddock/Types.hs
The diff was not included because it is too large.
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/57ec828fc520eba3106d85aad4407d…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/57ec828fc520eba3106d85aad4407d…
You're receiving this email because of your account on gitlab.haskell.org. Manage all notifications: https://gitlab.haskell.org/-/profile/notifications | Help: https://gitlab.haskell.org/help
1
0
[Git][ghc/ghc][wip/27380] parser: don't suggest ImportQualifiedPost when it is already enabled
by Sasha Bogicevic (@Bogicevic) 19 Jul '26
by Sasha Bogicevic (@Bogicevic) 19 Jul '26
19 Jul '26
Sasha Bogicevic pushed to branch wip/27380 at Glasgow Haskell Compiler / GHC
Commits:
9c420942 by Sasha Bogicevic at 2026-07-19T21:37:28+02:00
parser: don't suggest ImportQualifiedPost when it is already enabled
-Wprepositive-qualified-module unconditionally attached a hint to
enable ImportQualifiedPost, even when the extension was already on
(as it is by default under GHC2021). Record the extension's state in
the PsWarnImportPreQualified diagnostic and drop the hint when it is
already enabled.
Fixes #27380
- - - - -
8 changed files:
- + changelog.d/27380
- compiler/GHC/Parser/Errors/Ppr.hs
- compiler/GHC/Parser/Errors/Types.hs
- compiler/GHC/Parser/PostProcess.hs
- + testsuite/tests/module/T27380.hs
- + testsuite/tests/module/T27380.stderr
- testsuite/tests/module/all.T
- testsuite/tests/module/mod184.stderr
Changes:
=====================================
changelog.d/27380
=====================================
@@ -0,0 +1,7 @@
+section: compiler
+synopsis: Don't suggest enabling ``ImportQualifiedPost`` when it is already enabled.
+ The :ghc-flag:`-Wprepositive-qualified-module` warning no longer suggests
+ enabling the extension if it is already in effect (as it is by default
+ under GHC2021).
+issues: #27380
+mrs: !16376
=====================================
compiler/GHC/Parser/Errors/Ppr.hs
=====================================
@@ -113,7 +113,7 @@ instance Diagnostic PsMessage where
<> if null prag then empty else text ":" <+> text prag
PsWarnMisplacedPragma prag
-> mkSimpleDecorated $ text "Misplaced" <+> pprFileHeaderPragmaType prag <+> text "pragma"
- PsWarnImportPreQualified
+ PsWarnImportPreQualified _iqp_on
-> mkSimpleDecorated $
text "Found" <+> quotes (text "qualified")
<+> text "in prepositive position"
@@ -603,7 +603,7 @@ instance Diagnostic PsMessage where
PsWarnStarIsType -> WarningWithFlag Opt_WarnStarIsType
PsWarnUnrecognisedPragma{} -> WarningWithFlag Opt_WarnUnrecognisedPragmas
PsWarnMisplacedPragma{} -> WarningWithFlag Opt_WarnMisplacedPragmas
- PsWarnImportPreQualified -> WarningWithFlag Opt_WarnPrepositiveQualifiedModule
+ PsWarnImportPreQualified{} -> WarningWithFlag Opt_WarnPrepositiveQualifiedModule
PsWarnViewPatternSignatures{} -> WarningWithFlag Opt_WarnViewPatternSignatures
PsErrLexer{} -> ErrorWithoutFlag
PsErrCmmLexer -> ErrorWithoutFlag
@@ -735,8 +735,10 @@ instance Diagnostic PsMessage where
then noHints
else [SuggestCorrectPragmaName suggestions]
PsWarnMisplacedPragma{} -> [SuggestPlacePragmaInHeader]
- PsWarnImportPreQualified -> [ SuggestQualifiedAfterModuleName
- , suggestExtension LangExt.ImportQualifiedPost]
+ PsWarnImportPreQualified iqp_on | iqp_on -> [ SuggestQualifiedAfterModuleName ]
+ | otherwise -> [ SuggestQualifiedAfterModuleName
+ , suggestExtension LangExt.ImportQualifiedPost
+ ]
PsWarnViewPatternSignatures{} -> [SuggestParenthesizePatternRHS]
PsErrLexer{} -> noHints
PsErrCmmLexer -> noHints
=====================================
compiler/GHC/Parser/Errors/Types.hs
=====================================
@@ -133,7 +133,7 @@ data PsMessage
| PsWarnStarIsType
-- | Pre qualified import with 'WarnPrepositiveQualifiedModule' enabled
- | PsWarnImportPreQualified
+ | PsWarnImportPreQualified !Bool -- is 'ImportQualifiedPost' enabled?
| PsWarnOperatorWhitespaceExtConflict !OperatorWhitespaceSymbol
=====================================
compiler/GHC/Parser/PostProcess.hs
=====================================
@@ -1327,7 +1327,7 @@ checkImportDecl mPre mPost preLevel postLevel = do
-- Warn if 'qualified' found in prepositive position and
-- 'Opt_WarnPrepositiveQualifiedModule' is enabled.
whenJust mPre $ \pre ->
- warnPrepositiveQualifiedModule (tokenSpan pre)
+ warnPrepositiveQualifiedModule (tokenSpan pre) importQualifiedPostEnabled
return (qualSpec, levelSpec)
@@ -3499,9 +3499,9 @@ isImpExpQcWildcard _ = False
-----------------------------------------------------------------------------
-- Warnings and failures
-warnPrepositiveQualifiedModule :: SrcSpan -> P ()
-warnPrepositiveQualifiedModule span =
- addPsMessage span PsWarnImportPreQualified
+warnPrepositiveQualifiedModule :: SrcSpan -> Bool -> P ()
+warnPrepositiveQualifiedModule span qualifiedPostEnabled =
+ addPsMessage span $ PsWarnImportPreQualified qualifiedPostEnabled
failNotEnabledImportQualifiedPost :: SrcSpan -> P ()
failNotEnabledImportQualifiedPost loc =
=====================================
testsuite/tests/module/T27380.hs
=====================================
@@ -0,0 +1,7 @@
+{-# LANGUAGE NoImportQualifiedPost #-}
+{-# OPTIONS_GHC -Wprepositive-qualified-module #-}
+-- Negative control for #27380: with the extension explicitly disabled,
+-- the ImportQualifiedPost suggestion must still appear.
+import qualified System.IO
+main :: IO ()
+main = System.IO.print "hi"
=====================================
testsuite/tests/module/T27380.stderr
=====================================
@@ -0,0 +1,6 @@
+T27380.hs:5:8: warning: [GHC-07924] [-Wprepositive-qualified-module]
+ Found ‘qualified’ in prepositive position
+ Suggested fixes:
+ • Place ‘qualified’ after the module name.
+ • Perhaps you intended to use the ‘ImportQualifiedPost’ extension
+
=====================================
testsuite/tests/module/all.T
=====================================
@@ -295,3 +295,4 @@ test('T21826', normal, compile_fail, [''])
test('T20007', normal, compile_fail, [''])
test('T25901_imp_plain_wc', normal, compile_fail, [''])
test('T25901_exp_plain_wc', normal, compile_fail, [''])
+test('T27380', normal, compile, [''])
=====================================
testsuite/tests/module/mod184.stderr
=====================================
@@ -1,6 +1,4 @@
-
mod184.hs:6:8: warning: [GHC-07924] [-Wprepositive-qualified-module]
Found ‘qualified’ in prepositive position
- Suggested fixes:
- • Place ‘qualified’ after the module name.
- • Perhaps you intended to use the ‘ImportQualifiedPost’ extension
+ Suggested fix: Place ‘qualified’ after the module name.
+
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/9c420942aa07a1b302c6b8969099b73…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/9c420942aa07a1b302c6b8969099b73…
You're receiving this email because of your account on gitlab.haskell.org. Manage all notifications: https://gitlab.haskell.org/-/profile/notifications | Help: https://gitlab.haskell.org/help
1
0
Sasha Bogicevic pushed new branch wip/27380 at Glasgow Haskell Compiler / GHC
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/tree/wip/27380
You're receiving this email because of your account on gitlab.haskell.org. Manage all notifications: https://gitlab.haskell.org/-/profile/notifications | Help: https://gitlab.haskell.org/help
1
0
[Git][ghc/ghc][wip/andreask/deep-discounts-2026] 3 commits: Respect unfolding depth when creating unfoldings
by Andreas Klebinger (@AndreasK) 19 Jul '26
by Andreas Klebinger (@AndreasK) 19 Jul '26
19 Jul '26
Andreas Klebinger pushed to branch wip/andreask/deep-discounts-2026 at Glasgow Haskell Compiler / GHC
Commits:
957eb82e by Andreas Klebinger at 2026-07-18T16:53:53+00:00
Respect unfolding depth when creating unfoldings
- - - - -
651770ba by Andreas Klebinger at 2026-07-19T06:47:05+00:00
Clarify comment.
- - - - -
58f3327a by Andreas Klebinger at 2026-07-19T07:12:30+00:00
Short circuit for non-conlike vars
- - - - -
2 changed files:
- compiler/GHC/Core/Opt/Simplify/Inline.hs
- compiler/GHC/Core/Unfold.hs
Changes:
=====================================
compiler/GHC/Core/Opt/Simplify/Inline.hs
=====================================
@@ -923,12 +923,11 @@ interestingArg env e =
ConArg con fn_args
| isClassTyCon (dataConTyCon con) -> ValueArg
| otherwise ->
- -- fn_args can be non-empty if the head of the application is
- -- a variable whose unfolding is a partially applied constructor
- -- application (see the first clause of go_var). In that case the
- -- args from the unfolding come before the args of this
- -- application, e.g. for `v ys` with `v = (:) x` we get
- -- ConArg (:) [x_summary, ys_summary].
+ -- fn_args are the arguments already applied inside `fn`
+ -- in case `fn` is a variable representing a partial application.
+ -- For example if we have `v xs` with `v` unfolding into `(: x)`.
+ -- In that case we will get:
+ -- ConArg (:) [x_summary, xs_summary].
ConArg con (fn_args ++ arg_summaries)
_ -> fn_summary
@@ -947,7 +946,9 @@ interestingArg env e =
env' = env `addNewInScopeBndr` b
go_var depth n v
- | Just rhs <- maybeUnfoldingTemplate (idUnfolding v)
+ | unf <- (idUnfolding v)
+ , isConLikeUnfolding unf
+ , Just rhs <- maybeUnfoldingTemplate unf
, Just con_app <- isConApp_maybe rhs
= con_app
=====================================
compiler/GHC/Core/Unfold.hs
=====================================
@@ -693,7 +693,7 @@ sizeExpr opts !bOMB_OUT_SIZE top_args' expr
| Just v <- is_top_arg e
= let
-- Compute size of alternatives
- alt_sizes = map (size_up_alt depth (Just v) arg_comps) alts
+ alt_sizes = map (size_up_alt (depth-1) (Just v) arg_comps) alts
-- Apply a discount for a given constructor that brings the size down to just
-- the size of the alternative.
@@ -747,7 +747,7 @@ sizeExpr opts !bOMB_OUT_SIZE top_args' expr
size_up !depth arg_comps (Case e _ _ alts) = size_up depth arg_comps e `addSizeNSD`
- foldr (addAltSize . (size_up_alt depth Nothing arg_comps) ) case_size alts
+ foldr (addAltSize . (size_up_alt (depth-1) Nothing arg_comps) ) case_size alts
where
case_size
| is_inline_scrut e, lengthAtMost alts 1 = sizeN (-10)
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/551b9ccadbd91155770a8aa940b509…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/551b9ccadbd91155770a8aa940b509…
You're receiving this email because of your account on gitlab.haskell.org. Manage all notifications: https://gitlab.haskell.org/-/profile/notifications | Help: https://gitlab.haskell.org/help
1
0
[Git][ghc/ghc][wip/21101] Improve error messages for invalid record wildcards
by Sasha Bogicevic (@Bogicevic) 19 Jul '26
by Sasha Bogicevic (@Bogicevic) 19 Jul '26
19 Jul '26
Sasha Bogicevic pushed to branch wip/21101 at Glasgow Haskell Compiler / GHC
Commits:
73dd146c by Sasha Bogicevic at 2026-07-19T19:48:52+02:00
Improve error messages for invalid record wildcards
Record wildcard hints are now shown in more contexts and include
constructor arity; matching with `..` on a fieldless constructor
now produces a dedicated error message.
Fixes #21101
- - - - -
17 changed files:
- + changelog.d/21101
- compiler/GHC/Hs/Utils.hs
- compiler/GHC/Rename/Env.hs
- compiler/GHC/Rename/Names.hs
- compiler/GHC/Rename/Pat.hs
- compiler/GHC/Tc/Errors/Ppr.hs
- compiler/GHC/Tc/Errors/Types.hs
- compiler/GHC/Types/GREInfo.hs
- compiler/GHC/Types/Hint.hs
- compiler/GHC/Types/Hint/Ppr.hs
- + testsuite/tests/rename/should_fail/T21101.hs
- + testsuite/tests/rename/should_fail/T21101.stderr
- testsuite/tests/rename/should_fail/T9815.stderr
- testsuite/tests/rename/should_fail/T9815b.stderr
- testsuite/tests/rename/should_fail/T9815bghci.stderr
- testsuite/tests/rename/should_fail/T9815ghci.stderr
- testsuite/tests/rename/should_fail/all.T
Changes:
=====================================
changelog.d/21101
=====================================
@@ -0,0 +1,8 @@
+section: compiler
+synopsis: Improve error messages and hints for invalid record wildcards
+description:
+ Record wildcard hints are now shown in more contexts and include
+ constructor arity; matching with ``..`` on a fieldless constructor
+ now produces a dedicated error message.
+mrs: !8673
+issues: #21101
=====================================
compiler/GHC/Hs/Utils.hs
=====================================
@@ -1613,8 +1613,8 @@ hsConDeclsBinders in the following format:
with its record fields, in the form of a list of Int indices into...
- IntMap FieldOcc, an IntMap of record fields.
-(In actual fact, we use [(ConRdrName, Maybe [Located Int])], with Nothing indicating
-that the constructor has unlabelled fields: see Note [Local constructor info in the renamer]
+(In actual fact, we use [(ConRdrName, Either VisArity [Located Int])], with Left n indicating
+that the constructor has n unlabelled arguments: see Note [Local constructor info in the renamer]
in GHC.Types.GREInfo.)
This allows us to do the following (see GHC.Rename.Names.getLocalNonValBinders.new_tc):
@@ -1635,7 +1635,7 @@ Other relevant test cases: rnfail015.
-- See Note [Collecting record fields in data declarations].
data LConsWithFields p =
LConsWithFields
- { consWithFieldIndices :: [(LocatedA (IdP (GhcPass p)), Maybe [Located Int])]
+ { consWithFieldIndices :: [(LocatedA (IdP (GhcPass p)), Either VisArity [Located Int])]
, consFields :: IntMap (LFieldOcc (GhcPass p))
}
@@ -1675,16 +1675,15 @@ hsConDeclsBinders cons = go emptyFieldIndices cons
LConsWithFields ns fs = go seen' rs
get_flds_h98 :: FieldIndices p -> HsConDeclH98Details (GhcPass p)
- -> (Maybe [Located Int], FieldIndices p)
- get_flds_h98 seen (RecCon _ flds) = first Just $ get_flds seen flds
- get_flds_h98 seen (PrefixCon _ []) = (Just [], seen)
- get_flds_h98 seen _ = (Nothing, seen)
+ -> (Either VisArity [Located Int], FieldIndices p)
+ get_flds_h98 seen (RecCon _ flds) = first Right $ get_flds seen flds
+ get_flds_h98 seen (PrefixCon _ args) = (Left (length args), seen)
+ get_flds_h98 seen (InfixCon {}) = (Left 2, seen)
get_flds_gadt :: FieldIndices p -> HsConDeclGADTDetails (GhcPass p)
- -> (Maybe [Located Int], FieldIndices p)
- get_flds_gadt seen (RecConGADT _ flds) = first Just $ get_flds seen flds
- get_flds_gadt seen (PrefixConGADT _ []) = (Just [], seen)
- get_flds_gadt seen _ = (Nothing, seen)
+ -> (Either VisArity [Located Int], FieldIndices p)
+ get_flds_gadt seen (RecConGADT _ flds) = first Right $ get_flds seen flds
+ get_flds_gadt seen (PrefixConGADT _ args) = (Left (length args), seen)
get_flds :: FieldIndices p -> LocatedA [LHsConDeclRecField (GhcPass p)]
-> ([Located Int], FieldIndices p)
=====================================
compiler/GHC/Rename/Env.hs
=====================================
@@ -423,7 +423,12 @@ lookupConstructorInfo qcon@(WithUserRdr _ con_name)
= do { info <- lookupGREInfo_GRE con_name
; case info of
IAmConLike con_info -> return con_info
- UnboundGRE -> return $ ConInfo (ConIsData []) ConHasPositionalArgs
+ UnboundGRE -> return $ ConInfo (ConIsData []) (ConHasPositionalArgs 0)
+ -- NB: it's OK to use the dummy value of '0' for the constructor arity:
+ -- we only use this information for 'TcRnIllegalWildcardsInConstructor',
+ -- which is an error we don't emit when the constructor is unbound.
+ -- See GHC.Rename.Pat.rnHsRecFields.rn_dotdot.
+
IAmTyCon {} -> failIllegalTyCon WL_ConLike qcon
_ -> pprPanic "lookupConstructorInfo: not a ConLike" $
vcat [ text "name:" <+> ppr con_name ]
=====================================
compiler/GHC/Rename/Names.hs
=====================================
@@ -71,7 +71,7 @@ import GHC.Types.FieldLabel
import GHC.Types.Hint
import GHC.Types.SourceFile
import GHC.Types.SrcLoc as SrcLoc
-import GHC.Types.Basic ( TyConFlavour (..), convImportLevel )
+import GHC.Types.Basic (TyConFlavour (..), convImportLevel, VisArity)
import GHC.Types.Id
import GHC.Types.PkgQual
import GHC.Types.GREInfo (ConInfo(..), ConFieldInfo (..), ConLikeInfo (ConIsData))
@@ -875,15 +875,16 @@ getLocalNonValBinders fixity_env
--
-- The information we needed was all set up for us:
-- see Note [Collecting record fields in data declarations] in GHC.Hs.Utils.
- mk_fld_env :: [(Name, Maybe [Located Int])] -> IntMap FieldLabel
+ mk_fld_env :: [(Name, Either VisArity [Located Int])] -> IntMap FieldLabel
-> [(ConLikeName, ConInfo)]
mk_fld_env names flds =
[ (DataConName con, ConInfo (ConIsData (map fst names)) fld_info)
- | (con, mb_fl_indxs) <- names
- , let fld_info = case fmap (map ((flds IntMap.!) . unLoc)) mb_fl_indxs of
- Nothing -> ConHasPositionalArgs
- Just [] -> ConIsNullary
- Just (fld:flds) -> ConHasRecordFields $ fld NE.:| flds ]
+ | (con, con_fl_indxs) <- names
+ , let fld_info = case fmap (map ((flds IntMap.!) . unLoc)) con_fl_indxs of
+ Left 0 -> ConIsNullary
+ Left arity -> ConHasPositionalArgs arity
+ Right [] -> ConIsNullary
+ Right (fld:flds) -> ConHasRecordFields $ fld NE.:| flds ]
new_assoc :: DuplicateRecordFields -> FieldSelectors -> LInstDecl GhcPs
-> RnM [GlobalRdrElt]
@@ -939,10 +940,10 @@ getLocalNonValBinders fixity_env
-- Add errors if a constructor has a duplicate record field.
add_dup_fld_errs :: IntMap FieldLabel
- -> (Name, Maybe [Located Int])
+ -> (Name, Either VisArity [Located Int])
-> IOEnv (Env TcGblEnv TcLclEnv) ()
- add_dup_fld_errs all_flds (con, mb_con_flds)
- | Just con_flds <- mb_con_flds
+ add_dup_fld_errs all_flds (con, con_flds_or_arity)
+ | Right con_flds <- con_flds_or_arity
, let (_, dups) = removeDups (comparing unLoc) con_flds
= for_ dups $ \ dup_flds ->
-- Report the error at the location of the second occurrence
=====================================
compiler/GHC/Rename/Pat.hs
=====================================
@@ -874,7 +874,10 @@ rnHsRecFields ctxt mk_arg (HsRecFields { rec_flds = flds, rec_dotdot = dotdot })
; checkErr dd_flag (needFlagDotDot ctxt)
; (rdr_env, lcl_env) <- getRdrEnvs
; conInfo <- lookupConstructorInfo qcon
- ; when (conFieldInfo conInfo == ConHasPositionalArgs) (addErr (TcRnIllegalWildcardsInConstructor con))
+ ; case conFieldInfo conInfo of
+ ConHasPositionalArgs nbArgs ->
+ addErr $ TcRnIllegalWildcardsInConstructor (toRecordFieldPart ctxt) con nbArgs
+ _ -> return ()
; let present_flds = mkOccSet $ map rdrNameOcc (getFieldRdrs flds)
-- For constructor uses (but not patterns)
=====================================
compiler/GHC/Tc/Errors/Ppr.hs
=====================================
@@ -357,12 +357,12 @@ instance Diagnostic TcRnMessage where
-> mkSimpleDecorated $ vcat [text "Illegal view pattern: " <+> ppr pat]
TcRnCharLiteralOutOfRange c
-> mkSimpleDecorated $ text "character literal out of range: '\\" <> char c <> char '\''
- TcRnIllegalWildcardsInConstructor con
+ TcRnIllegalWildcardsInConstructor ctx con _
-> mkSimpleDecorated $
- vcat [ text "Illegal `{..}' notation for constructor" <+> quotes (ppr con)
- , nest 2 (text "Record wildcards may not be used for constructors with unlabelled fields.")
- , nest 2 (text "Possible fix: Remove the `{..}' and add a match for each field of the constructor.")
- ]
+ text "The data constructor" <+> quotes (ppr con)
+ <+> text "does not have named record fields, so the record"
+ <+> pprRecordFieldPart ctx
+ <+> quotes (ppr con <> text "{..}") <+> text "is invalid."
TcRnIgnoringAnnotations anns
-> mkSimpleDecorated $
text "Ignoring ANN annotation" <> plural anns <> comma
@@ -2791,8 +2791,12 @@ instance Diagnostic TcRnMessage where
-> [suggestExtension LangExt.ViewPatterns]
TcRnCharLiteralOutOfRange{}
-> noHints
- TcRnIllegalWildcardsInConstructor{}
- -> noHints
+ TcRnIllegalWildcardsInConstructor ctx con arity
+ -> case ctx of
+ RecordFieldPattern{} -> [ SuggestEmptyRecordBraces con
+ , SuggestExplicitConstructorArguments con arity
+ ]
+ _ -> [SuggestExplicitConstructorArguments con arity]
TcRnIgnoringAnnotations{}
-> noHints
TcRnAnnotationInSafeHaskell
=====================================
compiler/GHC/Tc/Errors/Types.hs
=====================================
@@ -818,17 +818,35 @@ data TcRnMessage where
TcRnNegativeNumTypeLiteral :: IntegralLit GhcRn -> TcRnMessage
{-| TcRnIllegalWildcardsInConstructor is an error that occurs whenever
- the record wildcards '..' are used inside a constructor without labeled fields.
+ the record wildcards '..' are used with a constructor whose fields are
+ positional (unlabelled). The 'RecordFieldPart' field records whether
+ the wildcards occurred in a record construction (an expression) or in
+ a record pattern, so that the message and its suggested fixes can be
+ worded accordingly. Constructors with no fields at all do not trigger
+ this error: since GHC proposal 496 ("Nullary record wildcards"),
+ @C {..}@ is legal for nullary constructors.
+ Example(s):
- Examples(s): None
+ data D = D Int Bool
+
+ f :: D -> ()
+ f D{..} = () -- record pattern
+
+ g :: D
+ g = D{..} -- record construction
Test cases:
rename/should_fail/T9815.hs
rename/should_fail/T9815b.hs
rename/should_fail/T9815ghci.hs
rename/should_fail/T9815bghci.hs
+ rename/should_fail/T21101.hs
-}
- TcRnIllegalWildcardsInConstructor :: !Name -> TcRnMessage
+ TcRnIllegalWildcardsInConstructor
+ :: !RecordFieldPart -- ^ context in which the constructor application occurs
+ -> !Name -- ^ name of the constructor
+ -> !VisArity -- ^ arity of the constructor
+ -> TcRnMessage
{-| TcRnIgnoringAnnotations is a warning that occurs when the source code
contains annotation pragmas but the platform in use does not support an
=====================================
compiler/GHC/Types/GREInfo.hs
=====================================
@@ -244,14 +244,14 @@ instance NFData ConLikeInfo where
-- See Note [Local constructor info in the renamer]
data ConFieldInfo
= ConHasRecordFields (NonEmpty FieldLabel)
- | ConHasPositionalArgs
+ | ConHasPositionalArgs !VisArity
| ConIsNullary
deriving stock Eq
deriving Data
instance NFData ConFieldInfo where
rnf ConIsNullary = ()
- rnf ConHasPositionalArgs = ()
+ rnf (ConHasPositionalArgs arity) = rnf arity
rnf (ConHasRecordFields flds) = rnf flds
mkConInfo :: ConLikeInfo -> VisArity -> [FieldLabel] -> ConInfo
@@ -259,9 +259,9 @@ mkConInfo con_ty n flds =
ConInfo { conLikeInfo = con_ty
, conFieldInfo = mkConFieldInfo n flds }
-mkConFieldInfo :: Arity -> [FieldLabel] -> ConFieldInfo
+mkConFieldInfo :: VisArity -> [FieldLabel] -> ConFieldInfo
mkConFieldInfo 0 _ = ConIsNullary
-mkConFieldInfo _ fields = maybe ConHasPositionalArgs ConHasRecordFields
+mkConFieldInfo arity fields = maybe (ConHasPositionalArgs arity) ConHasRecordFields
$ NonEmpty.nonEmpty fields
conInfoFields :: ConInfo -> [FieldLabel]
@@ -269,7 +269,7 @@ conInfoFields = conFieldInfoFields . conFieldInfo
conFieldInfoFields :: ConFieldInfo -> [FieldLabel]
conFieldInfoFields (ConHasRecordFields fields) = NonEmpty.toList fields
-conFieldInfoFields ConHasPositionalArgs = []
+conFieldInfoFields (ConHasPositionalArgs _) = []
conFieldInfoFields ConIsNullary = []
instance Outputable ConInfo where
@@ -284,7 +284,7 @@ instance Outputable ConLikeInfo where
instance Outputable ConFieldInfo where
ppr ConIsNullary = text "ConIsNullary"
- ppr ConHasPositionalArgs = text "ConHasPositionalArgs"
+ ppr (ConHasPositionalArgs arity) = text "ConHasPositionalArgs" <+> braces (ppr arity)
ppr (ConHasRecordFields fieldLabels) =
text "ConHasRecordFields" <+> braces (ppr fieldLabels)
=====================================
compiler/GHC/Types/Hint.hs
=====================================
@@ -45,7 +45,7 @@ import GHC.Types.InlinePragma (ActivationGhc)
import GHC.Types.Name (Name, NameSpace, OccName (occNameFS), isSymOcc, nameOccName)
import GHC.Types.Name.Reader (RdrName (Unqual), ImpDeclSpec, GlobalRdrElt)
import GHC.Types.SrcLoc (SrcSpan)
-import GHC.Types.Basic (RuleName)
+import GHC.Types.Basic (RuleName, VisArity)
import GHC.Parser.Errors.Basic
import GHC.Utils.Outputable
import GHC.Data.FastString (fsLit)
@@ -548,6 +548,23 @@ data GhcHint
| SuggestUpgradeForSemaphoreVersionMismatch !SemaphoreUpgradeTarget !Int
-- ^ The 'Int' is the required protocol version.
+ {-| Suggest replacing a record wildcard pattern @C {..}@ with @C {}@,
+ which matches a constructor without binding its fields.
+
+ Triggered by 'GHC.Tc.Errors.Types.TcRnIllegalWildcardsInConstructor'
+ in a record pattern.
+ -}
+ | SuggestEmptyRecordBraces !Name
+
+ {-| Suggest applying a constructor directly to its arguments instead
+ of record syntax, for constructors without labelled fields.
+
+ Triggered by 'GHC.Tc.Errors.Types.TcRnIllegalWildcardsInConstructor'
+ in a record construction and record patterns.
+ The 'VisArity' is the number of positional arguments of the constructor.
+ -}
+ | SuggestExplicitConstructorArguments !Name !VisArity
+
-- | What the user should upgrade to resolve an @-jsem@ semaphore
-- protocol version mismatch.
data SemaphoreUpgradeTarget
=====================================
compiler/GHC/Types/Hint/Ppr.hs
=====================================
@@ -345,6 +345,12 @@ instance Outputable GhcHint where
text "The jobserver uses a newer semaphore protocol than this GHC."
$$ (text "Upgrade GHC to a version that supports semaphore protocol v"
<> int required <> text " to resolve this.")
+ SuggestEmptyRecordBraces con
+ -> text "Use" <+> quotes (ppr con <> text "{}") <+> text "instead,"
+ <+> text "which matches" <+> quotes (ppr con) <+> text "regardless of its fields"
+ SuggestExplicitConstructorArguments con nbArgs
+ -> text "Apply" <+> quotes (ppr con) <+> text "to its"
+ <+> speakNOf nbArgs (text "argument")
perhapsAsPat :: SDoc
perhapsAsPat = text "Perhaps you meant an as-pattern, which must not be surrounded by whitespace"
=====================================
testsuite/tests/rename/should_fail/T21101.hs
=====================================
@@ -0,0 +1,7 @@
+{-# LANGUAGE RecordWildCards #-}
+module T21101 where
+
+data D = D Int Bool
+
+f :: D -> ()
+f D{..} = ()
=====================================
testsuite/tests/rename/should_fail/T21101.stderr
=====================================
@@ -0,0 +1,6 @@
+T21101.hs:7:3: error: [GHC-47217]
+ The data constructor ‘D’ does not have named record fields, so the record pattern ‘D{..}’ is invalid.
+ Suggested fixes:
+ • Use ‘D{}’ instead, which matches ‘D’ regardless of its fields
+ • Apply ‘D’ to its two arguments instead
+
=====================================
testsuite/tests/rename/should_fail/T9815.stderr
=====================================
@@ -1,5 +1,4 @@
-
T9815.hs:6:13: error: [GHC-47217]
- Illegal `{..}' notation for constructor ‘N’
- Record wildcards may not be used for constructors with unlabelled fields.
- Possible fix: Remove the `{..}' and add a match for each field of the constructor.
+ The data constructor ‘N’ does not have named record fields, so the record construction ‘N{..}’ is invalid.
+ Suggested fix: Apply ‘N’ to its one argument instead
+
=====================================
testsuite/tests/rename/should_fail/T9815b.stderr
=====================================
@@ -1,5 +1,4 @@
-
T9815.hs:6:13: error: [GHC-47217]
- Illegal `{..}' notation for constructor ‘N’
- Record wildcards may not be used for constructors with unlabelled fields.
- Possible fix: Remove the `{..}' and add a match for each field of the constructor.
+ The data constructor ‘N’ does not have named record fields, so the record construction ‘N{..}’ is invalid.
+ Suggested fix: Apply ‘N’ to its one argument instead
+
=====================================
testsuite/tests/rename/should_fail/T9815bghci.stderr
=====================================
@@ -1,5 +1,4 @@
+<interactive>:5:7: error: [GHC-47217]
+ The data constructor ‘Arg’ does not have named record fields, so the record construction ‘Arg{..}’ is invalid.
+ Suggested fix: Apply ‘Arg’ to its two arguments instead
-<interactive>:5:7: [GHC-47217]
- Illegal `{..}' notation for constructor ‘Arg’
- Record wildcards may not be used for constructors with unlabelled fields.
- Possible fix: Remove the `{..}' and add a match for each field of the constructor.
=====================================
testsuite/tests/rename/should_fail/T9815ghci.stderr
=====================================
@@ -1,5 +1,5 @@
+<interactive>:3:7: error: [GHC-47217]
+ The data constructor ‘Data.Semigroup.Arg’ does not have named record fields, so the record construction ‘Data.Semigroup.Arg{..}’ is invalid.
+ Suggested fix:
+ Apply ‘Data.Semigroup.Arg’ to its two arguments instead
-<interactive>:3:7: [GHC-47217]
- Illegal `{..}' notation for constructor ‘Data.Semigroup.Arg’
- Record wildcards may not be used for constructors with unlabelled fields.
- Possible fix: Remove the `{..}' and add a match for each field of the constructor.
=====================================
testsuite/tests/rename/should_fail/all.T
=====================================
@@ -186,6 +186,7 @@ test('T18138', normal, compile_fail, [''])
test('T20147', normal, compile_fail, [''])
test('RnEmptyStatementGroup1', normal, compile_fail, [''])
test('RnImplicitBindInMdoNotation', normal, compile_fail, [''])
+test('T21101', normal, compile_fail, [''])
test('T21605a', normal, compile_fail, [''])
test('T21605b', normal, compile_fail, [''])
test('T21605c', normal, compile_fail, [''])
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/73dd146cd3accbfa6f5cf2663892761…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/73dd146cd3accbfa6f5cf2663892761…
You're receiving this email because of your account on gitlab.haskell.org. Manage all notifications: https://gitlab.haskell.org/-/profile/notifications | Help: https://gitlab.haskell.org/help
1
0
[Git][ghc/ghc][wip/21101] Apply 1 suggestion(s) to 1 file(s)
by Sasha Bogicevic (@Bogicevic) 19 Jul '26
by Sasha Bogicevic (@Bogicevic) 19 Jul '26
19 Jul '26
Sasha Bogicevic pushed to branch wip/21101 at Glasgow Haskell Compiler / GHC
Commits:
a8d8bfb4 by Sasha Bogicevic at 2026-07-19T17:48:16+00:00
Apply 1 suggestion(s) to 1 file(s)
Co-authored-by: sheaf <sam.derbyshire(a)gmail.com>
- - - - -
1 changed file:
- changelog.d/21101
Changes:
=====================================
changelog.d/21101
=====================================
@@ -1,5 +1,5 @@
section: compiler
-synopsis: Improve error messages and hints for invalid record wildcard patterns
+synopsis: Improve error messages and hints for invalid record wildcards
description:
Record wildcard hints are now shown in more contexts and include
constructor arity; matching with ``..`` on a fieldless constructor
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/a8d8bfb40f8e74b8dc0874506d076ca…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/a8d8bfb40f8e74b8dc0874506d076ca…
You're receiving this email because of your account on gitlab.haskell.org. Manage all notifications: https://gitlab.haskell.org/-/profile/notifications | Help: https://gitlab.haskell.org/help
1
0