diff --git a/docs/release-notes/.FSharp.Compiler.Service/10.0.100.md b/docs/release-notes/.FSharp.Compiler.Service/10.0.100.md
index 067a9d56800..f5d0628ae75 100644
--- a/docs/release-notes/.FSharp.Compiler.Service/10.0.100.md
+++ b/docs/release-notes/.FSharp.Compiler.Service/10.0.100.md
@@ -1,3 +1,6 @@
+### Added
+* Add opt-in warning attribute not valid for union case with fields [PR #18532](https://github.com/dotnet/fsharp/pull/18532))
+
### Fixed
* Fix parsing errors using anonymous records and units of measures ([PR #18543](https://github.com/dotnet/fsharp/pull/18543))
diff --git a/src/Compiler/Checking/CheckDeclarations.fs b/src/Compiler/Checking/CheckDeclarations.fs
index 7d8a0e0764e..1877e892f4f 100644
--- a/src/Compiler/Checking/CheckDeclarations.fs
+++ b/src/Compiler/Checking/CheckDeclarations.fs
@@ -576,22 +576,33 @@ module TcRecdUnionAndEnumDeclarations =
let checkXmlDocs = cenv.diagnosticOptions.CheckXmlDocs
let xmlDoc = xmldoc.ToXmlDoc(checkXmlDocs, Some names)
- let attrs =
- (*
- The attributes of a union case decl get attached to the generated "static factory" method.
- Enforce union-cases AttributeTargets:
- - AttributeTargets.Method
- type SomeUnion =
- | Case1 of int // Compiles down to a static method
- - AttributeTargets.Property
- type SomeUnion =
- | Case1 // Compiles down to a static property
- *)
- if g.langVersion.SupportsFeature(LanguageFeature.EnforceAttributeTargets) then
- let target = if rfields.IsEmpty then AttributeTargets.Property else AttributeTargets.Method
- TcAttributes cenv env target synAttrs
- else
- TcAttributes cenv env AttributeTargets.UnionCaseDecl synAttrs
+ let attrs = TcAttributes cenv env AttributeTargets.UnionCaseDecl synAttrs
+ (*
+ The attributes of a union case decl get attached to the generated "static factory" method.
+ Enforce union-cases AttributeTargets:
+ - AttributeTargets.Method
+ type SomeUnion =
+ | Case1 of int // Compiles down to a static method
+ - AttributeTargets.Property
+ type SomeUnion =
+ | Case1 // Compiles down to a static property
+ *)
+ if g.langVersion.SupportsFeature(LanguageFeature.EnforceAttributeTargets) then
+ let attrTargets =
+ attrs
+ |> List.collect (fun attr ->
+ attr.TyconRef.Attribs
+ |> List.choose (fun attr ->
+ match attr with
+ | Attrib(unnamedArgs = [ AttribInt32Arg validOn ]) -> Some validOn
+ | _ -> None))
+
+ attrTargets
+ |> List.iter (fun target ->
+ // If the union case has fields, and the target is not AttributeTargets.Method || AttributeTargets.All. Then we raise a separate opt-in warning
+ let hasNotMethodTarget = (enum target &&& AttributeTargets.Method) = enum 0
+ if hasNotMethodTarget then
+ warning(Error(FSComp.SR.tcAttributeIsNotValidForUnionCaseWithFields(), id.idRange)))
Construct.NewUnionCase id rfields recordTy attrs xmlDoc vis
diff --git a/src/Compiler/Checking/Expressions/CheckExpressions.fs b/src/Compiler/Checking/Expressions/CheckExpressions.fs
index 1e0d3edc889..4ce2fb1700b 100644
--- a/src/Compiler/Checking/Expressions/CheckExpressions.fs
+++ b/src/Compiler/Checking/Expressions/CheckExpressions.fs
@@ -11288,6 +11288,75 @@ and TcNonRecursiveBinding declKind cenv env tpenv ty binding =
let explicitTyparInfo, tpenv = TcNonrecBindingTyparDecls cenv env tpenv binding
TcNormalizedBinding declKind cenv env tpenv ty None NoSafeInitInfo ([], explicitTyparInfo) binding
+and ResolveAttributeType (cenv: cenv) (env: TcEnv) (mAttr: range) (tycon: Ident list) =
+ let tpenv = emptyUnscopedTyparEnv
+ let ad = env.eAccessRights
+
+ let tyPath, tyId = List.frontAndBack tycon
+
+ let try1 n =
+ let tyid = mkSynId tyId.idRange n
+ let tycon = (tyPath @ [tyid])
+
+ match ResolveTypeLongIdent cenv.tcSink cenv.nameResolver ItemOccurrence.UseInAttribute OpenQualified env.eNameResEnv ad tycon TypeNameResolutionStaticArgsInfo.DefiniteEmpty PermitDirectReferenceToGeneratedType.No with
+ | Exception err -> raze err
+ | Result(tinstEnclosing, tcref, inst) -> success(TcTypeApp cenv NoNewTypars CheckCxs ItemOccurrence.UseInAttribute env tpenv mAttr tcref tinstEnclosing [] inst)
+
+ ForceRaise ((try1 (tyId.idText + "Attribute")) |> otherwise (fun () -> (try1 tyId.idText)))
+
+and CheckAttributeUsage (g: TcGlobals) (mAttr: range) (tcref: TyconRef) (attrTgt: AttributeTargets) (targetIndicator: Ident option) (attrEx: AttributeTargets) =
+ // REVIEW: take notice of inherited?
+ let validOn, _inherited =
+ let validOnDefault = 0x7fff
+ let inheritedDefault = true
+ if tcref.IsILTycon then
+ let tdef = tcref.ILTyconRawMetadata
+ let tref = g.attrib_AttributeUsageAttribute.TypeRef
+
+ match TryDecodeILAttribute tref tdef.CustomAttrs with
+ | Some ([ILAttribElem.Int32 validOn ], named) ->
+ let inherited =
+ match List.tryPick (function "Inherited", _, _, ILAttribElem.Bool res -> Some res | _ -> None) named with
+ | None -> inheritedDefault
+ | Some x -> x
+ (validOn, inherited)
+ | Some ([ILAttribElem.Int32 validOn; ILAttribElem.Bool _allowMultiple; ILAttribElem.Bool inherited ], _) ->
+ (validOn, inherited)
+ | _ ->
+ (validOnDefault, inheritedDefault)
+ else
+ match (TryFindFSharpAttribute g g.attrib_AttributeUsageAttribute tcref.Attribs) with
+ | Some(Attrib(unnamedArgs = [ AttribInt32Arg validOn ])) ->
+ validOn, inheritedDefault
+ | Some(Attrib(unnamedArgs = [ AttribInt32Arg validOn; AttribBoolArg(_allowMultiple); AttribBoolArg inherited])) ->
+ validOn, inherited
+ | Some _ ->
+ warning(Error(FSComp.SR.tcUnexpectedConditionInImportedAssembly(), mAttr))
+ validOnDefault, inheritedDefault
+ | _ ->
+ validOnDefault, inheritedDefault
+
+ // Determine valid attribute targets
+ let attributeTargets = enum validOn &&& attrTgt
+ let directedTargets =
+ match targetIndicator with
+ | LongFormAttrTarget attrTarget -> attrTarget
+ | UnrecognizedLongAttrTarget attrTarget ->
+ errorR(Error(FSComp.SR.tcUnrecognizedAttributeTarget(), attrTarget.idRange))
+ attributeTargets
+ | ShortFormAttributeTarget -> attributeTargets &&& ~~~ attrEx
+
+ let constrainedTargets = attributeTargets &&& directedTargets
+
+ // Check if attribute is valid for the target
+ if constrainedTargets = enum 0 then
+ if (directedTargets = AttributeTargets.Assembly || directedTargets = AttributeTargets.Module) then
+ errorR(Error(FSComp.SR.tcAttributeIsNotValidForLanguageElementUseDo(), mAttr))
+ else
+ warning(Error(FSComp.SR.tcAttributeIsNotValidForLanguageElement(), mAttr))
+
+ constrainedTargets
+
//-------------------------------------------------------------------------
// TcAttribute*
// *Ex means the function accepts attribute targets that must be explicit
@@ -11302,24 +11371,13 @@ and TcAttributeEx canFail (cenv: cenv) (env: TcEnv) attrTgt attrEx (synAttr: Syn
let targetIndicator = synAttr.Target
let isAppliedToGetterOrSetter = synAttr.AppliesToGetterAndSetter
let mAttr = synAttr.Range
- let typath, tyid = List.frontAndBack tycon
- let tpenv = emptyUnscopedTyparEnv
+ let _, tyId = List.frontAndBack tycon
let ad = env.eAccessRights
// if we're checking an attribute that was applied directly to a getter or a setter, then
// what we're really checking against is a method, not a property
let attrTgt = if isAppliedToGetterOrSetter then ((attrTgt ^^^ AttributeTargets.Property) ||| AttributeTargets.Method) else attrTgt
- let ty, tpenv =
- let try1 n =
- let tyid = mkSynId tyid.idRange n
- let tycon = (typath @ [tyid])
-
- match ResolveTypeLongIdent cenv.tcSink cenv.nameResolver ItemOccurrence.UseInAttribute OpenQualified env.eNameResEnv ad tycon TypeNameResolutionStaticArgsInfo.DefiniteEmpty PermitDirectReferenceToGeneratedType.No with
- | Exception err -> raze err
- | Result(tinstEnclosing, tcref, inst) -> success(TcTypeApp cenv NoNewTypars CheckCxs ItemOccurrence.UseInAttribute env tpenv mAttr tcref tinstEnclosing [] inst)
-
- ForceRaise ((try1 (tyid.idText + "Attribute")) |> otherwise (fun () -> (try1 tyid.idText)))
-
+ let ty, tpenv = ResolveAttributeType cenv env mAttr tycon
if not (IsTypeAccessible g cenv.amap mAttr ad ty) then errorR(Error(FSComp.SR.tcTypeIsInaccessible(), mAttr))
let tcref = tcrefOfAppTy g ty
@@ -11330,53 +11388,7 @@ and TcAttributeEx canFail (cenv: cenv) (env: TcEnv) attrTgt attrEx (synAttr: Syn
| Some d, Some defines when not (List.contains d defines) ->
[], false
| _ ->
- // REVIEW: take notice of inherited?
- let validOn, _inherited =
- let validOnDefault = 0x7fff
- let inheritedDefault = true
- if tcref.IsILTycon then
- let tdef = tcref.ILTyconRawMetadata
- let tref = g.attrib_AttributeUsageAttribute.TypeRef
-
- match TryDecodeILAttribute tref tdef.CustomAttrs with
- | Some ([ILAttribElem.Int32 validOn ], named) ->
- let inherited =
- match List.tryPick (function "Inherited", _, _, ILAttribElem.Bool res -> Some res | _ -> None) named with
- | None -> inheritedDefault
- | Some x -> x
- (validOn, inherited)
- | Some ([ILAttribElem.Int32 validOn; ILAttribElem.Bool _allowMultiple; ILAttribElem.Bool inherited ], _) ->
- (validOn, inherited)
- | _ ->
- (validOnDefault, inheritedDefault)
- else
- match (TryFindFSharpAttribute g g.attrib_AttributeUsageAttribute tcref.Attribs) with
- | Some(Attrib(_, _, [ AttribInt32Arg validOn ], _, _, _, _)) ->
- (validOn, inheritedDefault)
- | Some(Attrib(_, _, [ AttribInt32Arg validOn
- AttribBoolArg(_allowMultiple)
- AttribBoolArg inherited], _, _, _, _)) ->
- (validOn, inherited)
- | Some _ ->
- warning(Error(FSComp.SR.tcUnexpectedConditionInImportedAssembly(), mAttr))
- (validOnDefault, inheritedDefault)
- | _ ->
- (validOnDefault, inheritedDefault)
- let attributeTargets = enum validOn &&& attrTgt
- let directedTargets =
- match targetIndicator with
- | LongFormAttrTarget attrTarget -> attrTarget
- | UnrecognizedLongAttrTarget attrTarget ->
- errorR(Error(FSComp.SR.tcUnrecognizedAttributeTarget(), attrTarget.idRange))
- attributeTargets
- | ShortFormAttributeTarget -> attributeTargets &&& ~~~ attrEx
-
- let constrainedTargets = attributeTargets &&& directedTargets
- if constrainedTargets = enum 0 then
- if (directedTargets = AttributeTargets.Assembly || directedTargets = AttributeTargets.Module) then
- error(Error(FSComp.SR.tcAttributeIsNotValidForLanguageElementUseDo(), mAttr))
- else
- warning(Error(FSComp.SR.tcAttributeIsNotValidForLanguageElement(), mAttr))
+ let constrainedTargets = CheckAttributeUsage g mAttr tcref attrTgt targetIndicator attrEx
match ResolveObjectConstructor cenv.nameResolver env.DisplayEnv mAttr ad ty with
| Exception _ when canFail = TcCanFail.IgnoreAllErrors || canFail = TcCanFail.IgnoreMemberResoutionError -> [ ], true
@@ -11391,7 +11403,7 @@ and TcAttributeEx canFail (cenv: cenv) (env: TcEnv) attrTgt attrEx (synAttr: Syn
match item with
| Item.CtorGroup(methodName, minfos) ->
let meths = minfos |> List.map (fun minfo -> minfo, None)
- let afterResolution = ForNewConstructors cenv.tcSink env tyid.idRange methodName minfos
+ let afterResolution = ForNewConstructors cenv.tcSink env tyId.idRange methodName minfos
let (expr, attributeAssignedNamedItems, _), _ =
TcMethodApplication true cenv env tpenv None [] mAttr mAttr methodName None ad PossiblyMutates false meths afterResolution NormalValUse [arg] (MustEqual ty) None []
diff --git a/src/Compiler/Checking/Expressions/CheckExpressions.fsi b/src/Compiler/Checking/Expressions/CheckExpressions.fsi
index ed18b07a58a..5992a4afc95 100644
--- a/src/Compiler/Checking/Expressions/CheckExpressions.fsi
+++ b/src/Compiler/Checking/Expressions/CheckExpressions.fsi
@@ -955,6 +955,8 @@ module AttributeTargets =
val FieldDeclRestricted: AttributeTargets
/// The allowed attribute targets for an F# union case declaration
+ /// - AttributeTargets.Method: union case with fields
+ /// - AttributeTargets.Property: union case with no fields
val UnionCaseDecl: AttributeTargets
/// The allowed attribute targets for an F# type declaration
diff --git a/src/Compiler/Driver/CompilerDiagnostics.fs b/src/Compiler/Driver/CompilerDiagnostics.fs
index 5f96b1f58c8..c43b23c99c2 100644
--- a/src/Compiler/Driver/CompilerDiagnostics.fs
+++ b/src/Compiler/Driver/CompilerDiagnostics.fs
@@ -402,6 +402,7 @@ type PhasedDiagnostic with
| 3579 -> false // alwaysUseTypedStringInterpolation - off by default
| 3582 -> false // infoIfFunctionShadowsUnionCase - off by default
| 3570 -> false // tcAmbiguousDiscardDotLambda - off by default
+ | 3878 -> false // tcAttributeIsNotValidForUnionCaseWithFields - off by default
| _ ->
match x.Exception with
| DiagnosticEnabledWithLanguageFeature(_, _, _, enabled) -> enabled
diff --git a/src/Compiler/FSComp.txt b/src/Compiler/FSComp.txt
index f1c65d5771e..78dde5bd148 100644
--- a/src/Compiler/FSComp.txt
+++ b/src/Compiler/FSComp.txt
@@ -1806,4 +1806,5 @@ featureAllowLetOrUseBangTypeAnnotationWithoutParens,"Allow let! and use! type an
3874,lexWarnDirectiveMustBeFirst,"#nowarn/#warnon directives must appear as the first non-whitespace characters on a line"
3875,lexWarnDirectiveMustHaveArgs,"Warn directives must have warning number(s) as argument(s)"
3876,lexWarnDirectivesMustMatch,"There is another %s for this warning already in line %d."
-3877,lexLineDirectiveMappingIsNotUnique,"The file '%s' was also pointed to in a line directive in '%s'. Proper warn directive application may not be possible."
\ No newline at end of file
+3877,lexLineDirectiveMappingIsNotUnique,"The file '%s' was also pointed to in a line directive in '%s'. Proper warn directive application may not be possible."
+3878,tcAttributeIsNotValidForUnionCaseWithFields,"This attribute is not valid for use on union cases with fields."
\ No newline at end of file
diff --git a/src/Compiler/xlf/FSComp.txt.cs.xlf b/src/Compiler/xlf/FSComp.txt.cs.xlf
index 397f1269c6d..bcd1c3fb0bd 100644
--- a/src/Compiler/xlf/FSComp.txt.cs.xlf
+++ b/src/Compiler/xlf/FSComp.txt.cs.xlf
@@ -1397,6 +1397,11 @@
Pole {0} se v tomto anonymním typu záznamu vyskytuje vícekrát.
+
+ This attribute is not valid for use on union cases with fields.
+ This attribute is not valid for use on union cases with fields.
+
+ Attributes cannot be applied to type extensions.Atributy nejde použít pro rozšíření typů.
diff --git a/src/Compiler/xlf/FSComp.txt.de.xlf b/src/Compiler/xlf/FSComp.txt.de.xlf
index ca308ca9b13..0886b9ec60b 100644
--- a/src/Compiler/xlf/FSComp.txt.de.xlf
+++ b/src/Compiler/xlf/FSComp.txt.de.xlf
@@ -1397,6 +1397,11 @@
Das Feld "{0}" ist in diesem anonymen Datensatztyp mehrmals vorhanden.
+
+ This attribute is not valid for use on union cases with fields.
+ This attribute is not valid for use on union cases with fields.
+
+ Attributes cannot be applied to type extensions.Attribute können nicht auf Typerweiterungen angewendet werden.
diff --git a/src/Compiler/xlf/FSComp.txt.es.xlf b/src/Compiler/xlf/FSComp.txt.es.xlf
index 4b82afb40de..bdb43c5e1af 100644
--- a/src/Compiler/xlf/FSComp.txt.es.xlf
+++ b/src/Compiler/xlf/FSComp.txt.es.xlf
@@ -1397,6 +1397,11 @@
El campo "{0}" aparece varias veces en este tipo de registro anónimo.
+
+ This attribute is not valid for use on union cases with fields.
+ This attribute is not valid for use on union cases with fields.
+
+ Attributes cannot be applied to type extensions.Los atributos no se pueden aplicar a las extensiones de tipo.
diff --git a/src/Compiler/xlf/FSComp.txt.fr.xlf b/src/Compiler/xlf/FSComp.txt.fr.xlf
index 88b5c2c8f11..5344354b3ab 100644
--- a/src/Compiler/xlf/FSComp.txt.fr.xlf
+++ b/src/Compiler/xlf/FSComp.txt.fr.xlf
@@ -1397,6 +1397,11 @@
Le champ '{0}' apparaît plusieurs fois dans ce type d'enregistrement anonyme.
+
+ This attribute is not valid for use on union cases with fields.
+ This attribute is not valid for use on union cases with fields.
+
+ Attributes cannot be applied to type extensions.Impossible d'appliquer des attributs aux extensions de type.
diff --git a/src/Compiler/xlf/FSComp.txt.it.xlf b/src/Compiler/xlf/FSComp.txt.it.xlf
index dc03b73e98a..ec472ee00b9 100644
--- a/src/Compiler/xlf/FSComp.txt.it.xlf
+++ b/src/Compiler/xlf/FSComp.txt.it.xlf
@@ -1397,6 +1397,11 @@
Il campo '{0}' viene visualizzato più volte in questo tipo di record anonimo.
+
+ This attribute is not valid for use on union cases with fields.
+ This attribute is not valid for use on union cases with fields.
+
+ Attributes cannot be applied to type extensions.Gli attributi non possono essere applicati a estensioni di tipo.
diff --git a/src/Compiler/xlf/FSComp.txt.ja.xlf b/src/Compiler/xlf/FSComp.txt.ja.xlf
index 99644e44b11..8db04ab1625 100644
--- a/src/Compiler/xlf/FSComp.txt.ja.xlf
+++ b/src/Compiler/xlf/FSComp.txt.ja.xlf
@@ -1397,6 +1397,11 @@
この匿名レコードの種類に、フィールド '{0}' が複数回出現します。
+
+ This attribute is not valid for use on union cases with fields.
+ This attribute is not valid for use on union cases with fields.
+
+ Attributes cannot be applied to type extensions.属性を型拡張に適用することはできません。
diff --git a/src/Compiler/xlf/FSComp.txt.ko.xlf b/src/Compiler/xlf/FSComp.txt.ko.xlf
index cd439a93768..a17460ee156 100644
--- a/src/Compiler/xlf/FSComp.txt.ko.xlf
+++ b/src/Compiler/xlf/FSComp.txt.ko.xlf
@@ -1397,6 +1397,11 @@
'{0}' 필드가 이 익명 레코드 형식에서 여러 번 나타납니다.
+
+ This attribute is not valid for use on union cases with fields.
+ This attribute is not valid for use on union cases with fields.
+
+ Attributes cannot be applied to type extensions.형식 확장에 특성을 적용할 수 없습니다.
diff --git a/src/Compiler/xlf/FSComp.txt.pl.xlf b/src/Compiler/xlf/FSComp.txt.pl.xlf
index f50063b24f1..94416cfb231 100644
--- a/src/Compiler/xlf/FSComp.txt.pl.xlf
+++ b/src/Compiler/xlf/FSComp.txt.pl.xlf
@@ -1397,6 +1397,11 @@
Pole „{0}” występuje wielokrotnie w tym anonimowym typie rekordu.
+
+ This attribute is not valid for use on union cases with fields.
+ This attribute is not valid for use on union cases with fields.
+
+ Attributes cannot be applied to type extensions.Atrybutów nie można stosować do rozszerzeń typu.
diff --git a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf
index 1e60a4d33b3..99709def4e0 100644
--- a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf
+++ b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf
@@ -1397,6 +1397,11 @@
O campo '{0}' aparece várias vezes nesse tipo de registro anônimo.
+
+ This attribute is not valid for use on union cases with fields.
+ This attribute is not valid for use on union cases with fields.
+
+ Attributes cannot be applied to type extensions.Os atributos não podem ser aplicados às extensões de tipo.
diff --git a/src/Compiler/xlf/FSComp.txt.ru.xlf b/src/Compiler/xlf/FSComp.txt.ru.xlf
index b1592085f5c..e1e97fdf67e 100644
--- a/src/Compiler/xlf/FSComp.txt.ru.xlf
+++ b/src/Compiler/xlf/FSComp.txt.ru.xlf
@@ -1397,6 +1397,11 @@
Поле "{0}" появляется несколько раз в этом типе анонимной записи.
+
+ This attribute is not valid for use on union cases with fields.
+ This attribute is not valid for use on union cases with fields.
+
+ Attributes cannot be applied to type extensions.Атрибуты не могут быть применены к расширениям типа.
diff --git a/src/Compiler/xlf/FSComp.txt.tr.xlf b/src/Compiler/xlf/FSComp.txt.tr.xlf
index 3ea96d4b85e..cff0f89ef17 100644
--- a/src/Compiler/xlf/FSComp.txt.tr.xlf
+++ b/src/Compiler/xlf/FSComp.txt.tr.xlf
@@ -1397,6 +1397,11 @@
'{0}' alanı bu anonim kayıt türünde birden fazla yerde görünüyor.
+
+ This attribute is not valid for use on union cases with fields.
+ This attribute is not valid for use on union cases with fields.
+
+ Attributes cannot be applied to type extensions.Öznitelikler tür uzantılarına uygulanamaz.
diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf
index cdc91d51daa..5ce3ac9c822 100644
--- a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf
+++ b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf
@@ -1397,6 +1397,11 @@
字段“{0}”在此匿名记录类型中多次出现。
+
+ This attribute is not valid for use on union cases with fields.
+ This attribute is not valid for use on union cases with fields.
+
+ Attributes cannot be applied to type extensions.属性不可应用于类型扩展。
diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf
index 99dd36c34bc..ae4eeed6b13 100644
--- a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf
+++ b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf
@@ -1397,6 +1397,11 @@
欄位 '{0}' 在這個匿名記錄類型中出現多次。
+
+ This attribute is not valid for use on union cases with fields.
+ This attribute is not valid for use on union cases with fields.
+
+ Attributes cannot be applied to type extensions.屬性無法套用到類型延伸模組。
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 f027745b73e..b0fa891d2b7 100644
--- a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/AttributeUsage/AttributeUsage.fs
+++ b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/AttributeUsage/AttributeUsage.fs
@@ -64,6 +64,7 @@ module CustomAttributes_AttributeUsage =
let ``AttributeTargetsIsMethod01_fs 8.0`` compilation =
compilation
|> withLangVersion80
+ |> withWarnOn 3878
|> verifyCompileAndRun
|> shouldSucceed
@@ -74,6 +75,15 @@ module CustomAttributes_AttributeUsage =
|> verifyCompileAndRun
|> shouldSucceed
+ // SOURCE=AttributeTargetsIsMethod01.fs # AttributeTargetsIsMethod01.fs
+ []
+ let ``Preview: AttributeTargetsIsMethod01_fs opt-in warning`` compilation =
+ compilation
+ |> withLangVersionPreview
+ |> withWarnOn 3878
+ |> verifyCompileAndRun
+ |> shouldSucceed
+
// SOURCE=AttributeTargetsIsProperty.fs # AttributeTargetsIsProperty.fs
[]
let ``AttributeTargetsIsProperty_fs 8.0`` compilation =
@@ -483,6 +493,18 @@ module CustomAttributes_AttributeUsage =
|> withDiagnostics [
(Warning 842, Line 14, Col 5, Line 14, Col 15, "This attribute is not valid for use on this language element")
]
+
+ // SOURCE=E_AttributeTargetIsField03.fs # E_AttributeTargetIsField03.fs
+ []
+ let ``E_AttributeTargetIsField03_fs opt-in warning`` compilation =
+ compilation
+ |> withLangVersion90
+ |> withWarnOn 3878
+ |> verifyCompile
+ |> shouldFail
+ |> withDiagnostics [
+ (Warning 842, Line 14, Col 5, Line 14, Col 15, "This attribute is not valid for use on this language element")
+ ]
// SOURCE=E_AttributeTargetIsField03.fs # E_AttributeTargetIsField03.fs
[]
@@ -493,7 +515,20 @@ module CustomAttributes_AttributeUsage =
|> shouldFail
|> withDiagnostics [
(Warning 842, Line 14, Col 5, Line 14, Col 15, "This attribute is not valid for use on this language element")
- (Warning 842, Line 15, Col 5, Line 15, Col 25, "This attribute is not valid for use on this language element")
+ ]
+
+ // SOURCE=E_AttributeTargetIsField03.fs # E_AttributeTargetIsField03.fs
+ []
+ let ``Preview: E_AttributeTargetIsField03_fs opt-in warning`` compilation =
+ compilation
+ |> withLangVersionPreview
+ |> withWarnOn 3878
+ |> verifyCompile
+ |> shouldFail
+ |> withDiagnostics [
+ (Warning 842, Line 14, Col 5, Line 14, Col 15, "This attribute is not valid for use on this language element");
+ (Warning 3878, Line 14, Col 18, Line 14, Col 23, "This attribute is not valid for use on union cases with fields.");
+ (Warning 3878, Line 15, Col 28, Line 15, Col 33, "This attribute is not valid for use on union cases with fields.")
]
// SOURCE=E_AttributeTargetIsProperty01.fs # E_AttributeTargetIsField03.fs
@@ -510,11 +545,7 @@ module CustomAttributes_AttributeUsage =
compilation
|> withLangVersionPreview
|> verifyCompile
- |> shouldFail
- |> withDiagnostics [
- (Warning 842, Line 14, Col 5, Line 14, Col 18, "This attribute is not valid for use on this language element")
- (Warning 842, Line 15, Col 5, Line 15, Col 25, "This attribute is not valid for use on this language element")
- ]
+ |> shouldSucceed
// SOURCE=E_AttributeTargetIsCtor01.fs # E_AttributeTargetIsCtor01.fs
[]