Skip to content

Commit 4fee713

Browse files
T-GroCopilot
andcommitted
Fix internal error when using custom attribute with optional value type argument (#8353)
GenAttribArg in IlxGen.fs handles Const.Zero (the default for [<Optional>] params without [<DefaultParameterValue>]) for System.Object, System.String, and System.Type, but not for primitive value types. This causes an internal error (FS0073) when applying an attribute with an [<Optional>] value type parameter and no default. Add Const.Zero -> default value mappings for all 12 primitive types valid in custom attributes: bool, sbyte, int16, int32, int64, byte, uint16, uint32, uint64, single, double, char. Fixes #8353 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 40e815c commit 4fee713

File tree

4 files changed

+112
-0
lines changed

4 files changed

+112
-0
lines changed

docs/release-notes/.FSharp.Compiler.Service/11.0.100.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
* Fixed how the source ranges of warn directives are reported (as trivia) in the parser output (by not reporting leading spaces). ([Issue #19405](https://github.com/dotnet/fsharp/issues/19405), [PR #19408]((https://github.com/dotnet/fsharp/pull/19408)))
2020
* Fix UoM value type `ToString()` returning garbage values when `--checknulls+` is enabled, caused by double address-taking in codegen. ([Issue #19435](https://github.com/dotnet/fsharp/issues/19435), [PR #19440](https://github.com/dotnet/fsharp/pull/19440))
2121
* Fix completion inconsistently showing some obsolete members (fields and events) while hiding others (methods and properties). All obsolete members are now consistently hidden by default. ([Issue #13512](https://github.com/dotnet/fsharp/issues/13512), [PR #19506](https://github.com/dotnet/fsharp/pull/19506))
22+
* Fix internal error when using custom attribute with `[<Optional>]` value type parameter and no `[<DefaultParameterValue>]`. ([Issue #8353](https://github.com/dotnet/fsharp/issues/8353), [PR #19484](https://github.com/dotnet/fsharp/pull/19484))
2223

2324
### Added
2425

src/Compiler/CodeGen/IlxGen.fs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10217,6 +10217,18 @@ and GenAttribArg amap g eenv x (ilArgTy: ILType) =
1021710217
| Const.Zero when isobj -> ILAttribElem.Null
1021810218
| Const.Zero when tynm = "System.String" -> ILAttribElem.String None
1021910219
| Const.Zero when tynm = "System.Type" -> ILAttribElem.Type None
10220+
| Const.Zero when tynm = "System.Boolean" -> ILAttribElem.Bool false
10221+
| Const.Zero when tynm = "System.SByte" -> ILAttribElem.SByte 0y
10222+
| Const.Zero when tynm = "System.Int16" -> ILAttribElem.Int16 0s
10223+
| Const.Zero when tynm = "System.Int32" -> ILAttribElem.Int32 0
10224+
| Const.Zero when tynm = "System.Int64" -> ILAttribElem.Int64 0L
10225+
| Const.Zero when tynm = "System.Byte" -> ILAttribElem.Byte 0uy
10226+
| Const.Zero when tynm = "System.UInt16" -> ILAttribElem.UInt16 0us
10227+
| Const.Zero when tynm = "System.UInt32" -> ILAttribElem.UInt32 0u
10228+
| Const.Zero when tynm = "System.UInt64" -> ILAttribElem.UInt64 0UL
10229+
| Const.Zero when tynm = "System.Single" -> ILAttribElem.Single 0.0f
10230+
| Const.Zero when tynm = "System.Double" -> ILAttribElem.Double 0.0
10231+
| Const.Zero when tynm = "System.Char" -> ILAttribElem.Char '\000'
1022010232
| Const.String i when isobj || tynm = "System.String" -> ILAttribElem.String(Some i)
1022110233
| _ -> error (InternalError("The type '" + tynm + "' may not be used as a custom attribute value", m))
1022210234

tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/CustomAttributes/Basic/Basic.fs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,14 @@ module CustomAttributes_Basic =
303303
|> verifyCompileAndRun
304304
|> shouldSucceed
305305

306+
// SOURCE=OptionalAttributeArgs.fs # OptionalAttributeArgs.fs
307+
// Regression test for https://github.com/dotnet/fsharp/issues/8353
308+
[<Theory; Directory(__SOURCE_DIRECTORY__, Includes=[|"OptionalAttributeArgs.fs"|])>]
309+
let ``OptionalAttributeArgs_fs`` compilation =
310+
compilation
311+
|> verifyCompile
312+
|> shouldSucceed
313+
306314
// SOURCE=W_ReturnType03b.fs SCFLAGS="--test:ErrorRanges" # W_ReturnType03b.fs
307315
[<Theory; Directory(__SOURCE_DIRECTORY__, Includes=[|"W_ReturnType03b.fs"|])>]
308316
let ``W_ReturnType03b_fs`` compilation =
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
// #Regression #Conformance #DeclarationElements #Attributes
2+
// Regression test for https://github.com/dotnet/fsharp/issues/8353
3+
// Verify that custom attributes with [<Optional>] parameters (no DefaultParameterValue) compile for all value types
4+
5+
open System
6+
open System.Runtime.InteropServices
7+
8+
type BoolAttribute(name : string, flag : bool) =
9+
inherit Attribute()
10+
new([<Optional>] flag : bool) = BoolAttribute("", flag)
11+
12+
type IntAttribute(name : string, value : int) =
13+
inherit Attribute()
14+
new([<Optional>] value : int) = IntAttribute("", value)
15+
16+
type ByteAttribute(name : string, value : byte) =
17+
inherit Attribute()
18+
new([<Optional>] value : byte) = ByteAttribute("", value)
19+
20+
type SByteAttribute(name : string, value : sbyte) =
21+
inherit Attribute()
22+
new([<Optional>] value : sbyte) = SByteAttribute("", value)
23+
24+
type Int16Attribute(name : string, value : int16) =
25+
inherit Attribute()
26+
new([<Optional>] value : int16) = Int16Attribute("", value)
27+
28+
type Int64Attribute(name : string, value : int64) =
29+
inherit Attribute()
30+
new([<Optional>] value : int64) = Int64Attribute("", value)
31+
32+
type UInt16Attribute(name : string, value : uint16) =
33+
inherit Attribute()
34+
new([<Optional>] value : uint16) = UInt16Attribute("", value)
35+
36+
type UInt32Attribute(name : string, value : uint32) =
37+
inherit Attribute()
38+
new([<Optional>] value : uint32) = UInt32Attribute("", value)
39+
40+
type UInt64Attribute(name : string, value : uint64) =
41+
inherit Attribute()
42+
new([<Optional>] value : uint64) = UInt64Attribute("", value)
43+
44+
type FloatAttribute(name : string, value : float) =
45+
inherit Attribute()
46+
new([<Optional>] value : float) = FloatAttribute("", value)
47+
48+
type SingleAttribute(name : string, value : float32) =
49+
inherit Attribute()
50+
new([<Optional>] value : float32) = SingleAttribute("", value)
51+
52+
type CharAttribute(name : string, value : char) =
53+
inherit Attribute()
54+
new([<Optional>] value : char) = CharAttribute("", value)
55+
56+
[<Bool>]
57+
type T1() = class end
58+
59+
[<Int>]
60+
type T2() = class end
61+
62+
[<Byte>]
63+
type T3() = class end
64+
65+
[<Float>]
66+
type T4() = class end
67+
68+
[<Single>]
69+
type T5() = class end
70+
71+
[<Char>]
72+
type T6() = class end
73+
74+
[<SByte>]
75+
type T7() = class end
76+
77+
[<Int16>]
78+
type T8() = class end
79+
80+
[<Int64>]
81+
type T9() = class end
82+
83+
[<UInt16>]
84+
type T10() = class end
85+
86+
[<UInt32>]
87+
type T11() = class end
88+
89+
[<UInt64>]
90+
type T12() = class end
91+

0 commit comments

Comments
 (0)