2007-06-20 Marek Safar <marek.safar@gmail.com>
[mono.git] / mcs / mcs / statement.cs
index ca2f18955c45917d993c7a84e7edd608b296ae64..207cf7bdc70a3094169c02bd3ad59728084d6a15 100644 (file)
@@ -99,9 +99,6 @@ namespace Mono.CSharp {
                public Statement Clone (CloneContext clonectx)
                {
                        Statement s = (Statement) this.MemberwiseClone ();
-                       if (s is Block)
-                               clonectx.AddBlockMap ((Block) this, (Block) s);
-                       
                        CloneTo (clonectx, s);
                        return s;
                }
@@ -1138,10 +1135,15 @@ namespace Mono.CSharp {
                public abstract void EmitAddressOf (EmitContext ec);
        }
 
+       public interface IKnownVariable {
+               Block Block { get; }
+               Location Location { get; }
+       }
+
        //
        // The information about a user-perceived local variable
        //
-       public class LocalInfo {
+       public class LocalInfo : IKnownVariable {
                public Expression Type;
 
                public Type VariableType;
@@ -1241,7 +1243,7 @@ namespace Mono.CSharp {
                public bool Resolve (EmitContext ec)
                {
                        if (VariableType == null) {
-                               TypeExpr texpr = Type.ResolveAsTypeTerminal (ec, false);
+                               TypeExpr texpr = Type.ResolveAsContextualType (ec, false);
                                if (texpr == null)
                                        return false;
                                
@@ -1268,42 +1270,23 @@ namespace Mono.CSharp {
                }
 
                public bool IsCaptured {
-                       get {
-                               return (flags & Flags.Captured) != 0;
-                       }
-
-                       set {
-                               flags |= Flags.Captured;
-                       }
+                       get { return (flags & Flags.Captured) != 0; }
+                       set { flags |= Flags.Captured; }
                }
 
                public bool IsConstant {
-                       get {
-                               return (flags & Flags.IsConstant) != 0;
-                       }
-                       set {
-                               flags |= Flags.IsConstant;
-                       }
+                       get { return (flags & Flags.IsConstant) != 0; }
+                       set { flags |= Flags.IsConstant; }
                }
 
                public bool AddressTaken {
-                       get {
-                               return (flags & Flags.AddressTaken) != 0;
-                       }
-
-                       set {
-                               flags |= Flags.AddressTaken;
-                       }
+                       get { return (flags & Flags.AddressTaken) != 0; }
+                       set { flags |= Flags.AddressTaken; }
                }
 
                public bool CompilerGenerated {
-                       get {
-                               return (flags & Flags.CompilerGenerated) != 0;
-                       }
-
-                       set {
-                               flags |= Flags.CompilerGenerated;
-                       }
+                       get { return (flags & Flags.CompilerGenerated) != 0; }
+                       set { flags |= Flags.CompilerGenerated; }
                }
 
                public override string ToString ()
@@ -1313,18 +1296,12 @@ namespace Mono.CSharp {
                }
 
                public bool Used {
-                       get {
-                               return (flags & Flags.Used) != 0;
-                       }
-                       set {
-                               flags = value ? (flags | Flags.Used) : (unchecked (flags & ~Flags.Used));
-                       }
+                       get { return (flags & Flags.Used) != 0; }
+                       set { flags = value ? (flags | Flags.Used) : (unchecked (flags & ~Flags.Used)); }
                }
 
                public bool ReadOnly {
-                       get {
-                               return (flags & Flags.ReadOnly) != 0;
-                       }
+                       get { return (flags & Flags.ReadOnly) != 0; }
                }
 
                public void SetReadOnlyContext (ReadOnlyContext context)
@@ -1354,21 +1331,21 @@ namespace Mono.CSharp {
                // allocated in a pinned slot with DeclareLocal.
                //
                public bool Pinned {
-                       get {
-                               return (flags & Flags.Pinned) != 0;
-                       }
-                       set {
-                               flags = value ? (flags | Flags.Pinned) : (flags & ~Flags.Pinned);
-                       }
+                       get { return (flags & Flags.Pinned) != 0; }
+                       set { flags = value ? (flags | Flags.Pinned) : (flags & ~Flags.Pinned); }
                }
 
                public bool IsThis {
-                       get {
-                               return (flags & Flags.IsThis) != 0;
-                       }
-                       set {
-                               flags = value ? (flags | Flags.IsThis) : (flags & ~Flags.IsThis);
-                       }
+                       get { return (flags & Flags.IsThis) != 0; }
+                       set { flags = value ? (flags | Flags.IsThis) : (flags & ~Flags.IsThis); }
+               }
+
+               Block IKnownVariable.Block {
+                       get { return Block; }
+               }
+
+               Location IKnownVariable.Location {
+                       get { return Location; }
                }
 
                protected class LocalVariable : Variable
@@ -1445,25 +1422,18 @@ namespace Mono.CSharp {
                public ToplevelBlock Toplevel;
 
                [Flags]
-               public enum Flags : ushort {
-                       IsExplicit = 1,
-                       Unchecked = 2,
-                       BlockUsed = 4,
-                       VariablesInitialized = 8,
-                       HasRet = 16,
-                       IsDestructor = 32,
-                       IsToplevel = 64,
-                       Unsafe = 128,
-                       HasVarargs = 256, // Used in ToplevelBlock
-                       IsIterator = 512
-
+               public enum Flags : byte {
+                       Unchecked = 1,
+                       BlockUsed = 2,
+                       VariablesInitialized = 4,
+                       HasRet = 8,
+                       IsDestructor = 16,
+                       Unsafe = 32,
+                       HasVarargs = 64, // Used in ToplevelBlock
+                       IsIterator = 128
                }
                protected Flags flags;
 
-               public bool Implicit {
-                       get { return (flags & Flags.IsExplicit) == 0; }
-               }
-
                public bool Unchecked {
                        get { return (flags & Flags.Unchecked) != 0; }
                        set { flags |= Flags.Unchecked; }
@@ -1536,8 +1506,13 @@ namespace Mono.CSharp {
 
                public Block (Block parent, Flags flags, Location start, Location end)
                {
-                       if (parent != null)
+                       if (parent != null) {
                                parent.AddChild (this);
+
+                               // the appropriate constructors will fixup these fields
+                               Toplevel = parent.Toplevel;
+                               Explicit = parent.Explicit;
+                       }
                        
                        this.Parent = parent;
                        this.flags = flags;
@@ -1546,16 +1521,6 @@ namespace Mono.CSharp {
                        this.loc = start;
                        this_id = id++;
                        statements = new ArrayList ();
-
-                       if ((flags & Flags.IsToplevel) != 0)
-                               Toplevel = (ToplevelBlock) this;
-                       else
-                               Toplevel = parent.Toplevel;
-
-                       if ((flags & Flags.IsExplicit) != 0)
-                               Explicit = (ExplicitBlock) this;
-                       else
-                               Explicit = parent.Explicit;
                }
 
                public Block CreateSwitchBlock (Location start)
@@ -1622,7 +1587,7 @@ namespace Mono.CSharp {
                                        return false;
                                }
 
-                               if (!Implicit)
+                               if (this == Explicit)
                                        break;
 
                                cur = cur.Parent;
@@ -1668,7 +1633,7 @@ namespace Mono.CSharp {
                                return null;
 
                        foreach (Block child in children) {
-                               if (!child.Implicit)
+                               if (Explicit != child.Explicit)
                                        continue;
 
                                s = child.LookupLabel (name);
@@ -1694,12 +1659,12 @@ namespace Mono.CSharp {
                public bool CheckInvariantMeaningInBlock (string name, Expression e, Location loc)
                {
                        Block b = this;
-                       LocalInfo kvi = b.Explicit.GetKnownVariableInfo (name, true);
+                       IKnownVariable kvi = b.Explicit.GetKnownVariable (name);
                        while (kvi == null) {
                                b = b.Explicit.Parent;
                                if (b == null)
                                        return true;
-                               kvi = b.Explicit.GetKnownVariableInfo (name, true);
+                               kvi = b.Explicit.GetKnownVariable (name);
                        }
 
                        if (kvi.Block == b)
@@ -1733,7 +1698,7 @@ namespace Mono.CSharp {
                        // an indirect check that depends on AddVariable doing its
                        // part in maintaining the invariant-meaning-in-block property.
                        //
-                       if (e is LocalVariableReference || (e is Constant && b.GetLocalInfo (name) != null))
+                       if (e is VariableReference || (e is Constant && b.GetLocalInfo (name) != null))
                                return true;
 
                        //
@@ -1745,103 +1710,6 @@ namespace Mono.CSharp {
                        return false;
                }
 
-               public bool CheckError136_InParents (string name, Location loc)
-               {
-                       for (Block b = Parent; b != null; b = b.Parent) {
-                               if (!b.DoCheckError136 (name, "parent or current", loc))
-                                       return false;
-                       }
-
-                       for (Block b = Toplevel.ContainerBlock; b != null; b = b.Toplevel.ContainerBlock) {
-                               if (!b.CheckError136_InParents (name, loc))
-                                       return false;
-                       }
-
-                       return true;
-               }
-
-               public bool CheckError136_InChildren (string name, Location loc)
-               {
-                       if (!DoCheckError136_InChildren (name, loc))
-                               return false;
-
-                       Block b = this;
-                       while (b.Implicit) {
-                               if (!b.Parent.DoCheckError136_InChildren (name, loc))
-                                       return false;
-                               b = b.Parent;
-                       }
-
-                       return true;
-               }
-
-               protected bool DoCheckError136_InChildren (string name, Location loc)
-               {
-                       if (!DoCheckError136 (name, "child", loc))
-                               return false;
-
-                       if (AnonymousChildren != null) {
-                               foreach (ToplevelBlock child in AnonymousChildren) {
-                                       if (!child.DoCheckError136_InChildren (name, loc))
-                                               return false;
-                               }
-                       }
-
-                       if (children != null) {
-                               foreach (Block child in children) {
-                                       if (!child.DoCheckError136_InChildren (name, loc))
-                                               return false;
-                               }
-                       }
-
-                       return true;
-               }
-
-               public bool CheckError136 (string name, string scope, bool check_parents,
-                                          bool check_children, Location loc)
-               {
-                       if (!DoCheckError136 (name, scope, loc))
-                               return false;
-
-                       if (check_parents) {
-                               if (!CheckError136_InParents (name, loc))
-                                       return false;
-                       }
-
-                       if (check_children) {
-                               if (!CheckError136_InChildren (name, loc))
-                                       return false;
-                       }
-
-                       for (Block c = Toplevel.ContainerBlock; c != null; c = c.Toplevel.ContainerBlock) {
-                               if (!c.DoCheckError136 (name, "parent or current", loc))
-                                       return false;
-                       }
-
-                       return true;
-               }
-
-               protected bool DoCheckError136 (string name, string scope, Location loc)
-               {
-                       LocalInfo vi = Explicit.GetKnownVariableInfo (name, false);
-                       if (vi != null) {
-                               Report.SymbolRelatedToPreviousError (vi.Location, name);
-                               Error_AlreadyDeclared (loc, name, scope != null ? scope : "child");
-                               return false;
-                       }
-
-                       int idx;
-                       Parameter p = Toplevel.Parameters.GetParameterByName (name, out idx);
-                       if (p != null) {
-                               Report.SymbolRelatedToPreviousError (p.Location, name);
-                               Error_AlreadyDeclared (
-                                       loc, name, scope != null ? scope : "method argument");
-                               return false;
-                       }
-
-                       return true;
-               }
-
                public LocalInfo AddVariable (Expression type, string name, Location l)
                {
                        LocalInfo vi = GetLocalInfo (name);
@@ -1855,8 +1723,19 @@ namespace Mono.CSharp {
                                return null;
                        }
 
-                       if (!CheckError136 (name, null, true, true, l))
+                       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");
+                       }
+
+                       IKnownVariable kvi = Explicit.GetKnownVariable (name);
+                       if (kvi != null) {
+                               Report.SymbolRelatedToPreviousError (kvi.Location, name);
+                               Error_AlreadyDeclared (l, name, "child");
                                return null;
+                       }
 
                        vi = new LocalInfo (type, name, this, l);
                        Variables.Add (name, vi);
@@ -1868,7 +1747,7 @@ namespace Mono.CSharp {
                        return vi;
                }
 
-               void Error_AlreadyDeclared (Location loc, string var, string reason)
+               protected static void Error_AlreadyDeclared (Location loc, string var, string reason)
                {
                        Report.Error (136, loc, "A local variable named `{0}' cannot be declared " +
                                      "in this scope because it would give a different meaning " +
@@ -2259,9 +2138,7 @@ namespace Mono.CSharp {
 
                        // If we're a non-static `struct' constructor which doesn't have an
                        // initializer, then we must initialize all of the struct's fields.
-                       if ((flags & Flags.IsToplevel) != 0 && 
-                           !Toplevel.IsThisAssigned (ec) &&
-                           !vector.IsUnreachable)
+                       if (this == Toplevel && !Toplevel.IsThisAssigned (ec) && !vector.IsUnreachable)
                                ok = false;
 
                        if ((labels != null) && (RootContext.WarningLevel >= 2)) {
@@ -2314,7 +2191,7 @@ namespace Mono.CSharp {
                        ec.CurrentBlock = this;
 
                        bool emit_debug_info = (CodeGen.SymbolWriter != null);
-                       bool is_lexical_block = !Implicit && (Parent != null);
+                       bool is_lexical_block = this == Explicit && Parent != null;
 
                        if (emit_debug_info) {
                                if (is_lexical_block)
@@ -2343,21 +2220,6 @@ namespace Mono.CSharp {
                        ec.CurrentBlock = prev_block;
                }
 
-               //
-               // Returns true if we ar ea child of `b'.
-               //
-               public bool IsChildOf (Block b)
-               {
-                       Block current = this;
-                       
-                       do {
-                               if (current.Parent == b)
-                                       return true;
-                               current = current.Parent;
-                       } while (current != null);
-                       return false;
-               }
-
                public override string ToString ()
                {
                        return String.Format ("{0} ({1}:{2})", GetType (),ID, StartLocation);
@@ -2367,7 +2229,10 @@ namespace Mono.CSharp {
                {
                        Block target = (Block) t;
 
+                       clonectx.AddBlockMap (this, target);
+
                        target.Toplevel = (ToplevelBlock) clonectx.LookupBlock (Toplevel);
+                       target.Explicit = (ExplicitBlock) clonectx.LookupBlock (Explicit);
                        if (Parent != null)
                                target.Parent = clonectx.LookupBlock (Parent);
                        
@@ -2408,8 +2273,9 @@ namespace Mono.CSharp {
                }
 
                public ExplicitBlock (Block parent, Flags flags, Location start, Location end)
-                       : base (parent, flags | Flags.IsExplicit, start, end)
+                       : base (parent, flags, start, end)
                {
+                       this.Explicit = this;
                }
 
                Hashtable known_variables;
@@ -2419,7 +2285,7 @@ namespace Mono.CSharp {
                //   If a variable name has been used in a child block, it's illegal to
                //   declare a variable with the same name in the current block.
                // </summary>
-               internal void AddKnownVariable (string name, LocalInfo info)
+               internal void AddKnownVariable (string name, IKnownVariable info)
                {
                        if (known_variables == null)
                                known_variables = new Hashtable ();
@@ -2430,16 +2296,38 @@ namespace Mono.CSharp {
                                Parent.Explicit.AddKnownVariable (name, info);
                }
 
-               internal LocalInfo GetKnownVariableInfo (string name, bool recurse)
+               internal IKnownVariable GetKnownVariable (string name)
                {
-                       if (known_variables == null)
-                               return null;
-                       LocalInfo vi = (LocalInfo) known_variables [name];
-                       if (vi == null)
-                               return null;
-                       if (!recurse && vi.Block.Explicit != this)
-                               return null;
-                       return vi;
+                       return known_variables == null ? null : (IKnownVariable) known_variables [name];
+               }
+
+               protected override void CloneTo (CloneContext clonectx, Statement t)
+               {
+                       ExplicitBlock target = (ExplicitBlock) t;
+                       target.known_variables = null;
+                       base.CloneTo (clonectx, t);
+               }
+       }
+
+       public class ToplevelParameterInfo : IKnownVariable {
+               public readonly ToplevelBlock Block;
+               public readonly int Index;
+               public VariableInfo VariableInfo;
+
+               Block IKnownVariable.Block {
+                       get { return Block; }
+               }
+               public Parameter Parameter {
+                       get { return Block.Parameters [Index]; }
+               }
+               public Location Location {
+                       get { return Parameter.Location; }
+               }
+
+               public ToplevelParameterInfo (ToplevelBlock block, int idx)
+               {
+                       this.Block = block;
+                       this.Index = idx;
                }
        }
 
@@ -2452,11 +2340,6 @@ namespace Mono.CSharp {
        // Methods was implemented. 
        // 
        public class ToplevelBlock : ExplicitBlock {
-               //
-               // Pointer to the host of this anonymous method, or null
-               // if we are the topmost block
-               //
-               Block container;
                GenericMethod generic;
                FlowBranchingToplevel top_level_branching;
                AnonymousContainer anonymous_container;
@@ -2481,15 +2364,13 @@ namespace Mono.CSharp {
 
                public bool CompleteContexts (EmitContext ec)
                {
-                       Report.Debug (64, "TOPLEVEL COMPLETE CONTEXTS", this,
-                                     container, root_scope);
+                       Report.Debug (64, "TOPLEVEL COMPLETE CONTEXTS", this, Parent, root_scope);
 
                        if (root_scope != null)
                                root_scope.LinkScopes ();
 
-                       if ((container == null) && (root_scope != null)) {
-                               Report.Debug (64, "TOPLEVEL COMPLETE CONTEXTS #1", this,
-                                             root_scope);
+                       if (Parent == null && root_scope != null) {
+                               Report.Debug (64, "TOPLEVEL COMPLETE CONTEXTS #1", this, root_scope);
 
                                if (root_scope.DefineType () == null)
                                        return false;
@@ -2509,11 +2390,7 @@ namespace Mono.CSharp {
                }
 
                public ToplevelBlock Container {
-                       get { return container != null ? container.Toplevel : null; }
-               }
-
-               public Block ContainerBlock {
-                       get { return container; }
+                       get { return Parent == null ? null : Parent.Toplevel; }
                }
 
                public AnonymousContainer AnonymousContainer {
@@ -2521,18 +2398,13 @@ namespace Mono.CSharp {
                        set { anonymous_container = value; }
                }
 
-               //
-               // Parent is only used by anonymous blocks to link back to their
-               // parents
-               //
-               public ToplevelBlock (Block container, Parameters parameters, Location start) :
-                       this (container, (Flags) 0, parameters, start)
+               public ToplevelBlock (Block parent, Parameters parameters, Location start) :
+                       this (parent, (Flags) 0, parameters, start)
                {
                }
 
-               public ToplevelBlock (Block container, Parameters parameters, GenericMethod generic,
-                                     Location start) :
-                       this (container, parameters, start)
+               public ToplevelBlock (Block parent, Parameters parameters, GenericMethod generic, Location start) :
+                       this (parent, parameters, start)
                {
                        this.generic = generic;
                }
@@ -2547,17 +2419,37 @@ namespace Mono.CSharp {
                {
                }
 
-               public ToplevelBlock (Block container, Flags flags, Parameters parameters, Location start) :
-                       base (null, flags | Flags.IsToplevel, start, Location.Null)
+               // 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) :
+                       base (null, flags, start, Location.Null)
                {
+                       this.Toplevel = this;
+
                        this.parameters = parameters == null ? Parameters.EmptyReadOnlyParameters : parameters;
-                       this.container = container;
+                       this.Parent = parent;
+                       if (parent != null)
+                               parent.AddAnonymousChild (this);
+
+                       if (this.parameters.Count != 0)
+                               ProcessParameters ();
                }
 
                public ToplevelBlock (Location loc) : this (null, (Flags) 0, null, loc)
                {
                }
 
+               protected override void CloneTo (CloneContext clonectx, Statement t)
+               {
+                       ToplevelBlock target = (ToplevelBlock) t;
+                       base.CloneTo (clonectx, t);
+
+                       if (parameters.Count != 0)
+                               target.parameter_info = new ToplevelParameterInfo [parameters.Count];
+                       for (int i = 0; i < parameters.Count; ++i)
+                               target.parameter_info [i] = new ToplevelParameterInfo (target, i);
+               }
+
                public bool CheckError158 (string name, Location loc)
                {
                        if (AnonymousChildren != null) {
@@ -2575,6 +2467,38 @@ namespace Mono.CSharp {
                        return true;
                }
 
+               ToplevelParameterInfo [] parameter_info;
+               void ProcessParameters ()
+               {
+                       int n = parameters.Count;
+                       parameter_info = new ToplevelParameterInfo [n];
+                       for (int i = 0; i < n; ++i) {
+                               parameter_info [i] = new ToplevelParameterInfo (this, i);
+
+                               string name = parameters [i].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]);
+                       }
+
+                       // mark this block as "used" so that we create local declarations in a sub-block
+                       // FIXME: This appears to uncover a lot of bugs
+                       //this.Use ();
+               }
+
                bool DoCheckError158 (string name, Location loc)
                {
                        LabeledStatement s = LookupLabel (name);
@@ -2605,10 +2529,9 @@ namespace Mono.CSharp {
 
                public void CreateIteratorHost (RootScopeInfo root)
                {
-                       Report.Debug (64, "CREATE ITERATOR HOST", this, root,
-                                     container, root_scope);
+                       Report.Debug (64, "CREATE ITERATOR HOST", this, root, Parent, root_scope);
 
-                       if ((container != null) || (root_scope != null))
+                       if (Parent != null || root_scope != null)
                                throw new InternalErrorException ();
 
                        scope_info = root_scope = root;
@@ -2643,7 +2566,6 @@ namespace Mono.CSharp {
                        if ((flags & Flags.VariablesInitialized) != 0)
                                throw new InternalErrorException ("block has already been resolved");
 
-                       container = new_parent;
                        Parent = new_parent;
                }
 
@@ -2652,12 +2574,18 @@ namespace Mono.CSharp {
                // is no such parameter
                //
                public ParameterReference 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 new ParameterReference (par, this, idx, loc);
+                                       return t.parameter_info [idx];
                        }
                        return null;
                }
@@ -2719,18 +2647,10 @@ namespace Mono.CSharp {
                        return this_variable == null || this_variable.IsThisAssigned (ec);
                }
 
-               VariableInfo [] param_map;
-               public VariableInfo [] ParameterMap {
-                       get {
-                               if ((flags & Flags.VariablesInitialized) == 0)
-                                       throw new Exception ("Variables have not been initialized yet");
-                               return param_map;
-                       }
-               }
-
                public bool ResolveMeta (EmitContext ec, Parameters ip)
                {
                        int errors = Report.Errors;
+                       int orig_count = parameters.Count;
 
                        if (top_level_branching != null)
                                return true;
@@ -2738,27 +2658,21 @@ namespace Mono.CSharp {
                        if (ip != null)
                                parameters = ip;
 
-                       if (!IsIterator && (container != null) && (parameters != null)) {
-                               foreach (Parameter p in parameters.FixedParameters) {
-                                       if (!CheckError136_InParents (p.Name, loc))
-                                               return false;
-                               }
-                       }
+                       // Assert: orig_count != parameter.Count => orig_count == 0
+                       if (orig_count != 0 && orig_count != parameters.Count)
+                               throw new InternalErrorException ("parameter information mismatch");
 
                        int offset = Parent == null ? 0 : Parent.AssignableSlots;
 
-                       if (parameters != null) {
-                               for (int i = 0; i < parameters.Count; ++i) {
-                                       Parameter.Modifier mod = parameters.ParameterModifier (i);
+                       for (int i = 0; i < orig_count; ++i) {
+                               Parameter.Modifier mod = parameters.ParameterModifier (i);
 
-                                       if ((mod & Parameter.Modifier.OUT) != Parameter.Modifier.OUT)
-                                               continue;
+                               if ((mod & Parameter.Modifier.OUT) != Parameter.Modifier.OUT)
+                                       continue;
 
-                                       if (param_map == null)
-                                               param_map = new VariableInfo [parameters.Count];
-                                       param_map [i] = new VariableInfo (ip, i, offset);
-                                       offset += param_map [i].Length;
-                               }
+                               VariableInfo vi = new VariableInfo (ip, i, offset);
+                               parameter_info [i].VariableInfo = vi;
+                               offset += vi.Length;
                        }
 
                        ResolveMeta (ec, offset);
@@ -2768,6 +2682,30 @@ namespace Mono.CSharp {
                        return Report.Errors == errors;
                }
 
+               // <summary>
+               //   Check whether all `out' parameters have been assigned.
+               // </summary>
+               public void CheckOutParameters (FlowBranching.UsageVector vector, Location loc)
+               {
+                       if (vector.IsUnreachable)
+                               return;
+
+                       int n = parameter_info == null ? 0 : parameter_info.Length;
+
+                       for (int i = 0; i < n; i++) {
+                               VariableInfo var = parameter_info [i].VariableInfo;
+
+                               if (var == null)
+                                       continue;
+
+                               if (vector.IsAssigned (var, false))
+                                       continue;
+
+                               Report.Error (177, loc, "The out parameter `{0}' must be assigned to before control leaves the current method",
+                                       var.Name);
+                       }
+               }
+
                public override void EmitMeta (EmitContext ec)
                {
                        base.EmitMeta (ec);
@@ -3411,7 +3349,11 @@ namespace Mono.CSharp {
                        
                        if (!fFoundDefault) {
                                ig.MarkLabel (lblDefault);
+                               if (HaveUnwrap && !fFoundNull) {
+                                       ig.MarkLabel (null_target);
+                               }
                        }
+                       
                        ig.MarkLabel (lblEnd);
                }
                //
@@ -3973,22 +3915,7 @@ namespace Mono.CSharp {
                                return false;
                        }
                        
-                       TypeExpr texpr = null;
-                       if (type is VarExpr) {
-                               Unary u = ((Pair) declarators[0]).Second as Unary;
-                               if (u == null)
-                                       return false;
-                               
-                               Expression e = u.Expr.Resolve (ec);
-                               if (e == null || e.Type == null)
-                                       return false;
-                               
-                               Type t = TypeManager.GetPointerType (e.Type);
-                               texpr = new TypeExpression (t, loc);
-                       }
-                       else
-                               texpr = type.ResolveAsTypeTerminal (ec, false);
-
+                       TypeExpr texpr = type.ResolveAsTypeTerminal (ec, false);
                        if (texpr == null)
                                return false;
 
@@ -4006,9 +3933,6 @@ namespace Mono.CSharp {
                                LocalInfo vi = (LocalInfo) p.First;
                                Expression e = (Expression) p.Second;
                                
-                               if (type is VarExpr)
-                                       vi.VariableType = expr_type;
-
                                vi.VariableInfo.SetAssigned (ec);
                                vi.SetReadOnlyContext (LocalInfo.ReadOnlyContext.Fixed);
 
@@ -4464,7 +4388,7 @@ namespace Mono.CSharp {
                Type expr_type;
                Expression [] resolved_vars;
                Expression [] converted_vars;
-               ExpressionStatement [] assign;
+               Expression [] assign;
                TemporaryVariable local_copy;
                
                public Using (object expression_or_block, Statement stmt, Location l)
@@ -4479,97 +4403,52 @@ namespace Mono.CSharp {
                //
                bool ResolveLocalVariableDecls (EmitContext ec)
                {
-                       int i = 0;
-
-                       TypeExpr texpr = null;
-                       
-                       if (expr is VarExpr) {
-                               Expression e = ((Expression)((DictionaryEntry)var_list[0]).Value).Resolve (ec);
-                               if (e == null || e.Type == null)
-                                       return false;
-                               texpr = new TypeExpression (e.Type, loc);
-                       }
-                       else
-                               texpr = expr.ResolveAsTypeTerminal (ec, false);
-
-                       if (texpr == null)
-                               return false;
-
-                       expr_type = texpr.Type;
-
-                       //
-                       // The type must be an IDisposable or an implicit conversion
-                       // must exist.
-                       //
-                       converted_vars = new Expression [var_list.Count];
-                       resolved_vars = new Expression [var_list.Count];
-                       assign = new ExpressionStatement [var_list.Count];
+                       resolved_vars = new Expression[var_list.Count];
+                       assign = new Expression [var_list.Count];
+                       converted_vars = new Expression[var_list.Count];
 
-                       bool need_conv = !TypeManager.ImplementsInterface (
-                               expr_type, TypeManager.idisposable_type);
-
-                       foreach (DictionaryEntry e in var_list){
+                       for (int i = 0; i < assign.Length; ++i) {
+                               DictionaryEntry e = (DictionaryEntry) var_list [i];
                                Expression var = (Expression) e.Key;
-                               
-                               if (expr is VarExpr) {
-                                       LocalVariableReference l = var as LocalVariableReference;
-                                       ((LocalInfo)l.Block.Variables[l.Name]).VariableType = expr_type;
-                                       ((VarExpr)expr).Handled = true;
-                               }
+                               Expression new_expr = (Expression) e.Value;
 
-                               var = var.ResolveLValue (ec, new EmptyExpression (), loc);
-                               if (var == null)
+                               Expression a = new Assign (var, new_expr, loc);
+                               a = a.Resolve (ec);
+                               if (a == null)
                                        return false;
 
                                resolved_vars [i] = var;
+                               assign [i] = a;
 
-                               if (!need_conv) {
-                                       i++;
+                               if (TypeManager.ImplementsInterface (a.Type, TypeManager.idisposable_type)) {
+                                       converted_vars [i] = var;
                                        continue;
                                }
 
-                               converted_vars [i] = Convert.ImplicitConversion (
-                                       ec, var, TypeManager.idisposable_type, loc);
-
-                               if (converted_vars [i] == null) {
-                                       Error_IsNotConvertibleToIDisposable ();
+                               a = Convert.ImplicitConversion (ec, a, TypeManager.idisposable_type, var.Location);
+                               if (a == null) {
+                                       Error_IsNotConvertibleToIDisposable (var);
                                        return false;
                                }
 
-                               i++;
-                       }
-
-                       i = 0;
-                       foreach (DictionaryEntry e in var_list){
-                               Expression var = resolved_vars [i];
-                               Expression new_expr = (Expression) e.Value;
-                               Expression a;
-
-                               a = new Assign (var, new_expr, loc);
-                               a = a.Resolve (ec);
-                               if (a == null)
-                                       return false;
-
-                               if (!need_conv)
-                                       converted_vars [i] = var;
-                               assign [i] = (ExpressionStatement) a;
-                               i++;
+                               converted_vars [i] = a;
                        }
 
                        return true;
                }
 
-               void Error_IsNotConvertibleToIDisposable ()
+               static void Error_IsNotConvertibleToIDisposable (Expression expr)
                {
-                       Report.Error (1674, loc, "`{0}': type used in a using statement must be implicitly convertible to `System.IDisposable'",
-                               TypeManager.CSharpName (expr_type));
+                       Report.SymbolRelatedToPreviousError (expr.Type);
+                       Report.Error (1674, expr.Location, "`{0}': type used in a using statement must be implicitly convertible to `System.IDisposable'",
+                               expr.GetSignatureForError ());
                }
 
                bool ResolveExpression (EmitContext ec)
                {
                        if (!TypeManager.ImplementsInterface (expr_type, TypeManager.idisposable_type)){
                                if (Convert.ImplicitConversion (ec, expr, TypeManager.idisposable_type, loc) == null) {
-                                       Error_IsNotConvertibleToIDisposable ();
+                                       Error_IsNotConvertibleToIDisposable (expr);
                                        return false;
                                }
                        }
@@ -4589,7 +4468,7 @@ namespace Mono.CSharp {
                        int i = 0;
 
                        for (i = 0; i < assign.Length; i++) {
-                               assign [i].EmitStatement (ec);
+                               assign [i].Emit (ec);
 
                                if (emit_finally)
                                        ig.BeginExceptionBlock ();
@@ -4813,58 +4692,11 @@ namespace Mono.CSharp {
                        if (expr == null)
                                return false;
 
-                       if (type is VarExpr) {
-                               Type element_type = null;
-                               if (TypeManager.HasElementType (expr.Type))
-                                       element_type = TypeManager.GetElementType (expr.Type);
-                               else {
-                                       MethodGroupExpr mg = Expression.MemberLookup (
-                                               ec.ContainerType, expr.Type, "GetEnumerator", MemberTypes.Method,
-                                               Expression.AllBindingFlags, loc) as MethodGroupExpr;
-                                       
-                                       if (mg == null)
-                                                       return false;
-                                       
-                                       MethodInfo get_enumerator = null;
-                                       foreach (MethodInfo mi in mg.Methods) {
-                                               if (TypeManager.GetParameterData (mi).Count != 0)
-                                                       continue;
-                                               if ((mi.Attributes & MethodAttributes.Public) != MethodAttributes.Public)
-                                                       continue;
-                                               if (CollectionForeach.IsOverride (mi))
-                                                       continue;
-                                               get_enumerator = mi;
-                                       }
-                                       
-                                       if (get_enumerator == null)
-                                               return false;
-                                       
-                                       PropertyInfo pi = TypeManager.GetProperty (get_enumerator.ReturnType, "Current");
-                                       
-                                       if (pi == null)
-                                               return false;
-                                               
-                                       element_type = pi.PropertyType;
-                               }
-
-                               type = new TypeLookupExpression (element_type.AssemblyQualifiedName);
-                
-                               LocalVariableReference lv = variable as LocalVariableReference;
-                               ((LocalInfo)lv.Block.Variables[lv.Name]).VariableType = element_type;
-                       }
-
-                       Constant c = expr as Constant;
-                       if (c != null && c.GetValue () == null) {
+                       if (expr.Type == TypeManager.null_type) {
                                Report.Error (186, loc, "Use of null is not valid in this context");
                                return false;
                        }
 
-                       TypeExpr texpr = type.ResolveAsTypeTerminal (ec, false);
-                       if (texpr == null)
-                               return false;
-
-                       Type var_type = texpr.Type;
-
                        if (expr.eclass == ExprClass.MethodGroup || expr is AnonymousMethodExpression) {
                                Report.Error (446, expr.Location, "Foreach statement cannot operate on a `{0}'",
                                        expr.ExprClassName);
@@ -4885,13 +4717,12 @@ namespace Mono.CSharp {
                        }
 
                        if (expr.Type.IsArray) {
-                               array = new ArrayForeach (var_type, variable, expr, statement, loc);
+                               array = new ArrayForeach (type, variable, expr, statement, loc);
                                return array.Resolve (ec);
-                       } else {
-                               collection = new CollectionForeach (
-                                       var_type, variable, expr, statement, loc);
-                               return collection.Resolve (ec);
                        }
+                       
+                       collection = new CollectionForeach (type, variable, expr, statement, loc);
+                       return collection.Resolve (ec);
                }
 
                protected override void DoEmit (EmitContext ec)
@@ -4939,7 +4770,7 @@ namespace Mono.CSharp {
                        Expression variable, expr, conv;
                        Statement statement;
                        Type array_type;
-                       Type var_type;
+                       Expression var_type;
                        TemporaryVariable[] lengths;
                        ArrayCounter[] counter;
                        int rank;
@@ -4947,7 +4778,7 @@ namespace Mono.CSharp {
                        TemporaryVariable copy;
                        Expression access;
 
-                       public ArrayForeach (Type var_type, Expression var,
+                       public ArrayForeach (Expression var_type, Expression var,
                                             Expression expr, Statement stmt, Location l)
                        {
                                this.var_type = var_type;
@@ -4983,7 +4814,17 @@ namespace Mono.CSharp {
                                if (access == null)
                                        return false;
 
-                               conv = Convert.ExplicitConversion (ec, access, var_type, loc);
+                               VarExpr ve = var_type as VarExpr;
+                               if (ve != null) {
+                                       // Infer implicitly typed local variable from foreach array type
+                                       var_type = new TypeExpression (access.Type, ve.Location);
+                               }
+
+                               var_type = var_type.ResolveAsTypeTerminal (ec, false);
+                               if (var_type == null)
+                                       return false;
+
+                               conv = Convert.ExplicitConversion (ec, access, var_type.Type, loc);
                                if (conv == null)
                                        return false;
 
@@ -5065,11 +4906,12 @@ namespace Mono.CSharp {
                        MethodGroupExpr get_enumerator;
                        PropertyExpr get_current;
                        MethodInfo move_next;
-                       Type var_type, enumerator_type;
+                       Expression var_type;
+                       Type enumerator_type;
                        bool is_disposable;
                        bool enumerator_found;
 
-                       public CollectionForeach (Type var_type, Expression var,
+                       public CollectionForeach (Expression var_type, Expression var,
                                                  Expression expr, Statement stmt, Location l)
                        {
                                this.var_type = var_type;
@@ -5369,6 +5211,16 @@ namespace Mono.CSharp {
                                        return false;
                                }
 
+                               VarExpr ve = var_type as VarExpr;
+                               if (ve != null) {
+                                       // Infer implicitly typed local variable from foreach enumerable type
+                                       var_type = new TypeExpression (get_current.PropertyInfo.PropertyType, var_type.Location);
+                               }
+
+                               var_type = var_type.ResolveAsTypeTerminal (ec, false);
+                               if (var_type == null)
+                                       return false;
+                                                               
                                enumerator = new TemporaryVariable (enumerator_type, loc);
                                enumerator.Resolve (ec);
 
@@ -5389,7 +5241,7 @@ namespace Mono.CSharp {
                                get_current.InstanceExpression = enumerator;
 
                                Statement block = new CollectionForeachStatement (
-                                       var_type, variable, get_current, statement, loc);
+                                       var_type.Type, variable, get_current, statement, loc);
 
                                loop = new While (move_next_expr, block, loc);