protected override Expression VisitTry(TryExpression node) { // Visit finally/fault block first BlockInfo block = new BlockInfo { InFinally = true }; _blocks.Push(block); Expression @finally = Visit(node.Finally); Expression fault = Visit(node.Fault); block.InFinally = false; LabelTarget finallyEnd = block.FlowLabel; if (finallyEnd != null) { if (@finally != null) { @finally = Expression.Label(finallyEnd, @finally); } if (fault != null) { fault = Expression.Label(finallyEnd, fault); } // Make a new target, which will be emitted after the try block.FlowLabel = Expression.Label(); } Expression @try = Visit(node.Body); IList <CatchBlock> handlers = Visit(node.Handlers, VisitCatchBlock); _blocks.Pop(); if (@try == node.Body && handlers == node.Handlers && @finally == node.Finally && fault == node.Fault) { return(node); } if (!block.HasFlow) { return(Expression.MakeTry(@try, @finally, fault, handlers)); } // If there is a control flow in finally, emit outer: // try { // // try block body and all catch handling // } catch (Exception all) { // saved = all; // } finally { // finally_body // if (saved != null) { // throw saved; // } // } // // If we have a fault handler we turn this into the better: // try { // // try block body and all catch handling // } catch (Exception all) { // saved = all; // fault_body // throw saved // } if (handlers.Count > 0) { @try = Expression.MakeTry(@try, null, null, handlers); } var all = Expression.Variable(typeof(Exception), "$exception"); if (@finally != null) { handlers = new[] { Expression.Catch(all.Type, Expression.Empty()) }; @finally = Expression.Block( @finally, Expression.Condition( Expression.NotEqual(all, Expression.Constant(null, all.Type)), Expression.Throw(all), Expression.Empty() ) ); } else { handlers = new[] { Expression.Catch( all.Type, Expression.Block(fault, Expression.Throw(all)) ) }; fault = null; } // Emit flow control return(Expression.Block( new ParameterExpression[] { all }, Expression.MakeTry(@try, @finally, fault, handlers), Expression.Label(block.FlowLabel), MakeFlowControlSwitch(block) )); }