2005-01-31 Zoltan Varga <vargaz@freemail.hu>
[mono.git] / mcs / mcs / iterators.cs
1 //
2 // iterators.cs: Support for implementing iterators
3 //
4 // Author:
5 //   Miguel de Icaza (miguel@ximian.com)
6 //
7 // (C) 2003 Ximian, Inc.
8 //
9 // TODO:
10 //    Flow analysis for Yield.
11 //    Emit calls to base object constructor.
12 //
13 // Generics note:
14 //    Current should be defined to return T, and IEnumerator.Current returns object
15 //
16
17 using System;
18 using System.Collections;
19 using System.Reflection;
20 using System.Reflection.Emit;
21
22 namespace Mono.CSharp {
23
24         public interface IIteratorContainer {
25
26                 //
27                 // Invoked if a yield statement is found in the body
28                 //
29                 void SetYields ();
30         }
31         
32         public class Yield : Statement {
33                 public Expression expr;
34                 ArrayList finally_blocks;
35                 
36                 public Yield (Expression expr, Location l)
37                 {
38                         this.expr = expr;
39                         loc = l;
40                 }
41
42                 public static bool CheckContext (EmitContext ec, Location loc)
43                 {
44                         if (ec.CurrentBranching.InFinally (true)){
45                                 Report.Error (1625, loc, "Cannot yield in the body of a " +
46                                               "finally clause");
47                                 return false;
48                         }
49                         if (ec.CurrentBranching.InCatch ()){
50                                 Report.Error (1631, loc, "Cannot yield in the body of a " +
51                                               "catch clause");
52                                 return false;
53                         }
54                         if (ec.CurrentAnonymousMethod != null){
55                                 Report.Error (1621, loc, "yield statement can not appear inside an anonymoud method");
56                                 return false;
57                         }
58
59                         //
60                         // FIXME: Missing check for Yield inside try block that contains catch clauses
61                         //
62                         return true;
63                 }
64                 
65                 public override bool Resolve (EmitContext ec)
66                 {
67                         expr = expr.Resolve (ec);
68                         if (expr == null)
69                                 return false;
70                         if (!CheckContext (ec, loc))
71                                 return false;
72
73                         Iterator iterator = ec.CurrentIterator;
74                         if (expr.Type != iterator.IteratorType){
75                                 expr = Convert.ImplicitConversionRequired (
76                                         ec, expr, iterator.IteratorType, loc);
77                                 if (expr == null)
78                                         return false;
79                         }
80
81                         ec.CurrentBranching.StealFinallyClauses (ref finally_blocks);
82                         return true;
83                 }
84
85                 protected override void DoEmit (EmitContext ec)
86                 {
87                         ec.CurrentIterator.MarkYield (ec, expr, finally_blocks);
88                 }
89         }
90
91         public class YieldBreak : Statement {
92
93                 public YieldBreak (Location l)
94                 {
95                         loc = l;
96                 }
97
98                 public override bool Resolve (EmitContext ec)
99                 {
100                         if (!Yield.CheckContext (ec, loc))
101                                 return false;
102
103                         ec.CurrentBranching.CurrentUsageVector.Goto ();
104                         return true;
105                 }
106
107                 protected override void DoEmit (EmitContext ec)
108                 {
109                         ec.CurrentIterator.EmitYieldBreak (ec.ig);
110                 }
111         }
112
113         public class Iterator : Class {
114                 ToplevelBlock original_block;
115                 ToplevelBlock block;
116                 string original_name;
117
118                 Type iterator_type;
119                 TypeExpr iterator_type_expr;
120                 bool is_enumerable;
121                 bool is_static;
122
123                 Hashtable fields;
124
125                 //
126                 // The state as we generate the iterator
127                 //
128                 Label move_next_ok, move_next_error;
129                 ArrayList resume_points = new ArrayList ();
130                 int pc;
131                 
132                 //
133                 // Context from the original method
134                 //
135                 TypeContainer container;
136                 Type return_type;
137                 Type [] param_types;
138                 InternalParameters parameters;
139
140                 protected enum State {
141                         Uninitialized   = -2,
142                         After,
143                         Running
144                 }
145
146                 static int proxy_count;
147
148                 public void EmitYieldBreak (ILGenerator ig)
149                 {
150                         ig.Emit (OpCodes.Ldarg_0);
151                         IntConstant.EmitInt (ig, (int) State.After);
152                         ig.Emit (OpCodes.Stfld, pc_field.FieldBuilder);
153                         ig.Emit (OpCodes.Br, move_next_error);
154                 }
155
156                 public void EmitMoveNext (EmitContext ec)
157                 {
158                         ILGenerator ig = ec.ig;
159
160                         move_next_ok = ig.DefineLabel ();
161                         move_next_error = ig.DefineLabel ();
162
163                         LocalBuilder retval = ec.GetTemporaryLocal (TypeManager.int32_type);
164
165                         ig.BeginExceptionBlock ();
166
167                         Label dispatcher = ig.DefineLabel ();
168                         ig.Emit (OpCodes.Br, dispatcher);
169
170                         ResumePoint entry_point = new ResumePoint (null);
171                         resume_points.Add (entry_point);
172                         entry_point.Define (ig);
173
174                         ec.EmitTopBlock (original_block, parameters, Location);
175                         EmitYieldBreak (ig);
176
177                         ig.MarkLabel (dispatcher);
178
179                         Label [] labels = new Label [resume_points.Count];
180                         for (int i = 0; i < labels.Length; i++)
181                                 labels [i] = ((ResumePoint) resume_points [i]).Label;
182
183                         ig.Emit (OpCodes.Ldarg_0);
184                         ig.Emit (OpCodes.Ldfld, pc_field.FieldBuilder);
185                         ig.Emit (OpCodes.Switch, labels);
186
187                         Label end = ig.DefineLabel ();
188
189                         ig.MarkLabel (move_next_error);
190                         ig.Emit (OpCodes.Ldc_I4_0); 
191                         ig.Emit (OpCodes.Stloc, retval);
192                         ig.Emit (OpCodes.Leave, end);
193
194                         ig.MarkLabel (move_next_ok);
195                         ig.Emit (OpCodes.Ldc_I4_1);
196                         ig.Emit (OpCodes.Stloc, retval);
197                         ig.Emit (OpCodes.Leave, end);
198
199                         ig.BeginFaultBlock ();
200
201                         ig.Emit (OpCodes.Ldarg_0);
202                         ig.Emit (OpCodes.Callvirt, dispose.MethodBuilder);
203
204                         ig.EndExceptionBlock ();
205
206                         ig.MarkLabel (end);
207                         ig.Emit (OpCodes.Ldloc, retval);
208                         ig.Emit (OpCodes.Ret);
209                 }
210
211                 public void EmitDispose (EmitContext ec)
212                 {
213                         ILGenerator ig = ec.ig;
214
215                         Label end = ig.DefineLabel ();
216                         Label dispatcher = ig.DefineLabel ();
217                         ig.Emit (OpCodes.Br, dispatcher);
218
219                         ec.RemapToProxy = true;
220                         Label [] labels = new Label [resume_points.Count];
221                         for (int i = 0; i < labels.Length; i++) {
222                                 ResumePoint point = (ResumePoint) resume_points [i];
223
224                                 if (point.FinallyBlocks == null) {
225                                         labels [i] = end;
226                                         continue;
227                                 }
228
229                                 labels [i] = ig.DefineLabel ();
230                                 ig.MarkLabel (labels [i]);
231
232                                 ig.BeginExceptionBlock ();
233                                 ig.BeginFinallyBlock ();
234
235                                 foreach (ExceptionStatement stmt in point.FinallyBlocks) {
236                                         if (stmt != null)
237                                                 stmt.EmitFinally (ec);
238                                 }
239
240                                 ig.EndExceptionBlock ();
241                                 ig.Emit (OpCodes.Br, end);
242                         }
243                         ec.RemapToProxy = false;
244                         
245                         ig.MarkLabel (dispatcher);
246                         ig.Emit (OpCodes.Ldarg_0);
247                         ig.Emit (OpCodes.Ldfld, pc_field.FieldBuilder);
248                         ig.Emit (OpCodes.Switch, labels);
249
250                         ig.Emit (OpCodes.Ldarg_0);
251                         IntConstant.EmitInt (ig, (int) State.After);
252                         ig.Emit (OpCodes.Stfld, pc_field.FieldBuilder);
253
254                         ig.MarkLabel (end);
255                 }
256
257                 protected class ResumePoint
258                 {
259                         public Label Label;
260                         public readonly ExceptionStatement[] FinallyBlocks;
261
262                         public ResumePoint (ArrayList list)
263                         {
264                                 if (list != null) {
265                                         FinallyBlocks = new ExceptionStatement [list.Count];
266                                         list.CopyTo (FinallyBlocks, 0);
267                                 }
268                         }
269
270                         public void Define (ILGenerator ig)
271                         {
272                                 Label = ig.DefineLabel ();
273                                 ig.MarkLabel (Label);
274                         }
275                 }
276
277                 // 
278                 // Invoked when a local variable declaration needs to be mapped to
279                 // a field in our proxy class
280                 //
281                 // Prefixes registered:
282                 //   v_   for EmitContext.MapVariable
283                 //   s_   for Storage
284                 //
285                 public FieldBuilder MapVariable (string pfx, string name, Type t)
286                 {
287                         string full_name = pfx + name;
288                         FieldBuilder fb = (FieldBuilder) fields [full_name];
289                         if (fb != null)
290                                 return fb;
291
292                         fb = TypeBuilder.DefineField (full_name, t, FieldAttributes.Private);
293                         fields.Add (full_name, fb);
294                         return fb;
295                 }
296
297                 //
298                 // Called back from Yield
299                 //
300                 public void MarkYield (EmitContext ec, Expression expr,
301                                        ArrayList finally_blocks)
302                 {
303                         ILGenerator ig = ec.ig;
304
305                         // Store the new current
306                         ig.Emit (OpCodes.Ldarg_0);
307                         expr.Emit (ec);
308                         ig.Emit (OpCodes.Stfld, current_field.FieldBuilder);
309
310                         // increment pc
311                         pc++;
312                         ig.Emit (OpCodes.Ldarg_0);
313                         IntConstant.EmitInt (ig, pc);
314                         ig.Emit (OpCodes.Stfld, pc_field.FieldBuilder);
315
316                         // Return ok
317                         ig.Emit (OpCodes.Br, move_next_ok);
318
319                         ResumePoint point = new ResumePoint (finally_blocks);
320                         resume_points.Add (point);
321                         point.Define (ig);
322                 }
323
324                 public void MarkFinally (EmitContext ec, ArrayList finally_blocks)
325                 {
326                         ILGenerator ig = ec.ig;
327
328                         // increment pc
329                         pc++;
330                         ig.Emit (OpCodes.Ldarg_0);
331                         IntConstant.EmitInt (ig, pc);
332                         ig.Emit (OpCodes.Stfld, pc_field.FieldBuilder);
333
334                         ResumePoint point = new ResumePoint (finally_blocks);
335                         resume_points.Add (point);
336                         point.Define (ig);
337                 }
338
339                 private static MemberName MakeProxyName (string name)
340                 {
341                         int pos = name.LastIndexOf ('.');
342                         if (pos > 0)
343                                 name = name.Substring (pos + 1);
344
345                         return new MemberName ("<" + name + ">__" + (proxy_count++));
346                 }
347
348                 //
349                 // Our constructor
350                 //
351                 public Iterator (TypeContainer container, string name, Type return_type,
352                                  Type [] param_types, InternalParameters parameters,
353                                  int modifiers, ToplevelBlock block, Location loc)
354                         : base (container.NamespaceEntry, container, MakeProxyName (name),
355                                 Modifiers.PRIVATE, null, loc)
356                 {
357                         this.container = container;
358                         this.return_type = return_type;
359                         this.param_types = param_types;
360                         this.parameters = parameters;
361                         this.original_name = name;
362                         this.original_block = block;
363                         this.block = new ToplevelBlock (loc);
364
365                         fields = new Hashtable ();
366
367                         is_static = (modifiers & Modifiers.STATIC) != 0;
368                 }
369
370                 public bool DefineIterator ()
371                 {
372                         ec = new EmitContext (this, Mono.CSharp.Location.Null, null, null, ModFlags);
373
374                         if (!CheckType (return_type)) {
375                                 Report.Error (
376                                         1624, Location,
377                                         "The body of `{0}' cannot be an iterator block " +
378                                         "because '{1}' is not an iterator interface type",
379                                         original_name, TypeManager.CSharpName (return_type));
380                                 return false;
381                         }
382
383                         for (int i = 0; i < parameters.Count; i++){
384                                 Parameter.Modifier mod = parameters.ParameterModifier (i);
385                                 if ((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) != 0){
386                                         Report.Error (
387                                                 1623, Location,
388                                                 "Iterators cannot have ref or out parameters");
389                                         return false;
390                                 }
391                         }
392
393                         ArrayList list = new ArrayList ();
394                         if (is_enumerable)
395                                 list.Add (new TypeExpression (
396                                                   TypeManager.ienumerable_type, Location));
397                         list.Add (new TypeExpression (TypeManager.ienumerator_type, Location));
398                         list.Add (new TypeExpression (TypeManager.idisposable_type, Location));
399
400                         iterator_type_expr = new TypeExpression (iterator_type, Location);
401
402                         container.AddIterator (this);
403
404                         Bases = list;
405                         return true;
406                 }
407
408                 //
409                 // Returns the new block for the method, or null on failure
410                 //
411                 protected override bool DefineNestedTypes ()
412                 {
413                         Define_Fields ();
414                         Define_Constructor ();
415                         Define_Current ();
416                         Define_MoveNext ();
417                         Define_Reset ();
418                         Define_Dispose ();
419
420                         if (is_enumerable)
421                                 Define_GetEnumerator ();
422
423                         Create_Block ();
424
425                         return base.DefineNestedTypes ();
426                 }
427
428
429                 Field pc_field;
430                 Field current_field;
431                 Method dispose;
432
433                 public Field this_field;
434                 public Field[] parameter_fields;
435
436                 void Create_Block ()
437                 {
438                         int first = is_static ? 0 : 1;
439
440                         ArrayList args = new ArrayList ();
441                         if (!is_static) {
442                                 Type t = container.TypeBuilder;
443                                 args.Add (new Argument (
444                                         new ThisParameterReference (t, 0, Location)));
445                         }
446
447                         args.Add (new Argument (new BoolLiteral (false)));
448
449                         for (int i = 0; i < parameters.Count; i++) {
450                                 Type t = parameters.ParameterType (i);
451                                 args.Add (new Argument (
452                                         new SimpleParameterReference (t, first + i, Location)));
453                         }
454
455                         Expression new_expr = new New (
456                                 new TypeExpression (TypeBuilder, Location), args, Location);
457
458                         block.AddStatement (new NoCheckReturn (new_expr, Location));
459                 }
460
461                 void Define_Fields ()
462                 {
463                         Location loc = Location.Null;
464
465                         pc_field = new Field (
466                                 this, TypeManager.system_int32_expr, Modifiers.PRIVATE, "PC",
467                                 null, null, loc);
468                         AddField (pc_field);
469
470                         current_field = new Field (
471                                 this, iterator_type_expr, Modifiers.PRIVATE, "current",
472                                 null, null, loc);
473                         AddField (current_field);
474
475                         if (!is_static) {
476                                 this_field = new Field (
477                                         this,
478                                         new TypeExpression (container.TypeBuilder, Location),
479                                         Modifiers.PRIVATE, "this", null, null, loc);
480                                 AddField (this_field);
481                         }
482
483                         parameter_fields = new Field [parameters.Count];
484                         for (int i = 0; i < parameters.Count; i++) {
485                                 string fname = String.Format (
486                                         "field{0}_{1}", i, parameters.ParameterName (i));
487
488                                 parameter_fields [i] = new Field (
489                                         this,
490                                         new TypeExpression (parameters.ParameterType (i), loc),
491                                         Modifiers.PRIVATE, fname, null, null, loc);
492                                 AddField (parameter_fields [i]);
493                         }
494                 }
495
496                 void Define_Constructor ()
497                 {
498                         Parameters ctor_params;
499
500                         ArrayList list = new ArrayList ();
501
502                         if (!is_static)
503                                 list.Add (new Parameter (
504                                         new TypeExpression (container.TypeBuilder, Location),
505                                         "this", Parameter.Modifier.NONE, null));
506                         list.Add (new Parameter (
507                                 TypeManager.system_boolean_expr, "initialized",
508                                 Parameter.Modifier.NONE, null));
509
510                         Parameter[] old_fixed = parameters.Parameters.FixedParameters;
511                         if (old_fixed != null)
512                                 list.AddRange (old_fixed);
513
514                         Parameter[] fixed_params = new Parameter [list.Count];
515                         list.CopyTo (fixed_params);
516
517                         ctor_params = new Parameters (
518                                 fixed_params, parameters.Parameters.ArrayParameter,
519                                 Location);
520
521                         Constructor ctor = new Constructor (
522                                 this, Name, Modifiers.PUBLIC, ctor_params,
523                                 new ConstructorBaseInitializer (
524                                         null, Parameters.EmptyReadOnlyParameters, Location),
525                                 Location);
526                         AddConstructor (ctor);
527
528                         ToplevelBlock block = ctor.Block = new ToplevelBlock (Location);
529
530                         if (!is_static) {
531                                 Type t = container.TypeBuilder;
532
533                                 Assign assign = new Assign (
534                                         new FieldExpression (this_field),
535                                         new SimpleParameterReference (t, 1, Location),
536                                         Location);
537
538                                 block.AddStatement (new StatementExpression (assign, Location));
539                         }
540
541                         int first = is_static ? 2 : 3;
542
543                         for (int i = 0; i < parameters.Count; i++) {
544                                 Type t = parameters.ParameterType (i);
545
546                                 Assign assign = new Assign (
547                                         new FieldExpression (parameter_fields [i]),
548                                         new SimpleParameterReference (t, first + i, Location),
549                                         Location);
550
551                                 block.AddStatement (new StatementExpression (assign, Location));
552                         }
553
554                         State initial = is_enumerable ? State.Uninitialized : State.Running;
555                         block.AddStatement (new SetState (this, initial, Location));
556
557                         block.AddStatement (new If (
558                                 new SimpleParameterReference (
559                                         TypeManager.bool_type, first - 1, Location),
560                                 new SetState (this, State.Running, Location),
561                                 Location));
562                 }
563
564                 Statement Create_ThrowInvalidOperation ()
565                 {
566                         TypeExpr ex_type = new TypeExpression (
567                                 TypeManager.invalid_operation_exception_type, Location);
568
569                         return new Throw (new New (ex_type, null, Location), Location);
570                 }
571
572                 Statement Create_ThrowNotSupported ()
573                 {
574                         TypeExpr ex_type = new TypeExpression (
575                                 TypeManager.not_supported_exception_type, Location);
576
577                         return new Throw (new New (ex_type, null, Location), Location);
578                 }
579
580                 void Define_Current ()
581                 {
582                         ToplevelBlock get_block = new ToplevelBlock (Location);
583                         MemberName left = new MemberName ("System.Collections.IEnumerator");
584                         MemberName name = new MemberName (left, "Current");
585
586                         get_block.AddStatement (new If (
587                                 new Binary (
588                                         Binary.Operator.LessThanOrEqual,
589                                         new FieldExpression (pc_field),
590                                         new IntLiteral ((int) State.Running), Location),
591                                 Create_ThrowInvalidOperation (),
592                                 new Return (
593                                         new FieldExpression (current_field), Location),
594                                 Location));
595
596                         Accessor getter = new Accessor (get_block, 0, null, Location);
597
598                         Property current = new Property (
599                                 this, iterator_type_expr, 0,
600                                 false, name, null, getter, null, Location);
601                         AddProperty (current);
602                 }
603
604                 void Define_MoveNext ()
605                 {
606                         Method move_next = new Method (
607                                 this, TypeManager.system_boolean_expr,
608                                 Modifiers.PUBLIC, false, new MemberName ("MoveNext"),
609                                 Parameters.EmptyReadOnlyParameters, null,
610                                 Location.Null);
611                         AddMethod (move_next);
612
613                         ToplevelBlock block = move_next.Block = new ToplevelBlock (Location);
614
615                         MoveNextMethod inline = new MoveNextMethod (this, Location);
616                         block.AddStatement (inline);
617                 }
618
619                 void Define_GetEnumerator ()
620                 {
621                         MemberName left = new MemberName ("System.Collections.IEnumerable");
622                         MemberName name = new MemberName (left, "GetEnumerator");
623
624                         Method get_enumerator = new Method (
625                                 this,
626                                 new TypeExpression (TypeManager.ienumerator_type, Location),
627                                 0, false, name,
628                                 Parameters.EmptyReadOnlyParameters, null,
629                                 Location.Null);
630                         AddMethod (get_enumerator);
631
632                         get_enumerator.Block = new ToplevelBlock (Location);
633
634                         Expression ce = new MemberAccess (
635                                 new SimpleName ("System.Threading.Interlocked", Location),
636                                 "CompareExchange", Location);
637
638                         Expression pc = new FieldExpression (pc_field);
639                         Expression before = new IntLiteral ((int) State.Running);
640                         Expression uninitialized = new IntLiteral ((int) State.Uninitialized);
641
642                         ArrayList args = new ArrayList ();
643                         args.Add (new Argument (pc, Argument.AType.Ref));
644                         args.Add (new Argument (before, Argument.AType.Expression));
645                         args.Add (new Argument (uninitialized, Argument.AType.Expression));
646
647                         get_enumerator.Block.AddStatement (new If (
648                                 new Binary (
649                                         Binary.Operator.Equality,
650                                         new Invocation (ce, args, Location),
651                                         uninitialized, Location),
652                                 new Return (new This (block, Location), Location),
653                                 Location));
654
655                         args = new ArrayList ();
656                         if (!is_static)
657                                 args.Add (new Argument (new FieldExpression (this_field)));
658
659                         args.Add (new Argument (new BoolLiteral (true)));
660
661                         for (int i = 0; i < parameters.Count; i++)
662                                 args.Add (new Argument (
663                                                   new FieldExpression (parameter_fields [i])));
664
665                         Expression new_expr = new New (
666                                 new TypeExpression (TypeBuilder, Location), args, Location);
667                         get_enumerator.Block.AddStatement (new Return (new_expr, Location));
668                 }
669
670                 protected class SimpleParameterReference : Expression
671                 {
672                         int idx;
673
674                         public SimpleParameterReference (Type type, int idx, Location loc)
675                         {
676                                 this.idx = idx;
677                                 this.loc = loc;
678                                 this.type = type;
679                                 eclass = ExprClass.Variable;
680                         }
681
682                         public override Expression DoResolve (EmitContext ec)
683                         {
684                                 return this;
685                         }
686
687                         public override void Emit (EmitContext ec)
688                         {
689                                 DoEmit (ec);
690                         }
691
692                         protected virtual void DoEmit (EmitContext ec)
693                         {
694                                 ParameterReference.EmitLdArg (ec.ig, idx);
695                         }
696                 }
697
698                 protected class ThisParameterReference : SimpleParameterReference
699                 {
700                         public ThisParameterReference (Type type, int idx, Location loc)
701                                 : base (type, idx, loc)
702                         { }
703
704                         protected override void DoEmit (EmitContext ec)
705                         {
706                                 base.DoEmit (ec);
707                                 if (ec.TypeContainer is Struct)
708                                         ec.ig.Emit (OpCodes.Ldobj, type);
709                         }
710                 }
711
712                 protected class FieldExpression : Expression
713                 {
714                         Field field;
715
716                         public FieldExpression (Field field)
717                         {
718                                 this.field = field;
719                         }
720
721                         public override Expression DoResolve (EmitContext ec)
722                         {
723                                 FieldExpr fexpr = new FieldExpr (field.FieldBuilder, loc);
724                                 fexpr.InstanceExpression = ec.GetThis (loc);
725                                 return fexpr.Resolve (ec);
726                         }
727
728                         public override void Emit (EmitContext ec)
729                         {
730                                 throw new InvalidOperationException ();
731                         }
732                 }
733
734                 protected class MoveNextMethod : Statement {
735                         Iterator iterator;
736
737                         public MoveNextMethod (Iterator iterator, Location loc)
738                         {
739                                 this.loc = loc;
740                                 this.iterator = iterator;
741                         }
742
743                         public override bool Resolve (EmitContext ec)
744                         {
745                                 ec.CurrentBranching.CurrentUsageVector.Return ();
746                                 return true;
747                         }
748
749                         protected override void DoEmit (EmitContext ec)
750                         {
751                                 int code_flags = Modifiers.METHOD_YIELDS;
752                                 if (iterator.is_static)
753                                         code_flags |= Modifiers.STATIC;
754
755                                 EmitContext new_ec = new EmitContext (
756                                         iterator.container, loc, ec.ig,
757                                         TypeManager.int32_type, code_flags);
758
759                                 new_ec.CurrentIterator = iterator;
760
761                                 iterator.EmitMoveNext (new_ec);
762                         }
763                 }
764
765                 protected class DisposeMethod : Statement {
766                         Iterator iterator;
767
768                         public DisposeMethod (Iterator iterator, Location loc)
769                         {
770                                 this.loc = loc;
771                                 this.iterator = iterator;
772                         }
773
774                         public override bool Resolve (EmitContext ec)
775                         {
776                                 return true;
777                         }
778
779                         protected override void DoEmit (EmitContext ec)
780                         {
781                                 iterator.EmitDispose (ec);
782                         }
783                 }
784
785                 protected class StatementList : Statement {
786                         ArrayList statements;
787
788                         public StatementList (Location loc)
789                         {
790                                 this.loc = loc;
791                                 statements = new ArrayList ();
792                         }
793
794                         public void Add (Statement statement)
795                         {
796                                 statements.Add (statement);
797                         }
798
799                         public override bool Resolve (EmitContext ec)
800                         {
801                                 foreach (Statement stmt in statements) {
802                                         if (!stmt.Resolve (ec))
803                                                 return false;
804                                 }
805
806                                 return true;
807                         }
808
809                         protected override void DoEmit (EmitContext ec)
810                         {
811                                 foreach (Statement stmt in statements)
812                                         stmt.Emit (ec);
813                         }
814                 }
815
816                 protected class SetState : Statement
817                 {
818                         Iterator iterator;
819                         State state;
820
821                         public SetState (Iterator iterator, State state, Location loc)
822                         {
823                                 this.iterator = iterator;
824                                 this.state = state;
825                                 this.loc = loc;
826                         }
827
828                         public override bool Resolve (EmitContext ec)
829                         {
830                                 return true;
831                         }
832
833                         protected override void DoEmit (EmitContext ec)
834                         {
835                                 ec.ig.Emit (OpCodes.Ldarg_0);
836                                 IntConstant.EmitInt (ec.ig, (int) state);
837                                 ec.ig.Emit (OpCodes.Stfld, iterator.pc_field.FieldBuilder);
838                         }
839                 }
840
841                 void Define_Reset ()
842                 {
843                         Method reset = new Method (
844                                 this, TypeManager.system_void_expr, Modifiers.PUBLIC,
845                                 false, new MemberName ("Reset"),
846                                 Parameters.EmptyReadOnlyParameters, null, Location);
847                         AddMethod (reset);
848
849                         reset.Block = new ToplevelBlock (Location);
850                         reset.Block.AddStatement (Create_ThrowNotSupported ());
851                 }
852
853                 void Define_Dispose ()
854                 {
855                         dispose = new Method (
856                                 this, TypeManager.system_void_expr, Modifiers.PUBLIC,
857                                 false, new MemberName ("Dispose"),
858                                 Parameters.EmptyReadOnlyParameters, null, Location);
859                         AddMethod (dispose);
860
861                         dispose.Block = new ToplevelBlock (Location);
862                         dispose.Block.AddStatement (new DisposeMethod (this, Location));
863                 }
864
865                 public ToplevelBlock Block {
866                         get { return block; }
867                 }
868
869                 public Type IteratorType {
870                         get { return iterator_type; }
871                 }
872
873                 //
874                 // This return statement tricks return into not flagging an error for being
875                 // used in a Yields method
876                 //
877                 class NoCheckReturn : Return {
878                         public NoCheckReturn (Expression expr, Location loc) : base (expr, loc)
879                         {
880                         }
881
882                         public override bool Resolve (EmitContext ec)
883                         {
884                                 ec.InIterator = false;
885                                 bool ret_val = base.Resolve (ec);
886                                 ec.InIterator = true;
887
888                                 return ret_val;
889                         }
890                 }
891
892                 bool CheckType (Type t)
893                 {
894                         if (t == TypeManager.ienumerable_type) {
895                                 iterator_type = TypeManager.object_type;
896                                 is_enumerable = true;
897                                 return true;
898                         } else if (t == TypeManager.ienumerator_type) {
899                                 iterator_type = TypeManager.object_type;
900                                 is_enumerable = false;
901                                 return true;
902                         }
903
904                         return false;
905                 }
906         }
907 }
908