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