Attribute targets on records (#17207) · dotnet/fsharp@0294fe7 · GitHub
Skip to content

Commit 0294fe7

Browse files
edgarfgppsfinaki
andauthored
Attribute targets on records (#17207)
Co-authored-by: Petr <psfinaki@users.noreply.github.com>
1 parent 86df629 commit 0294fe7

10 files changed

Lines changed: 69 additions & 5 deletions

File tree

‎docs/release-notes/.FSharp.Compiler.Service/8.0.400.md‎

Lines changed: 1 addition & 0 deletions

‎docs/release-notes/.FSharp.Core/8.0.400.md‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88

99
* Cache delegate in query extensions. ([PR #17130](https://github.com/dotnet/fsharp/pull/17130))
1010
* Update `AllowNullLiteralAttribute` to also use `AttributeTargets.Interface` ([PR #17173](https://github.com/dotnet/fsharp/pull/17173))
11+
* Update `StructAttribute ` to also use `AttributeTargets.Class` ([PR #17207](https://github.com/dotnet/fsharp/pull/17207))
1112

1213
### Breaking Changes
1314

14-
* Fixed argument exception throwing inconsistency - accessing an out-of-bounds collection index will now throw `ArgumentOutOfRangeException` instead of `ArgumentException` ([#17328](https://github.com/dotnet/fsharp/pull/17328))
15+
* Fixed argument exception throwing inconsistency - accessing an out-of-bounds collection index will now throw `ArgumentOutOfRangeException` instead of `ArgumentException` ([#17328](https://github.com/dotnet/fsharp/pull/17328))

‎src/Compiler/Checking/CheckDeclarations.fs‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -428,6 +428,7 @@ module TcRecdUnionAndEnumDeclarations =
428428
let g = cenv.g
429429
let m = id.idRange
430430
let attrs, _ = TcAttributesWithPossibleTargets false cenv env AttributeTargets.FieldDecl synAttrs
431+
431432
let attrsForProperty, attrsForField = attrs |> List.partition (fun (attrTargets, _) -> (attrTargets &&& AttributeTargets.Property) <> enum 0)
432433
let attrsForProperty = (List.map snd attrsForProperty)
433434
let attrsForField = (List.map snd attrsForField)
@@ -2840,6 +2841,7 @@ module EstablishTypeDefinitionCores =
28402841
// Allow failure of constructor resolution because Vals for members in the same recursive group are not yet available
28412842
let attrs, getFinalAttrs = TcAttributesCanFail cenv envinner AttributeTargets.TyconDecl synAttrs
28422843
let hasMeasureAttr = HasFSharpAttribute g g.attrib_MeasureAttribute attrs
2844+
let hasStructAttr = HasFSharpAttribute g g.attrib_StructAttribute attrs
28432845

28442846
let isStructRecordOrUnionType =
28452847
match synTyconRepr with
@@ -2896,6 +2898,12 @@ module EstablishTypeDefinitionCores =
28962898

28972899
// Run InferTyconKind to raise errors on inconsistent attribute sets
28982900
InferTyconKind g (SynTypeDefnKind.Record, attrs, [], [], inSig, true, m) |> ignore
2901+
2902+
if g.langVersion.SupportsFeature(LanguageFeature.EnforceAttributeTargets) then
2903+
if hasStructAttr then
2904+
TcAttributesWithPossibleTargets false cenv envinner AttributeTargets.Struct synAttrs |> ignore
2905+
else
2906+
TcAttributesWithPossibleTargets false cenv envinner AttributeTargets.Class synAttrs |> ignore
28992907

29002908
// Note: the table of record fields is initially empty
29012909
TFSharpTyconRepr (Construct.NewEmptyFSharpTyconData TFSharpRecord)

‎src/FSharp.Core/prim-types.fs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ namespace Microsoft.FSharp.Core
180180
inherit Attribute()
181181
member _.CompiledName = compiledName
182182

183-
[<AttributeUsage (AttributeTargets.Struct ||| AttributeTargets.ReturnValue, AllowMultiple=false)>]
183+
[<AttributeUsage (AttributeTargets.Class ||| AttributeTargets.Struct ||| AttributeTargets.ReturnValue, AllowMultiple=false)>]
184184
[<Sealed>]
185185
type StructAttribute() =
186186
inherit Attribute()

‎src/FSharp.Core/prim-types.fsi‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ namespace Microsoft.FSharp.Core
199199
/// <summary>Adding this attribute to a type causes it to be represented using a CLI struct.</summary>
200200
///
201201
/// <category>Attributes</category>
202-
[<AttributeUsage (AttributeTargets.Struct ||| AttributeTargets.ReturnValue ,AllowMultiple=false)>]
202+
[<AttributeUsage (AttributeTargets.Class ||| AttributeTargets.Struct ||| AttributeTargets.ReturnValue ,AllowMultiple=false)>]
203203
[<Sealed>]
204204
type StructAttribute =
205205
inherit Attribute

‎tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/AttributeUsage/AttributeTargetsIsClass.fs‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,11 @@ type SemanticClassificationItem =
2424
type ILTableName(idx: int) =
2525
member __.Index = idx
2626
static member FromIndex n = ILTableName n
27+
28+
[<RequireQualifiedAccess>]
29+
[<CustomClass>]
30+
type Record = { Prop: string }
31+
32+
[<RequireQualifiedAccess>]
33+
[<Struct>]
34+
type StructRecord = { Prop: string }

‎tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/AttributeUsage/AttributeTargetsIsProperty.fs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,4 @@ type PropertyLevelAttribute() =
77

88
type U =
99
| [<PropertyLevel>] A
10-
| [<PropertyLevel>] B
10+
| [<PropertyLevel>] B

‎tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/AttributeUsage/AttributeUsage.fs‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -638,4 +638,25 @@ type InterruptibleLazy<'T> private (valueFactory: unit -> 'T) =
638638
(Error 842, Line 14, Col 3, Line 14, Col 15, "This attribute is not valid for use on this language element")
639639
(Error 842, Line 18, Col 3, Line 18, Col 14, "This attribute is not valid for use on this language element")
640640
(Error 842, Line 19, Col 3, Line 19, Col 15, "This attribute is not valid for use on this language element")
641+
]
642+
643+
// SOURCE= E_AttributeTargetIsClass02.fs # E_AttributeTargetIsClass02.fs
644+
[<Theory; Directory(__SOURCE_DIRECTORY__, Includes=[|"E_AttributeTargetIsClass02.fs"|])>]
645+
let ``E_AttributeTargetIsClass02_fs`` compilation =
646+
compilation
647+
|> verifyCompile
648+
|> shouldSucceed
649+
650+
// SOURCE=E_AttributeTargetIsClass02.fs # E_AttributeTargetIsClass02.fs
651+
[<Theory; Directory(__SOURCE_DIRECTORY__, Includes=[|"E_AttributeTargetIsClass02.fs"|])>]
652+
let ``E_AttributeTargetIsClass02_fs preview`` compilation =
653+
compilation
654+
|> withLangVersionPreview
655+
|> verifyCompile
656+
|> shouldFail
657+
|> withDiagnostics [
658+
(Error 842, Line 15, Col 3, Line 15, Col 18, "This attribute is not valid for use on this language element")
659+
(Error 842, Line 16, Col 3, Line 16, Col 15, "This attribute is not valid for use on this language element")
660+
(Error 842, Line 20, Col 3, Line 20, Col 14, "This attribute is not valid for use on this language element")
661+
(Error 842, Line 21, Col 3, Line 21, Col 18, "This attribute is not valid for use on this language element")
641662
]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
open System
2+
3+
[<AttributeUsage(AttributeTargets.Class)>]
4+
type ClassTargetAttribute() =
5+
inherit Attribute()
6+
7+
[<AttributeUsage(AttributeTargets.Interface)>]
8+
type InterfaceTargetAttribute() =
9+
inherit Attribute()
10+
11+
[<AttributeUsage(AttributeTargets.Struct)>]
12+
type StructTargetAttribute() =
13+
inherit Attribute()
14+
15+
[<InterfaceTarget>]
16+
[<StructTarget>]
17+
[<ClassTarget>]
18+
type Record = { Prop: string }
19+
20+
[<ClassTarget>]
21+
[<InterfaceTarget>]
22+
[<StructTarget>]
23+
[<Struct>]
24+
type StructRecord = { Prop: string }

‎tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/AttributeUsage/E_AttributeTargetIsProperty01.fs‎

Lines changed: 2 additions & 1 deletion

0 commit comments

Comments
 (0)