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