X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fgmcs%2Fstatement.cs;h=9332dd8543b25adf3b99c2cb4d187bc2d71888d8;hb=f489466a114f3bd72845adf8dfcd206a20deae33;hp=f9936936343c2e51727fb04e16f9805e684f1cfb;hpb=234225d112c4b018b8d1796f4c06a15812137500;p=mono.git diff --git a/mcs/gmcs/statement.cs b/mcs/gmcs/statement.cs index f9936936343..9332dd8543b 100644 --- a/mcs/gmcs/statement.cs +++ b/mcs/gmcs/statement.cs @@ -139,11 +139,14 @@ 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; @@ -172,22 +175,22 @@ namespace Mono.CSharp { if ((FalseStatement != null) && !FalseStatement.Resolve (ec)) - return false; - } + return false; + } 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 (); @@ -346,12 +349,14 @@ namespace Mono.CSharp { } ec.StartFlowBranching (FlowBranching.BranchingType.Loop, loc); + if (!infinite) + ec.CurrentBranching.CreateSibling (); if (!Statement.Resolve (ec)) ok = false; - ec.CurrentBranching.Infinite = infinite; - ec.EndFlowBranching (); + ec.CurrentBranching.Infinite = infinite; + ec.EndFlowBranching (); return ok; } @@ -530,7 +535,8 @@ namespace Mono.CSharp { public override bool Resolve (EmitContext ec) { - expr = expr.ResolveStatement (ec); + if (expr != null) + expr = expr.ResolveStatement (ec); return expr != null; } @@ -562,7 +568,7 @@ namespace Mono.CSharp { public override bool Resolve (EmitContext ec) { if (ec.ReturnType == null){ - if (Expr != null){ + if (Expr != null){ if (ec.CurrentAnonymousMethod != null){ Report.Error (1662, loc, String.Format ( "Anonymous method could not be converted to delegate " + @@ -579,6 +585,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; @@ -601,7 +613,7 @@ 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 @@ -632,7 +644,6 @@ namespace Mono.CSharp { public class Goto : Statement { string target; - Block block; LabeledStatement label; public override bool Resolve (EmitContext ec) @@ -651,9 +662,8 @@ namespace Mono.CSharp { return true; } - public Goto (Block parent_block, string label, Location l) + public Goto (string label, Location l) { - block = parent_block; loc = l; target = label; } @@ -863,13 +873,13 @@ namespace Mono.CSharp { return true; } - if (ec.CurrentBranching.InFinally (true)) { - Error (724, "A throw statement with no argument is only allowed in a catch clause nested inside of the innermost catch clause"); + if (!ec.InCatch) { + Error (156, "A throw statement with no arguments is not allowed outside of a catch clause"); return false; } - if (!ec.CurrentBranching.InCatch ()) { - Error (156, "A throw statement with no argument is only allowed in a catch clause"); + 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; @@ -901,13 +911,13 @@ 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 && ec.CurrentBranching.BreakCrossesTryCatchBoundary()) { Error (157, "Control can not leave the body of the finally block"); return false; } else if (ec.CurrentBranching.InTryOrCatch (false)) ec.CurrentBranching.AddFinallyVector ( ec.CurrentBranching.CurrentUsageVector); - else if (ec.CurrentBranching.InLoop ()) + else if (ec.CurrentBranching.InLoop () || ec.CurrentBranching.InSwitch ()) ec.CurrentBranching.AddBreakVector ( ec.CurrentBranching.CurrentUsageVector); @@ -946,7 +956,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)) @@ -1002,8 +1012,15 @@ namespace Mono.CSharp { AddressTaken = 32 } - Flags flags; + public enum ReadOnlyContext: byte { + Using, + Foreach, + Fixed + } + Flags flags; + ReadOnlyContext ro_context; + public LocalInfo (Expression type, string name, Block block, Location l) { Type = type; @@ -1116,9 +1133,28 @@ namespace Mono.CSharp { get { return (flags & Flags.ReadOnly) != 0; } - set { - flags = value ? (flags | Flags.ReadOnly) : (unchecked (flags & ~Flags.ReadOnly)); + } + + public void SetReadOnlyContext (ReadOnlyContext context) + { + flags |= Flags.ReadOnly; + ro_context = context; + } + + public string GetReadOnlyContext () + { + if (!ReadOnly) + throw new InternalErrorException ("Variable is not readonly"); + + switch (ro_context) { + case ReadOnlyContext.Fixed: + return "fixed variable"; + case ReadOnlyContext.Foreach: + return "foreach iteration variable"; + case ReadOnlyContext.Using: + return "using variable"; } + throw new NotImplementedException (); } // @@ -1163,6 +1199,8 @@ namespace Mono.CSharp { public readonly Location StartLocation; public Location EndLocation = Location.Null; + public readonly ToplevelBlock Toplevel; + [Flags] public enum Flags { Implicit = 1, @@ -1241,11 +1279,6 @@ namespace Mono.CSharp { // // Keeps track of constants Hashtable constants; - - // - // The parameters for the block, this is only needed on the toplevel block really - // TODO: move `parameters' into ToplevelBlock - Parameters parameters; // // If this is a switch section, the enclosing switch block. @@ -1264,42 +1297,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; } } @@ -1446,30 +1470,54 @@ namespace Mono.CSharp { } } - 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 (); - child_variable_names [name] = null; + 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 (child_variable_names == null) + if (known_variables == null) + return null; + return (LocalInfo) known_variables [name]; + } + + public bool CheckInvariantMeaningInBlock (string name, Expression e, Location loc) + { + 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; } // @@ -1496,58 +1544,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 (); @@ -1556,9 +1593,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) @@ -1620,78 +1657,6 @@ namespace Mono.CSharp { return e != null; } - // - // Returns a `ParameterReference' for the given name, or null if there - // is no such parameter - // - public ParameterReference GetParameterReference (string name, Location loc) - { - Block b = this; - - do { - Parameters pars = b.parameters; - - if (pars != null){ - Parameter par; - int idx; - - par = pars.GetParameterByName (name, out idx); - if (par != null){ - ParameterReference pr; - - pr = new ParameterReference (pars, this, idx, name, loc); - return pr; - } - } - b = b.Parent; - } while (b != null); - 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) - { - Block b = this; - int toplevel_count = 0; - - do { - if (this is ToplevelBlock) - toplevel_count++; - - Parameters pars = b.parameters; - if (pars != null){ - if (pars.GetParameterByName (name) != null) - return true; - return false; - } - if (toplevel_count > 0) - return false; - b = b.Parent; - } while (b != null); - return false; - } - - // - // Whether the `name' is a parameter reference - // - public bool IsParameterReference (string name) - { - Block b = this; - - do { - Parameters pars = b.parameters; - - if (pars != null) - if (pars.GetParameterByName (name) != null) - return true; - b = b.Parent; - } while (b != null); - return false; - } - /// /// A list of labels that were not used within this block /// @@ -1844,14 +1809,11 @@ namespace Mono.CSharp { ec.CurrentBlock = this; Expression e = cv.Resolve (ec); - if (e == null) - continue; Constant ce = e as Constant; if (ce == null){ Report.Error (133, vi.Location, - "The expression being assigned to `" + - name + "' must be constant (" + e + ")"); + "The expression being assigned to '{0}' must be constant", name); continue; } @@ -1938,6 +1900,7 @@ namespace Mono.CSharp { } bool unreachable_shown; + bool unreachable; public override bool Resolve (EmitContext ec) { @@ -1951,38 +1914,37 @@ namespace Mono.CSharp { Report.Debug (4, "RESOLVE BLOCK", StartLocation, ec.CurrentBranching); - bool unreachable = unreachable_shown; - + // + // 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. + // int statement_count = statements.Count; for (int ix = 0; ix < statement_count; ix++){ Statement s = (Statement) statements [ix]; - - if (unreachable && !(s is LabeledStatement)) { - if (s == EmptyStatement.Value) - s.loc = EndLocation; - if (!s.ResolveUnreachable (ec, !unreachable_shown)) - ok = false; + if (unreachable) { + if (s is Block) + ((Block) s).unreachable = true; - if (s != EmptyStatement.Value) + if (!unreachable_shown && (RootContext.WarningLevel >= 2)) { + Report.Warning ( + 162, loc, "Unreachable code detected"); unreachable_shown = true; - else - s.loc = Location.Null; - - if (ok && !(s is Block)) { - statements [ix] = EmptyStatement.Value; - continue; } } - if (s.Resolve (ec) == false) { - ok = false; + if (!s.Resolve (ec)) { + ok = false; statements [ix] = EmptyStatement.Value; continue; } - num_statements = ix + 1; + if (unreachable && !(s is LabeledStatement) && !(s is Block)) + statements [ix] = EmptyStatement.Value; + num_statements = ix + 1; if (s is LabeledStatement) unreachable = false; else @@ -2029,13 +1991,11 @@ namespace Mono.CSharp { public override bool ResolveUnreachable (EmitContext ec, bool warn) { unreachable_shown = true; + unreachable = true; 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 (); @@ -2071,7 +2031,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) { @@ -2091,25 +2051,12 @@ namespace Mono.CSharp { ec.Mark (EndLocation, true); if (emit_debug_info && is_lexical_block) - ec.ig.EndScope (); + ec.EndScope (); ec.CurrentBlock = prev_block; } - public ToplevelBlock Toplevel { - get { - Block b = this; - while (b.Parent != null){ - if ((b.flags & Flags.IsToplevel) != 0) - break; - b = b.Parent; - } - - return (ToplevelBlock) b; - } - } - - // + // // Returns true if we ar ea child of `b'. // public bool IsChildOf (Block b) @@ -2123,6 +2070,11 @@ namespace Mono.CSharp { } while (current != null); return false; } + + public override string ToString () + { + return String.Format ("{0} ({1}:{2})", GetType (),ID, StartLocation); + } } // @@ -2140,11 +2092,14 @@ namespace Mono.CSharp { // public ToplevelBlock Container; CaptureContext capture_context; + FlowBranching top_level_branching; Hashtable capture_contexts; - static int did = 0; - + // + // The parameters for the block. + // + public readonly Parameters Parameters; public void RegisterCaptureContext (CaptureContext cc) { @@ -2174,22 +2129,28 @@ namespace Mono.CSharp { // parents // public ToplevelBlock (ToplevelBlock container, Parameters parameters, Location start) : - base (null, Flags.IsToplevel, parameters, start, Location.Null) + this (container, (Flags) 0, parameters, start) { - Container = container; } public ToplevelBlock (Parameters parameters, Location start) : - base (null, Flags.IsToplevel, parameters, start, Location.Null) + this (null, (Flags) 0, parameters, start) { } public ToplevelBlock (Flags flags, Parameters parameters, Location start) : - base (null, flags | Flags.IsToplevel, 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) : base (null, Flags.IsToplevel, loc, loc) + public ToplevelBlock (Location loc) : this (null, (Flags) 0, null, loc) { } @@ -2204,6 +2165,68 @@ namespace Mono.CSharp { return capture_context; } } + + public FlowBranching TopLevelBranching { + get { + return top_level_branching; + } + } + + // + // 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 (ToplevelBlock t = this; t != null; t = t.Container) { + Parameters pars = t.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 Parameters.GetParameterByName (name) != null; + } + + // + // Whether the `name' is a parameter reference + // + public bool IsParameterReference (string name) + { + Parameter par; + int idx; + + for (ToplevelBlock t = this; t != null; t = t.Container) { + if (t.IsLocalParameter (name)) + return true; + } + return false; + } + + public bool ResolveMeta (EmitContext ec, InternalParameters ip) + { + int errors = Report.Errors; + + if (top_level_branching != null) + return true; + + ResolveMeta (this, ec, ip); + + top_level_branching = ec.StartFlowBranching (this); + + return Report.Errors == errors; + } } public class SwitchLabel { @@ -2318,11 +2341,11 @@ namespace Mono.CSharp { // // Computed // - bool got_default; Label default_target; Expression new_expr; bool is_constant; SwitchSection constant_section; + SwitchSection default_section; // // The types allowed to be implicitly cast from @@ -2339,7 +2362,7 @@ namespace Mono.CSharp { public bool GotDefault { get { - return got_default; + return default_section != null; } } @@ -2444,8 +2467,6 @@ namespace Mono.CSharp { bool error = false; Elements = new Hashtable (); - got_default = false; - if (TypeManager.IsEnumType (SwitchType)){ compare_type = TypeManager.EnumToUnderlying (SwitchType); } else @@ -2459,11 +2480,11 @@ namespace Mono.CSharp { } if (sl.Label == null){ - if (got_default){ + if (default_section != null){ Report.Error (152, sl.loc, Error152, "default"); error = true; } - got_default = true; + default_section = ss; continue; } @@ -2869,12 +2890,11 @@ namespace Mono.CSharp { Label end_of_switch = ig.DefineLabel (); Label next_test = ig.DefineLabel (); Label null_target = ig.DefineLabel (); - bool default_found = false; bool first_test = true; bool pending_goto_end = false; + bool null_marked = false; bool null_found; - bool default_at_end = false; - + ig.Emit (OpCodes.Ldloc, val); if (Elements.Contains (NullLiteral.Null)){ @@ -2885,17 +2905,22 @@ namespace Mono.CSharp { ig.Emit (OpCodes.Ldloc, val); ig.Emit (OpCodes.Call, TypeManager.string_isinterneted_string); ig.Emit (OpCodes.Stloc, val); - + int section_count = Sections.Count; for (int section = 0; section < section_count; section++){ SwitchSection ss = (SwitchSection) Sections [section]; + + if (ss == default_section) + continue; + Label sec_begin = ig.DefineLabel (); + ig.Emit (OpCodes.Nop); + if (pending_goto_end) ig.Emit (OpCodes.Br, end_of_switch); int label_count = ss.Labels.Count; - bool mark_default = false; null_found = false; for (int label = 0; label < label_count; label++){ SwitchLabel sl = (SwitchLabel) ss.Labels [label]; @@ -2908,12 +2933,7 @@ namespace Mono.CSharp { // // If we are the default target // - if (sl.Label == null){ - if (label+1 == label_count) - default_at_end = true; - mark_default = true; - default_found = true; - } else { + if (sl.Label != null){ object lit = sl.Converted; if (lit is NullLiteral){ @@ -2937,24 +2957,24 @@ namespace Mono.CSharp { } } } - if (null_found) + if (null_found) { ig.MarkLabel (null_target); + null_marked = true; + } ig.MarkLabel (sec_begin); foreach (SwitchLabel sl in ss.Labels) ig.MarkLabel (sl.GetILLabelCode (ec)); - if (mark_default) - ig.MarkLabel (default_target); ss.Block.Emit (ec); pending_goto_end = !ss.Block.HasRet; first_test = false; } ig.MarkLabel (next_test); - if (default_found){ - if (!default_at_end) - ig.Emit (OpCodes.Br, default_target); - } else - ig.MarkLabel (default_target); + ig.MarkLabel (default_target); + if (!null_marked) + ig.MarkLabel (null_target); + if (default_section != null) + default_section.Block.Emit (ec); ig.MarkLabel (end_of_switch); } @@ -2970,24 +2990,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); @@ -3019,6 +3021,8 @@ namespace Mono.CSharp { SwitchLabel label = (SwitchLabel) Elements [key]; constant_section = FindSection (label); + if (constant_section == null) + constant_section = default_section; } bool first = true; @@ -3038,11 +3042,11 @@ namespace Mono.CSharp { return false; } else { if (!ss.Block.Resolve (ec)) - return false; + return false; } } - if (!got_default) + if (default_section == null) ec.CurrentBranching.CreateSibling ( null, FlowBranching.SiblingType.SwitchSection); @@ -3429,7 +3433,7 @@ namespace Mono.CSharp { Expression e = (Expression) p.Second; vi.VariableInfo.SetAssigned (ec); - vi.ReadOnly = true; + vi.SetReadOnlyContext (LocalInfo.ReadOnlyContext.Fixed); // // The rules for the possible declarators are pretty wise, @@ -3624,23 +3628,30 @@ namespace Mono.CSharp { public override bool Resolve (EmitContext ec) { - if (type_expr != null) { - TypeExpr te = type_expr.ResolveAsTypeTerminal (ec); - if (te == null) - return false; + bool was_catch = ec.InCatch; + ec.InCatch = true; + try { + if (type_expr != null) { + TypeExpr te = type_expr.ResolveAsTypeTerminal (ec); + if (te == null) + return false; - type = te.Type; + type = te.ResolveType (ec); - CheckObsolete (type); + 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; + 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; + } } } @@ -3735,9 +3746,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); @@ -3803,6 +3816,13 @@ namespace Mono.CSharp { Fini.Emit (ec); } } + + public bool HasCatch + { + get { + return General != null || Specific.Count > 0; + } + } } public class Using : ExceptionStatement { @@ -3894,11 +3914,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; @@ -4116,6 +4136,7 @@ namespace Mono.CSharp { Type array_type, element_type; Type var_type; VariableStorage enumerator; + ArrayForeach array; public Foreach (Expression type, LocalVariableReference var, Expression expr, Statement stmt, Location l) @@ -4162,6 +4183,9 @@ namespace Mono.CSharp { element_type = TypeManager.GetElementType (array_type); empty = new EmptyExpression (element_type); + + array = new ArrayForeach (type, variable, expr, statement, loc); + return array.Resolve (ec); } else { hm = ProbeCollectionType (ec, expr.Type); if (hm == null){ @@ -4607,175 +4631,228 @@ namespace Mono.CSharp { } } - // - // FIXME: possible optimization. - // We might be able to avoid creating `empty' if the type is the sam - // - bool EmitArrayForeach (EmitContext ec) + protected override void DoEmit (EmitContext ec) { - int rank = array_type.GetArrayRank (); ILGenerator ig = ec.ig; - - VariableStorage copy = new VariableStorage (ec, array_type); - // - // Make our copy of the array - // - copy.EmitThis (ig); - expr.Emit (ec); - copy.EmitStore (ig); + Label old_begin = ec.LoopBegin, old_end = ec.LoopEnd; + ec.LoopBegin = ig.DefineLabel (); + ec.LoopEnd = ig.DefineLabel (); - if (rank == 1){ - VariableStorage counter = new VariableStorage (ec,TypeManager.int32_type); + if (hm != null) + EmitCollectionForeach (ec); + else + array.Emit (ec); + + ec.LoopBegin = old_begin; + ec.LoopEnd = old_end; + } - Label loop, test; + protected class TemporaryVariable : Expression + { + FieldBuilder fb; + LocalBuilder local; - counter.EmitThis (ig); - ig.Emit (OpCodes.Ldc_I4_0); - counter.EmitStore (ig); - test = ig.DefineLabel (); - ig.Emit (OpCodes.Br, test); + public TemporaryVariable (Type type, Location loc) + { + this.type = type; + this.loc = loc; + eclass = ExprClass.Value; + } - loop = ig.DefineLabel (); - ig.MarkLabel (loop); + static int count; - if (ec.InIterator) - ig.Emit (OpCodes.Ldarg_0); - - copy.EmitThis (ig); - copy.EmitLoad (ig); - counter.EmitThis (ig); - counter.EmitLoad (ig); + public override Expression DoResolve (EmitContext ec) + { + if (ec.InIterator) { + count++; + fb = ec.CurrentIterator.MapVariable ( + "s_", count.ToString (), type); + } else + local = ec.ig.DeclareLocal (type); - // - // Load the value, we load the value using the underlying type, - // then we use the variable.EmitAssign to load using the proper cast. - // - ArrayAccess.EmitLoadOpcode (ig, element_type); - if (ec.InIterator){ - conv.Emit (ec); - ig.Emit (OpCodes.Stfld, ((LocalVariableReference) variable).local_info.FieldBuilder); - } else - ((IAssignMethod)variable).EmitAssign (ec, conv, false, false); + return this; + } - statement.Emit (ec); + public override void Emit (EmitContext ec) + { + ILGenerator ig = ec.ig; - ig.MarkLabel (ec.LoopBegin); - counter.EmitThis (ig); - counter.EmitThis (ig); - counter.EmitLoad (ig); - ig.Emit (OpCodes.Ldc_I4_1); - ig.Emit (OpCodes.Add); - counter.EmitStore (ig); - - ig.MarkLabel (test); - 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); - } else { - VariableStorage [] dim_len = new VariableStorage [rank]; - VariableStorage [] dim_count = new VariableStorage [rank]; - Label [] loop = new Label [rank]; - Label [] test = new Label [rank]; - int dim; - - for (dim = 0; dim < rank; dim++){ - dim_len [dim] = new VariableStorage (ec, TypeManager.int32_type); - dim_count [dim] = new VariableStorage (ec, TypeManager.int32_type); - test [dim] = ig.DefineLabel (); - loop [dim] = ig.DefineLabel (); + if (fb != null) { + ig.Emit (OpCodes.Ldarg_0); + ig.Emit (OpCodes.Ldfld, fb); + } else { + ig.Emit (OpCodes.Ldloc, local); } - - for (dim = 0; dim < rank; dim++){ - 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 (ig); - + } + + public void Store (EmitContext ec, Expression right_side) + { + if (fb != null) + ec.ig.Emit (OpCodes.Ldarg_0); + right_side.Emit (ec); + if (fb == null) + ec.ig.Emit (OpCodes.Stloc, local); + else + ec.ig.Emit (OpCodes.Stfld, fb); + } + + public void EmitThis (ILGenerator ig) + { + if (fb != null) + ig.Emit (OpCodes.Ldarg_0); + } + + public void EmitStore (ILGenerator ig) + { + if (fb == null) + ig.Emit (OpCodes.Stloc, local); + else + ig.Emit (OpCodes.Stfld, fb); + } + } + + protected class ArrayCounter : TemporaryVariable + { + public ArrayCounter (Location loc) + : base (TypeManager.int32_type, loc) + { } + + public void Initialize (EmitContext ec) + { + EmitThis (ec.ig); + ec.ig.Emit (OpCodes.Ldc_I4_0); + EmitStore (ec.ig); + } + + public void Increment (EmitContext ec) + { + EmitThis (ec.ig); + Emit (ec); + ec.ig.Emit (OpCodes.Ldc_I4_1); + ec.ig.Emit (OpCodes.Add); + EmitStore (ec.ig); + } + } + + protected class ArrayForeach : Statement + { + Expression type, variable, expr, conv; + Statement statement; + Type array_type; + Type var_type; + TemporaryVariable[] lengths; + ArrayCounter[] counter; + int rank; + + TemporaryVariable copy; + Expression access; + + public ArrayForeach (Expression type, Expression var, + Expression expr, Statement stmt, Location l) + { + this.type = type; + this.variable = var; + this.expr = expr; + statement = stmt; + loc = l; + } + + public override bool Resolve (EmitContext ec) + { + TypeExpr texpr = type.ResolveAsTypeTerminal (ec); + if (texpr == null) + return false; + + var_type = texpr.Type; + + array_type = expr.Type; + rank = array_type.GetArrayRank (); + + copy = new TemporaryVariable (array_type, loc); + copy.Resolve (ec); + + counter = new ArrayCounter [rank]; + lengths = new TemporaryVariable [rank]; + + ArrayList list = new ArrayList (); + for (int i = 0; i < rank; i++) { + counter [i] = new ArrayCounter (loc); + counter [i].Resolve (ec); + + lengths [i] = new TemporaryVariable (TypeManager.int32_type, loc); + lengths [i].Resolve (ec); + + list.Add (counter [i]); } - for (dim = 0; dim < rank; dim++){ - dim_count [dim].EmitThis (ig); - ig.Emit (OpCodes.Ldc_I4_0); - dim_count [dim].EmitStore (ig); - ig.Emit (OpCodes.Br, test [dim]); - ig.MarkLabel (loop [dim]); + access = new ElementAccess (copy, list, loc).Resolve (ec); + if (access == null) + return false; + + conv = Convert.ExplicitConversion (ec, access, var_type, loc); + if (conv == null) + return false; + + bool ok = true; + + ec.StartFlowBranching (FlowBranching.BranchingType.Loop, loc); + ec.CurrentBranching.CreateSibling (); + + variable = variable.ResolveLValue (ec, conv); + if (variable == null) + ok = false; + + if (!statement.Resolve (ec)) + ok = false; + + ec.EndFlowBranching (); + + return ok; + } + + protected override void DoEmit (EmitContext ec) + { + ILGenerator ig = ec.ig; + + copy.Store (ec, expr); + + Label[] test = new Label [rank]; + Label[] loop = new Label [rank]; + + for (int i = 0; i < rank; i++) { + test [i] = ig.DefineLabel (); + loop [i] = ig.DefineLabel (); + + lengths [i].EmitThis (ig); + ((ArrayAccess) access).EmitGetLength (ec, i); + lengths [i].EmitStore (ig); } - if (ec.InIterator) - ig.Emit (OpCodes.Ldarg_0); - - copy.EmitThis (ig); - copy.EmitLoad (ig); - for (dim = 0; dim < rank; dim++){ - dim_count [dim].EmitThis (ig); - dim_count [dim].EmitLoad (ig); + for (int i = 0; i < rank; i++) { + counter [i].Initialize (ec); + + ig.Emit (OpCodes.Br, test [i]); + ig.MarkLabel (loop [i]); } - // - // FIXME: Maybe we can cache the computation of `get'? - // - Type [] args = new Type [rank]; - MethodInfo get; - - for (int i = 0; i < rank; i++) - args [i] = TypeManager.int32_type; - - ModuleBuilder mb = CodeGen.Module.Builder; - get = mb.GetArrayMethod ( - array_type, "Get", - CallingConventions.HasThis| CallingConventions.Standard, - var_type, args); - ig.Emit (OpCodes.Call, get); - if (ec.InIterator){ - conv.Emit (ec); - ig.Emit (OpCodes.Stfld, ((LocalVariableReference) variable).local_info.FieldBuilder); - } else - ((IAssignMethod)variable).EmitAssign (ec, conv, false, false); + ((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 (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 (ig); - - ig.MarkLabel (test [dim]); - 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]); + + for (int i = rank - 1; i >= 0; i--){ + counter [i].Increment (ec); + + ig.MarkLabel (test [i]); + counter [i].Emit (ec); + lengths [i].Emit (ec); + ig.Emit (OpCodes.Blt, loop [i]); } + + ig.MarkLabel (ec.LoopEnd); } - ig.MarkLabel (ec.LoopEnd); - - return false; - } - - 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 (); - - if (hm != null) - EmitCollectionForeach (ec); - else - EmitArrayForeach (ec); - - ec.LoopBegin = old_begin; - ec.LoopEnd = old_end; } } }