[System.ServiceModel] Changed test port from 8080 to 30158
[mono.git] / mcs / mcs / statement.cs
index 83d5e89daad2271fb9d64c6db840292b6c564614..a09c4acd939b99b5262234bdac40c46019aa09ce 100644 (file)
@@ -101,7 +101,7 @@ namespace Mono.CSharp {
                                return DoFlowAnalysis (fc);
                        }
 
-                       if (this is EmptyStatement)
+                       if (this is EmptyStatement || loc.IsNull)
                                return true;
 
                        if (fc.UnreachableReported)
@@ -688,11 +688,7 @@ namespace Mono.CSharp {
                                infinite = true;
                        }
 
-                       base.Resolve (bc);
-
-                       Iterator.Resolve (bc);
-
-                       return true;
+                       return base.Resolve (bc) && Iterator.Resolve (bc);
                }
 
                protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
@@ -859,11 +855,11 @@ namespace Mono.CSharp {
                        var prev_loop = bc.EnclosingLoop;
                        var prev_los = bc.EnclosingLoopOrSwitch;
                        bc.EnclosingLoopOrSwitch = bc.EnclosingLoop = this;
-                       Statement.Resolve (bc);
+                       var ok = Statement.Resolve (bc);
                        bc.EnclosingLoopOrSwitch = prev_los;
                        bc.EnclosingLoop = prev_loop;
 
-                       return true;
+                       return ok;
                }
 
                //
