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 5c87eb88b88..3966f6ba5cd 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md +++ b/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md @@ -1,5 +1,6 @@ ### Fixed +* Fix attributes on return type of unparenthesized tuple methods being silently dropped from IL. ([Issue #462](https://github.com/dotnet/fsharp/issues/462), [PR #19714](https://github.com/dotnet/fsharp/pull/19714)) * Fix internal error FS0073 "Undefined or unsolved type variable" in IlxGen when nested inline SRTP functions with multiple overloads leave unsolved typars in the non-witness codegen path. ([Issue #19709](https://github.com/dotnet/fsharp/issues/19709), [PR #19710](https://github.com/dotnet/fsharp/pull/19710)) * Fix NRE when calling virtual Object methods on value types through inline SRTP functions. ([Issue #8098](https://github.com/dotnet/fsharp/issues/8098), [PR #19511](https://github.com/dotnet/fsharp/pull/19511)) * Fix DU case names matching IWSAM member names no longer cause duplicate property entries. (Issue [#14321](https://github.com/dotnet/fsharp/issues/14321), [PR #19341](https://github.com/dotnet/fsharp/pull/19341)) diff --git a/src/Compiler/pars.fsy b/src/Compiler/pars.fsy index 3d9967a5724..315afebadc0 100644 --- a/src/Compiler/pars.fsy +++ b/src/Compiler/pars.fsy @@ -6066,7 +6066,12 @@ topType: | topTupleType { let ty, rmdata = $1 - ty, (SynValInfo([], (match rmdata with [md] -> md | _ -> SynInfo.unnamedRetVal))) } + let retArgInfo = + match rmdata with + | [md] -> md + | SynArgInfo(attrs, _, _) :: _ when not attrs.IsEmpty -> SynArgInfo(attrs, false, None) + | _ -> SynInfo.unnamedRetVal + ty, SynValInfo([], retArgInfo) } topTupleType: | topAppType STAR topTupleTypeElements diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/Basic/Basic.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/Basic/Basic.fs index 333191c9b4b..93148810451 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/Basic/Basic.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/Basic/Basic.fs @@ -263,6 +263,14 @@ module CustomAttributes_Basic = |> verifyCompileAndRun |> shouldSucceed + // SOURCE=ReturnType04.fs # ReturnType04.fs + // Regression test for https://github.com/dotnet/fsharp/issues/462 + [] + let ``ReturnType04_fs`` compilation = + compilation + |> verifyCompileAndRun + |> shouldSucceed + // SOURCE=SanityCheck01.fs # SanityCheck01.fs [] let ``SanityCheck01_fs`` compilation = diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/Basic/ReturnType04.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/Basic/ReturnType04.fs new file mode 100644 index 00000000000..2b27ccd10af --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/Basic/ReturnType04.fs @@ -0,0 +1,38 @@ +// #Regression #Conformance #DeclarationElements #Attributes +// Regression test for https://github.com/dotnet/fsharp/issues/462 +// Attributes on return type of unparenthesized tuple must not be silently dropped. +// + +open System + +[] +type ReturnDescriptionAttribute(info: string) = + inherit Attribute() + member _.Info = info + +type T = + static member Parenthesized(name: string) : + [] + [] + (string * string) = + name, name + + static member Bare(name: string) : + [] + [] + string * string = + name, name + +let getAttrs (methodName: string) = + typeof + .GetMethod(methodName) + .ReturnParameter + .GetCustomAttributes(typeof, false) + |> Array.map (fun a -> (a :?> ReturnDescriptionAttribute).Info) + |> Array.sort + +let parenthesized = getAttrs "Parenthesized" +if parenthesized.Length <> 2 then failwithf "Parenthesized: expected 2 attributes, got %d" parenthesized.Length + +let bare = getAttrs "Bare" +if bare.Length <> 2 then failwithf "Bare: expected 2 attributes, got %d (bug #462 — attributes on unparenthesized tuple return type are silently dropped)" bare.Length diff --git a/tests/service/data/SyntaxTree/Attribute/ReturnTypeAttributeOnBareTuple.fs b/tests/service/data/SyntaxTree/Attribute/ReturnTypeAttributeOnBareTuple.fs new file mode 100644 index 00000000000..a00d6b4b53e --- /dev/null +++ b/tests/service/data/SyntaxTree/Attribute/ReturnTypeAttributeOnBareTuple.fs @@ -0,0 +1,7 @@ +module M + +type T = + static member GetPair() : + [] + string * string = + "", "" diff --git a/tests/service/data/SyntaxTree/Attribute/ReturnTypeAttributeOnBareTuple.fs.bsl b/tests/service/data/SyntaxTree/Attribute/ReturnTypeAttributeOnBareTuple.fs.bsl new file mode 100644 index 00000000000..166ea4e9260 --- /dev/null +++ b/tests/service/data/SyntaxTree/Attribute/ReturnTypeAttributeOnBareTuple.fs.bsl @@ -0,0 +1,122 @@ +ImplFile + (ParsedImplFileInput + ("/root/Attribute/ReturnTypeAttributeOnBareTuple.fs", false, + QualifiedNameOfFile M, [], + [SynModuleOrNamespace + ([M], false, NamedModule, + [Types + ([SynTypeDefn + (SynComponentInfo + ([], None, [], [T], + PreXmlDoc ((3,0), FSharp.Compiler.Xml.XmlDocCollector), + false, None, (3,5--3,6)), + ObjectModel + (Unspecified, + [Member + (SynBinding + (None, Normal, false, false, [], + PreXmlDoc ((4,4), FSharp.Compiler.Xml.XmlDocCollector), + SynValData + (Some { IsInstance = false + IsDispatchSlot = false + IsOverrideOrExplicitImpl = false + IsFinal = false + GetterOrSetterIsCompilerGenerated = false + MemberKind = Member }, + SynValInfo + ([[]], + SynArgInfo + ([{ Attributes = + [{ TypeName = + SynLongIdent ([A], [], [None]) + ArgExpr = Const (Unit, (5,10--5,11)) + Target = None + AppliesToGetterAndSetter = false + Range = (5,10--5,11) }] + Range = (5,8--5,13) }], false, None)), + None), + LongIdent + (SynLongIdent ([GetPair], [], [None]), None, None, + Pats + [Paren + (Const (Unit, (4,25--4,27)), (4,25--4,27))], + None, (4,18--4,27)), + Some + (SynBindingReturnInfo + (Tuple + (false, + [Type + (SignatureParameter + ([{ Attributes = + [{ TypeName = + SynLongIdent + ([A], [], [None]) + ArgExpr = + Const (Unit, (5,10--5,11)) + Target = None + AppliesToGetterAndSetter = + false + Range = (5,10--5,11) }] + Range = (5,8--5,13) }], false, + None, + LongIdent + (SynLongIdent + ([string], [], [None])), + (5,8--6,14))); Star (6,15--6,16); + Type + (LongIdent + (SynLongIdent ([string], [], [None])))], + (5,8--6,23)), (5,8--6,23), + [{ Attributes = + [{ TypeName = + SynLongIdent ([A], [], [None]) + ArgExpr = Const (Unit, (5,10--5,11)) + Target = None + AppliesToGetterAndSetter = false + Range = (5,10--5,11) }] + Range = (5,8--5,13) }], + { ColonRange = Some (4,28--4,29) })), + Typed + (Tuple + (false, + [Const + (String ("", Regular, (7,12--7,14)), + (7,12--7,14)); + Const + (String ("", Regular, (7,16--7,18)), + (7,16--7,18))], [(7,14--7,15)], + (7,12--7,18)), + Tuple + (false, + [Type + (SignatureParameter + ([{ Attributes = + [{ TypeName = + SynLongIdent ([A], [], [None]) + ArgExpr = + Const (Unit, (5,10--5,11)) + Target = None + AppliesToGetterAndSetter = false + Range = (5,10--5,11) }] + Range = (5,8--5,13) }], false, None, + LongIdent + (SynLongIdent ([string], [], [None])), + (5,8--6,14))); Star (6,15--6,16); + Type + (LongIdent + (SynLongIdent ([string], [], [None])))], + (5,8--6,23)), (7,12--7,18)), (4,18--4,27), + NoneAtInvisible, + { LeadingKeyword = + StaticMember ((4,4--4,10), (4,11--4,17)) + InlineKeyword = None + EqualsRange = Some (6,24--6,25) }), (4,4--7,18))], + (4,4--7,18)), [], None, (3,5--7,18), + { LeadingKeyword = Type (3,0--3,4) + EqualsRange = Some (3,7--3,8) + WithKeyword = None })], (3,0--7,18))], + PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None, + (1,0--7,18), { LeadingKeyword = Module (1,0--1,6) })], (true, true), + { ConditionalDirectives = [] + WarnDirectives = [] + CodeComments = [] }, set [])) diff --git a/tests/service/data/SyntaxTree/Attribute/ReturnTypeAttributeOnParenthesizedTuple.fs b/tests/service/data/SyntaxTree/Attribute/ReturnTypeAttributeOnParenthesizedTuple.fs new file mode 100644 index 00000000000..7a0bfc47e7f --- /dev/null +++ b/tests/service/data/SyntaxTree/Attribute/ReturnTypeAttributeOnParenthesizedTuple.fs @@ -0,0 +1,7 @@ +module M + +type T = + static member GetPair() : + [] + (string * string) = + "", "" diff --git a/tests/service/data/SyntaxTree/Attribute/ReturnTypeAttributeOnParenthesizedTuple.fs.bsl b/tests/service/data/SyntaxTree/Attribute/ReturnTypeAttributeOnParenthesizedTuple.fs.bsl new file mode 100644 index 00000000000..41b874e5280 --- /dev/null +++ b/tests/service/data/SyntaxTree/Attribute/ReturnTypeAttributeOnParenthesizedTuple.fs.bsl @@ -0,0 +1,123 @@ +ImplFile + (ParsedImplFileInput + ("/root/Attribute/ReturnTypeAttributeOnParenthesizedTuple.fs", false, + QualifiedNameOfFile M, [], + [SynModuleOrNamespace + ([M], false, NamedModule, + [Types + ([SynTypeDefn + (SynComponentInfo + ([], None, [], [T], + PreXmlDoc ((3,0), FSharp.Compiler.Xml.XmlDocCollector), + false, None, (3,5--3,6)), + ObjectModel + (Unspecified, + [Member + (SynBinding + (None, Normal, false, false, [], + PreXmlDoc ((4,4), FSharp.Compiler.Xml.XmlDocCollector), + SynValData + (Some { IsInstance = false + IsDispatchSlot = false + IsOverrideOrExplicitImpl = false + IsFinal = false + GetterOrSetterIsCompilerGenerated = false + MemberKind = Member }, + SynValInfo + ([[]], + SynArgInfo + ([{ Attributes = + [{ TypeName = + SynLongIdent ([A], [], [None]) + ArgExpr = Const (Unit, (5,10--5,11)) + Target = None + AppliesToGetterAndSetter = false + Range = (5,10--5,11) }] + Range = (5,8--5,13) }], false, None)), + None), + LongIdent + (SynLongIdent ([GetPair], [], [None]), None, None, + Pats + [Paren + (Const (Unit, (4,25--4,27)), (4,25--4,27))], + None, (4,18--4,27)), + Some + (SynBindingReturnInfo + (SignatureParameter + ([{ Attributes = + [{ TypeName = + SynLongIdent ([A], [], [None]) + ArgExpr = Const (Unit, (5,10--5,11)) + Target = None + AppliesToGetterAndSetter = false + Range = (5,10--5,11) }] + Range = (5,8--5,13) }], false, None, + Paren + (Tuple + (false, + [Type + (LongIdent + (SynLongIdent + ([string], [], [None]))); + Star (6,16--6,17); + Type + (LongIdent + (SynLongIdent + ([string], [], [None])))], + (6,9--6,24)), (6,8--6,25)), + (5,8--6,25)), (5,8--6,25), + [{ Attributes = + [{ TypeName = + SynLongIdent ([A], [], [None]) + ArgExpr = Const (Unit, (5,10--5,11)) + Target = None + AppliesToGetterAndSetter = false + Range = (5,10--5,11) }] + Range = (5,8--5,13) }], + { ColonRange = Some (4,28--4,29) })), + Typed + (Tuple + (false, + [Const + (String ("", Regular, (7,12--7,14)), + (7,12--7,14)); + Const + (String ("", Regular, (7,16--7,18)), + (7,16--7,18))], [(7,14--7,15)], + (7,12--7,18)), + SignatureParameter + ([{ Attributes = + [{ TypeName = + SynLongIdent ([A], [], [None]) + ArgExpr = Const (Unit, (5,10--5,11)) + Target = None + AppliesToGetterAndSetter = false + Range = (5,10--5,11) }] + Range = (5,8--5,13) }], false, None, + Paren + (Tuple + (false, + [Type + (LongIdent + (SynLongIdent + ([string], [], [None]))); + Star (6,16--6,17); + Type + (LongIdent + (SynLongIdent + ([string], [], [None])))], + (6,9--6,24)), (6,8--6,25)), (5,8--6,25)), + (7,12--7,18)), (4,18--4,27), NoneAtInvisible, + { LeadingKeyword = + StaticMember ((4,4--4,10), (4,11--4,17)) + InlineKeyword = None + EqualsRange = Some (6,26--6,27) }), (4,4--7,18))], + (4,4--7,18)), [], None, (3,5--7,18), + { LeadingKeyword = Type (3,0--3,4) + EqualsRange = Some (3,7--3,8) + WithKeyword = None })], (3,0--7,18))], + PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None, + (1,0--7,18), { LeadingKeyword = Module (1,0--1,6) })], (true, true), + { ConditionalDirectives = [] + WarnDirectives = [] + CodeComments = [] }, set []))