diff --git a/docs/release-notes/.FSharp.Compiler.Service/8.0.300.md b/docs/release-notes/.FSharp.Compiler.Service/8.0.300.md index 56f71544b5..83a1b23aa9 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/8.0.300.md +++ b/docs/release-notes/.FSharp.Compiler.Service/8.0.300.md @@ -14,6 +14,7 @@ * Allow calling method with both Optional and ParamArray. ([#PR 16688](https://github.com/dotnet/fsharp/pull/16688), [suggestions #1120](https://github.com/fsharp/fslang-suggestions/issues/1120)) * Fix release inline optimization, which leads to MethodAccessException if used with `assembly:InternalsVisibleTo`` attribute. ([Issue #16105](https://github.com/dotnet/fsharp/issues/16105), ([PR #16737](https://github.com/dotnet/fsharp/pull/16737)) * Enforce AttributeTargets on let values and functions. ([PR #16692](https://github.com/dotnet/fsharp/pull/16692)) +* Enforce AttributeTargets on union case declarations. ([PR #16764](https://github.com/dotnet/fsharp/pull/16764)) ### Added diff --git a/docs/release-notes/.Language/preview.md b/docs/release-notes/.Language/preview.md index f39dd17256..a4dd48f213 100644 --- a/docs/release-notes/.Language/preview.md +++ b/docs/release-notes/.Language/preview.md @@ -9,6 +9,7 @@ * Allow extension methods without type attribute work for types from imported assemblies. ([PR #16368](https://github.com/dotnet/fsharp/pull/16368)) * Enforce AttributeTargets on let values and functions. ([PR #16692](https://github.com/dotnet/fsharp/pull/16692)) +* Enforce AttributeTargets on union case declarations. ([PR #16764](https://github.com/dotnet/fsharp/pull/16764)) ### Changed diff --git a/src/Compiler/Checking/CheckDeclarations.fs b/src/Compiler/Checking/CheckDeclarations.fs index 5bb8d4081a..c82a5edf6f 100644 --- a/src/Compiler/Checking/CheckDeclarations.fs +++ b/src/Compiler/Checking/CheckDeclarations.fs @@ -511,7 +511,14 @@ module TcRecdUnionAndEnumDeclarations = let TcUnionCaseDecl (cenv: cenv) env parent thisTy thisTyInst tpenv hasRQAAttribute (SynUnionCase(Attributes synAttrs, SynIdent(id, _), args, xmldoc, vis, m, _)) = let g = cenv.g - let attrs = TcAttributes cenv env AttributeTargets.UnionCaseDecl synAttrs // the attributes of a union case decl get attached to the generated "static factory" method + let attrs = + // The attributes of a union case decl get attached to the generated "static factory" method + // Enforce that the union-cases can only be targeted by attributes with AttributeTargets.Method + if g.langVersion.SupportsFeature(LanguageFeature.EnforceAttributeTargetsUnionCaseDeclarations) then + TcAttributes cenv env AttributeTargets.Method synAttrs + else + TcAttributes cenv env AttributeTargets.UnionCaseDecl synAttrs + let vis, _ = ComputeAccessAndCompPath g env None m vis None parent let vis = CombineReprAccess parent vis diff --git a/src/Compiler/Checking/CheckExpressions.fs b/src/Compiler/Checking/CheckExpressions.fs index 11ecd5216f..f7e048223b 100644 --- a/src/Compiler/Checking/CheckExpressions.fs +++ b/src/Compiler/Checking/CheckExpressions.fs @@ -10875,17 +10875,31 @@ and TcNormalizedBinding declKind (cenv: cenv) env tpenv overallTy safeThisValOpt errorR(Error(FSComp.SR.tcLiteralCannotHaveGenericParameters(), mBinding)) if g.langVersion.SupportsFeature(LanguageFeature.EnforceAttributeTargetsOnFunctions) && memberFlagsOpt.IsNone && not attrs.IsEmpty then - let rhsIsFunction = isFunTy g overallPatTy - let lhsIsFunction = isFunTy g overallExprTy - let attrTgt = - match rhsIsFunction, lhsIsFunction with - | false, false when declaredTypars.IsEmpty -> AttributeTargets.Field ||| AttributeTargets.Property ||| AttributeTargets.ReturnValue - | _, _ -> AttributeTargets.Method ||| AttributeTargets.ReturnValue - - TcAttributesWithPossibleTargets false cenv env attrTgt attrs |> ignore + TcAttributeTargetsOnLetBindings cenv env attrs overallPatTy overallExprTy (not declaredTypars.IsEmpty) CheckedBindingInfo(inlineFlag, valAttribs, xmlDoc, tcPatPhase2, explicitTyparInfo, nameToPrelimValSchemeMap, rhsExprChecked, argAndRetAttribs, overallPatTy, mBinding, debugPoint, isCompGen, literalValue, isFixed), tpenv +// Note: +// - Let bound values can only have attributes that uses AttributeTargets.Field ||| AttributeTargets.Property ||| AttributeTargets.ReturnValue +// - Let function bindings can only have attributes that uses AttributeTargets.Method ||| AttributeTargets.ReturnValue +and TcAttributeTargetsOnLetBindings (cenv: cenv) env attrs overallPatTy overallExprTy areTyparsDeclared = + let attrTgt = + if + // It's a type function: + // let x<'a> = … + areTyparsDeclared + // It's a regular function-valued binding: + // let f x = … + // let f = fun x -> … + || isFunTy cenv.g overallPatTy + || isFunTy cenv.g overallExprTy + then + AttributeTargets.ReturnValue ||| AttributeTargets.Method + else + AttributeTargets.ReturnValue ||| AttributeTargets.Field ||| AttributeTargets.Property + + TcAttributes cenv env attrTgt attrs |> ignore + and TcLiteral (cenv: cenv) overallTy env tpenv (attrs, synLiteralValExpr) = let g = cenv.g diff --git a/src/Compiler/FSComp.txt b/src/Compiler/FSComp.txt index cdd483858e..52a5a18482 100644 --- a/src/Compiler/FSComp.txt +++ b/src/Compiler/FSComp.txt @@ -1595,6 +1595,7 @@ featureChkTailCallAttrOnNonRec,"Raises warnings if the 'TailCall' attribute is u featureUnionIsPropertiesVisible,"Union case test properties" featureBooleanReturningAndReturnTypeDirectedPartialActivePattern,"Boolean-returning and return-type-directed partial active patterns" featureEnforceAttributeTargetsOnFunctions,"Enforce AttributeTargets on functions" +featureEnforceAttributeTargetsUnionCaseDeclarations,"Enforce AttributeTargets on union case declarations" featureLowerInterpolatedStringToConcat,"Optimizes interpolated strings in certain cases, by lowering to concatenation" 3354,tcNotAFunctionButIndexerNamedIndexingNotYetEnabled,"This value supports indexing, e.g. '%s.[index]'. The syntax '%s[index]' requires /langversion:preview. See https://aka.ms/fsharp-index-notation." 3354,tcNotAFunctionButIndexerIndexingNotYetEnabled,"This expression supports indexing, e.g. 'expr.[index]'. The syntax 'expr[index]' requires /langversion:preview. See https://aka.ms/fsharp-index-notation." diff --git a/src/Compiler/Facilities/LanguageFeatures.fs b/src/Compiler/Facilities/LanguageFeatures.fs index 6e2d91bc6c..dd7133224e 100644 --- a/src/Compiler/Facilities/LanguageFeatures.fs +++ b/src/Compiler/Facilities/LanguageFeatures.fs @@ -86,6 +86,7 @@ type LanguageFeature = | WarningWhenTailCallAttrOnNonRec | BooleanReturningAndReturnTypeDirectedPartialActivePattern | EnforceAttributeTargetsOnFunctions + | EnforceAttributeTargetsUnionCaseDeclarations | LowerInterpolatedStringToConcat /// LanguageVersion management @@ -200,6 +201,7 @@ type LanguageVersion(versionText) = LanguageFeature.UnionIsPropertiesVisible, previewVersion LanguageFeature.BooleanReturningAndReturnTypeDirectedPartialActivePattern, previewVersion LanguageFeature.EnforceAttributeTargetsOnFunctions, previewVersion + LanguageFeature.EnforceAttributeTargetsUnionCaseDeclarations, previewVersion LanguageFeature.LowerInterpolatedStringToConcat, previewVersion ] @@ -345,6 +347,7 @@ type LanguageVersion(versionText) = | LanguageFeature.BooleanReturningAndReturnTypeDirectedPartialActivePattern -> FSComp.SR.featureBooleanReturningAndReturnTypeDirectedPartialActivePattern () | LanguageFeature.EnforceAttributeTargetsOnFunctions -> FSComp.SR.featureEnforceAttributeTargetsOnFunctions () + | LanguageFeature.EnforceAttributeTargetsUnionCaseDeclarations -> FSComp.SR.featureEnforceAttributeTargetsUnionCaseDeclarations () | LanguageFeature.LowerInterpolatedStringToConcat -> FSComp.SR.featureLowerInterpolatedStringToConcat () /// Get a version string associated with the given feature. diff --git a/src/Compiler/Facilities/LanguageFeatures.fsi b/src/Compiler/Facilities/LanguageFeatures.fsi index 4888479d86..5be15a8828 100644 --- a/src/Compiler/Facilities/LanguageFeatures.fsi +++ b/src/Compiler/Facilities/LanguageFeatures.fsi @@ -77,6 +77,7 @@ type LanguageFeature = | WarningWhenTailCallAttrOnNonRec | BooleanReturningAndReturnTypeDirectedPartialActivePattern | EnforceAttributeTargetsOnFunctions + | EnforceAttributeTargetsUnionCaseDeclarations | LowerInterpolatedStringToConcat /// LanguageVersion management diff --git a/src/Compiler/xlf/FSComp.txt.cs.xlf b/src/Compiler/xlf/FSComp.txt.cs.xlf index 875c2a1e4b..c46e652979 100644 --- a/src/Compiler/xlf/FSComp.txt.cs.xlf +++ b/src/Compiler/xlf/FSComp.txt.cs.xlf @@ -297,6 +297,11 @@ Enforce AttributeTargets on functions + + Enforce AttributeTargets on union case declarations + Enforce AttributeTargets on union case declarations + + Raises errors for non-virtual members overrides Vyvolá chyby pro přepsání jiných než virtuálních členů diff --git a/src/Compiler/xlf/FSComp.txt.de.xlf b/src/Compiler/xlf/FSComp.txt.de.xlf index 7f878306f1..56f7493d1d 100644 --- a/src/Compiler/xlf/FSComp.txt.de.xlf +++ b/src/Compiler/xlf/FSComp.txt.de.xlf @@ -297,6 +297,11 @@ Enforce AttributeTargets on functions + + Enforce AttributeTargets on union case declarations + Enforce AttributeTargets on union case declarations + + Raises errors for non-virtual members overrides Löst Fehler für Außerkraftsetzungen nicht virtueller Member aus. diff --git a/src/Compiler/xlf/FSComp.txt.es.xlf b/src/Compiler/xlf/FSComp.txt.es.xlf index 23f6709525..a35a6bce59 100644 --- a/src/Compiler/xlf/FSComp.txt.es.xlf +++ b/src/Compiler/xlf/FSComp.txt.es.xlf @@ -297,6 +297,11 @@ Enforce AttributeTargets on functions + + Enforce AttributeTargets on union case declarations + Enforce AttributeTargets on union case declarations + + Raises errors for non-virtual members overrides Genera errores para invalidaciones de miembros no virtuales diff --git a/src/Compiler/xlf/FSComp.txt.fr.xlf b/src/Compiler/xlf/FSComp.txt.fr.xlf index 4777bed578..aeeb53ac93 100644 --- a/src/Compiler/xlf/FSComp.txt.fr.xlf +++ b/src/Compiler/xlf/FSComp.txt.fr.xlf @@ -297,6 +297,11 @@ Enforce AttributeTargets on functions + + Enforce AttributeTargets on union case declarations + Enforce AttributeTargets on union case declarations + + Raises errors for non-virtual members overrides Déclenche des erreurs pour les remplacements de membres non virtuels diff --git a/src/Compiler/xlf/FSComp.txt.it.xlf b/src/Compiler/xlf/FSComp.txt.it.xlf index 683a5a6cec..390160ee95 100644 --- a/src/Compiler/xlf/FSComp.txt.it.xlf +++ b/src/Compiler/xlf/FSComp.txt.it.xlf @@ -297,6 +297,11 @@ Enforce AttributeTargets on functions + + Enforce AttributeTargets on union case declarations + Enforce AttributeTargets on union case declarations + + Raises errors for non-virtual members overrides Genera errori per gli override dei membri non virtuali diff --git a/src/Compiler/xlf/FSComp.txt.ja.xlf b/src/Compiler/xlf/FSComp.txt.ja.xlf index 7618f5faa1..e57dac6f31 100644 --- a/src/Compiler/xlf/FSComp.txt.ja.xlf +++ b/src/Compiler/xlf/FSComp.txt.ja.xlf @@ -297,6 +297,11 @@ Enforce AttributeTargets on functions + + Enforce AttributeTargets on union case declarations + Enforce AttributeTargets on union case declarations + + Raises errors for non-virtual members overrides 仮想メンバー以外のオーバーライドに対してエラーを発生させます diff --git a/src/Compiler/xlf/FSComp.txt.ko.xlf b/src/Compiler/xlf/FSComp.txt.ko.xlf index 8b2ddd074b..2d6a4e5e22 100644 --- a/src/Compiler/xlf/FSComp.txt.ko.xlf +++ b/src/Compiler/xlf/FSComp.txt.ko.xlf @@ -297,6 +297,11 @@ Enforce AttributeTargets on functions + + Enforce AttributeTargets on union case declarations + Enforce AttributeTargets on union case declarations + + Raises errors for non-virtual members overrides 비가상 멤버 재정의에 대한 오류 발생 diff --git a/src/Compiler/xlf/FSComp.txt.pl.xlf b/src/Compiler/xlf/FSComp.txt.pl.xlf index 43f58a77a9..db56cd3ba4 100644 --- a/src/Compiler/xlf/FSComp.txt.pl.xlf +++ b/src/Compiler/xlf/FSComp.txt.pl.xlf @@ -297,6 +297,11 @@ Enforce AttributeTargets on functions + + Enforce AttributeTargets on union case declarations + Enforce AttributeTargets on union case declarations + + Raises errors for non-virtual members overrides Zgłasza błędy w przypadku przesłonięć elementów innych niż wirtualne diff --git a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf index f3e8b58378..7566fb49ae 100644 --- a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf +++ b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf @@ -297,6 +297,11 @@ Enforce AttributeTargets on functions + + Enforce AttributeTargets on union case declarations + Enforce AttributeTargets on union case declarations + + Raises errors for non-virtual members overrides Gera erros para substituições de membros não virtuais diff --git a/src/Compiler/xlf/FSComp.txt.ru.xlf b/src/Compiler/xlf/FSComp.txt.ru.xlf index d6f3358a69..90c39f565e 100644 --- a/src/Compiler/xlf/FSComp.txt.ru.xlf +++ b/src/Compiler/xlf/FSComp.txt.ru.xlf @@ -297,6 +297,11 @@ Enforce AttributeTargets on functions + + Enforce AttributeTargets on union case declarations + Enforce AttributeTargets on union case declarations + + Raises errors for non-virtual members overrides Вызывает ошибки при переопределениях невиртуальных элементов diff --git a/src/Compiler/xlf/FSComp.txt.tr.xlf b/src/Compiler/xlf/FSComp.txt.tr.xlf index 2f313d8c49..496bc35ef9 100644 --- a/src/Compiler/xlf/FSComp.txt.tr.xlf +++ b/src/Compiler/xlf/FSComp.txt.tr.xlf @@ -297,6 +297,11 @@ Enforce AttributeTargets on functions + + Enforce AttributeTargets on union case declarations + Enforce AttributeTargets on union case declarations + + Raises errors for non-virtual members overrides Sanal olmayan üyelerde geçersiz kılmalar için hatalar oluştur diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf index d115f81d27..94bd2ea062 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf @@ -297,6 +297,11 @@ Enforce AttributeTargets on functions + + Enforce AttributeTargets on union case declarations + Enforce AttributeTargets on union case declarations + + Raises errors for non-virtual members overrides 引发非虚拟成员替代的错误 diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf index 2dadd07ff7..9334199ba0 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf @@ -297,6 +297,11 @@ Enforce AttributeTargets on functions + + Enforce AttributeTargets on union case declarations + Enforce AttributeTargets on union case declarations + + Raises errors for non-virtual members overrides 引發非虛擬成員覆寫的錯誤 diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/AttributeUsage/AttributeTargetsIsMethod01.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/AttributeUsage/AttributeTargetsIsMethod01.fs index b8de3b3349..4018ae74be 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/AttributeUsage/AttributeTargetsIsMethod01.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/AttributeUsage/AttributeTargetsIsMethod01.fs @@ -48,3 +48,10 @@ let test1 = |> (=) 6 if not test1 then failwith "Failed: 1" + +[] +type MethodLevelAttribute() = + inherit Attribute() + +type SomeUnion = +| [] Case1 of int 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 b9d20fe0ca..5d930ea1e1 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,14 @@ module CustomAttributes_AttributeUsage = |> verifyCompileAndRun |> shouldSucceed + // SOURCE=AttributeTargetsIsMethod01.fs # AttributeTargetsIsMethod01.fs + [] + let ``AttributeTargetsIsMethod01_fs preview`` compilation = + compilation + |> withLangVersionPreview + |> verifyCompileAndRun + |> shouldSucceed + // SOURCE=ConditionalAttribute.fs # ConditionalAttribute.fs [] let ``ConditionalAttribute_fs`` compilation = @@ -352,5 +360,45 @@ module CustomAttributes_AttributeUsage = |> withDiagnostics [ (Warning 2003, Line 5, Col 59, Line 5, Col 68, "The attribute System.Reflection.AssemblyFileVersionAttribute specified version '9.8.*.6', but this value is invalid and has been ignored") ] - - + + // SOURCE=E_AttributeTargetIsField03.fs # E_AttributeTargetIsField03.fs + [] + let ``E_AttributeTargetIsField03_fs`` compilation = + compilation + |> verifyCompile + |> shouldFail + |> withDiagnostics [ + (Error 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 preview`` compilation = + compilation + |> withLangVersionPreview + |> verifyCompile + |> shouldFail + |> withDiagnostics [ + (Error 842, Line 14, Col 5, Line 14, Col 15, "This attribute is not valid for use on this language element") + (Error 842, Line 15, Col 5, Line 15, Col 25, "This attribute is not valid for use on this language element") + ] + + + // SOURCE=E_AttributeTargetIsProperty01.fs # E_AttributeTargetIsField03.fs + [] + let ``E_AttributeTargetIsProperty01_fs`` compilation = + compilation + |> verifyCompile + |> shouldSucceed + + // SOURCE=E_AttributeTargetIsProperty01.fs # E_AttributeTargetIsField03.fs + [] + let ``E_AttributeTargetIsProperty01_fs preview`` compilation = + compilation + |> withLangVersionPreview + |> verifyCompile + |> shouldFail + |> withDiagnostics [ + (Error 842, Line 14, Col 5, Line 14, Col 18, "This attribute is not valid for use on this language element") + (Error 842, Line 15, Col 5, Line 15, Col 25, "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_AttributeTargetIsField03.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/AttributeUsage/E_AttributeTargetIsField03.fs new file mode 100644 index 0000000000..cc5fb20b49 --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/AttributeUsage/E_AttributeTargetIsField03.fs @@ -0,0 +1,16 @@ +// This tests that AttributeTargets.Field is not allowed in union-case declaration + +open System + +[] +type FieldLevelAttribute() = + inherit Attribute() + +[] +type PropertyOrFieldLevelAttribute() = + inherit Attribute() + +type SomeUnion = +| [] Case1 of int // Should fail +| [] Case2 of int // Should fail + diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/AttributeUsage/E_AttributeTargetIsProperty01.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/AttributeUsage/E_AttributeTargetIsProperty01.fs new file mode 100644 index 0000000000..4627c3680d --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/AttributeUsage/E_AttributeTargetIsProperty01.fs @@ -0,0 +1,15 @@ +// This tests that AttributeTargets.Property is not allowed in union-case declaration + +open System + +[] +type PropertyLevelAttribute() = + inherit Attribute() + +[] +type PropertyOrFieldLevelAttribute() = + inherit Attribute() + +type SomeUnion = +| [] Case1 of int // Should fail +| [] Case2 of int // Should fail \ No newline at end of file