}
ec.StartFlowBranching (FlowBranching.BranchingType.Loop, loc);
+ if (!infinite)
+ ec.CurrentBranching.CreateSibling ();
if (!Statement.Resolve (ec))
ok = false;
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
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;
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);
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))
AddressTaken = 32
}
+ public enum ReadOnlyContext: byte {
+ Using,
+ Foreach,
+ Fixed
+ }
+
Flags flags;
+ ReadOnlyContext ro_context;
public LocalInfo (Expression type, string name, Block block, Location l)
{
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 ();
}
//
int idx;
Parameter p = Toplevel.Parameters.GetParameterByName (name, out idx);
if (p != null) {
- Report.SymbolRelatedToPreviousError (Toplevel.Parameters.Location, name);
+ Report.SymbolRelatedToPreviousError (p.Location, name);
Report.Error (136, l, "'{0}' hides a method parameter", name);
return null;
}
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)
- {
- 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;
- }
-
/// <returns>
/// A list of labels that were not used within this block
/// </returns>
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;
}
}
bool unreachable_shown;
+ bool unreachable;
public override bool Resolve (EmitContext ec)
{
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;
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;
+ //
+ // Warn if we detect unreachable code.
+ //
+ 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;
+ //
+ // Note that we're not using ResolveUnreachable() for unreachable
+ // statements here. ResolveUnreachable() creates a temporary
+ // flow branching and kills it afterwards. This leads to problems
+ // if you have two unreachable statements where the first one
+ // assigns a variable and the second one tries to access it.
+ //
+
+ 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
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 ();
} while (current != null);
return false;
}
+
+ public override string ToString ()
+ {
+ return String.Format ("{0} ({1}:{2})", GetType (),ID, StartLocation);
+ }
}
//
//
public ToplevelBlock Container;
CaptureContext capture_context;
+ FlowBranching top_level_branching;
Hashtable capture_contexts;
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 {
//
// 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
public bool GotDefault {
get {
- return got_default;
+ return default_section != null;
}
}
bool error = false;
Elements = new Hashtable ();
- got_default = false;
-
if (TypeManager.IsEnumType (SwitchType)){
compare_type = TypeManager.EnumToUnderlying (SwitchType);
} else
}
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;
}
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)){
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];
//
// 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){
}
}
}
- 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);
}
SwitchLabel label = (SwitchLabel) Elements [key];
constant_section = FindSection (label);
+ if (constant_section == null)
+ constant_section = default_section;
}
bool first = true;
}
}
- if (!got_default)
+ if (default_section == null)
ec.CurrentBranching.CreateSibling (
null, FlowBranching.SiblingType.SwitchSection);
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,
public override bool Resolve (EmitContext ec)
{
- if (type_expr != null) {
- TypeExpr te = type_expr.ResolveAsTypeTerminal (ec, false);
- if (te == 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;
- type = te.ResolveType (ec);
+ 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;
+ }
}
}
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);
Fini.Emit (ec);
}
}
+
+ public bool HasCatch
+ {
+ get {
+ return General != null || Specific.Count > 0;
+ }
+ }
}
public class Using : ExceptionStatement {
foreach (DictionaryEntry e in var_list){
Expression var = (Expression) e.Key;
- var = var.ResolveLValue (ec, new EmptyExpression ());
+ var = var.ResolveLValue (ec, new EmptyExpression (), loc);
if (var == null)
return false;
Type array_type, element_type;
Type var_type;
VariableStorage enumerator;
+ ArrayForeach array;
public Foreach (Expression type, LocalVariableReference var, Expression expr,
Statement stmt, Location l)
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){
if (conv == null)
ok = false;
- variable = variable.ResolveLValue (ec, empty);
+ variable = variable.ResolveLValue (ec, empty, loc);
if (variable == null)
ok = false;
}
}
- //
- // 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, element_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, false);
+ if (texpr == null)
+ return false;
+
+ var_type = texpr.Type;
+
+ array_type = expr.Type;
+ element_type = TypeManager.GetElementType (array_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, loc);
+ 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);
-
- 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;
+ ig.MarkLabel (ec.LoopEnd);
+ }
}
}
}