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