diff --git a/src/fsharp/CheckComputationExpressions.fs b/src/fsharp/CheckComputationExpressions.fs index 27c98d172a..c3a74e2c7b 100644 --- a/src/fsharp/CheckComputationExpressions.fs +++ b/src/fsharp/CheckComputationExpressions.fs @@ -1091,7 +1091,7 @@ let TcComputationExpression cenv env (overallTy: OverallTy) tpenv (mWhole, inter Some (trans CompExprTranslationPass.Initial q varSpace thenComp (fun holeFill -> translatedCtxt (SynExpr.IfThenElse (guardExpr, holeFill, Some elseComp, spIfToThen, isRecovery, mIfToEndOfElseBranch, trivia)))) // 'let binds in expr' - | SynExpr.LetOrUse (isRec, false, binds, innerComp, m) -> + | SynExpr.LetOrUse (isRec, false, binds, innerComp, m, trivia) -> // For 'query' check immediately if isQuery then @@ -1118,7 +1118,7 @@ let TcComputationExpression cenv env (overallTy: OverallTy) tpenv (mWhole, inter // error case error(Error(FSComp.SR.tcCustomOperationMayNotBeUsedInConjunctionWithNonSimpleLetBindings(), mQueryOp))) - Some (trans CompExprTranslationPass.Initial q varSpace innerComp (fun holeFill -> translatedCtxt (SynExpr.LetOrUse (isRec, false, binds, holeFill, m)))) + Some (trans CompExprTranslationPass.Initial q varSpace innerComp (fun holeFill -> translatedCtxt (SynExpr.LetOrUse (isRec, false, binds, holeFill, m, trivia)))) // 'use x = expr in expr' | SynExpr.LetOrUse (isUse=true; bindings=[SynBinding (kind=SynBindingKind.Normal; headPat=pat; expr=rhsExpr; debugPoint=spBind)]; body=innerComp) -> @@ -1566,11 +1566,11 @@ let TcComputationExpression cenv env (overallTy: OverallTy) tpenv (mWhole, inter | None -> None | Some elseExprOpt -> Some (SynExpr.IfThenElse (guardExpr, thenExpr, elseExprOpt, spIfToThen, isRecovery, mIfToEndOfElseBranch, trivia), None) - | SynExpr.LetOrUse (isRec, false, binds, innerComp, m) -> + | SynExpr.LetOrUse (isRec, false, binds, innerComp, m, trivia) -> match convertSimpleReturnToExpr varSpace innerComp with | None -> None | Some (_, Some _) -> None - | Some (innerExpr, None) -> Some (SynExpr.LetOrUse (isRec, false, binds, innerExpr, m), None) + | Some (innerExpr, None) -> Some (SynExpr.LetOrUse (isRec, false, binds, innerExpr, m, trivia), None) | OptionalSequential (CustomOperationClause (nm, _, _, mClause, _), _) when customOperationMaintainsVarSpaceUsingBind nm -> @@ -1607,7 +1607,7 @@ let TcComputationExpression cenv env (overallTy: OverallTy) tpenv (mWhole, inter | SynExpr.Sequential (_, _, innerComp1, innerComp2, _) -> isSimpleExpr innerComp1 && isSimpleExpr innerComp2 | SynExpr.IfThenElse (thenExpr=thenComp; elseExpr=elseCompOpt) -> isSimpleExpr thenComp && (match elseCompOpt with None -> true | Some c -> isSimpleExpr c) - | SynExpr.LetOrUse (_, _, _, innerComp, _) -> isSimpleExpr innerComp + | SynExpr.LetOrUse (body=innerComp) -> isSimpleExpr innerComp | SynExpr.LetOrUseBang _ -> false | SynExpr.Match (clauses=clauses) -> clauses |> List.forall (fun (SynMatchClause(resultExpr = innerComp)) -> isSimpleExpr innerComp) @@ -1840,7 +1840,7 @@ let TcSequenceExpression (cenv: cenv) env tpenv comp (overallTy: OverallTy) m = Some(mkCond spIfToThen DebugPointAtTarget.Yes mIfToEndOfElseBranch genOuterTy guardExpr' thenExpr elseExpr, tpenv) // 'let x = expr in expr' - | SynExpr.LetOrUse (_, false (* not a 'use' binding *), _, _, _) -> + | SynExpr.LetOrUse (isUse=false (* not a 'use' binding *)) -> TcLinearExprs (fun overallTy envinner tpenv e -> tcSequenceExprBody envinner overallTy.Commit tpenv e) cenv env overallTy diff --git a/src/fsharp/CheckExpressions.fs b/src/fsharp/CheckExpressions.fs index 58310006a3..b3a053a478 100644 --- a/src/fsharp/CheckExpressions.fs +++ b/src/fsharp/CheckExpressions.fs @@ -9693,7 +9693,7 @@ and TcLinearExprs bodyChecker cenv env overallTy tpenv isCompExpr expr cont = TcLinearExprs bodyChecker cenv env overallTy tpenv isCompExpr e2 (fun (e2', tpenv) -> cont (Expr.Sequential (e1', e2', NormalSeq, sp, m), tpenv)) - | SynExpr.LetOrUse (isRec, isUse, binds, body, m) when not (isUse && isCompExpr) -> + | SynExpr.LetOrUse (isRec, isUse, binds, body, m, _) when not (isUse && isCompExpr) -> if isRec then // TcLinearExprs processes at most one recursive binding, this is not tailcalling CheckRecursiveBindingIds binds diff --git a/src/fsharp/SyntaxTree.fs b/src/fsharp/SyntaxTree.fs index 20b4addbf1..f42109b24c 100644 --- a/src/fsharp/SyntaxTree.fs +++ b/src/fsharp/SyntaxTree.fs @@ -613,7 +613,8 @@ type SynExpr = isUse: bool * bindings: SynBinding list * body: SynExpr * - range: range + range: range * + trivia: SynExprLetOrUseTrivia | TryWith of tryExpr: SynExpr * diff --git a/src/fsharp/SyntaxTree.fsi b/src/fsharp/SyntaxTree.fsi index 425c780438..4b7c2db8e0 100644 --- a/src/fsharp/SyntaxTree.fsi +++ b/src/fsharp/SyntaxTree.fsi @@ -757,7 +757,8 @@ type SynExpr = isUse: bool * bindings: SynBinding list * body: SynExpr * - range: range + range: range * + trivia: SynExprLetOrUseTrivia /// F# syntax: try expr with pat -> expr | TryWith of diff --git a/src/fsharp/SyntaxTreeOps.fs b/src/fsharp/SyntaxTreeOps.fs index 969dac27ca..25d1eaef96 100644 --- a/src/fsharp/SyntaxTreeOps.fs +++ b/src/fsharp/SyntaxTreeOps.fs @@ -711,7 +711,7 @@ let rec synExprContainsError inpExpr = | SynExpr.Match (expr=e; clauses=cl) -> walkExpr e || walkMatchClauses cl - | SynExpr.LetOrUse (_, _, bs, e, _) -> + | SynExpr.LetOrUse (bindings=bs; body=e) -> walkBinds bs || walkExpr e | SynExpr.TryWith (tryExpr=e; withCases=cl) -> diff --git a/src/fsharp/SyntaxTrivia.fs b/src/fsharp/SyntaxTrivia.fs index 305a990aac..cc0f37082e 100644 --- a/src/fsharp/SyntaxTrivia.fs +++ b/src/fsharp/SyntaxTrivia.fs @@ -29,6 +29,10 @@ type SynExprLambdaTrivia = { ArrowRange: range option } static member Zero: SynExprLambdaTrivia = { ArrowRange = None } +[] +type SynExprLetOrUseTrivia = + { InKeyword: range option } + [] type SynMatchClauseTrivia = { ArrowRange: range option diff --git a/src/fsharp/SyntaxTrivia.fsi b/src/fsharp/SyntaxTrivia.fsi index 44f2f5d010..7f5eff58a6 100644 --- a/src/fsharp/SyntaxTrivia.fsi +++ b/src/fsharp/SyntaxTrivia.fsi @@ -53,6 +53,14 @@ type SynExprLambdaTrivia = } static member Zero: SynExprLambdaTrivia +/// Represents additional information for SynExpr.Lambda +[] +type SynExprLetOrUseTrivia = + { + /// The syntax range of the `in` keyword. + InKeyword: range option + } + /// Represents additional information for SynMatchClause [] type SynMatchClauseTrivia = diff --git a/src/fsharp/pars.fsy b/src/fsharp/pars.fsy index 29d4161fc2..d6a94a8082 100644 --- a/src/fsharp/pars.fsy +++ b/src/fsharp/pars.fsy @@ -157,10 +157,10 @@ let mkClassMemberLocalBindings(isStatic, initialRangeOpt, attrs, vis, BindingSet if isUse then errorR(Error(FSComp.SR.parsUseBindingsIllegalInImplicitClassConstructors(), wholeRange)) SynMemberDefn.LetBindings (decls, isStatic, isRec, wholeRange) -let mkLocalBindings (mWhole, BindingSetPreAttrs(_, isRec, isUse, declsPreAttrs, _), body) = +let mkLocalBindings (mWhole, BindingSetPreAttrs(_, isRec, isUse, declsPreAttrs, _), mIn, body) = let ignoredFreeAttrs, decls = declsPreAttrs [] None if not (isNil ignoredFreeAttrs) then warning(Error(FSComp.SR.parsAttributesIgnored(), mWhole)) - SynExpr.LetOrUse (isRec, isUse, decls, body, mWhole) + SynExpr.LetOrUse (isRec, isUse, decls, body, mWhole, { InKeyword = mIn }) let mkDefnBindings (mWhole, BindingSetPreAttrs(_, isRec, isUse, declsPreAttrs, _bindingSetRange), attrs, vis, attrsm) = if isUse then warning(Error(FSComp.SR.parsUseBindingsIllegalInModules(), mWhole)) @@ -1309,7 +1309,7 @@ moduleDefn: /* 'let' or 'do' definitions in #light */ | opt_attributes opt_declVisibility hardwhiteLetBindings %prec decl_let - { let hwlb, m = $3 + { let hwlb, m, _ = $3 if Option.isSome $2 then errorR(Error(FSComp.SR.parsVisibilityDeclarationsShouldComePriorToIdentifier(), rhs parseState 2)) parseState.ResetSynArgNameGenerator() mkDefnBindings (m, hwlb, $1, $2, m) } @@ -2711,7 +2711,8 @@ hardwhiteLetBindings: { let mLetKwd = rhs parseState 1 let isUse = $1 let isRec = $2 - $4 (if isUse then "use" else "let") mLetKwd // report unterminated error + let report, mIn = $4 + report (if isUse then "use" else "let") mLetKwd // report unterminated error let localBindingsLastRangeOpt, localBindingsBuilder = $3 @@ -2729,7 +2730,9 @@ hardwhiteLetBindings: if not isRec && not (isNilOrSingleton binds) then reportParseErrorAt mLetKwd (FSComp.SR.parsLetAndForNonRecBindings()) [], binds), - bindingSetRange), (unionRanges mLetKwd bindingSetRange) } + bindingSetRange), + (unionRanges mLetKwd bindingSetRange), + mIn } /* A 'do ...' statement */ @@ -2752,7 +2755,7 @@ classDefnBindings: { $1 } | hardwhiteLetBindings - { let b, m = $1 in b } + { let b, m, _ = $1 in b } | hardwhiteDoBinding { fst $1 } @@ -2761,7 +2764,10 @@ classDefnBindings: /* The terminator for a 'let ....' binding in the #light syntax */ hardwhiteDefnBindingsTerminator: | ODECLEND - { (fun _ m -> ()) } + { let mToken = rhs parseState 1 + // In LexFilter.fs the IN token could have been transformed to an ODECLEND one. + let mIn = if (mToken.EndColumn - mToken.StartColumn) = 2 then Some mToken else None + (fun _ m -> ()), mIn } | recover { (fun kwd m -> @@ -2771,7 +2777,7 @@ hardwhiteDefnBindingsTerminator: | "use!" -> FSComp.SR.parsUnmatchedUseBang() | "use" -> FSComp.SR.parsUnmatchedUse() | _ (*"let" *) -> FSComp.SR.parsUnmatchedLet() - reportParseErrorAt m msg) } + reportParseErrorAt m msg), None } /* An 'extern' DllImport function definition in C-style syntax */ cPrototype: @@ -3489,12 +3495,12 @@ sequentialExpr: { SynExpr.Sequential (DebugPointAtSequential.SuppressNeither, false, $1, $4, unionRanges $1.Range $4.Range) } | hardwhiteLetBindings %prec prec_args_error - { let hwlb, m = $1 + { let hwlb, m, mIn = $1 let mLetKwd, isUse = match hwlb with (BindingSetPreAttrs(m, _, isUse, _, _)) -> m, isUse let usedKeyword = if isUse then "use" else "let" reportParseErrorAt mLetKwd (FSComp.SR.parsExpectedExpressionAfterLet(usedKeyword, usedKeyword)) let fauxRange = m.EndRange // zero width range at end of m - mkLocalBindings (m, hwlb, arbExpr("seqExpr", fauxRange)) } + mkLocalBindings (m, hwlb, mIn, arbExpr("seqExpr", fauxRange)) } /* Use this as the last terminal when performing error recovery */ /* The contract for using this is that (a) if EOF occurs then the */ @@ -3515,7 +3521,8 @@ moreBinders: SynExprAndBang(spBind, $1, true, $2, mEquals, $4, m) :: $6 } | OAND_BANG headBindingPattern EQUALS typedSequentialExprBlock hardwhiteDefnBindingsTerminator opt_OBLOCKSEP moreBinders %prec expr_let - { $5 "and!" (rhs parseState 1) // report unterminated error + { let report, mIn = $5 + report "and!" (rhs parseState 1) // report unterminated error let spBind = DebugPointAtBinding.Yes(rhs2 parseState 1 5) (* TODO Pretty sure this is wrong *) let mEquals = rhs parseState 3 let m = rhs parseState 1 (* TODO Pretty sure this is wrong *) @@ -3526,31 +3533,33 @@ moreBinders: declExpr: | defnBindings IN typedSequentialExpr %prec expr_let - { mkLocalBindings (unionRanges (rhs2 parseState 1 2) $3.Range, $1, $3) } + { let mIn = rhs parseState 2 |> Some + mkLocalBindings (unionRanges (rhs2 parseState 1 2) $3.Range, $1, mIn, $3) } | defnBindings IN error %prec expr_let - { mkLocalBindings (rhs2 parseState 1 2, $1, arbExpr("declExpr1", (rhs parseState 3))) } + { let mIn = rhs parseState 2 |> Some + mkLocalBindings (rhs2 parseState 1 2, $1, mIn, arbExpr("declExpr1", (rhs parseState 3))) } /* FSComp.SR.parsNoMatchingInForLet() -- leave this in for now - it's an unused error string */ | hardwhiteLetBindings typedSequentialExprBlock %prec expr_let - { let hwlb, m = $1 - mkLocalBindings (unionRanges m $2.Range, hwlb, $2) } + { let hwlb, m, mIn = $1 + mkLocalBindings (unionRanges m $2.Range, hwlb, mIn, $2) } | hardwhiteLetBindings error %prec expr_let - { let hwlb, m = $1 + { let hwlb, m, mIn = $1 reportParseErrorAt (match hwlb with (BindingSetPreAttrs(m, _, _, _, _)) -> m) (FSComp.SR.parsErrorInReturnForLetIncorrectIndentation()) - mkLocalBindings (m, hwlb, arbExpr("declExpr2", (rhs parseState 2))) } + mkLocalBindings (m, hwlb, mIn, arbExpr("declExpr2", (rhs parseState 2))) } | hardwhiteLetBindings OBLOCKSEP typedSequentialExprBlock %prec expr_let - { let hwlb, m = $1 - mkLocalBindings (unionRanges m $3.Range, hwlb, $3) } + { let hwlb, m, mIn = $1 + mkLocalBindings (unionRanges m $3.Range, hwlb, mIn, $3) } | hardwhiteLetBindings OBLOCKSEP error %prec expr_let - { let hwlb, m = $1 + { let hwlb, m, mIn = $1 //reportParseErrorAt (match hwlb with (BindingSetPreAttrs(m, _, _, _, _)) -> m) (FSComp.SR.parsErrorInReturnForLetIncorrectIndentation()) - mkLocalBindings (unionRanges m (rhs parseState 3), hwlb, arbExpr("declExpr3", (rhs parseState 3))) } + mkLocalBindings (unionRanges m (rhs parseState 3), hwlb, mIn, arbExpr("declExpr3", (rhs parseState 3))) } | hardwhiteDoBinding %prec expr_let { let e = snd $1 @@ -3828,7 +3837,8 @@ declExpr: SynExpr.LetOrUseBang(spBind, ($1 = "use"), true, $2, Some mEquals, $4, $7, $8, m) } | OBINDER headBindingPattern EQUALS typedSequentialExprBlock hardwhiteDefnBindingsTerminator opt_OBLOCKSEP moreBinders typedSequentialExprBlock %prec expr_let - { $5 (if $1 = "use" then "use!" else "let!") (rhs parseState 1) // report unterminated error + { let report, mIn = $5 + report (if $1 = "use" then "use!" else "let!") (rhs parseState 1) // report unterminated error let spBind = DebugPointAtBinding.Yes(unionRanges (rhs parseState 1) $4.Range) let mEquals = rhs parseState 3 let m = unionRanges (rhs parseState 1) $8.Range diff --git a/src/fsharp/service/FSharpParseFileResults.fs b/src/fsharp/service/FSharpParseFileResults.fs index 92519ce8a8..7a9743977e 100644 --- a/src/fsharp/service/FSharpParseFileResults.fs +++ b/src/fsharp/service/FSharpParseFileResults.fs @@ -106,7 +106,7 @@ type FSharpParseFileResults(diagnostics: FSharpDiagnostic[], input: ParsedInput, walkBinding expr2 workingRange - | SynExpr.LetOrUse(_, _, bindings, bodyExpr, _) -> + | SynExpr.LetOrUse(bindings=bindings; body=bodyExpr) -> let potentialNestedRange = bindings |> List.tryFind (fun binding -> rangeContainsPos binding.RangeOfBindingWithRhs pos) @@ -205,7 +205,7 @@ type FSharpParseFileResults(diagnostics: FSharpDiagnostic[], input: ParsedInput, // of the identifier of the function we're after getIdentRangeForFuncExprInApp traverseSynExpr funcExpr pos - | SynExpr.LetOrUse (_, _, bindings, body, range) when rangeContainsPos range pos -> + | SynExpr.LetOrUse (bindings=bindings; body=body; range=range) when rangeContainsPos range pos -> let binding = bindings |> List.tryFind (fun x -> rangeContainsPos x.RangeOfBindingWithRhs pos) @@ -631,7 +631,7 @@ type FSharpParseFileResults(diagnostics: FSharpDiagnostic[], input: ParsedInput, yield! walkExprOpt true whenExpr yield! walkExpr true tgtExpr - | SynExpr.LetOrUse (_, _, binds, bodyExpr, _) -> + | SynExpr.LetOrUse (bindings=binds; body=bodyExpr) -> yield! walkBinds binds yield! walkExpr true bodyExpr diff --git a/src/fsharp/service/ServiceInterfaceStubGenerator.fs b/src/fsharp/service/ServiceInterfaceStubGenerator.fs index 773666c555..82907e029f 100644 --- a/src/fsharp/service/ServiceInterfaceStubGenerator.fs +++ b/src/fsharp/service/ServiceInterfaceStubGenerator.fs @@ -824,7 +824,7 @@ module InterfaceStubGenerator = | SynExpr.TypeApp (synExpr, _, _synTypeList, _commas, _, _, _range) -> walkExpr synExpr - | SynExpr.LetOrUse (_, _, synBindingList, synExpr, _range) -> + | SynExpr.LetOrUse (bindings=synBindingList; body=synExpr) -> Option.orElse (List.tryPick walkBinding synBindingList) (walkExpr synExpr) | SynExpr.TryWith (tryExpr=synExpr) -> diff --git a/src/fsharp/service/ServiceParseTreeWalk.fs b/src/fsharp/service/ServiceParseTreeWalk.fs index f1ff997d3c..03869fe17b 100755 --- a/src/fsharp/service/ServiceParseTreeWalk.fs +++ b/src/fsharp/service/ServiceParseTreeWalk.fs @@ -479,7 +479,7 @@ module SyntaxTraversal = | SynExpr.TypeApp (synExpr, _, _synTypeList, _commas, _, _, _range) -> traverseSynExpr synExpr - | SynExpr.LetOrUse (_, isRecursive, synBindingList, synExpr, range) -> + | SynExpr.LetOrUse (_, isRecursive, synBindingList, synExpr, range, _) -> match visitor.VisitLetOrUse(path, isRecursive, traverseSynBinding path, synBindingList, range) with | Some x -> Some x | None -> diff --git a/src/fsharp/service/ServiceParsedInputOps.fs b/src/fsharp/service/ServiceParsedInputOps.fs index 2bf3aab596..d5f5bf0ce1 100644 --- a/src/fsharp/service/ServiceParsedInputOps.fs +++ b/src/fsharp/service/ServiceParsedInputOps.fs @@ -586,7 +586,7 @@ module ParsedInput = | SynExpr.App (_, _, e1, e2, _) -> List.tryPick (walkExprWithKind parentKind) [e1; e2] | SynExpr.TypeApp (e, _, tys, _, _, _, _) -> walkExprWithKind (Some EntityKind.Type) e |> Option.orElseWith (fun () -> List.tryPick walkType tys) - | SynExpr.LetOrUse (_, _, bindings, e, _) -> List.tryPick walkBinding bindings |> Option.orElseWith (fun () -> walkExprWithKind parentKind e) + | SynExpr.LetOrUse (bindings=bindings; body=e) -> List.tryPick walkBinding bindings |> Option.orElseWith (fun () -> walkExprWithKind parentKind e) | SynExpr.TryWith (tryExpr=e; withCases=clauses) -> walkExprWithKind parentKind e |> Option.orElseWith (fun () -> List.tryPick walkClause clauses) | SynExpr.TryFinally (tryExpr=e1; finallyExpr=e2) -> List.tryPick (walkExprWithKind parentKind) [e1; e2] | SynExpr.Lazy (e, _) -> walkExprWithKind parentKind e @@ -1358,7 +1358,7 @@ module ParsedInput = List.iter walkClause synMatchClauseList | SynExpr.TypeApp (e, _, tys, _, _, _, _) -> List.iter walkType tys; walkExpr e - | SynExpr.LetOrUse (_, _, bindings, e, _) -> + | SynExpr.LetOrUse (bindings=bindings; body=e) -> List.iter walkBinding bindings; walkExpr e | SynExpr.TryWith (tryExpr=e; withCases=clauses) -> List.iter walkClause clauses; walkExpr e diff --git a/src/fsharp/service/ServiceStructure.fs b/src/fsharp/service/ServiceStructure.fs index e8b006ae2a..6ada269903 100644 --- a/src/fsharp/service/ServiceStructure.fs +++ b/src/fsharp/service/ServiceStructure.fs @@ -267,7 +267,7 @@ module Structure = | SynExpr.ForEach (_, _, _, _, _, e, r) -> rcheck Scope.For Collapse.Below r r parseExpr e - | SynExpr.LetOrUse (_, _, bindings, body, _) -> + | SynExpr.LetOrUse (bindings=bindings; body=body) -> parseBindings bindings parseExpr body | SynExpr.Match (matchDebugPoint=seqPointAtBinding; clauses=clauses; range=r) diff --git a/tests/FSharp.Compiler.Service.Tests/FSharp.CompilerService.SurfaceArea.netstandard.expected b/tests/FSharp.Compiler.Service.Tests/FSharp.CompilerService.SurfaceArea.netstandard.expected index d5c07975e7..dd8792934d 100644 --- a/tests/FSharp.Compiler.Service.Tests/FSharp.CompilerService.SurfaceArea.netstandard.expected +++ b/tests/FSharp.Compiler.Service.Tests/FSharp.CompilerService.SurfaceArea.netstandard.expected @@ -6420,6 +6420,8 @@ FSharp.Compiler.Syntax.SynExpr+LetOrUse: Boolean isRecursive FSharp.Compiler.Syntax.SynExpr+LetOrUse: Boolean isUse FSharp.Compiler.Syntax.SynExpr+LetOrUse: FSharp.Compiler.Syntax.SynExpr body FSharp.Compiler.Syntax.SynExpr+LetOrUse: FSharp.Compiler.Syntax.SynExpr get_body() +FSharp.Compiler.Syntax.SynExpr+LetOrUse: FSharp.Compiler.SyntaxTrivia.SynExprLetOrUseTrivia get_trivia() +FSharp.Compiler.Syntax.SynExpr+LetOrUse: FSharp.Compiler.SyntaxTrivia.SynExprLetOrUseTrivia trivia FSharp.Compiler.Syntax.SynExpr+LetOrUse: FSharp.Compiler.Text.Range get_range() FSharp.Compiler.Syntax.SynExpr+LetOrUse: FSharp.Compiler.Text.Range range FSharp.Compiler.Syntax.SynExpr+LetOrUse: Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.SynBinding] bindings @@ -6932,7 +6934,7 @@ FSharp.Compiler.Syntax.SynExpr: FSharp.Compiler.Syntax.SynExpr NewInterpolatedSt FSharp.Compiler.Syntax.SynExpr: FSharp.Compiler.Syntax.SynExpr NewJoinIn(FSharp.Compiler.Syntax.SynExpr, FSharp.Compiler.Text.Range, FSharp.Compiler.Syntax.SynExpr, FSharp.Compiler.Text.Range) FSharp.Compiler.Syntax.SynExpr: FSharp.Compiler.Syntax.SynExpr NewLambda(Boolean, Boolean, FSharp.Compiler.Syntax.SynSimplePats, FSharp.Compiler.Syntax.SynExpr, Microsoft.FSharp.Core.FSharpOption`1[System.Tuple`2[Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.SynPat],FSharp.Compiler.Syntax.SynExpr]], FSharp.Compiler.Text.Range, FSharp.Compiler.SyntaxTrivia.SynExprLambdaTrivia) FSharp.Compiler.Syntax.SynExpr: FSharp.Compiler.Syntax.SynExpr NewLazy(FSharp.Compiler.Syntax.SynExpr, FSharp.Compiler.Text.Range) -FSharp.Compiler.Syntax.SynExpr: FSharp.Compiler.Syntax.SynExpr NewLetOrUse(Boolean, Boolean, Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.SynBinding], FSharp.Compiler.Syntax.SynExpr, FSharp.Compiler.Text.Range) +FSharp.Compiler.Syntax.SynExpr: FSharp.Compiler.Syntax.SynExpr NewLetOrUse(Boolean, Boolean, Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.SynBinding], FSharp.Compiler.Syntax.SynExpr, FSharp.Compiler.Text.Range, FSharp.Compiler.SyntaxTrivia.SynExprLetOrUseTrivia) FSharp.Compiler.Syntax.SynExpr: FSharp.Compiler.Syntax.SynExpr NewLetOrUseBang(FSharp.Compiler.Syntax.DebugPointAtBinding, Boolean, Boolean, FSharp.Compiler.Syntax.SynPat, Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Text.Range], FSharp.Compiler.Syntax.SynExpr, Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.SynExprAndBang], FSharp.Compiler.Syntax.SynExpr, FSharp.Compiler.Text.Range) FSharp.Compiler.Syntax.SynExpr: FSharp.Compiler.Syntax.SynExpr NewLibraryOnlyILAssembly(System.Object, Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.SynType], Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.SynExpr], Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.SynType], FSharp.Compiler.Text.Range) FSharp.Compiler.Syntax.SynExpr: FSharp.Compiler.Syntax.SynExpr NewLibraryOnlyStaticOptimization(Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.SynStaticOptimizationConstraint], FSharp.Compiler.Syntax.SynExpr, FSharp.Compiler.Syntax.SynExpr, FSharp.Compiler.Text.Range) @@ -9083,6 +9085,11 @@ FSharp.Compiler.SyntaxTrivia.SynExprLambdaTrivia: Microsoft.FSharp.Core.FSharpOp FSharp.Compiler.SyntaxTrivia.SynExprLambdaTrivia: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Text.Range] get_ArrowRange() FSharp.Compiler.SyntaxTrivia.SynExprLambdaTrivia: System.String ToString() FSharp.Compiler.SyntaxTrivia.SynExprLambdaTrivia: Void .ctor(Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Text.Range]) +FSharp.Compiler.SyntaxTrivia.SynExprLetOrUseTrivia +FSharp.Compiler.SyntaxTrivia.SynExprLetOrUseTrivia: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Text.Range] InKeyword +FSharp.Compiler.SyntaxTrivia.SynExprLetOrUseTrivia: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Text.Range] get_InKeyword() +FSharp.Compiler.SyntaxTrivia.SynExprLetOrUseTrivia: System.String ToString() +FSharp.Compiler.SyntaxTrivia.SynExprLetOrUseTrivia: Void .ctor(Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Text.Range]) FSharp.Compiler.SyntaxTrivia.SynExprTryFinallyTrivia FSharp.Compiler.SyntaxTrivia.SynExprTryFinallyTrivia: FSharp.Compiler.Text.Range FinallyKeyword FSharp.Compiler.SyntaxTrivia.SynExprTryFinallyTrivia: FSharp.Compiler.Text.Range TryKeyword diff --git a/tests/service/Symbols.fs b/tests/service/Symbols.fs index 4654f88efc..d39bef095c 100644 --- a/tests/service/Symbols.fs +++ b/tests/service/Symbols.fs @@ -891,6 +891,83 @@ match! x with assertRange (5, 27) (5, 31) mWithSynInterfaceImpl | _ -> Assert.Fail "Could not get valid AST" + [] + let ``SynExpr.LetOrUse contains the range of in keyword`` () = + let ast = + getParseResults "let x = 1 in ()" + + match ast with + | ParsedInput.ImplFile(ParsedImplFileInput(modules = [ + SynModuleOrNamespace.SynModuleOrNamespace(decls = [ + SynModuleDecl.DoExpr(expr = + SynExpr.LetOrUse(trivia={ InKeyword = Some mIn })) + ]) + ])) -> + assertRange (1, 10) (1, 12) mIn + | _ -> Assert.Fail "Could not get valid AST" + + [] + let ``SynExpr.LetOrUse with recursive binding contains the range of in keyword`` () = + let ast = + getParseResults """ +do + let rec f = () + and g = () in + () +""" + + match ast with + | ParsedInput.ImplFile(ParsedImplFileInput(modules = [ + SynModuleOrNamespace.SynModuleOrNamespace(decls = [ + SynModuleDecl.DoExpr(expr = + SynExpr.Do(expr = SynExpr.LetOrUse(bindings=[_;_]; trivia={ InKeyword = Some mIn }))) + ]) + ])) -> + assertRange (4, 15) (4, 17) mIn + | _ -> Assert.Fail "Could not get valid AST" + + [] + let ``nested SynExpr.LetOrUse contains the range of in keyword`` () = + let ast = + getParseResults """ +let f () = + let x = 1 in // the "in" keyword is available in F# + let y = 2 in + x + y +""" + + match ast with + | ParsedInput.ImplFile(ParsedImplFileInput(modules = [ + SynModuleOrNamespace.SynModuleOrNamespace(decls = [ + SynModuleDecl.Let(bindings = [ + SynBinding(expr = + SynExpr.LetOrUse(bindings=[_]; trivia={ InKeyword = Some mIn }; body=SynExpr.LetOrUse(trivia={ InKeyword = Some mInnerIn }))) + ]) + ]) + ])) -> + assertRange (3, 14) (3, 16) mIn + assertRange (4, 14) (4, 16) mInnerIn + | _ -> Assert.Fail "Could not get valid AST" + + [] + let ``SynExpr.LetOrUse does not contain the range of in keyword`` () = + let ast = + getParseResults """ +do + let x = 1 + () +""" + + match ast with + | ParsedInput.ImplFile(ParsedImplFileInput(modules = [ + SynModuleOrNamespace.SynModuleOrNamespace(decls = [ + SynModuleDecl.DoExpr(expr = + SynExpr.Do(expr = SynExpr.LetOrUse(trivia={ InKeyword = None }))) + ]) + ])) -> + Assert.Pass() + | _ -> Assert.Fail "Could not get valid AST" + module Strings = let getBindingExpressionValue (parseResults: ParsedInput) = match parseResults with