Skip to content

Commit

Permalink
Fixed #223
Browse files Browse the repository at this point in the history
  • Loading branch information
sakno committed Feb 17, 2024
1 parent 1dddcce commit 1f19990
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -103,4 +103,7 @@ protected override AsyncResultExpression VisitChildren(ExpressionVisitor visitor
var expression = visitor.Visit(AsyncResult);
return ReferenceEquals(expression, AsyncResult) ? this : new(expression, taskType);
}

internal AsyncResultExpression Update(Expression asyncResult)
=> new(asyncResult, taskType);
}
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,12 @@ internal AsyncStateMachineBuilder(Type taskType, IReadOnlyList<ParameterExpressi
stateSwitchTable = new StateTransitionTable();
}

internal ParameterExpression? ResultVariable
{
get;
private set;
}

private static void MarkAsParameter(ParameterExpression parameter, int position)
=> parameter.GetUserData().Set(ParameterPositionSlot, position);

Expand Down Expand Up @@ -239,8 +245,18 @@ private Expression VisitAsyncResult(AsyncResultExpression expr)
var prologue = context.CurrentStatement.PrologueCodeInserter();
expr = (AsyncResultExpression)base.VisitExtension(expr);

var containsAwait = ExpressionAttributes.Get(expr.AsyncResult) is { ContainsAwait: true };

if (containsAwait && Task.HasResult)
{
ResultVariable ??= Expression.Parameter(Task.ResultType);
prologue(Expression.Assign(ResultVariable, expr.AsyncResult));
expr = expr.Update(ResultVariable);
}

foreach (var finalization in context.CreateJumpPrologue(AsyncMethodEnd.Goto(), this))
prologue(finalization);

return expr;
}

Expand Down Expand Up @@ -604,6 +620,13 @@ internal Expression<TDelegate> Build(Expression body, bool tailCall, bool usePoo
// replace all special expressions
body = Visit(body);

if (methodBuilder.ResultVariable is { } resultVar)
{
body = body is BlockExpression block
? block.Update(block.Variables.Append(resultVar), block.Expressions)
: Expression.Block(body.Type, [resultVar], body);
}

// now we have state machine method, wrap it into lambda
return Build(BuildStateMachine(body, stateMachine, tailCall));
}
Expand Down
41 changes: 41 additions & 0 deletions src/DotNext.Tests/Metaprogramming/RegressionIssue223.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
using System.Linq.Expressions;
using System.Reflection;
using DotNext.Linq.Expressions;

namespace DotNext.Metaprogramming;

using static Linq.Expressions.ExpressionBuilder;
using static Metaprogramming.CodeGenerator;

public sealed class RegressionIssue223 : Test
{
[Fact]
public static async Task ThrowOnReturn()
{
var lambda = AsyncLambda<Func<Task<int>>>(_ =>
{
Try(() =>
{
var methodInfo = new Func<Task<int>>(Throw).Method;
var methodResult = Expression.Call(null, methodInfo);

Return(methodResult.Await());
})
.Catch(typeof(Exception), _ =>
{
CallStatic(typeof(Console), nameof(Console.WriteLine), Expression.Constant("Exception caught"));
})
.End();
});

var action = lambda.Compile();

Equal(0, await action());

static async Task<int> Throw()
{
await Task.Yield();
throw new InvalidOperationException("Exception was not caught");
}
}
}

0 comments on commit 1f19990

Please sign in to comment.