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