Default use of implicit conversion creates non-working code (using Pulumi libraries)
See original GitHub issueThe code generated by the new (12.0.1.0 compiler for F# 6) which implicitly uses op_Implicit is generating code that doesn’t work the same way that calling op_Implict (or using C#'s implicits) does.
This doesn’t work
let conditionImplicit =
Cdn.Inputs.DeliveryRuleRequestSchemeConditionArgs(
Name = "RequestScheme1",
Parameters =
Cdn.Inputs.RequestSchemeMatchConditionParametersArgs(
MatchValues = matchValues,
Operator = Input.op_Implicit "Equal",
OdataType = Input.op_Implicit "#Microsoft.Azure.Cdn.Models.DeliveryRuleRequestSchemeConditionParameters"
)
)
Not using implicit conversions does work
let conditionExplicit =
Cdn.Inputs.DeliveryRuleRequestSchemeConditionArgs(
Name = "RequestScheme2",
Parameters =
Input.op_Implicit (Cdn.Inputs.RequestSchemeMatchConditionParametersArgs(
MatchValues = matchValues,
Operator = Input.op_Implicit "Equal",
OdataType = Input.op_Implicit "#Microsoft.Azure.Cdn.Models.DeliveryRuleRequestSchemeConditionParameters"
))
)
C#'s implicit conversions do work
var conditionImplicit =
new DeliveryRuleRequestSchemeConditionArgs {
Name = "RequestScheme1",
Parameters =
new RequestSchemeMatchConditionParametersArgs {
MatchValues = matchValues,
Operator = "Equal",
OdataType = "#Microsoft.Azure.Cdn.Models.DeliveryRuleRequestSchemeConditionParameters"
}
};
The repro case is at https://github.com/marklam/ImplicitsProblem
It looks like the code generation (as disassembled with ILspy) is different for the F# implicit case. This means that when this code is used within a Pulumi app, errors like https://github.com/pulumi/pulumi-azure-native/issues/1569 occur.
It seems like this is being produced by the implicit calls:
call class [Pulumi]Pulumi.Input`1<!0> class [Pulumi]Pulumi.Input`1<class [Pulumi.AzureNative]Pulumi.AzureNative.Cdn.Inputs.RequestSchemeMatchConditionParametersArgs>::op_Implicit(!0)
instead of
newobj instance void [Pulumi.AzureNative]Pulumi.AzureNative.Cdn.Inputs.DeliveryRuleRequestSchemeConditionArgs::.ctor()
Known workarounds
Enable warnings for implicit conversions, and use the old way (call op_Implicit
yourself)
<WarnOn>3388;3391;3395</WarnOn>
Related information
Provide any related information (optional):
- Windows 10
- Visual Studio 2022
- F# 6
- .NET Runtime 3.1
Issue Analytics
- State:
- Created a year ago
- Comments:10 (6 by maintainers)
Top GitHub Comments
Thanks!
I’ve minimized the repro further and analyzed the IL.
The il of test looks like this:
Following the lines, starting from
IL_0011
the compiler went astray:Pushing this all into ilverify confirms my conclusion:
Now at this point if this was a virtual property the runtime would have to look at the instance reference it has on the stack to run
set_Name
for (in this case a reference to an Input). It would get the method table from the object header and try to findset_Name
which doesn’t exist on Input. The runtime would then throw some invalid program exception killing the process, which would have made this a bit easier 😃Here though, because it’s a non virtual method, the instructions were even inlined (and the F# compiler might also do this if Pulumi’s Input class was written in F#). As a result this runtime work does not happen and code just overwrote what was there (in whatever instance reference given) at the offset the backing field for Name would normally live. For Input this offset corresponds with the underlying/wrapped value. And indeed navigating the value in the debugger shows that
SomeArgs.OtherArgs
now directly points to an Input storingName
instead ofOtherArgs
. Heap corruption!Fix is in https://github.com/dotnet/fsharp/pull/13673
Not sure, might have made it for rc1 but otherwise rc2 maybe?