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