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