2009-07-11 Michael Barker <mike@middlesoft.co.uk>
[mono.git] / mcs / mcs / statement.cs
index 63052ea98966ebb6f550dd386b8d573591f0c086..417830431dbf5bc64fe2e3fdf555152b2bd63f99 100644 (file)
@@ -1074,6 +1074,8 @@ namespace Mono.CSharp {
                                return false;
                        }
 
+                       ec.CurrentBranching.CurrentUsageVector.Goto ();
+
                        expr = expr.Resolve (ec);
                        if (expr == null)
                                return false;
@@ -1085,21 +1087,18 @@ namespace Mono.CSharp {
                        }
 
                        Type type = ec.Switch.SwitchType;
-                       if (!Convert.ImplicitStandardConversionExists (c, type))
-                               Report.Warning (469, 2, loc, "The `goto case' value is not implicitly " +
-                                               "convertible to type `{0}'", TypeManager.CSharpName (type));
-
-                       bool fail = false;
-                       object val = c.GetValue ();
-                       if ((val != null) && (c.Type != type) && (c.Type != TypeManager.object_type))
-                               val = TypeManager.ChangeType (val, type, out fail);
-
-                       if (fail) {
-                               Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
-                                             c.GetSignatureForError (), TypeManager.CSharpName (type));
+                       Constant res = c.TryReduce (ec, type, c.Location);
+                       if (res == null) {
+                               c.Error_ValueCannotBeConverted (ec, loc, type, true);
                                return false;
                        }
 
+                       if (!Convert.ImplicitStandardConversionExists (c, type))
+                               Report.Warning (469, 2, loc,
+                                       "The `goto case' value is not implicitly convertible to type `{0}'",
+                                       TypeManager.CSharpName (type));
+
+                       object val = res.GetValue ();
                        if (val == null)
                                val = SwitchLabel.NullStringCase;
                                        
@@ -1111,7 +1110,6 @@ namespace Mono.CSharp {
                                return false;
                        }
 
-                       ec.CurrentBranching.CurrentUsageVector.Goto ();
                        return true;
                }
 
