Search code examples
c#ironpython

IronPython is throwing the following Exception: Unable to cast object of type Func<PythonFunction,Object> to Func<CodeContext, CodeContext>


We have IronPython embedded in our software, and allow users to write and run their own custom Python scripts that we run in an IronPython Engine. One of our users has been getting the following exception:

Unable to cast object of type 'System.Func`2[IronPython.Runtime.PythonFunction,System.Object]' to type 'System.Func`2[IronPython.Runtime.CodeContext,IronPython.Runtime.CodeContext]'.

This exception is thrown on the first line for the following code (obviously there is more code but that is the line that is failing):

class User:
    pass

Stack trace is as follows:

at IronPython.Runtime.Operations.PythonOps.GetClassCode(CodeContext context, FunctionCode funcCode, Func`2 body)
at IronPython.Runtime.Operations.PythonOps.MakeClass(FunctionCode funcCode, Func`2 body, CodeContext parentContext, String name, Object[] bases, String selfNames)
at Microsoft.Scripting.Interpreter.FuncCallInstruction`7.Run(InterpretedFrame frame)
at Microsoft.Scripting.Interpreter.Interpreter.Run(InterpretedFrame frame)
at Microsoft.Scripting.Interpreter.LightLambda.Run2[T0,T1,TRet](T0 arg0, T1 arg1)
at IronPython.Compiler.PythonCallTargets.OriginalCallTarget1(PythonFunction function, Object arg0)
at IronPython.Runtime.FunctionCaller`1.Call1(CallSite site, CodeContext context, Object func, T0 arg0)
at System.Dynamic.UpdateDelegates.UpdateAndExecute3[T0,T1,T2,TRet](CallSite site, T0 arg0, T1 arg1, T2 arg2)
at Microsoft.Scripting.Interpreter.DynamicInstruction`4.Run(InterpretedFrame frame)
at Microsoft.Scripting.Interpreter.Interpreter.Run(InterpretedFrame frame)
at Microsoft.Scripting.Interpreter.LightLambda.Run2[T0,T1,TRet](T0 arg0, T1 arg1)
at IronPython.Compiler.PythonScriptCode.RunWorker(CodeContext ctx)
at IronPython.Compiler.PythonScriptCode.Run(Scope scope)
at IronPython.Compiler.RuntimeScriptCode.InvokeTarget(Scope scope)
at IronPython.Compiler.RuntimeScriptCode.Run(Scope scope)
at Microsoft.Scripting.SourceUnit.Execute(Scope scope, ErrorSink errorSink)
at Microsoft.Scripting.Hosting.ScriptSource.Execute(ScriptScope scope)
at Microsoft.Scripting.Hosting.ScriptEngine.Execute(String expression, ScriptScope scope)...

Looking at the IronPython source code it's clearly failing when it's trying to cast funcCode.Target to a Func<CodeContext, CodeContext> in IronPython.Runtime.Operations.PythonOps:

public static object MakeClass(FunctionCode funcCode, Func<CodeContext, CodeContext> body, CodeContext/*!*/ parentContext, string name, object[] bases, string selfNames) {
    Func<CodeContext, CodeContext> func = GetClassCode(parentContext, funcCode, body);

    return MakeClass(parentContext, name, bases, selfNames, func(parentContext).Dict);
}

private static Func<CodeContext, CodeContext> GetClassCode(CodeContext/*!*/ context, FunctionCode funcCode, Func<CodeContext, CodeContext> body) {
    if (body == null) {
        if (funcCode.Target == null) {
            funcCode.UpdateDelegate(context.LanguageContext, true);
        }
        return (Func<CodeContext, CodeContext>)funcCode.Target;
    } else {
        if (funcCode.Target == null) {
            funcCode.SetTarget(body);
            funcCode._normalDelegate = body;
        }
        return body;
    }
}

To me, this seems like a bug in IronPython. But I have to admit I'm in a little over my head in terms of what's truly causing IronPython to croak there. funcCode.Target is a Delegate, and IronPython expects it to be of type Func<CodeContext, CodeContext> but for some reason it's of type Func<PythonFunction, Object>. But I have no clue how or why that Delegate would be getting set to a Func of a different type.

The customer's code seems pretty innocuous. I haven't been able to recreate the exception in my dev environment, but it happens regularly for this customer.

Is there anything I can try on my end? Or is this a bug I should file with the IronPython folks. And if so, how do I file a bug with the IronPython folks?

I should also mention this is IronPython2, not 3.


Solution

  • It's a bug in IronPython.

    Was able to first reproduce the bug in our software and then in a simple console app. I reported the bug to the IronPython team.

    Update: The issue was fixed in a pull request and I was able to confirm that it fixed the issue for my case.