2004-12-06 Martin Baulig <martin@ximian.com>
[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 parent 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                         if (!CheckType (return_type)) {
373                                 Report.Error (
374                                         1624, Location,
375                                         "The body of `{0}' cannot be an iterator block " +
376                                         "because '{1}' is not an iterator interface type",
377                                         original_name, TypeManager.CSharpName (return_type));
378                                 return false;
379                         }
380
381                         for (int i = 0; i < parameters.Count; i++){
382                                 Parameter.Modifier mod = parameters.ParameterModifier (i);
383                                 if ((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) != 0){
384                                         Report.Error (
385                                                 1623, Location,
386                                                 "Iterators cannot have ref or out parameters");
387                                         return false;
388                                 }
389                         }
390
391                         ArrayList list = new ArrayList ();
392                         if (is_enumerable)
393                                 list.Add (new TypeExpression (
394                                                   TypeManager.ienumerable_type, Location));
395                         list.Add (new TypeExpression (TypeManager.ienumerator_type, Location));
396                         list.Add (new TypeExpression (TypeManager.idisposable_type, Location));
397
398                         iterator_type_expr = new TypeExpression (iterator_type, Location);
399
400                         container.AddIterator (this);
401
402                         Bases = list;
403                         return true;
404                 }
405
406                 //
407                 // Returns the new block for the method, or null on failure
408                 //
409                 protected override bool DefineNestedTypes ()
410                 {
411                         Define_Fields ();
412                         Define_Constructor ();
413                         Define_Current ();
414                         Define_MoveNext ();
415                         Define_Reset ();
416                         Define_Dispose ();
417
418                         if (is_enumerable)
419                                 Define_GetEnumerator ();
420
421                         Create_Block ();
422
423                         return base.DefineNestedTypes ();
424                 }
425
426
427                 Field pc_field;
428                 Field current_field;
429                 Method dispose;
430
431                 public Field this_field;
432                 public Field[] parameter_fields;
433
434                 void Create_Block ()
435                 {
436                         int first = is_static ? 0 : 1;
437
438                         ArrayList args = new ArrayList ();
439                         if (!is_static) {
440                                 Type t = container.TypeBuilder;
441                                 args.Add (new Argument (
442                                         new ThisParameterReference (t, 0, Location)));
443                         }
444
445                         args.Add (new Argument (new BoolLiteral (false)));
446
447                         for (int i = 0; i < parameters.Count; i++) {
448                                 Type t = parameters.ParameterType (i);
449                                 args.Add (new Argument (
450                                         new SimpleParameterReference (t, first + i, Location)));
451                         }
452
453                         Expression new_expr = new New (
454                                 new TypeExpression (TypeBuilder, Location), args, Location);
455
456                         block.AddStatement (new NoCheckReturn (new_expr, Location));
457                 }
458
459                 void Define_Fields ()
460                 {
461                         Location loc = Location.Null;
462
463                         pc_field = new Field (
464                                 this, TypeManager.system_int32_expr, Modifiers.PRIVATE, "PC",
465                                 null, null, loc);
466                         AddField (pc_field);
467
468                         current_field = new Field (
469                                 this, iterator_type_expr, Modifiers.PRIVATE, "current",
470                                 null, null, loc);
471                         AddField (current_field);
472
473                         if (!is_static) {
474                                 this_field = new Field (
475                                         this,
476                                         new TypeExpression (container.TypeBuilder, Location),
477                                         Modifiers.PRIVATE, "this", null, null, loc);
478                                 AddField (this_field);
479                         }
480
481                         parameter_fields = new Field [parameters.Count];
482                         for (int i = 0; i < parameters.Count; i++) {
483                                 string fname = String.Format (
484                                         "field{0}_{1}", i, parameters.ParameterName (i));
485
486                                 parameter_fields [i] = new Field (
487                                         this,
488                                         new TypeExpression (parameters.ParameterType (i), loc),
489                                         Modifiers.PRIVATE, fname, null, null, loc);
490                                 AddField (parameter_fields [i]);
491                         }
492                 }
493
494                 void Define_Constructor ()
495                 {
496                         Parameters ctor_params;
497
498                         ArrayList list = new ArrayList ();
499
500                         if (!is_static)
501                                 list.Add (new Parameter (
502                                         new TypeExpression (container.TypeBuilder, Location),
503                                         "this", Parameter.Modifier.NONE, null));
504                         list.Add (new Parameter (
505                                 TypeManager.system_boolean_expr, "initialized",
506                                 Parameter.Modifier.NONE, null));
507
508                         Parameter[] old_fixed = parameters.Parameters.FixedParameters;
509                         if (old_fixed != null)
510                                 list.AddRange (old_fixed);
511
512                         Parameter[] fixed_params = new Parameter [list.Count];
513                         list.CopyTo (fixed_params);
514
515                         ctor_params = new Parameters (
516                                 fixed_params, parameters.Parameters.ArrayParameter,
517                                 Location);
518
519                         Constructor ctor = new Constructor (
520                                 this, Name, Modifiers.PUBLIC, ctor_params,
521                                 new ConstructorBaseInitializer (
522                                         null, Parameters.EmptyReadOnlyParameters, Location),
523                                 Location);
524                         AddConstructor (ctor);
525
526                         ToplevelBlock block = ctor.Block = new ToplevelBlock (Location);
527
528                         if (!is_static) {
529                                 Type t = container.TypeBuilder;
530
531                                 Assign assign = new Assign (
532                                         new FieldExpression (this_field),
533                                         new SimpleParameterReference (t, 1, Location),
534                                         Location);
535
536                                 block.AddStatement (new StatementExpression (assign, Location));
537                         }
538
539                         int first = is_static ? 2 : 3;
540
541                         for (int i = 0; i < parameters.Count; i++) {
542                                 Type t = parameters.ParameterType (i);
543
544                                 Assign assign = new Assign (
545                                         new FieldExpression (parameter_fields [i]),
546                                         new SimpleParameterReference (t, first + i, Location),
547                                         Location);
548
549                                 block.AddStatement (new StatementExpression (assign, Location));
550                         }
551
552                         State initial = is_enumerable ? State.Uninitialized : State.Running;
553                         block.AddStatement (new SetState (this, initial, Location));
554
555                         block.AddStatement (new If (
556                                 new SimpleParameterReference (
557                                         TypeManager.bool_type, first - 1, Location),
558                                 new SetState (this, State.Running, Location),
559                                 Location));
560                 }
561
562                 Statement Create_ThrowInvalidOperation ()
563                 {
564                         TypeExpr ex_type = new TypeExpression (
565                                 TypeManager.invalid_operation_exception_type, Location);
566
567                         return new Throw (new New (ex_type, null, Location), Location);
568                 }
569
570                 Statement Create_ThrowNotSupported ()
571                 {
572                         TypeExpr ex_type = new TypeExpression (
573                                 TypeManager.not_supported_exception_type, Location);
574
575                         return new Throw (new New (ex_type, null, Location), Location);
576                 }
577
578                 void Define_Current ()
579                 {
580                         ToplevelBlock get_block = new ToplevelBlock (Location);
581                         MemberName left = new MemberName ("System.Collections.IEnumerator");
582                         MemberName name = new MemberName (left, "Current");
583
584                         get_block.AddStatement (new If (
585                                 new Binary (
586                                         Binary.Operator.LessThanOrEqual,
587                                         new FieldExpression (pc_field),
588                                         new IntLiteral ((int) State.Running), Location),
589                                 Create_ThrowInvalidOperation (),
590                                 new Return (
591                                         new FieldExpression (current_field), Location),
592                                 Location));
593
594                         Accessor getter = new Accessor (get_block, 0, null, Location);
595
596                         Property current = new Property (
597                                 this, iterator_type_expr, 0,
598                                 false, name, null, getter, null, Location);
599                         AddProperty (current);
600                 }
601
602                 void Define_MoveNext ()
603                 {
604                         Method move_next = new Method (
605                                 this, TypeManager.system_boolean_expr,
606                                 Modifiers.PUBLIC, false, new MemberName ("MoveNext"),
607                                 Parameters.EmptyReadOnlyParameters, null,
608                                 Location.Null);
609                         AddMethod (move_next);
610
611                         ToplevelBlock block = move_next.Block = new ToplevelBlock (Location);
612
613                         MoveNextMethod inline = new MoveNextMethod (this, Location);
614                         block.AddStatement (inline);
615                 }
616
617                 void Define_GetEnumerator ()
618                 {
619                         MemberName left = new MemberName ("System.Collections.IEnumerable");
620                         MemberName name = new MemberName (left, "GetEnumerator");
621
622                         Method get_enumerator = new Method (
623                                 this,
624                                 new TypeExpression (TypeManager.ienumerator_type, Location),
625                                 0, false, name,
626                                 Parameters.EmptyReadOnlyParameters, null,
627                                 Location.Null);
628                         AddMethod (get_enumerator);
629
630                         get_enumerator.Block = new ToplevelBlock (Location);
631
632                         Expression ce = new MemberAccess (
633                                 new SimpleName ("System.Threading.Interlocked", Location),
634                                 "CompareExchange", Location);
635
636                         Expression pc = new FieldExpression (pc_field);
637                         Expression before = new IntLiteral ((int) State.Running);
638                         Expression uninitialized = new IntLiteral ((int) State.Uninitialized);
639
640                         ArrayList args = new ArrayList ();
641                         args.Add (new Argument (pc, Argument.AType.Ref));
642                         args.Add (new Argument (before, Argument.AType.Expression));
643                         args.Add (new Argument (uninitialized, Argument.AType.Expression));
644
645                         get_enumerator.Block.AddStatement (new If (
646                                 new Binary (
647                                         Binary.Operator.Equality,
648                                         new Invocation (ce, args, Location),
649                                         uninitialized, Location),
650                                 new Return (new This (block, Location), Location),
651                                 Location));
652
653                         args = new ArrayList ();
654                         if (!is_static)
655                                 args.Add (new Argument (new FieldExpression (this_field)));
656
657                         args.Add (new Argument (new BoolLiteral (true)));
658
659                         for (int i = 0; i < parameters.Count; i++)
660                                 args.Add (new Argument (
661                                                   new FieldExpression (parameter_fields [i])));
662
663                         Expression new_expr = new New (
664                                 new TypeExpression (TypeBuilder, Location), args, Location);
665                         get_enumerator.Block.AddStatement (new Return (new_expr, Location));
666                 }
667
668                 protected class SimpleParameterReference : Expression
669                 {
670                         int idx;
671
672                         public SimpleParameterReference (Type type, int idx, Location loc)
673                         {
674                                 this.idx = idx;
675                                 this.loc = loc;
676                                 this.type = type;
677                                 eclass = ExprClass.Variable;
678                         }
679
680                         public override Expression DoResolve (EmitContext ec)
681                         {
682                                 return this;
683                         }
684
685                         public override void Emit (EmitContext ec)
686                         {
687                                 DoEmit (ec);
688                         }
689
690                         protected virtual void DoEmit (EmitContext ec)
691                         {
692                                 ParameterReference.EmitLdArg (ec.ig, idx);
693                         }
694                 }
695
696                 protected class ThisParameterReference : SimpleParameterReference
697                 {
698                         public ThisParameterReference (Type type, int idx, Location loc)
699                                 : base (type, idx, loc)
700                         { }
701
702                         protected override void DoEmit (EmitContext ec)
703                         {
704                                 base.DoEmit (ec);
705                                 if (ec.TypeContainer is Struct)
706                                         ec.ig.Emit (OpCodes.Ldobj, type);
707                         }
708                 }
709
710                 protected class FieldExpression : Expression
711                 {
712                         Field field;
713
714                         public FieldExpression (Field field)
715                         {
716                                 this.field = field;
717                         }
718
719                         public override Expression DoResolve (EmitContext ec)
720                         {
721                                 FieldExpr fexpr = new FieldExpr (field.FieldBuilder, loc);
722                                 fexpr.InstanceExpression = ec.GetThis (loc);
723                                 return fexpr.Resolve (ec);
724                         }
725
726                         public override void Emit (EmitContext ec)
727                         {
728                                 throw new InvalidOperationException ();
729                         }
730                 }
731
732                 protected class MoveNextMethod : Statement {
733                         Iterator iterator;
734
735                         public MoveNextMethod (Iterator iterator, Location loc)
736                         {
737                                 this.loc = loc;
738                                 this.iterator = iterator;
739                         }
740
741                         public override bool Resolve (EmitContext ec)
742                         {
743                                 ec.CurrentBranching.CurrentUsageVector.Return ();
744                                 return true;
745                         }
746
747                         protected override void DoEmit (EmitContext ec)
748                         {
749                                 int code_flags = Modifiers.METHOD_YIELDS;
750                                 if (iterator.is_static)
751                                         code_flags |= Modifiers.STATIC;
752
753                                 EmitContext new_ec = new EmitContext (
754                                         iterator.container, loc, ec.ig,
755                                         TypeManager.int32_type, code_flags);
756
757                                 new_ec.CurrentIterator = iterator;
758
759                                 iterator.EmitMoveNext (new_ec);
760                         }
761                 }
762
763                 protected class DisposeMethod : Statement {
764                         Iterator iterator;
765
766                         public DisposeMethod (Iterator iterator, Location loc)
767                         {
768                                 this.loc = loc;
769                                 this.iterator = iterator;
770                         }
771
772                         public override bool Resolve (EmitContext ec)
773                         {
774                                 return true;
775                         }
776
777                         protected override void DoEmit (EmitContext ec)
778                         {
779                                 iterator.EmitDispose (ec);
780                         }
781                 }
782
783                 protected class StatementList : Statement {
784                         ArrayList statements;
785
786                         public StatementList (Location loc)
787                         {
788                                 this.loc = loc;
789                                 statements = new ArrayList ();
790                         }
791
792                         public void Add (Statement statement)
793                         {
794                                 statements.Add (statement);
795                         }
796
797                         public override bool Resolve (EmitContext ec)
798                         {
799                                 foreach (Statement stmt in statements) {
800                                         if (!stmt.Resolve (ec))
801                                                 return false;
802                                 }
803
804                                 return true;
805                         }
806
807                         protected override void DoEmit (EmitContext ec)
808                         {
809                                 foreach (Statement stmt in statements)
810                                         stmt.Emit (ec);
811                         }
812                 }
813
814                 protected class SetState : Statement
815                 {
816                         Iterator iterator;
817                         State state;
818
819                         public SetState (Iterator iterator, State state, Location loc)
820                         {
821                                 this.iterator = iterator;
822                                 this.state = state;
823                                 this.loc = loc;
824                         }
825
826                         public override bool Resolve (EmitContext ec)
827                         {
828                                 return true;
829                         }
830
831                         protected override void DoEmit (EmitContext ec)
832                         {
833                                 ec.ig.Emit (OpCodes.Ldarg_0);
834                                 IntConstant.EmitInt (ec.ig, (int) state);
835                                 ec.ig.Emit (OpCodes.Stfld, iterator.pc_field.FieldBuilder);
836                         }
837                 }
838
839                 void Define_Reset ()
840                 {
841                         Method reset = new Method (
842                                 this, TypeManager.system_void_expr, Modifiers.PUBLIC,
843                                 false, new MemberName ("Reset"),
844                                 Parameters.EmptyReadOnlyParameters, null, Location);
845                         AddMethod (reset);
846
847                         reset.Block = new ToplevelBlock (Location);
848                         reset.Block.AddStatement (Create_ThrowNotSupported ());
849                 }
850
851                 void Define_Dispose ()
852                 {
853                         dispose = new Method (
854                                 this, TypeManager.system_void_expr, Modifiers.PUBLIC,
855                                 false, new MemberName ("Dispose"),
856                                 Parameters.EmptyReadOnlyParameters, null, Location);
857                         AddMethod (dispose);
858
859                         dispose.Block = new ToplevelBlock (Location);
860                         dispose.Block.AddStatement (new DisposeMethod (this, Location));
861                 }
862
863                 public ToplevelBlock Block {
864                         get { return block; }
865                 }
866
867                 public Type IteratorType {
868                         get { return iterator_type; }
869                 }
870
871                 //
872                 // This return statement tricks return into not flagging an error for being
873                 // used in a Yields method
874                 //
875                 class NoCheckReturn : Return {
876                         public NoCheckReturn (Expression expr, Location loc) : base (expr, loc)
877                         {
878                         }
879
880                         public override bool Resolve (EmitContext ec)
881                         {
882                                 ec.InIterator = false;
883                                 bool ret_val = base.Resolve (ec);
884                                 ec.InIterator = true;
885
886                                 return ret_val;
887                         }
888                 }
889
890                 bool CheckType (Type t)
891                 {
892                         if (t == TypeManager.ienumerable_type) {
893                                 iterator_type = TypeManager.object_type;
894                                 is_enumerable = true;
895                                 return true;
896                         } else if (t == TypeManager.ienumerator_type) {
897                                 iterator_type = TypeManager.object_type;
898                                 is_enumerable = false;
899                                 return true;
900                         }
901
902                         return false;
903                 }
904         }
905 }
906