diff --git a/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md b/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md index ba843ca702c..9b7ad651b60 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md +++ b/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md @@ -3,6 +3,7 @@ * Semantic classification no longer marks recursive object self-references (`as this`, `let rec` self-refs) as mutable. ([Issue #5229](https://github.com/dotnet/fsharp/issues/5229)) * Fix `MethodAccessException` under `--realsig+` when a closure (inner `let rec`, `task`/`async` state machine, or quotation splice) inside a member defined in an intrinsic type augmentation (`type C with member ...`) accesses a `private` member of `C`. The synthesized closure is now nested inside the declaring type instead of beside it in the module class. ([Issue #19933](https://github.com/dotnet/fsharp/issues/19933), [PR #19955](https://github.com/dotnet/fsharp/pull/19955)) * Preserve source range for type errors on empty-bodied computation expressions (e.g. `foo {}`) in pipelines, function arguments, and type-annotated contexts, instead of reporting `unknown(1,1)`. ([Issue #19550](https://github.com/dotnet/fsharp/issues/19550), [PR #19849](https://github.com/dotnet/fsharp/pull/19849)) +* Fix multiline nested type arguments failing to parse when the closing `>` aligns with the opening type name's column. ([Issue #15171](https://github.com/dotnet/fsharp/issues/15171)) * Tooltip "Full name" now shows demangled companion module names (e.g. `MyType.func` instead of `MyTypeModule.func`). ([Issue #17335](https://github.com/dotnet/fsharp/issues/17335), [PR #19867](https://github.com/dotnet/fsharp/pull/19867)) * Fix internal error (FS0193) when calling an indexed property setter with a named argument that matches an indexer parameter. ([Issue #16034](https://github.com/dotnet/fsharp/issues/16034), [PR #19851](https://github.com/dotnet/fsharp/pull/19851)) * Fix missing FS1182 ("unused binding") warning for unused `let` function bindings inside class types. ([Issue #13849](https://github.com/dotnet/fsharp/issues/13849), [PR #19805](https://github.com/dotnet/fsharp/pull/19805)) diff --git a/src/Compiler/SyntaxTree/LexFilter.fs b/src/Compiler/SyntaxTree/LexFilter.fs index e0e450c398f..16376828996 100644 --- a/src/Compiler/SyntaxTree/LexFilter.fs +++ b/src/Compiler/SyntaxTree/LexFilter.fs @@ -383,6 +383,11 @@ let rec isSeqBlockElementContinuator token = // Shortcut.CtrlO) | END | AND | WITH | THEN | RPAREN | RBRACE _ | BAR_RBRACE | RBRACK | BAR_RBRACK | RQUOTE _ -> true + // A closing '>' of a (possibly multiline) type-argument list is a closing bracket, like ')' or ']' + // above: it may align with the first column of a sequence block without starting a new element. + // See dotnet/fsharp#15171. + | GREATER true -> true + // The following arise during reprocessing of the inserted tokens when we hit a DONE | ORIGHT_BLOCK_END _ | OBLOCKEND _ | ODECLEND (_, _) -> true | ODUMMY token -> isSeqBlockElementContinuator token diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/LexicalFiltering/OffsideExceptions/MultilineNestedTypeArguments.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/LexicalFiltering/OffsideExceptions/MultilineNestedTypeArguments.fs new file mode 100644 index 00000000000..06cf74ba3ac --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/LexicalFiltering/OffsideExceptions/MultilineNestedTypeArguments.fs @@ -0,0 +1,17 @@ +// #Regression #Conformance #LexFilter #Exceptions +// https://github.com/dotnet/fsharp/issues/15171 +// The closing '>' of a nested, multiline type-argument list may align with the column of the +// opening type name (here the inner 'Foo'); it must not be treated as a new sequence-block item. + +open System + +type Bar = class end +type Foo<'a> = class end + +type Terminal = + abstract onKey: + IEvent< + Foo< + Bar * int + > + > with get, set diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/LexicalFiltering/OffsideExceptions/OffsideExceptions.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/LexicalFiltering/OffsideExceptions/OffsideExceptions.fs index 9dc910ba249..effaefb51c8 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/LexicalFiltering/OffsideExceptions/OffsideExceptions.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/LexicalFiltering/OffsideExceptions/OffsideExceptions.fs @@ -9,12 +9,23 @@ open FSharp.Test.Compiler.Assertions.StructuredResultsAsserts module OffsideExceptions = + // https://github.com/dotnet/fsharp/issues/15171 + // The closing '>' of a nested multiline type-argument list may align with the opening type name. + [] + let MultilineNestedTypeArguments compilation = + compilation + |> getCompilation + |> asFsx + |> typecheck + |> shouldSucceed + |> ignore + // This test was automatically generated (moved from FSharpQA suite - Conformance/LexicalFiltering/Basic/OffsideExceptions) // [] let InfixTokenPlusOne compilation = compilation - |> getCompilation + |> getCompilation |> asFsx |> typecheck |> shouldSucceed diff --git a/tests/service/data/SyntaxTree/SynType/SynTypeAppNestedMultilineClosingGreaterAligned.fs b/tests/service/data/SyntaxTree/SynType/SynTypeAppNestedMultilineClosingGreaterAligned.fs new file mode 100644 index 00000000000..dddf7143e80 --- /dev/null +++ b/tests/service/data/SyntaxTree/SynType/SynTypeAppNestedMultilineClosingGreaterAligned.fs @@ -0,0 +1,7 @@ +type T = + abstract M: + A< + B< + int + > + > diff --git a/tests/service/data/SyntaxTree/SynType/SynTypeAppNestedMultilineClosingGreaterAligned.fs.bsl b/tests/service/data/SyntaxTree/SynType/SynTypeAppNestedMultilineClosingGreaterAligned.fs.bsl new file mode 100644 index 00000000000..a33d80c9764 --- /dev/null +++ b/tests/service/data/SyntaxTree/SynType/SynTypeAppNestedMultilineClosingGreaterAligned.fs.bsl @@ -0,0 +1,49 @@ +ImplFile + (ParsedImplFileInput + ("/root/SynType/SynTypeAppNestedMultilineClosingGreaterAligned.fs", false, + QualifiedNameOfFile SynTypeAppNestedMultilineClosingGreaterAligned, [], + [SynModuleOrNamespace + ([SynTypeAppNestedMultilineClosingGreaterAligned], false, AnonModule, + [Types + ([SynTypeDefn + (SynComponentInfo + ([], None, [], [T], + PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), + false, None, (1,5--1,6)), + ObjectModel + (Unspecified, + [AbstractSlot + (SynValSig + ([], SynIdent (M, None), + SynValTyparDecls (None, true), + App + (LongIdent (SynLongIdent ([A], [], [None])), + Some (3,9--3,10), + [App + (LongIdent (SynLongIdent ([B], [], [None])), + Some (4,13--4,14), + [LongIdent (SynLongIdent ([int], [], [None]))], + [], Some (6,12--6,13), false, (4,12--6,13))], + [], Some (7,8--7,9), false, (3,8--7,9)), + SynValInfo ([], SynArgInfo ([], false, None)), false, + false, + PreXmlDoc ((2,4), FSharp.Compiler.Xml.XmlDocCollector), + Single None, None, (2,4--7,9), + { LeadingKeyword = Abstract (2,4--2,12) + InlineKeyword = None + WithKeyword = None + EqualsRange = None }), + { IsInstance = true + IsDispatchSlot = true + IsOverrideOrExplicitImpl = false + IsFinal = false + GetterOrSetterIsCompilerGenerated = false + MemberKind = PropertyGet }, (2,4--7,9), + { GetSetKeywords = None })], (2,4--7,9)), [], None, + (1,5--7,9), { LeadingKeyword = Type (1,0--1,4) + EqualsRange = Some (1,7--1,8) + WithKeyword = None })], (1,0--7,9))], + PreXmlDocEmpty, [], None, (1,0--8,0), { LeadingKeyword = None })], + (true, true), { ConditionalDirectives = [] + WarnDirectives = [] + CodeComments = [] }, set []))