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