Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/release-notes/.FSharp.Compiler.Service/8.0.300.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
### Fixed

* Fix wrong range start of INTERP_STRING_END. ([PR #16774](https://github.com/dotnet/fsharp/pull/16774))
* Fix missing warning for recursive calls in list comprehensions. ([PR #16652](https://github.com/dotnet/fsharp/pull/16652))
* 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))
* `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))
Expand Down
2 changes: 1 addition & 1 deletion src/Compiler/Service/FSharpCheckerResults.fs
Original file line number Diff line number Diff line change
Expand Up @@ -2685,7 +2685,7 @@ module internal ParseAndCheckFile =
| INTERP_STRING_BEGIN_PART _ | INTERP_STRING_PART _ as tok, _ ->
let braceOffset =
match tok with
| INTERP_STRING_BEGIN_PART(_, SynStringKind.TripleQuote, (LexerContinuation.Token(_, (_, _, dl, _) :: _))) ->
| INTERP_STRING_BEGIN_PART(_, SynStringKind.TripleQuote, (LexerContinuation.Token(_, (_, _, dl, _, _) :: _))) ->
dl - 1
| _ -> 0

Expand Down
12 changes: 6 additions & 6 deletions src/Compiler/Service/ServiceLexing.fs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ module FSharpTokenTag =
tagOfToken (INTERP_STRING_BEGIN_PART("a", SynStringKind.Regular, LexCont.Default))

let INTERP_STRING_PART = tagOfToken (INTERP_STRING_PART("a", LexCont.Default))
let INTERP_STRING_END = tagOfToken (INTERP_STRING_END("a", LexCont.Default))
let INTERP_STRING_END = tagOfToken (INTERP_STRING_END("a", None, LexCont.Default))
let LPAREN = tagOfToken LPAREN
let RPAREN = tagOfToken RPAREN
let LBRACK = tagOfToken LBRACK
Expand Down Expand Up @@ -493,7 +493,7 @@ module internal LexerStateEncoding =
| INTERP_STRING_BEGIN_PART(_, _, cont)
| INTERP_STRING_PART(_, cont)
| INTERP_STRING_BEGIN_END(_, _, cont)
| INTERP_STRING_END(_, cont)
| INTERP_STRING_END(_, _, cont)
| LBRACE cont
| RBRACE cont
| BYTEARRAY(_, _, cont)
Expand Down Expand Up @@ -621,12 +621,12 @@ module internal LexerStateEncoding =
let tag1, i1, kind1, rest =
match stringNest with
| [] -> false, 0, 0, []
| (i1, kind1, _, _) :: rest -> true, i1, encodeStringStyle kind1, rest
| (i1, kind1, _, _, _) :: rest -> true, i1, encodeStringStyle kind1, rest

let tag2, i2, kind2 =
match rest with
| [] -> false, 0, 0
| (i2, kind2, _, _) :: _ -> true, i2, encodeStringStyle kind2
| (i2, kind2, _, _, _) :: _ -> true, i2, encodeStringStyle kind2

(if tag1 then 0b100000000000 else 0)
||| (if tag2 then 0b010000000000 else 0)
Expand Down Expand Up @@ -696,9 +696,9 @@ module internal LexerStateEncoding =
let nest =
[
if tag1 then
i1, decodeStringStyle kind1, 0, range0
i1, decodeStringStyle kind1, 0, None, range0
if tag2 then
i2, decodeStringStyle kind2, 0, range0
i2, decodeStringStyle kind2, 0, None, range0
]

nest
Expand Down
2 changes: 1 addition & 1 deletion src/Compiler/SyntaxTree/LexHelpers.fs
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ type LexerStringFinisher =
else if isPart then
INTERP_STRING_PART(s, cont)
else
INTERP_STRING_END(s, cont)
INTERP_STRING_END(s, None, cont)
elif kind.IsByteString then
let synByteStringKind =
if isVerbatim then
Expand Down
4 changes: 2 additions & 2 deletions src/Compiler/SyntaxTree/ParseHelpers.fs
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ type LexerStringKind =

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

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

match nesting with
| [] -> ()
| (_, _, _, m) :: _ -> reportParseErrorAt m (FSComp.SR.parsEofInInterpolatedStringFill ())
| (_, _, _, _, m) :: _ -> reportParseErrorAt m (FSComp.SR.parsEofInInterpolatedStringFill ())

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

Expand Down
2 changes: 1 addition & 1 deletion src/Compiler/SyntaxTree/ParseHelpers.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ type LexerStringKind =

static member String: LexerStringKind

type LexerInterpolatedStringNesting = (int * LexerStringStyle * int * range) list
type LexerInterpolatedStringNesting = (int * LexerStringStyle * int * range option * range) list

[<RequireQualifiedAccess; NoComparison; NoEquality>]
type LexerContinuation =
Expand Down
62 changes: 33 additions & 29 deletions src/Compiler/lex.fsl
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ let checkExprGreaterColonOp (lexbuf:UnicodeLexing.Lexbuf) =
let unexpectedChar lexbuf =
LEX_FAILURE (FSComp.SR.lexUnexpectedChar(lexeme lexbuf))

let startString args (lexbuf: UnicodeLexing.Lexbuf) =
let startString args (lexbuf: UnicodeLexing.Lexbuf) altStartForStringEnd =
let buf = ByteBuffer.Create StringCapacity
let m = lexbuf.LexemeRange
let startp = lexbuf.StartPos
Expand Down Expand Up @@ -160,7 +160,7 @@ let startString args (lexbuf: UnicodeLexing.Lexbuf) =
if isPart then
INTERP_STRING_PART (s, cont)
else
INTERP_STRING_END (s, cont)
INTERP_STRING_END (s, altStartForStringEnd, cont)
else
let s = Lexhelp.stringBufferAsString buf
let synStringKind =
Expand Down Expand Up @@ -587,20 +587,20 @@ rule token (args: LexArgs) (skip: bool) = parse
else mlOnly m args skip lexbuf }

| '"'
{ let buf, fin, m = startString args lexbuf
{ let buf, fin, m = startString args lexbuf None

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

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

| '$' '"' '"' '"'
{ let buf, fin, m = startString args lexbuf
{ let buf, fin, m = startString args lexbuf None

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

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

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

| '$' '"'
{ let buf,fin,m = startString args lexbuf
{ let buf,fin,m = startString args lexbuf None

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

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

| '"' '"' '"'
{ let buf, fin, m = startString args lexbuf
{ let buf, fin, m = startString args lexbuf None

args.interpolationDelimiterLength <- 0

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

| '@' '"'
{ let buf, fin, m = startString args lexbuf
{ let buf, fin, m = startString args lexbuf None

// Single quote in triple quote ok, others disallowed
match args.stringNest with
| (_, LexerStringStyle.ExtendedInterpolated, _, _) :: _
| (_, LexerStringStyle.TripleQuote, _, _) :: _ -> ()
| (_, LexerStringStyle.ExtendedInterpolated, _, _, _) :: _
| (_, LexerStringStyle.TripleQuote, _, _, _) :: _ -> ()
| _ :: _ -> errorR(Error(FSComp.SR.lexSingleQuoteInSingleQuote(), m))
| _ -> ()

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

| ("$@" | "@$") '"'
{ let buf, fin, m = startString args lexbuf
{ let buf, fin, m = startString args lexbuf None

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

Expand Down Expand Up @@ -888,10 +888,10 @@ rule token (args: LexArgs) (skip: bool) = parse
{
match args.stringNest with
| [] -> ()
| (counter, style, d, m) :: rest ->
| (counter, style, d, _, m) :: rest ->
// Note, we do not update the 'm', any incomplete-interpolation error
// will be reported w.r.t. the first '{'
args.stringNest <- (counter + 1, style, d, m) :: rest
args.stringNest <- (counter + 1, style, d, None, m) :: rest
// To continue token-by-token lexing may involve picking up the new args.stringNes
let cont = LexCont.Token(args.ifdefStack, args.stringNest)
LBRACE cont
Expand All @@ -904,12 +904,17 @@ rule token (args: LexArgs) (skip: bool) = parse
// We encounter a '}' in the expression token stream. First check if we're in an interpolated string expression
// and continue the string if necessary
match args.stringNest with
| (1, LexerStringStyle.ExtendedInterpolated, delimLength, r) :: rest when delimLength > 1 ->
args.stringNest <- (1, LexerStringStyle.ExtendedInterpolated, delimLength - 1, r) :: rest
| (1, LexerStringStyle.ExtendedInterpolated, delimLength, altR, r) :: rest when delimLength > 1 ->
// On the first "}" of multiple "}", keep the range of the starting "}" for later processing in startString
let altStart =
match altR with
| None -> Some lexbuf.LexemeRange
| _ -> altR
args.stringNest <- (1, LexerStringStyle.ExtendedInterpolated, delimLength - 1, altStart, r) :: rest
token args skip lexbuf
| (1, style, _, _) :: rest ->
| (1, style, _, altR, _r) :: rest ->
args.stringNest <- rest
let buf, fin, m = startString args lexbuf
let buf, fin, m = startString args lexbuf altR
if not skip then
STRING_TEXT (LexCont.String(args.ifdefStack, args.stringNest, style, LexerStringKind.InterpolatedStringPart, args.interpolationDelimiterLength, m))
else
Expand All @@ -918,11 +923,10 @@ rule token (args: LexArgs) (skip: bool) = parse
| LexerStringStyle.SingleQuote -> singleQuoteString (buf, fin, m, LexerStringKind.InterpolatedStringPart, args) skip lexbuf
| LexerStringStyle.TripleQuote -> tripleQuoteString (buf, fin, m, LexerStringKind.InterpolatedStringPart, args) skip lexbuf
| LexerStringStyle.ExtendedInterpolated -> extendedInterpolatedString (buf, fin, m, LexerStringKind.InterpolatedStringPart, args) skip lexbuf

| (counter, style, d, m) :: rest ->
| (counter, style, d, altR, m) :: rest ->
// Note, we do not update the 'm', any incomplete-interpolation error
// will be reported w.r.t. the first '{'
args.stringNest <- (counter - 1, style, d, m) :: rest
args.stringNest <- (counter - 1, style, d, altR, m) :: rest
let cont = LexCont.Token(args.ifdefStack, args.stringNest)
RBRACE cont

Expand Down Expand Up @@ -1260,7 +1264,7 @@ and singleQuoteString (sargs: LexerStringArgs) (skip: bool) = parse
if kind.IsInterpolated then
// get a new range for where the fill starts
let m2 = lexbuf.LexemeRange
args.stringNest <- (1, LexerStringStyle.SingleQuote, args.interpolationDelimiterLength, m2) :: args.stringNest
args.stringNest <- (1, LexerStringStyle.SingleQuote, args.interpolationDelimiterLength, None, m2) :: args.stringNest
let cont = LexCont.Token(args.ifdefStack, args.stringNest)
fin.Finish buf kind LexerStringFinisherContext.InterpolatedPart cont
else
Expand Down Expand Up @@ -1376,7 +1380,7 @@ and verbatimString (sargs: LexerStringArgs) (skip: bool) = parse
if kind.IsInterpolated then
// get a new range for where the fill starts
let m2 = lexbuf.LexemeRange
args.stringNest <- (1, LexerStringStyle.Verbatim, args.interpolationDelimiterLength, m2) :: args.stringNest
args.stringNest <- (1, LexerStringStyle.Verbatim, args.interpolationDelimiterLength, None, m2) :: args.stringNest
let cont = LexCont.Token(args.ifdefStack, args.stringNest)
fin.Finish buf kind (LexerStringFinisherContext.InterpolatedPart ||| LexerStringFinisherContext.Verbatim) cont
else
Expand Down Expand Up @@ -1495,7 +1499,7 @@ and tripleQuoteString (sargs: LexerStringArgs) (skip: bool) = parse
if kind.IsInterpolated then
// get a new range for where the fill starts
let m2 = lexbuf.LexemeRange
args.stringNest <- (1, LexerStringStyle.TripleQuote, args.interpolationDelimiterLength, m2) :: args.stringNest
args.stringNest <- (1, LexerStringStyle.TripleQuote, args.interpolationDelimiterLength, None, m2) :: args.stringNest
let cont = LexCont.Token(args.ifdefStack, args.stringNest)
fin.Finish buf kind (LexerStringFinisherContext.InterpolatedPart ||| LexerStringFinisherContext.TripleQuote) cont
else
Expand Down Expand Up @@ -1600,7 +1604,7 @@ and extendedInterpolatedString (sargs: LexerStringArgs) (skip: bool) = parse
let maxBraces = 2 * args.interpolationDelimiterLength - 1
if numBraces > maxBraces then
let m2 = lexbuf.LexemeRange
args.stringNest <- (1, LexerStringStyle.ExtendedInterpolated, args.interpolationDelimiterLength, m2) :: args.stringNest
args.stringNest <- (1, LexerStringStyle.ExtendedInterpolated, args.interpolationDelimiterLength, None, m2) :: args.stringNest
let cont = LexCont.Token(args.ifdefStack, args.stringNest)
fail args lexbuf
(FSComp.SR.lexTooManyLBracesInTripleQuote())
Expand All @@ -1621,7 +1625,7 @@ and extendedInterpolatedString (sargs: LexerStringArgs) (skip: bool) = parse
String.replicate extraBraces "{" |> addUnicodeString buf
// get a new range for where the fill starts
let m2 = lexbuf.LexemeRange
args.stringNest <- (1, LexerStringStyle.ExtendedInterpolated, args.interpolationDelimiterLength, m2) :: args.stringNest
args.stringNest <- (1, LexerStringStyle.ExtendedInterpolated, args.interpolationDelimiterLength, None, m2) :: args.stringNest
let cont = LexCont.Token(args.ifdefStack, args.stringNest)
fin.Finish buf kind (LexerStringFinisherContext.InterpolatedPart ||| LexerStringFinisherContext.TripleQuote) cont
}
Expand Down
11 changes: 9 additions & 2 deletions src/Compiler/pars.fsy
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ let parse_error_rich = Some(fun (ctxt: ParseErrorContext<_>) ->
%token <string * SynStringKind * ParseHelpers.LexerContinuation> INTERP_STRING_BEGIN_END
%token <string * SynStringKind * ParseHelpers.LexerContinuation> INTERP_STRING_BEGIN_PART
%token <string * ParseHelpers.LexerContinuation> INTERP_STRING_PART
%token <string * ParseHelpers.LexerContinuation> INTERP_STRING_END
%token <string * range option * ParseHelpers.LexerContinuation> INTERP_STRING_END
%token <ParseHelpers.LexerContinuation> LBRACE RBRACE

%token <string * string> KEYWORD_STRING // Like __SOURCE_DIRECTORY__
Expand Down Expand Up @@ -6774,7 +6774,14 @@ interpolatedStringFill:

interpolatedStringParts:
| INTERP_STRING_END
{ [ SynInterpolatedStringPart.String(fst $1, rhs parseState 1) ] }
{
let (s, altStart, _) = $1
let mOrig = rhs parseState 1
let m =
match altStart with
| Some r -> unionRanges r mOrig
| None -> mOrig
[ SynInterpolatedStringPart.String(s, m) ] }

| INTERP_STRING_PART interpolatedStringFill interpolatedStringParts
{ SynInterpolatedStringPart.String(fst $1, rhs parseState 1) :: SynInterpolatedStringPart.FillExpr $2 :: $3 }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ ImplFile
FillExpr (Const (Int32 41, (2,21--2,23)), None);
String (" = ", (2,25--2,32));
FillExpr (Const (Int32 6, (2,32--2,33)), None);
String (" * 7", (2,35--2,43))], TripleQuote, (2,8--2,43)),
String (" * 7", (2,33--2,43))], TripleQuote, (2,8--2,43)),
(2,4--2,5), Yes (2,0--2,43), { LeadingKeyword = Let (2,0--2,3)
InlineKeyword = None
EqualsRange = Some (2,6--2,7) })],
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@

$$$"""{{{5}}}"""
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
ImplFile
(ParsedImplFileInput
("/root/String/SynExprInterpolatedStringWithTripleQuoteMultipleDollars2.fs",
false,
QualifiedNameOfFile
SynExprInterpolatedStringWithTripleQuoteMultipleDollars2, [], [],
[SynModuleOrNamespace
([SynExprInterpolatedStringWithTripleQuoteMultipleDollars2], false,
AnonModule,
[Expr
(InterpolatedString
([String ("", (2,0--2,9));
FillExpr (Const (Int32 5, (2,9--2,10)), None);
String ("", (2,10--2,16))], TripleQuote, (2,0--2,16)),
(2,0--2,16))], PreXmlDocEmpty, [], None, (2,0--2,16),
{ LeadingKeyword = None })], (true, true),
{ ConditionalDirectives = []
CodeComments = [] }, set []))