@@ -1159,7 +1157,7 @@ namespace Mono.CSharp {
 
                        if ((t != TypeManager.exception_type) &&
                            !TypeManager.IsSubclassOf (t, TypeManager.exception_type) &&
-                           !(expr is NullLiteral)) {
+                           t != TypeManager.null_type) {
                                Error (155, "The type caught or thrown must be derived from System.Exception");
                                return false;
                        }
@@ -1272,7 +1270,7 @@ namespace Mono.CSharp {
        // The information about a user-perceived local variable
        //
        public class LocalInfo : IKnownVariable, ILocalVariable {
-               public readonly Expression Type;
+               public readonly FullNamedExpression Type;
 
                public Type VariableType;
                public readonly string Name;
@@ -1302,8 +1300,8 @@ namespace Mono.CSharp {
                Flags flags;
                ReadOnlyContext ro_context;
                LocalBuilder builder;
-               
-               public LocalInfo (Expression type, string name, Block block, Location l)
+
+               public LocalInfo (FullNamedExpression type, string name, Block block, Location l)
                {
                        Type = type;
                        Name = name;
@@ -1480,7 +1478,7 @@ namespace Mono.CSharp {
                        // Variables in anonymous block are not resolved yet
                        //
                        if (VariableType == null)
-                               return new LocalInfo (Type.Clone (clonectx), Name, clonectx.LookupBlock (Block), Location);
+                               return new LocalInfo ((FullNamedExpression) Type.Clone (clonectx), Name, clonectx.LookupBlock (Block), Location);
 
                        //
                        // Variables in method block are resolved
@@ -1519,10 +1517,10 @@ namespace Mono.CSharp {
                        BlockUsed = 2,
                        VariablesInitialized = 4,
                        HasRet = 8,
-                       IsDestructor = 16,
-                       Unsafe = 32,
-                       IsIterator = 64,
-                       HasStoreyAccess = 128
+                       Unsafe = 16,
+                       IsIterator = 32,
+                       HasCapturedVariable = 64,
+                       HasCapturedThis = 128
                }
                protected Flags flags;
 
@@ -1559,7 +1557,6 @@ namespace Mono.CSharp {
                // Keeps track of (name, type) pairs
                //
                IDictionary variables;
-               protected IDictionary range_variables;
 
                //
                // Keeps track of constants
@@ -1575,7 +1572,7 @@ namespace Mono.CSharp {
                //
                Block switch_block;
 
-               ArrayList scope_initializers;
+               protected ArrayList scope_initializers;
 
                ArrayList anonymous_children;
 
@@ -1599,6 +1596,20 @@ namespace Mono.CSharp {
                        : this (parent, (Flags) 0, start, end)
                { }
 
+               //
+               // Useful when TopLevel block is downgraded to normal block
+               //
+               public Block (ToplevelBlock parent, ToplevelBlock source)
+                       : this (parent, source.flags, source.StartLocation, source.EndLocation)
+               {
+                       statements = source.statements;
+                       children = source.children;
+                       labels = source.labels;
+                       variables = source.variables;
+                       constants = source.constants;
+                       switch_block = source.switch_block;
+               }
+
                public Block (Block parent, Flags flags, Location start, Location end)
                {
                        if (parent != null) {
@@ -1811,35 +1822,45 @@ namespace Mono.CSharp {
                        return false;
                }
 
-               public LocalInfo AddVariable (Expression type, string name, Location l)
+               protected virtual bool CheckParentConflictName (ToplevelBlock block, string name, Location l)
                {
                        LocalInfo vi = GetLocalInfo (name);
                        if (vi != null) {
                                Report.SymbolRelatedToPreviousError (vi.Location, name);
                                if (Explicit == vi.Block.Explicit) {
-                                       if (type == Linq.ImplicitQueryParameter.ImplicitType.Instance && type == vi.Type)
-                                               Error_AlreadyDeclared (l, name);
-                                       else
-                                               Error_AlreadyDeclared (l, name, null);
+                                       Error_AlreadyDeclared (l, name, null);
                                } else {
-                                       Error_AlreadyDeclared (l, name, "parent");
+                                       Error_AlreadyDeclared (l, name, this is ToplevelBlock ?
+                                               "parent or current" : "parent");
                                }
-                               return null;
+                               return false;
                        }
 
-                       ToplevelParameterInfo pi = Toplevel.GetParameterInfo (name);
-                       if (pi != null) {
-                               Report.SymbolRelatedToPreviousError (pi.Location, name);
-                               Error_AlreadyDeclared (loc, name,
-                                       pi.Block == Toplevel ? "method argument" : "parent or current");
-                               return null;
+                       if (block != null) {
+                               Expression e = block.GetParameterReference (name, Location.Null);
+                               if (e != null) {
+                                       ParameterReference pr = e as ParameterReference;
+                                       if (this is Linq.QueryBlock && (pr != null && pr.Parameter is Linq.QueryBlock.ImplicitQueryParameter || e is MemberAccess))
+                                               Error_AlreadyDeclared (loc, name);
+                                       else
+                                               Error_AlreadyDeclared (loc, name, "parent or current");
+                                       return false;
+                               }
                        }
-                       
+
+                       return true;
+               }
+
+               public LocalInfo AddVariable (Expression type, string name, Location l)
+               {
+                       if (!CheckParentConflictName (Toplevel, name, l))
+                               return null;
+
                        if (Toplevel.GenericMethod != null) {
                                foreach (TypeParameter tp in Toplevel.GenericMethod.CurrentTypeParameters) {
                                        if (tp.Name == name) {
                                                Report.SymbolRelatedToPreviousError (tp);
-                                               Error_AlreadyDeclaredTypeParameter (loc, name);
+                                               Error_AlreadyDeclaredTypeParameter (loc, name, "local variable");
                                                return null;
                                        }
                                }
@@ -1852,7 +1873,7 @@ namespace Mono.CSharp {
                                return null;
                        }
 
-                       vi = new LocalInfo (type, name, this, l);
+                       LocalInfo vi = new LocalInfo ((FullNamedExpression) type, name, this, l);
                        AddVariable (vi);
 
                        if ((flags & Flags.VariablesInitialized) != 0)
@@ -1886,10 +1907,11 @@ namespace Mono.CSharp {
                                "A local variable named `{0}' is already defined in this scope", name);
                }
                                        
-               protected virtual void Error_AlreadyDeclaredTypeParameter (Location loc, string name)
+               public virtual void Error_AlreadyDeclaredTypeParameter (Location loc, string name, string conflict)
                {
-                       GenericMethod.Error_ParameterNameCollision (loc, name, "local variable");
-               }                                       
+                       Report.Error (412, loc, "The type parameter name `{0}' is the same as `{1}'",
+                               name, conflict);
+               }
 
                public bool AddConstant (Expression type, string name, Expression value, Location l)
                {
@@ -1933,12 +1955,6 @@ namespace Mono.CSharp {
                                        if (ret != null)
                                                return ret;
                                }
-
-                               if (b.range_variables != null) {
-                                       ret = (LocalInfo) b.range_variables [name];
-                                       if (ret != null)
-                                               return ret;
-                               }
                        }
 
                        return null;
@@ -1966,7 +1982,7 @@ namespace Mono.CSharp {
                // It should be used by expressions which require to
                // register a statement during resolve process.
                //
-               public void AddScopeStatement (StatementExpression s)
+               public void AddScopeStatement (Statement s)
                {
                        if (scope_initializers == null)
                                scope_initializers = new ArrayList ();
@@ -1993,15 +2009,6 @@ namespace Mono.CSharp {
                        get { return (flags & Flags.HasRet) != 0; }
                }
 
-               public bool IsDestructor {
-                       get { return (flags & Flags.IsDestructor) != 0; }
-               }
-
-               public void SetDestructor ()
-               {
-                       flags |= Flags.IsDestructor;
-               }
-
                public int AssignableSlots {
                        get {
 // TODO: Re-enable                     
@@ -2313,16 +2320,8 @@ namespace Mono.CSharp {
                        Block prev_block = ec.CurrentBlock;
                        ec.CurrentBlock = this;
 
-                       if (scope_initializers != null) {
-                               SymbolWriter.OpenCompilerGeneratedBlock (ec.ig);
-
-                               using (ec.Set (EmitContext.Flags.OmitDebuggingInfo)) {
-                                       foreach (StatementExpression s in scope_initializers)
-                                               s.Emit (ec);
-                               }
-
-                               SymbolWriter.CloseCompilerGeneratedBlock (ec.ig);
-                       }
+                       if (scope_initializers != null)
+                               EmitScopeInitializers (ec);
 
                        ec.Mark (StartLocation);
                        DoEmit (ec);
@@ -2333,6 +2332,18 @@ namespace Mono.CSharp {
                        ec.CurrentBlock = prev_block;
                }
 
+               protected void EmitScopeInitializers (EmitContext ec)
+               {
+                       SymbolWriter.OpenCompilerGeneratedBlock (ec.ig);
+
+                       using (ec.Set (EmitContext.Flags.OmitDebuggingInfo)) {
+                               foreach (Statement s in scope_initializers)
+                                       s.Emit (ec);
+                       }
+
+                       SymbolWriter.CloseCompilerGeneratedBlock (ec.ig);
+               }
+
                protected virtual void EmitSymbolInfo (EmitContext ec)
                {
                        if (variables != null) {
@@ -2456,7 +2467,6 @@ namespace Mono.CSharp {
                        // When referencing a variable in iterator storey from children anonymous method
                        //
                        if (Toplevel.am_storey is IteratorStorey) {
-                               ec.CurrentAnonymousMethod.AddStoreyReference (Toplevel.am_storey);
                                return Toplevel.am_storey;
                        }
 
@@ -2471,26 +2481,18 @@ namespace Mono.CSharp {
                                GenericMethod gm = mc == null ? null : mc.GenericMethod;
 
                                //
-                               // Create anonymous method storey for this block
+                               // Creates anonymous method storey for this block
                                //
                                am_storey = new AnonymousMethodStorey (this, ec.TypeContainer, mc, gm, "AnonStorey");
                        }
 
-                       //
-                       // Creates a link between this block and the anonymous method
-                       //
-                       // An anonymous method can reference variables from any outer block, but they are
-                       // hoisted in their own ExplicitBlock. When more than one block is referenced we
-                       // need to create another link between those variable storeys
-                       //
-                       ec.CurrentAnonymousMethod.AddStoreyReference (am_storey);
                        return am_storey;
                }
 
                public override void Emit (EmitContext ec)
                {
                        if (am_storey != null)
-                               am_storey.EmitHoistedVariables (ec);
+                               am_storey.EmitStoreyInstantiation (ec);
 
                        bool emit_debug_info = SymbolWriter.HasSymbolWriter && Parent != null && !(am_storey is IteratorStorey);
                        if (emit_debug_info)
@@ -2509,13 +2511,46 @@ namespace Mono.CSharp {
                        //
                        if (am_storey != null) {
                                if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod.Storey != null) {
+                                       //
+                                       // Creates parent storey reference when hoisted this is accessible
+                                       //
+                                       if (am_storey.OriginalSourceBlock.Explicit.HasCapturedThis) {
+                                               ExplicitBlock parent = Toplevel.Parent.Explicit;
+
+                                               //
+                                               // Hoisted this exists in top-level parent storey only
+                                               //
+                                               while (parent.am_storey == null || parent.am_storey.Parent is AnonymousMethodStorey)
+                                                       parent = parent.Parent.Explicit;
+
+                                               am_storey.AddParentStoreyReference (parent.am_storey);
+                                       }
+
                                        am_storey.ChangeParentStorey (ec.CurrentAnonymousMethod.Storey);
                                }
 
                                am_storey.DefineType ();
-                               am_storey.ResolveType ();                               
+                               am_storey.ResolveType ();
                                am_storey.Define ();
                                am_storey.Parent.PartialContainer.AddCompilerGeneratedClass (am_storey);
+
+                               ArrayList ref_blocks = am_storey.ReferencesFromChildrenBlock;
+                               if (ref_blocks != null) {
+                                       foreach (ExplicitBlock ref_block in ref_blocks) {
+                                               for (ExplicitBlock b = ref_block.Explicit; b != this; b = b.Parent.Explicit) {
+                                                       if (b.am_storey != null) {
+                                                               b.am_storey.AddParentStoreyReference (am_storey);
+
+                                                               // Stop propagation inside same top block
+                                                               if (b.Toplevel == Toplevel)
+                                                                       break;
+
+                                                               b = b.Toplevel;
+                                                   }
+                                                       b.HasCapturedVariable = true;
+                                               }
+                                       }
+                               }
                        }
 
                        base.EmitMeta (ec);
@@ -2526,29 +2561,16 @@ namespace Mono.CSharp {
                        return known_variables == null ? null : (IKnownVariable) known_variables [name];
                }
 
-               public void PropagateStoreyReference (AnonymousMethodStorey s)
+               public bool HasCapturedThis
                {
-                       if (Parent != null && am_storey != s) {
-                               if (am_storey != null)
-                                       am_storey.AddParentStoreyReference (s);
-
-                               Parent.Explicit.PropagateStoreyReference (s);
-                       }
+                       set { flags = value ? flags | Flags.HasCapturedThis : flags & ~Flags.HasCapturedThis; }
+                       get { return (flags & Flags.HasCapturedThis) != 0; }
                }
 
-               public override bool Resolve (EmitContext ec)
+               public bool HasCapturedVariable
                {
-                       bool ok = base.Resolve (ec);
-
-                       //
-                       // Discard an anonymous method storey when this block has no hoisted variables
-                       //
-                       if (am_storey != null && !am_storey.HasHoistedVariables) {
-                               am_storey.Undo ();
-                               am_storey = null;
-                       }
-
-                       return ok;
+                       set { flags = value ? flags | Flags.HasCapturedVariable : flags & ~Flags.HasCapturedVariable; }
+                       get { return (flags & Flags.HasCapturedVariable) != 0; }
                }
 
                protected override void CloneTo (CloneContext clonectx, Statement t)
@@ -2594,10 +2616,60 @@ namespace Mono.CSharp {
        // In particular, this was introduced when the support for Anonymous
        // Methods was implemented. 
        // 
-       public class ToplevelBlock : ExplicitBlock {
+       public class ToplevelBlock : ExplicitBlock
+       {
+               // 
+               // Block is converted to an expression
+               //
+               sealed class BlockScopeExpression : Expression
+               {
+                       Expression child;
+                       readonly ToplevelBlock block;
+
+                       public BlockScopeExpression (Expression child, ToplevelBlock block)
+                       {
+                               this.child = child;
+                               this.block = block;
+                       }
+
+                       public override Expression CreateExpressionTree (EmitContext ec)
+                       {
+                               throw new NotSupportedException ();
+                       }
+
+                       public override Expression DoResolve (EmitContext ec)
+                       {
+                               if (child == null)
+                                       return null;
+                               
+                               block.ResolveMeta (ec, ParametersCompiled.EmptyReadOnlyParameters);
+                               child = child.Resolve (ec);
+                               if (child == null)
+                                       return null;
+
+                               eclass = child.eclass;
+                               type = child.Type;
+                               return this;
+                       }
+
+                       public override void Emit (EmitContext ec)
+                       {
+                               block.EmitMeta (ec);
+                               block.EmitScopeInitializers (ec);
+                               child.Emit (ec);
+                       }
+
+                       public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+                       {
+                               type = storey.MutateType (type);
+                               child.MutateHoistedGenericType (storey);
+                               block.MutateHoistedGenericType (storey);
+                       }
+               }
+
                GenericMethod generic;
                FlowBranchingToplevel top_level_branching;
-               Parameters parameters;
+               protected ParametersCompiled parameters;
                ToplevelParameterInfo[] parameter_info;
                LocalInfo this_variable;
 
@@ -2606,7 +2678,7 @@ namespace Mono.CSharp {
                //
                // The parameters for the block.
                //
-               public Parameters Parameters {
+               public ParametersCompiled Parameters {
                        get { return parameters; }
                }
 
@@ -2614,44 +2686,39 @@ namespace Mono.CSharp {
                        get { return generic; }
                }
 
-               public bool HasStoreyAccess {
-                       set { flags = value ? flags | Flags.HasStoreyAccess : flags & ~Flags.HasStoreyAccess; }
-                       get { return (flags & Flags.HasStoreyAccess) != 0;  }
-               }
-
                public ToplevelBlock Container {
                        get { return Parent == null ? null : Parent.Toplevel; }
                }
 
-               public ToplevelBlock (Block parent, Parameters parameters, Location start) :
+               public ToplevelBlock (Block parent, ParametersCompiled parameters, Location start) :
                        this (parent, (Flags) 0, parameters, start)
                {
                }
 
-               public ToplevelBlock (Block parent, Parameters parameters, GenericMethod generic, Location start) :
+               public ToplevelBlock (Block parent, ParametersCompiled parameters, GenericMethod generic, Location start) :
                        this (parent, parameters, start)
                {
                        this.generic = generic;
                }
                
-               public ToplevelBlock (Parameters parameters, Location start) :
+               public ToplevelBlock (ParametersCompiled parameters, Location start) :
                        this (null, (Flags) 0, parameters, start)
                {
                }
 
-               ToplevelBlock (Flags flags, Parameters parameters, Location start) :
+               ToplevelBlock (Flags flags, ParametersCompiled parameters, Location start) :
                        this (null, flags, parameters, start)
                {
                }
 
                // We use 'Parent' to hook up to the containing block, but don't want to register the current block as a child.
                // So, we use a two-stage setup -- first pass a null parent to the base constructor, and then override 'Parent'.
-               public ToplevelBlock (Block parent, Flags flags, Parameters parameters, Location start) :
+               public ToplevelBlock (Block parent, Flags flags, ParametersCompiled parameters, Location start) :
                        base (null, flags, start, Location.Null)
                {
                        this.Toplevel = this;
 
-                       this.parameters = parameters == null ? Parameters.EmptyReadOnlyParameters : parameters;
+                       this.parameters = parameters;
                        this.Parent = parent;
                        if (parent != null)
                                parent.AddAnonymousChild (this);
@@ -2660,7 +2727,8 @@ namespace Mono.CSharp {
                                ProcessParameters ();
                }
 
-               public ToplevelBlock (Location loc) : this (null, (Flags) 0, null, loc)
+               public ToplevelBlock (Location loc)
+                       : this (null, (Flags) 0, ParametersCompiled.EmptyReadOnlyParameters, loc)
                {
                }
 
@@ -2692,15 +2760,11 @@ namespace Mono.CSharp {
                        return true;
                }
 
-               public virtual Expression GetTransparentIdentifier (string name)
-               {
-                       return null;
-               }
-
                void ProcessParameters ()
                {
                        int n = parameters.Count;
                        parameter_info = new ToplevelParameterInfo [n];
+                       ToplevelBlock top_parent = Parent == null ? null : Parent.Toplevel;
                        for (int i = 0; i < n; ++i) {
                                parameter_info [i] = new ToplevelParameterInfo (this, i);
 
@@ -2709,21 +2773,8 @@ namespace Mono.CSharp {
                                        continue;
 
                                string name = p.Name;
-                               LocalInfo vi = GetLocalInfo (name);
-                               if (vi != null) {
-                                       Report.SymbolRelatedToPreviousError (vi.Location, name);
-                                       Error_AlreadyDeclared (loc, name, "parent or current");
-                                       continue;
-                               }
-
-                               ToplevelParameterInfo pi = Parent == null ? null : Parent.Toplevel.GetParameterInfo (name);
-                               if (pi != null) {
-                                       Report.SymbolRelatedToPreviousError (pi.Location, name);
-                                       Error_AlreadyDeclared (loc, name, "parent or current");
-                                       continue;
-                               }
-
-                               AddKnownVariable (name, parameter_info [i]);
+                               if (CheckParentConflictName (top_parent, name, loc))
+                                       AddKnownVariable (name, parameter_info [i]);
                        }
 
                        // mark this block as "used" so that we create local declarations in a sub-block
@@ -2745,8 +2796,13 @@ namespace Mono.CSharp {
 
                public override Expression CreateExpressionTree (EmitContext ec)
                {
-                       if (statements.Count == 1)
-                               return ((Statement) statements [0]).CreateExpressionTree (ec);
+                       if (statements.Count == 1) {
+                               Expression expr = ((Statement) statements[0]).CreateExpressionTree (ec);
+                               if (scope_initializers != null)
+                                       expr = new BlockScopeExpression (expr, this);
+
+                               return expr;
+                       }
 
                        return base.CreateExpressionTree (ec);
                }
@@ -2756,16 +2812,10 @@ namespace Mono.CSharp {
                //
                public IteratorStorey ChangeToIterator (Iterator iterator, ToplevelBlock source)
                {
-                       // Create block with original statements
-                       ExplicitBlock iter_block = new ExplicitBlock (this, flags, StartLocation, EndLocation);
                        IsIterator = true;
 
-                       // TODO: Change to iter_block.statements = statements;
-                       foreach (Statement stmt in source.statements)
-                               iter_block.AddStatement (stmt);
-                       labels = source.labels;
-                       
-                       AddStatement (new IteratorStatement (iterator, iter_block));
+                       // Creates block with original statements
+                       AddStatement (new IteratorStatement (iterator, new Block (this, source)));
 
                        source.statements = new ArrayList (1);
                        source.AddStatement (new Return (iterator, iterator.Location));
@@ -2781,26 +2831,27 @@ namespace Mono.CSharp {
                }
 
                //
-               // Returns a `ParameterReference' for the given name, or null if there
-               // is no such parameter
+               // Returns a parameter reference expression for the given name,
+               // or null if there is no such parameter
                //
-               public ParameterReference GetParameterReference (string name, Location loc)
+               public Expression GetParameterReference (string name, Location loc)
                {
-                       ToplevelParameterInfo p = GetParameterInfo (name);
-                       return p == null ? null : new ParameterReference (this, p, loc);
-               }
-
-               public ToplevelParameterInfo GetParameterInfo (string name)
-               {
-                       int idx;
                        for (ToplevelBlock t = this; t != null; t = t.Container) {
-                               Parameter par = t.Parameters.GetParameterByName (name, out idx);
-                               if (par != null)
-                                       return t.parameter_info [idx];
+                               Expression expr = t.GetParameterReferenceExpression (name, loc);
+                               if (expr != null)
+                                       return expr;
                        }
+
                        return null;
                }
 
+               protected virtual Expression GetParameterReferenceExpression (string name, Location loc)
+               {
+                       int idx = parameters.GetParameterIndexByName (name);
+                       return idx < 0 ?
+                               null : new ParameterReference (parameter_info [idx], loc);
+               }
+
                // <summary>
                //   Returns the "this" instance variable of this block.
                //   See AddThisVariable() for more information.
@@ -2839,7 +2890,7 @@ namespace Mono.CSharp {
                        return this_variable == null || this_variable.IsThisAssigned (ec);
                }
 
-               public bool ResolveMeta (EmitContext ec, Parameters ip)
+               public bool ResolveMeta (EmitContext ec, ParametersCompiled ip)
                {
                        int errors = Report.Errors;
                        int orig_count = parameters.Count;
@@ -3086,20 +3137,14 @@ namespace Mono.CSharp {
                FieldExpr switch_cache_field;
                static int unique_counter;
 
-#if GMCS_SOURCE
                //
-               // Nullable Types support for GMCS.
+               // Nullable Types support
                //
                Nullable.Unwrap unwrap;
 
                protected bool HaveUnwrap {
                        get { return unwrap != null; }
                }
-#else
-               protected bool HaveUnwrap {
-                       get { return false; }
-               }
-#endif
 
                //
                // The types allowed to be implicitly cast from
@@ -3551,6 +3596,7 @@ namespace Mono.CSharp {
                public static void Reset ()
                {
                        unique_counter = 0;
+                       allowed_types = null;
                }
 
                public override bool Resolve (EmitContext ec)
@@ -3561,18 +3607,18 @@ namespace Mono.CSharp {
 
                        new_expr = SwitchGoverningType (ec, Expr);
 
-#if GMCS_SOURCE
                        if ((new_expr == null) && TypeManager.IsNullableType (Expr.Type)) {
-                               unwrap = Nullable.Unwrap.Create (Expr, ec);
+                               unwrap = Nullable.Unwrap.Create (Expr, false);
                                if (unwrap == null)
                                        return false;
 
                                new_expr = SwitchGoverningType (ec, unwrap);
                        }
-#endif
 
                        if (new_expr == null){
-                               Report.Error (151, loc, "A value of an integral type or string expected for switch");
+                               Report.Error (151, loc,
+                                       "A switch expression of type `{0}' cannot be converted to an integral type, bool, char, string, enum or nullable type",
+                                       TypeManager.CSharpName (Expr.Type));
                                return false;
                        }
 
@@ -3653,20 +3699,21 @@ namespace Mono.CSharp {
                void ResolveStringSwitchMap (EmitContext ec)
                {
                        FullNamedExpression string_dictionary_type;
-#if GMCS_SOURCE
-                       MemberAccess system_collections_generic = new MemberAccess (new MemberAccess (
-                               new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Collections", loc), "Generic", loc);
-
-                       string_dictionary_type = new MemberAccess (system_collections_generic, "Dictionary",
-                               new TypeArguments (loc,
-                                       new TypeExpression (TypeManager.string_type, loc),
-                                       new TypeExpression (TypeManager.int32_type, loc)), loc);
-#else
-                       MemberAccess system_collections_generic = new MemberAccess (
-                               new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Collections", loc);
-
-                       string_dictionary_type = new MemberAccess (system_collections_generic, "Hashtable", loc);
-#endif
+                       if (TypeManager.generic_ienumerable_type != null) {
+                               MemberAccess system_collections_generic = new MemberAccess (new MemberAccess (
+                                       new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Collections", loc), "Generic", loc);
+
+                               string_dictionary_type = new MemberAccess (system_collections_generic, "Dictionary",
+                                       new TypeArguments (
+                                               new TypeExpression (TypeManager.string_type, loc),
+                                               new TypeExpression (TypeManager.int32_type, loc)), loc);
+                       } else {
+                               MemberAccess system_collections_generic = new MemberAccess (
+                                       new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Collections", loc);
+
+                               string_dictionary_type = new MemberAccess (system_collections_generic, "Hashtable", loc);
+                       }
+
                        Field field = new Field (ec.TypeContainer, string_dictionary_type,
                                Modifiers.STATIC | Modifiers.PRIVATE | Modifiers.COMPILER_GENERATED,
                                new MemberName (CompilerGeneratedClass.MakeName (null, "f", "switch$map", unique_counter++), loc), null);
@@ -3679,11 +3726,10 @@ namespace Mono.CSharp {
                        Elements.Clear ();
                        string value = null;
                        foreach (SwitchSection section in Sections) {
+                               int last_count = init.Count;
                                foreach (SwitchLabel sl in section.Labels) {
-                                       if (sl.Label == null || sl.Converted == SwitchLabel.NullStringCase) {
-                                               value = null;
+                                       if (sl.Label == null || sl.Converted == SwitchLabel.NullStringCase)
                                                continue;
-                                       }
 
                                        value = (string) sl.Converted;
                                        ArrayList init_args = new ArrayList (2);
@@ -3692,15 +3738,18 @@ namespace Mono.CSharp {
                                        init.Add (new CollectionElementInitializer (init_args, loc));
                                }
 
-                               if (value == null)
+                               //
+                               // Don't add empty sections
+                               //
+                               if (last_count == init.Count)
                                        continue;
 
                                Elements.Add (counter, section.Labels [0]);
                                ++counter;
                        }
 
-                       ArrayList args = new ArrayList (1);
-                       args.Add (new Argument (new IntConstant (Sections.Count, loc)));
+                       Arguments args = new Arguments (1);
+                       args.Add (new Argument (new IntConstant (init.Count, loc)));
                        Expression initializer = new NewInitialize (string_dictionary_type, args,
                                new CollectionOrObjectInitializers (init, loc), loc);
 
@@ -3727,36 +3776,37 @@ namespace Mono.CSharp {
 
                        LocalTemporary string_switch_variable = new LocalTemporary (TypeManager.int32_type);
 
-#if GMCS_SOURCE
-                       ArrayList get_value_args = new ArrayList (2);
-                       get_value_args.Add (new Argument (value));
-                       get_value_args.Add (new Argument (string_switch_variable, Argument.AType.Out));
-                       Expression get_item = new Invocation (new MemberAccess (switch_cache_field, "TryGetValue", loc), get_value_args).Resolve (ec);
-                       if (get_item == null)
-                               return;
+                       if (TypeManager.generic_ienumerable_type != null) {
+                               Arguments get_value_args = new Arguments (2);
+                               get_value_args.Add (new Argument (value));
+                               get_value_args.Add (new Argument (string_switch_variable, Argument.AType.Out));
+                               Expression get_item = new Invocation (new MemberAccess (switch_cache_field, "TryGetValue", loc), get_value_args).Resolve (ec);
+                               if (get_item == null)
+                                       return;
 
-                       //
-                       // A value was not found, go to default case
-                       //
-                       get_item.EmitBranchable (ec, default_target, false);
-#else
-                       ArrayList get_value_args = new ArrayList (1);
-                       get_value_args.Add (value);
+                               //
+                               // A value was not found, go to default case
+                               //
+                               get_item.EmitBranchable (ec, default_target, false);
+                       } else {
+                               Arguments get_value_args = new Arguments (1);
+                               get_value_args.Add (new Argument (value));
 
-                       Expression get_item = new IndexerAccess (new ElementAccess (switch_cache_field, get_value_args), loc).Resolve (ec);
-                       if (get_item == null)
-                               return;
+                               Expression get_item = new IndexerAccess (new ElementAccess (switch_cache_field, get_value_args), loc).Resolve (ec);
+                               if (get_item == null)
+                                       return;
 
-                       LocalTemporary get_item_object = new LocalTemporary (TypeManager.object_type);
-                       get_item_object.EmitAssign (ec, get_item, true, false);
-                       ec.ig.Emit (OpCodes.Brfalse, default_target);
+                               LocalTemporary get_item_object = new LocalTemporary (TypeManager.object_type);
+                               get_item_object.EmitAssign (ec, get_item, true, false);
+                               ec.ig.Emit (OpCodes.Brfalse, default_target);
 
-                       ExpressionStatement get_item_int = (ExpressionStatement) new SimpleAssign (string_switch_variable,
-                               new Cast (new TypeExpression (TypeManager.int32_type, loc), get_item_object, loc)).Resolve (ec);
+                               ExpressionStatement get_item_int = (ExpressionStatement) new SimpleAssign (string_switch_variable,
+                                       new Cast (new TypeExpression (TypeManager.int32_type, loc), get_item_object, loc)).Resolve (ec);
+
+                               get_item_int.EmitStatement (ec);
+                               get_item_object.Release (ec);
+                       }
 
-                       get_item_int.EmitStatement (ec);
-                       get_item_object.Release (ec);
-#endif
                        TableSwitchEmit (ec, string_switch_variable);
                        string_switch_variable.Release (ec);
                }
@@ -3773,12 +3823,10 @@ namespace Mono.CSharp {
                        LocalTemporary value;
                        if (HaveUnwrap) {
                                value = new LocalTemporary (SwitchType);
-#if GMCS_SOURCE
                                unwrap.EmitCheck (ec);
                                ig.Emit (OpCodes.Brfalse, null_target);
                                new_expr.Emit (ec);
                                value.Store (ec);
-#endif
                        } else if (!is_constant) {
                                value = new LocalTemporary (SwitchType);
                                new_expr.Emit (ec);
@@ -4029,7 +4077,7 @@ namespace Mono.CSharp {
                        if (expr == null)
                                return false;
 
-                       if (expr.Type.IsValueType){
+                       if (!TypeManager.IsReferenceType (expr.Type)){
                                Report.Error (185, loc,
                                              "`{0}' is not a reference type as required by the lock statement",
                                              TypeManager.CSharpName (expr.Type));
@@ -4248,81 +4296,51 @@ namespace Mono.CSharp {
                        }
                }
 
-               class StringEmitter : Emitter {
-                       class StringPtr : Expression
-                       {
-                               LocalBuilder b;
-
-                               public StringPtr (LocalBuilder b, Location l)
-                               {
-                                       this.b = b;
-                                       eclass = ExprClass.Value;
-                                       type = TypeManager.char_ptr_type;
-                                       loc = l;
-                               }
-
-                               public override Expression CreateExpressionTree (EmitContext ec)
-                               {
-                                       throw new NotSupportedException ("ET");
-                               }
-
-                               public override Expression DoResolve (EmitContext ec)
-                               {
-                                       // This should never be invoked, we are born in fully
-                                       // initialized state.
-
-                                       return this;
-                               }
-
-                               public override void Emit (EmitContext ec)
-                               {
-                                       if (TypeManager.int_get_offset_to_string_data == null) {
-                                               // TODO: Move to resolve !!
-                                               TypeManager.int_get_offset_to_string_data = TypeManager.GetPredefinedMethod (
-                                                       TypeManager.runtime_helpers_type, "get_OffsetToStringData", loc, Type.EmptyTypes);
-                                       }
-
-                                       ILGenerator ig = ec.ig;
-
-                                       ig.Emit (OpCodes.Ldloc, b);
-                                       ig.Emit (OpCodes.Conv_I);
-                                       ig.Emit (OpCodes.Call, TypeManager.int_get_offset_to_string_data);
-                                       ig.Emit (OpCodes.Add);
-                               }
-                       }
-
-                       LocalBuilder pinned_string;
-                       Location loc;
+               class StringEmitter : Emitter
+               {
+                       LocalInfo pinned_string;
 
                        public StringEmitter (Expression expr, LocalInfo li, Location loc):
                                base (expr, li)
                        {
-                               this.loc = loc;
+                               pinned_string = new LocalInfo (new TypeExpression (TypeManager.string_type, loc), null, null, loc);
+                               pinned_string.Pinned = true;
                        }
 
                        public override void Emit (EmitContext ec)
                        {
-                               ILGenerator ig = ec.ig;
-                               pinned_string = TypeManager.DeclareLocalPinned (ig, TypeManager.string_type);
-                                       
+                               pinned_string.Resolve (ec);
+                               pinned_string.ResolveVariable (ec);
+
                                converted.Emit (ec);
-                               ig.Emit (OpCodes.Stloc, pinned_string);
+                               pinned_string.EmitAssign (ec);
 
-                               Expression sptr = new StringPtr (pinned_string, loc);
-                               converted = Convert.ImplicitConversionRequired (
-                                       ec, sptr, vi.VariableType, loc);
-                                       
-                               if (converted == null)
-                                       return;
+                               PropertyInfo p = TypeManager.int_get_offset_to_string_data;
+                               if (p == null) {
+                                       // TODO: Move to resolve
+                                       p = TypeManager.int_get_offset_to_string_data = TypeManager.GetPredefinedProperty (
+                                               TypeManager.runtime_helpers_type, "OffsetToStringData", pinned_string.Location, TypeManager.int32_type);
 
-                               converted.Emit (ec);
+                                       if (p == null)
+                                               return;
+                               }
+
+                               // TODO: Should use Binary::Add
+                               pinned_string.Emit (ec);
+                               ec.ig.Emit (OpCodes.Conv_I);
+
+                               PropertyExpr pe = new PropertyExpr (pinned_string.VariableType, p, pinned_string.Location);
+                               //pe.InstanceExpression = pinned_string;
+                               pe.Resolve (ec).Emit (ec);
+
+                               ec.ig.Emit (OpCodes.Add);
                                vi.EmitAssign (ec);
                        }
 
                        public override void EmitExit (EmitContext ec)
                        {
                                ec.ig.Emit (OpCodes.Ldnull);
-                               ec.ig.Emit (OpCodes.Stloc, pinned_string);
+                               pinned_string.EmitAssign (ec);
                        }
                }
 
@@ -4560,6 +4578,12 @@ namespace Mono.CSharp {
                                // TODO: Move to resolve
                                LocalVariableReference lvr = new LocalVariableReference (Block, Name, loc);
                                lvr.Resolve (ec);
+                               
+#if GMCS_SOURCE
+                               // Only to make verifier happy
+                               if (TypeManager.IsGenericParameter (lvr.Type))
+                                       ig.Emit (OpCodes.Unbox_Any, lvr.Type);
+#endif
 
                                Expression source;
                                if (lvr.IsHoisted) {
@@ -4747,7 +4771,9 @@ namespace Mono.CSharp {
                                Type resolved_type = c.CatchType;
                                for (int ii = 0; ii < last_index; ++ii) {
                                        if (resolved_type == prev_catches [ii] || TypeManager.IsSubclassOf (resolved_type, prev_catches [ii])) {
-                                               Report.Error (160, c.loc, "A previous catch clause already catches all exceptions of this or a super type `{0}'", prev_catches [ii].FullName);
+                                               Report.Error (160, c.loc,
+                                                       "A previous catch clause already catches all exceptions of this or a super type `{0}'",
+                                                       TypeManager.CSharpName (prev_catches [ii]));
                                                ok = false;
                                        }
                                }
@@ -4758,7 +4784,7 @@ namespace Mono.CSharp {
                        if (General != null) {
                                if (CodeGen.Assembly.WrapNonExceptionThrows) {
                                        foreach (Catch c in Specific){
-                                               if (c.CatchType == TypeManager.exception_type) {
+                                               if (c.CatchType == TypeManager.exception_type && PredefinedAttributes.Get.RuntimeCompatibility.IsDefined) {
                                                        Report.Warning (1058, 1, c.loc, "A previous catch clause already catches all exceptions. All non-exceptions thrown will be wrapped in a `System.Runtime.CompilerServices.RuntimeWrappedException'");
                                                }
                                        }
@@ -4831,6 +4857,7 @@ namespace Mono.CSharp {
                }
        }
 
+       // FIXME: Why is it almost exact copy of Using ??
        public class UsingTemporary : ExceptionStatement {
                TemporaryVariable local_copy;
                public Statement Statement;
@@ -4891,7 +4918,7 @@ namespace Mono.CSharp {
                protected override void EmitFinallyBody (EmitContext ec)
                {
                        ILGenerator ig = ec.ig;
-                       if (!expr_type.IsValueType) {
+                       if (!TypeManager.IsStruct (expr_type)) {
                                Label skip = ig.DefineLabel ();
                                local_copy.Emit (ec);
                                ig.Emit (OpCodes.Brfalse, skip);
@@ -4955,7 +4982,6 @@ namespace Mono.CSharp {
                Expression var;
                Expression init;
 
-               Expression converted_var;
                ExpressionStatement assign;
 
                public Using (Expression var, Expression init, Statement stmt, Location l)
@@ -4966,31 +4992,6 @@ namespace Mono.CSharp {
                        loc = l;
                }
 
-               bool ResolveVariable (EmitContext ec)
-               {
-                       ExpressionStatement a = new SimpleAssign (var, init, loc);
-                       a = a.ResolveStatement (ec);
-                       if (a == null)
-                               return false;
-
-                       assign = a;
-
-                       if (TypeManager.ImplementsInterface (a.Type, TypeManager.idisposable_type)) {
-                               converted_var = var;
-                               return true;
-                       }
-
-                       Expression e = Convert.ImplicitConversionStandard (ec, a, TypeManager.idisposable_type, var.Location);
-                       if (e == null) {
-                               Error_IsNotConvertibleToIDisposable (var);
-                               return false;
-                       }
-
-                       converted_var = e;
-
-                       return true;
-               }
-
                static public void Error_IsNotConvertibleToIDisposable (Expression expr)
                {
                        Report.SymbolRelatedToPreviousError (expr.Type);
@@ -5011,42 +5012,18 @@ namespace Mono.CSharp {
                protected override void EmitFinallyBody (EmitContext ec)
                {
                        ILGenerator ig = ec.ig;
+                       Label skip = ig.DefineLabel ();
 
-                       if (!var.Type.IsValueType) {
-                               Label skip = ig.DefineLabel ();
+                       bool emit_null_check = !TypeManager.IsValueType (var.Type);
+                       if (emit_null_check) {
                                var.Emit (ec);
                                ig.Emit (OpCodes.Brfalse, skip);
-                               converted_var.Emit (ec);
-                               ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
-                               ig.MarkLabel (skip);
-                       } else {
-                               Expression ml = Expression.MemberLookup(ec.ContainerType, TypeManager.idisposable_type, var.Type, "Dispose", Mono.CSharp.Location.Null);
-
-                               if (!(ml is MethodGroupExpr)) {
-                                       var.Emit (ec);
-                                       ig.Emit (OpCodes.Box, var.Type);
-                                       ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
-                               } else {
-                                       MethodInfo mi = null;
-
-                                       foreach (MethodInfo mk in ((MethodGroupExpr) ml).Methods) {
-                                               if (TypeManager.GetParameterData (mk).Count == 0) {
-                                                       mi = mk;
-                                                       break;
-                                               }
-                                       }
-
-                                       if (mi == null) {
-                                               Report.Error(-100, Mono.CSharp.Location.Null, "Internal error: No Dispose method which takes 0 parameters.");
-                                               return;
-                                       }
+                       }
 
-                                       IMemoryLocation mloc = (IMemoryLocation) var;
+                       Invocation.EmitCall (ec, false, var, TypeManager.void_dispose_void, null, loc);
 
-                                       mloc.AddressOf (ec, AddressOp.Load);
-                                       ig.Emit (OpCodes.Call, mi);
-                               }
-                       }
+                       if (emit_null_check)
+                               ig.MarkLabel (skip);
                }
 
                public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
@@ -5077,6 +5054,27 @@ namespace Mono.CSharp {
                        return ok;
                }
 
+               bool ResolveVariable (EmitContext ec)
+               {
+                       assign = new SimpleAssign (var, init, loc);
+                       assign = assign.ResolveStatement (ec);
+                       if (assign == null)
+                               return false;
+
+                       if (assign.Type == TypeManager.idisposable_type ||
+                               TypeManager.ImplementsInterface (assign.Type, TypeManager.idisposable_type)) {
+                               return true;
+                       }
+
+                       Expression e = Convert.ImplicitConversionStandard (ec, assign, TypeManager.idisposable_type, var.Location);
+                       if (e == null) {
+                               Error_IsNotConvertibleToIDisposable (var);
+                               return false;
+                       }
+
+                       throw new NotImplementedException ("covariance?");
+               }
+
                protected override void CloneTo (CloneContext clonectx, Statement t)
                {
                        Using target = (Using) t;
@@ -5154,7 +5152,7 @@ namespace Mono.CSharp {
                                copy.Resolve (ec);
 
                                int rank = length_exprs.Length;
-                               ArrayList list = new ArrayList (rank);
+                               Arguments list = new Arguments (rank);
                                for (int i = 0; i < rank; i++) {
                                        counter [i] = new ArrayCounter (loc);
                                        counter [i].ResolveIncrement (ec);                                      
@@ -5165,12 +5163,12 @@ namespace Mono.CSharp {
                                                lengths [i] = new TemporaryVariable (TypeManager.int32_type, loc);
                                                lengths [i].Resolve (ec);
 
-                                               ArrayList args = new ArrayList (1);
+                                               Arguments args = new Arguments (1);
                                                args.Add (new Argument (new IntConstant (i, loc)));
                                                length_exprs [i] = new Invocation (new MemberAccess (copy, "GetLength"), args).Resolve (ec);
                                        }
 
-                                       list.Add (counter [i]);
+                                       list.Add (new Argument (counter [i]));
                                }
 
                                access = new ElementAccess (copy, list).Resolve (ec);
@@ -5197,7 +5195,7 @@ namespace Mono.CSharp {
                                ec.StartFlowBranching (FlowBranching.BranchingType.Loop, loc);
                                ec.CurrentBranching.CreateSibling ();
 
-                               for_each.variable = for_each.variable.ResolveLValue (ec, conv, loc);
+                               for_each.variable = for_each.variable.ResolveLValue (ec, conv);
                                if (for_each.variable == null)
                                        ok = false;
 
@@ -5377,8 +5375,7 @@ namespace Mono.CSharp {
                                //
 
                                if (return_type == TypeManager.ienumerator_type ||
-                                   TypeManager.ienumerator_type.IsAssignableFrom (return_type) ||
-                                   (!RootContext.StdLib && TypeManager.ImplementsInterface (return_type, TypeManager.ienumerator_type))) {
+                                       TypeManager.ImplementsInterface (return_type, TypeManager.ienumerator_type)) {
                                        //
                                        // If it is not an interface, lets try to find the methods ourselves.
                                        // For example, if we have:
@@ -5403,11 +5400,10 @@ namespace Mono.CSharp {
                                                        TypeManager.ienumerator_type, "Current", loc, TypeManager.object_type);
                                        }
 
-#if GMCS_SOURCE
                                        //
                                        // Prefer a generic enumerator over a non-generic one.
                                        //
-                                       if (return_type.IsInterface && return_type.IsGenericType) {
+                                       if (return_type.IsInterface && TypeManager.IsGenericType (return_type)) {
                                                enumerator_type = return_type;
                                                if (!FetchGetCurrent (ec, return_type))
                                                        get_current = new PropertyExpr (
@@ -5416,7 +5412,6 @@ namespace Mono.CSharp {
                                                        move_next = TypeManager.bool_movenext_void;
                                                return true;
                                        }
-#endif
 
                                        if (return_type.IsInterface ||
                                            !FetchMoveNext (return_type) ||
@@ -5450,14 +5445,10 @@ namespace Mono.CSharp {
                        //
                        bool FetchMoveNext (Type t)
                        {
-                               MemberList move_next_list;
-
-                               move_next_list = TypeContainer.FindMembers (
-                                       t, MemberTypes.Method,
+                               MemberInfo[] move_next_list = TypeManager.MemberLookup (null, null, t,
+                                       MemberTypes.Method,
                                        BindingFlags.Public | BindingFlags.Instance,
-                                       Type.FilterName, "MoveNext");
-                               if (move_next_list.Count == 0)
-                                       return false;
+                                       "MoveNext", null);
 
                                foreach (MemberInfo m in move_next_list){
                                        MethodInfo mi = (MethodInfo) m;
@@ -5487,31 +5478,6 @@ namespace Mono.CSharp {
                                return true;
                        }
 
-                       // 
-                       // Retrieves a `public void Dispose ()' method from the Type `t'
-                       //
-                       static MethodInfo FetchMethodDispose (Type t)
-                       {
-                               MemberList dispose_list;
-
-                               dispose_list = TypeContainer.FindMembers (
-                                       t, MemberTypes.Method,
-                                       BindingFlags.Public | BindingFlags.Instance,
-                                       Type.FilterName, "Dispose");
-                               if (dispose_list.Count == 0)
-                                       return null;
-
-                               foreach (MemberInfo m in dispose_list){
-                                       MethodInfo mi = (MethodInfo) m;
-
-                                       if (TypeManager.GetParameterData (mi).Count == 0){
-                                               if (mi.ReturnType == TypeManager.void_type)
-                                                       return mi;
-                                       }
-                               }
-                               return null;
-                       }
-
                        void Error_Enumerator ()
                        {
                                if (enumerator_found) {
@@ -5654,9 +5620,6 @@ namespace Mono.CSharp {
                                        return false;
                                }
 
-                               bool is_disposable = !enumerator_type.IsSealed ||
-                                       TypeManager.ImplementsInterface (enumerator_type, TypeManager.idisposable_type);
-
                                VarExpr ve = var_type as VarExpr;
                                if (ve != null) {
                                        // Infer implicitly typed local variable from foreach enumerable type
@@ -5691,9 +5654,14 @@ namespace Mono.CSharp {
 
                                loop = new While (move_next_expr, block, loc);
 
-                               wrapper = is_disposable ?
-                                       (Statement) new DisposableWrapper (this) :
-                                       (Statement) new NonDisposableWrapper (this);
+
+                               bool implements_idisposable = TypeManager.ImplementsInterface (enumerator_type, TypeManager.idisposable_type);
+                               if (implements_idisposable || !enumerator_type.IsSealed) {
+                                       wrapper = new DisposableWrapper (this, implements_idisposable);
+                               } else {
+                                       wrapper = new NonDisposableWrapper (this);
+                               }
+
                                return wrapper.Resolve (ec);
                        }
 
@@ -5732,12 +5700,15 @@ namespace Mono.CSharp {
                                }
                        }
 
-                       class DisposableWrapper : ExceptionStatement {
+                       sealed class DisposableWrapper : ExceptionStatement
+                       {
                                CollectionForeach parent;
+                               bool implements_idisposable;
 
-                               internal DisposableWrapper (CollectionForeach parent)
+                               internal DisposableWrapper (CollectionForeach parent, bool implements)
                                {
                                        this.parent = parent;
+                                       this.implements_idisposable = implements;
                                }
 
                                protected override void CloneTo (CloneContext clonectx, Statement target)
@@ -5777,7 +5748,30 @@ namespace Mono.CSharp {
 
                                protected override void EmitFinallyBody (EmitContext ec)
                                {
-                                       parent.EmitFinallyBody (ec);
+                                       Expression instance = parent.enumerator;
+                                       if (!TypeManager.IsValueType (parent.enumerator_type)) {
+                                               ILGenerator ig = ec.ig;
+
+                                               parent.enumerator.Emit (ec);
+
+                                               Label call_dispose = ig.DefineLabel ();
+
+                                               if (!implements_idisposable) {
+                                                       ec.ig.Emit (OpCodes.Isinst, TypeManager.idisposable_type);
+                                                       LocalTemporary temp = new LocalTemporary (TypeManager.idisposable_type);
+                                                       temp.Store (ec);
+                                                       temp.Emit (ec);
+                                                       instance = temp;
+                                               }
+                                               
+                                               ig.Emit (OpCodes.Brtrue_S, call_dispose);
+
+                                               // using 'endfinally' to empty the evaluation stack
+                                               ig.Emit (OpCodes.Endfinally);
+                                               ig.MarkLabel (call_dispose);
+                                       }
+
+                                       Invocation.EmitCall (ec, false, instance, TypeManager.void_dispose_void, null, loc);
                                }
 
                                public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
@@ -5801,37 +5795,6 @@ namespace Mono.CSharp {
                                loop.Emit (ec);
                        }
 
-                       void EmitFinallyBody (EmitContext ec)
-                       {
-                               ILGenerator ig = ec.ig;
-
-                               if (enumerator_type.IsValueType) {
-                                       MethodInfo mi = FetchMethodDispose (enumerator_type);
-                                       if (mi != null) {
-                                               enumerator.AddressOf (ec, AddressOp.Load);
-                                               ig.Emit (OpCodes.Call, mi);
-                                       } else {
-                                               enumerator.Emit (ec);
-                                               ig.Emit (OpCodes.Box, enumerator_type);
-                                               ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
-                                       }
-                               } else {
-                                       Label call_dispose = ig.DefineLabel ();
-
-                                       enumerator.Emit (ec);
-                                       ig.Emit (OpCodes.Isinst, TypeManager.idisposable_type);
-                                       ig.Emit (OpCodes.Dup);
-                                       ig.Emit (OpCodes.Brtrue_S, call_dispose);
-
-                                       // 'endfinally' empties the evaluation stack, and can appear anywhere inside a finally block
-                                       // (Partition III, Section 3.35)
-                                       ig.Emit (OpCodes.Endfinally);
-
-                                       ig.MarkLabel (call_dispose);
-                                       ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
-                               }
-                       }
-
                        public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
                        {
                                enumerator_type = storey.MutateType (enumerator_type);