Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using a non-null constant expression bound to a literal variable of a less-specific type generates invalid IL #18319

Open
IS4Code opened this issue Feb 14, 2025 · 1 comment
Labels
Area-Compiler-CodeGen IlxGen, ilwrite and things at the backend Bug Impact-Medium (Internal MS Team use only) Describes an issue with moderate impact on existing code.
Milestone

Comments

@IS4Code
Copy link

IS4Code commented Feb 14, 2025

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.

Environment: https://sharplab.io/#v2:DYLgZgzgPg9gDgUwHYAIDKBPCAXBBbAWACh5l0tc8A6AJQFclsBLPBKgSUYQCd40eAbkwDGCCMWIBtADwAZJrm4BDYAD4AusWAJsKAEZKAJjD0ArECgBqKuggAqGRCgC8KAIwSiAYRhIIMbSoAdW4FBHkkBAAKA2MzAEpPbEcEFDsUOFCBJVwo+JdiFBQZADkYHzw4Jm1uTmAmJAaAcw1ClBwckRRWPD0eFABZKJkAeThmXxUNGQARBDAlOmBsAAUlZVZFa2BbGKMTU3iNOHWlPAtt2wdEfNcTjc8fPwC2ELCI6LsqIfj4oA

@abonie
Copy link
Member

abonie commented Feb 24, 2025

This should be a compile time error for defining literals without exact type.

@abonie abonie added the Impact-Medium (Internal MS Team use only) Describes an issue with moderate impact on existing code. label Feb 24, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-Compiler-CodeGen IlxGen, ilwrite and things at the backend Bug Impact-Medium (Internal MS Team use only) Describes an issue with moderate impact on existing code.
Projects
Status: New
Development

No branches or pull requests

2 participants