Skip to content

Commit 2e95cbc

Browse files
dawedaweabonie
andauthored
fix wrong range start of INTERP_STRING_END (#16774)
* fix wrong range start of INTERP_STRING_END * add release notes entry --------- Co-authored-by: Adam Boniecki <20281641+abonie@users.noreply.github.com>
1 parent 1899bce commit 2e95cbc

File tree

11 files changed

+75
-43
lines changed

11 files changed

+75
-43
lines changed

docs/release-notes/.FSharp.Compiler.Service/8.0.300.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
### Fixed
22

3+
* Fix wrong range start of INTERP_STRING_END. ([PR #16774](https://github.com/dotnet/fsharp/pull/16774))
34
* Fix missing warning for recursive calls in list comprehensions. ([PR #16652](https://github.com/dotnet/fsharp/pull/16652))
45
* Code generated files with > 64K methods and generated symbols crash when loaded. Use infered sequence points for debugging. ([Issue #16399](https://github.com/dotnet/fsharp/issues/16399), [#PR 16514](https://github.com/dotnet/fsharp/pull/16514))
56
* `nameof Module` expressions and patterns are processed to link files in `--test:GraphBasedChecking`. ([PR #16550](https://github.com/dotnet/fsharp/pull/16550), [PR #16743](https://github.com/dotnet/fsharp/pull/16743))

src/Compiler/Service/FSharpCheckerResults.fs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2685,7 +2685,7 @@ module internal ParseAndCheckFile =
26852685
| INTERP_STRING_BEGIN_PART _ | INTERP_STRING_PART _ as tok, _ ->
26862686
let braceOffset =
26872687
match tok with
2688-
| INTERP_STRING_BEGIN_PART(_, SynStringKind.TripleQuote, (LexerContinuation.Token(_, (_, _, dl, _) :: _))) ->
2688+
| INTERP_STRING_BEGIN_PART(_, SynStringKind.TripleQuote, (LexerContinuation.Token(_, (_, _, dl, _, _) :: _))) ->
26892689
dl - 1
26902690
| _ -> 0
26912691

src/Compiler/Service/ServiceLexing.fs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ module FSharpTokenTag =
3636
tagOfToken (INTERP_STRING_BEGIN_PART("a", SynStringKind.Regular, LexCont.Default))
3737

3838
let INTERP_STRING_PART = tagOfToken (INTERP_STRING_PART("a", LexCont.Default))
39-
let INTERP_STRING_END = tagOfToken (INTERP_STRING_END("a", LexCont.Default))
39+
let INTERP_STRING_END = tagOfToken (INTERP_STRING_END("a", None, LexCont.Default))
4040
let LPAREN = tagOfToken LPAREN
4141
let RPAREN = tagOfToken RPAREN
4242
let LBRACK = tagOfToken LBRACK
@@ -493,7 +493,7 @@ module internal LexerStateEncoding =
493493
| INTERP_STRING_BEGIN_PART(_, _, cont)
494494
| INTERP_STRING_PART(_, cont)
495495
| INTERP_STRING_BEGIN_END(_, _, cont)
496-
| INTERP_STRING_END(_, cont)
496+
| INTERP_STRING_END(_, _, cont)
497497
| LBRACE cont
498498
| RBRACE cont
499499
| BYTEARRAY(_, _, cont)
@@ -621,12 +621,12 @@ module internal LexerStateEncoding =
621621
let tag1, i1, kind1, rest =
622622
match stringNest with
623623
| [] -> false, 0, 0, []
624-
| (i1, kind1, _, _) :: rest -> true, i1, encodeStringStyle kind1, rest
624+
| (i1, kind1, _, _, _) :: rest -> true, i1, encodeStringStyle kind1, rest
625625

626626
let tag2, i2, kind2 =
627627
match rest with
628628
| [] -> false, 0, 0
629-
| (i2, kind2, _, _) :: _ -> true, i2, encodeStringStyle kind2
629+
| (i2, kind2, _, _, _) :: _ -> true, i2, encodeStringStyle kind2
630630

631631
(if tag1 then 0b100000000000 else 0)
632632
||| (if tag2 then 0b010000000000 else 0)
@@ -696,9 +696,9 @@ module internal LexerStateEncoding =
696696
let nest =
697697
[
698698
if tag1 then
699-
i1, decodeStringStyle kind1, 0, range0
699+
i1, decodeStringStyle kind1, 0, None, range0
700700
if tag2 then
701-
i2, decodeStringStyle kind2, 0, range0
701+
i2, decodeStringStyle kind2, 0, None, range0
702702
]
703703

704704
nest

src/Compiler/SyntaxTree/LexHelpers.fs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ type LexerStringFinisher =
190190
else if isPart then
191191
INTERP_STRING_PART(s, cont)
192192
else
193-
INTERP_STRING_END(s, cont)
193+
INTERP_STRING_END(s, None, cont)
194194
elif kind.IsByteString then
195195
let synByteStringKind =
196196
if isVerbatim then

src/Compiler/SyntaxTree/ParseHelpers.fs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,7 @@ type LexerStringKind =
308308

309309
/// Represents the degree of nesting of '{..}' and the style of the string to continue afterwards, in an interpolation fill.
310310
/// Nesting counters and styles of outer interpolating strings are pushed on this stack.
311-
type LexerInterpolatedStringNesting = (int * LexerStringStyle * int * range) list
311+
type LexerInterpolatedStringNesting = (int * LexerStringStyle * int * range option * range) list
312312

313313
/// The parser defines a number of tokens for whitespace and
314314
/// comments eliminated by the lexer. These carry a specification of
@@ -973,7 +973,7 @@ let checkEndOfFileError t =
973973

974974
match nesting with
975975
| [] -> ()
976-
| (_, _, _, m) :: _ -> reportParseErrorAt m (FSComp.SR.parsEofInInterpolatedStringFill ())
976+
| (_, _, _, _, m) :: _ -> reportParseErrorAt m (FSComp.SR.parsEofInInterpolatedStringFill ())
977977

978978
type BindingSet = BindingSetPreAttrs of range * bool * bool * (SynAttributes -> SynAccess option -> SynAttributes * SynBinding list) * range
979979

src/Compiler/SyntaxTree/ParseHelpers.fsi

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ type LexerStringKind =
118118

119119
static member String: LexerStringKind
120120

121-
type LexerInterpolatedStringNesting = (int * LexerStringStyle * int * range) list
121+
type LexerInterpolatedStringNesting = (int * LexerStringStyle * int * range option * range) list
122122

123123
[<RequireQualifiedAccess; NoComparison; NoEquality>]
124124
type LexerContinuation =

src/Compiler/lex.fsl

Lines changed: 33 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ let checkExprGreaterColonOp (lexbuf:UnicodeLexing.Lexbuf) =
120120
let unexpectedChar lexbuf =
121121
LEX_FAILURE (FSComp.SR.lexUnexpectedChar(lexeme lexbuf))
122122

123-
let startString args (lexbuf: UnicodeLexing.Lexbuf) =
123+
let startString args (lexbuf: UnicodeLexing.Lexbuf) altStartForStringEnd =
124124
let buf = ByteBuffer.Create StringCapacity
125125
let m = lexbuf.LexemeRange
126126
let startp = lexbuf.StartPos
@@ -160,7 +160,7 @@ let startString args (lexbuf: UnicodeLexing.Lexbuf) =
160160
if isPart then
161161
INTERP_STRING_PART (s, cont)
162162
else
163-
INTERP_STRING_END (s, cont)
163+
INTERP_STRING_END (s, altStartForStringEnd, cont)
164164
else
165165
let s = Lexhelp.stringBufferAsString buf
166166
let synStringKind =
@@ -587,20 +587,20 @@ rule token (args: LexArgs) (skip: bool) = parse
587587
else mlOnly m args skip lexbuf }
588588

589589
| '"'
590-
{ let buf, fin, m = startString args lexbuf
590+
{ let buf, fin, m = startString args lexbuf None
591591

592592
// Single quote in triple quote ok, others disallowed
593593
match args.stringNest with
594-
| (_, LexerStringStyle.ExtendedInterpolated, _, _) :: _
595-
| (_, LexerStringStyle.TripleQuote, _, _) :: _ -> ()
594+
| (_, LexerStringStyle.ExtendedInterpolated, _, _, _) :: _
595+
| (_, LexerStringStyle.TripleQuote, _, _, _) :: _ -> ()
596596
| _ :: _ -> errorR(Error(FSComp.SR.lexSingleQuoteInSingleQuote(), m))
597597
| [] -> ()
598598

599599
if not skip then STRING_TEXT (LexCont.String(args.ifdefStack, args.stringNest, LexerStringStyle.SingleQuote, LexerStringKind.String, args.interpolationDelimiterLength, m))
600600
else singleQuoteString (buf, fin, m, LexerStringKind.String, args) skip lexbuf }
601601

602602
| '$' '"' '"' '"'
603-
{ let buf, fin, m = startString args lexbuf
603+
{ let buf, fin, m = startString args lexbuf None
604604

605605
// Single quote in triple quote ok, others disallowed
606606
match args.stringNest with
@@ -612,7 +612,7 @@ rule token (args: LexArgs) (skip: bool) = parse
612612
else tripleQuoteString (buf, fin, m, LexerStringKind.InterpolatedStringFirst, args) skip lexbuf }
613613

614614
| ('$'+) '"' '"' '"'
615-
{ let buf, fin, m = startString args lexbuf
615+
{ let buf, fin, m = startString args lexbuf None
616616

617617
if lexbuf.SupportsFeature LanguageFeature.ExtendedStringInterpolation then
618618
// Single quote in triple quote ok, others disallowed
@@ -635,11 +635,11 @@ rule token (args: LexArgs) (skip: bool) = parse
635635
}
636636

637637
| '$' '"'
638-
{ let buf,fin,m = startString args lexbuf
638+
{ let buf,fin,m = startString args lexbuf None
639639

640640
// Single quote in triple quote ok, others disallowed
641641
match args.stringNest with
642-
| (_, style, _, _) :: _ when style = LexerStringStyle.ExtendedInterpolated || style = LexerStringStyle.TripleQuote -> ()
642+
| (_, style, _, _, _) :: _ when style = LexerStringStyle.ExtendedInterpolated || style = LexerStringStyle.TripleQuote -> ()
643643
| _ :: _ -> errorR(Error(FSComp.SR.lexSingleQuoteInSingleQuote(), m))
644644
| _ -> ()
645645

@@ -649,7 +649,7 @@ rule token (args: LexArgs) (skip: bool) = parse
649649
singleQuoteString (buf, fin, m, LexerStringKind.InterpolatedStringFirst, args) skip lexbuf }
650650

651651
| '"' '"' '"'
652-
{ let buf, fin, m = startString args lexbuf
652+
{ let buf, fin, m = startString args lexbuf None
653653

654654
args.interpolationDelimiterLength <- 0
655655

@@ -664,12 +664,12 @@ rule token (args: LexArgs) (skip: bool) = parse
664664
tripleQuoteString (buf, fin, m, LexerStringKind.String, args) skip lexbuf }
665665

666666
| '@' '"'
667-
{ let buf, fin, m = startString args lexbuf
667+
{ let buf, fin, m = startString args lexbuf None
668668

669669
// Single quote in triple quote ok, others disallowed
670670
match args.stringNest with
671-
| (_, LexerStringStyle.ExtendedInterpolated, _, _) :: _
672-
| (_, LexerStringStyle.TripleQuote, _, _) :: _ -> ()
671+
| (_, LexerStringStyle.ExtendedInterpolated, _, _, _) :: _
672+
| (_, LexerStringStyle.TripleQuote, _, _, _) :: _ -> ()
673673
| _ :: _ -> errorR(Error(FSComp.SR.lexSingleQuoteInSingleQuote(), m))
674674
| _ -> ()
675675

@@ -679,11 +679,11 @@ rule token (args: LexArgs) (skip: bool) = parse
679679
verbatimString (buf, fin, m, LexerStringKind.String, args) skip lexbuf }
680680

681681
| ("$@" | "@$") '"'
682-
{ let buf, fin, m = startString args lexbuf
682+
{ let buf, fin, m = startString args lexbuf None
683683

684684
// Single quote in triple quote ok, others disallowed
685685
match args.stringNest with
686-
| (_, style, _, _) :: _ when style = LexerStringStyle.ExtendedInterpolated || style = LexerStringStyle.TripleQuote -> ()
686+
| (_, style, _, _, _) :: _ when style = LexerStringStyle.ExtendedInterpolated || style = LexerStringStyle.TripleQuote -> ()
687687
| _ :: _ -> errorR(Error(FSComp.SR.lexSingleQuoteInSingleQuote(), m))
688688
| _ -> ()
689689

@@ -888,10 +888,10 @@ rule token (args: LexArgs) (skip: bool) = parse
888888
{
889889
match args.stringNest with
890890
| [] -> ()
891-
| (counter, style, d, m) :: rest ->
891+
| (counter, style, d, _, m) :: rest ->
892892
// Note, we do not update the 'm', any incomplete-interpolation error
893893
// will be reported w.r.t. the first '{'
894-
args.stringNest <- (counter + 1, style, d, m) :: rest
894+
args.stringNest <- (counter + 1, style, d, None, m) :: rest
895895
// To continue token-by-token lexing may involve picking up the new args.stringNes
896896
let cont = LexCont.Token(args.ifdefStack, args.stringNest)
897897
LBRACE cont
@@ -904,12 +904,17 @@ rule token (args: LexArgs) (skip: bool) = parse
904904
// We encounter a '}' in the expression token stream. First check if we're in an interpolated string expression
905905
// and continue the string if necessary
906906
match args.stringNest with
907-
| (1, LexerStringStyle.ExtendedInterpolated, delimLength, r) :: rest when delimLength > 1 ->
908-
args.stringNest <- (1, LexerStringStyle.ExtendedInterpolated, delimLength - 1, r) :: rest
907+
| (1, LexerStringStyle.ExtendedInterpolated, delimLength, altR, r) :: rest when delimLength > 1 ->
908+
// On the first "}" of multiple "}", keep the range of the starting "}" for later processing in startString
909+
let altStart =
910+
match altR with
911+
| None -> Some lexbuf.LexemeRange
912+
| _ -> altR
913+
args.stringNest <- (1, LexerStringStyle.ExtendedInterpolated, delimLength - 1, altStart, r) :: rest
909914
token args skip lexbuf
910-
| (1, style, _, _) :: rest ->
915+
| (1, style, _, altR, _r) :: rest ->
911916
args.stringNest <- rest
912-
let buf, fin, m = startString args lexbuf
917+
let buf, fin, m = startString args lexbuf altR
913918
if not skip then
914919
STRING_TEXT (LexCont.String(args.ifdefStack, args.stringNest, style, LexerStringKind.InterpolatedStringPart, args.interpolationDelimiterLength, m))
915920
else
@@ -918,11 +923,10 @@ rule token (args: LexArgs) (skip: bool) = parse
918923
| LexerStringStyle.SingleQuote -> singleQuoteString (buf, fin, m, LexerStringKind.InterpolatedStringPart, args) skip lexbuf
919924
| LexerStringStyle.TripleQuote -> tripleQuoteString (buf, fin, m, LexerStringKind.InterpolatedStringPart, args) skip lexbuf
920925
| LexerStringStyle.ExtendedInterpolated -> extendedInterpolatedString (buf, fin, m, LexerStringKind.InterpolatedStringPart, args) skip lexbuf
921-
922-
| (counter, style, d, m) :: rest ->
926+
| (counter, style, d, altR, m) :: rest ->
923927
// Note, we do not update the 'm', any incomplete-interpolation error
924928
// will be reported w.r.t. the first '{'
925-
args.stringNest <- (counter - 1, style, d, m) :: rest
929+
args.stringNest <- (counter - 1, style, d, altR, m) :: rest
926930
let cont = LexCont.Token(args.ifdefStack, args.stringNest)
927931
RBRACE cont
928932

@@ -1260,7 +1264,7 @@ and singleQuoteString (sargs: LexerStringArgs) (skip: bool) = parse
12601264
if kind.IsInterpolated then
12611265
// get a new range for where the fill starts
12621266
let m2 = lexbuf.LexemeRange
1263-
args.stringNest <- (1, LexerStringStyle.SingleQuote, args.interpolationDelimiterLength, m2) :: args.stringNest
1267+
args.stringNest <- (1, LexerStringStyle.SingleQuote, args.interpolationDelimiterLength, None, m2) :: args.stringNest
12641268
let cont = LexCont.Token(args.ifdefStack, args.stringNest)
12651269
fin.Finish buf kind LexerStringFinisherContext.InterpolatedPart cont
12661270
else
@@ -1376,7 +1380,7 @@ and verbatimString (sargs: LexerStringArgs) (skip: bool) = parse
13761380
if kind.IsInterpolated then
13771381
// get a new range for where the fill starts
13781382
let m2 = lexbuf.LexemeRange
1379-
args.stringNest <- (1, LexerStringStyle.Verbatim, args.interpolationDelimiterLength, m2) :: args.stringNest
1383+
args.stringNest <- (1, LexerStringStyle.Verbatim, args.interpolationDelimiterLength, None, m2) :: args.stringNest
13801384
let cont = LexCont.Token(args.ifdefStack, args.stringNest)
13811385
fin.Finish buf kind (LexerStringFinisherContext.InterpolatedPart ||| LexerStringFinisherContext.Verbatim) cont
13821386
else
@@ -1495,7 +1499,7 @@ and tripleQuoteString (sargs: LexerStringArgs) (skip: bool) = parse
14951499
if kind.IsInterpolated then
14961500
// get a new range for where the fill starts
14971501
let m2 = lexbuf.LexemeRange
1498-
args.stringNest <- (1, LexerStringStyle.TripleQuote, args.interpolationDelimiterLength, m2) :: args.stringNest
1502+
args.stringNest <- (1, LexerStringStyle.TripleQuote, args.interpolationDelimiterLength, None, m2) :: args.stringNest
14991503
let cont = LexCont.Token(args.ifdefStack, args.stringNest)
15001504
fin.Finish buf kind (LexerStringFinisherContext.InterpolatedPart ||| LexerStringFinisherContext.TripleQuote) cont
15011505
else
@@ -1600,7 +1604,7 @@ and extendedInterpolatedString (sargs: LexerStringArgs) (skip: bool) = parse
16001604
let maxBraces = 2 * args.interpolationDelimiterLength - 1
16011605
if numBraces > maxBraces then
16021606
let m2 = lexbuf.LexemeRange
1603-
args.stringNest <- (1, LexerStringStyle.ExtendedInterpolated, args.interpolationDelimiterLength, m2) :: args.stringNest
1607+
args.stringNest <- (1, LexerStringStyle.ExtendedInterpolated, args.interpolationDelimiterLength, None, m2) :: args.stringNest
16041608
let cont = LexCont.Token(args.ifdefStack, args.stringNest)
16051609
fail args lexbuf
16061610
(FSComp.SR.lexTooManyLBracesInTripleQuote())
@@ -1621,7 +1625,7 @@ and extendedInterpolatedString (sargs: LexerStringArgs) (skip: bool) = parse
16211625
String.replicate extraBraces "{" |> addUnicodeString buf
16221626
// get a new range for where the fill starts
16231627
let m2 = lexbuf.LexemeRange
1624-
args.stringNest <- (1, LexerStringStyle.ExtendedInterpolated, args.interpolationDelimiterLength, m2) :: args.stringNest
1628+
args.stringNest <- (1, LexerStringStyle.ExtendedInterpolated, args.interpolationDelimiterLength, None, m2) :: args.stringNest
16251629
let cont = LexCont.Token(args.ifdefStack, args.stringNest)
16261630
fin.Finish buf kind (LexerStringFinisherContext.InterpolatedPart ||| LexerStringFinisherContext.TripleQuote) cont
16271631
}

src/Compiler/pars.fsy

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ let parse_error_rich = Some(fun (ctxt: ParseErrorContext<_>) ->
3838
%token <string * SynStringKind * ParseHelpers.LexerContinuation> INTERP_STRING_BEGIN_END
3939
%token <string * SynStringKind * ParseHelpers.LexerContinuation> INTERP_STRING_BEGIN_PART
4040
%token <string * ParseHelpers.LexerContinuation> INTERP_STRING_PART
41-
%token <string * ParseHelpers.LexerContinuation> INTERP_STRING_END
41+
%token <string * range option * ParseHelpers.LexerContinuation> INTERP_STRING_END
4242
%token <ParseHelpers.LexerContinuation> LBRACE RBRACE
4343

4444
%token <string * string> KEYWORD_STRING // Like __SOURCE_DIRECTORY__
@@ -6774,7 +6774,14 @@ interpolatedStringFill:
67746774

67756775
interpolatedStringParts:
67766776
| INTERP_STRING_END
6777-
{ [ SynInterpolatedStringPart.String(fst $1, rhs parseState 1) ] }
6777+
{
6778+
let (s, altStart, _) = $1
6779+
let mOrig = rhs parseState 1
6780+
let m =
6781+
match altStart with
6782+
| Some r -> unionRanges r mOrig
6783+
| None -> mOrig
6784+
[ SynInterpolatedStringPart.String(s, m) ] }
67786785

67796786
| INTERP_STRING_PART interpolatedStringFill interpolatedStringParts
67806787
{ SynInterpolatedStringPart.String(fst $1, rhs parseState 1) :: SynInterpolatedStringPart.FillExpr $2 :: $3 }

tests/service/data/SyntaxTree/String/SynExprInterpolatedStringWithTripleQuoteMultipleDollars.fs.bsl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ ImplFile
2020
FillExpr (Const (Int32 41, (2,21--2,23)), None);
2121
String (" = ", (2,25--2,32));
2222
FillExpr (Const (Int32 6, (2,32--2,33)), None);
23-
String (" * 7", (2,35--2,43))], TripleQuote, (2,8--2,43)),
23+
String (" * 7", (2,33--2,43))], TripleQuote, (2,8--2,43)),
2424
(2,4--2,5), Yes (2,0--2,43), { LeadingKeyword = Let (2,0--2,3)
2525
InlineKeyword = None
2626
EqualsRange = Some (2,6--2,7) })],
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
2+
$$$"""{{{5}}}"""

0 commit comments

Comments
 (0)