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;
}
}
}