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