diff --git a/src/Compiler/Checking/CheckExpressions.fs b/src/Compiler/Checking/CheckExpressions.fs index b08b9632f10..72e8448e62c 100644 --- a/src/Compiler/Checking/CheckExpressions.fs +++ b/src/Compiler/Checking/CheckExpressions.fs @@ -5467,7 +5467,7 @@ and TcExprUndelayed (cenv: cenv) (overallTy: OverallTy) env tpenv (synExpr: SynE TcNonControlFlowExpr env <| fun env -> CallExprHasTypeSink cenv.tcSink (m, env.NameEnv, overallTy.Commit, env.AccessRights) TcConstExpr cenv overallTy env m tpenv synConst - | SynExpr.DotLambda (synExpr, m) -> + | SynExpr.DotLambda (synExpr, m, _) -> let unaryArg = mkSynId m (cenv.synArgNameGenerator.New()) let svar = mkSynCompGenSimplePatVar unaryArg let pushedExpr = pushUnaryArg synExpr unaryArg diff --git a/src/Compiler/SyntaxTree/SyntaxTree.fs b/src/Compiler/SyntaxTree/SyntaxTree.fs index 36d2f245c1b..f75e92b47b5 100644 --- a/src/Compiler/SyntaxTree/SyntaxTree.fs +++ b/src/Compiler/SyntaxTree/SyntaxTree.fs @@ -611,7 +611,7 @@ type SynExpr = | DotGet of expr: SynExpr * rangeOfDot: range * longDotId: SynLongIdent * range: range - | DotLambda of expr: SynExpr * range: range + | DotLambda of expr: SynExpr * range: range * trivia: SynExprDotLambdaTrivia | DotSet of targetExpr: SynExpr * longDotId: SynLongIdent * rhsExpr: SynExpr * range: range diff --git a/src/Compiler/SyntaxTree/SyntaxTree.fsi b/src/Compiler/SyntaxTree/SyntaxTree.fsi index b8075eef8d3..18dc34af44a 100644 --- a/src/Compiler/SyntaxTree/SyntaxTree.fsi +++ b/src/Compiler/SyntaxTree/SyntaxTree.fsi @@ -767,7 +767,7 @@ type SynExpr = | DotGet of expr: SynExpr * rangeOfDot: range * longDotId: SynLongIdent * range: range /// F# syntax: _.ident.ident - | DotLambda of expr: SynExpr * range: range + | DotLambda of expr: SynExpr * range: range * trivia: SynExprDotLambdaTrivia /// F# syntax: expr.ident...ident <- expr | DotSet of targetExpr: SynExpr * longDotId: SynLongIdent * rhsExpr: SynExpr * range: range diff --git a/src/Compiler/SyntaxTree/SyntaxTrivia.fs b/src/Compiler/SyntaxTree/SyntaxTrivia.fs index 1b03d20b615..cee917e457b 100644 --- a/src/Compiler/SyntaxTree/SyntaxTrivia.fs +++ b/src/Compiler/SyntaxTree/SyntaxTrivia.fs @@ -75,6 +75,13 @@ type SynExprLambdaTrivia = static member Zero: SynExprLambdaTrivia = { ArrowRange = None } +[] +type SynExprDotLambdaTrivia = + { + UnderscoreRange : range + DotRange : range + } + [] type SynExprLetOrUseTrivia = { InKeyword: range option } diff --git a/src/Compiler/SyntaxTree/SyntaxTrivia.fsi b/src/Compiler/SyntaxTree/SyntaxTrivia.fsi index fbdf8ecf30e..bb9cfc307e7 100644 --- a/src/Compiler/SyntaxTree/SyntaxTrivia.fsi +++ b/src/Compiler/SyntaxTree/SyntaxTrivia.fsi @@ -119,6 +119,14 @@ type SynExprLambdaTrivia = static member Zero: SynExprLambdaTrivia +/// Represents additional information for SynExpr.DotLambda +[] +type SynExprDotLambdaTrivia = + { + UnderscoreRange : range + DotRange : range + } + /// Represents additional information for SynExpr.LetOrUse [] type SynExprLetOrUseTrivia = diff --git a/src/Compiler/pars.fsy b/src/Compiler/pars.fsy index 51ec58e5f21..f9748cf0d5d 100644 --- a/src/Compiler/pars.fsy +++ b/src/Compiler/pars.fsy @@ -4307,9 +4307,11 @@ argExpr: atomicExpr: | UNDERSCORE DOT atomicExpr %prec dot_lambda - { let arg1 = lhs parseState - let arg2, hpa = $3 - SynExpr.DotLambda(arg2, arg2.Range), false } + { let arg1 = rhs parseState 1 + let arg2 = rhs parseState 2 + let arg3, hpa = $3 + let trivia: SynExprDotLambdaTrivia = { UnderscoreRange = arg1; DotRange = arg2 } + SynExpr.DotLambda(arg3, unionRanges arg1 arg3.Range, trivia), false } | atomicExpr HIGH_PRECEDENCE_BRACK_APP atomicExpr { let arg1, _ = $1 diff --git a/tests/service/SyntaxTreeTests/ExpressionTests.fs b/tests/service/SyntaxTreeTests/ExpressionTests.fs index 5a44f95c013..965ebc13326 100644 --- a/tests/service/SyntaxTreeTests/ExpressionTests.fs +++ b/tests/service/SyntaxTreeTests/ExpressionTests.fs @@ -4,15 +4,6 @@ open FSharp.Compiler.Service.Tests.Common open FSharp.Compiler.Syntax open FSharp.Compiler.SyntaxTrivia open NUnit.Framework - -open Xunit -// [] -// let ``Thomas`` () = - // let ast = """_.ToString.ToString "b" """ |> getParseResults - // let ast = """_.x""" |> getParseResults - // let ast = """_.x()""" |> getParseResults - // Assert.Fail (ast.ToString()) - [] let ``SynExpr.Do contains the range of the do keyword`` () = let ast = """let a = @@ -502,3 +493,29 @@ type CFoo() = assertRange (7,4) (7, 67) m | _ -> Assert.Fail $"Could not get valid AST, got {ast}" +[] +let ``SynExpr.DotLambda has correct ranges and trivia`` () = + let ast = + getParseResults """ +let e1 : obj [] -> string = _(*test*).(*test*)[5].ToString() +""" + + match ast with + | ParsedInput.ImplFile(ParsedImplFileInput(contents = [ + SynModuleOrNamespace.SynModuleOrNamespace(decls = [ + SynModuleDecl.Let(bindings = + [SynBinding.SynBinding(expr = + SynExpr.Typed(expr = + SynExpr.DotLambda( + SynExpr.App(range = innerRange), + dlRange, + { UnderscoreRange = urange; DotRange = dRange } + )))]) + ]) + ])) -> + assertRange (2, 28) (2, 60) dlRange + assertRange (2, 28) (2, 29) urange + assertRange (2, 37) (2, 38) dRange + assertRange (2, 46) (2, 60) innerRange + Assert.Pass() + | _ -> Assert.Fail $"Could not get valid AST, got {ast}"