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

Optional args/return either doesn't compile or throws at runtime #295

Open
atifaziz opened this issue Oct 23, 2024 · 0 comments · May be fixed by #299
Open

Optional args/return either doesn't compile or throws at runtime #295

atifaziz opened this issue Oct 23, 2024 · 0 comments · May be fixed by #299

Comments

@atifaziz
Copy link
Contributor

Suppose the following Python function:

def test_optional_result(x: int) -> Optional[int]:
    return x if x >= 0 else None

I would have expected the C# method to return a long?, but instead it's typed to return just long:

long TestOptionalResult(long x);

This means that it's not possible to test for null statically, like so:

switch (testModule.TestOptionalResult(-1))
{
    case null:
        // ...
        break;
    case var result:
        // ...
        break;
}

since the compiler (rightfully) emits CS0037, “Cannot convert null to 'long' because it is a non-nullable value type”. If one works around that by casting to object before testing:

//      V......V
switch ((object)testModule.TestOptionalResult(-1))
{
    case null:
        // ...
        break;
    case var result:
        // ...
        break;
}

the code compiles but results in the runtime exception:

CSnakes.Runtime.PythonInvocationException
Error converting Python object to int, check that the object was a Python int or that the value wasn't too large. See InnerException for details.
   at CSnakes.Runtime.CPython.CPythonAPI.PyLong_AsLongLong(PyObject p) in A:\CSnakes\main\src\CSnakes.Runtime\CPython\Long.cs:line 26

The inner exception reads:

CSnakes.Runtime.PythonRuntimeException
'NoneType' object cannot be interpreted as an integer
  Exception doesn't have a stacktrace

The same problem exists with input arguments that are typed as Optional of some type (when there's no default of None given).

It looks like the problem is with TypeReflection.AsPredefinedType, which simply looks at the type argument:

"typing.Optional" or "Optional" => AsPredefinedType(pythonType.Arguments[0], direction),

The existing nullability support is predicated on the presence of None as the default argument in ArgumentReflection.ArgumentSyntax:

case PythonConstant.None:
literalExpressionSyntax = SyntaxFactory.LiteralExpression(SyntaxKind.NullLiteralExpression);
isNullableType = true;
break;

The fix would be to consider Optional in the type hint as opposed to requiring a default of None. This is especially problematic for the return value.

@atifaziz atifaziz linked a pull request Oct 26, 2024 that will close this issue
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant