2007-02-06 Marek Safar <marek.safar@gmail.com>
[mono.git] / mcs / mcs / iterators.cs
1 //
2 // iterators.cs: Support for implementing iterators
3 //
4 // Author:
5 //   Miguel de Icaza (miguel@ximian.com)
6 //
7 // (C) 2003 Ximian, Inc.
8 //
9 // TODO:
10 //    Flow analysis for Yield.
11 //    Emit calls to 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 class Yield : Statement {
25                 Expression expr;
26                 ArrayList finally_blocks;
27
28                 public Yield (Expression expr, Location l)
29                 {
30                         this.expr = expr;
31                         loc = l;
32                 }
33
34                 public static bool CheckContext (EmitContext ec, Location loc, bool isYieldBreak)
35                 {
36                         if (ec.InFinally) {
37                                 Report.Error (1625, loc, "Cannot yield in the body of a " +
38                                               "finally clause");
39                                 return false;
40                         }
41
42                         for (Block block = ec.CurrentBlock; block != null; block = block.Parent) {
43                                 if (!block.Unsafe)
44                                         continue;
45
46                                 Report.Error (1629, loc, "Unsafe code may not appear in iterators");
47                                 return false;
48                         }
49
50                         //
51                         // We can't use `ec.InUnsafe' here because it's allowed to have an iterator
52                         // inside an unsafe class.  See test-martin-29.cs for an example.
53                         //
54                         if (!ec.CurrentAnonymousMethod.IsIterator) {
55                                 Report.Error (1621, loc,
56                                               "The yield statement cannot be used inside " +
57                                               "anonymous method blocks");
58                                 return false;
59                         }
60
61                         if (ec.CurrentBranching.InTryWithCatch () && (!isYieldBreak || !ec.InCatch)) {
62                                 if (!ec.InCatch)
63                                         Report.Error (1626, loc, "Cannot yield a value in the body " +
64                                                       "of a try block with a catch clause");
65                                 else
66                                         Report.Error (1631, loc, "Cannot yield a value in the body " +
67                                                       "of a catch clause");
68                                 return false;
69                         }
70
71                         return true;
72                 }
73                 
74                 public override bool Resolve (EmitContext ec)
75                 {
76                         Report.Debug (64, "RESOLVE YIELD", this, ec, expr, expr.GetType ());
77                         expr = expr.Resolve (ec);
78                         if (expr == null)
79                                 return false;
80
81                         Report.Debug (64, "RESOLVE YIELD #1", this, ec, expr, expr.GetType (),
82                                       ec.CurrentAnonymousMethod, ec.CurrentIterator);
83
84                         if (!CheckContext (ec, loc, false))
85                                 return false;
86
87                         Iterator iterator = ec.CurrentIterator;
88                         if (expr.Type != iterator.IteratorType) {
89                                 expr = Convert.ImplicitConversionRequired (
90                                         ec, expr, iterator.IteratorType, loc);
91                                 if (expr == null)
92                                         return false;
93                         }
94
95                         ec.CurrentBranching.StealFinallyClauses (ref finally_blocks);
96                         return true;
97                 }
98
99                 protected override void DoEmit (EmitContext ec)
100                 {
101                         ec.CurrentIterator.MarkYield (ec, expr, finally_blocks);
102                 }
103         }
104
105         public class YieldBreak : Statement {
106
107                 public YieldBreak (Location l)
108                 {
109                         loc = l;
110                 }
111
112                 public override bool Resolve (EmitContext ec)
113                 {
114                         if (!Yield.CheckContext (ec, loc, true))
115                                 return false;
116
117                         ec.CurrentBranching.CurrentUsageVector.Goto ();
118                         return true;
119                 }
120
121                 protected override void DoEmit (EmitContext ec)
122                 {
123                         ec.CurrentIterator.EmitYieldBreak (ec.ig);
124                 }
125         }
126
127         public class IteratorHost : RootScopeInfo
128         {
129                 public readonly Iterator Iterator;
130
131                 TypeExpr iterator_type_expr;
132                 Field pc_field;
133                 Field current_field;
134                 MethodInfo dispose_method;
135
136                 TypeExpr enumerator_type;
137                 TypeExpr enumerable_type;
138                 TypeArguments generic_args;
139                 TypeExpr generic_enumerator_type;
140                 TypeExpr generic_enumerable_type;
141
142                 public IteratorHost (Iterator iterator)
143                         : base (iterator.Container.Toplevel, iterator.Host, iterator.GenericMethod,
144                                 iterator.Location)
145                 {
146                         this.Iterator = iterator;
147                 }
148
149                 public override bool IsIterator {
150                         get { return true; }
151                 }
152
153                 public MethodInfo Dispose {
154                         get { return dispose_method; }
155                 }
156
157                 public Field PC {
158                         get { return pc_field; }
159                 }
160
161                 public Field CurrentField {
162                         get { return current_field; }
163                 }
164
165                 public Type IteratorType {
166                         get { return iterator_type_expr.Type; }
167                 }
168
169                 public override TypeExpr [] GetClassBases (out TypeExpr base_class)
170                 {
171                         iterator_type_expr = InflateType (Iterator.OriginalIteratorType);
172
173 #if GMCS_SOURCE
174                         generic_args = new TypeArguments (Location);
175                         generic_args.Add (iterator_type_expr);
176 #endif
177
178                         ArrayList list = new ArrayList ();
179                         if (Iterator.IsEnumerable) {
180                                 enumerable_type = new TypeExpression (
181                                         TypeManager.ienumerable_type, Location);
182                                 list.Add (enumerable_type);
183
184 #if GMCS_SOURCE
185                                 generic_enumerable_type = new ConstructedType (
186                                         TypeManager.generic_ienumerable_type,
187                                         generic_args, Location);
188                                 list.Add (generic_enumerable_type);
189 #endif
190                         }
191
192                         enumerator_type = new TypeExpression (
193                                 TypeManager.ienumerator_type, Location);
194                         list.Add (enumerator_type);
195
196                         list.Add (new TypeExpression (TypeManager.idisposable_type, Location));
197
198 #if GMCS_SOURCE
199                         generic_enumerator_type = new ConstructedType (
200                                 TypeManager.generic_ienumerator_type,
201                                 generic_args, Location);
202                         list.Add (generic_enumerator_type);
203 #endif
204
205                         Bases = list;
206
207                         return base.GetClassBases (out base_class);
208                 }
209
210                 protected override bool DoResolveMembers ()
211                 {
212                         pc_field = CaptureVariable ("$PC", TypeManager.system_int32_expr);
213                         current_field = CaptureVariable ("$current", iterator_type_expr);
214
215 #if GMCS_SOURCE
216                         Define_Current (true);
217 #endif
218                         Define_Current (false);
219                         new DisposeMethod (this);
220                         Define_Reset ();
221
222                         if (Iterator.IsEnumerable) {
223                                 new GetEnumeratorMethod (this, false);
224 #if GMCS_SOURCE
225                                 new GetEnumeratorMethod (this, true);
226 #endif
227                         }
228
229                         return base.DoResolveMembers ();
230                 }
231
232                 public void CaptureScopes ()
233                 {
234                         Report.Debug (128, "DEFINE ITERATOR HOST", this, scopes);
235
236                         foreach (ScopeInfo si in scopes)
237                                 CaptureScope (si);
238
239                         foreach (ScopeInfo si in scopes) {
240                                 if (!si.Define ())
241                                         throw new InternalErrorException ();
242                                 if (si.DefineType () == null)
243                                         throw new InternalErrorException ();
244                                 if (!si.ResolveType ())
245                                         throw new InternalErrorException ();
246                                 if (!si.ResolveMembers ())
247                                         throw new InternalErrorException ();
248                                 if (!si.DefineMembers ())
249                                         throw new InternalErrorException ();
250                         }
251                 }
252
253                 protected override bool DoDefineMembers ()
254                 {
255                         if (!base.DoDefineMembers ())
256                                 return false;
257
258                         FetchMethodDispose ();
259
260                         return true;
261                 }
262
263                 protected override void EmitScopeConstructor (EmitContext ec)
264                 {
265                         ec.ig.Emit (OpCodes.Ldarg_0);
266                         ec.ig.Emit (OpCodes.Ldarg_1);
267                         ec.ig.Emit (OpCodes.Stfld, pc_field.FieldBuilder);
268                         base.EmitScopeConstructor (ec);
269                 }
270
271                 void FetchMethodDispose ()
272                 {
273                         MemberList dispose_list;
274
275                         dispose_list = FindMembers (
276                                 CurrentType != null ? CurrentType : TypeBuilder,
277                                 MemberTypes.Method, BindingFlags.Public | BindingFlags.Instance,
278                                 Type.FilterName, "Dispose");
279
280                         if (dispose_list.Count != 1)
281                                 throw new InternalErrorException ("Cannot find Dipose() method.");
282
283                         dispose_method = (MethodInfo) dispose_list [0];
284                 }
285
286                 void Define_Current (bool is_generic)
287                 {
288                         MemberName left;
289                         Expression type;
290
291                         if (is_generic) {
292                                 left = new MemberName (
293                                         "System.Collections.Generic.IEnumerator",
294                                         generic_args, Location);
295                                 type = iterator_type_expr;
296                         } else {
297                                 left = new MemberName ("System.Collections.IEnumerator", Location);
298                                 type = TypeManager.system_object_expr;
299                         }
300
301                         MemberName name = new MemberName (left, "Current", null, Location);
302
303                         ToplevelBlock get_block = new ToplevelBlock (Location);
304                         get_block.AddStatement (new CurrentBlock (this, is_generic));
305
306                         Accessor getter = new Accessor (get_block, 0, null, Location);
307
308                         Property current = new Property (
309                                 this, type, 0, false, name, null, getter, null, false);
310                         AddProperty (current);
311                 }
312
313                 void Define_Reset ()
314                 {
315                         Method reset = new Method (
316                                 this, null, TypeManager.system_void_expr, Modifiers.PUBLIC,
317                                 false, new MemberName ("Reset", Location),
318                                 Parameters.EmptyReadOnlyParameters, null);
319                         AddMethod (reset);
320
321                         reset.Block = new ToplevelBlock (Location);
322                         reset.Block.AddStatement (Create_ThrowNotSupported ());
323                 }
324
325                 Statement Create_ThrowNotSupported ()
326                 {
327                         TypeExpr ex_type = new TypeExpression (
328                                 TypeManager.not_supported_exception_type, Location);
329
330                         return new Throw (new New (ex_type, null, Location), Location);
331                 }
332
333                 ConstructorInfo GetInvalidOperationException ()
334                 {
335                         return TypeManager.GetConstructor (
336                                 TypeManager.invalid_operation_exception_type, Type.EmptyTypes);
337                 }
338
339                 protected override ScopeInitializer CreateScopeInitializer ()
340                 {
341                         return new IteratorHostInitializer (this);
342                 }
343
344                 protected class IteratorHostInitializer : RootScopeInitializer
345                 {
346                         new public readonly IteratorHost Host;
347                         protected Iterator.State state;
348
349                         public IteratorHostInitializer (IteratorHost host)
350                                 : base (host)
351                         {
352                                 this.Host = host;
353                         }
354
355                         protected override bool DoResolveInternal (EmitContext ec)
356                         {
357                                 if (this is EnumeratorScopeInitializer)
358                                         state = Iterator.State.Running;
359                                 else if (Host.Iterator.IsEnumerable)
360                                         state = Iterator.State.Uninitialized;
361                                 else
362                                         state = Iterator.State.Running;
363
364                                 return base.DoResolveInternal (ec);
365                         }
366
367                         protected override void EmitScopeConstructor (EmitContext ec)
368                         {
369                                 ec.ig.Emit (OpCodes.Ldc_I4, (int) state);
370                                 base.EmitScopeConstructor (ec);
371                         }
372                 }
373
374                 protected class GetEnumeratorMethod : Method
375                 {
376                         public IteratorHost Host;
377
378                         static MemberName GetMemberName (IteratorHost host, bool is_generic)
379                         {
380                                 MemberName left;
381                                 if (is_generic) {
382                                         left = new MemberName (
383                                                 "System.Collections.Generic.IEnumerable",
384                                                 host.generic_args, host.Location);
385                                 } else {
386                                         left = new MemberName (
387                                                 "System.Collections.IEnumerable", host.Location);
388                                 }
389
390                                 return new MemberName (left, "GetEnumerator", host.Location);
391                         }
392
393                         public GetEnumeratorMethod (IteratorHost host, bool is_generic)
394                                 : base (host, null, is_generic ?
395                                         host.generic_enumerator_type : host.enumerator_type,
396                                         0, false, GetMemberName (host, is_generic),
397                                         Parameters.EmptyReadOnlyParameters, null)
398                         {
399                                 this.Host = host;
400
401                                 host.AddMethod (this);
402
403                                 Block = new ToplevelBlock (host.Iterator.Container.Toplevel, null, Location);
404                                 Block.AddStatement (new GetEnumeratorStatement (host, Type));
405                         }
406
407                         public override EmitContext CreateEmitContext (DeclSpace tc, ILGenerator ig)
408                         {
409                                 EmitContext ec = new EmitContext (
410                                         this, tc, this.ds, Location, ig, MemberType, ModFlags, false);
411
412                                 ec.CurrentAnonymousMethod = Host.Iterator;
413                                 return ec;
414                         }
415
416                         protected class GetEnumeratorStatement : Statement
417                         {
418                                 IteratorHost host;
419                                 Expression type;
420
421                                 ExpressionStatement initializer;
422                                 Expression cast;
423                                 MethodInfo ce;
424
425                                 public GetEnumeratorStatement (IteratorHost host, Expression type)
426                                 {
427                                         this.host = host;
428                                         this.type = type;
429                                         loc = host.Location;
430                                 }
431
432                                 public override bool Resolve (EmitContext ec)
433                                 {
434                                         type = type.ResolveAsTypeTerminal (ec, false);
435                                         if ((type == null) || (type.Type == null))
436                                                 return false;
437
438                                         initializer = host.GetEnumeratorInitializer (ec);
439                                         if (initializer == null)
440                                                 return false;
441
442                                         cast = new ClassCast (initializer, type.Type);
443
444                                         ce = TypeManager.int_interlocked_compare_exchange;
445
446                                         ec.CurrentBranching.CurrentUsageVector.Return ();
447                                         return true;
448                                 }
449
450                                 protected override void DoEmit (EmitContext ec)
451                                 {
452                                         ILGenerator ig = ec.ig;
453                                         Label label_init = ig.DefineLabel ();
454
455                                         ig.Emit (OpCodes.Ldarg_0);
456                                         ig.Emit (OpCodes.Ldflda, host.PC.FieldBuilder);
457                                         ig.Emit (OpCodes.Ldc_I4, (int) Iterator.State.Running);
458                                         ig.Emit (OpCodes.Ldc_I4, (int) Iterator.State.Uninitialized);
459                                         ig.Emit (OpCodes.Call, ce);
460
461                                         ig.Emit (OpCodes.Ldc_I4, (int) Iterator.State.Uninitialized);
462                                         ig.Emit (OpCodes.Bne_Un, label_init);
463
464                                         ig.Emit (OpCodes.Ldarg_0);
465                                         ig.Emit (OpCodes.Ret);
466
467                                         ig.MarkLabel (label_init);
468
469                                         initializer.EmitStatement (ec);
470                                         cast.Emit (ec);
471                                         ig.Emit (OpCodes.Ret);
472                                 }
473                         }
474                 }
475
476                 protected class DisposeMethod : Method
477                 {
478                         public IteratorHost Host;
479
480                         public DisposeMethod (IteratorHost host)
481                                 : base (host, null, TypeManager.system_void_expr, Modifiers.PUBLIC,
482                                         false, new MemberName ("Dispose", host.Location),
483                                         Parameters.EmptyReadOnlyParameters, null)
484                         {
485                                 this.Host = host;
486
487                                 host.AddMethod (this);
488
489                                 Block = new ToplevelBlock (host.Iterator.Block, null, Location);
490                                 Block.AddStatement (new DisposeMethodStatement (Host.Iterator));
491
492                                 Report.Debug (64, "DISPOSE METHOD", host, Block);
493                         }
494
495                         public override EmitContext CreateEmitContext (DeclSpace tc, ILGenerator ig)
496                         {
497                                 EmitContext ec = new EmitContext (
498                                         this, tc, this.ds, Location, ig, MemberType, ModFlags, false);
499
500                                 ec.CurrentAnonymousMethod = Host.Iterator;
501                                 return ec;
502                         }
503
504                         protected class DisposeMethodStatement : Statement
505                         {
506                                 Iterator iterator;
507
508                                 public DisposeMethodStatement (Iterator iterator)
509                                 {
510                                         this.iterator = iterator;
511                                         this.loc = iterator.Location;
512                                 }
513
514                                 public override bool Resolve (EmitContext ec)
515                                 {
516                                         return true;
517                                 }
518
519                                 protected override void DoEmit (EmitContext ec)
520                                 {
521                                         iterator.EmitDispose (ec);
522                                 }
523                         }
524                 }
525
526                 protected ScopeInitializer GetEnumeratorInitializer (EmitContext ec)
527                 {
528                         ScopeInitializer init = new EnumeratorScopeInitializer (this);
529                         if (init.Resolve (ec) == null)
530                                 throw new InternalErrorException ();
531                         return init;
532                 }
533
534                 protected class EnumeratorScopeInitializer : IteratorHostInitializer
535                 {
536                         IteratorHost host;
537
538                         public EnumeratorScopeInitializer (IteratorHost host)
539                                 : base (host)
540                         {
541                                 this.host = host;
542                         }
543
544                         protected override bool DoResolveInternal (EmitContext ec)
545                         {
546                                 type = host.IsGeneric ? host.CurrentType : host.TypeBuilder;
547                                 return base.DoResolveInternal (ec);
548                         }
549
550                         protected override void DoEmit (EmitContext ec)
551                         {
552                                 DoEmitInstance (ec);
553                         }
554
555                         protected override bool IsGetEnumerator {
556                                 get { return true; }
557                         }
558
559                         protected override void EmitParameterReference (EmitContext ec,
560                                                                         CapturedParameter cp)
561                         {
562                                 ec.ig.Emit (OpCodes.Ldarg_0);
563                                 ec.ig.Emit (OpCodes.Ldfld, cp.Field.FieldBuilder);
564                         }
565                 }
566
567                 protected class CurrentBlock : Statement {
568                         IteratorHost host;
569                         bool is_generic;
570
571                         public CurrentBlock (IteratorHost host, bool is_generic)
572                         {
573                                 this.host = host;
574                                 this.is_generic = is_generic;
575                                 loc = host.Location;
576                         }
577
578                         public override bool Resolve (EmitContext ec)
579                         {
580                                 ec.CurrentBranching.CurrentUsageVector.Return ();
581                                 return true;
582                         }
583
584                         protected override void DoEmit (EmitContext ec)
585                         {
586                                 ILGenerator ig = ec.ig;
587                                 Label label_ok = ig.DefineLabel ();
588
589                                 ig.Emit (OpCodes.Ldarg_0);
590                                 ig.Emit (OpCodes.Ldfld, host.PC.FieldBuilder);
591                                 ig.Emit (OpCodes.Ldc_I4, (int) Iterator.State.Running);
592                                 ig.Emit (OpCodes.Bgt, label_ok);
593
594                                 ig.Emit (OpCodes.Newobj, host.GetInvalidOperationException ());
595                                 ig.Emit (OpCodes.Throw);
596
597                                 ig.MarkLabel (label_ok);
598                                 ig.Emit (OpCodes.Ldarg_0);
599                                 ig.Emit (OpCodes.Ldfld, host.CurrentField.FieldBuilder);
600                                 if (!is_generic)
601                                         ig.Emit (OpCodes.Box, host.CurrentField.MemberType);
602                                 ig.Emit (OpCodes.Ret);
603                         }
604                 }
605         }
606
607         public class Iterator : AnonymousContainer {
608                 protected readonly ToplevelBlock OriginalBlock;
609                 protected readonly IMethodData OriginalMethod;
610                 protected ToplevelBlock block;
611
612                 public readonly bool IsEnumerable;
613                 public readonly bool IsStatic;
614
615                 //
616                 // The state as we generate the iterator
617                 //
618                 Label move_next_ok, move_next_error;
619                 ArrayList resume_points = new ArrayList ();
620                 int pc;
621                 
622                 public readonly Type OriginalIteratorType;
623                 public readonly IteratorHost IteratorHost;
624
625                 public enum State {
626                         Uninitialized   = -2,
627                         After,
628                         Running
629                 }
630
631                 public void EmitYieldBreak (ILGenerator ig)
632                 {
633                         ig.Emit (OpCodes.Ldarg_0);
634                         IntConstant.EmitInt (ig, (int) State.After);
635                         ig.Emit (OpCodes.Stfld, IteratorHost.PC.FieldBuilder);
636                         ig.Emit (OpCodes.Br, move_next_error);
637                 }
638
639                 internal void EmitMoveNext (EmitContext ec, Block original_block)
640                 {
641                         ILGenerator ig = ec.ig;
642
643                         move_next_ok = ig.DefineLabel ();
644                         move_next_error = ig.DefineLabel ();
645
646                         LocalBuilder retval = ec.GetTemporaryLocal (TypeManager.int32_type);
647
648                         ig.BeginExceptionBlock ();
649
650                         Label dispatcher = ig.DefineLabel ();
651                         ig.Emit (OpCodes.Br, dispatcher);
652
653                         ResumePoint entry_point = new ResumePoint (null);
654                         resume_points.Add (entry_point);
655                         entry_point.Define (ig);
656
657                         original_block.Emit (ec);
658
659                         EmitYieldBreak (ig);
660
661                         ig.MarkLabel (dispatcher);
662
663                         Label [] labels = new Label [resume_points.Count];
664                         for (int i = 0; i < labels.Length; i++)
665                                 labels [i] = ((ResumePoint) resume_points [i]).Label;
666
667                         ig.Emit (OpCodes.Ldarg_0);
668                         ig.Emit (OpCodes.Ldfld, IteratorHost.PC.FieldBuilder);
669                         ig.Emit (OpCodes.Switch, labels);
670
671                         Label end = ig.DefineLabel ();
672
673                         ig.MarkLabel (move_next_error);
674                         ig.Emit (OpCodes.Ldc_I4_0); 
675                         ig.Emit (OpCodes.Stloc, retval);
676                         ig.Emit (OpCodes.Leave, end);
677
678                         ig.MarkLabel (move_next_ok);
679                         ig.Emit (OpCodes.Ldc_I4_1);
680                         ig.Emit (OpCodes.Stloc, retval);
681                         ig.Emit (OpCodes.Leave, end);
682
683                         ig.BeginFaultBlock ();
684
685                         ig.Emit (OpCodes.Ldarg_0);
686                         ig.Emit (OpCodes.Callvirt, IteratorHost.Dispose);
687
688                         ig.EndExceptionBlock ();
689
690                         ig.MarkLabel (end);
691                         ig.Emit (OpCodes.Ldloc, retval);
692                         ig.Emit (OpCodes.Ret);
693                 }
694
695                 public void EmitDispose (EmitContext ec)
696                 {
697                         ILGenerator ig = ec.ig;
698
699                         Label end = ig.DefineLabel ();
700                         Label dispatcher = ig.DefineLabel ();
701                         ig.Emit (OpCodes.Br, dispatcher);
702
703                         Label [] labels = new Label [resume_points.Count];
704                         for (int i = 0; i < labels.Length; i++) {
705                                 ResumePoint point = (ResumePoint) resume_points [i];
706
707                                 if (point.FinallyBlocks == null) {
708                                         labels [i] = end;
709                                         continue;
710                                 }
711
712                                 labels [i] = ig.DefineLabel ();
713                                 ig.MarkLabel (labels [i]);
714
715                                 ig.BeginExceptionBlock ();
716                                 ig.BeginFinallyBlock ();
717
718                                 foreach (ExceptionStatement stmt in point.FinallyBlocks) {
719                                         if (stmt != null)
720                                                 stmt.EmitFinally (ec);
721                                 }
722
723                                 ig.EndExceptionBlock ();
724                                 ig.Emit (OpCodes.Br, end);
725                         }
726
727                         ig.MarkLabel (dispatcher);
728                         ig.Emit (OpCodes.Ldarg_0);
729                         ig.Emit (OpCodes.Ldfld, IteratorHost.PC.FieldBuilder);
730                         ig.Emit (OpCodes.Switch, labels);
731
732                         ig.Emit (OpCodes.Ldarg_0);
733                         IntConstant.EmitInt (ig, (int) State.After);
734                         ig.Emit (OpCodes.Stfld, IteratorHost.PC.FieldBuilder);
735
736                         ig.MarkLabel (end);
737                 }
738
739                 protected class ResumePoint
740                 {
741                         public Label Label;
742                         public readonly ExceptionStatement[] FinallyBlocks;
743
744                         public ResumePoint (ArrayList list)
745                         {
746                                 if (list != null) {
747                                         FinallyBlocks = new ExceptionStatement [list.Count];
748                                         list.CopyTo (FinallyBlocks, 0);
749                                 }
750                         }
751
752                         public void Define (ILGenerator ig)
753                         {
754                                 Label = ig.DefineLabel ();
755                                 ig.MarkLabel (Label);
756                         }
757                 }
758
759                 //
760                 // Called back from Yield
761                 //
762                 public void MarkYield (EmitContext ec, Expression expr,
763                                        ArrayList finally_blocks)
764                 {
765                         ILGenerator ig = ec.ig;
766
767                         // Store the new current
768                         ig.Emit (OpCodes.Ldarg_0);
769                         expr.Emit (ec);
770                         ig.Emit (OpCodes.Stfld, IteratorHost.CurrentField.FieldBuilder);
771
772                         // increment pc
773                         pc++;
774                         ig.Emit (OpCodes.Ldarg_0);
775                         IntConstant.EmitInt (ig, pc);
776                         ig.Emit (OpCodes.Stfld, IteratorHost.PC.FieldBuilder);
777
778                         // Return ok
779                         ig.Emit (OpCodes.Br, move_next_ok);
780
781                         ResumePoint point = new ResumePoint (finally_blocks);
782                         resume_points.Add (point);
783                         point.Define (ig);
784                 }
785
786                 public void MarkFinally (EmitContext ec, ArrayList finally_blocks)
787                 {
788                         ILGenerator ig = ec.ig;
789
790                         // increment pc
791                         pc++;
792                         ig.Emit (OpCodes.Ldarg_0);
793                         IntConstant.EmitInt (ig, pc);
794                         ig.Emit (OpCodes.Stfld, IteratorHost.PC.FieldBuilder);
795
796                         ResumePoint point = new ResumePoint (finally_blocks);
797                         resume_points.Add (point);
798                         point.Define (ig);
799                 }
800
801                 public override bool IsIterator {
802                         get { return true; }
803                 }
804
805                 public override RootScopeInfo RootScope {
806                         get { return IteratorHost; }
807                 }
808
809                 public override ScopeInfo Scope {
810                         get { return IteratorHost; }
811                 }
812
813                 //
814                 // Our constructor
815                 //
816                 private Iterator (IMethodData m_container, DeclSpace host, GenericMethod generic,
817                                  int modifiers, Type iterator_type, bool is_enumerable)
818                         : base (null, host, generic, m_container.ParameterInfo,
819                                 new ToplevelBlock (m_container.ParameterInfo, m_container.Location),
820                                 m_container.Block, TypeManager.bool_type, modifiers,
821                                 m_container.Location)
822                 {
823                         this.OriginalBlock = m_container.Block;
824                         this.OriginalMethod = m_container;
825                         this.OriginalIteratorType = iterator_type;
826                         this.IsEnumerable = is_enumerable;
827
828                         Report.Debug (64, "NEW ITERATOR", host, generic, OriginalBlock,
829                                       Container, Block);
830
831                         IteratorHost = new IteratorHost (this);
832                         Block.CreateIteratorHost (IteratorHost);
833
834                         OriginalBlock.ReParent (Container.Toplevel);
835
836                         m_container.Block = Container.Toplevel;
837
838                         OriginalBlock.MakeIterator (this);
839                 }
840
841                 protected class TestStatement : Statement
842                 {
843                         public override bool Resolve (EmitContext ec)
844                         {
845                                 return true;
846                         }
847
848                         protected override void DoEmit (EmitContext ec)
849                         {
850                                 ec.ig.Emit (OpCodes.Nop);
851                                 ec.ig.Emit (OpCodes.Neg);
852                                 ec.ig.Emit (OpCodes.Pop);
853                                 ec.ig.Emit (OpCodes.Ret);
854                         }
855                 }
856
857                 public override string GetSignatureForError ()
858                 {
859                         return OriginalMethod.GetSignatureForError ();
860                 }
861
862                 public override bool Resolve (EmitContext ec)
863                 {
864                         Report.Debug (64, "RESOLVE ITERATOR", this, Container, Block);
865
866                         Parameters parameters = OriginalMethod.ParameterInfo;
867                         for (int i = 0; i < parameters.Count; i++){
868                                 Parameter.Modifier mod = parameters.ParameterModifier (i);
869                                 if ((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) != 0){
870                                         Report.Error (1623, Location,
871                                                       "Iterators cannot have ref or out parameters");
872                                         return false;
873                                 }
874
875                                 if ((mod & Parameter.Modifier.ARGLIST) != 0) {
876                                         Report.Error (1636, Location,
877                                                       "__arglist is not allowed in parameter list " +
878                                                       "of iterators");
879                                         return false;
880                                 }
881
882                                 if (parameters.ParameterType (i).IsPointer) {
883                                         Report.Error (1637, Location,
884                                                       "Iterators cannot have unsafe parameters or " +
885                                                       "yield types");
886                                         return false;
887                                 }
888                         }
889
890                         if ((ModFlags & Modifiers.UNSAFE) != 0) {
891                                 Report.Error (1629, Location, "Unsafe code may not appear in iterators");
892                                 return false;
893                         }
894
895                         if (!base.Resolve (ec))
896                                 return false;
897
898                         Report.Debug (64, "RESOLVE ITERATOR #1", this, method, method.Parent,
899                                       RootScope, ec);
900
901                         if (!RootScope.ResolveType ())
902                                 return false;
903                         if (!RootScope.ResolveMembers ())
904                                 return false;
905                         if (!RootScope.DefineMembers ())
906                                 return false;
907
908                         ExpressionStatement scope_init = RootScope.GetScopeInitializer (ec);
909                         Container.AddStatement (new StatementExpression (scope_init));
910                         Expression cast = new ClassCast (scope_init, OriginalMethod.ReturnType);
911                         Container.AddStatement (new NoCheckReturn (cast));
912
913                         return true;
914                 }
915
916                 protected override Method DoCreateMethodHost (EmitContext ec)
917                 {
918                         Report.Debug (128, "CREATE METHOD HOST", this, IteratorHost);
919
920                         IteratorHost.CaptureScopes ();
921
922                         return new AnonymousMethodMethod (
923                                 this, RootScope, null, TypeManager.system_boolean_expr,
924                                 Modifiers.PUBLIC, new MemberName ("MoveNext", Location),
925                                 Parameters.EmptyReadOnlyParameters);
926                 }
927
928                 protected class MoveNextStatement : Statement {
929                         Iterator iterator;
930
931                         public MoveNextStatement (Iterator iterator, Location loc)
932                         {
933                                 this.loc = loc;
934                                 this.iterator = iterator;
935                         }
936
937                         public override bool Resolve (EmitContext ec)
938                         {
939                                 return iterator.OriginalBlock.Resolve (ec);
940                         }
941
942                         protected override void DoEmit (EmitContext ec)
943                         {
944                                 iterator.EmitMoveNext (ec, iterator.Block);
945                         }
946                 }
947
948                 public Type IteratorType {
949                         get { return IteratorHost.IteratorType; }
950                 }
951
952                 //
953                 // This return statement tricks return into not flagging an error for being
954                 // used in a Yields method
955                 //
956                 class NoCheckReturn : Statement {
957                         public Expression Expr;
958                 
959                         public NoCheckReturn (Expression expr)
960                         {
961                                 Expr = expr;
962                                 loc = expr.Location;
963                         }
964
965                         public override bool Resolve (EmitContext ec)
966                         {
967                                 Expr = Expr.Resolve (ec);
968                                 if (Expr == null)
969                                         return false;
970
971                                 ec.CurrentBranching.CurrentUsageVector.Return ();
972
973                                 return true;
974                         }
975
976                         protected override void DoEmit (EmitContext ec)
977                         {
978                                 Expr.Emit (ec);
979                                 ec.ig.Emit (OpCodes.Ret);
980                         }
981                 }
982
983                 public static Iterator CreateIterator (IMethodData method, DeclSpace parent,
984                                                        GenericMethod generic, int modifiers)
985                 {
986                         bool is_enumerable;
987                         Type iterator_type;
988
989                         if (!CheckType (method.ReturnType, out iterator_type, out is_enumerable)) {
990                                 Report.Error (1624, method.Location,
991                                               "The body of `{0}' cannot be an iterator block " +
992                                               "because `{1}' is not an iterator interface type",
993                                               method.GetSignatureForError (),
994                                               TypeManager.CSharpName (method.ReturnType));
995                                 return null;
996                         }
997
998                         return new Iterator (method, parent, generic, modifiers,
999                                              iterator_type, is_enumerable);
1000                 }
1001
1002                 static bool CheckType (Type ret, out Type original_iterator_type, out bool is_enumerable)
1003                 {
1004                         original_iterator_type = null;
1005                         is_enumerable = false;
1006
1007                         if (ret == TypeManager.ienumerable_type) {
1008                                 original_iterator_type = TypeManager.object_type;
1009                                 is_enumerable = true;
1010                                 return true;
1011                         }
1012                         if (ret == TypeManager.ienumerator_type) {
1013                                 original_iterator_type = TypeManager.object_type;
1014                                 is_enumerable = false;
1015                                 return true;
1016                         }
1017
1018 #if GMCS_SOURCE
1019                         if (!ret.IsGenericType)
1020                                 return false;
1021
1022                         Type[] args = TypeManager.GetTypeArguments (ret);
1023                         if (args.Length != 1)
1024                                 return false;
1025
1026                         Type gt = ret.GetGenericTypeDefinition ();
1027                         if (gt == TypeManager.generic_ienumerable_type) {
1028                                 original_iterator_type = args [0];
1029                                 is_enumerable = true;
1030                                 return true;
1031                         } else if (gt == TypeManager.generic_ienumerator_type) {
1032                                 original_iterator_type = args [0];
1033                                 is_enumerable = false;
1034                                 return true;
1035                         }
1036 #endif
1037
1038                         return false;
1039                 }
1040         }
1041 }
1042