From 8e1146815b2b5dfda251bcb7a2c640c5b01bad2f Mon Sep 17 00:00:00 2001 From: Edgar Gonzalez Date: Fri, 23 Aug 2024 12:19:50 +0100 Subject: [PATCH] Account for `AllowNullLiteralAttribute` when checking attribute targets (#17583) --- src/Compiler/Checking/CheckDeclarations.fs | 10 ++-- .../AttributeUsage/AllowNullLiteral01.fs | 3 ++ .../AttributeUsage/AttributeUsage.fs | 54 ++++++++++++++++++- .../AttributeUsage/E_AllowNullLiteral.fs | 48 +++++++++++++++++ tests/fsharp/typecheck/sigs/neg16.bsl | 6 --- 5 files changed, 111 insertions(+), 10 deletions(-) create mode 100644 tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/AttributeUsage/AllowNullLiteral01.fs create mode 100644 tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/AttributeUsage/E_AllowNullLiteral.fs diff --git a/src/Compiler/Checking/CheckDeclarations.fs b/src/Compiler/Checking/CheckDeclarations.fs index 502bbf8d1e..0f67c71ee3 100644 --- a/src/Compiler/Checking/CheckDeclarations.fs +++ b/src/Compiler/Checking/CheckDeclarations.fs @@ -2855,9 +2855,13 @@ module EstablishTypeDefinitionCores = let hasMeasureAttr = HasFSharpAttribute g g.attrib_MeasureAttribute attrs let hasStructAttr = HasFSharpAttribute g g.attrib_StructAttribute attrs let hasCLIMutable = HasFSharpAttribute g g.attrib_CLIMutableAttribute attrs - // CLIMutableAttribute has a special treatment(specific error FS3132) in the case of records(Only record types may have this attribute.) - // So we want to keep these special treatment for records and avoid having two errors for the same attribute. - let reportAttributeTargetsErrors = g.langVersion.SupportsFeature(LanguageFeature.EnforceAttributeTargets) && not hasCLIMutable + let hasAllowNullLiteralAttr = HasFSharpAttribute g g.attrib_AllowNullLiteralAttribute attrs + + // We want to keep these special attributes treatment and avoid having two errors for the same attribute. + let reportAttributeTargetsErrors = + g.langVersion.SupportsFeature(LanguageFeature.EnforceAttributeTargets) + && not hasCLIMutable // CLIMutableAttribute has a special treatment(specific error FS3132) + && not hasAllowNullLiteralAttr // AllowNullLiteralAttribute has a special treatment(specific errors FS0934, FS093) let noCLIMutableAttributeCheck() = if hasCLIMutable then errorR (Error(FSComp.SR.tcThisTypeMayNotHaveACLIMutableAttribute(), m)) diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/AttributeUsage/AllowNullLiteral01.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/AttributeUsage/AllowNullLiteral01.fs new file mode 100644 index 0000000000..a51ad77a44 --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/AttributeUsage/AllowNullLiteral01.fs @@ -0,0 +1,3 @@ +[] +type D() = + member x.P = 1 \ 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 68df8538d0..ce6efe8033 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/AttributeUsage/AttributeUsage.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/AttributeUsage/AttributeUsage.fs @@ -738,4 +738,56 @@ type InterruptibleLazy<'T> private (valueFactory: unit -> 'T) = (Error 3132, Line 19, Col 8, Line 19, Col 19, "This type definition may not have the 'CLIMutable' attribute. Only record types may have this attribute.") (Error 3132, Line 22, Col 8, Line 22, Col 17, "This type definition may not have the 'CLIMutable' attribute. Only record types may have this attribute.") (Error 3132, Line 25, Col 8, Line 25, Col 18, "This type definition may not have the 'CLIMutable' attribute. Only record types may have this attribute.") - ] \ No newline at end of file + ] + + // SOURCE= E_AllowNullLiteral.fs # E_AllowNullLiteral.fs + [] + let ``E_AllowNullLiteral 8.0`` compilation = + compilation + |> withLangVersion80 + |> verifyCompile + |> shouldFail + |> withDiagnostics [ + (Error 935, Line 15, Col 10, Line 15, Col 11, "Types with the 'AllowNullLiteral' attribute may only inherit from or implement types which also allow the use of the null literal") + (Error 934, Line 27, Col 10, Line 27, Col 11, "Records, union, abbreviations and struct types cannot have the 'AllowNullLiteral' attribute") + (Error 934, Line 30, Col 10, Line 30, Col 11, "Records, union, abbreviations and struct types cannot have the 'AllowNullLiteral' attribute") + (Error 934, Line 33, Col 10, Line 33, Col 11, "Records, union, abbreviations and struct types cannot have the 'AllowNullLiteral' attribute") + (Error 934, Line 36, Col 10, Line 36, Col 11, "Records, union, abbreviations and struct types cannot have the 'AllowNullLiteral' attribute") + (Error 934, Line 39, Col 10, Line 39, Col 13, "Records, union, abbreviations and struct types cannot have the 'AllowNullLiteral' attribute") + (Error 842, Line 41, Col 7, Line 41, Col 23, "This attribute is not valid for use on this language element") + (Error 842, Line 44, Col 7, Line 44, Col 23, "This attribute is not valid for use on this language element") + ] + + // SOURCE=E_AllowNullLiteral.fs # E_AllowNullLiteral.fs + [] + let ``E_AllowNullLiteral preview`` compilation = + compilation + |> withLangVersionPreview + |> verifyCompile + |> shouldFail + |> withDiagnostics [ + (Error 935, Line 15, Col 10, Line 15, Col 11, "Types with the 'AllowNullLiteral' attribute may only inherit from or implement types which also allow the use of the null literal") + (Error 934, Line 27, Col 10, Line 27, Col 11, "Records, union, abbreviations and struct types cannot have the 'AllowNullLiteral' attribute") + (Error 934, Line 30, Col 10, Line 30, Col 11, "Records, union, abbreviations and struct types cannot have the 'AllowNullLiteral' attribute") + (Error 934, Line 33, Col 10, Line 33, Col 11, "Records, union, abbreviations and struct types cannot have the 'AllowNullLiteral' attribute") + (Error 934, Line 36, Col 10, Line 36, Col 11, "Records, union, abbreviations and struct types cannot have the 'AllowNullLiteral' attribute") + (Error 934, Line 39, Col 10, Line 39, Col 13, "Records, union, abbreviations and struct types cannot have the 'AllowNullLiteral' attribute") + (Error 842, Line 41, Col 7, Line 41, Col 23, "This attribute is not valid for use on this language element"); + (Error 842, Line 44, Col 7, Line 44, Col 23, "This attribute is not valid for use on this language element") + ] + + // SOURCE= AllowNullLiteral01.fs # AllowNullLiteral01.fs + [] + let ``AllowNullLiteral01 8.0`` compilation = + compilation + |> withLangVersion80 + |> verifyCompile + |> shouldSucceed + + // SOURCE=AllowNullLiteral01.fs # AllowNullLiteral01.fs + [] + let ``AllowNullLiteral01 preview`` compilation = + compilation + |> withLangVersionPreview + |> verifyCompile + |> shouldSucceed \ No newline at end of file diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/AttributeUsage/E_AllowNullLiteral.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/AttributeUsage/E_AllowNullLiteral.fs new file mode 100644 index 0000000000..243abb3866 --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/AttributeUsage/E_AllowNullLiteral.fs @@ -0,0 +1,48 @@ +module AllowNullLiteralTest = begin + + //[] + type I = + interface + abstract P : int + end + + //[] + type C() = + member x.P = 1 + + + [] + type D() = + inherit C() + interface I with + member x.P = 2 + member x.P = 1 + + let d = (null : D) + + let d2 = ((box null) :?> D) + + + [] // expect an error here + type S(c:int) = struct end + + [] // expect an error here + type R = { r : int } + + [] // expect an error here + type U = A | B of int + + [] // expect an error here + type E = A = 1 | B = 2 + + [] // expect an error here + type Del = delegate of int -> int + + [] // expect an error here + let x = 1 + + [] // expect an error here + let f x = 1 + +end + \ No newline at end of file diff --git a/tests/fsharp/typecheck/sigs/neg16.bsl b/tests/fsharp/typecheck/sigs/neg16.bsl index 4a6dde0f03..1440ccc78d 100644 --- a/tests/fsharp/typecheck/sigs/neg16.bsl +++ b/tests/fsharp/typecheck/sigs/neg16.bsl @@ -3,20 +3,14 @@ neg16.fs(7,13,7,16): typecheck error FS0644: Namespaces cannot contain extension neg16.fs(23,10,23,11): typecheck error FS0935: Types with the 'AllowNullLiteral' attribute may only inherit from or implement types which also allow the use of the null literal -neg16.fs(34,7,34,23): typecheck error FS0842: This attribute is not valid for use on this language element - neg16.fs(35,10,35,11): typecheck error FS0934: Records, union, abbreviations and struct types cannot have the 'AllowNullLiteral' attribute neg16.fs(38,10,38,11): typecheck error FS0934: Records, union, abbreviations and struct types cannot have the 'AllowNullLiteral' attribute neg16.fs(41,10,41,11): typecheck error FS0934: Records, union, abbreviations and struct types cannot have the 'AllowNullLiteral' attribute -neg16.fs(43,7,43,23): typecheck error FS0842: This attribute is not valid for use on this language element - neg16.fs(44,10,44,11): typecheck error FS0934: Records, union, abbreviations and struct types cannot have the 'AllowNullLiteral' attribute -neg16.fs(46,7,46,23): typecheck error FS0842: This attribute is not valid for use on this language element - neg16.fs(47,10,47,13): typecheck error FS0934: Records, union, abbreviations and struct types cannot have the 'AllowNullLiteral' attribute neg16.fs(49,7,49,23): typecheck error FS0842: This attribute is not valid for use on this language element