Brandon Chinn pushed to branch wip/T26503 at Glasgow Haskell Compiler / GHC
Commits:
-
6dfed3a3
by Brandon Chinn at 2026-01-20T21:36:48-08:00
12 changed files:
- compiler/GHC/Hs/Lit.hs
- compiler/GHC/HsToCore/Pmc/Desugar.hs
- compiler/GHC/Rename/Expr.hs
- compiler/GHC/Rename/Pat.hs
- + testsuite/tests/qualified-strings/should_fail/Example/Length.hs
- testsuite/tests/qualified-strings/should_fail/all.T
- + testsuite/tests/qualified-strings/should_fail/qstrings_bad_expr.hs
- + testsuite/tests/qualified-strings/should_fail/qstrings_bad_expr.stderr
- + testsuite/tests/qualified-strings/should_fail/qstrings_bad_pat.hs
- + testsuite/tests/qualified-strings/should_fail/qstrings_bad_pat.stderr
- + testsuite/tests/qualified-strings/should_fail/qstrings_redundant_pattern.hs
- + testsuite/tests/qualified-strings/should_fail/qstrings_redundant_pattern.stderr
Changes:
| ... | ... | @@ -35,6 +35,7 @@ import GHC.Hs.Extension |
| 35 | 35 | import Language.Haskell.Syntax.Expr ( HsExpr )
|
| 36 | 36 | import Language.Haskell.Syntax.Extension
|
| 37 | 37 | import Language.Haskell.Syntax.Lit
|
| 38 | +import Language.Haskell.Syntax.Module.Name (moduleNameString)
|
|
| 38 | 39 | |
| 39 | 40 | {-
|
| 40 | 41 | ************************************************************************
|
| ... | ... | @@ -211,14 +212,18 @@ Equivalently it's True if |
| 211 | 212 | instance IsPass p => Outputable (HsLit (GhcPass p)) where
|
| 212 | 213 | ppr (HsChar st c) = pprWithSourceText st (pprHsChar c)
|
| 213 | 214 | ppr (HsCharPrim st c) = pprWithSourceText st (pprPrimChar c)
|
| 214 | - ppr (HsString StringMeta{..} s)
|
|
| 215 | - -- multiline strings
|
|
| 216 | - | strMetaMultiline =
|
|
| 215 | + ppr (HsString StringMeta{..} s) =
|
|
| 216 | + handleQualified $ if strMetaMultiline then renderMultiline else renderNormal
|
|
| 217 | + where
|
|
| 218 | + handleQualified =
|
|
| 219 | + case strMetaQualified of
|
|
| 220 | + Nothing -> id
|
|
| 221 | + Just modName -> (text (moduleNameString modName ++ ".") <>)
|
|
| 222 | + renderMultiline =
|
|
| 217 | 223 | case strMetaSrc of
|
| 218 | 224 | NoSourceText -> pprHsString s
|
| 219 | - SourceText src -> vcat $ map text $ split '\n' (unpackFS src)
|
|
| 220 | - -- normal strings
|
|
| 221 | - | otherwise = pprWithSourceText strMetaSrc (pprHsString s)
|
|
| 225 | + SourceText src -> vcat . map text . split '\n' . unpackFS $ src
|
|
| 226 | + renderNormal = pprWithSourceText strMetaSrc (pprHsString s)
|
|
| 222 | 227 | ppr (HsStringPrim st s) = pprWithSourceText st (pprHsBytes s)
|
| 223 | 228 | ppr (HsInt _ i)
|
| 224 | 229 | = pprWithSourceText (il_text i) (integer (il_value i))
|
| ... | ... | @@ -39,6 +39,7 @@ import GHC.Core.TyCo.Compare( eqType ) |
| 39 | 39 | import GHC.Core.Type
|
| 40 | 40 | import GHC.Data.Maybe
|
| 41 | 41 | import GHC.Types.SourceText (FractionalLit(..))
|
| 42 | +import GHC.Types.StringMeta (StringMeta(..))
|
|
| 42 | 43 | import Control.Monad (zipWithM, replicateM)
|
| 43 | 44 | import Data.List (elemIndex)
|
| 44 | 45 | import Data.List.NonEmpty ( NonEmpty(..) )
|
| ... | ... | @@ -137,6 +138,11 @@ desugarPat x pat = case pat of |
| 137 | 138 | , is_to_list (unLoc lrhs)
|
| 138 | 139 | -> desugarLPat x pat
|
| 139 | 140 | |
| 141 | + -- Desugar qualified string literals the same as RebindableSyntax
|
|
| 142 | + LitPat _ (HsString StringMeta{strMetaQualified = Just _} s)
|
|
| 143 | + | ViewPat ty _ _ <- expansion
|
|
| 144 | + -> mkPmLitGrds x $ PmLit ty (PmLitOverString s)
|
|
| 145 | + |
|
| 140 | 146 | _ -> desugarPat x expansion
|
| 141 | 147 | |
| 142 | 148 | -- See Note [Desugar CoPats]
|
| ... | ... | @@ -359,7 +359,8 @@ rnExpr (HsLit x lit) | Just (meta, s) <- stringLike lit |
| 359 | 359 | | StringMeta{strMetaQualified = Just modName} <- meta -> do
|
| 360 | 360 | (qualifiedFromString, fvs) <- first genHsVar <$> lookupNameWithQualifier fromStringName modName
|
| 361 | 361 | let hsLit = HsLit x (convertLit lit)
|
| 362 | - return (HsApp noExtField (noLocA qualifiedFromString) (noLocA hsLit), fvs)
|
|
| 362 | + let expr = HsApp noExtField (noLocA qualifiedFromString) (noLocA hsLit)
|
|
| 363 | + return (mkExpandedExpr hsLit expr, fvs)
|
|
| 363 | 364 | | opt_OverloadedStrings ->
|
| 364 | 365 | rnExpr (HsOverLit x (mkHsIsString (strMetaSrc meta) s))
|
| 365 | 366 | | otherwise -> do {
|
| ... | ... | @@ -567,13 +567,14 @@ rnPatAndThen mk (LitPat x lit) |
| 567 | 567 | -- M."asdf" => ((M.fromString "asdf" ==) -> True)
|
| 568 | 568 | eqExpr <- liftCpsFV $ lookupSyntaxExpr eqName
|
| 569 | 569 | fromStringExpr <- fmap genHsVar $ liftCpsFV $ lookupNameWithQualifier fromStringName modName
|
| 570 | - let lit = noLocA $ HsLit noExtField (mkHsStringFS s)
|
|
| 571 | - let trueExpr = noLocA $
|
|
| 570 | + let litExpr = noLocA $ HsLit noExtField (convertLit lit)
|
|
| 571 | + truePat = noLocA $
|
|
| 572 | 572 | ConPat
|
| 573 | 573 | noExtField
|
| 574 | 574 | (noLocA $ noUserRdr trueDataConName)
|
| 575 | 575 | (PrefixCon [])
|
| 576 | - return $ ViewPat Nothing (genLHsApp eqExpr (genLHsApp fromStringExpr lit)) trueExpr
|
|
| 576 | + return . mkExpandedPat (LitPat x (convertLit lit)) $
|
|
| 577 | + ViewPat Nothing (genLHsApp eqExpr (genLHsApp fromStringExpr litExpr)) truePat
|
|
| 577 | 578 | | opt_OverloadedStrings ->
|
| 578 | 579 | rnPatAndThen mk
|
| 579 | 580 | (mkNPat (noLocA (mkHsIsString (strMetaSrc meta) s))
|
| 1 | +module Example.Length where
|
|
| 2 | + |
|
| 3 | +fromString :: String -> Int
|
|
| 4 | +fromString = length |
| 1 | 1 | setTestOpts(only_ways(['normal']));
|
| 2 | 2 | |
| 3 | +qextra_files = extra_files(['Example'])
|
|
| 4 | + |
|
| 3 | 5 | test('qstrings_multiline_no_ext', normal, compile_fail, [''])
|
| 6 | +test('qstrings_bad_expr', [qextra_files], multimod_compile_fail, ['qstrings_bad_expr', ''])
|
|
| 7 | +test('qstrings_bad_pat', [qextra_files], multimod_compile_fail, ['qstrings_bad_pat', ''])
|
|
| 8 | +test('qstrings_redundant_pattern', [qextra_files], multimod_compile_fail, ['qstrings_redundant_pattern', '']) |
| 1 | +{-# LANGUAGE QualifiedStrings #-}
|
|
| 2 | + |
|
| 3 | +import qualified Example.Length as Length
|
|
| 4 | + |
|
| 5 | +main :: IO ()
|
|
| 6 | +main = putStrLn Length."this fails after being converted into an Int" |
| 1 | +[1 of 3] Compiling Example.Length ( Example/Length.hs, Example/Length.o )
|
|
| 2 | +[2 of 3] Compiling Main ( qstrings_bad_expr.hs, qstrings_bad_expr.o )
|
|
| 3 | +qstrings_bad_expr.hs:6:17: error: [GHC-83865]
|
|
| 4 | + • Couldn't match type ‘Int’ with ‘[Char]’
|
|
| 5 | + Expected: String
|
|
| 6 | + Actual: Int
|
|
| 7 | + • In the first argument of ‘putStrLn’, namely
|
|
| 8 | + ‘Length."this fails after being converted into an Int"’
|
|
| 9 | + In the expression:
|
|
| 10 | + putStrLn
|
|
| 11 | + Length."this fails after being converted into an Int"
|
|
| 12 | + In an equation for ‘main’:
|
|
| 13 | + main
|
|
| 14 | + = putStrLn
|
|
| 15 | + Length."this fails after being converted into an Int" |
| 1 | +{-# LANGUAGE QualifiedStrings #-}
|
|
| 2 | + |
|
| 3 | +import qualified Example.Length as Length
|
|
| 4 | + |
|
| 5 | +main :: IO ()
|
|
| 6 | +main =
|
|
| 7 | + case "" of
|
|
| 8 | + Length."this fails after being converted into an Int" -> pure ()
|
|
| 9 | + _ -> pure () |
| 1 | +[1 of 3] Compiling Example.Length ( Example/Length.hs, Example/Length.o )
|
|
| 2 | +[2 of 3] Compiling Main ( qstrings_bad_pat.hs, qstrings_bad_pat.o )
|
|
| 3 | +qstrings_bad_pat.hs:8:5: error: [GHC-83865]
|
|
| 4 | + • Couldn't match type ‘[Char]’ with ‘Int’
|
|
| 5 | + Expected: String
|
|
| 6 | + Actual: Int
|
|
| 7 | + • In the pattern:
|
|
| 8 | + Length."this fails after being converted into an Int"
|
|
| 9 | + In a case alternative:
|
|
| 10 | + Length."this fails after being converted into an Int"
|
|
| 11 | + -> pure ()
|
|
| 12 | + In the expression:
|
|
| 13 | + case "" of
|
|
| 14 | + Length."this fails after being converted into an Int" -> pure ()
|
|
| 15 | + _ -> pure () |
| 1 | +{-# LANGUAGE QualifiedStrings #-}
|
|
| 2 | +{-# OPTIONS_GHC -Wall -Werror #-}
|
|
| 3 | + |
|
| 4 | +import qualified Example.Length as Length
|
|
| 5 | + |
|
| 6 | +main :: IO ()
|
|
| 7 | +main = print $ foo Length."abc"
|
|
| 8 | + |
|
| 9 | +foo :: Int -> ()
|
|
| 10 | +foo Length."abc" = ()
|
|
| 11 | +foo other =
|
|
| 12 | + case other of
|
|
| 13 | + Length."abc" -> ()
|
|
| 14 | + Length."def" -> ()
|
|
| 15 | + _ -> () |
| 1 | +[1 of 3] Compiling Example.Length ( Example/Length.hs, Example/Length.o )
|
|
| 2 | +[2 of 3] Compiling Main ( qstrings_redundant_pattern.hs, qstrings_redundant_pattern.o )
|
|
| 3 | +qstrings_redundant_pattern.hs:13:5: error: [GHC-53633] [-Woverlapping-patterns (in -Wdefault), Werror=overlapping-patterns]
|
|
| 4 | + Pattern match is redundant
|
|
| 5 | + In a case alternative: Length."abc" -> ...
|
|
| 6 | + |