@@ -1202,15 +1198,16 @@ namespace Mono.CSharp {
                                                var async_type = storey.ReturnType;
 
                                                if (async_type == null && async_block.ReturnTypeInference != null) {
-                                                       async_block.ReturnTypeInference.AddCommonTypeBoundAsync (expr.Type);
+                                                       if (expr.Type.Kind == MemberKind.Void && !(this is ContextualReturn))
+                                                               ec.Report.Error (4029, loc, "Cannot return an expression of type `void'");
+                                                       else
+                                                               async_block.ReturnTypeInference.AddCommonTypeBoundAsync (expr.Type);
                                                        return true;
                                                }
 
                                                if (async_type.Kind == MemberKind.Void) {
-                                                       ec.Report.Error (127, loc,
-                                                               "`{0}': A return keyword must not be followed by any expression when method returns void",
-                                                               ec.GetSignatureForError ());
-
+                                                       ec.Report.Error (8030, loc,
+                                                               "Anonymous function or lambda expression converted to a void returning delegate cannot return a value");
                                                        return false;
                                                }
 
@@ -1218,18 +1215,14 @@ namespace Mono.CSharp {
                                                        if (this is ContextualReturn)
                                                                return true;
 
-                                                       // Same error code as .NET but better error message
                                                        if (async_block.DelegateType != null) {
-                                                               ec.Report.Error (1997, loc,
-                                                                       "`{0}': A return keyword must not be followed by an expression when async delegate returns `Task'. Consider using `Task<T>' return type",
-                                                                       async_block.DelegateType.GetSignatureForError ());
+                                                               ec.Report.Error (8031, loc,
+                                                                       "Async lambda expression or anonymous method converted to a `Task' cannot return a value. Consider returning `Task<T>'");
                                                        } else {
                                                                ec.Report.Error (1997, loc,
                                                                        "`{0}': A return keyword must not be followed by an expression when async method returns `Task'. Consider using `Task<T>' return type",
                                                                        ec.GetSignatureForError ());
-
                                                        }
-
                                                        return false;
                                                }
 
@@ -1245,12 +1238,9 @@ namespace Mono.CSharp {
                                                }
                                        }
                                } else {
-                                       // Same error code as .NET but better error message
                                        if (block_return_type.Kind == MemberKind.Void) {
-                                               ec.Report.Error (127, loc,
-                                                       "`{0}': A return keyword must not be followed by any expression when delegate returns void",
-                                                       am.GetSignatureForError ());
-
+                                               ec.Report.Error (8030, loc,
+                                                       "Anonymous function or lambda expression converted to a void returning delegate cannot return a value");
                                                return false;
                                        }
 
@@ -1791,9 +1781,20 @@ namespace Mono.CSharp {
                        
                protected override void DoEmit (EmitContext ec)
                {
-                       if (expr == null)
-                               ec.Emit (OpCodes.Rethrow);
-                       else {
+                       if (expr == null) {
+                               var atv = ec.AsyncThrowVariable;
+                               if (atv != null) {
+                                       if (atv.HoistedVariant != null) {
+                                               atv.HoistedVariant.Emit (ec);
+                                       } else {
+                                               atv.Emit (ec);
+                                       }
+
+                                       ec.Emit (OpCodes.Throw);
+                               } else {
+                                       ec.Emit (OpCodes.Rethrow);
+                               }
+                       } else {
                                expr.Emit (ec);
 
                                ec.Emit (OpCodes.Throw);
@@ -2185,13 +2186,13 @@ namespace Mono.CSharp {
                {
                        li.CreateBuilder (ec);
 
-                       if (Initializer != null)
+                       if (Initializer != null && !IsUnreachable)
                                ((ExpressionStatement) Initializer).EmitStatement (ec);
 
                        if (declarators != null) {
                                foreach (var d in declarators) {
                                        d.Variable.CreateBuilder (ec);
-                                       if (d.Initializer != null) {
+                                       if (d.Initializer != null && !IsUnreachable) {
                                                ec.Mark (d.Variable.Location);
                                                ((ExpressionStatement) d.Initializer).EmitStatement (ec);
                                        }
@@ -2817,12 +2818,7 @@ namespace Mono.CSharp {
                        if (rc.IsUnreachable)
                                return rc;
 
-                       base.MarkReachable (rc);
-
-                       if (scope_initializers != null) {
-                               foreach (var si in scope_initializers)
-                                       si.MarkReachable (rc);
-                       }
+                       MarkReachableScope (rc);
 
                        foreach (var s in statements) {
                                rc = s.MarkReachable (rc);
@@ -2839,6 +2835,16 @@ namespace Mono.CSharp {
                        return rc;
                }
 
+               public void MarkReachableScope (Reachability rc)
+               {
+                       base.MarkReachable (rc);
+
+                       if (scope_initializers != null) {
+                               foreach (var si in scope_initializers)
+                                       si.MarkReachable (rc);
+                       }
+               }
+
                public override bool Resolve (BlockContext bc)
                {
                        if ((flags & Flags.Resolved) != 0)
@@ -2893,10 +2899,12 @@ namespace Mono.CSharp {
                        DoEmit (ec);
                }
 
-               protected void EmitScopeInitializers (EmitContext ec)
+               public void EmitScopeInitializers (EmitContext ec)
                {
                        foreach (Statement s in scope_initializers)
                                s.Emit (ec);
+
+                       scope_initializers = null;
                }
 
                protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
@@ -2917,7 +2925,7 @@ namespace Mono.CSharp {
 
                                end_unreachable = s.FlowAnalysis (fc);
                                if (s.IsUnreachable) {
-                                       statements[startIndex] = new EmptyStatement (s.loc);
+                                       statements [startIndex] = RewriteUnreachableStatement (s);
                                        continue;
                                }
 
@@ -2944,7 +2952,7 @@ namespace Mono.CSharp {
 
                                                if (s.IsUnreachable) {
                                                        s.FlowAnalysis (fc);
-                                                       statements[startIndex] = new EmptyStatement (s.loc);
+                                                       statements [startIndex] = RewriteUnreachableStatement (s);
                                                }
                                        }
                                }
@@ -2959,6 +2967,24 @@ namespace Mono.CSharp {
                        return !Explicit.HasReachableClosingBrace;
                }
 
+               static Statement RewriteUnreachableStatement (Statement s)
+               {
+                       // LAMESPEC: It's not clear whether declararion statement should be part of reachability
+                       // analysis. Even csc report unreachable warning for it but it's actually used hence
+                       // we try to emulate this behaviour
+                       //
+                       // Consider:
+                       //      goto L;
+                       //      int v;
+                       // L:
+                       //      v = 1;
+
+                       if (s is BlockVariable)
+                               return s;
+
+                       return new EmptyStatement (s.loc);
+               }
+
                public void ScanGotoJump (Statement label)
                {
                        int i;
@@ -3204,8 +3230,9 @@ namespace Mono.CSharp {
 
                                                for (ExplicitBlock b = ref_block; b.AnonymousMethodStorey != storey; b = b.Parent.Explicit) {
                                                        ParametersBlock pb;
+                                                       AnonymousMethodStorey b_storey = b.AnonymousMethodStorey;
 
-                                                       if (b.AnonymousMethodStorey != null) {
+                                                       if (b_storey != null) {
                                                                //
                                                                // Don't add storey cross reference for `this' when the storey ends up not
                                                                // beeing attached to any parent
@@ -3224,21 +3251,23 @@ namespace Mono.CSharp {
                                                                                b.AnonymousMethodStorey.AddCapturedThisField (ec, parent);
                                                                                break;
                                                                        }
-                                                               }
 
-                                                               b.AnonymousMethodStorey.AddParentStoreyReference (ec, storey);
-                                                               b.AnonymousMethodStorey.HoistedThis = storey.HoistedThis;
+                                                               }
 
                                                                //
                                                                // Stop propagation inside same top block
                                                                //
-                                                               if (b.ParametersBlock == ParametersBlock.Original)
+                                                               if (b.ParametersBlock == ParametersBlock.Original) {
+                                                                       b_storey.AddParentStoreyReference (ec, storey);
+//                                                                     b_storey.HoistedThis = storey.HoistedThis;
                                                                        break;
+                                                               }
 
-                                                               b = b.ParametersBlock;
+                                                               b = pb = b.ParametersBlock;
+                                                       } else {
+                                                               pb = b as ParametersBlock;
                                                        }
 
-                                                       pb = b as ParametersBlock;
                                                        if (pb != null && pb.StateMachine != null) {
                                                                if (pb.StateMachine == storey)
                                                                        break;
@@ -3263,8 +3292,14 @@ namespace Mono.CSharp {
 
                                                                pb.StateMachine.AddParentStoreyReference (ec, storey);
                                                        }
-                                                       
-                                                       b.HasCapturedVariable = true;
+
+                                                       //
+                                                       // Add parent storey reference only when this is not captured directly
+                                                       //
+                                                       if (b_storey != null) {
+                                                               b_storey.AddParentStoreyReference (ec, storey);
+                                                               b_storey.HoistedThis = storey.HoistedThis;
+                                                       }
                                                }
                                        }
                                }
@@ -3712,16 +3747,14 @@ namespace Mono.CSharp {
                        var label = value as LabeledStatement;
                        Block b = block;
                        if (label != null) {
-                               do {
-                                       if (label.Block == b)
-                                               return label;
-                                       b = b.Parent;
-                               } while (b != null);
+                               if (IsLabelVisible (label, b))
+                                       return label;
+
                        } else {
                                List<LabeledStatement> list = (List<LabeledStatement>) value;
                                for (int i = 0; i < list.Count; ++i) {
                                        label = list[i];
-                                       if (label.Block == b)
+                                       if (IsLabelVisible (label, b))
                                                return label;
                                }
                        }
@@ -3729,6 +3762,17 @@ namespace Mono.CSharp {
                        return null;
                }
 
+               static bool IsLabelVisible (LabeledStatement label, Block b)
+               {
+                       do {
+                               if (label.Block == b)
+                                       return true;
+                               b = b.Parent;
+                       } while (b != null);
+
+                       return false;
+               }
+
                public ParameterInfo GetParameterInfo (Parameter p)
                {
                        for (int i = 0; i < parameters.Count; ++i) {
@@ -5028,6 +5072,8 @@ namespace Mono.CSharp {
 
                        base.MarkReachable (rc);
 
+                       block.MarkReachableScope (rc);
+
                        if (block.Statements.Count == 0)
                                return rc;
 
@@ -5442,7 +5488,7 @@ namespace Mono.CSharp {
                        EmitTryBodyPrepare (ec);
                        EmitTryBody (ec);
 
-                       ec.BeginFinallyBlock ();
+                       bool begin = EmitBeginFinallyBlock (ec);
 
                        Label start_finally = ec.DefineLabel ();
                        if (resume_points != null) {
@@ -5470,7 +5516,8 @@ namespace Mono.CSharp {
                                EmitFinallyBody (ec);
                        }
 
-                       ec.EndExceptionBlock ();
+                       if (begin)
+                               ec.EndExceptionBlock ();
                }
 
                public override void EmitForDispose (EmitContext ec, LocalBuilder pc, Label end, bool have_dispatcher)
@@ -5544,6 +5591,12 @@ namespace Mono.CSharp {
                        return res;
                }
 
+               protected virtual bool EmitBeginFinallyBlock (EmitContext ec)
+               {
+                       ec.BeginFinallyBlock ();
+                       return true;
+               }
+
                public override Reachability MarkReachable (Reachability rc)
                {
                        base.MarkReachable (rc);
@@ -6248,12 +6301,76 @@ namespace Mono.CSharp {
 
        public class Catch : Statement
        {
+               class FilterStatement : Statement
+               {
+                       readonly Catch ctch;
+
+                       public FilterStatement (Catch ctch)
+                       {
+                               this.ctch = ctch;
+                       }
+
+                       protected override void CloneTo (CloneContext clonectx, Statement target)
+                       {
+                       }
+
+                       protected override void DoEmit (EmitContext ec)
+                       {
+                               if (ctch.li != null) {
+                                       if (ctch.hoisted_temp != null)
+                                               ctch.hoisted_temp.Emit (ec);
+                                       else
+                                               ctch.li.Emit (ec);
+                               }
+
+                               var expr_start = ec.DefineLabel ();
+                               var end = ec.DefineLabel ();
+
+                               ec.Emit (OpCodes.Brtrue_S, expr_start);
+                               ec.EmitInt (0);
+                               ec.Emit (OpCodes.Br, end);
+                               ec.MarkLabel (expr_start);
+
+                               ctch.Filter.Emit (ec);
+
+                               ec.MarkLabel (end);
+                               ec.Emit (OpCodes.Endfilter);
+                               ec.BeginFilterHandler ();
+                               ec.Emit (OpCodes.Pop);
+                       }
+
+                       protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
+                       {
+                               ctch.Filter.FlowAnalysis (fc);
+                               return true;
+                       }
+
+                       public override bool Resolve (BlockContext bc)
+                       {
+                               ctch.Filter = ctch.Filter.Resolve (bc);
+
+                               if (ctch.Filter != null) {
+                                       if (ctch.Filter.ContainsEmitWithAwait ()) {
+                                               bc.Report.Error (7094, ctch.Filter.Location, "The `await' operator cannot be used in the filter expression of a catch clause");
+                                       }
+
+                                       var c = ctch.Filter as Constant;
+                                       if (c != null && !c.IsDefaultValue) {
+                                               bc.Report.Warning (7095, 1, ctch.Filter.Location, "Exception filter expression is a constant");
+                                       }
+                               }
+
+                               return true;
+                       }
+               }
+
                ExplicitBlock block;
                LocalVariable li;
                FullNamedExpression type_expr;
                CompilerAssign assign;
                TypeSpec type;
-               
+               LocalTemporary hoisted_temp;
+
                public Catch (ExplicitBlock block, Location loc)
                {
                        this.block = block;
@@ -6274,6 +6391,10 @@ namespace Mono.CSharp {
                        }
                }
 
+               public Expression Filter {
+                       get; set;
+               }
+
                public bool IsGeneral {
                        get {
                                return type_expr == null;
@@ -6302,46 +6423,77 @@ namespace Mono.CSharp {
 
                protected override void DoEmit (EmitContext ec)
                {
+                       if (Filter != null) {
+                               ec.BeginExceptionFilterBlock ();
+                               ec.Emit (OpCodes.Isinst, IsGeneral ? ec.BuiltinTypes.Object : CatchType);
+
+                               if (li != null)
+                                       EmitCatchVariableStore (ec);
+
+                               if (Block.HasAwait) {
+                                       Block.EmitScopeInitializers (ec);
+                               } else {
+                                       Block.Emit (ec);
+                               }
+
+                               return;
+                       }
+
                        if (IsGeneral)
                                ec.BeginCatchBlock (ec.BuiltinTypes.Object);
                        else
                                ec.BeginCatchBlock (CatchType);
 
                        if (li != null) {
-                               li.CreateBuilder (ec);
-
-                               //
-                               // Special case hoisted catch variable, we have to use a temporary variable
-                               // to pass via anonymous storey initialization with the value still on top
-                               // of the stack
-                               //
-                               if (li.HoistedVariant != null) {
-                                       LocalTemporary lt = new LocalTemporary (li.Type);
-                                       lt.Store (ec);
-
-                                       // switch to assigning from the temporary variable and not from top of the stack
-                                       assign.UpdateSource (lt);
-                               }
+                               EmitCatchVariableStore (ec);
                        } else {
                                ec.Emit (OpCodes.Pop);
                        }
 
-                       Block.Emit (ec);
+                       if (!Block.HasAwait)
+                               Block.Emit (ec);
                }
 
-               public override bool Resolve (BlockContext ec)
+               void EmitCatchVariableStore (EmitContext ec)
                {
-                       using (ec.Set (ResolveContext.Options.CatchScope)) {
-                               if (type_expr != null) {
-                                       type = type_expr.ResolveAsType (ec);
+                       li.CreateBuilder (ec);
+
+                       //
+                       // Special case hoisted catch variable, we have to use a temporary variable
+                       // to pass via anonymous storey initialization with the value still on top
+                       // of the stack
+                       //
+                       if (li.HoistedVariant != null) {
+                               hoisted_temp = new LocalTemporary (li.Type);
+                               hoisted_temp.Store (ec);
+
+                               // switch to assignment from temporary variable and not from top of the stack
+                               assign.UpdateSource (hoisted_temp);
+                       }
+               }
+
+               public override bool Resolve (BlockContext bc)
+               {
+                       using (bc.Set (ResolveContext.Options.CatchScope)) {
+                               if (type_expr == null) {
+                                       if (CreateExceptionVariable (bc.Module.Compiler.BuiltinTypes.Object)) {
+                                               Expression source = new EmptyExpression (li.Type);
+                                               assign = new CompilerAssign (new LocalVariableReference (li, Location.Null), source, Location.Null);
+                                               Block.AddScopeStatement (new StatementExpression (assign, Location.Null));
+                                       }
+                               } else {
+                                       type = type_expr.ResolveAsType (bc);
                                        if (type == null)
                                                return false;
 
-                                       if (type.BuiltinType != BuiltinTypeSpec.Type.Exception && !TypeSpec.IsBaseClass (type, ec.BuiltinTypes.Exception, false)) {
-                                               ec.Report.Error (155, loc, "The type caught or thrown must be derived from System.Exception");
+                                       if (li == null)
+                                               CreateExceptionVariable (type);
+
+                                       if (type.BuiltinType != BuiltinTypeSpec.Type.Exception && !TypeSpec.IsBaseClass (type, bc.BuiltinTypes.Exception, false)) {
+                                               bc.Report.Error (155, loc, "The type caught or thrown must be derived from System.Exception");
                                        } else if (li != null) {
                                                li.Type = type;
-                                               li.PrepareAssignmentAnalysis (ec);
+                                               li.PrepareAssignmentAnalysis (bc);
 
                                                // source variable is at the top of the stack
                                                Expression source = new EmptyExpression (li.Type);
@@ -6356,14 +6508,31 @@ namespace Mono.CSharp {
                                        }
                                }
 
+                               if (Filter != null) {
+                                       Block.AddScopeStatement (new FilterStatement (this));
+                               }
+
                                Block.SetCatchBlock ();
-                               return Block.Resolve (ec);
+                               return Block.Resolve (bc);
                        }
                }
 
+               bool CreateExceptionVariable (TypeSpec type)
+               {
+                       if (!Block.HasAwait)
+                               return false;
+
+                       // TODO: Scan the block for rethrow expression
+                       //if (!Block.HasRethrow)
+                       //      return;
+
+                       li = LocalVariable.CreateCompilerGenerated (type, block, Location.Null);
+                       return true;
+               }
+
                protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
                {
-                       if (li != null) {
+                       if (li != null && !li.IsCompilerGenerated) {
                                fc.SetVariableAssigned (li.VariableInfo, true);
                        }
 
@@ -6374,6 +6543,10 @@ namespace Mono.CSharp {
                {
                        base.MarkReachable (rc);
 
+                       var c = Filter as Constant;
+                       if (c != null && c.IsDefaultValue)
+                               return Reachability.CreateUnreachable ();
+
                        return block.MarkReachable (rc);
                }
 
@@ -6384,6 +6557,9 @@ namespace Mono.CSharp {
                        if (type_expr != null)
                                target.type_expr = (FullNamedExpression) type_expr.Clone (clonectx);
 
+                       if (Filter != null)
+                               target.Filter = Filter.Clone (clonectx);
+
                        target.block = (ExplicitBlock) clonectx.LookupBlock (block);
                }
        }
@@ -6430,9 +6606,62 @@ namespace Mono.CSharp {
                        stmt.Emit (ec);
                }
 
+               protected override bool EmitBeginFinallyBlock (EmitContext ec)
+               {
+                       if (fini.HasAwait)
+                               return false;
+
+                       return base.EmitBeginFinallyBlock (ec);
+               }
+
                public override void EmitFinallyBody (EmitContext ec)
                {
+                       StackFieldExpr exception_field;
+
+                       if (fini.HasAwait) {
+                               //
+                               // Emits catch block like
+                               //
+                               // catch (object temp) {
+                               //      this.exception_field = temp;
+                               // }
+                               //
+                               var type = ec.BuiltinTypes.Object;
+                               ec.BeginCatchBlock (type);
+
+                               var temp = ec.GetTemporaryLocal (type);
+                               ec.Emit (OpCodes.Stloc, temp);
+
+                               exception_field = ec.GetTemporaryField (type);
+                               ec.EmitThis ();
+                               ec.Emit (OpCodes.Ldloc, temp);
+                               exception_field.EmitAssignFromStack (ec);
+
+                               ec.EndExceptionBlock ();
+
+                               ec.FreeTemporaryLocal (temp, type);
+                       } else {
+                               exception_field = null;
+                       }
+
                        fini.Emit (ec);
+
+                       if (exception_field != null) {
+                               //
+                               // Emits exception rethrow
+                               //
+                               // if (this.exception_field != null)
+                               //      throw this.exception_field;
+                               //
+                               exception_field.Emit (ec);
+                               var skip_throw = ec.DefineLabel ();
+                               ec.Emit (OpCodes.Brfalse_S, skip_throw);
+                               exception_field.Emit (ec);
+                               ec.Emit (OpCodes.Throw);
+                               ec.MarkLabel (skip_throw);
+
+                               exception_field.IsAvailableForReuse = true;
+                       }
                }
 
                protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
@@ -6496,6 +6725,7 @@ namespace Mono.CSharp {
                public Block Block;
                List<Catch> clauses;
                readonly bool inside_try_finally;
+               List<Catch> catch_sm;
 
                public TryCatch (Block block, List<Catch> catch_clauses, Location l, bool inside_try_finally)
                        : base (l)
@@ -6540,6 +6770,16 @@ namespace Mono.CSharp {
 
                                ok &= c.Resolve (bc);
 
+                               if (c.Block.HasAwait) {
+                                       if (catch_sm == null)
+                                               catch_sm = new List<Catch> ();
+
+                                       catch_sm.Add (c);
+                               }
+
+                               if (c.Filter != null)
+                                       continue;
+
                                TypeSpec resolved_type = c.CatchType;
                                if (resolved_type == null)
                                        continue;
@@ -6548,6 +6788,9 @@ namespace Mono.CSharp {
                                        if (ii == i)
                                                continue;
 
+                                       if (clauses[ii].Filter != null)
+                                               continue;
+
                                        if (clauses[ii].IsGeneral) {
                                                if (resolved_type.BuiltinType != BuiltinTypeSpec.Type.Exception)
                                                        continue;
@@ -6590,11 +6833,56 @@ namespace Mono.CSharp {
 
                        Block.Emit (ec);
 
-                       foreach (Catch c in clauses)
+                       LocalBuilder state_variable = null;
+                       foreach (Catch c in clauses) {
                                c.Emit (ec);
 
+                               if (catch_sm != null) {
+                                       if (state_variable == null)
+                                               state_variable = ec.GetTemporaryLocal (ec.Module.Compiler.BuiltinTypes.Int);
+
+                                       var index = catch_sm.IndexOf (c);
+                                       if (index < 0)
+                                               continue;
+
+                                       ec.EmitInt (index + 1);
+                                       ec.Emit (OpCodes.Stloc, state_variable);
+                               }
+                       }
+
                        if (!inside_try_finally)
                                ec.EndExceptionBlock ();
+
+                       if (state_variable != null) {
+                               ec.Emit (OpCodes.Ldloc, state_variable);
+
+                               var labels = new Label [catch_sm.Count + 1];
+                               for (int i = 0; i < labels.Length; ++i) {
+                                       labels [i] = ec.DefineLabel ();
+                               }
+
+                               var end = ec.DefineLabel ();
+                               ec.Emit (OpCodes.Switch, labels);
+
+                               // 0 value is default label
+                               ec.MarkLabel (labels [0]);
+                               ec.Emit (OpCodes.Br, end);
+
+                               var atv = ec.AsyncThrowVariable;
+                               Catch c = null;
+                               for (int i = 0; i < catch_sm.Count; ++i) {
+                                       if (c != null && c.Block.HasReachableClosingBrace)
+                                               ec.Emit (OpCodes.Br, end);
+
+                                       ec.MarkLabel (labels [i + 1]);
+                                       c = catch_sm [i];
+                                       ec.AsyncThrowVariable = c.Variable;
+                                       c.Block.Emit (ec);
+                               }
+                               ec.AsyncThrowVariable = atv;
+
+                               ec.MarkLabel (end);
+                       }
                }
 
                protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
@@ -6668,6 +6956,7 @@ namespace Mono.CSharp {
                        public VariableDeclaration (LocalVariable li, Location loc)
                                : base (li)
                        {
+                               reachable = true;
                                this.loc = loc;
                        }
 
@@ -6742,7 +7031,7 @@ namespace Mono.CSharp {
                        {
                                var type = li.Type;
 
-                               if (type.BuiltinType != BuiltinTypeSpec.Type.IDisposable && !type.ImplementsInterface (bc.BuiltinTypes.IDisposable, false)) {
+                               if (type.BuiltinType != BuiltinTypeSpec.Type.IDisposable && !CanConvertToIDisposable (bc, type)) {
                                        if (type.IsNullableType) {
                                                // it's handled in CreateDisposeCall
                                                return;
@@ -6759,6 +7048,16 @@ namespace Mono.CSharp {
                                }
                        }
 
+                       static bool CanConvertToIDisposable (BlockContext bc, TypeSpec type)
+                       {
+                               var target = bc.BuiltinTypes.IDisposable;
+                               var tp = type as TypeParameterSpec;
+                               if (tp != null)
+                                       return Convert.ImplicitTypeParameterConversion (null, tp, target) != null;
+
+                               return type.ImplementsInterface (target, false);
+                       }
+
                        protected virtual Statement CreateDisposeCall (BlockContext bc, LocalVariable lv)
                        {
                                var lvr = lv.CreateReferenceExpression (bc, lv.Location);
@@ -6779,7 +7078,7 @@ namespace Mono.CSharp {
                                Statement dispose = new StatementExpression (new Invocation (dispose_mg, null), Location.Null);
 
                                // Add conditional call when disposing possible null variable
-                               if (!type.IsStruct || type.IsNullableType)
+                               if (!TypeSpec.IsValueType (type) || type.IsNullableType)
                                        dispose = new If (new Binary (Binary.Operator.Inequality, lvr, new NullLiteral (loc)), dispose, dispose.loc);
 
                                return dispose;
@@ -6907,12 +7206,12 @@ namespace Mono.CSharp {
                                }
                        }
 
-                       base.Resolve (ec);
+                       var ok = base.Resolve (ec);
 
                        if (vr != null)
                                vr.IsLockedByStatement = vr_locked;
 
-                       return true;
+                       return ok;
                }
 
                protected override void CloneTo (CloneContext clonectx, Statement t)
@@ -7100,6 +7399,7 @@ namespace Mono.CSharp {
                                public RuntimeDispose (LocalVariable lv, Location loc)
                                        : base (lv, loc)
                                {
+                                       reachable = true;
                                }
 
                                protected override void CheckIDiposableConversion (BlockContext bc, LocalVariable li, Expression initializer)
@@ -7473,8 +7773,7 @@ namespace Mono.CSharp {
                                Statement = new CollectionForeach (this, variable, expr);
                        }
 
-                       base.Resolve (ec);
-                       return true;
+                       return base.Resolve (ec);
                }
 
                protected override void DoEmit (EmitContext ec)