Skip to content

Commit

Permalink
Add SynExprSequentialTrivia (#16981)
Browse files Browse the repository at this point in the history
* Add SynExprSequentialTrivia

* Add release note

* Format

* Apply feedback from code review

* PR is fine

---------

Co-authored-by: Vlad Zarytovskii <vzaritovsky@hotmail.com>
  • Loading branch information
nojaf and vzarytovskii committed Apr 5, 2024
1 parent 3d95e4e commit 050271d
Show file tree
Hide file tree
Showing 30 changed files with 221 additions and 79 deletions.
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
Expand Up @@ -45,6 +45,7 @@
* Parser: more 'as' pattern recovery ([PR #16837](https://github.com/dotnet/fsharp/pull/16837))
* Add extended data for `DefinitionsInSigAndImplNotCompatibleAbbreviationsDiffer` (FS0318). ([PR #16811](https://github.com/dotnet/fsharp/pull/16811)))
* Checker/patterns: recover on unresolved long identifiers ([PR #16842](https://github.com/dotnet/fsharp/pull/16842))
* SynExprSequentialTrivia ([Issue #16914](https://github.com/dotnet/fsharp/issues/16914), [PR #16981](https://github.com/dotnet/fsharp/pull/16981))

### Changed

Expand Down
53 changes: 40 additions & 13 deletions src/Compiler/Checking/CheckComputationExpressions.fs
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ let (|SimpleSemicolonSequence|_|) cenv acceptDeprecated cexpr =

let rec TryGetSimpleSemicolonSequenceOfComprehension expr acc =
match expr with
| SynExpr.Sequential(_, true, e1, e2, _) ->
| SynExpr.Sequential(isTrueSeq = true; expr1 = e1; expr2 = e2) ->
if IsSimpleSemicolonSequenceElement e1 then
TryGetSimpleSemicolonSequenceOfComprehension e2 (e1 :: acc)
else
Expand Down Expand Up @@ -752,8 +752,14 @@ let TcComputationExpression (cenv: cenv) env (overallTy: OverallTy) tpenv (mWhol

let (|ForEachThen|_|) synExpr =
match synExpr with
| SynExpr.ForEach(_spFor, _spIn, SeqExprOnly false, isFromSource, pat1, expr1, SynExpr.Sequential(_, true, clause, rest, _), _) ->
Some(isFromSource, pat1, expr1, clause, rest)
| SynExpr.ForEach(_spFor,
_spIn,
SeqExprOnly false,
isFromSource,
pat1,
expr1,
SynExpr.Sequential(isTrueSeq = true; expr1 = clause; expr2 = rest),
_) -> Some(isFromSource, pat1, expr1, clause, rest)
| _ -> None

let (|CustomOpId|_|) predicate synExpr =
Expand Down Expand Up @@ -998,7 +1004,7 @@ let TcComputationExpression (cenv: cenv) env (overallTy: OverallTy) tpenv (mWhol

let (|OptionalSequential|) e =
match e with
| SynExpr.Sequential(_sp, true, dataComp1, dataComp2, _) -> (dataComp1, Some dataComp2)
| SynExpr.Sequential(debugPoint = _sp; isTrueSeq = true; expr1 = dataComp1; expr2 = dataComp2) -> (dataComp1, Some dataComp2)
| _ -> (e, None)

// "cexpr; cexpr" is treated as builder.Combine(cexpr1, cexpr1)
Expand Down Expand Up @@ -1233,7 +1239,14 @@ let TcComputationExpression (cenv: cenv) env (overallTy: OverallTy) tpenv (mWhol
// 2. incompatible types: int and string
// with SynExpr.ArbitraryAfterError we have only first one
let wrapInArbErrSequence l caption =
SynExpr.Sequential(DebugPointAtSequential.SuppressNeither, true, l, (arbExpr (caption, l.Range.EndRange)), l.Range)
SynExpr.Sequential(
DebugPointAtSequential.SuppressNeither,
true,
l,
(arbExpr (caption, l.Range.EndRange)),
l.Range,
SynExprSequentialTrivia.Zero
)

let mkOverallExprGivenVarSpaceExpr, varSpaceInner =

Expand Down Expand Up @@ -1529,7 +1542,14 @@ let TcComputationExpression (cenv: cenv) env (overallTy: OverallTy) tpenv (mWhol
SynExpr.While(
DebugPointAtWhile.No,
SynExpr.Ident idCond,
SynExpr.Sequential(DebugPointAtSequential.SuppressBoth, true, innerComp, bindCondExpr, mWhile),
SynExpr.Sequential(
DebugPointAtSequential.SuppressBoth,
true,
innerComp,
bindCondExpr,
mWhile,
SynExprSequentialTrivia.Zero
),
mOrig
)

Expand Down Expand Up @@ -1658,7 +1678,7 @@ let TcComputationExpression (cenv: cenv) env (overallTy: OverallTy) tpenv (mWhol
// Now run the consumeCustomOpClauses
Some(consumeCustomOpClauses q varSpace dataCompPriorToOp comp false mClause)

| SynExpr.Sequential(sp, true, innerComp1, innerComp2, m) ->
| SynExpr.Sequential(sp, true, innerComp1, innerComp2, m, _) ->

// Check for 'where x > y' and other mis-applications of infix operators. If detected, give a good error message, and just ignore innerComp1
if isQuery && checkForBinaryApp innerComp1 then
Expand Down Expand Up @@ -1761,7 +1781,7 @@ let TcComputationExpression (cenv: cenv) env (overallTy: OverallTy) tpenv (mWhol

SynExpr.SequentialOrImplicitYield(sp, innerComp1, holeFill, combineExpr, m)
else
SynExpr.Sequential(sp, true, innerComp1, holeFill, m)
SynExpr.Sequential(sp, true, innerComp1, holeFill, m, SynExprSequentialTrivia.Zero)

translatedCtxt fillExpr)
)
Expand Down Expand Up @@ -2643,7 +2663,14 @@ let TcComputationExpression (cenv: cenv) env (overallTy: OverallTy) tpenv (mWhol
comp.Range
)
else
SynExpr.Sequential(DebugPointAtSequential.SuppressExpr, true, comp, holeFill, comp.Range)
SynExpr.Sequential(
DebugPointAtSequential.SuppressExpr,
true,
comp,
holeFill,
comp.Range,
SynExprSequentialTrivia.Zero
)

translatedCtxt fillExpr)

Expand Down Expand Up @@ -2772,14 +2799,14 @@ let TcComputationExpression (cenv: cenv) env (overallTy: OverallTy) tpenv (mWhol

Some(varSpaceExpr, Some(innerComp, mClause))

| SynExpr.Sequential(sp, true, innerComp1, innerComp2, m) ->
| SynExpr.Sequential(sp, true, innerComp1, innerComp2, m, trivia) ->

// Check the first part isn't a computation expression construct
if isSimpleExpr innerComp1 then
// Check the second part is a simple return
match convertSimpleReturnToExpr varSpace innerComp2 with
| None -> None
| Some(innerExpr2, optionalCont) -> Some(SynExpr.Sequential(sp, true, innerComp1, innerExpr2, m), optionalCont)
| Some(innerExpr2, optionalCont) -> Some(SynExpr.Sequential(sp, true, innerComp1, innerExpr2, m, trivia), optionalCont)
else
None

Expand All @@ -2798,7 +2825,7 @@ let TcComputationExpression (cenv: cenv) env (overallTy: OverallTy) tpenv (mWhol
| SynExpr.ImplicitZero _ -> false
| OptionalSequential(JoinOrGroupJoinOrZipClause _, _) -> false
| OptionalSequential(CustomOperationClause _, _) -> false
| SynExpr.Sequential(_, _, innerComp1, innerComp2, _) -> isSimpleExpr innerComp1 && isSimpleExpr innerComp2
| SynExpr.Sequential(expr1 = innerComp1; expr2 = innerComp2) -> isSimpleExpr innerComp1 && isSimpleExpr innerComp2
| SynExpr.IfThenElse(thenExpr = thenComp; elseExpr = elseCompOpt) ->
isSimpleExpr thenComp
&& (match elseCompOpt with
Expand Down Expand Up @@ -3122,7 +3149,7 @@ let TcSequenceExpression (cenv: cenv) env tpenv comp (overallTy: OverallTy) m =

| SynExpr.DoBang(_rhsExpr, m) -> error (Error(FSComp.SR.tcDoBangIllegalInSequenceExpression (), m))

| SynExpr.Sequential(sp, true, innerComp1, innerComp2, m) ->
| SynExpr.Sequential(sp, true, innerComp1, innerComp2, m, _) ->
let env1 =
{ env with
eIsControlFlow =
Expand Down
4 changes: 2 additions & 2 deletions src/Compiler/Checking/CheckExpressions.fs
Original file line number Diff line number Diff line change
Expand Up @@ -5795,7 +5795,7 @@ and TcExprUndelayed (cenv: cenv) (overallTy: OverallTy) env tpenv (synExpr: SynE
let _, tpenv = suppressErrorReporting (fun () -> TcExpr cenv overallTy env tpenv expr1)
mkDefault(m, overallTy.Commit), tpenv

| SynExpr.Sequential (sp, dir, synExpr1, synExpr2, m) ->
| SynExpr.Sequential (sp, dir, synExpr1, synExpr2, m, _) ->
TcExprSequential cenv overallTy env tpenv (synExpr, sp, dir, synExpr1, synExpr2, m)

// Used to implement the type-directed 'implicit yield' rule for computation expressions
Expand Down Expand Up @@ -10337,7 +10337,7 @@ and TcLinearExprs bodyChecker cenv env overallTy tpenv isCompExpr synExpr cont =
let g = cenv.g

match synExpr with
| SynExpr.Sequential (sp, true, expr1, expr2, m) when not isCompExpr ->
| SynExpr.Sequential (sp, true, expr1, expr2, m, _) when not isCompExpr ->
let expr1R, _ =
let env1 = { env with eIsControlFlow = (match sp with | DebugPointAtSequential.SuppressNeither | DebugPointAtSequential.SuppressExpr -> true | _ -> false) }
TcStmtThatCantBeCtorBody cenv env1 tpenv expr1
Expand Down
9 changes: 8 additions & 1 deletion src/Compiler/Interactive/fsi.fs
Original file line number Diff line number Diff line change
Expand Up @@ -4258,7 +4258,14 @@ type FsiInteractionProcessor
let m = expr.Range
// Make this into "(); expr" to suppress generalization and compilation-as-function
let exprWithSeq =
SynExpr.Sequential(DebugPointAtSequential.SuppressExpr, true, SynExpr.Const(SynConst.Unit, m.StartRange), expr, m)
SynExpr.Sequential(
DebugPointAtSequential.SuppressExpr,
true,
SynExpr.Const(SynConst.Unit, m.StartRange),
expr,
m,
SynExprSequentialTrivia.Zero
)

ExecuteParsedExpressionOnMainThread(ctok, diagnosticsLogger, exprWithSeq, istate))
|> commitResult
Expand Down
4 changes: 2 additions & 2 deletions src/Compiler/Service/FSharpParseFileResults.fs
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ type FSharpParseFileResults(diagnostics: FSharpDiagnostic[], input: ParsedInput,
match expr with

// This lets us dive into subexpressions that may contain the binding we're after
| SynExpr.Sequential(_, _, expr1, expr2, _) ->
| SynExpr.Sequential(expr1 = expr1; expr2 = expr2) ->
if rangeContainsPos expr1.Range pos then
walkBinding expr1 workingRange
else
Expand Down Expand Up @@ -714,7 +714,7 @@ type FSharpParseFileResults(diagnostics: FSharpDiagnostic[], input: ParsedInput,
yield! walkFinallySeqPt spFinally

| SynExpr.SequentialOrImplicitYield(spSeq, e1, e2, _, _)
| SynExpr.Sequential(spSeq, _, e1, e2, _) ->
| SynExpr.Sequential(debugPoint = spSeq; expr1 = e1; expr2 = e2) ->
let implicit1 =
match spSeq with
| DebugPointAtSequential.SuppressExpr
Expand Down
4 changes: 2 additions & 2 deletions src/Compiler/Service/ServiceParsedInputOps.fs
Original file line number Diff line number Diff line change
Expand Up @@ -263,8 +263,8 @@ module ParsedInput =

let rec collect expr acc =
match expr with
| SynExpr.Sequential(_, _, e1, (SynExpr.Sequential _ as e2), _) -> collect e2 (e1 :: acc)
| SynExpr.Sequential(_, _, e1, e2, _) -> e2 :: e1 :: acc
| SynExpr.Sequential(expr1 = e1; expr2 = (SynExpr.Sequential _ as e2)) -> collect e2 (e1 :: acc)
| SynExpr.Sequential(expr1 = e1; expr2 = e2) -> e2 :: e1 :: acc
| _ -> acc

match collect expr [] with
Expand Down
2 changes: 1 addition & 1 deletion src/Compiler/Service/ServiceStructure.fs
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,7 @@ module Structure =
parseExpr argExpr
parseExpr funcExpr

| SynExpr.Sequential(_, _, e1, e2, _) ->
| SynExpr.Sequential(expr1 = e1; expr2 = e2) ->
parseExpr e1
parseExpr e2

Expand Down
14 changes: 10 additions & 4 deletions src/Compiler/SyntaxTree/SyntaxTree.fs
Original file line number Diff line number Diff line change
Expand Up @@ -630,7 +630,13 @@ type SynExpr =

| Lazy of expr: SynExpr * range: range

| Sequential of debugPoint: DebugPointAtSequential * isTrueSeq: bool * expr1: SynExpr * expr2: SynExpr * range: range
| Sequential of
debugPoint: DebugPointAtSequential *
isTrueSeq: bool *
expr1: SynExpr *
expr2: SynExpr *
range: range *
trivia: SynExprSequentialTrivia

| IfThenElse of
ifExpr: SynExpr *
Expand Down Expand Up @@ -835,9 +841,9 @@ type SynExpr =
match e with
// these are better than just .Range, and also commonly applicable inside queries
| SynExpr.Paren(_, m, _, _) -> m
| SynExpr.Sequential(_, _, e1, _, _)
| SynExpr.SequentialOrImplicitYield(_, e1, _, _, _)
| SynExpr.App(_, _, e1, _, _) -> e1.RangeOfFirstPortion
| SynExpr.Sequential(expr1 = e1)
| SynExpr.SequentialOrImplicitYield(expr1 = e1)
| SynExpr.App(funcExpr = e1) -> e1.RangeOfFirstPortion
| SynExpr.ForEach(pat = pat; range = r) ->
let e = (pat.Range: range).Start
withEnd e r
Expand Down
3 changes: 2 additions & 1 deletion src/Compiler/SyntaxTree/SyntaxTree.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -754,7 +754,8 @@ type SynExpr =
isTrueSeq: bool *
expr1: SynExpr *
expr2: SynExpr *
range: range
range: range *
trivia: SynExprSequentialTrivia

/// F# syntax: if expr then expr
/// F# syntax: if expr then expr else expr
Expand Down
2 changes: 1 addition & 1 deletion src/Compiler/SyntaxTree/SyntaxTreeOps.fs
Original file line number Diff line number Diff line change
Expand Up @@ -942,7 +942,7 @@ let rec synExprContainsError inpExpr =

| SynExpr.TryFinally(tryExpr = e1; finallyExpr = e2) -> walkExpr e1 || walkExpr e2

| SynExpr.Sequential(_, _, e1, e2, _) -> walkExpr e1 || walkExpr e2
| SynExpr.Sequential(expr1 = e1; expr2 = e2) -> walkExpr e1 || walkExpr e2

| SynExpr.SequentialOrImplicitYield(_, e1, e2, _, _) -> walkExpr e1 || walkExpr e2

Expand Down
8 changes: 8 additions & 0 deletions src/Compiler/SyntaxTree/SyntaxTrivia.fs
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,14 @@ type SynExprMatchBangTrivia =
[<NoEquality; NoComparison>]
type SynExprAnonRecdTrivia = { OpeningBraceRange: range }

[<NoEquality; NoComparison>]
type SynExprSequentialTrivia =
{
SeparatorRange: range option
}

static member val Zero = { SeparatorRange = None }

[<NoEquality; NoComparison>]
type SynMatchClauseTrivia =
{
Expand Down
11 changes: 11 additions & 0 deletions src/Compiler/SyntaxTree/SyntaxTrivia.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,17 @@ type SynExprAnonRecdTrivia =
OpeningBraceRange: range
}

/// Represents additional information for SynExpr.Sequential
[<NoEquality; NoComparison>]
type SynExprSequentialTrivia =
{
/// The syntax range of the `;` token.
/// Could also be the `then` keyword.
SeparatorRange: range option
}

static member Zero: SynExprSequentialTrivia

/// Represents additional information for SynMatchClause
[<NoEquality; NoComparison>]
type SynMatchClauseTrivia =
Expand Down
17 changes: 10 additions & 7 deletions src/Compiler/pars.fsy
Original file line number Diff line number Diff line change
Expand Up @@ -3895,7 +3895,8 @@ typedSequentialExprEOF:

sequentialExpr:
| declExpr seps sequentialExpr
{ SynExpr.Sequential(DebugPointAtSequential.SuppressNeither, true, $1, $3, unionRanges $1.Range $3.Range) }
{ let trivia = { SeparatorRange = $2 }
SynExpr.Sequential(DebugPointAtSequential.SuppressNeither, true, $1, $3, unionRanges $1.Range $3.Range, trivia) }

| declExpr seps
{ $1 }
Expand All @@ -3904,10 +3905,12 @@ sequentialExpr:
{ $1 }

| declExpr THEN sequentialExpr %prec prec_then_before
{ SynExpr.Sequential(DebugPointAtSequential.SuppressNeither, false, $1, $3, unionRanges $1.Range $3.Range) }
{ let trivia = { SeparatorRange = Some (rhs parseState 2) }
SynExpr.Sequential(DebugPointAtSequential.SuppressNeither, false, $1, $3, unionRanges $1.Range $3.Range, trivia) }

| declExpr OTHEN OBLOCKBEGIN typedSequentialExpr oblockend %prec prec_then_before
{ SynExpr.Sequential(DebugPointAtSequential.SuppressNeither, false, $1, $4, unionRanges $1.Range $4.Range) }
{ let trivia = { SeparatorRange = Some (rhs parseState 2) }
SynExpr.Sequential(DebugPointAtSequential.SuppressNeither, false, $1, $4, unionRanges $1.Range $4.Range, trivia) }

| hardwhiteLetBindings %prec prec_args_error
{ let hwlb, m, mIn = $1
Expand Down Expand Up @@ -6658,10 +6661,10 @@ opt_topSeparators:

/* Seprators in either #light or non-#light */
seps:
| OBLOCKSEP { }
| SEMICOLON { }
| OBLOCKSEP SEMICOLON { }
| SEMICOLON OBLOCKSEP { }
| OBLOCKSEP { None }
| SEMICOLON { Some (rhs parseState 1) }
| OBLOCKSEP SEMICOLON { Some (rhs parseState 2) }
| SEMICOLON OBLOCKSEP { Some (rhs parseState 1) }

/* An 'end' that's optional only in #light, where an ODECLEND gets inserted, and explicit 'end's get converted to OEND */
declEnd:
Expand Down

0 comments on commit 050271d

Please sign in to comment.