-
Notifications
You must be signed in to change notification settings - Fork 833
Description
It is possible to define literal values that are the result of upcasting a literal to a less specific type. Using such literals however produces invalid IL that is missing the upcast.
Repro steps
[<Literal>]
let badobj: System.ValueType = 1
System.Console.WriteLine(badobj)Expected behavior
The code should either succeed and print "1", or it should fail to compile on the basis that badobj is not assigned a constant expression.
Actual behavior
The code compiles fine without any warnings, but generates invalid IL upon retrieving the literal value:
ldc.i4.1
call void [System.Console]System.Console::WriteLine(object)The box instruction is missing, resulting in System.InvalidProgramException being thrown when the program is launched.
Known workarounds
Avoiding upcasts in constant expressions.
Related information
It seems such a .NET literal is technically valid (the runtime attaches no semantics to the value encoded in the metadata), but it is not CLS-compliant:
CLS Rule 13: The value of a literal static is specified through the use of field initialization metadata (see Partition II Metadata). A CLS-compliant literal must have a value specified in field initialization metadata that is of exactly the same type as the literal (or of the underlying type, if that literal is an enum).
Based on my understanding of the F# specification, it likely should not be possible to define such [<Literal>] values, as upcasting is not mentioned in the list of allowed operations. However, such literals could still be found in imported assemblies compiled from languages that do support them, and thus may be re-referenced in F# code.
This broken literal can also be referenced as a default parameter value:
static member M([<Optional>][<DefaultParameterValue(badobj)>]param: ValueType)This use seems valid, but also generates invalid IL upon calling the method.
Metadata
Metadata
Assignees
Labels
Type
Projects
Status