Skip to content

[BUG]: Void method call before Await produces a coersion exception #155

@victorr99

Description

@victorr99

Current Behavior

Calling a method returning void before an await call results in an InvalidOperationException:

Unhandled exception. System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation.
 ---> System.InvalidOperationException: No coercion operator is defined between types 'System.Void' and 'System.Object'.
   at System.Linq.Expressions.Expression.GetUserDefinedCoercionOrThrow(ExpressionType coercionType, Expression expression, Type convertToType)
   at Hyperbee.Expressions.CompilerServices.Transitions.Transition.EnsureConvert(Expression expression, Type targetType)
   at Hyperbee.Expressions.CompilerServices.Transitions.Transition.SetResult(List`1 expressions, StateMachineContext context)
   at Hyperbee.Expressions.CompilerServices.Transitions.Transition.AddExpressions(List`1 expressions, StateMachineContext context)
   at Hyperbee.Expressions.CompilerServices.Transitions.AwaitTransition.AddExpressions(List`1 expressions, StateMachineContext context)
   at Hyperbee.Expressions.CompilerServices.StateNode.GetExpression(StateMachineContext context)
   at Hyperbee.Expressions.CompilerServices.StateContext.Scope.GetExpressions(StateMachineContext context)
   at Hyperbee.Expressions.CompilerServices.AsyncStateMachineBuilder`1.CreateBody(FieldInfo[] fields, StateMachineContext context, Expression[] antecedents)
   at Hyperbee.Expressions.CompilerServices.AsyncStateMachineBuilder`1.CreateMoveNextBody(Int32 id, StateMachineContext context, Type stateMachineType, FieldInfo[] fields, Type lambdaType)
   at Hyperbee.Expressions.CompilerServices.AsyncStateMachineBuilder`1.BuildStateMachineExpression(Int32 id, StateMachineContext context)
   at Hyperbee.Expressions.CompilerServices.AsyncStateMachineBuilder`1.CreateStateMachine(AsyncLoweringTransformer loweringTransformer, Int32 id)
   at Hyperbee.Expressions.CompilerServices.AsyncStateMachineBuilder.Create[TResult](AsyncLoweringTransformer loweringTransformer, ExpressionRuntimeOptions options)
   at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor)
   at System.Reflection.MethodBaseInvoker.InvokeDirectByRefWithFewArgs(Object obj, Span`1 copyOfArgs, BindingFlags invokeAttr)
   --- End of inner exception stack trace ---
   at System.Reflection.MethodBaseInvoker.InvokeDirectByRefWithFewArgs(Object obj, Span`1 copyOfArgs, BindingFlags invokeAttr)
   at System.Reflection.MethodBaseInvoker.InvokeWithFewArgs(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   at System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters)
   at Hyperbee.Expressions.CompilerServices.AsyncStateMachineBuilder.Create(Type resultType, AsyncLoweringTransformer loweringTransformer, ExpressionRuntimeOptions options)
   at Hyperbee.Expressions.AsyncBlockExpression.Reduce()
   at Playground.Program.Main() in C:\Playground\Program.cs:line 114
   at Playground.Program.<Main>()

Expected Behavior

No exception thrown during reducing/compiling.

Steps To Reproduce

public class Program
{
	public static void Main()
	{
		var expression = BlockAsync(
			Call(typeof(Program).GetMethod("VoidMethod")),
			Await(Call(typeof(Program).GetMethod("AsyncObjectMethod"))));

		expression.Reduce(); // <- throws InvalidOperationException
	}
	
	public static Task<object?> AsyncObjectMethod()
	{
		return Task.FromResult<object?>(null);
	}

	public static void VoidMethod()
	{
	}
}

Anything else?

There may be a workaround for this issue, which I still need to test in my actual expression. It does workaround the issue of the reproduction code however. edit: the workaround seems to be valid, it works for my actual expression.

var expression = BlockAsync(
    Block(
        Call(typeof(Program).GetMethod("VoidMethod")),
        Constant(null)), // <- The result type of the block is now object which lets the expression reduce correctly
    Await(Call(typeof(Program).GetMethod("AsyncObjectMethod"))));

expression.Reduce();

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions