2003-05-27 Miguel de Icaza <miguel@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
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.InFinally){
44                                 Report.Error (-208, loc, "yield statement can not appear in finally clause");
45                                 return false;
46                         }
47                         if (ec.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 bool DoEmit (EmitContext ec)
80                 {
81                         IteratorHandler.Current.MarkYield (ec, expr);
82                         
83                         return false;
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.Breaks = FlowReturns.ALWAYS;
100                         ec.CurrentBranching.CurrentUsageVector.Returns = FlowReturns.ALWAYS;
101                         return true;
102                 }
103
104                 protected override bool DoEmit (EmitContext ec)
105                 {
106                         IteratorHandler.Current.EmitYieldBreak (ec.ig, true);
107                         return false;
108                 }
109         }
110
111         public class IteratorHandler {
112                 //
113                 // Points to the current iterator handler, will be probed by
114                 // Yield and YieldBreak to get their context information
115                 //
116                 public static IteratorHandler Current;
117                 
118                 //
119                 // The typebuilder to the proxy class we create
120                 //
121                 TypeBuilder enumerator_proxy_class;
122                 TypeBuilder enumerable_proxy_class;
123
124                 //
125                 // The type of this iterator, object by default.
126                 //
127                 public Type IteratorType;
128                 
129                 //
130                 // The members we create on the proxy class
131                 //
132                 MethodBuilder move_next_method;
133                 MethodBuilder reset_method;
134                 MethodBuilder get_current_method;
135                 MethodBuilder dispose_method;
136                 MethodBuilder getenumerator_method;
137                 PropertyBuilder current_property;
138                 ConstructorBuilder enumerator_proxy_constructor;
139                 ConstructorBuilder enumerable_proxy_constructor;
140
141                 //
142                 // The PC for the state machine.
143                 //
144                 FieldBuilder pc_field;
145
146                 //
147                 // The value computed for Current
148                 //
149                 FieldBuilder current_field;
150
151                 //
152                 // Used to reference fields on the container class (instance methods)
153                 //
154                 public FieldBuilder this_field;
155                 public FieldBuilder enumerable_this_field;
156
157                 //
158                 // References the parameters
159                 //
160
161                 public FieldBuilder [] parameter_fields;
162                 FieldBuilder [] enumerable_parameter_fields;
163                 
164                 //
165                 // The state as we generate the iterator
166                 //
167                 ArrayList resume_labels = new ArrayList ();
168                 int pc;
169                 
170                 //
171                 // Context from the original method
172                 //
173                 string name;
174                 TypeContainer container;
175                 Type return_type;
176                 Type [] param_types;
177                 InternalParameters parameters;
178                 Block original_block;
179                 Location loc;
180                 int modifiers;
181
182                 static int proxy_count;
183                 string MakeProxyName ()
184                 {
185                         return String.Format ("<Proxy_{0}>", proxy_count++);
186                 }
187
188                 public void EmitYieldBreak (ILGenerator ig, bool add_return)
189                 {
190                         ig.Emit (OpCodes.Ldarg_0);
191                         IntConstant.EmitInt (ig, -1);
192                         ig.Emit (OpCodes.Stfld, pc_field);
193                         if (add_return){
194                                 ig.Emit (OpCodes.Ldc_I4_0);
195                                 ig.Emit (OpCodes.Ret);
196                         }
197                 }
198
199                 void EmitThrowInvalidOp (ILGenerator ig)
200                 {
201                         ig.Emit (OpCodes.Newobj, TypeManager.invalid_operation_ctor);
202                         ig.Emit (OpCodes.Throw);
203                 }
204                 
205                 void Create_MoveNext ()
206                 {
207                         move_next_method = enumerator_proxy_class.DefineMethod (
208                                 "System.IEnumerator.MoveNext",
209                                 MethodAttributes.HideBySig | MethodAttributes.NewSlot |
210                                 MethodAttributes.Virtual,
211                                 CallingConventions.HasThis, TypeManager.bool_type, TypeManager.NoTypes);
212                         enumerator_proxy_class.DefineMethodOverride (move_next_method, TypeManager.bool_movenext_void);
213
214                         ILGenerator ig = move_next_method.GetILGenerator ();
215                         EmitContext ec = new EmitContext (
216                                 container, loc, ig,
217                                 TypeManager.void_type, modifiers);
218
219                         Label dispatcher = ig.DefineLabel ();
220                         ig.Emit (OpCodes.Br, dispatcher);
221                         Label entry_point = ig.DefineLabel ();
222                         ig.MarkLabel (entry_point);
223                         resume_labels.Add (entry_point);
224                         
225                         Current = this;
226                         SymbolWriter sw = CodeGen.SymbolWriter;
227                         if ((sw != null) && !Location.IsNull (loc) && !Location.IsNull (original_block.EndLocation)) {
228                                 sw.OpenMethod (container, move_next_method, loc, original_block.EndLocation);
229
230                                 ec.EmitTopBlock (original_block, parameters, loc);
231
232                                 sw.CloseMethod ();
233                         } else {
234                                 ec.EmitTopBlock (original_block, parameters, loc);
235                         }
236                         Current = null;
237
238                         EmitYieldBreak (ig, true);
239
240                         //
241                         // FIXME: Split the switch in blocks that can be consumed by switch.
242                         //
243                         ig.MarkLabel (dispatcher);
244                         
245                         Label [] labels = new Label [resume_labels.Count];
246                         resume_labels.CopyTo (labels);
247                         ig.Emit (OpCodes.Ldarg_0);
248                         ig.Emit (OpCodes.Ldfld, pc_field);
249                         ig.Emit (OpCodes.Switch, labels);
250                         ig.Emit (OpCodes.Ldc_I4_0); 
251                         ig.Emit (OpCodes.Ret); 
252                 }
253
254                 // 
255                 // Invoked when a local variable declaration needs to be mapped to
256                 // a field in our proxy class
257                 //
258                 public FieldBuilder MapVariable (string name, Type t)
259                 {
260                         return enumerator_proxy_class.DefineField ("v" + 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 TypeExpr (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 TypeExpr (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                         Type [] proxy_base_interfaces = new Type [2];
421                         proxy_base_interfaces [0] = TypeManager.ienumerator_type;
422                         proxy_base_interfaces [1] = TypeManager.idisposable_type;
423                         TypeBuilder container_builder = container.TypeBuilder;
424
425                         //
426                         // Create the class
427                         //
428                         enumerator_proxy_class = container_builder.DefineNestedType (
429                                 MakeProxyName (), TypeAttributes.AutoLayout | TypeAttributes.Class |TypeAttributes.NestedPublic,
430                                 TypeManager.object_type, proxy_base_interfaces);
431
432                         TypeManager.RegisterBuilder (enumerator_proxy_class, proxy_base_interfaces);
433
434                         //
435                         // Define our fields
436                         //
437                         pc_field = enumerator_proxy_class.DefineField ("PC", TypeManager.int32_type, FieldAttributes.Private);
438                         current_field = enumerator_proxy_class.DefineField ("current", IteratorType, FieldAttributes.Private);
439                         if ((modifiers & Modifiers.STATIC) == 0)
440                                 this_field = enumerator_proxy_class.DefineField ("THIS", container.TypeBuilder, FieldAttributes.Private);
441
442                         parameter_fields = new FieldBuilder [parameters.Count];
443                         for (int i = 0; i < parameters.Count; i++){
444                                 parameter_fields [i] = enumerator_proxy_class.DefineField (
445                                         String.Format ("p{0}_{1}", i, parameters.ParameterName (i)),
446                                         parameters.ParameterType (i), FieldAttributes.Private);
447                         }
448                         
449                         //
450                         // Define a constructor 
451                         //
452                         // FIXME: currently its parameterless
453                         Type [] constructor_types;
454                         Parameters constructor_parameters;
455
456                         ComputeConstructorTypes (out constructor_types, out constructor_parameters);
457                         
458                         enumerator_proxy_constructor = enumerator_proxy_class.DefineConstructor (
459                                 MethodAttributes.Public | MethodAttributes.HideBySig |
460                                 MethodAttributes.SpecialName | MethodAttributes.RTSpecialName,
461                                 CallingConventions.HasThis, constructor_types);
462                         InternalParameters parameter_info = new InternalParameters (constructor_types, constructor_parameters);
463                         TypeManager.RegisterMethod (enumerator_proxy_constructor, parameter_info, constructor_types);
464
465                         //
466                         // Our constructor
467                         //
468                         ILGenerator ig = enumerator_proxy_constructor.GetILGenerator ();
469                         ig.Emit (OpCodes.Ldarg_0);
470                         ig.Emit (OpCodes.Call, TypeManager.object_ctor);
471
472                         int arg_start;
473                         if (this_field != null){
474                                 arg_start = 2;
475                                 ig.Emit (OpCodes.Ldarg_0);
476                                 ig.Emit (OpCodes.Ldarg_1);
477                                 ig.Emit (OpCodes.Stfld, this_field);
478                         } else {
479                                 arg_start = 1;
480                         }
481                         for (int i = 0; i < parameters.Count; i++){
482                                 ig.Emit (OpCodes.Ldarg_0);
483                                 ParameterReference.EmitLdArg (ig, i + arg_start);
484                                 ig.Emit (OpCodes.Stfld, parameter_fields [i]);
485                         }
486                         ig.Emit (OpCodes.Ret);
487                 }
488
489                 //
490                 // Creates the IEnumerable proxy class
491                 //
492                 void MakeEnumerableProxy ()
493                 {
494                         TypeBuilder container_builder = container.TypeBuilder;
495                         Type [] proxy_base_interfaces = new Type [1];
496                         proxy_base_interfaces [0] = TypeManager.ienumerable_type;
497
498                         //
499                         // Creates the Enumerable proxy class.
500                         //
501                         enumerable_proxy_class = container_builder.DefineNestedType (
502                                 MakeProxyName (), TypeAttributes.AutoLayout | TypeAttributes.Class |TypeAttributes.NestedPublic,
503                                 TypeManager.object_type, proxy_base_interfaces);
504
505                         //
506                         // Constructor
507                         //
508                         Type [] constructor_types;
509                         Parameters constructor_parameters;
510
511                         ComputeConstructorTypes (out constructor_types, out constructor_parameters);
512                         if ((modifiers & Modifiers.STATIC) == 0){
513                                 enumerable_this_field = enumerable_proxy_class.DefineField (
514                                         "THIS", container.TypeBuilder, FieldAttributes.Private);
515                         }
516                         enumerable_parameter_fields = new FieldBuilder [parameters.Count];
517                         for (int i = 0; i < parameters.Count; i++){
518                                 enumerable_parameter_fields [i] = enumerable_proxy_class.DefineField (
519                                         String.Format ("p{0}_{1}", i, parameters.ParameterName (i)),
520                                         parameters.ParameterType (i), FieldAttributes.Private);
521                         }
522                         
523                         enumerable_proxy_constructor = enumerable_proxy_class.DefineConstructor (
524                                 MethodAttributes.Public | MethodAttributes.HideBySig |
525                                 MethodAttributes.SpecialName | MethodAttributes.RTSpecialName,
526                                 CallingConventions.HasThis, constructor_types);
527                         InternalParameters parameter_info = new InternalParameters (constructor_types, constructor_parameters);
528                         TypeManager.RegisterMethod (enumerable_proxy_constructor, parameter_info, constructor_types);
529                         
530                         ILGenerator ig = enumerable_proxy_constructor.GetILGenerator ();
531                         ig.Emit (OpCodes.Ldarg_0);
532                         ig.Emit (OpCodes.Call, TypeManager.object_ctor);
533
534                         int first_arg;
535                         if (enumerable_this_field != null){
536                                 ig.Emit (OpCodes.Ldarg_0);
537                                 ig.Emit (OpCodes.Ldarg_1);
538                                 ig.Emit (OpCodes.Stfld, enumerable_this_field);
539                                 first_arg = 2;
540                         } else
541                                 first_arg = 1;
542                         
543                         for (int i = 0; i < parameters.Count; i++){
544                                 ig.Emit (OpCodes.Ldarg_0);
545                                 ParameterReference.EmitLdArg (ig, i + first_arg);
546                                 ig.Emit (OpCodes.Stfld, enumerable_parameter_fields [i]);
547                         }
548                         ig.Emit (OpCodes.Ret);
549                 }
550
551                 //
552                 // Populates the Enumerator Proxy class
553                 //
554                 void PopulateProxy ()
555                 {
556                         RootContext.RegisterHelperClass (enumerator_proxy_class);
557                         
558                         Create_MoveNext ();
559                         Create_Reset ();
560                         Create_Current ();
561                         Create_Dispose ();
562
563                         if (return_type == TypeManager.ienumerable_type){
564                                 Create_GetEnumerator ();
565                                 RootContext.RegisterHelperClass (enumerable_proxy_class);
566                         }
567                 }
568                 
569
570                 //
571                 // This is invoked by the EmitCode hook
572                 //
573                 void SetupIterator ()
574                 {
575                         PopulateProxy ();
576                 }
577
578                 //
579                 // Our constructor
580                 //
581                 public IteratorHandler (string name, TypeContainer container, Type return_type, Type [] param_types,
582                                         InternalParameters parameters, int modifiers, Location loc)
583                 {
584                         this.name = name;
585                         this.container = container;
586                         this.return_type = return_type;
587                         this.param_types = param_types;
588                         this.parameters = parameters;
589                         this.modifiers = modifiers;
590                         this.loc = loc;
591
592                         IteratorType = TypeManager.object_type;
593                         
594                         RootContext.EmitCodeHook += new RootContext.Hook (SetupIterator);
595                 }
596
597                 //
598                 // This class is just an expression that evaluates to a type, and the
599                 // type is our internal proxy class.  Used in the generated new body
600                 // of the original method
601                 //
602                 class NewInnerType : Expression {
603                         IteratorHandler handler;
604                         
605                         public NewInnerType (IteratorHandler handler, Location l) 
606                         {
607                                 this.handler = handler;
608                                 eclass = ExprClass.Value;
609                                 loc = l;
610                         }
611
612                         public override Expression DoResolve (EmitContext ec)
613                         {
614                                 // Create the proxy class type.
615                                 handler.MakeEnumeratorProxy ();
616
617                                 if (handler.return_type == TypeManager.ienumerable_type)
618                                         handler.MakeEnumerableProxy ();
619
620                                 type = handler.return_type;
621                                 return this;
622                         }
623
624                         public override Expression ResolveAsTypeStep (EmitContext ec)
625                         {
626                                 return DoResolve (ec);
627                         }
628
629                         public override void Emit (EmitContext ec)
630                         {
631                                 handler.LoadArgs (ec.ig);
632                                 
633                                 if (handler.return_type == TypeManager.ienumerable_type)
634                                         ec.ig.Emit (OpCodes.Newobj, (ConstructorInfo) handler.enumerable_proxy_constructor);
635                                 else 
636                                         ec.ig.Emit (OpCodes.Newobj, (ConstructorInfo) handler.enumerator_proxy_constructor);
637                         }
638                 }
639
640                 //
641                 // This return statement tricks return into not flagging an error for being
642                 // used in a Yields method
643                 //
644                 class NoCheckReturn : Return {
645                         public NoCheckReturn (Expression expr, Location loc) : base (expr, loc)
646                         {
647                         }
648                         
649                         public override bool Resolve (EmitContext ec)
650                         {
651                                 ec.InIterator = false;
652                                 bool ret_val = base.Resolve (ec);
653                                 ec.InIterator = true;
654
655                                 return ret_val;
656                         }
657                 }
658                 
659                 //
660                 // Returns the new block for the method, or null on failure
661                 //
662                 public Block Setup (Block block)
663                 {
664                         if (return_type != TypeManager.ienumerator_type &&
665                             return_type != TypeManager.ienumerable_type){
666                                 Report.Error (
667                                         -205, loc, String.Format (
668                                                 "The method `{0}' contains a yield statement, but has an invalid return type for an iterator",
669                                                 name));
670                                 return null;
671                         }
672
673                         for (int i = 0; i < parameters.Count; i++){
674                                 Parameter.Modifier mod = parameters.ParameterModifier (i);
675                                 if ((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) != 0){
676                                         Report.Error (-207, loc, String.Format (
677                                                               "Parameter {0} of `{1}' is {2} and not allowed for an iterator method",
678                                                               i+1, name, parameters.ParameterDesc (i)));
679                                         return null;
680                                 }
681                         }
682
683                         original_block = block;
684                         Block b = new Block (null);
685
686                         // return new InnerClass ()
687                         b.AddStatement (new NoCheckReturn (new NewInnerType (this, loc), loc));
688                         return b;
689                 }
690         }
691 }
692