X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fmcs%2Fstatement.cs;h=0ce9b01df8d59a1a2cc86440d32be57701bc7f83;hb=42a8c7a5c31610a55b519991a15fb04bd9170beb;hp=c4ceaab02a5e39ed8d7ad68eac30495f685255c4;hpb=c827fb125dba977164c43772e42327fdbdc2fdcc;p=mono.git diff --git a/mcs/mcs/statement.cs b/mcs/mcs/statement.cs old mode 100755 new mode 100644 index c4ceaab02a5..0ce9b01df8d --- a/mcs/mcs/statement.cs +++ b/mcs/mcs/statement.cs @@ -3,9 +3,10 @@ // // Author: // Miguel de Icaza (miguel@ximian.com) -// Martin Baulig (martin@gnome.org) +// Martin Baulig (martin@ximian.com) // // (C) 2001, 2002, 2003 Ximian, Inc. +// (C) 2003, 2004 Novell, Inc. // using System; @@ -45,16 +46,14 @@ namespace Mono.CSharp { // in unreachable code, for instance. // + if (warn && (RootContext.WarningLevel >= 2)) + Report.Warning (162, loc, "Unreachable code detected"); + ec.StartFlowBranching (FlowBranching.BranchingType.Block, loc); bool ok = Resolve (ec); ec.KillFlowBranching (); - if (!ok) - return false; - - if (warn && (RootContext.WarningLevel >= 2)) - Report.Warning (162, loc, "Unreachable code detected"); - return true; + return ok; } protected void CheckObsolete (Type type) @@ -140,11 +139,19 @@ namespace Mono.CSharp { public override bool Resolve (EmitContext ec) { + bool ok = true; + Report.Debug (1, "START IF BLOCK", loc); expr = Expression.ResolveBoolean (ec, expr, loc); if (expr == null){ - return false; + ok = false; + goto skip; + } + + Assign ass = expr as Assign; + if (ass != null && ass.Source is Constant) { + Report.Warning (665, 3, loc, "Assignment in conditional expression is always constant; did you mean to use == instead of = ?"); } // @@ -173,17 +180,17 @@ namespace Mono.CSharp { return true; } - + skip: ec.StartFlowBranching (FlowBranching.BranchingType.Conditional, loc); - bool ok = TrueStatement.Resolve (ec); + ok &= TrueStatement.Resolve (ec); is_true_ret = ec.CurrentBranching.CurrentUsageVector.Reachability.IsUnreachable; ec.CurrentBranching.CreateSibling (); - if ((FalseStatement != null) && !FalseStatement.Resolve (ec)) - ok = false; + if (FalseStatement != null) + ok &= FalseStatement.Resolve (ec); ec.EndFlowBranching (); @@ -526,7 +533,8 @@ namespace Mono.CSharp { public override bool Resolve (EmitContext ec) { - expr = expr.ResolveStatement (ec); + if (expr != null) + expr = expr.ResolveStatement (ec); return expr != null; } @@ -559,6 +567,11 @@ namespace Mono.CSharp { { if (ec.ReturnType == null){ if (Expr != null){ + if (ec.CurrentAnonymousMethod != null){ + Report.Error (1662, loc, String.Format ( + "Anonymous method could not be converted to delegate " + + "since the return value does not match the delegate value")); + } Error (127, "Return with a value not allowed here"); return false; } @@ -570,6 +583,12 @@ namespace Mono.CSharp { return false; } + if (ec.InIterator) { + Report.Error (1622, loc, "Cannot return a value from iterators. Use the yield return " + + "statement to return a value, or yield break to end the iteration"); + return false; + } + Expr = Expr.Resolve (ec); if (Expr == null) return false; @@ -592,12 +611,15 @@ namespace Mono.CSharp { if (ec.CurrentBranching.InTryOrCatch (true)) { ec.CurrentBranching.AddFinallyVector (vector); in_exc = true; - } else if (ec.CurrentBranching.InFinally (true)) { + } else if (ec.InFinally) { Error (157, "Control can not leave the body of the finally block"); return false; } else vector.CheckOutParameters (ec.CurrentBranching); + if (in_exc) + ec.NeedReturnLabel (); + ec.CurrentBranching.CurrentUsageVector.Return (); return true; } @@ -611,18 +633,15 @@ namespace Mono.CSharp { ec.ig.Emit (OpCodes.Stloc, ec.TemporaryReturn ()); } - if (in_exc) { - ec.NeedReturnLabel (); + if (in_exc) ec.ig.Emit (OpCodes.Leave, ec.ReturnLabel); - } else { + else ec.ig.Emit (OpCodes.Ret); - } } } public class Goto : Statement { string target; - Block block; LabeledStatement label; public override bool Resolve (EmitContext ec) @@ -636,13 +655,13 @@ namespace Mono.CSharp { label.AddUsageVector (ec.CurrentBranching.CurrentUsageVector); ec.CurrentBranching.CurrentUsageVector.Goto (); + label.AddReference (); return true; } - public Goto (Block parent_block, string label, Location l) + public Goto (string label, Location l) { - block = parent_block; loc = l; target = label; } @@ -665,6 +684,7 @@ namespace Mono.CSharp { bool defined; bool referenced; Label label; + ILGenerator ig; FlowBranching.UsageVector vectors; @@ -677,6 +697,7 @@ namespace Mono.CSharp { { if (defined) return label; + ig = ec.ig; label = ec.ig.DefineLabel (); defined = true; @@ -706,16 +727,23 @@ namespace Mono.CSharp { { ec.CurrentBranching.Label (vectors); - referenced = true; - return true; } protected override void DoEmit (EmitContext ec) { + if (ig != null && ig != ec.ig) { + Report.Error (1632, "Control cannot leave body of anonymous method"); + return; + } LabelTarget (ec); ec.ig.MarkLabel (label); } + + public void AddReference () + { + referenced = true; + } } @@ -755,7 +783,7 @@ namespace Mono.CSharp { /// public class GotoCase : Statement { Expression expr; - Label label; + SwitchLabel sl; public GotoCase (Expression e, Location l) { @@ -785,7 +813,7 @@ namespace Mono.CSharp { if (val == null) return false; - SwitchLabel sl = (SwitchLabel) ec.Switch.Elements [val]; + sl = (SwitchLabel) ec.Switch.Elements [val]; if (sl == null){ Report.Error ( @@ -794,15 +822,13 @@ namespace Mono.CSharp { return false; } - label = sl.ILLabelCode; - ec.CurrentBranching.CurrentUsageVector.Goto (); return true; } protected override void DoEmit (EmitContext ec) { - ec.ig.Emit (OpCodes.Br, label); + ec.ig.Emit (OpCodes.Br, sl.GetILLabelCode (ec)); } } @@ -817,7 +843,6 @@ namespace Mono.CSharp { public override bool Resolve (EmitContext ec) { - bool in_catch = ec.CurrentBranching.InCatch (); ec.CurrentBranching.CurrentUsageVector.Throw (); if (expr != null){ @@ -828,28 +853,33 @@ namespace Mono.CSharp { ExprClass eclass = expr.eclass; if (!(eclass == ExprClass.Variable || eclass == ExprClass.PropertyAccess || - eclass == ExprClass.Value || eclass == ExprClass.IndexerAccess)) { - expr.Error_UnexpectedKind ("value, variable, property or indexer access "); + eclass == ExprClass.Value || eclass == ExprClass.IndexerAccess)) { + expr.Error_UnexpectedKind ("value, variable, property or indexer access ", loc); return false; } Type t = expr.Type; if ((t != TypeManager.exception_type) && - !t.IsSubclassOf (TypeManager.exception_type) && - !(expr is NullLiteral)) { + !t.IsSubclassOf (TypeManager.exception_type) && + !(expr is NullLiteral)) { Error (155, - "The type caught or thrown must be derived " + - "from System.Exception"); + "The type caught or thrown must be derived " + + "from System.Exception"); return false; } - } else if (!in_catch) { - Error (156, - "A throw statement with no argument is only " + - "allowed in a catch clause"); + return true; + } + + if (!ec.InCatch) { + Error (156, "A throw statement with no arguments is not allowed outside of a catch clause"); return false; } + if (ec.InFinally) { + Error (724, "A throw statement with no argument is only allowed in a catch clause nested inside of the innermost catch clause"); + return false; + } return true; } @@ -879,7 +909,7 @@ namespace Mono.CSharp { if (!ec.CurrentBranching.InLoop () && !ec.CurrentBranching.InSwitch ()){ Error (139, "No enclosing loop or switch to continue to"); return false; - } else if (ec.CurrentBranching.InFinally (false)) { + } else if (ec.InFinally) { Error (157, "Control can not leave the body of the finally block"); return false; } else if (ec.CurrentBranching.InTryOrCatch (false)) @@ -891,6 +921,9 @@ namespace Mono.CSharp { crossing_exc = ec.CurrentBranching.BreakCrossesTryCatchBoundary (); + if (!crossing_exc) + ec.NeedReturnLabel (); + ec.CurrentBranching.CurrentUsageVector.Break (); return true; } @@ -902,7 +935,6 @@ namespace Mono.CSharp { if (crossing_exc) ig.Emit (OpCodes.Leave, ec.LoopEnd); else { - ec.NeedReturnLabel (); ig.Emit (OpCodes.Br, ec.LoopEnd); } } @@ -922,7 +954,7 @@ namespace Mono.CSharp { if (!ec.CurrentBranching.InLoop () && !ec.CurrentBranching.InSwitch ()){ Error (139, "No enclosing loop to continue to"); return false; - } else if (ec.CurrentBranching.InFinally (false)) { + } else if (ec.InFinally) { Error (157, "Control can not leave the body of the finally block"); return false; } else if (ec.CurrentBranching.InTryOrCatch (false)) @@ -945,13 +977,17 @@ namespace Mono.CSharp { } } + // + // The information about a user-perceived local variable + // public class LocalInfo { public Expression Type; // // Most of the time a variable will be stored in a LocalBuilder // - // But sometimes, it will be stored in a field. The context of the field will + // But sometimes, it will be stored in a field (variables that have been + // hoisted by iterators or by anonymous methods). The context of the field will // be stored in the EmitContext // // @@ -969,7 +1005,9 @@ namespace Mono.CSharp { Used = 1, ReadOnly = 2, Pinned = 4, - IsThis = 8 + IsThis = 8, + Captured = 16, + AddressTaken = 32 } Flags flags; @@ -1010,8 +1048,13 @@ namespace Mono.CSharp { public bool Resolve (EmitContext ec) { - if (VariableType == null) - VariableType = ec.DeclSpace.ResolveType (Type, false, Location); + if (VariableType == null) { + TypeExpr texpr = Type.ResolveAsTypeTerminal (ec, false); + if (texpr == null) + return false; + + VariableType = texpr.ResolveType (ec); + } if (VariableType == TypeManager.void_type) { Report.Error (1547, Location, @@ -1019,9 +1062,6 @@ namespace Mono.CSharp { return false; } - if (VariableType == null) - return false; - if (VariableType.IsAbstract && VariableType.IsSealed) { Report.Error (723, Location, "Cannot declare variable of static type '{0}'", TypeManager.CSharpName (VariableType)); return false; @@ -1045,6 +1085,26 @@ namespace Mono.CSharp { } } + public bool IsCaptured { + get { + return (flags & Flags.Captured) != 0; + } + + set { + flags |= Flags.Captured; + } + } + + public bool AddressTaken { + get { + return (flags & Flags.AddressTaken) != 0; + } + + set { + flags |= Flags.AddressTaken; + } + } + public override string ToString () { return String.Format ("LocalInfo ({0},{1},{2},{3})", @@ -1056,7 +1116,7 @@ namespace Mono.CSharp { return (flags & Flags.Used) != 0; } set { - flags = value ? (flags | Flags.Used) : (flags & ~Flags.Used); + flags = value ? (flags | Flags.Used) : (unchecked (flags & ~Flags.Used)); } } @@ -1065,7 +1125,7 @@ namespace Mono.CSharp { return (flags & Flags.ReadOnly) != 0; } set { - flags = value ? (flags | Flags.ReadOnly) : (flags & ~Flags.ReadOnly); + flags = value ? (flags | Flags.ReadOnly) : (unchecked (flags & ~Flags.ReadOnly)); } } @@ -1107,19 +1167,23 @@ namespace Mono.CSharp { /// they contain extra information that is not necessary on normal blocks. /// public class Block : Statement { - public readonly Block Parent; + public Block Parent; public readonly Location StartLocation; - public Location EndLocation = Location.Null; + public Location EndLocation = Location.Null; + + public readonly ToplevelBlock Toplevel; [Flags] - public enum Flags : byte { + public enum Flags { Implicit = 1, Unchecked = 2, BlockUsed = 4, VariablesInitialized = 8, HasRet = 16, IsDestructor = 32, - HasVarargs = 64 + HasVarargs = 64, + IsToplevel = 128, + Unsafe = 256 } Flags flags; @@ -1138,6 +1202,15 @@ namespace Mono.CSharp { } } + public bool Unsafe { + get { + return (flags & Flags.Unsafe) != 0; + } + set { + flags |= Flags.Unsafe; + } + } + public bool HasVarargs { get { if (Parent != null) @@ -1178,13 +1251,13 @@ namespace Mono.CSharp { // // Keeps track of constants Hashtable constants; - + // // If this is a switch section, the enclosing switch block. // Block switch_block; - static int id; + protected static int id; int this_id; @@ -1196,42 +1269,33 @@ namespace Mono.CSharp { : this (parent, flags, Location.Null, Location.Null) { } - public Block (Block parent, Flags flags, Parameters parameters) - : this (parent, flags, parameters, Location.Null, Location.Null) - { } - public Block (Block parent, Location start, Location end) : this (parent, (Flags) 0, start, end) { } - public Block (Block parent, Parameters parameters, Location start, Location end) - : this (parent, (Flags) 0, parameters, start, end) - { } - public Block (Block parent, Flags flags, Location start, Location end) - : this (parent, flags, Parameters.EmptyReadOnlyParameters, start, end) - { } - - public Block (Block parent, Flags flags, Parameters parameters, - Location start, Location end) { if (parent != null) parent.AddChild (this); this.Parent = parent; this.flags = flags; - this.parameters = parameters; this.StartLocation = start; this.EndLocation = end; this.loc = start; this_id = id++; statements = new ArrayList (); + if ((flags & Flags.IsToplevel) != 0) + Toplevel = (ToplevelBlock) this; + else + Toplevel = parent.Toplevel; + if (parent != null && Implicit) { - if (parent.child_variable_names == null) - parent.child_variable_names = new Hashtable(); + if (parent.known_variables == null) + parent.known_variables = new Hashtable (); // share with parent - child_variable_names = parent.child_variable_names; + known_variables = parent.known_variables; } } @@ -1369,40 +1433,63 @@ namespace Mono.CSharp { // public LocalInfo ThisVariable { get { - if (this_variable != null) - return this_variable; - else if (Parent != null) - return Parent.ThisVariable; - else - return null; + for (Block b = this; b != null; b = b.Parent) { + if (b.this_variable != null) + return b.this_variable; + } + + return null; } } - Hashtable child_variable_names; + Hashtable known_variables; // - // Marks a variable with name @name as being used in a child block. + // Marks a variable with name @name as being used in this or a child block. // 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. // - public void AddChildVariableName (string name) + void AddKnownVariable (string name, LocalInfo info) { - if (child_variable_names == null) - child_variable_names = new Hashtable (); + if (known_variables == null) + known_variables = new Hashtable (); - if (!child_variable_names.Contains (name)) - child_variable_names.Add (name, true); + known_variables [name] = info; } - // - // Checks whether a variable name has already been used in a child block. - // - public bool IsVariableNameUsedInChildBlock (string name) + LocalInfo GetKnownVariableInfo (string name) + { + if (known_variables == null) + return null; + return (LocalInfo) known_variables [name]; + } + + public bool CheckInvariantMeaningInBlock (string name, Expression e, Location loc) { - if (child_variable_names == null) + LocalInfo kvi = GetKnownVariableInfo (name); + if (kvi == null || kvi.Block == this) + return true; + + if (known_variables != kvi.Block.known_variables) { + Report.SymbolRelatedToPreviousError (kvi.Location, name); + Report.Error (135, loc, "'{0}' has a different meaning in a child block", name); return false; + } + + // + // this block and kvi.Block are the same textual block. + // However, different variables are extant. + // + // Check if the variable is in scope in both blocks. We use + // 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 && GetLocalInfo (name) != null)) + return true; - return child_variable_names.Contains (name); + Report.SymbolRelatedToPreviousError (kvi.Location, name); + Report.Error (136, loc, "'{0}' has a different meaning later in the block", name); + return false; } // @@ -1429,58 +1516,47 @@ namespace Mono.CSharp { return this_variable; } - public LocalInfo AddVariable (Expression type, string name, Parameters pars, Location l) + public LocalInfo AddVariable (Expression type, string name, Location l) { if (variables == null) variables = new Hashtable (); LocalInfo vi = GetLocalInfo (name); if (vi != null) { - if (vi.Block != this) - Report.Error (136, l, "A local variable named `" + name + "' " + - "cannot be declared in this scope since it would " + - "give a different meaning to `" + name + "', which " + - "is already used in a `parent or current' scope to " + - "denote something else"); + Report.SymbolRelatedToPreviousError (vi.Location, name); + if (known_variables == vi.Block.known_variables) + Report.Error (128, l, + "A local variable '{0}' is already declared in this scope", name); else - Report.Error (128, l, "A local variable `" + name + "' is already " + - "defined in this scope"); + Report.Error (136, l, + "'{0}' hides the declaration of local variable '{0}' in a parent scope", name); return null; } - if (IsVariableNameUsedInChildBlock (name)) { - Report.Error (136, l, "A local variable named `" + name + "' " + - "cannot be declared in this scope since it would " + - "give a different meaning to `" + name + "', which " + - "is already used in a `child' scope to denote something " + - "else"); + vi = GetKnownVariableInfo (name); + if (vi != null) { + Report.SymbolRelatedToPreviousError (vi.Location, name); + Report.Error (136, l, + "A child block already has a declaration of local variable '{0}':" + + " allowing this declaration would violate 'invariant meaning in a block'", + name); return null; } - if (pars != null) { - int idx; - Parameter p = pars.GetParameterByName (name, out idx); - if (p != null) { - Report.Error (136, l, "A local variable named `" + name + "' " + - "cannot be declared in this scope since it would " + - "give a different meaning to `" + name + "', which " + - "is already used in a `parent or current' scope to " + - "denote something else"); - return null; - } + int idx; + Parameter p = Toplevel.Parameters.GetParameterByName (name, out idx); + if (p != null) { + Report.SymbolRelatedToPreviousError (Toplevel.Parameters.Location, name); + Report.Error (136, l, "'{0}' hides a method parameter", name); + return null; } vi = new LocalInfo (type, name, this, l); variables.Add (name, vi); - // Mark 'name' as "used by a child block" in every surrounding block - Block cur = this; - while (cur != null && cur.Implicit) - cur = cur.Parent; - if (cur != null) - for (Block par = cur.Parent; par != null; par = par.Parent) - par.AddChildVariableName (name); + for (Block b = this; b != null; b = b.Parent) + b.AddKnownVariable (name, vi); if ((flags & Flags.VariablesInitialized) != 0) throw new Exception (); @@ -1489,9 +1565,9 @@ namespace Mono.CSharp { return vi; } - public bool AddConstant (Expression type, string name, Expression value, Parameters pars, Location l) + public bool AddConstant (Expression type, string name, Expression value, Location l) { - if (AddVariable (type, name, pars, l) == null) + if (AddVariable (type, name, l) == null) return false; if (constants == null) @@ -1552,17 +1628,50 @@ namespace Mono.CSharp { return e != null; } - - Parameters parameters = null; - public Parameters Parameters { - get { - Block b = this; - while (b.Parent != null) - b = b.Parent; - return b.parameters; + + // + // Returns a `ParameterReference' for the given name, or null if there + // is no such parameter + // + public ParameterReference GetParameterReference (string name, Location loc) + { + Parameter par; + int idx; + + for (Block b = this; b != null; b = b.Toplevel.Parent) { + Parameters pars = b.Toplevel.Parameters; + par = pars.GetParameterByName (name, out idx); + if (par != null) + return new ParameterReference (pars, this, idx, name, loc); } + return null; } + // + // Whether the parameter named `name' is local to this block, + // or false, if the parameter belongs to an encompassing block. + // + public bool IsLocalParameter (string name) + { + return Toplevel.Parameters.GetParameterByName (name) != null; + } + + // + // Whether the `name' is a parameter reference + // + public bool IsParameterReference (string name) + { + Parameter par; + int idx; + + for (Block b = this; b != null; b = b.Toplevel.Parent) { + par = b.Toplevel.Parameters.GetParameterByName (name, out idx); + if (par != null) + return true; + } + return false; + } + /// /// A list of labels that were not used within this block /// @@ -1611,7 +1720,7 @@ namespace Mono.CSharp { public VariableMap ParameterMap { get { if ((flags & Flags.VariablesInitialized) == 0) - throw new Exception (); + throw new Exception ("Variables have not been initialized yet"); return param_map; } @@ -1620,17 +1729,12 @@ namespace Mono.CSharp { public VariableMap LocalMap { get { if ((flags & Flags.VariablesInitialized) == 0) - throw new Exception (); + throw new Exception ("Variables have not been initialized yet"); return local_map; } } - public bool LiftVariable (LocalInfo local_info) - { - return false; - } - /// /// Emits the variable declarations and labels. /// @@ -1638,9 +1742,13 @@ namespace Mono.CSharp { /// tc: is our typecontainer (to resolve type references) /// ig: is the code generator: /// - public void EmitMeta (EmitContext ec, InternalParameters ip) + public void ResolveMeta (ToplevelBlock toplevel, EmitContext ec, InternalParameters ip) { - ILGenerator ig = ec.ig; + bool old_unsafe = ec.InUnsafe; + + // If some parent block was unsafe, we remain unsafe even if this block + // isn't explicitly marked as such. + ec.InUnsafe |= Unsafe; // // Compute the VariableMap's. @@ -1669,8 +1777,7 @@ namespace Mono.CSharp { bool old_check_state = ec.ConstantCheckState; ec.ConstantCheckState = (flags & Flags.Unchecked) == 0; - bool remap_locals = ec.RemapToProxy; - + // // Process this block variables // @@ -1695,6 +1802,7 @@ namespace Mono.CSharp { continue; } +#if false if (remap_locals) vi.FieldBuilder = ec.MapVariable (name, vi.VariableType); else if (vi.Pinned) @@ -1705,6 +1813,7 @@ namespace Mono.CSharp { vi.LocalBuilder = TypeManager.DeclareLocalPinned (ig, vi.VariableType); else if (!vi.IsThis) vi.LocalBuilder = ig.DeclareLocal (vi.VariableType); +#endif if (constants == null) continue; @@ -1743,7 +1852,46 @@ namespace Mono.CSharp { // if (children != null){ foreach (Block b in children) - b.EmitMeta (ec, ip); + b.ResolveMeta (toplevel, ec, ip); + } + ec.InUnsafe = old_unsafe; + } + + // + // Emits the local variable declarations for a block + // + public void EmitMeta (EmitContext ec) + { + ILGenerator ig = ec.ig; + + if (variables != null){ + bool have_captured_vars = ec.HaveCapturedVariables (); + bool remap_locals = ec.RemapToProxy; + + foreach (DictionaryEntry de in variables){ + LocalInfo vi = (LocalInfo) de.Value; + + if (have_captured_vars && ec.IsCaptured (vi)) + continue; + + if (remap_locals){ + vi.FieldBuilder = ec.MapVariable (vi.Name, vi.VariableType); + } else { + if (vi.Pinned) + // + // This is needed to compile on both .NET 1.x and .NET 2.x + // the later introduced `DeclareLocal (Type t, bool pinned)' + // + vi.LocalBuilder = TypeManager.DeclareLocalPinned (ig, vi.VariableType); + else if (!vi.IsThis) + vi.LocalBuilder = ig.DeclareLocal (vi.VariableType); + } + } + } + + if (children != null){ + foreach (Block b in children) + b.EmitMeta (ec); } } @@ -1783,6 +1931,12 @@ namespace Mono.CSharp { Report.Debug (4, "RESOLVE BLOCK", StartLocation, ec.CurrentBranching); + // + // This flag is used to notate nested statements as unreachable from the beginning of this block. + // For the purposes of this resolution, it doesn't matter that the whole block is unreachable + // from the beginning of the function. The outer Resolve() that detected the unreachability is + // responsible for handling the situation. + // bool unreachable = false; int statement_count = statements.Count; @@ -1801,8 +1955,10 @@ namespace Mono.CSharp { else s.loc = Location.Null; - statements [ix] = EmptyStatement.Value; - continue; + if (ok && !(s is Block)) { + statements [ix] = EmptyStatement.Value; + continue; + } } if (s.Resolve (ec) == false) { @@ -1859,7 +2015,18 @@ namespace Mono.CSharp { public override bool ResolveUnreachable (EmitContext ec, bool warn) { unreachable_shown = true; - return base.ResolveUnreachable (ec, warn); + + if (warn && (RootContext.WarningLevel >= 2)) + Report.Warning (162, loc, "Unreachable code detected"); + + if (Implicit) + return Resolve (ec); + + ec.StartFlowBranching (FlowBranching.BranchingType.Block, loc); + bool ok = Resolve (ec); + ec.KillFlowBranching (); + + return ok; } protected override void DoEmit (EmitContext ec) @@ -1870,7 +2037,7 @@ namespace Mono.CSharp { // Check whether we are the last statement in a // top-level block. - if ((Parent == null) && (ix+1 == num_statements)) + if (((Parent == null) || Implicit) && (ix+1 == num_statements) && !(s is Block)) ec.IsLastStatement = true; else ec.IsLastStatement = false; @@ -1890,7 +2057,7 @@ namespace Mono.CSharp { if (emit_debug_info) { if (is_lexical_block) - ec.ig.BeginScope (); + ec.BeginScope (); if (variables != null) { foreach (DictionaryEntry de in variables) { @@ -1910,23 +2077,113 @@ namespace Mono.CSharp { ec.Mark (EndLocation, true); if (emit_debug_info && is_lexical_block) - ec.ig.EndScope (); + ec.EndScope (); 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; + } } // + // A toplevel block contains extra information, the split is done + // only to separate information that would otherwise bloat the more + // lightweight Block. + // + // In particular, this was introduced when the support for Anonymous + // Methods was implemented. // public class ToplevelBlock : Block { + // + // Pointer to the host of this anonymous method, or null + // if we are the topmost block + // + public ToplevelBlock Container; + CaptureContext capture_context; + + Hashtable capture_contexts; + + // + // The parameters for the block. + // + public readonly Parameters Parameters; + + public void RegisterCaptureContext (CaptureContext cc) + { + if (capture_contexts == null) + capture_contexts = new Hashtable (); + capture_contexts [cc] = cc; + } + + public void CompleteContexts () + { + if (capture_contexts == null) + return; + + foreach (CaptureContext cc in capture_contexts.Keys){ + cc.AdjustScopes (); + } + } + + public CaptureContext ToplevelBlockCaptureContext { + get { + return capture_context; + } + } + + // + // Parent is only used by anonymous blocks to link back to their + // parents + // + public ToplevelBlock (ToplevelBlock container, Parameters parameters, Location start) : + this (container, (Flags) 0, parameters, start) + { + } + public ToplevelBlock (Parameters parameters, Location start) : - base (null, parameters, start, Location.Null) + this (null, (Flags) 0, parameters, start) { } public ToplevelBlock (Flags flags, Parameters parameters, Location start) : - base (null, flags, parameters, start, Location.Null) + this (null, flags, parameters, start) + { + } + + public ToplevelBlock (ToplevelBlock container, Flags flags, Parameters parameters, Location start) : + base (null, flags | Flags.IsToplevel, start, Location.Null) + { + Parameters = parameters == null ? Parameters.EmptyReadOnlyParameters : parameters; + Container = container; + } + + public ToplevelBlock (Location loc) : this (null, (Flags) 0, null, loc) + { + } + + public void SetHaveAnonymousMethods (Location loc, AnonymousMethod host) { + if (capture_context == null) + capture_context = new CaptureContext (this, loc, host); + } + + public CaptureContext CaptureContext { + get { + return capture_context; + } } } @@ -1934,8 +2191,11 @@ namespace Mono.CSharp { Expression label; object converted; public Location loc; - public Label ILLabel; - public Label ILLabelCode; + + Label il_label; + bool il_label_set; + Label il_label_code; + bool il_label_code_set; // // if expr == null, then it is the default case. @@ -1958,15 +2218,30 @@ namespace Mono.CSharp { } } + public Label GetILLabel (EmitContext ec) + { + if (!il_label_set){ + il_label = ec.ig.DefineLabel (); + il_label_set = true; + } + return il_label; + } + + public Label GetILLabelCode (EmitContext ec) + { + if (!il_label_code_set){ + il_label_code = ec.ig.DefineLabel (); + il_label_code_set = true; + } + return il_label_code; + } + // // Resolves the expression, reduces it to a literal if possible // and then converts it to the requested type. // public bool ResolveAndReduce (EmitContext ec, Type required_type) { - ILLabel = ec.ig.DefineLabel (); - ILLabelCode = ec.ig.DefineLabel (); - if (label == null) return true; @@ -1983,7 +2258,6 @@ namespace Mono.CSharp { if (e is StringConstant || e is NullLiteral){ if (required_type == TypeManager.string_type){ converted = e; - ILLabel = ec.ig.DefineLabel (); return true; } } @@ -2080,12 +2354,12 @@ namespace Mono.CSharp { if (allowed_types == null){ allowed_types = new Type [] { + TypeManager.int32_type, + TypeManager.uint32_type, TypeManager.sbyte_type, TypeManager.byte_type, TypeManager.short_type, TypeManager.ushort_type, - TypeManager.int32_type, - TypeManager.uint32_type, TypeManager.int64_type, TypeManager.uint64_type, TypeManager.char_type, @@ -2108,13 +2382,26 @@ namespace Mono.CSharp { if (e == null) continue; + // + // Ignore over-worked ImplicitUserConversions that do + // an implicit conversion in addition to the user conversion. + // + if (e is UserCast){ + UserCast ue = e as UserCast; + + if (ue.Source != Expr) + e = null; + } + if (converted != null){ - Report.Error (-12, loc, "More than one conversion to an integral " + - " type exists for type `" + - TypeManager.CSharpName (Expr.Type)+"'"); + Report.ExtraInformation ( + loc, + String.Format ("reason: more than one conversion to an integral type exist for type {0}", + TypeManager.CSharpName (Expr.Type))); return null; - } else + } else { converted = e; + } } return converted; } @@ -2450,7 +2737,7 @@ namespace Mono.CSharp { ig.Emit (OpCodes.Ldloc, val); EmitObjectInteger (ig, key); SwitchLabel sl = (SwitchLabel) Elements [key]; - ig.Emit (OpCodes.Beq, sl.ILLabel); + ig.Emit (OpCodes.Beq, sl.GetILLabel (ec)); } } else @@ -2506,7 +2793,7 @@ namespace Mono.CSharp { if (System.Convert.ToInt64 (key) == kb.nFirst + iJump) { SwitchLabel sl = (SwitchLabel) Elements [key]; - rgLabels [iJump] = sl.ILLabel; + rgLabels [iJump] = sl.GetILLabel (ec); iKey++; } else @@ -2534,8 +2821,8 @@ namespace Mono.CSharp { { foreach (SwitchLabel sl in ss.Labels) { - ig.MarkLabel (sl.ILLabel); - ig.MarkLabel (sl.ILLabelCode); + ig.MarkLabel (sl.GetILLabel (ec)); + ig.MarkLabel (sl.GetILLabelCode (ec)); if (sl.Label == null) { ig.MarkLabel (lblDefault); @@ -2593,7 +2880,7 @@ namespace Mono.CSharp { null_found = false; for (int label = 0; label < label_count; label++){ SwitchLabel sl = (SwitchLabel) ss.Labels [label]; - ig.MarkLabel (sl.ILLabel); + ig.MarkLabel (sl.GetILLabel (ec)); if (!first_test){ ig.MarkLabel (next_test); @@ -2635,7 +2922,7 @@ namespace Mono.CSharp { ig.MarkLabel (null_target); ig.MarkLabel (sec_begin); foreach (SwitchLabel sl in ss.Labels) - ig.MarkLabel (sl.ILLabelCode); + ig.MarkLabel (sl.GetILLabelCode (ec)); if (mark_default) ig.MarkLabel (default_target); @@ -2664,24 +2951,6 @@ namespace Mono.CSharp { return null; } - bool ResolveConstantSwitch (EmitContext ec) - { - object key = ((Constant) new_expr).GetValue (); - SwitchLabel label = (SwitchLabel) Elements [key]; - - if (label == null) - return true; - - constant_section = FindSection (label); - if (constant_section == null) - return true; - - if (constant_section.Block.Resolve (ec) != true) - return false; - - return true; - } - public override bool Resolve (EmitContext ec) { Expr = Expr.Resolve (ec); @@ -2973,6 +3242,7 @@ namespace Mono.CSharp { public Unsafe (Block b) { Block = b; + Block.Unsafe = true; } public override bool Resolve (EmitContext ec) @@ -3005,15 +3275,81 @@ namespace Mono.CSharp { ArrayList declarators; Statement statement; Type expr_type; - FixedData[] data; + Emitter[] data; bool has_ret; - struct FixedData { - public bool is_object; - public LocalInfo vi; - public Expression expr; - public Expression converted; - } + abstract class Emitter + { + protected LocalInfo vi; + protected Expression converted; + + protected Emitter (Expression expr, LocalInfo li) + { + converted = expr; + vi = li; + } + + public abstract void Emit (EmitContext ec); + public abstract void EmitExit (ILGenerator ig); + } + + class ExpressionEmitter: Emitter { + public ExpressionEmitter (Expression converted, LocalInfo li) : + base (converted, li) + { + } + + public override void Emit (EmitContext ec) { + // + // Store pointer in pinned location + // + converted.Emit (ec); + ec.ig.Emit (OpCodes.Stloc, vi.LocalBuilder); + } + + public override void EmitExit (ILGenerator ig) + { + ig.Emit (OpCodes.Ldc_I4_0); + ig.Emit (OpCodes.Conv_U); + ig.Emit (OpCodes.Stloc, vi.LocalBuilder); + } + } + + class StringEmitter: Emitter { + LocalBuilder pinned_string; + Location loc; + + public StringEmitter (Expression expr, LocalInfo li, Location loc): + base (expr, li) + { + this.loc = loc; + } + + public override void Emit (EmitContext ec) + { + ILGenerator ig = ec.ig; + pinned_string = TypeManager.DeclareLocalPinned (ig, TypeManager.string_type); + + converted.Emit (ec); + ig.Emit (OpCodes.Stloc, pinned_string); + + Expression sptr = new StringPtr (pinned_string, loc); + converted = Convert.ImplicitConversionRequired ( + ec, sptr, vi.VariableType, loc); + + if (converted == null) + return; + + converted.Emit (ec); + ig.Emit (OpCodes.Stloc, vi.LocalBuilder); + } + + public override void EmitExit(ILGenerator ig) + { + ig.Emit (OpCodes.Ldnull); + ig.Emit (OpCodes.Stloc, pinned_string); + } + } public Fixed (Expression type, ArrayList decls, Statement stmt, Location l) { @@ -3030,10 +3366,12 @@ namespace Mono.CSharp { return false; } - expr_type = ec.DeclSpace.ResolveType (type, false, loc); - if (expr_type == null) + TypeExpr texpr = type.ResolveAsTypeTerminal (ec, false); + if (texpr == null) return false; + expr_type = texpr.ResolveType (ec); + CheckObsolete (expr_type); if (ec.RemapToProxy){ @@ -3041,7 +3379,7 @@ namespace Mono.CSharp { return false; } - data = new FixedData [declarators.Count]; + data = new Emitter [declarators.Count]; if (!expr_type.IsPointer){ Report.Error (209, loc, "Variables in a fixed statement must be pointers"); @@ -3098,10 +3436,7 @@ namespace Mono.CSharp { if (!TypeManager.VerifyUnManaged (child.Type, loc)) return false; - data [i].is_object = true; - data [i].expr = e; - data [i].converted = null; - data [i].vi = vi; + data [i] = new ExpressionEmitter (e, vi); i++; continue; @@ -3129,17 +3464,14 @@ namespace Mono.CSharp { // and T* is implicitly convertible to the // pointer type given in the fixed statement. // - ArrayPtr array_ptr = new ArrayPtr (e, loc); + ArrayPtr array_ptr = new ArrayPtr (e, array_type, loc); Expression converted = Convert.ImplicitConversionRequired ( ec, array_ptr, vi.VariableType, loc); if (converted == null) return false; - data [i].is_object = false; - data [i].expr = e; - data [i].converted = converted; - data [i].vi = vi; + data [i] = new ExpressionEmitter (converted, vi); i++; continue; @@ -3149,14 +3481,30 @@ namespace Mono.CSharp { // Case 3: string // if (e.Type == TypeManager.string_type){ - data [i].is_object = false; - data [i].expr = e; - data [i].converted = null; - data [i].vi = vi; + data [i] = new StringEmitter (e, vi, loc); i++; continue; } + // Case 4: fixed buffer + FieldExpr fe = e as FieldExpr; + if (fe != null) { + IFixedBuffer ff = AttributeTester.GetFixedBuffer (fe.FieldInfo); + if (ff != null) { + Expression fixed_buffer_ptr = new FixedBufferPtr (fe, ff.ElementType, loc); + + Expression converted = Convert.ImplicitConversionRequired ( + ec, fixed_buffer_ptr, vi.VariableType, loc); + if (converted == null) + return false; + + data [i] = new ExpressionEmitter (converted, vi); + i++; + + continue; + } + } + // // For other cases, flag a `this is already fixed expression' // @@ -3186,60 +3534,8 @@ namespace Mono.CSharp { protected override void DoEmit (EmitContext ec) { - ILGenerator ig = ec.ig; - - LocalBuilder [] clear_list = new LocalBuilder [data.Length]; - for (int i = 0; i < data.Length; i++) { - LocalInfo vi = data [i].vi; - - // - // Case 1: & object. - // - if (data [i].is_object) { - // - // Store pointer in pinned location - // - data [i].expr.Emit (ec); - ig.Emit (OpCodes.Stloc, vi.LocalBuilder); - clear_list [i] = vi.LocalBuilder; - continue; - } - - // - // Case 2: Array - // - if (data [i].expr.Type.IsArray){ - // - // Store pointer in pinned location - // - data [i].converted.Emit (ec); - - ig.Emit (OpCodes.Stloc, vi.LocalBuilder); - clear_list [i] = vi.LocalBuilder; - continue; - } - - // - // Case 3: string - // - if (data [i].expr.Type == TypeManager.string_type){ - LocalBuilder pinned_string = TypeManager.DeclareLocalPinned (ig, TypeManager.string_type); - clear_list [i] = pinned_string; - - data [i].expr.Emit (ec); - ig.Emit (OpCodes.Stloc, pinned_string); - - Expression sptr = new StringPtr (pinned_string, loc); - Expression converted = Convert.ImplicitConversionRequired ( - ec, sptr, vi.VariableType, loc); - - if (converted == null) - continue; - - converted.Emit (ec); - ig.Emit (OpCodes.Stloc, vi.LocalBuilder); - } + data [i].Emit (ec); } statement.Emit (ec); @@ -3247,18 +3543,13 @@ namespace Mono.CSharp { if (has_ret) return; + ILGenerator ig = ec.ig; + // // Clear the pinned variable // for (int i = 0; i < data.Length; i++) { - if (data [i].is_object || data [i].expr.Type.IsArray) { - ig.Emit (OpCodes.Ldc_I4_0); - ig.Emit (OpCodes.Conv_U); - ig.Emit (OpCodes.Stloc, clear_list [i]); - } else if (data [i].expr.Type == TypeManager.string_type){ - ig.Emit (OpCodes.Ldnull); - ig.Emit (OpCodes.Stloc, clear_list [i]); - } + data [i].EmitExit (ig); } } } @@ -3296,21 +3587,30 @@ namespace Mono.CSharp { public override bool Resolve (EmitContext ec) { - if (type_expr != null) { - type = ec.DeclSpace.ResolveType (type_expr, false, loc); - if (type == null) - return false; + bool was_catch = ec.InCatch; + ec.InCatch = true; + try { + if (type_expr != null) { + TypeExpr te = type_expr.ResolveAsTypeTerminal (ec, false); + if (te == null) + return false; - CheckObsolete (type); + type = te.ResolveType (ec); - if (type != TypeManager.exception_type && !type.IsSubclassOf (TypeManager.exception_type)){ - Error (155, "The type caught or thrown must be derived from System.Exception"); - return false; - } - } else - type = null; + CheckObsolete (type); + + if (type != TypeManager.exception_type && !type.IsSubclassOf (TypeManager.exception_type)){ + Error (155, "The type caught or thrown must be derived from System.Exception"); + return false; + } + } else + type = null; - return Block.Resolve (ec); + return Block.Resolve (ec); + } + finally { + ec.InCatch = was_catch; + } } } @@ -3405,9 +3705,11 @@ namespace Mono.CSharp { Fini, FlowBranching.SiblingType.Finally); Report.Debug (1, "STARTED SIBLING FOR FINALLY", ec.CurrentBranching, vector); - + bool was_finally = ec.InFinally; + ec.InFinally = true; if (!Fini.Resolve (ec)) ok = false; + ec.InFinally = was_finally; } ResolveFinally (branching); @@ -3473,6 +3775,13 @@ namespace Mono.CSharp { Fini.Emit (ec); } } + + public bool HasCatch + { + get { + return General != null || Specific.Count > 0; + } + } } public class Using : ExceptionStatement { @@ -3499,12 +3808,14 @@ namespace Mono.CSharp { // bool ResolveLocalVariableDecls (EmitContext ec) { - expr_type = ec.DeclSpace.ResolveType (expr, false, loc); int i = 0; - if (expr_type == null) + TypeExpr texpr = expr.ResolveAsTypeTerminal (ec, false); + if (texpr == null) return false; + expr_type = texpr.ResolveType (ec); + // // The type must be an IDisposable or an implicit conversion // must exist. @@ -3562,11 +3873,11 @@ namespace Mono.CSharp { bool ResolveExpression (EmitContext ec) { if (!TypeManager.ImplementsInterface (expr_type, TypeManager.idisposable_type)){ - conv = Convert.ImplicitConversionRequired ( - ec, expr, TypeManager.idisposable_type, loc); - - if (conv == null) + if (Convert.ImplicitConversion (ec, expr, TypeManager.idisposable_type, loc) == null) { + Report.Error (1674, loc, "'{0}': type used in a using statement must be implicitly convertible to 'System.IDisposable'", + TypeManager.CSharpName (expr_type)); return false; + } } return true; @@ -3597,7 +3908,7 @@ namespace Mono.CSharp { ILGenerator ig = ec.ig; int i = assign.Length; - foreach (DictionaryEntry e in var_list){ + for (int ii = 0; ii < var_list.Count; ++ii){ Expression var = resolved_vars [--i]; Label skip = ig.DefineLabel (); @@ -3671,12 +3982,39 @@ namespace Mono.CSharp { void EmitExpressionFinally (EmitContext ec) { ILGenerator ig = ec.ig; - Label skip = ig.DefineLabel (); - ig.Emit (OpCodes.Ldloc, local_copy); - ig.Emit (OpCodes.Brfalse, skip); - ig.Emit (OpCodes.Ldloc, local_copy); - ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void); - ig.MarkLabel (skip); + if (!local_copy.LocalType.IsValueType) { + Label skip = ig.DefineLabel (); + ig.Emit (OpCodes.Ldloc, local_copy); + ig.Emit (OpCodes.Brfalse, skip); + ig.Emit (OpCodes.Ldloc, local_copy); + ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void); + ig.MarkLabel (skip); + } else { + Expression ml = Expression.MemberLookup(ec, TypeManager.idisposable_type, local_copy.LocalType, "Dispose", Mono.CSharp.Location.Null); + + if (!(ml is MethodGroupExpr)) { + ig.Emit (OpCodes.Ldloc, local_copy); + ig.Emit (OpCodes.Box, local_copy.LocalType); + ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void); + } else { + MethodInfo mi = null; + + foreach (MethodInfo mk in ((MethodGroupExpr) ml).Methods) { + if (TypeManager.GetArgumentTypes (mk).Length == 0) { + mi = mk; + break; + } + } + + if (mi == null) { + Report.Error(-100, Mono.CSharp.Location.Null, "Internal error: No Dispose method which takes 0 parameters."); + return; + } + + ig.Emit (OpCodes.Ldloca, local_copy); + ig.Emit (OpCodes.Call, mi); + } + } } public override bool Resolve (EmitContext ec) @@ -3771,9 +4109,16 @@ namespace Mono.CSharp { if (expr == null) return false; - var_type = ec.DeclSpace.ResolveType (type, false, loc); - if (var_type == null) + if (expr is NullLiteral) { + Report.Error (186, expr.Location, "Use of null is not valid in this context"); + return false; + } + + TypeExpr texpr = type.ResolveAsTypeTerminal (ec, false); + if (texpr == null) return false; + + var_type = texpr.ResolveType (ec); // // We need an instance variable. Not sure this is the best @@ -3798,8 +4143,12 @@ namespace Mono.CSharp { if (hm == null){ error1579 (expr.Type); return false; - } + } + // When ProbeCollection reported error + if (hm.move_next == null) + return false; + array_type = expr.Type; element_type = hm.element_type; @@ -3936,10 +4285,12 @@ namespace Mono.CSharp { public Type element_type; public Type enumerator_type; public bool is_disposable; + public readonly Location Location; - public ForeachHelperMethods (EmitContext ec) + public ForeachHelperMethods (EmitContext ec, Location loc) { this.ec = ec; + this.Location = loc; this.element_type = TypeManager.object_type; this.enumerator_type = TypeManager.ienumerator_type; this.is_disposable = true; @@ -3964,7 +4315,6 @@ namespace Mono.CSharp { return false; } ForeachHelperMethods hm = (ForeachHelperMethods) criteria; - EmitContext ec = hm.ec; // Check whether GetEnumerator is public if ((mi.Attributes & MethodAttributes.Public) != MethodAttributes.Public) @@ -4014,6 +4364,16 @@ namespace Mono.CSharp { } else { + if (return_type.IsPointer || return_type.IsArray) { + Report.SymbolRelatedToPreviousError (mi); + Type t = return_type.GetElementType (); + Report.SymbolRelatedToPreviousError (t); + Report.Error (202, hm.Location, "foreach requires that the return type '{0}' of '{1}' must have a suitable public MoveNext method and public Current property", + TypeManager.CSharpName (return_type), TypeManager.GetFullNameSignature (m)); + hm.get_enumerator = mi; + return false; + } + // // Ok, so they dont return an IEnumerable, we will have to // find if they support the GetEnumerator pattern. @@ -4078,7 +4438,7 @@ namespace Mono.CSharp { // ForeachHelperMethods ProbeCollectionType (EmitContext ec, Type t) { - ForeachHelperMethods hm = new ForeachHelperMethods (ec); + ForeachHelperMethods hm = new ForeachHelperMethods (ec, loc); for (Type tt = t; tt != null && tt != TypeManager.object_type;){ if (TryType (tt, hm)) @@ -4121,7 +4481,7 @@ namespace Mono.CSharp { ILGenerator ig = ec.ig; enumerator = new VariableStorage (ec, hm.enumerator_type); - enumerator.EmitThis (); + enumerator.EmitThis (ig); // // Instantiate the enumerator // @@ -4153,7 +4513,7 @@ namespace Mono.CSharp { expr.Emit (ec); ig.Emit (OpCodes.Callvirt, hm.get_enumerator); } - enumerator.EmitStore (); + enumerator.EmitStore (ig); // // Protect the code in a try/finalize block, so that @@ -4166,17 +4526,18 @@ namespace Mono.CSharp { ig.MarkLabel (ec.LoopBegin); - enumerator.EmitCall (hm.move_next); + enumerator.EmitCall (ig, hm.move_next); ig.Emit (OpCodes.Brfalse, end_try); + if (ec.InIterator) - ec.EmitThis (); + ig.Emit (OpCodes.Ldarg_0); - enumerator.EmitCall (hm.get_current); + enumerator.EmitCall (ig, hm.get_current); if (ec.InIterator){ conv.Emit (ec); - ig.Emit (OpCodes.Stfld, ((FieldExpr) variable).FieldInfo); + ig.Emit (OpCodes.Stfld, ((LocalVariableReference) variable).local_info.FieldBuilder); } else ((IAssignMethod)variable).EmitAssign (ec, conv, false, false); @@ -4202,30 +4563,36 @@ namespace Mono.CSharp { ILGenerator ig = ec.ig; if (hm.enumerator_type.IsValueType) { - enumerator.EmitThis (); + enumerator.EmitThis (ig); MethodInfo mi = FetchMethodDispose (hm.enumerator_type); if (mi != null) { - enumerator.EmitLoadAddress (); + enumerator.EmitLoadAddress (ig); ig.Emit (OpCodes.Call, mi); } else { - enumerator.EmitLoad (); + enumerator.EmitLoad (ig); ig.Emit (OpCodes.Box, hm.enumerator_type); ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void); - } + } } else { Label call_dispose = ig.DefineLabel (); - enumerator.EmitThis (); - enumerator.EmitLoad (); + enumerator.EmitThis (ig); + enumerator.EmitLoad (ig); ig.Emit (OpCodes.Isinst, TypeManager.idisposable_type); ig.Emit (OpCodes.Dup); ig.Emit (OpCodes.Brtrue_S, call_dispose); ig.Emit (OpCodes.Pop); - ig.Emit (OpCodes.Endfinally); + + Label end_finally = ig.DefineLabel (); + ig.Emit (OpCodes.Br, end_finally); ig.MarkLabel (call_dispose); ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void); + ig.MarkLabel (end_finally); + + if (emit_finally) + ig.Emit (OpCodes.Endfinally); } } @@ -4243,18 +4610,18 @@ namespace Mono.CSharp { // // Make our copy of the array // - copy.EmitThis (); + copy.EmitThis (ig); expr.Emit (ec); - copy.EmitStore (); + copy.EmitStore (ig); if (rank == 1){ VariableStorage counter = new VariableStorage (ec,TypeManager.int32_type); Label loop, test; - counter.EmitThis (); + counter.EmitThis (ig); ig.Emit (OpCodes.Ldc_I4_0); - counter.EmitStore (); + counter.EmitStore (ig); test = ig.DefineLabel (); ig.Emit (OpCodes.Br, test); @@ -4262,12 +4629,12 @@ namespace Mono.CSharp { ig.MarkLabel (loop); if (ec.InIterator) - ec.EmitThis (); + ig.Emit (OpCodes.Ldarg_0); - copy.EmitThis (); - copy.EmitLoad (); - counter.EmitThis (); - counter.EmitLoad (); + copy.EmitThis (ig); + copy.EmitLoad (ig); + counter.EmitThis (ig); + counter.EmitLoad (ig); // // Load the value, we load the value using the underlying type, @@ -4276,25 +4643,25 @@ namespace Mono.CSharp { ArrayAccess.EmitLoadOpcode (ig, element_type); if (ec.InIterator){ conv.Emit (ec); - ig.Emit (OpCodes.Stfld, ((FieldExpr) variable).FieldInfo); + ig.Emit (OpCodes.Stfld, ((LocalVariableReference) variable).local_info.FieldBuilder); } else ((IAssignMethod)variable).EmitAssign (ec, conv, false, false); statement.Emit (ec); ig.MarkLabel (ec.LoopBegin); - counter.EmitThis (); - counter.EmitThis (); - counter.EmitLoad (); + counter.EmitThis (ig); + counter.EmitThis (ig); + counter.EmitLoad (ig); ig.Emit (OpCodes.Ldc_I4_1); ig.Emit (OpCodes.Add); - counter.EmitStore (); + counter.EmitStore (ig); ig.MarkLabel (test); - counter.EmitThis (); - counter.EmitLoad (); - copy.EmitThis (); - copy.EmitLoad (); + counter.EmitThis (ig); + counter.EmitLoad (ig); + copy.EmitThis (ig); + copy.EmitLoad (ig); ig.Emit (OpCodes.Ldlen); ig.Emit (OpCodes.Conv_I4); ig.Emit (OpCodes.Blt, loop); @@ -4313,30 +4680,31 @@ namespace Mono.CSharp { } for (dim = 0; dim < rank; dim++){ - dim_len [dim].EmitThis (); - copy.EmitThis (); - copy.EmitLoad (); + dim_len [dim].EmitThis (ig); + copy.EmitThis (ig); + copy.EmitLoad (ig); IntLiteral.EmitInt (ig, dim); ig.Emit (OpCodes.Callvirt, TypeManager.int_getlength_int); - dim_len [dim].EmitStore (); + dim_len [dim].EmitStore (ig); } for (dim = 0; dim < rank; dim++){ - dim_count [dim].EmitThis (); + dim_count [dim].EmitThis (ig); ig.Emit (OpCodes.Ldc_I4_0); - dim_count [dim].EmitStore (); + dim_count [dim].EmitStore (ig); ig.Emit (OpCodes.Br, test [dim]); ig.MarkLabel (loop [dim]); } if (ec.InIterator) - ec.EmitThis (); - copy.EmitThis (); - copy.EmitLoad (); + ig.Emit (OpCodes.Ldarg_0); + + copy.EmitThis (ig); + copy.EmitLoad (ig); for (dim = 0; dim < rank; dim++){ - dim_count [dim].EmitThis (); - dim_count [dim].EmitLoad (); + dim_count [dim].EmitThis (ig); + dim_count [dim].EmitLoad (ig); } // @@ -4356,24 +4724,24 @@ namespace Mono.CSharp { ig.Emit (OpCodes.Call, get); if (ec.InIterator){ conv.Emit (ec); - ig.Emit (OpCodes.Stfld, ((FieldExpr) variable).FieldInfo); + ig.Emit (OpCodes.Stfld, ((LocalVariableReference) variable).local_info.FieldBuilder); } else ((IAssignMethod)variable).EmitAssign (ec, conv, false, false); statement.Emit (ec); ig.MarkLabel (ec.LoopBegin); for (dim = rank - 1; dim >= 0; dim--){ - dim_count [dim].EmitThis (); - dim_count [dim].EmitThis (); - dim_count [dim].EmitLoad (); + dim_count [dim].EmitThis (ig); + dim_count [dim].EmitThis (ig); + dim_count [dim].EmitLoad (ig); ig.Emit (OpCodes.Ldc_I4_1); ig.Emit (OpCodes.Add); - dim_count [dim].EmitStore (); + dim_count [dim].EmitStore (ig); ig.MarkLabel (test [dim]); - dim_count [dim].EmitThis (); - dim_count [dim].EmitLoad (); - dim_len [dim].EmitThis (); - dim_len [dim].EmitLoad (); + dim_count [dim].EmitThis (ig); + dim_count [dim].EmitLoad (ig); + dim_len [dim].EmitThis (ig); + dim_len [dim].EmitLoad (ig); ig.Emit (OpCodes.Blt, loop [dim]); } } @@ -4385,7 +4753,7 @@ namespace Mono.CSharp { protected override void DoEmit (EmitContext ec) { ILGenerator ig = ec.ig; - + Label old_begin = ec.LoopBegin, old_end = ec.LoopEnd; ec.LoopBegin = ig.DefineLabel (); ec.LoopEnd = ig.DefineLabel ();