Brandon Chinn pushed to branch wip/interpolated-strings at Glasgow Haskell Compiler / GHC

Commits:

16 changed files:

Changes:

  • compiler/GHC/Hs/Expr.hs
    ... ... @@ -27,7 +27,6 @@ import GHC.Hs.Pat
    27 27
     import GHC.Hs.Lit
    
    28 28
     import Language.Haskell.Syntax.Extension
    
    29 29
     import Language.Haskell.Syntax.Basic (FieldLabelString(..))
    
    30
    -import Language.Haskell.Syntax.StringMeta (StringMeta (..))
    
    31 30
     import Language.Haskell.Syntax.Text
    
    32 31
     import Language.Haskell.Syntax.Module.Name
    
    33 32
     import GHC.Hs.Extension
    
    ... ... @@ -239,12 +238,12 @@ type instance XQualLitE (GhcPass _) = NoExtField
    239 238
     type instance XLam           (GhcPass _) = EpAnnLam
    
    240 239
     type instance XApp           (GhcPass _) = NoExtField
    
    241 240
     
    
    242
    -type instance XInterString GhcPs = NoExtField
    
    243
    -type instance XInterString GhcRn = NoExtField
    
    241
    +type instance XInterString GhcPs = AnnInterString
    
    242
    +type instance XInterString GhcRn = AnnInterString
    
    244 243
     type instance XInterString GhcTc = DataConCantHappen
    
    245
    --- | Note: does not contain any delimiters
    
    246
    -type instance XInterStringRaw  (GhcPass _) = SourceText
    
    247
    -type instance XInterStringExpr (GhcPass _) = NoExtField
    
    244
    +type instance XInterStringRaw   (GhcPass _) = SourceText -- Note: does not contain any delimiters
    
    245
    +type instance XInterStringExpr  (GhcPass _) = NoExtField
    
    246
    +type instance XXInterStringPart (GhcPass _) = DataConCantHappen
    
    248 247
     
    
    249 248
     type instance XAppTypeE      GhcPs = EpToken "@"
    
    250 249
     type instance XAppTypeE      GhcRn = NoExtField
    
    ... ... @@ -623,6 +622,18 @@ data AnnFunRhs
    623 622
     instance NoAnn AnnFunRhs where
    
    624 623
       noAnn = AnnFunRhs noAnn noAnn noAnn
    
    625 624
     
    
    625
    +data AnnInterString = AnnInterString
    
    626
    +  { ais_delim :: !AnnInterStringDelim
    
    627
    +  , ais_open  :: !EpaLocation -- ^ @s"@ or @s"""@, including any @M.@ prefix
    
    628
    +  , ais_close :: !EpaLocation -- ^ @"@ or @"""@
    
    629
    +  }
    
    630
    +  deriving (Data, Show, Eq)
    
    631
    +
    
    632
    +data AnnInterStringDelim
    
    633
    +  = AnnInterStringSingle -- ^ @s"..."@
    
    634
    +  | AnnInterStringMulti  -- ^ @s"""..."""@
    
    635
    +  deriving (Data, Show, Eq)
    
    636
    +
    
    626 637
     -- ---------------------------------------------------------------------
    
    627 638
     
    
    628 639
     type instance XSCC           (GhcPass _) = (AnnPragSCC, SourceText)
    
    ... ... @@ -821,21 +832,26 @@ ppr_expr (HsLit _ lit) = ppr lit
    821 832
     ppr_expr (HsOverLit _ lit)   = ppr lit
    
    822 833
     ppr_expr (HsQualLit _ lit)   = ppr lit
    
    823 834
     
    
    824
    -ppr_expr (HsInterString _ meta parts) =
    
    835
    +ppr_expr (HsInterString x _ parts) =
    
    825 836
       char 's' <> delim <> hcat (map pprInterPart parts) <> delim
    
    826 837
       where
    
    838
    +    isMultiline =
    
    839
    +      case (ghcPass @p, x) of
    
    840
    +        (GhcPs, AnnInterString{ais_delim = AnnInterStringMulti}) -> True
    
    841
    +        (GhcRn, AnnInterString{ais_delim = AnnInterStringMulti}) -> True
    
    842
    +        _ -> False
    
    827 843
         delim
    
    828
    -      | strMetaMultiline meta = text "\"\"\""
    
    844
    +      | isMultiline = text "\"\"\""
    
    829 845
           | otherwise = char '"'
    
    830 846
         pprInterPart = \case
    
    831 847
           HsInterStringExpr _ expr -> text "${" <> ppr_lexpr expr <> text "}"
    
    832 848
           HsInterStringRaw st s ->
    
    833 849
             case st of
    
    834 850
               SourceText src
    
    835
    -            | strMetaMultiline meta -> vcat $ map text $ split '\n' (unpackFS src)
    
    851
    +            | isMultiline -> vcat $ map text $ split '\n' (unpackFS src)
    
    836 852
                 | otherwise -> ftext src
    
    837 853
               NoSourceText
    
    838
    -            | strMetaMultiline meta -> pprHsStringMulti' (unpackHText s)
    
    854
    +            | isMultiline -> pprHsStringMulti' (unpackHText s)
    
    839 855
                 | otherwise -> pprHsString' (unpackHText s)
    
    840 856
     
    
    841 857
     ppr_expr (HsHole x) = case (ghcPass @p, x) of
    

  • compiler/GHC/HsToCore/Ticks.hs
    ... ... @@ -584,8 +584,8 @@ addTickHsExpr e@(HsLit {}) = return e
    584 584
     addTickHsExpr e@(HsQualLit {})          = return e
    
    585 585
     addTickHsExpr (HsInterString x ty parts) = do
    
    586 586
       parts' <- forM parts $ \case
    
    587
    -    part@(HsInterStringRaw {}) -> return part
    
    588 587
         HsInterStringExpr x e -> HsInterStringExpr x <$> addTickLHsExpr e
    
    588
    +    p -> return p
    
    589 589
       return $ HsInterString x ty parts'
    
    590 590
     addTickHsExpr e@(HsEmbTy {})            = return e
    
    591 591
     addTickHsExpr e@(HsStar {})             = return e
    

  • compiler/GHC/Parser.y
    ... ... @@ -4419,9 +4419,18 @@ processStringInter ::
    4419 4419
     processStringInter tokBegin parts tokEnd = do
    
    4420 4420
       parts' <- mapM mkInterStringPartPV $ processRawLexedStrings parts
    
    4421 4421
       ams1 (L (comb2 tokBegin tokEnd) ()) $
    
    4422
    -    HsInterString noExtField meta parts'
    
    4422
    +    HsInterString ann (strMetaQualified meta) parts'
    
    4423 4423
       where
    
    4424 4424
         L _ (ITstringInterBegin meta) = tokBegin
    
    4425
    +    ann =
    
    4426
    +      AnnInterString
    
    4427
    +        { ais_delim =
    
    4428
    +            if strMetaMultiline meta
    
    4429
    +              then AnnInterStringMulti
    
    4430
    +              else AnnInterStringSingle
    
    4431
    +        , ais_open = glR tokBegin
    
    4432
    +        , ais_close = glR tokEnd
    
    4433
    +        }
    
    4425 4434
     
    
    4426 4435
         processRawLexedStrings ::
    
    4427 4436
           [Either (SourceText, RawLexedString) ECP] ->
    

  • compiler/GHC/Parser/Lexer.x
    ... ... @@ -2236,7 +2236,7 @@ tok_string_inter_begin meta span _ _ _ = do
    2236 2236
     
    
    2237 2237
     tok_string_inter_qual_begin :: StringMeta -> Action
    
    2238 2238
     tok_string_inter_qual_begin meta span buf len buf2 = do
    
    2239
    -  let modName = ModuleName $ lexemeToFastString buf modNameLen
    
    2239
    +  let modName = HsModuleName $ lexemeToText buf modNameLen
    
    2240 2240
       let meta' = meta{strMetaQualified = Just modName}
    
    2241 2241
       tok_string_inter_begin meta' span buf len buf2
    
    2242 2242
       where
    

  • compiler/GHC/Parser/Lexer/String.x
    ... ... @@ -73,8 +73,8 @@ $hexit = [$decdigit A-F a-f]
    73 73
            | "DC1" | "DC2" | "DC3" | "DC4" | "NAK" | "SYN" | "ETB" | "CAN"
    
    74 74
            | "EM" | "SUB" | "ESC" | "FS" | "GS" | "RS" | "US" | "SP" | "DEL"
    
    75 75
     @escape     = \\ ( $charesc      | @ascii | @decimal | o @octal | x @hexadecimal )
    
    76
    -@stringchar = ($graphic # [\\ \"])         | $space | @escape     | @gap
    
    77
    -@stringinterchar = ($graphic # [\\ \" \$]) | $space | @escape     | @gap
    
    76
    +@stringchar = ($graphic # [\\ \"])         | $space | @escape         | @gap
    
    77
    +@stringinterchar = ($graphic # [\\ \" \$]) | $space | @escape | \\ \$ | @gap
    
    78 78
     
    
    79 79
     :-
    
    80 80
     
    
    ... ... @@ -91,7 +91,6 @@ $hexit = [$decdigit A-F a-f]
    91 91
     
    
    92 92
     -- Note [Lexing interpolated strings]
    
    93 93
     -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    94
    ---
    
    95 94
     -- Lexing interpolated strings will do the following steps:
    
    96 95
     --
    
    97 96
     -- 1. Lex `s"` => push `string_inter_content` lex state
    
    ... ... @@ -123,6 +122,7 @@ $hexit = [$decdigit A-F a-f]
    123 122
       (\" | \"\") / ([\n .] # \")   { StringInterContentRaw }
    
    124 123
     
    
    125 124
       \$ \{                         { StringInterContentExpOpen }
    
    125
    +  \$                            { StringInterContentRaw }
    
    126 126
       \" \" \"                      { StringInterContentEnd }
    
    127 127
     }
    
    128 128
     
    

  • compiler/GHC/Parser/String.hs
    ... ... @@ -32,6 +32,7 @@ import qualified Data.Foldable1 as Foldable1
    32 32
     import Data.Functor.Identity (Identity (..))
    
    33 33
     import qualified Data.List.NonEmpty as NonEmpty
    
    34 34
     import Data.Maybe (listToMaybe, mapMaybe)
    
    35
    +import GHC.Data.Maybe (rightToMaybe)
    
    35 36
     import GHC.Data.OrdList (fromOL, nilOL, snocOL)
    
    36 37
     import GHC.Data.StringBuffer (StringBuffer)
    
    37 38
     import qualified GHC.Data.StringBuffer as StringBuffer
    
    ... ... @@ -51,7 +52,7 @@ data StringLexError = StringLexError LexErr BufPos
    51 52
       deriving (Show, Eq)
    
    52 53
     
    
    53 54
     lexString :: Int -> StringBuffer -> Either StringLexError String
    
    54
    -lexString = lexStringWith (fromRight . processCharsSingle)
    
    55
    +lexString = lexStringWith (rightToMaybe . processCharsSingle)
    
    55 56
     
    
    56 57
     -- -----------------------------------------------------------------------------
    
    57 58
     -- Lexing interface
    
    ... ... @@ -194,7 +195,7 @@ resolveEscapes = go nilOL
    194 195
           c : cs -> go (acc `snocOL` c) cs
    
    195 196
     
    
    196 197
     resolveEscapesMaybe :: HasChar c => [c] -> Maybe [c]
    
    197
    -resolveEscapesMaybe = fromRight . resolveEscapes
    
    198
    +resolveEscapesMaybe = rightToMaybe . resolveEscapes
    
    198 199
     
    
    199 200
     -- -----------------------------------------------------------------------------
    
    200 201
     -- Escape characters
    
    ... ... @@ -221,6 +222,8 @@ resolveEscapeChar = \case
    221 222
       Char '^' : Char c : cs -> pure (chr $ ord c - ord '@', cs)
    
    222 223
       -- long form escapes (e.g. '\NUL')
    
    223 224
       cs | Just (esc, cs') <- parseLongEscape cs -> pure (esc, cs')
    
    225
    +  -- string interpolation
    
    226
    +  Char '$' : cs -> pure ('$', cs)
    
    224 227
       -- shouldn't happen
    
    225 228
       Char c : _ -> panic $ "found unexpected escape character: " ++ show c
    
    226 229
       [] -> panic "escape character unexpectedly ended"
    
    ... ... @@ -626,9 +629,3 @@ It's more precisely defined with the following algorithm:
    626 629
         * Lines with only whitespace characters
    
    627 630
     3. Calculate the longest prefix of whitespace shared by all lines in the remaining list
    
    628 631
     -}
    629
    -
    
    630
    --- -----------------------------------------------------------------------------
    
    631
    --- Other utilities
    
    632
    -
    
    633
    -fromRight :: Either e a -> Maybe a
    
    634
    -fromRight = either (const Nothing) Just

  • compiler/GHC/Rename/Expr.hs
    ... ... @@ -379,9 +379,9 @@ rnExpr (HsOverLit x lit)
    379 379
                      return (HsApp noExtField (noLocA neg) (noLocA (HsOverLit x lit'))
    
    380 380
                             , fvs ) }
    
    381 381
     
    
    382
    -rnExpr (HsInterString _ meta parts) = do
    
    382
    +rnExpr (HsInterString _ mQual parts) = do
    
    383 383
       (parts', fvs1) <- unzip <$> mapM rnInterStringPart parts
    
    384
    -  (expr, fvs2) <- rewriteInterString meta parts'
    
    384
    +  (expr, fvs2) <- rewriteInterString mQual parts'
    
    385 385
       pure (expr, plusFNs fvs1 `plusFN` fvs2)
    
    386 386
       where
    
    387 387
         rnInterStringPart = \case
    

  • compiler/GHC/Rename/String.hs
    ... ... @@ -14,14 +14,14 @@ import GHC.Rename.Env (lookupNameWithQualifier, lookupSyntaxExpr, lookupSyntaxNa
    14 14
     import GHC.Tc.Utils.Monad
    
    15 15
     import GHC.Types.Name.Set (FreeNames, emptyFNs, plusFNs)
    
    16 16
     import GHC.Types.SrcLoc (unLoc)
    
    17
    -import Language.Haskell.Syntax.StringMeta (StringMeta (..))
    
    17
    +import Language.Haskell.Syntax.Module.Name (HsModuleName)
    
    18 18
     
    
    19 19
     {- Note [Desugaring interpolated strings]
    
    20 20
     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    21 21
     
    
    22 22
     Cross-references:
    
    23
    -* Note [Parsing interpolated strings]
    
    24
    -* Note [Doing XXExprGhcRn in the Renamer vs Typechecker]
    
    23
    +  * Note [Parsing interpolated strings]
    
    24
    +  * Note [Doing XXExprGhcRn in the Renamer vs Typechecker]
    
    25 25
     
    
    26 26
     Interpolated strings are represented with the following HsExpr tree:
    
    27 27
     
    
    ... ... @@ -52,10 +52,10 @@ can be typechecked as usual, without any additional work.
    52 52
     -- have already been renamed, but handles renaming of overloaded strings, if
    
    53 53
     -- necessary.
    
    54 54
     rewriteInterString ::
    
    55
    -  StringMeta ->
    
    55
    +  Maybe HsModuleName ->
    
    56 56
       [HsInterStringPart GhcRn] ->
    
    57 57
       RnM (HsExpr GhcRn, FreeNames)
    
    58
    -rewriteInterString meta parts = do
    
    58
    +rewriteInterString mQual parts = do
    
    59 59
       (mkOverloaded, fns1) <- get_mkOverloaded
    
    60 60
       (rawName, fns2) <- lookupName KnownOccs.interpolateRawIdOcc
    
    61 61
       (convertName, fns3) <- lookupName KnownOccs.interpolateValueIdOcc
    
    ... ... @@ -73,7 +73,7 @@ rewriteInterString meta parts = do
    73 73
       pure (expr, plusFNs [fns1, fns2, fns3, fns4, fns5, fns6])
    
    74 74
       where
    
    75 75
         lookupName =
    
    76
    -      case strMetaQualified meta of
    
    76
    +      case mQual of
    
    77 77
             Just mod -> lookupNameWithQualifier mod
    
    78 78
             Nothing -> lookupSyntaxName
    
    79 79
     
    
    ... ... @@ -84,7 +84,7 @@ rewriteInterString meta parts = do
    84 84
         -- Handle -XOverloadedStrings
    
    85 85
         get_mkOverloaded = do
    
    86 86
           overloaded <- xoptM LangExt.OverloadedStrings
    
    87
    -      if overloaded && isNothing (strMetaQualified meta)
    
    87
    +      if overloaded && isNothing mQual
    
    88 88
             then do
    
    89 89
               (fromStringExpr, fns) <- lookupSyntaxExpr KnownOccs.fromStringClassOpOcc
    
    90 90
               pure (nlHsApp (noLocA fromStringExpr), fns)
    

  • compiler/Language/Haskell/Syntax/Expr.hs
    ... ... @@ -21,7 +21,6 @@ import Language.Haskell.Syntax.Text
    21 21
     import Language.Haskell.Syntax.Module.Name
    
    22 22
     import Language.Haskell.Syntax.Type
    
    23 23
     import Language.Haskell.Syntax.Binds
    
    24
    -import Language.Haskell.Syntax.StringMeta (StringMeta)
    
    25 24
     
    
    26 25
     -- libraries:
    
    27 26
     import Data.Data hiding (Fixity(..))
    
    ... ... @@ -345,7 +344,7 @@ data HsExpr p
    345 344
       | -- | See Note [Parsing interpolated strings]
    
    346 345
         HsInterString
    
    347 346
           (XInterString p)
    
    348
    -      StringMeta
    
    347
    +      (Maybe HsModuleName)
    
    349 348
           [HsInterStringPart p]
    
    350 349
     
    
    351 350
       -- | Lambda, Lambda-case, and Lambda-cases
    
    ... ... @@ -591,6 +590,7 @@ data HsLamVariant
    591 590
     data HsInterStringPart p
    
    592 591
       = HsInterStringRaw (XInterStringRaw p) HText
    
    593 592
       | HsInterStringExpr (XInterStringExpr p) (LHsExpr p)
    
    593
    +  | XHsInterStringPart !(XXInterStringPart p)
    
    594 594
     
    
    595 595
     {-
    
    596 596
     Note [Parens in HsSyn]
    

  • compiler/Language/Haskell/Syntax/Extension.hs
    ... ... @@ -500,6 +500,7 @@ type family XQualLitE x
    500 500
     type family XInterString    x
    
    501 501
     type family XInterStringRaw x
    
    502 502
     type family XInterStringExpr x
    
    503
    +type family XXInterStringPart x
    
    503 504
     type family XLam            x
    
    504 505
     type family XLamCase        x
    
    505 506
     type family XApp            x
    

  • testsuite/tests/parser/should_fail/StringInterpolationLessIndent.hs
    1
    +{-# LANGUAGE StringInterpolation #-}
    
    2
    +
    
    3
    +test :: String
    
    4
    +test = example
    
    5
    +  where
    
    6
    +    example = s"a ${fromMaybe
    
    7
    +  False (Just True)} b"

  • testsuite/tests/parser/should_fail/all.T
    ... ... @@ -269,6 +269,7 @@ test('StringInterpolationInPat', normal, compile_fail, [''])
    269 269
     test('StringInterpolationInType', normal, compile_fail, [''])
    
    270 270
     test('StringInterpolationLineComment', normal, compile_fail, [''])
    
    271 271
     test('StringInterpolationSmartQuotes', normal, compile_fail, [''])
    
    272
    +test('StringInterpolationLessIndent', normal, compile_fail, [''])
    
    272 273
     
    
    273 274
     # ---------- END OF FILE ---------- #
    
    274 275
     # Don't just place tests at the end here; put in correct section

  • testsuite/tests/parser/should_run/StringInterpolation.hs
    ... ... @@ -46,6 +46,14 @@ allTests =
    46 46
           , expression =
    
    47 47
               let s = "world" in s ++ s" hello ${s}"
    
    48 48
           }
    
    49
    +  , TestCase -- dollars
    
    50
    +      { label =
    
    51
    +          """
    
    52
    +          "$foo \\$foo \\${foo}"
    
    53
    +          """
    
    54
    +      , expression =
    
    55
    +          "$foo \$foo \${foo}"
    
    56
    +      }
    
    49 57
       , TestCase -- curly brace Char
    
    50 58
           { label =
    
    51 59
               """
    
    ... ... @@ -54,6 +62,36 @@ allTests =
    54 62
           , expression =
    
    55 63
               s"a ${'}'} b"
    
    56 64
           }
    
    65
    +  , TestCase -- interpolated multiline expression
    
    66
    +      { label =
    
    67
    +          """
    
    68
    +          let a = s"example ${fromMaybe
    
    69
    +                                (0 :: Int)
    
    70
    +                                (Just 10)} value"
    
    71
    +              b = s"example ${fromMaybe
    
    72
    +                False (Just True)} value"
    
    73
    +          in a ++ b
    
    74
    +          """
    
    75
    +      , expression =
    
    76
    +          let a = s"example ${fromMaybe
    
    77
    +                                (0 :: Int)
    
    78
    +                                (Just 10)} value"
    
    79
    +              b = s"example ${fromMaybe
    
    80
    +                False (Just True)} value"
    
    81
    +          in a ++ b
    
    82
    +      }
    
    83
    +  , TestCase -- interpolated expression blocks
    
    84
    +      { label =
    
    85
    +          """
    
    86
    +          let a = s"${case True of True -> 1; False -> 2 :: Int}"
    
    87
    +              b = s"${do True}"
    
    88
    +          in a ++ b
    
    89
    +          """
    
    90
    +      , expression =
    
    91
    +          let a = s"${case True of True -> 1; False -> 2 :: Int}"
    
    92
    +              b = s"${do True}"
    
    93
    +          in a ++ b
    
    94
    +      }
    
    57 95
       , TestCase -- interpolated expression with comment
    
    58 96
           { label =
    
    59 97
               """
    
    ... ... @@ -146,7 +184,24 @@ allTests =
    146 184
           , expression =
    
    147 185
               let x = "test" in s"a “${x}” b"
    
    148 186
           }
    
    149
    -  -- TODO(bchinn): interpolated multiline strings
    
    187
    +  , TestCase -- interpolated multiline strings
    
    188
    +      { label =
    
    189
    +          """
    
    190
    +          let x = "test" in
    
    191
    +            s\"""
    
    192
    +            line one
    
    193
    +            ${x}
    
    194
    +            a "quoted value"
    
    195
    +            \"""
    
    196
    +          """
    
    197
    +      , expression =
    
    198
    +          let x = "test" in
    
    199
    +            s"""
    
    200
    +            line one
    
    201
    +            ${x}
    
    202
    +            a "quoted value"
    
    203
    +            """
    
    204
    +      }
    
    150 205
       ]
    
    151 206
     
    
    152 207
     {----- Types for tests -----}
    

  • testsuite/tests/printer/Makefile
    ... ... @@ -933,6 +933,11 @@ PprQualifiedStrings:
    933 933
     	$(CHECK_PPR)   $(LIBDIR) PprQualifiedStrings.hs
    
    934 934
     	$(CHECK_EXACT) $(LIBDIR) PprQualifiedStrings.hs
    
    935 935
     
    
    936
    +.PHONY: PprStringInterpolation
    
    937
    +PprStringInterpolation:
    
    938
    +	$(CHECK_PPR)   $(LIBDIR) PprStringInterpolation.hs
    
    939
    +	$(CHECK_EXACT) $(LIBDIR) PprStringInterpolation.hs
    
    940
    +
    
    936 941
     .PHONY: Haddock1
    
    937 942
     Haddock1:
    
    938 943
     	# $(CHECK_PPR)   $(LIBDIR) Haddock1.hs
    

  • testsuite/tests/printer/PprStringInterpolation.hs
    1
    +{-# LANGUAGE MultilineStrings #-}
    
    2
    +{-# LANGUAGE QualifiedStrings #-}
    
    3
    +{-# LANGUAGE StringInterpolation #-}
    
    4
    +
    
    5
    +module PprQualifiedStrings where
    
    6
    +
    
    7
    +import qualified Example.Text as Text
    
    8
    +
    
    9
    +exprs :: IO ()
    
    10
    +exprs = do
    
    11
    +  let name = "Alice"
    
    12
    +  print s"My name is: ${name}. Nice to meet you!"
    
    13
    +  print s"""
    
    14
    +    My name is:
    
    15
    +      ${name}
    
    16
    +    Nice to meet you!
    
    17
    +  """
    
    18
    +  print Text.s"My name is: ${name}. Nice to meet you!"
    
    19
    +  print Text.s"""
    
    20
    +    My name is:
    
    21
    +      ${name}
    
    22
    +    Nice to meet you!
    
    23
    +  """

  • testsuite/tests/printer/all.T
    ... ... @@ -226,3 +226,4 @@ test('PprQualifiedStrings', [ignore_stderr,req_ppr_deps], makefile_test, ['PprQu
    226 226
     test('Haddock1', [ignore_stderr,req_ppr_deps], makefile_test, ['Haddock1'])
    
    227 227
     test('T27423c', [ignore_stderr,req_ppr_deps], makefile_test, ['T27423c'])
    
    228 228
     test('PprStringNoSourceText', normal, compile, [''])
    
    229
    +test('PprStringInterpolation', [ignore_stderr,req_ppr_deps], makefile_test, ['PprStringInterpolation'])