Closed j2jensen closed 7 years ago
FYI @agocke
Tried fixing this bug this morning, then just realized it's far more complex than what might be guessed. Here was my description for my original fix for this issue, because it took a good chunk of my sanity to debug through, and I don't want anyone else to do the same:
diff --git a/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/OverloadResolution.cs b/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/OverloadResolution.cs
index a5a3121d29..792e30ec2f 100644
--- a/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/OverloadResolution.cs
+++ b/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/OverloadResolution.cs
@@ -2801,7 +2801,8 @@ private RefKind GetEffectiveParameterRefKind(ParameterSymbol parameter, RefKind
EffectiveParameters effectiveParameters;
if (member.Kind == SymbolKind.Method && (method = (MethodSymbol)(Symbol)member).Arity > 0)
{
- if (typeArgumentsBuilder.Count == 0 && arguments.HasDynamicArgument && !inferWithDynamic)
+ var isLocalFunction = ((MethodSymbol)(Symbol)member).MethodKind == MethodKind.LocalFunction;
+ if (typeArgumentsBuilder.Count == 0 && arguments.HasDynamicArgument && !inferWithDynamic && !isLocalFunction)
{
// Spec 7.5.4: Compile-time checking of dynamic overload resolution:
// * First, if F is a generic method and type arguments were provided,
dynamic
.BindLocalFunctionInvocationWithDynamicArgument
is called with the result
Invocations of local functions with dynamic arguments don't need to be dispatched as dynamic invocations since they cannot be overloaded. Instead, we'll just emit a standard call with dynamic implicit conversions for any dynamic arguments.
dynamic
argument is implicitly converted to the now-bogus type T (as this is outside of the local function)However, there is a large issue with this solution: the generic type inferred is object
, not the type of the object at runtime.
private static void Method<T>(T x) => Console.WriteLine(typeof(T).Name);
private static void M1()
{
Method((dynamic)2); // prints "Int32"
}
private static void M2()
{
void LocFunc<T>(T x) => Console.WriteLine(typeof(T).Name);
LocFunc((dynamic)2); // with this fix, prints "Object". Should print "Int32".
}
I don't know if this is possible to fix for local functions - I'm not sure how dynamic generics get constructed, and if it's possible to do with local functions.
Are there any plans to make this work in the near future?
Just disabling the stuff doesn't sound like the cleanest or most orthogonal solution...
I wanted to call a generic local function today using a dynamic parameter to reduce the amount of code (I could get rid of a private generic method that way) and was greeted with the compilation error.
Version Used: Roslyn 2.0
Steps to Reproduce:
Expected Behavior:
GenericLocal should be invoked, with
string
asT
.Actual Behavior:
BadImageFormatException: An attempt was made to load a program with an incorrect format. (Exception from HRESULT: 0x8007000B)
I described this on a StackOverflow post and the general consensus was that I'd found a bug. Note that the stacktrace shows the exception being thrown inside the method with this code, but no code actually gets run before the exception occurs.