This commit was manufactured by cvs2svn to create branch 'mono-1-0'.
[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 parent 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 interface IIteratorContainer {
25
26                 //
27                 // Invoked if a yield statement is found in the body
28                 //
29                 void SetYields ();
30         }
31         
32         public class Yield : Statement {
33                 public Expression expr;
34                 bool in_exc;
35                 
36                 public Yield (Expression expr, Location l)
37                 {
38                         this.expr = expr;
39                         loc = l;
40                 }
41
42                 public static bool CheckContext (EmitContext ec, Location loc)
43                 {
44                         if (ec.CurrentBranching.InFinally (true)){
45                                 Report.Error (1625, loc, "Cannot yield in the body of a " +
46                                               "finally clause");
47                                 return false;
48                         }
49                         if (ec.CurrentBranching.InCatch ()){
50                                 Report.Error (1631, loc, "Cannot yield in the body of a " +
51                                               "catch clause");
52                                 return false;
53                         }
54                         if (ec.InAnonymousMethod){
55                                 Report.Error (1621, loc, "yield statement can not appear " +
56                                               "inside an anonymoud method");
57                                 return false;
58                         }
59
60                         //
61                         // FIXME: Missing check for Yield inside try block that contains catch clauses
62                         //
63                         return true;
64                 }
65                 
66                 public override bool Resolve (EmitContext ec)
67                 {
68                         expr = expr.Resolve (ec);
69                         if (expr == null)
70                                 return false;
71                         if (!CheckContext (ec, loc))
72                                 return false;
73
74                         in_exc = ec.CurrentBranching.InTryOrCatch (false);
75                         Type iterator_type = IteratorHandler.Current.IteratorType;
76                         if (expr.Type != iterator_type){
77                                 expr = Convert.ImplicitConversionRequired (ec, expr, iterator_type, loc);
78                                 if (expr == null)
79                                         return false;
80                         }
81                         return true;
82                 }
83
84                 protected override void DoEmit (EmitContext ec)
85                 {
86                         IteratorHandler.Current.MarkYield (ec, expr, in_exc);
87                 }
88         }
89
90         public class YieldBreak : Statement {
91
92                 public YieldBreak (Location l)
93                 {
94                         loc = l;
95                 }
96
97                 public override bool Resolve (EmitContext ec)
98                 {
99                         if (!Yield.CheckContext (ec, loc))
100                                 return false;
101
102                         ec.CurrentBranching.CurrentUsageVector.Goto ();
103                         return true;
104                 }
105
106                 protected override void DoEmit (EmitContext ec)
107                 {
108                         IteratorHandler.Current.EmitYieldBreak (ec.ig, true);
109                 }
110         }
111
112         public class IteratorHandler {
113                 //
114                 // Points to the current iterator handler, will be probed by
115                 // Yield and YieldBreak to get their context information
116                 //
117                 public static IteratorHandler Current;
118                 
119                 //
120                 // The typebuilder to the proxy class we create
121                 //
122                 TypeBuilder enumerator_proxy_class;
123                 TypeBuilder enumerable_proxy_class;
124
125                 //
126                 // The type of this iterator, object by default.
127                 //
128                 public Type IteratorType;
129                 
130                 //
131                 // The members we create on the proxy class
132                 //
133                 MethodBuilder move_next_method;
134                 MethodBuilder reset_method;
135                 MethodBuilder get_current_method;
136                 MethodBuilder dispose_method;
137                 MethodBuilder getenumerator_method;
138                 PropertyBuilder current_property;
139                 ConstructorBuilder enumerator_proxy_constructor;
140                 ConstructorBuilder enumerable_proxy_constructor;
141
142                 //
143                 // The PC for the state machine.
144                 //
145                 FieldBuilder pc_field;
146
147                 //
148                 // The value computed for Current
149                 //
150                 FieldBuilder current_field;
151
152                 //
153                 // Used to reference fields on the container class (instance methods)
154                 //
155                 public FieldBuilder this_field;
156                 public FieldBuilder enumerable_this_field;
157
158                 //
159                 // References the parameters
160                 //
161
162                 public FieldBuilder [] parameter_fields;
163                 FieldBuilder [] enumerable_parameter_fields;
164                 
165                 //
166                 // The state as we generate the iterator
167                 //
168                 ArrayList resume_labels = new ArrayList ();
169                 int pc;
170                 
171                 //
172                 // Context from the original method
173                 //
174                 string name;
175                 TypeContainer container;
176                 Type return_type;
177                 Type [] param_types;
178                 InternalParameters parameters;
179                 Block original_block;
180                 Location loc;
181                 int modifiers;
182
183                 static int proxy_count;
184
185                 public void EmitYieldBreak (ILGenerator ig, bool add_return)
186                 {
187                         ig.Emit (OpCodes.Ldarg_0);
188                         IntConstant.EmitInt (ig, -1);
189                         ig.Emit (OpCodes.Stfld, pc_field);
190                         if (add_return){
191                                 ig.Emit (OpCodes.Ldc_I4_0);
192                                 ig.Emit (OpCodes.Ret);
193                         }
194                 }
195
196                 void EmitThrowInvalidOp (ILGenerator ig)
197                 {
198                         ig.Emit (OpCodes.Newobj, TypeManager.invalid_operation_ctor);
199                         ig.Emit (OpCodes.Throw);
200                 }
201                 
202                 void Create_MoveNext ()
203                 {
204                         move_next_method = enumerator_proxy_class.DefineMethod (
205                                 "System.IEnumerator.MoveNext",
206                                 MethodAttributes.HideBySig | MethodAttributes.NewSlot |
207                                 MethodAttributes.Virtual,
208                                 CallingConventions.HasThis, TypeManager.bool_type, TypeManager.NoTypes);
209                         enumerator_proxy_class.DefineMethodOverride (move_next_method, TypeManager.bool_movenext_void);
210
211                         ILGenerator ig = move_next_method.GetILGenerator ();
212                         EmitContext ec = new EmitContext (
213                                 container, loc, ig,
214                                 TypeManager.void_type, modifiers);
215
216                         Label dispatcher = ig.DefineLabel ();
217                         ig.Emit (OpCodes.Br, dispatcher);
218                         Label entry_point = ig.DefineLabel ();
219                         ig.MarkLabel (entry_point);
220                         resume_labels.Add (entry_point);
221                         
222                         Current = this;
223                         SymbolWriter sw = CodeGen.SymbolWriter;
224                         if ((sw != null) && !Location.IsNull (loc) && !Location.IsNull (original_block.EndLocation)) {
225                                 sw.OpenMethod (container, move_next_method, loc, original_block.EndLocation);
226
227                                 ec.EmitTopBlock (original_block, parameters, loc);
228
229                                 sw.CloseMethod ();
230                         } else {
231                                 ec.EmitTopBlock (original_block, parameters, loc);
232                         }
233                         Current = null;
234
235                         EmitYieldBreak (ig, true);
236
237                         //
238                         // FIXME: Split the switch in blocks that can be consumed by switch.
239                         //
240                         ig.MarkLabel (dispatcher);
241                         
242                         Label [] labels = new Label [resume_labels.Count];
243                         resume_labels.CopyTo (labels);
244                         ig.Emit (OpCodes.Ldarg_0);
245                         ig.Emit (OpCodes.Ldfld, pc_field);
246                         ig.Emit (OpCodes.Switch, labels);
247                         ig.Emit (OpCodes.Ldc_I4_0); 
248                         ig.Emit (OpCodes.Ret); 
249                 }
250
251                 // 
252                 // Invoked when a local variable declaration needs to be mapped to
253                 // a field in our proxy class
254                 //
255                 // Prefixes registered:
256                 //   v_   for EmitContext.MapVariable
257                 //   s_   for Storage
258                 //
259                 public FieldBuilder MapVariable (string pfx, string name, Type t)
260                 {
261                         return enumerator_proxy_class.DefineField (pfx + name, t, FieldAttributes.Public);
262                 }
263                 
264                 void Create_Reset ()
265                 {
266                         reset_method = enumerator_proxy_class.DefineMethod (
267                                 "System.IEnumerator.Reset",
268                                 MethodAttributes.HideBySig | MethodAttributes.NewSlot |
269                                 MethodAttributes.Virtual,
270                                 CallingConventions.HasThis, TypeManager.void_type, TypeManager.NoTypes);
271                         enumerator_proxy_class.DefineMethodOverride (reset_method, TypeManager.void_reset_void);
272                         ILGenerator ig = reset_method.GetILGenerator ();
273                         EmitThrowInvalidOp (ig);
274                 }
275
276                 void Create_Current ()
277                 {
278                         get_current_method = enumerator_proxy_class.DefineMethod (
279                                 "System.IEnumerator.get_Current",
280                                 MethodAttributes.HideBySig | MethodAttributes.SpecialName |
281                                 MethodAttributes.NewSlot | MethodAttributes.Virtual,
282                                 CallingConventions.HasThis, TypeManager.object_type, TypeManager.NoTypes);
283                         enumerator_proxy_class.DefineMethodOverride (get_current_method, TypeManager.object_getcurrent_void);
284
285                         current_property = enumerator_proxy_class.DefineProperty (
286                                 "Current",
287                                 PropertyAttributes.RTSpecialName | PropertyAttributes.SpecialName,
288                                 TypeManager.object_type, null);
289
290                         current_property.SetGetMethod (get_current_method);
291                         
292                         ILGenerator ig = get_current_method.GetILGenerator ();
293
294                         ig.Emit (OpCodes.Ldarg_0);
295                         ig.Emit (OpCodes.Ldfld, pc_field);
296                         ig.Emit (OpCodes.Ldc_I4_0);
297                         Label return_current = ig.DefineLabel ();
298                         ig.Emit (OpCodes.Bgt, return_current);
299                         EmitThrowInvalidOp (ig);
300                         
301                         ig.MarkLabel (return_current);
302                         ig.Emit (OpCodes.Ldarg_0);
303                         ig.Emit (OpCodes.Ldfld, current_field);
304                         ig.Emit (OpCodes.Ret);
305                 }
306
307                 void Create_Dispose ()
308                 {
309                         dispose_method = enumerator_proxy_class.DefineMethod (
310                                 "System.IDisposable.Dispose",
311                                 MethodAttributes.HideBySig | MethodAttributes.SpecialName |
312                                 MethodAttributes.NewSlot | MethodAttributes.Virtual,
313                                 CallingConventions.HasThis, TypeManager.void_type, TypeManager.NoTypes);
314                         enumerator_proxy_class.DefineMethodOverride (dispose_method, TypeManager.void_dispose_void);
315                         ILGenerator ig = dispose_method.GetILGenerator (); 
316
317                         EmitYieldBreak (ig, false);
318                         ig.Emit (OpCodes.Ret);
319                 }
320                 
321                 void Create_GetEnumerator ()
322                 {
323                         getenumerator_method = enumerable_proxy_class.DefineMethod (
324                                 "IEnumerable.GetEnumerator",
325                                 MethodAttributes.HideBySig | MethodAttributes.SpecialName |
326                                 MethodAttributes.NewSlot | MethodAttributes.Virtual,
327                                 CallingConventions.HasThis, TypeManager.ienumerator_type, TypeManager.NoTypes);
328
329                         enumerable_proxy_class.DefineMethodOverride  (getenumerator_method, TypeManager.ienumerable_getenumerator_void);
330                         ILGenerator ig = getenumerator_method.GetILGenerator ();
331
332                         ig.Emit (OpCodes.Newobj, (ConstructorInfo) enumerator_proxy_constructor);
333                         if (enumerable_this_field != null || parameters.Count > 0){
334                                 LocalBuilder obj = ig.DeclareLocal (enumerator_proxy_class);
335                                 ig.Emit (OpCodes.Stloc, obj);
336                                 if (enumerable_this_field != null){
337                                         ig.Emit (OpCodes.Ldloc, obj);
338                                         ig.Emit (OpCodes.Ldarg_0);
339                                         ig.Emit (OpCodes.Ldfld, enumerable_this_field);
340                                         ig.Emit (OpCodes.Stfld, this_field);
341                                 }
342                                 
343                                 for (int i = 0; i < parameters.Count; i++){
344                                         ig.Emit (OpCodes.Ldloc, obj);   
345                                         ig.Emit (OpCodes.Ldarg_0);
346                                         ig.Emit (OpCodes.Ldfld, enumerable_parameter_fields [i]);
347                                         ig.Emit (OpCodes.Stfld, parameter_fields [i]);
348                                 }
349                                 ig.Emit (OpCodes.Ldloc, obj);
350                         }
351                         
352                         ig.Emit (OpCodes.Ret);
353                 }
354
355                 //
356                 // Called back from Yield
357                 //
358                 public void MarkYield (EmitContext ec, Expression expr, bool in_exc)
359                 {
360                         ILGenerator ig = ec.ig;
361
362                         // Store the new current
363                         ig.Emit (OpCodes.Ldarg_0);
364                         expr.Emit (ec);
365                         ig.Emit (OpCodes.Stfld, current_field);
366
367                         // increment pc
368                         pc++;
369                         ig.Emit (OpCodes.Ldarg_0);
370                         IntConstant.EmitInt (ig, pc);
371                         ig.Emit (OpCodes.Stfld, pc_field);
372
373                         // Return ok
374                         ig.Emit (OpCodes.Ldc_I4_1);
375                         
376                         // Find out how to "leave"
377                         if (in_exc || !ec.IsLastStatement){
378                                 Type old = ec.ReturnType;
379                                 ec.ReturnType = TypeManager.int32_type;
380                                 ig.Emit (OpCodes.Stloc, ec.TemporaryReturn ());
381                                 ec.ReturnType = old;
382                         }
383
384                         if (in_exc){
385                                 ec.NeedReturnLabel ();
386                                 ig.Emit (OpCodes.Leave, ec.ReturnLabel);
387                         } else if (ec.IsLastStatement){
388                                 ig.Emit (OpCodes.Ret);
389                         } else {
390                                 ec.NeedReturnLabel ();
391                                 ig.Emit (OpCodes.Br, ec.ReturnLabel);
392                         }
393                         
394                         Label resume_point = ig.DefineLabel ();
395                         ig.MarkLabel (resume_point);
396                         resume_labels.Add (resume_point);
397                 }
398
399                 //
400                 // Creates the IEnumerator Proxy class
401                 //
402                 void MakeEnumeratorProxy ()
403                 {
404                         TypeExpr [] proxy_base_interfaces = new TypeExpr [2];
405                         proxy_base_interfaces [0] = new TypeExpression (TypeManager.ienumerator_type, loc);
406                         proxy_base_interfaces [1] = new TypeExpression (TypeManager.idisposable_type, loc);
407                         Type [] proxy_base_itypes = new Type [2];
408                         proxy_base_itypes [0] = TypeManager.ienumerator_type;
409                         proxy_base_itypes [1] = TypeManager.idisposable_type;
410                         TypeBuilder container_builder = container.TypeBuilder;
411
412                         //
413                         // Create the class
414                         //
415                         enumerator_proxy_class = container_builder.DefineNestedType (
416                                 "<Enumerator:" + name + ":" + (proxy_count++) + ">",
417                                 TypeAttributes.AutoLayout | TypeAttributes.Class |TypeAttributes.NestedPrivate,
418                                 TypeManager.object_type, proxy_base_itypes);
419
420                         TypeManager.RegisterBuilder (enumerator_proxy_class, proxy_base_interfaces);
421
422                         //
423                         // Define our fields
424                         //
425                         pc_field = enumerator_proxy_class.DefineField ("PC", TypeManager.int32_type, FieldAttributes.Assembly);
426                         current_field = enumerator_proxy_class.DefineField ("current", IteratorType, FieldAttributes.Assembly);
427                         if ((modifiers & Modifiers.STATIC) == 0)
428                                 this_field = enumerator_proxy_class.DefineField ("THIS", container.TypeBuilder, FieldAttributes.Assembly);
429
430                         parameter_fields = new FieldBuilder [parameters.Count];
431                         for (int i = 0; i < parameters.Count; i++){
432                                 parameter_fields [i] = enumerator_proxy_class.DefineField (
433                                         String.Format ("tor{0}_{1}", i, parameters.ParameterName (i)),
434                                         parameters.ParameterType (i), FieldAttributes.Assembly);
435                         }
436                         
437                         //
438                         // Define a constructor 
439                         //
440
441                         enumerator_proxy_constructor = enumerator_proxy_class.DefineConstructor (
442                                 MethodAttributes.Public | MethodAttributes.HideBySig |
443                                 MethodAttributes.SpecialName | MethodAttributes.RTSpecialName,
444                                 CallingConventions.HasThis, TypeManager.NoTypes);
445                         InternalParameters parameter_info = new InternalParameters (
446                                 TypeManager.NoTypes, Parameters.EmptyReadOnlyParameters);
447                         TypeManager.RegisterMethod (enumerator_proxy_constructor, parameter_info, TypeManager.NoTypes);
448
449                         //
450                         // Our constructor
451                         //
452                         ILGenerator ig = enumerator_proxy_constructor.GetILGenerator ();
453                         ig.Emit (OpCodes.Ldarg_0);
454                         ig.Emit (OpCodes.Call, TypeManager.object_ctor);
455
456                         ig.Emit (OpCodes.Ret);
457                 }
458
459                 //
460                 // Creates the IEnumerable proxy class
461                 //
462                 void MakeEnumerableProxy ()
463                 {
464                         TypeBuilder container_builder = container.TypeBuilder;
465                         Type [] proxy_base_interfaces = new Type [1];
466                         proxy_base_interfaces [0] = TypeManager.ienumerable_type;
467
468                         //
469                         // Creates the Enumerable proxy class.
470                         //
471                         enumerable_proxy_class = container_builder.DefineNestedType (
472                                 "<Enumerable:" + name + ":" + (proxy_count++)+ ">",
473                                 TypeAttributes.AutoLayout | TypeAttributes.Class |TypeAttributes.NestedPublic,
474                                 TypeManager.object_type, proxy_base_interfaces);
475
476                         //
477                         // Constructor
478                         //
479                         if ((modifiers & Modifiers.STATIC) == 0){
480                                 enumerable_this_field = enumerable_proxy_class.DefineField (
481                                         "THIS", container.TypeBuilder, FieldAttributes.Assembly);
482                         }
483                         enumerable_parameter_fields = new FieldBuilder [parameters.Count];
484                         for (int i = 0; i < parameters.Count; i++){
485                                 enumerable_parameter_fields [i] = enumerable_proxy_class.DefineField (
486                                         String.Format ("able{0}_{1}", i, parameters.ParameterName (i)),
487                                         parameters.ParameterType (i), FieldAttributes.Assembly);
488                         }
489                         
490                         enumerable_proxy_constructor = enumerable_proxy_class.DefineConstructor (
491                                 MethodAttributes.Public | MethodAttributes.HideBySig |
492                                 MethodAttributes.SpecialName | MethodAttributes.RTSpecialName,
493                                 CallingConventions.HasThis, TypeManager.NoTypes);
494                         InternalParameters parameter_info = new InternalParameters (
495                                 TypeManager.NoTypes, Parameters.EmptyReadOnlyParameters);
496                         TypeManager.RegisterMethod (enumerable_proxy_constructor, parameter_info, TypeManager.NoTypes);
497                         
498                         ILGenerator ig = enumerable_proxy_constructor.GetILGenerator ();
499                         ig.Emit (OpCodes.Ldarg_0);
500                         ig.Emit (OpCodes.Call, TypeManager.object_ctor);
501
502                         ig.Emit (OpCodes.Ret);
503                 }
504
505                 //
506                 // Populates the Enumerator Proxy class
507                 //
508                 void PopulateProxy ()
509                 {
510                         RootContext.RegisterHelperClass (enumerator_proxy_class);
511                         
512                         Create_MoveNext ();
513                         Create_Reset ();
514                         Create_Current ();
515                         Create_Dispose ();
516
517                         if (IsIEnumerable (return_type)){
518                                 Create_GetEnumerator ();
519                                 RootContext.RegisterHelperClass (enumerable_proxy_class);
520                         }
521                 }
522                 
523
524                 //
525                 // This is invoked by the EmitCode hook
526                 //
527                 void SetupIterator ()
528                 {
529                         PopulateProxy ();
530                 }
531
532                 //
533                 // Our constructor
534                 //
535                 public IteratorHandler (string name, TypeContainer container, Type return_type, Type [] param_types,
536                                         InternalParameters parameters, int modifiers, Location loc)
537                 {
538                         this.name = name;
539                         this.container = container;
540                         this.return_type = return_type;
541                         this.param_types = param_types;
542                         this.parameters = parameters;
543                         this.modifiers = modifiers;
544                         this.loc = loc;
545
546                         IteratorType = TypeManager.object_type;
547                         
548                         RootContext.EmitCodeHook += new RootContext.Hook (SetupIterator);
549                 }
550
551                 //
552                 // This class is just an expression that evaluates to a type, and the
553                 // type is our internal proxy class.  Used in the generated new body
554                 // of the original method
555                 //
556                 class NewInnerType : Expression {
557                         IteratorHandler handler;
558                         
559                         public NewInnerType (IteratorHandler handler, Location l) 
560                         {
561                                 this.handler = handler;
562                                 eclass = ExprClass.Value;
563                                 loc = l;
564                         }
565
566                         public override Expression DoResolve (EmitContext ec)
567                         {
568                                 // Create the proxy class type.
569                                 handler.MakeEnumeratorProxy ();
570
571                                 if (IsIEnumerable (handler.return_type))
572                                         handler.MakeEnumerableProxy ();
573
574                                 type = handler.return_type;
575                                 return this;
576                         }
577
578                         public override Expression ResolveAsTypeStep (EmitContext ec)
579                         {
580                                 return DoResolve (ec);
581                         }
582
583                         public override void Emit (EmitContext ec)
584                         {
585                                 ILGenerator ig = ec.ig;
586                                 FieldBuilder this_field = null;
587                                 bool is_ienumerable = IsIEnumerable (handler.return_type);
588                                 Type temp_type;
589                                 
590                                 if (is_ienumerable){
591                                         temp_type = handler.enumerable_proxy_class;
592                                         ig.Emit (OpCodes.Newobj, (ConstructorInfo) handler.enumerable_proxy_constructor);
593                                         this_field = handler.enumerable_this_field;
594                                 } else {
595                                         temp_type = handler.enumerator_proxy_class;
596                                         ig.Emit (OpCodes.Newobj, (ConstructorInfo) handler.enumerator_proxy_constructor);
597                                         this_field = handler.this_field;
598                                 }
599
600                                 if (this_field == null && handler.parameters.Count == 0)
601                                         return;
602                                 
603                                 LocalBuilder temp = ec.GetTemporaryLocal (temp_type);
604
605                                 ig.Emit (OpCodes.Stloc, temp);
606                                 //
607                                 // Initialize This
608                                 //
609                                 int first = 0;
610                                 if (this_field != null){
611                                         ig.Emit (OpCodes.Ldloc, temp);
612                                         ig.Emit (OpCodes.Ldarg_0);
613                                         if (handler.container is Struct)
614                                                 ig.Emit (OpCodes.Ldobj, handler.container.TypeBuilder);
615                                         ig.Emit (OpCodes.Stfld, this_field);
616                                         first = 1;
617                                 }
618
619                                 for (int i = 0; i < handler.parameters.Count; i++){
620                                         ig.Emit (OpCodes.Ldloc, temp);
621                                         ParameterReference.EmitLdArg (ig, i + first);
622                                         if (is_ienumerable)
623                                                 ig.Emit (OpCodes.Stfld, handler.enumerable_parameter_fields [i]);
624                                         else
625                                                 ig.Emit (OpCodes.Stfld, handler.parameter_fields [i]);
626                                 }
627                                 
628                                 //
629                                 // Initialize fields
630                                 //
631                                 ig.Emit (OpCodes.Ldloc, temp);
632                                 ec.FreeTemporaryLocal (temp, handler.container.TypeBuilder);
633                         }
634                 }
635
636                 //
637                 // This return statement tricks return into not flagging an error for being
638                 // used in a Yields method
639                 //
640                 class NoCheckReturn : Return {
641                         public NoCheckReturn (Expression expr, Location loc) : base (expr, loc)
642                         {
643                         }
644                         
645                         public override bool Resolve (EmitContext ec)
646                         {
647                                 ec.InIterator = false;
648                                 bool ret_val = base.Resolve (ec);
649                                 ec.InIterator = true;
650
651                                 return ret_val;
652                         }
653                 }
654
655                 static bool IsIEnumerable (Type t)
656                 {
657                         return t == TypeManager.ienumerable_type;
658                 }
659
660                 static bool IsIEnumerator (Type t)
661                 {
662                         return t == TypeManager.ienumerator_type;
663                 }
664                 
665                 //
666                 // Returns the new block for the method, or null on failure
667                 //
668                 public Block Setup (Block block)
669                 {
670                         if (!(IsIEnumerator (return_type) || IsIEnumerable (return_type))){
671                                 Report.Error (
672                                         1624, loc, "The body of `{0}' cannot be an iterator " +
673                                         "block because '{1}' is not an iterator interface type",
674                                         name, TypeManager.CSharpName (return_type));
675                                 return null;
676                         }
677
678                         for (int i = 0; i < parameters.Count; i++){
679                                 Parameter.Modifier mod = parameters.ParameterModifier (i);
680                                 if ((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) != 0){
681                                         Report.Error (1623, loc, "Iterators cannot have ref " +
682                                                       "or out parameters");
683                                         return null;
684                                 }
685                         }
686
687                         original_block = block;
688                         Block b = new Block (null);
689
690                         // return new InnerClass ()
691                         b.AddStatement (new NoCheckReturn (new NewInnerType (this, loc), loc));
692                         return b;
693                 }
694         }
695 }
696