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