diff --git a/docs/release-notes/.FSharp.Compiler.Service/9.0.100.md b/docs/release-notes/.FSharp.Compiler.Service/9.0.100.md index a2454c414f5..4888bd1aad6 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/9.0.100.md +++ b/docs/release-notes/.FSharp.Compiler.Service/9.0.100.md @@ -10,5 +10,6 @@ * Change compiler default setting realsig+ when building assemblies ([Issue #17384](https://github.com/dotnet/fsharp/issues/17384), [PR #17378](https://github.com/dotnet/fsharp/pull/17385)) * Change compiler default setting for compressedMetadata ([Issue #17379](https://github.com/dotnet/fsharp/issues/17379), [PR #17383](https://github.com/dotnet/fsharp/pull/17383)) +* Enforce `AttributeTargets` on unions. ([PR #17389](https://github.com/dotnet/fsharp/pull/17389)) ### Breaking Changes diff --git a/src/Compiler/Checking/CheckDeclarations.fs b/src/Compiler/Checking/CheckDeclarations.fs index cfedc7b334b..b18ee27f8cb 100644 --- a/src/Compiler/Checking/CheckDeclarations.fs +++ b/src/Compiler/Checking/CheckDeclarations.fs @@ -2879,6 +2879,12 @@ module EstablishTypeDefinitionCores = // Run InferTyconKind to raise errors on inconsistent attribute sets InferTyconKind g (SynTypeDefnKind.Union, attrs, [], [], inSig, true, m) |> ignore + + if g.langVersion.SupportsFeature(LanguageFeature.EnforceAttributeTargets) then + if hasStructAttr then + TcAttributesWithPossibleTargets false cenv envinner AttributeTargets.Struct synAttrs |> ignore + else + TcAttributesWithPossibleTargets false cenv envinner AttributeTargets.Class synAttrs |> ignore // Note: the table of union cases is initially empty Construct.MakeUnionRepr [] diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/AttributeUsage/AttributeTargetsIsClass.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/AttributeUsage/AttributeTargetsIsClass.fs index a2728dace4e..0c9af2292e4 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/AttributeUsage/AttributeTargetsIsClass.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/AttributeUsage/AttributeTargetsIsClass.fs @@ -30,5 +30,21 @@ type ILTableName(idx: int) = type Record = { Prop: string } [] -[] -type StructRecord = { Prop: string } +[] +type Record2 = { Prop: string } + +[] +type ClassUnion = + | StructUnionCase of int + | StructUnionCase2 of string + +[] +type ClassUnionId = Id + +[] +type ClassUnionId2 = Id + +[] +type UnionCase = + | UnionCase of int + | UnionCase2 of string diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/AttributeUsage/AttributeTargetsIsStruct.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/AttributeUsage/AttributeTargetsIsStruct.fs index 9b64c7cb33f..9269f786c0e 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/AttributeUsage/AttributeTargetsIsStruct.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/AttributeUsage/AttributeTargetsIsStruct.fs @@ -21,3 +21,33 @@ type SemanticClassificationItem = type ILTableName(idx: int) = member __.Index = idx static member FromIndex n = ILTableName n + +[] +[] +type StructRecord = { Prop: string } + +[] +[] +type StructUnion = + | StructUnionCase of a: int + | StructUnionCase2 of string + +[] +[] +type StructUnionId = Id + +[] +[] +type StructUnionId2 = Id + +[] +[] +type Union1 = + | UnionCase of a: int + | UnionCase2 of string + +[] +[] +type Union2 = + | UnionCase of a: int * b: int + | UnionCase2 of c: string * d: string \ No newline at end of file diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/AttributeUsage/AttributeUsage.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/AttributeUsage/AttributeUsage.fs index 3206e93fcbc..0cdde04516a 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/AttributeUsage/AttributeUsage.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/AttributeUsage/AttributeUsage.fs @@ -342,6 +342,14 @@ module CustomAttributes_AttributeUsage = (Error 842, Line 19, Col 3, Line 19, Col 14, "This attribute is not valid for use on this language element") (Error 842, Line 22, Col 11, Line 22, Col 22, "This attribute is not valid for use on this language element") (Error 842, Line 25, Col 3, Line 25, Col 14, "This attribute is not valid for use on this language element") + (Error 842, Line 34, Col 3, Line 34, Col 18, "This attribute is not valid for use on this language element") + (Error 842, Line 35, Col 3, Line 35, Col 15, "This attribute is not valid for use on this language element") + (Error 842, Line 40, Col 3, Line 40, Col 14, "This attribute is not valid for use on this language element") + (Error 842, Line 41, Col 3, Line 41, Col 18, "This attribute is not valid for use on this language element") + (Error 842, Line 49, Col 3, Line 49, Col 18, "This attribute is not valid for use on this language element") + (Error 842, Line 50, Col 3, Line 50, Col 15, "This attribute is not valid for use on this language element") + (Error 842, Line 53, Col 3, Line 53, Col 14, "This attribute is not valid for use on this language element") + (Error 842, Line 54, Col 3, Line 54, Col 18, "This attribute is not valid for use on this language element") ] // SOURCE=E_AttributeTargetIsClass.fs # E_AttributeTargetIsClass.fs @@ -655,8 +663,16 @@ type InterruptibleLazy<'T> private (valueFactory: unit -> 'T) = |> verifyCompile |> shouldFail |> withDiagnostics [ - (Error 842, Line 15, Col 3, Line 15, Col 18, "This attribute is not valid for use on this language element") + (Error 842, Line 15, Col 3, Line 15, Col 18, "This attribute is not valid for use on this language element"); (Error 842, Line 16, Col 3, Line 16, Col 15, "This attribute is not valid for use on this language element") (Error 842, Line 20, Col 3, Line 20, Col 14, "This attribute is not valid for use on this language element") (Error 842, Line 21, Col 3, Line 21, Col 18, "This attribute is not valid for use on this language element") + (Error 842, Line 26, Col 3, Line 26, Col 14, "This attribute is not valid for use on this language element") + (Error 842, Line 27, Col 3, Line 27, Col 18, "This attribute is not valid for use on this language element") + (Error 842, Line 34, Col 3, Line 34, Col 14, "This attribute is not valid for use on this language element") + (Error 842, Line 35, Col 3, Line 35, Col 18, "This attribute is not valid for use on this language element") + (Error 842, Line 43, Col 3, Line 43, Col 18, "This attribute is not valid for use on this language element") + (Error 842, Line 44, Col 3, Line 44, Col 15, "This attribute is not valid for use on this language element") + (Error 842, Line 47, Col 3, Line 47, Col 14, "This attribute is not valid for use on this language element") + (Error 842, Line 48, Col 3, Line 48, Col 18, "This attribute is not valid for use on this language element") ] \ No newline at end of file diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/AttributeUsage/E_AttributeTargetIsClass02.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/AttributeUsage/E_AttributeTargetIsClass02.fs index f95f54b8354..532509f0ad5 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/AttributeUsage/E_AttributeTargetIsClass02.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/AttributeUsage/E_AttributeTargetIsClass02.fs @@ -21,4 +21,31 @@ type Record = { Prop: string } [] [] [] -type StructRecord = { Prop: string } \ No newline at end of file +type StructRecord = { Prop: string } + +[] +[] +[] +[] +type UnionCase = + | UnionCase of a: int + | UnionCase2 of string + +[] +[] +[] +[] +type UnionCase2 = + | UnionCase of a: int * b: int + | UnionCase2 of c: string * d: string + +[] +[] +[] +type StructUnionId = Id + +[] +[] +[] +[] +type StructUnionId2 = Id \ No newline at end of file diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/AttributeUsage/E_AttributeTargetIsStruct.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/AttributeUsage/E_AttributeTargetIsStruct.fs index ace0b6a5c39..8e3fe0259d3 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/AttributeUsage/E_AttributeTargetIsStruct.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/AttributeUsage/E_AttributeTargetIsStruct.fs @@ -24,4 +24,34 @@ type Struct4 = struct end [] [] -type Struct5 = struct end \ No newline at end of file +type Struct5 = struct end + +[] +type InterfaceTargetAttribute() = + inherit Attribute() + +[] +[] +[] +type UnionCase = + | UnionCase of int + | UnionCase2 of string + +[] +[] +[] +[] +type UnionCase2 = + | UnionCase of a: int * b: int + | UnionCase2 of c: string * d: string + +[] +[] +[] +type StructUnionId = Id + +[] +[] +[] +[] +type StructUnionId2 = Id \ No newline at end of file diff --git a/tests/FSharp.Compiler.Service.Tests/ProjectAnalysisTests.fs b/tests/FSharp.Compiler.Service.Tests/ProjectAnalysisTests.fs index b89cfebc15d..f520a06bb2e 100644 --- a/tests/FSharp.Compiler.Service.Tests/ProjectAnalysisTests.fs +++ b/tests/FSharp.Compiler.Service.Tests/ProjectAnalysisTests.fs @@ -5075,31 +5075,34 @@ let ``Test Project40 all symbols`` () = let allSymbolUsesInfo = [ for s in allSymbolUses -> s.Symbol.DisplayName, tups s.Range, attribsOfSymbol s.Symbol ] allSymbolUsesInfo |> shouldEqual [("option", ((4, 10), (4, 16)), ["abbrev"]); ("x", ((4, 7), (4, 8)), []); - ("x", ((4, 23), (4, 24)), []); - ("IsSome", ((4, 23), (4, 31)), ["member"; "prop"; "funky"]); - ("x", ((4, 33), (4, 34)), []); - ("IsNone", ((4, 33), (4, 41)), ["member"; "prop"; "funky"]); - ("f", ((4, 4), (4, 5)), ["val"]); - ("CompilationRepresentationAttribute", ((6, 2), (6, 27)), ["class"]); - ("CompilationRepresentationAttribute", ((6, 2), (6, 27)), ["member"]); - ("CompilationRepresentationFlags", ((6, 28), (6, 58)), - ["enum"; "valuetype"]); - ("UseNullAsTrueValue", ((6, 28), (6, 77)), ["field"; "static"; "8"]); - ("string", ((9, 11), (9, 17)), ["abbrev"]); - ("string", ((9, 11), (9, 17)), ["abbrev"]); ("A", ((8, 6), (8, 7)), []); - ("B", ((9, 6), (9, 7)), []); ("C", ((7, 5), (7, 6)), ["union"]); - ("IsItAnA", ((10, 13), (10, 20)), ["member"; "getter"; "funky"]); - ("IsItAnAMethod", ((11, 13), (11, 26)), ["member"; "funky"]); - ("x", ((10, 11), (10, 12)), []); ("x", ((10, 29), (10, 30)), []); - ("A", ((10, 36), (10, 37)), []); ("B", ((10, 48), (10, 49)), []); - ("x", ((11, 11), (11, 12)), []); ("x", ((11, 37), (11, 38)), []); - ("A", ((11, 44), (11, 45)), []); ("B", ((11, 56), (11, 57)), []); - ("C", ((13, 10), (13, 11)), ["union"]); ("x", ((13, 7), (13, 8)), []); - ("x", ((13, 15), (13, 16)), []); - ("IsItAnA", ((13, 15), (13, 24)), ["member"; "prop"; "funky"]); - ("x", ((13, 25), (13, 26)), []); - ("IsItAnAMethod", ((13, 25), (13, 40)), ["member"; "funky"]); - ("g", ((13, 4), (13, 5)), ["val"]); ("M", ((2, 7), (2, 8)), ["module"])] + ("x", ((4, 23), (4, 24)), []); + ("IsSome", ((4, 23), (4, 31)), ["member"; "prop"; "funky"]); + ("x", ((4, 33), (4, 34)), []); + ("IsNone", ((4, 33), (4, 41)), ["member"; "prop"; "funky"]); + ("f", ((4, 4), (4, 5)), ["val"]); + ("CompilationRepresentationAttribute", ((6, 2), (6, 27)), ["class"]); + ("CompilationRepresentationAttribute", ((6, 2), (6, 27)), ["member"]); + ("CompilationRepresentationFlags", ((6, 28), (6, 58)), ["enum"; "valuetype"]); + ("UseNullAsTrueValue", ((6, 28), (6, 77)), ["field"; "static"; "8"]); + ("CompilationRepresentationAttribute", ((6, 2), (6, 27)), ["class"]); + ("CompilationRepresentationAttribute", ((6, 2), (6, 27)), ["member"]); + ("CompilationRepresentationFlags", ((6, 28), (6, 58)), ["enum"; "valuetype"]); + ("UseNullAsTrueValue", ((6, 28), (6, 77)), ["field"; "static"; "8"]); + ("string", ((9, 11), (9, 17)), ["abbrev"]); + ("string", ((9, 11), (9, 17)), ["abbrev"]); ("A", ((8, 6), (8, 7)), []); + ("B", ((9, 6), (9, 7)), []); ("C", ((7, 5), (7, 6)), ["union"]); + ("IsItAnA", ((10, 13), (10, 20)), ["member"; "getter"; "funky"]); + ("IsItAnAMethod", ((11, 13), (11, 26)), ["member"; "funky"]); + ("x", ((10, 11), (10, 12)), []); ("x", ((10, 29), (10, 30)), []); + ("A", ((10, 36), (10, 37)), []); ("B", ((10, 48), (10, 49)), []); + ("x", ((11, 11), (11, 12)), []); ("x", ((11, 37), (11, 38)), []); + ("A", ((11, 44), (11, 45)), []); ("B", ((11, 56), (11, 57)), []); + ("C", ((13, 10), (13, 11)), ["union"]); ("x", ((13, 7), (13, 8)), []); + ("x", ((13, 15), (13, 16)), []); + ("IsItAnA", ((13, 15), (13, 24)), ["member"; "prop"; "funky"]); + ("x", ((13, 25), (13, 26)), []); + ("IsItAnAMethod", ((13, 25), (13, 40)), ["member"; "funky"]); + ("g", ((13, 4), (13, 5)), ["val"]); ("M", ((2, 7), (2, 8)), ["module"])] //--------------------------------------------