From 03f306e823977ffdaf6a9c08668213f969b134d2 Mon Sep 17 00:00:00 2001 From: nojaf Date: Tue, 6 Sep 2022 14:17:34 +0200 Subject: [PATCH] Return None when Trivia is missing for Ident in SynLongIdent. --- src/Compiler/SyntaxTree/SyntaxTree.fs | 10 ++++-- src/Compiler/SyntaxTree/SyntaxTreeOps.fs | 2 +- .../FSharp.Compiler.Service.Tests.fsproj | 3 ++ .../service/SyntaxTreeTests/SynIdentTests.fs | 31 +++++++++++++++++++ 4 files changed, 42 insertions(+), 4 deletions(-) create mode 100644 tests/service/SyntaxTreeTests/SynIdentTests.fs diff --git a/src/Compiler/SyntaxTree/SyntaxTree.fs b/src/Compiler/SyntaxTree/SyntaxTree.fs index 8a0b853f63e..fef45e8f46e 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 590f5523214..82565fc99d7 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 30e2e9c933c..8aec4895b74 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}"