2003-09-22 Martin Baulig <martin@ximian.com>
[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.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.Goto ();
100                         return true;
101                 }
102
103                 protected override bool DoEmit (EmitContext ec)
104                 {
105                         IteratorHandler.Current.EmitYieldBreak (ec.ig, true);
106                         return false;
107                 }
108         }
109
110         public class IteratorHandler {
111                 //
112                 // Points to the current iterator handler, will be probed by
113                 // Yield and YieldBreak to get their context information
114                 //
115                 public static IteratorHandler Current;
116                 
117                 //
118                 // The typebuilder to the proxy class we create
119                 //
120                 TypeBuilder enumerator_proxy_class;
121                 TypeBuilder enumerable_proxy_class;
122
123                 //
124                 // The type of this iterator, object by default.
125                 //
126                 public Type IteratorType;
127                 
128                 //
129                 // The members we create on the proxy class
130                 //
131                 MethodBuilder move_next_method;
132                 MethodBuilder reset_method;
133                 MethodBuilder get_current_method;
134                 MethodBuilder dispose_method;
135                 MethodBuilder getenumerator_method;
136                 PropertyBuilder current_property;
137                 ConstructorBuilder enumerator_proxy_constructor;
138                 ConstructorBuilder enumerable_proxy_constructor;
139
140                 //
141                 // The PC for the state machine.
142                 //
143                 FieldBuilder pc_field;
144
145                 //
146                 // The value computed for Current
147                 //
148                 FieldBuilder current_field;
149
150                 //
151                 // Used to reference fields on the container class (instance methods)
152                 //
153                 public FieldBuilder this_field;
154                 public FieldBuilder enumerable_this_field;
155
156                 //
157                 // References the parameters
158                 //
159
160                 public FieldBuilder [] parameter_fields;
161                 FieldBuilder [] enumerable_parameter_fields;
162                 
163                 //
164                 // The state as we generate the iterator
165                 //
166                 ArrayList resume_labels = new ArrayList ();
167                 int pc;
168                 
169                 //
170                 // Context from the original method
171                 //
172                 string name;
173                 TypeContainer container;
174                 Type return_type;
175                 Type [] param_types;
176                 InternalParameters parameters;
177                 Block original_block;
178                 Location loc;
179                 int modifiers;
180
181                 static int proxy_count;
182                 string MakeProxyName ()
183                 {
184                         return String.Format ("__Proxy_{0}", proxy_count++);
185                 }
186
187                 public void EmitYieldBreak (ILGenerator ig, bool add_return)
188                 {
189                         ig.Emit (OpCodes.Ldarg_0);
190                         IntConstant.EmitInt (ig, -1);
191                         ig.Emit (OpCodes.Stfld, pc_field);
192                         if (add_return){
193                                 ig.Emit (OpCodes.Ldc_I4_0);
194                                 ig.Emit (OpCodes.Ret);
195                         }
196                 }
197
198                 void EmitThrowInvalidOp (ILGenerator ig)
199                 {
200                         ig.Emit (OpCodes.Newobj, TypeManager.invalid_operation_ctor);
201                         ig.Emit (OpCodes.Throw);
202                 }
203                 
204                 void Create_MoveNext ()
205                 {
206                         move_next_method = enumerator_proxy_class.DefineMethod (
207                                 "System.IEnumerator.MoveNext",
208                                 MethodAttributes.HideBySig | MethodAttributes.NewSlot |
209                                 MethodAttributes.Virtual,
210                                 CallingConventions.HasThis, TypeManager.bool_type, TypeManager.NoTypes);
211                         enumerator_proxy_class.DefineMethodOverride (move_next_method, TypeManager.bool_movenext_void);
212
213                         ILGenerator ig = move_next_method.GetILGenerator ();
214                         EmitContext ec = new EmitContext (
215                                 container, loc, ig,
216                                 TypeManager.void_type, modifiers);
217
218                         Label dispatcher = ig.DefineLabel ();
219                         ig.Emit (OpCodes.Br, dispatcher);
220                         Label entry_point = ig.DefineLabel ();
221                         ig.MarkLabel (entry_point);
222                         resume_labels.Add (entry_point);
223                         
224                         Current = this;
225                         SymbolWriter sw = CodeGen.SymbolWriter;
226                         if ((sw != null) && !Location.IsNull (loc) && !Location.IsNull (original_block.EndLocation)) {
227                                 sw.OpenMethod (container, move_next_method, loc, original_block.EndLocation);
228
229                                 ec.EmitTopBlock (original_block, parameters, loc);
230
231                                 sw.CloseMethod ();
232                         } else {
233                                 ec.EmitTopBlock (original_block, parameters, loc);
234                         }
235                         Current = null;
236
237                         EmitYieldBreak (ig, true);
238
239                         //
240                         // FIXME: Split the switch in blocks that can be consumed by switch.
241                         //
242                         ig.MarkLabel (dispatcher);
243                         
244                         Label [] labels = new Label [resume_labels.Count];
245                         resume_labels.CopyTo (labels);
246                         ig.Emit (OpCodes.Ldarg_0);
247                         ig.Emit (OpCodes.Ldfld, pc_field);
248                         ig.Emit (OpCodes.Switch, labels);
249                         ig.Emit (OpCodes.Ldc_I4_0); 
250                         ig.Emit (OpCodes.Ret); 
251                 }
252
253                 // 
254                 // Invoked when a local variable declaration needs to be mapped to
255                 // a field in our proxy class
256                 //
257                 // Prefixes registered:
258                 //   v_   for EmitContext.MapVariable
259                 //   s_   for Storage
260                 //
261                 public FieldBuilder MapVariable (string pfx, string name, Type t)
262                 {
263                         return enumerator_proxy_class.DefineField (pfx + name, t, FieldAttributes.Public);
264                 }
265                 
266                 void Create_Reset ()
267                 {
268                         reset_method = enumerator_proxy_class.DefineMethod (
269                                 "System.IEnumerator.Reset",
270                                 MethodAttributes.HideBySig | MethodAttributes.NewSlot |
271                                 MethodAttributes.Virtual,
272                                 CallingConventions.HasThis, TypeManager.void_type, TypeManager.NoTypes);
273                         enumerator_proxy_class.DefineMethodOverride (reset_method, TypeManager.void_reset_void);
274                         ILGenerator ig = reset_method.GetILGenerator ();
275                         EmitThrowInvalidOp (ig);
276                 }
277
278                 void Create_Current ()
279                 {
280                         get_current_method = enumerator_proxy_class.DefineMethod (
281                                 "System.IEnumerator.get_Current",
282                                 MethodAttributes.HideBySig | MethodAttributes.SpecialName |
283                                 MethodAttributes.NewSlot | MethodAttributes.Virtual,
284                                 CallingConventions.HasThis, TypeManager.object_type, TypeManager.NoTypes);
285                         enumerator_proxy_class.DefineMethodOverride (get_current_method, TypeManager.object_getcurrent_void);
286
287                         current_property = enumerator_proxy_class.DefineProperty (
288                                 "Current",
289                                 PropertyAttributes.RTSpecialName | PropertyAttributes.SpecialName,
290                                 TypeManager.object_type, null);
291
292                         current_property.SetGetMethod (get_current_method);
293                         
294                         ILGenerator ig = get_current_method.GetILGenerator ();
295
296                         ig.Emit (OpCodes.Ldarg_0);
297                         ig.Emit (OpCodes.Ldfld, pc_field);
298                         ig.Emit (OpCodes.Ldc_I4_0);
299                         Label return_current = ig.DefineLabel ();
300                         ig.Emit (OpCodes.Bgt, return_current);
301                         EmitThrowInvalidOp (ig);
302                         
303                         ig.MarkLabel (return_current);
304                         ig.Emit (OpCodes.Ldarg_0);
305                         ig.Emit (OpCodes.Ldfld, current_field);
306                         ig.Emit (OpCodes.Ret);
307                 }
308
309                 void Create_Dispose ()
310                 {
311                         dispose_method = enumerator_proxy_class.DefineMethod (
312                                 "System.IDisposable.Dispose",
313                                 MethodAttributes.HideBySig | MethodAttributes.SpecialName |
314                                 MethodAttributes.NewSlot | MethodAttributes.Virtual,
315                                 CallingConventions.HasThis, TypeManager.void_type, TypeManager.NoTypes);
316                         enumerator_proxy_class.DefineMethodOverride (dispose_method, TypeManager.void_dispose_void);
317                         ILGenerator ig = dispose_method.GetILGenerator (); 
318
319                         EmitYieldBreak (ig, false);
320                         ig.Emit (OpCodes.Ret);
321                 }
322                 
323                 void Create_GetEnumerator ()
324                 {
325                         getenumerator_method = enumerable_proxy_class.DefineMethod (
326                                 "IEnumerable.GetEnumerator",
327                                 MethodAttributes.HideBySig | MethodAttributes.SpecialName |
328                                 MethodAttributes.NewSlot | MethodAttributes.Virtual,
329                                 CallingConventions.HasThis, TypeManager.ienumerator_type, TypeManager.NoTypes);
330
331                         enumerable_proxy_class.DefineMethodOverride  (getenumerator_method, TypeManager.ienumerable_getenumerator_void);
332                         ILGenerator ig = getenumerator_method.GetILGenerator ();
333
334                         if (enumerable_this_field != null){
335                                 ig.Emit (OpCodes.Ldarg_0);
336                                 ig.Emit (OpCodes.Ldfld, enumerable_this_field);
337                         }
338                         for (int i = 0; i < parameters.Count; i++){
339                                 ig.Emit (OpCodes.Ldarg_0);
340                                 ig.Emit (OpCodes.Ldfld, enumerable_parameter_fields [i]);
341                         }
342                         ig.Emit (OpCodes.Newobj, (ConstructorInfo) enumerator_proxy_constructor);
343                         ig.Emit (OpCodes.Ret);
344                 }
345
346                 void LoadArgs (ILGenerator ig)
347                 {
348                         int count = parameters.Count;
349                         if ((modifiers & Modifiers.STATIC) == 0)
350                                 count++;
351
352                         for (int i = 0; i < count; i++)
353                                 ParameterReference.EmitLdArg (ig, i);
354                 }
355                 
356                 //
357                 // Called back from Yield
358                 //
359                 public void MarkYield (EmitContext ec, Expression expr)
360                 {
361                         ILGenerator ig = ec.ig;
362
363                         // Store the new current
364                         ig.Emit (OpCodes.Ldarg_0);
365                         expr.Emit (ec);
366                         ig.Emit (OpCodes.Stfld, current_field);
367
368                         // increment pc
369                         pc++;
370                         ig.Emit (OpCodes.Ldarg_0);
371                         IntConstant.EmitInt (ig, pc);
372                         ig.Emit (OpCodes.Stfld, pc_field);
373                         
374                         // Return ok.
375                         ig.Emit (OpCodes.Ldc_I4_1);
376                         ig.Emit (OpCodes.Ret);
377                         
378                         Label resume_point = ig.DefineLabel ();
379                         ig.MarkLabel (resume_point);
380                         resume_labels.Add (resume_point);
381                 }
382
383                 void ComputeConstructorTypes (out Type [] constructor_types, out Parameters constructor_parameters)
384                 {
385                         bool is_static =  (modifiers & Modifiers.STATIC) != 0;
386                         
387                         if (is_static && parameters.Count == 0){
388                                 constructor_types = TypeManager.NoTypes;
389                                 constructor_parameters = Parameters.EmptyReadOnlyParameters;
390                                 return;
391                         }
392
393                         int count = (is_static ? 0 : 1) + parameters.Count;
394                         constructor_types = new Type [count];
395                         Parameter [] pars = new Parameter [count];
396                         constructor_parameters = new Parameters (pars, null, loc);
397                         
398                         int i = 0;
399                         if (!is_static){
400                                 constructor_types [0] = container.TypeBuilder;
401
402                                 Parameter THIS = new Parameter (
403                                         new TypeExpr (container.TypeBuilder, loc), "this", Parameter.Modifier.NONE, null);
404                                 pars [0] = THIS;
405                                 i++;
406                         }
407
408                         for (int j = 0; j < parameters.Count; j++, i++){
409                                 Type partype = parameters.ParameterType (j);
410                                 
411                                 pars [i] = new Parameter (new TypeExpr (partype, loc),
412                                                           parameters.ParameterName (j),
413                                                           Parameter.Modifier.NONE, null);
414                                 constructor_types [i] = partype;
415                         }
416                 }
417                 
418                 //
419                 // Creates the IEnumerator Proxy class
420                 //
421                 void MakeEnumeratorProxy ()
422                 {
423                         Type [] proxy_base_interfaces = new Type [2];
424                         proxy_base_interfaces [0] = TypeManager.ienumerator_type;
425                         proxy_base_interfaces [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_interfaces);
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