Sasha Bogicevic pushed to branch wip/21101 at Glasgow Haskell Compiler / GHC
Commits:
-
6f1d6da8
by Sasha Bogicevic at 2026-07-15T18:24:05+02:00
14 changed files:
- 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.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
Changes:
| ... | ... | @@ -1589,8 +1589,8 @@ hsConDeclsBinders in the following format: |
| 1589 | 1589 | with its record fields, in the form of a list of Int indices into...
|
| 1590 | 1590 | - IntMap FieldOcc, an IntMap of record fields.
|
| 1591 | 1591 | |
| 1592 | -(In actual fact, we use [(ConRdrName, Maybe [Located Int])], with Nothing indicating
|
|
| 1593 | -that the constructor has unlabelled fields: see Note [Local constructor info in the renamer]
|
|
| 1592 | +(In actual fact, we use [(ConRdrName, Either VisArity [Located Int])], with Left n indicating
|
|
| 1593 | +that the constructor has n unlabelled arguments: see Note [Local constructor info in the renamer]
|
|
| 1594 | 1594 | in GHC.Types.GREInfo.)
|
| 1595 | 1595 | |
| 1596 | 1596 | This allows us to do the following (see GHC.Rename.Names.getLocalNonValBinders.new_tc):
|
| ... | ... | @@ -1611,7 +1611,7 @@ Other relevant test cases: rnfail015. |
| 1611 | 1611 | -- See Note [Collecting record fields in data declarations].
|
| 1612 | 1612 | data LConsWithFields p =
|
| 1613 | 1613 | LConsWithFields
|
| 1614 | - { consWithFieldIndices :: [(LocatedA (IdP (GhcPass p)), Maybe [Located Int])]
|
|
| 1614 | + { consWithFieldIndices :: [(LocatedA (IdP (GhcPass p)), Either VisArity [Located Int])]
|
|
| 1615 | 1615 | , consFields :: IntMap (LFieldOcc (GhcPass p))
|
| 1616 | 1616 | }
|
| 1617 | 1617 | |
| ... | ... | @@ -1651,16 +1651,15 @@ hsConDeclsBinders cons = go emptyFieldIndices cons |
| 1651 | 1651 | LConsWithFields ns fs = go seen' rs
|
| 1652 | 1652 | |
| 1653 | 1653 | get_flds_h98 :: FieldIndices p -> HsConDeclH98Details (GhcPass p)
|
| 1654 | - -> (Maybe [Located Int], FieldIndices p)
|
|
| 1655 | - get_flds_h98 seen (RecCon _ flds) = first Just $ get_flds seen flds
|
|
| 1656 | - get_flds_h98 seen (PrefixCon _ []) = (Just [], seen)
|
|
| 1657 | - get_flds_h98 seen _ = (Nothing, seen)
|
|
| 1654 | + -> (Either VisArity [Located Int], FieldIndices p)
|
|
| 1655 | + get_flds_h98 seen (RecCon _ flds) = first Right $ get_flds seen flds
|
|
| 1656 | + get_flds_h98 seen (PrefixCon _ args) = (Left (length args), seen)
|
|
| 1657 | + get_flds_h98 seen (InfixCon {}) = (Left 2, seen)
|
|
| 1658 | 1658 | |
| 1659 | 1659 | get_flds_gadt :: FieldIndices p -> HsConDeclGADTDetails (GhcPass p)
|
| 1660 | - -> (Maybe [Located Int], FieldIndices p)
|
|
| 1661 | - get_flds_gadt seen (RecConGADT _ flds) = first Just $ get_flds seen flds
|
|
| 1662 | - get_flds_gadt seen (PrefixConGADT _ []) = (Just [], seen)
|
|
| 1663 | - get_flds_gadt seen _ = (Nothing, seen)
|
|
| 1660 | + -> (Either VisArity [Located Int], FieldIndices p)
|
|
| 1661 | + get_flds_gadt seen (RecConGADT _ flds) = first Right $ get_flds seen flds
|
|
| 1662 | + get_flds_gadt seen (PrefixConGADT _ args) = (Left (length args), seen)
|
|
| 1664 | 1663 | |
| 1665 | 1664 | get_flds :: FieldIndices p -> LocatedA [LHsConDeclRecField (GhcPass p)]
|
| 1666 | 1665 | -> ([Located Int], FieldIndices p)
|
| ... | ... | @@ -423,7 +423,10 @@ lookupConstructorInfo qcon@(WithUserRdr _ con_name) |
| 423 | 423 | = do { info <- lookupGREInfo_GRE con_name
|
| 424 | 424 | ; case info of
|
| 425 | 425 | IAmConLike con_info -> return con_info
|
| 426 | - UnboundGRE -> return $ ConInfo (ConIsData []) ConHasPositionalArgs
|
|
| 426 | + UnboundGRE -> return $ ConInfo (ConIsData []) (ConHasPositionalArgs 0)
|
|
| 427 | + -- The arity is a dummy: an unbound constructor never reaches the
|
|
| 428 | + -- code that consults it (see the isUnboundName guard in
|
|
| 429 | + -- GHC.Rename.Pat.rn_dotdot).
|
|
| 427 | 430 | IAmTyCon {} -> failIllegalTyCon WL_ConLike qcon
|
| 428 | 431 | _ -> pprPanic "lookupConstructorInfo: not a ConLike" $
|
| 429 | 432 | vcat [ text "name:" <+> ppr con_name ]
|
| ... | ... | @@ -71,7 +71,7 @@ import GHC.Types.FieldLabel |
| 71 | 71 | import GHC.Types.Hint
|
| 72 | 72 | import GHC.Types.SourceFile
|
| 73 | 73 | import GHC.Types.SrcLoc as SrcLoc
|
| 74 | -import GHC.Types.Basic ( TyConFlavour (..), convImportLevel )
|
|
| 74 | +import GHC.Types.Basic (TyConFlavour (..), convImportLevel, VisArity)
|
|
| 75 | 75 | import GHC.Types.Id
|
| 76 | 76 | import GHC.Types.PkgQual
|
| 77 | 77 | import GHC.Types.GREInfo (ConInfo(..), ConFieldInfo (..), ConLikeInfo (ConIsData))
|
| ... | ... | @@ -875,15 +875,16 @@ getLocalNonValBinders fixity_env |
| 875 | 875 | --
|
| 876 | 876 | -- The information we needed was all set up for us:
|
| 877 | 877 | -- see Note [Collecting record fields in data declarations] in GHC.Hs.Utils.
|
| 878 | - mk_fld_env :: [(Name, Maybe [Located Int])] -> IntMap FieldLabel
|
|
| 878 | + mk_fld_env :: [(Name, Either VisArity [Located Int])] -> IntMap FieldLabel
|
|
| 879 | 879 | -> [(ConLikeName, ConInfo)]
|
| 880 | 880 | mk_fld_env names flds =
|
| 881 | 881 | [ (DataConName con, ConInfo (ConIsData (map fst names)) fld_info)
|
| 882 | - | (con, mb_fl_indxs) <- names
|
|
| 883 | - , let fld_info = case fmap (map ((flds IntMap.!) . unLoc)) mb_fl_indxs of
|
|
| 884 | - Nothing -> ConHasPositionalArgs
|
|
| 885 | - Just [] -> ConIsNullary
|
|
| 886 | - Just (fld:flds) -> ConHasRecordFields $ fld NE.:| flds ]
|
|
| 882 | + | (con, con_fl_indxs) <- names
|
|
| 883 | + , let fld_info = case fmap (map ((flds IntMap.!) . unLoc)) con_fl_indxs of
|
|
| 884 | + Left 0 -> ConIsNullary
|
|
| 885 | + Left arity -> ConHasPositionalArgs arity
|
|
| 886 | + Right [] -> ConIsNullary
|
|
| 887 | + Right (fld:flds) -> ConHasRecordFields $ fld NE.:| flds ]
|
|
| 887 | 888 | |
| 888 | 889 | new_assoc :: DuplicateRecordFields -> FieldSelectors -> LInstDecl GhcPs
|
| 889 | 890 | -> RnM [GlobalRdrElt]
|
| ... | ... | @@ -939,10 +940,10 @@ getLocalNonValBinders fixity_env |
| 939 | 940 | |
| 940 | 941 | -- Add errors if a constructor has a duplicate record field.
|
| 941 | 942 | add_dup_fld_errs :: IntMap FieldLabel
|
| 942 | - -> (Name, Maybe [Located Int])
|
|
| 943 | + -> (Name, Either VisArity [Located Int])
|
|
| 943 | 944 | -> IOEnv (Env TcGblEnv TcLclEnv) ()
|
| 944 | - add_dup_fld_errs all_flds (con, mb_con_flds)
|
|
| 945 | - | Just con_flds <- mb_con_flds
|
|
| 945 | + add_dup_fld_errs all_flds (con, con_flds_or_arity)
|
|
| 946 | + | Right con_flds <- con_flds_or_arity
|
|
| 946 | 947 | , let (_, dups) = removeDups (comparing unLoc) con_flds
|
| 947 | 948 | = for_ dups $ \ dup_flds ->
|
| 948 | 949 | -- Report the error at the location of the second occurrence
|
| ... | ... | @@ -874,7 +874,11 @@ rnHsRecFields ctxt mk_arg (HsRecFields { rec_flds = flds, rec_dotdot = dotdot }) |
| 874 | 874 | ; checkErr dd_flag (needFlagDotDot ctxt)
|
| 875 | 875 | ; (rdr_env, lcl_env) <- getRdrEnvs
|
| 876 | 876 | ; conInfo <- lookupConstructorInfo qcon
|
| 877 | - ; when (conFieldInfo conInfo == ConHasPositionalArgs) (addErr (TcRnIllegalWildcardsInConstructor (toRecordFieldPart ctxt) con))
|
|
| 877 | + |
|
| 878 | + ; case conFieldInfo conInfo of
|
|
| 879 | + ConHasPositionalArgs nbArgs ->
|
|
| 880 | + addErr $ TcRnIllegalWildcardsInConstructor (toRecordFieldPart ctxt) con nbArgs
|
|
| 881 | + _ -> return ()
|
|
| 878 | 882 | ; let present_flds = mkOccSet $ map rdrNameOcc (getFieldRdrs flds)
|
| 879 | 883 | |
| 880 | 884 | -- For constructor uses (but not patterns)
|
| ... | ... | @@ -357,7 +357,7 @@ instance Diagnostic TcRnMessage where |
| 357 | 357 | -> mkSimpleDecorated $ vcat [text "Illegal view pattern: " <+> ppr pat]
|
| 358 | 358 | TcRnCharLiteralOutOfRange c
|
| 359 | 359 | -> mkSimpleDecorated $ text "character literal out of range: '\\" <> char c <> char '\''
|
| 360 | - TcRnIllegalWildcardsInConstructor ctx con
|
|
| 360 | + TcRnIllegalWildcardsInConstructor ctx con _
|
|
| 361 | 361 | -> mkSimpleDecorated $
|
| 362 | 362 | text "The data constructor" <+> quotes (ppr con)
|
| 363 | 363 | <+> text "does not have named record fields, so the record"
|
| ... | ... | @@ -2791,10 +2791,12 @@ instance Diagnostic TcRnMessage where |
| 2791 | 2791 | -> [suggestExtension LangExt.ViewPatterns]
|
| 2792 | 2792 | TcRnCharLiteralOutOfRange{}
|
| 2793 | 2793 | -> noHints
|
| 2794 | - TcRnIllegalWildcardsInConstructor ctx con
|
|
| 2794 | + TcRnIllegalWildcardsInConstructor ctx con arity
|
|
| 2795 | 2795 | -> case ctx of
|
| 2796 | - RecordFieldPattern{} -> [SuggestEmptyRecordBraces con]
|
|
| 2797 | - _ -> [SuggestExplicitConstructorArguments con]
|
|
| 2796 | + RecordFieldPattern{} -> [ SuggestEmptyRecordBraces con
|
|
| 2797 | + , SuggestExplicitConstructorArguments con arity
|
|
| 2798 | + ]
|
|
| 2799 | + _ -> [SuggestExplicitConstructorArguments con arity]
|
|
| 2798 | 2800 | TcRnIgnoringAnnotations{}
|
| 2799 | 2801 | -> noHints
|
| 2800 | 2802 | TcRnAnnotationInSafeHaskell
|
| ... | ... | @@ -824,6 +824,8 @@ data TcRnMessage where |
| 824 | 824 | worded accordingly. Constructors with no fields at all do not trigger
|
| 825 | 825 | this error: since GHC proposal 496 ("Nullary record wildcards"),
|
| 826 | 826 | @C {..}@ is legal for nullary constructors.
|
| 827 | + The 'VisArity' field records the constructor's number of positional arguments
|
|
| 828 | + which the suggested fix mentions.
|
|
| 827 | 829 | |
| 828 | 830 | Example(s):
|
| 829 | 831 | |
| ... | ... | @@ -842,7 +844,7 @@ data TcRnMessage where |
| 842 | 844 | rename/should_fail/T9815bghci.hs
|
| 843 | 845 | rename/should_fail/T21101.hs
|
| 844 | 846 | -}
|
| 845 | - TcRnIllegalWildcardsInConstructor :: !RecordFieldPart -> !Name -> TcRnMessage
|
|
| 847 | + TcRnIllegalWildcardsInConstructor :: !RecordFieldPart -> !Name -> !VisArity -> TcRnMessage
|
|
| 846 | 848 | |
| 847 | 849 | {-| TcRnIgnoringAnnotations is a warning that occurs when the source code
|
| 848 | 850 | contains annotation pragmas but the platform in use does not support an
|
| ... | ... | @@ -244,14 +244,14 @@ instance NFData ConLikeInfo where |
| 244 | 244 | -- See Note [Local constructor info in the renamer]
|
| 245 | 245 | data ConFieldInfo
|
| 246 | 246 | = ConHasRecordFields (NonEmpty FieldLabel)
|
| 247 | - | ConHasPositionalArgs
|
|
| 247 | + | ConHasPositionalArgs !VisArity
|
|
| 248 | 248 | | ConIsNullary
|
| 249 | 249 | deriving stock Eq
|
| 250 | 250 | deriving Data
|
| 251 | 251 | |
| 252 | 252 | instance NFData ConFieldInfo where
|
| 253 | 253 | rnf ConIsNullary = ()
|
| 254 | - rnf ConHasPositionalArgs = ()
|
|
| 254 | + rnf (ConHasPositionalArgs arity) = rnf arity
|
|
| 255 | 255 | rnf (ConHasRecordFields flds) = rnf flds
|
| 256 | 256 | |
| 257 | 257 | mkConInfo :: ConLikeInfo -> VisArity -> [FieldLabel] -> ConInfo
|
| ... | ... | @@ -259,9 +259,9 @@ mkConInfo con_ty n flds = |
| 259 | 259 | ConInfo { conLikeInfo = con_ty
|
| 260 | 260 | , conFieldInfo = mkConFieldInfo n flds }
|
| 261 | 261 | |
| 262 | -mkConFieldInfo :: Arity -> [FieldLabel] -> ConFieldInfo
|
|
| 262 | +mkConFieldInfo :: VisArity -> [FieldLabel] -> ConFieldInfo
|
|
| 263 | 263 | mkConFieldInfo 0 _ = ConIsNullary
|
| 264 | -mkConFieldInfo _ fields = maybe ConHasPositionalArgs ConHasRecordFields
|
|
| 264 | +mkConFieldInfo arity fields = maybe (ConHasPositionalArgs arity) ConHasRecordFields
|
|
| 265 | 265 | $ NonEmpty.nonEmpty fields
|
| 266 | 266 | |
| 267 | 267 | conInfoFields :: ConInfo -> [FieldLabel]
|
| ... | ... | @@ -269,7 +269,7 @@ conInfoFields = conFieldInfoFields . conFieldInfo |
| 269 | 269 | |
| 270 | 270 | conFieldInfoFields :: ConFieldInfo -> [FieldLabel]
|
| 271 | 271 | conFieldInfoFields (ConHasRecordFields fields) = NonEmpty.toList fields
|
| 272 | -conFieldInfoFields ConHasPositionalArgs = []
|
|
| 272 | +conFieldInfoFields (ConHasPositionalArgs _) = []
|
|
| 273 | 273 | conFieldInfoFields ConIsNullary = []
|
| 274 | 274 | |
| 275 | 275 | instance Outputable ConInfo where
|
| ... | ... | @@ -284,7 +284,7 @@ instance Outputable ConLikeInfo where |
| 284 | 284 | |
| 285 | 285 | instance Outputable ConFieldInfo where
|
| 286 | 286 | ppr ConIsNullary = text "ConIsNullary"
|
| 287 | - ppr ConHasPositionalArgs = text "ConHasPositionalArgs"
|
|
| 287 | + ppr (ConHasPositionalArgs arity) = text "ConHasPositionalArgs" <+> braces (ppr arity)
|
|
| 288 | 288 | ppr (ConHasRecordFields fieldLabels) =
|
| 289 | 289 | text "ConHasRecordFields" <+> braces (ppr fieldLabels)
|
| 290 | 290 |
| ... | ... | @@ -45,7 +45,7 @@ import GHC.Types.InlinePragma (ActivationGhc) |
| 45 | 45 | import GHC.Types.Name (Name, NameSpace, OccName (occNameFS), isSymOcc, nameOccName)
|
| 46 | 46 | import GHC.Types.Name.Reader (RdrName (Unqual), ImpDeclSpec, GlobalRdrElt)
|
| 47 | 47 | import GHC.Types.SrcLoc (SrcSpan)
|
| 48 | -import GHC.Types.Basic (RuleName)
|
|
| 48 | +import GHC.Types.Basic (RuleName, VisArity)
|
|
| 49 | 49 | import GHC.Parser.Errors.Basic
|
| 50 | 50 | import GHC.Utils.Outputable
|
| 51 | 51 | import GHC.Data.FastString (fsLit)
|
| ... | ... | @@ -560,9 +560,10 @@ data GhcHint |
| 560 | 560 | of record syntax, for constructors without labelled fields.
|
| 561 | 561 | |
| 562 | 562 | Triggered by 'GHC.Tc.Errors.Types.TcRnIllegalWildcardsInConstructor'
|
| 563 | - in a record construction.
|
|
| 563 | + in a record construction and record patterns.
|
|
| 564 | + The 'VisArity' is the number of positional arguments of the constructor.
|
|
| 564 | 565 | -}
|
| 565 | - | SuggestExplicitConstructorArguments !Name
|
|
| 566 | + | SuggestExplicitConstructorArguments !Name !VisArity
|
|
| 566 | 567 | |
| 567 | 568 | -- | What the user should upgrade to resolve an @-jsem@ semaphore
|
| 568 | 569 | -- protocol version mismatch.
|
| ... | ... | @@ -348,8 +348,9 @@ instance Outputable GhcHint where |
| 348 | 348 | SuggestEmptyRecordBraces con
|
| 349 | 349 | -> text "Use" <+> quotes (ppr con <> text "{}") <+> text "instead,"
|
| 350 | 350 | <+> text "which matches" <+> quotes (ppr con) <+> text "regardless of its fields"
|
| 351 | - SuggestExplicitConstructorArguments con
|
|
| 352 | - -> text "Apply" <+> quotes (ppr con) <+> text "to its arguments instead"
|
|
| 351 | + SuggestExplicitConstructorArguments con nbArgs
|
|
| 352 | + -> text "Apply" <+> quotes (ppr con) <+> text "to its"
|
|
| 353 | + <+> speakNOf nbArgs (text "argument") <+> text "instead"
|
|
| 353 | 354 | |
| 354 | 355 | perhapsAsPat :: SDoc
|
| 355 | 356 | perhapsAsPat = text "Perhaps you meant an as-pattern, which must not be surrounded by whitespace"
|
| 1 | 1 | T21101.hs:7:3: error: [GHC-47217]
|
| 2 | 2 | The data constructor ‘D’ does not have named record fields, so the record pattern ‘D{..}’ is invalid.
|
| 3 | - Suggested fix:
|
|
| 4 | - Use ‘D{}’ instead, which matches ‘D’ regardless of its fields
|
|
| 3 | + Suggested fixes:
|
|
| 4 | + • Use ‘D{}’ instead, which matches ‘D’ regardless of its fields
|
|
| 5 | + • Apply ‘D’ to its two arguments instead
|
|
| 5 | 6 |
| 1 | 1 | T9815.hs:6:13: error: [GHC-47217]
|
| 2 | 2 | The data constructor ‘N’ does not have named record fields, so the record construction ‘N{..}’ is invalid.
|
| 3 | - Suggested fix: Apply ‘N’ to its arguments instead
|
|
| 3 | + Suggested fix: Apply ‘N’ to its one argument instead
|
|
| 4 | 4 |
| 1 | 1 | T9815.hs:6:13: error: [GHC-47217]
|
| 2 | 2 | The data constructor ‘N’ does not have named record fields, so the record construction ‘N{..}’ is invalid.
|
| 3 | - Suggested fix: Apply ‘N’ to its arguments instead
|
|
| 3 | + Suggested fix: Apply ‘N’ to its one argument instead
|
|
| 4 | 4 |
| 1 | 1 | <interactive>:5:7: error: [GHC-47217]
|
| 2 | 2 | The data constructor ‘Arg’ does not have named record fields, so the record construction ‘Arg{..}’ is invalid.
|
| 3 | - Suggested fix: Apply ‘Arg’ to its arguments instead
|
|
| 3 | + Suggested fix: Apply ‘Arg’ to its two arguments instead
|
|
| 4 | 4 |
| 1 | 1 | <interactive>:3:7: error: [GHC-47217]
|
| 2 | 2 | The data constructor ‘Data.Semigroup.Arg’ does not have named record fields, so the record construction ‘Data.Semigroup.Arg{..}’ is invalid.
|
| 3 | - Suggested fix: Apply ‘Data.Semigroup.Arg’ to its arguments instead
|
|
| 3 | + Suggested fix:
|
|
| 4 | + Apply ‘Data.Semigroup.Arg’ to its two arguments instead
|
|
| 4 | 5 |