diff --git a/src/Compiler/SyntaxTree/SyntaxTree.fs b/src/Compiler/SyntaxTree/SyntaxTree.fs index ce5571ab4d9..9127727c196 100644 --- a/src/Compiler/SyntaxTree/SyntaxTree.fs +++ b/src/Compiler/SyntaxTree/SyntaxTree.fs @@ -47,10 +47,14 @@ type SynLongIdent = member this.IdentsWithTrivia = let (SynLongIdent (lid, _, trivia)) = this - if lid.Length <> trivia.Length then - failwith "difference between idents and trivia" - else + if lid.Length = trivia.Length then + List.zip lid trivia |> List.map SynIdent + elif lid.Length > trivia.Length then + let delta = lid.Length - trivia.Length + let trivia = [ yield! trivia; yield! List.replicate delta None ] List.zip lid trivia |> List.map SynIdent + else + failwith "difference between idents and trivia" member this.ThereIsAnExtraDotAtTheEnd = match this with diff --git a/src/Compiler/SyntaxTree/SyntaxTreeOps.fs b/src/Compiler/SyntaxTree/SyntaxTreeOps.fs index b36ec372a78..ef3673fa44f 100644 --- a/src/Compiler/SyntaxTree/SyntaxTreeOps.fs +++ b/src/Compiler/SyntaxTree/SyntaxTreeOps.fs @@ -468,7 +468,7 @@ let mkSynDotMissing mDot m l = | SynExpr.LongIdent (isOpt, SynLongIdent (lid, dots, trivia), None, _) -> // REVIEW: MEMORY PERFORMANCE: This list operation is memory intensive (we create a lot of these list nodes) SynExpr.LongIdent(isOpt, SynLongIdent(lid, dots @ [ mDot ], trivia), None, m) - | SynExpr.Ident id -> SynExpr.LongIdent(false, SynLongIdent([ id ], [ mDot ], []), None, m) + | SynExpr.Ident id -> SynExpr.LongIdent(false, SynLongIdent([ id ], [ mDot ], [ None ]), None, m) | SynExpr.DotGet (e, dm, SynLongIdent (lid, dots, trivia), _) -> SynExpr.DotGet(e, dm, SynLongIdent(lid, dots @ [ mDot ], trivia), m) // REVIEW: MEMORY PERFORMANCE: This is memory intensive (we create a lot of these list nodes) | expr -> SynExpr.DiscardAfterMissingQualificationAfterDot(expr, m) diff --git a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.Tests.fsproj b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.Tests.fsproj index fae9537443b..19175fd7f05 100644 --- a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.Tests.fsproj +++ b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.Tests.fsproj @@ -113,6 +113,9 @@ SyntaxTree\OperatorNameTests.fs + + SyntaxTree\SynIdentTests.fs + FileSystemTests.fs diff --git a/tests/service/SyntaxTreeTests/SynIdentTests.fs b/tests/service/SyntaxTreeTests/SynIdentTests.fs new file mode 100644 index 00000000000..887910e1448 --- /dev/null +++ b/tests/service/SyntaxTreeTests/SynIdentTests.fs @@ -0,0 +1,31 @@ +module FSharp.Compiler.Service.Tests.SyntaxTreeTests.SynIdentTests + +open FSharp.Compiler.Service.Tests.Common +open FSharp.Compiler.Syntax +open FSharp.Compiler.Text +open NUnit.Framework + +[] +let ``Incomplete long ident`` () = + let ast = + """ +module Module + +A. +""" + |> getParseResults + + match ast with + | ParsedInput.ImplFile (ParsedImplFileInput(modules = [ SynModuleOrNamespace.SynModuleOrNamespace(decls = + [ SynModuleDecl.Expr(expr = SynExpr.LongIdent (longDotId = lid)) ]) ])) -> + Assert.AreEqual(1, lid.IdentsWithTrivia.Length) + | _ -> Assert.Fail $"Could not get valid AST, got {ast}" + +[] +let ``IdentsWithTrivia with unbalance collection should not throw`` () = + let synLongIdent = + SynLongIdent([ Ident("A", Range.Zero); Ident("B", Range.Zero) ], [ Range.Zero ], [ None ]) + + match synLongIdent.IdentsWithTrivia with + | [ SynIdent (_, None); SynIdent (_, None) ] -> Assert.Pass() + | identsWithTrivia -> Assert.Fail $"Unexpected identsWithTrivia, got {identsWithTrivia}"