Skip to content

Commit

Permalink
Attribute targets on unions (dotnet#17389)
Browse files Browse the repository at this point in the history
* Attribute targets on unions

* fix tests

* release notes
  • Loading branch information
edgarfgp authored Jul 22, 2024
1 parent 2818689 commit 8ac35dc
Show file tree
Hide file tree
Showing 8 changed files with 159 additions and 30 deletions.
1 change: 1 addition & 0 deletions docs/release-notes/.FSharp.Compiler.Service/9.0.100.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
6 changes: 6 additions & 0 deletions src/Compiler/Checking/CheckDeclarations.fs
Original file line number Diff line number Diff line change
Expand Up @@ -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 []
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,21 @@ type ILTableName(idx: int) =
type Record = { Prop: string }

[<RequireQualifiedAccess>]
[<Struct>]
type StructRecord = { Prop: string }
[<CustomClass>]
type Record2 = { Prop: string }

[<RequireQualifiedAccess>]
type ClassUnion =
| StructUnionCase of int
| StructUnionCase2 of string

[<RequireQualifiedAccess>]
type ClassUnionId = Id

[<CustomClass>]
type ClassUnionId2 = Id

[<CustomClass>]
type UnionCase =
| UnionCase of int
| UnionCase2 of string
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,33 @@ type SemanticClassificationItem =
type ILTableName(idx: int) =
member __.Index = idx
static member FromIndex n = ILTableName n

[<RequireQualifiedAccess>]
[<Struct>]
type StructRecord = { Prop: string }

[<RequireQualifiedAccess>]
[<Struct>]
type StructUnion =
| StructUnionCase of a: int
| StructUnionCase2 of string

[<RequireQualifiedAccess>]
[<Struct>]
type StructUnionId = Id

[<CustomStruct>]
[<Struct>]
type StructUnionId2 = Id

[<CustomStruct>]
[<Struct>]
type Union1 =
| UnionCase of a: int
| UnionCase2 of string

[<CustomStruct>]
[<Struct>]
type Union2 =
| UnionCase of a: int * b: int
| UnionCase2 of c: string * d: string
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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")
]
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,31 @@ type Record = { Prop: string }
[<InterfaceTarget>]
[<StructTarget>]
[<Struct>]
type StructRecord = { Prop: string }
type StructRecord = { Prop: string }

[<ClassTarget>]
[<InterfaceTarget>]
[<StructTarget>]
[<Struct>]
type UnionCase =
| UnionCase of a: int
| UnionCase2 of string

[<ClassTarget>]
[<InterfaceTarget>]
[<StructTarget>]
[<Struct>]
type UnionCase2 =
| UnionCase of a: int * b: int
| UnionCase2 of c: string * d: string

[<ClassTarget>]
[<InterfaceTarget>]
[<StructTarget>]
type StructUnionId = Id

[<ClassTarget>]
[<InterfaceTarget>]
[<StructTarget>]
[<Struct>]
type StructUnionId2 = Id
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,34 @@ type Struct4 = struct end

[<CustomClass>]
[<Struct>]
type Struct5 = struct end
type Struct5 = struct end

[<AttributeUsage(AttributeTargets.Interface)>]
type InterfaceTargetAttribute() =
inherit Attribute()

[<CustomClass>]
[<InterfaceTarget>]
[<CustomStruct>]
type UnionCase =
| UnionCase of int
| UnionCase2 of string

[<CustomClass>]
[<InterfaceTarget>]
[<CustomStruct>]
[<Struct>]
type UnionCase2 =
| UnionCase of a: int * b: int
| UnionCase2 of c: string * d: string

[<CustomClass>]
[<InterfaceTarget>]
[<CustomStruct>]
type StructUnionId = Id

[<CustomClass>]
[<InterfaceTarget>]
[<CustomStruct>]
[<Struct>]
type StructUnionId2 = Id
53 changes: 28 additions & 25 deletions tests/FSharp.Compiler.Service.Tests/ProjectAnalysisTests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -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"])]

//--------------------------------------------

Expand Down

0 comments on commit 8ac35dc

Please sign in to comment.