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