2003-08-06 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                 // Prefixes registered:
259                 //   v_   for EmitContext.MapVariable
260                 //   s_   for Storage
261                 //
262                 public FieldBuilder MapVariable (string pfx, string name, Type t)
263                 {
264                         return enumerator_proxy_class.DefineField (pfx + name, t, FieldAttributes.Public);
265                 }
266                 
267                 void Create_Reset ()
268                 {
269                         reset_method = enumerator_proxy_class.DefineMethod (
270                                 "System.IEnumerator.Reset",
271                                 MethodAttributes.HideBySig | MethodAttributes.NewSlot |
272                                 MethodAttributes.Virtual,
273                                 CallingConventions.HasThis, TypeManager.void_type, TypeManager.NoTypes);
274                         enumerator_proxy_class.DefineMethodOverride (reset_method, TypeManager.void_reset_void);
275                         ILGenerator ig = reset_method.GetILGenerator ();
276                         EmitThrowInvalidOp (ig);
277                 }
278
279                 void Create_Current ()
280                 {
281                         get_current_method = enumerator_proxy_class.DefineMethod (
282                                 "System.IEnumerator.get_Current",
283                                 MethodAttributes.HideBySig | MethodAttributes.SpecialName |
284                                 MethodAttributes.NewSlot | MethodAttributes.Virtual,
285                                 CallingConventions.HasThis, TypeManager.object_type, TypeManager.NoTypes);
286                         enumerator_proxy_class.DefineMethodOverride (get_current_method, TypeManager.object_getcurrent_void);
287
288                         current_property = enumerator_proxy_class.DefineProperty (
289                                 "Current",
290                                 PropertyAttributes.RTSpecialName | PropertyAttributes.SpecialName,
291                                 TypeManager.object_type, null);
292
293                         current_property.SetGetMethod (get_current_method);
294                         
295                         ILGenerator ig = get_current_method.GetILGenerator ();
296
297                         ig.Emit (OpCodes.Ldarg_0);
298                         ig.Emit (OpCodes.Ldfld, pc_field);
299                         ig.Emit (OpCodes.Ldc_I4_0);
300                         Label return_current = ig.DefineLabel ();
301                         ig.Emit (OpCodes.Bgt, return_current);
302                         EmitThrowInvalidOp (ig);
303                         
304                         ig.MarkLabel (return_current);
305                         ig.Emit (OpCodes.Ldarg_0);
306                         ig.Emit (OpCodes.Ldfld, current_field);
307                         ig.Emit (OpCodes.Ret);
308                 }
309
310                 void Create_Dispose ()
311                 {
312                         dispose_method = enumerator_proxy_class.DefineMethod (
313                                 "System.IDisposable.Dispose",
314                                 MethodAttributes.HideBySig | MethodAttributes.SpecialName |
315                                 MethodAttributes.NewSlot | MethodAttributes.Virtual,
316                                 CallingConventions.HasThis, TypeManager.void_type, TypeManager.NoTypes);
317                         enumerator_proxy_class.DefineMethodOverride (dispose_method, TypeManager.void_dispose_void);
318                         ILGenerator ig = dispose_method.GetILGenerator (); 
319
320                         EmitYieldBreak (ig, false);
321                         ig.Emit (OpCodes.Ret);
322                 }
323                 
324                 void Create_GetEnumerator ()
325                 {
326                         getenumerator_method = enumerable_proxy_class.DefineMethod (
327                                 "IEnumerable.GetEnumerator",
328                                 MethodAttributes.HideBySig | MethodAttributes.SpecialName |
329                                 MethodAttributes.NewSlot | MethodAttributes.Virtual,
330                                 CallingConventions.HasThis, TypeManager.ienumerator_type, TypeManager.NoTypes);
331
332                         enumerable_proxy_class.DefineMethodOverride  (getenumerator_method, TypeManager.ienumerable_getenumerator_void);
333                         ILGenerator ig = getenumerator_method.GetILGenerator ();
334
335                         if (enumerable_this_field != null){
336                                 ig.Emit (OpCodes.Ldarg_0);
337                                 ig.Emit (OpCodes.Ldfld, enumerable_this_field);
338                         }
339                         for (int i = 0; i < parameters.Count; i++){
340                                 ig.Emit (OpCodes.Ldarg_0);
341                                 ig.Emit (OpCodes.Ldfld, enumerable_parameter_fields [i]);
342                         }
343                         ig.Emit (OpCodes.Newobj, (ConstructorInfo) enumerator_proxy_constructor);
344                         ig.Emit (OpCodes.Ret);
345                 }
346
347                 void LoadArgs (ILGenerator ig)
348                 {
349                         int count = parameters.Count;
350                         if ((modifiers & Modifiers.STATIC) == 0)
351                                 count++;
352
353                         for (int i = 0; i < count; i++)
354                                 ParameterReference.EmitLdArg (ig, i);
355                 }
356                 
357                 //
358                 // Called back from Yield
359                 //
360                 public void MarkYield (EmitContext ec, Expression expr)
361                 {
362                         ILGenerator ig = ec.ig;
363
364                         // Store the new current
365                         ig.Emit (OpCodes.Ldarg_0);
366                         expr.Emit (ec);
367                         ig.Emit (OpCodes.Stfld, current_field);
368
369                         // increment pc
370                         pc++;
371                         ig.Emit (OpCodes.Ldarg_0);
372                         IntConstant.EmitInt (ig, pc);
373                         ig.Emit (OpCodes.Stfld, pc_field);
374                         
375                         // Return ok.
376                         ig.Emit (OpCodes.Ldc_I4_1);
377                         ig.Emit (OpCodes.Ret);
378                         
379                         Label resume_point = ig.DefineLabel ();
380                         ig.MarkLabel (resume_point);
381                         resume_labels.Add (resume_point);
382                 }
383
384                 void ComputeConstructorTypes (out Type [] constructor_types, out Parameters constructor_parameters)
385                 {
386                         bool is_static =  (modifiers & Modifiers.STATIC) != 0;
387                         
388                         if (is_static && parameters.Count == 0){
389                                 constructor_types = TypeManager.NoTypes;
390                                 constructor_parameters = Parameters.EmptyReadOnlyParameters;
391                                 return;
392                         }
393
394                         int count = (is_static ? 0 : 1) + parameters.Count;
395                         constructor_types = new Type [count];
396                         Parameter [] pars = new Parameter [count];
397                         constructor_parameters = new Parameters (pars, null, loc);
398                         
399                         int i = 0;
400                         if (!is_static){
401                                 constructor_types [0] = container.TypeBuilder;
402
403                                 Parameter THIS = new Parameter (
404                                         new TypeExpr (container.TypeBuilder, loc), "this", Parameter.Modifier.NONE, null);
405                                 pars [0] = THIS;
406                                 i++;
407                         }
408
409                         for (int j = 0; j < parameters.Count; j++, i++){
410                                 Type partype = parameters.ParameterType (j);
411                                 
412                                 pars [i] = new Parameter (new TypeExpr (partype, loc),
413                                                           parameters.ParameterName (j),
414                                                           Parameter.Modifier.NONE, null);
415                                 constructor_types [i] = partype;
416                         }
417                 }
418                 
419                 //
420                 // Creates the IEnumerator Proxy class
421                 //
422                 void MakeEnumeratorProxy ()
423                 {
424                         Type [] proxy_base_interfaces = new Type [2];
425                         proxy_base_interfaces [0] = TypeManager.ienumerator_type;
426                         proxy_base_interfaces [1] = TypeManager.idisposable_type;
427                         TypeBuilder container_builder = container.TypeBuilder;
428
429                         //
430                         // Create the class
431                         //
432                         enumerator_proxy_class = container_builder.DefineNestedType (
433                                 MakeProxyName (), TypeAttributes.AutoLayout | TypeAttributes.Class |TypeAttributes.NestedPublic,
434                                 TypeManager.object_type, proxy_base_interfaces);
435
436                         TypeManager.RegisterBuilder (enumerator_proxy_class, proxy_base_interfaces);
437
438                         //
439                         // Define our fields
440                         //
441                         pc_field = enumerator_proxy_class.DefineField ("PC", TypeManager.int32_type, FieldAttributes.Private);
442                         current_field = enumerator_proxy_class.DefineField ("current", IteratorType, FieldAttributes.Private);
443                         if ((modifiers & Modifiers.STATIC) == 0)
444                                 this_field = enumerator_proxy_class.DefineField ("THIS", container.TypeBuilder, FieldAttributes.Private);
445
446                         parameter_fields = new FieldBuilder [parameters.Count];
447                         for (int i = 0; i < parameters.Count; i++){
448                                 parameter_fields [i] = enumerator_proxy_class.DefineField (
449                                         String.Format ("p{0}_{1}", i, parameters.ParameterName (i)),
450                                         parameters.ParameterType (i), FieldAttributes.Private);
451                         }
452                         
453                         //
454                         // Define a constructor 
455                         //
456                         // FIXME: currently its parameterless
457                         Type [] constructor_types;
458                         Parameters constructor_parameters;
459
460                         ComputeConstructorTypes (out constructor_types, out constructor_parameters);
461                         
462                         enumerator_proxy_constructor = enumerator_proxy_class.DefineConstructor (
463                                 MethodAttributes.Public | MethodAttributes.HideBySig |
464                                 MethodAttributes.SpecialName | MethodAttributes.RTSpecialName,
465                                 CallingConventions.HasThis, constructor_types);
466                         InternalParameters parameter_info = new InternalParameters (constructor_types, constructor_parameters);
467                         TypeManager.RegisterMethod (enumerator_proxy_constructor, parameter_info, constructor_types);
468
469                         //
470                         // Our constructor
471                         //
472                         ILGenerator ig = enumerator_proxy_constructor.GetILGenerator ();
473                         ig.Emit (OpCodes.Ldarg_0);
474                         ig.Emit (OpCodes.Call, TypeManager.object_ctor);
475
476                         int arg_start;
477                         if (this_field != null){
478                                 arg_start = 2;
479                                 ig.Emit (OpCodes.Ldarg_0);
480                                 ig.Emit (OpCodes.Ldarg_1);
481                                 ig.Emit (OpCodes.Stfld, this_field);
482                         } else {
483                                 arg_start = 1;
484                         }
485                         for (int i = 0; i < parameters.Count; i++){
486                                 ig.Emit (OpCodes.Ldarg_0);
487                                 ParameterReference.EmitLdArg (ig, i + arg_start);
488                                 ig.Emit (OpCodes.Stfld, parameter_fields [i]);
489                         }
490                         ig.Emit (OpCodes.Ret);
491                 }
492
493                 //
494                 // Creates the IEnumerable proxy class
495                 //
496                 void MakeEnumerableProxy ()
497                 {
498                         TypeBuilder container_builder = container.TypeBuilder;
499                         Type [] proxy_base_interfaces = new Type [1];
500                         proxy_base_interfaces [0] = TypeManager.ienumerable_type;
501
502                         //
503                         // Creates the Enumerable proxy class.
504                         //
505                         enumerable_proxy_class = container_builder.DefineNestedType (
506                                 MakeProxyName (), TypeAttributes.AutoLayout | TypeAttributes.Class |TypeAttributes.NestedPublic,
507                                 TypeManager.object_type, proxy_base_interfaces);
508
509                         //
510                         // Constructor
511                         //
512                         Type [] constructor_types;
513                         Parameters constructor_parameters;
514
515                         ComputeConstructorTypes (out constructor_types, out constructor_parameters);
516                         if ((modifiers & Modifiers.STATIC) == 0){
517                                 enumerable_this_field = enumerable_proxy_class.DefineField (
518                                         "THIS", container.TypeBuilder, FieldAttributes.Private);
519                         }
520                         enumerable_parameter_fields = new FieldBuilder [parameters.Count];
521                         for (int i = 0; i < parameters.Count; i++){
522                                 enumerable_parameter_fields [i] = enumerable_proxy_class.DefineField (
523                                         String.Format ("p{0}_{1}", i, parameters.ParameterName (i)),
524                                         parameters.ParameterType (i), FieldAttributes.Private);
525                         }
526                         
527                         enumerable_proxy_constructor = enumerable_proxy_class.DefineConstructor (
528                                 MethodAttributes.Public | MethodAttributes.HideBySig |
529                                 MethodAttributes.SpecialName | MethodAttributes.RTSpecialName,
530                                 CallingConventions.HasThis, constructor_types);
531                         InternalParameters parameter_info = new InternalParameters (constructor_types, constructor_parameters);
532                         TypeManager.RegisterMethod (enumerable_proxy_constructor, parameter_info, constructor_types);
533                         
534                         ILGenerator ig = enumerable_proxy_constructor.GetILGenerator ();
535                         ig.Emit (OpCodes.Ldarg_0);
536                         ig.Emit (OpCodes.Call, TypeManager.object_ctor);
537
538                         int first_arg;
539                         if (enumerable_this_field != null){
540                                 ig.Emit (OpCodes.Ldarg_0);
541                                 ig.Emit (OpCodes.Ldarg_1);
542                                 ig.Emit (OpCodes.Stfld, enumerable_this_field);
543                                 first_arg = 2;
544                         } else
545                                 first_arg = 1;
546                         
547                         for (int i = 0; i < parameters.Count; i++){
548                                 ig.Emit (OpCodes.Ldarg_0);
549                                 ParameterReference.EmitLdArg (ig, i + first_arg);
550                                 ig.Emit (OpCodes.Stfld, enumerable_parameter_fields [i]);
551                         }
552                         ig.Emit (OpCodes.Ret);
553                 }
554
555                 //
556                 // Populates the Enumerator Proxy class
557                 //
558                 void PopulateProxy ()
559                 {
560                         RootContext.RegisterHelperClass (enumerator_proxy_class);
561                         
562                         Create_MoveNext ();
563                         Create_Reset ();
564                         Create_Current ();
565                         Create_Dispose ();
566
567                         if (return_type == TypeManager.ienumerable_type){
568                                 Create_GetEnumerator ();
569                                 RootContext.RegisterHelperClass (enumerable_proxy_class);
570                         }
571                 }
572                 
573
574                 //
575                 // This is invoked by the EmitCode hook
576                 //
577                 void SetupIterator ()
578                 {
579                         PopulateProxy ();
580                 }
581
582                 //
583                 // Our constructor
584                 //
585                 public IteratorHandler (string name, TypeContainer container, Type return_type, Type [] param_types,
586                                         InternalParameters parameters, int modifiers, Location loc)
587                 {
588                         this.name = name;
589                         this.container = container;
590                         this.return_type = return_type;
591                         this.param_types = param_types;
592                         this.parameters = parameters;
593                         this.modifiers = modifiers;
594                         this.loc = loc;
595
596                         IteratorType = TypeManager.object_type;
597                         
598                         RootContext.EmitCodeHook += new RootContext.Hook (SetupIterator);
599                 }
600
601                 //
602                 // This class is just an expression that evaluates to a type, and the
603                 // type is our internal proxy class.  Used in the generated new body
604                 // of the original method
605                 //
606                 class NewInnerType : Expression {
607                         IteratorHandler handler;
608                         
609                         public NewInnerType (IteratorHandler handler, Location l) 
610                         {
611                                 this.handler = handler;
612                                 eclass = ExprClass.Value;
613                                 loc = l;
614                         }
615
616                         public override Expression DoResolve (EmitContext ec)
617                         {
618                                 // Create the proxy class type.
619                                 handler.MakeEnumeratorProxy ();
620
621                                 if (handler.return_type == TypeManager.ienumerable_type)
622                                         handler.MakeEnumerableProxy ();
623
624                                 type = handler.return_type;
625                                 return this;
626                         }
627
628                         public override Expression ResolveAsTypeStep (EmitContext ec)
629                         {
630                                 return DoResolve (ec);
631                         }
632
633                         public override void Emit (EmitContext ec)
634                         {
635                                 handler.LoadArgs (ec.ig);
636                                 
637                                 if (handler.return_type == TypeManager.ienumerable_type)
638                                         ec.ig.Emit (OpCodes.Newobj, (ConstructorInfo) handler.enumerable_proxy_constructor);
639                                 else 
640                                         ec.ig.Emit (OpCodes.Newobj, (ConstructorInfo) handler.enumerator_proxy_constructor);
641                         }
642                 }
643
644                 //
645                 // This return statement tricks return into not flagging an error for being
646                 // used in a Yields method
647                 //
648                 class NoCheckReturn : Return {
649                         public NoCheckReturn (Expression expr, Location loc) : base (expr, loc)
650                         {
651                         }
652                         
653                         public override bool Resolve (EmitContext ec)
654                         {
655                                 ec.InIterator = false;
656                                 bool ret_val = base.Resolve (ec);
657                                 ec.InIterator = true;
658
659                                 return ret_val;
660                         }
661                 }
662                 
663                 //
664                 // Returns the new block for the method, or null on failure
665                 //
666                 public Block Setup (Block block)
667                 {
668                         if (return_type != TypeManager.ienumerator_type &&
669                             return_type != TypeManager.ienumerable_type){
670                                 Report.Error (
671                                         -205, loc, String.Format (
672                                                 "The method `{0}' contains a yield statement, but has an invalid return type for an iterator",
673                                                 name));
674                                 return null;
675                         }
676
677                         for (int i = 0; i < parameters.Count; i++){
678                                 Parameter.Modifier mod = parameters.ParameterModifier (i);
679                                 if ((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) != 0){
680                                         Report.Error (-207, loc, String.Format (
681                                                               "Parameter {0} of `{1}' is {2} and not allowed for an iterator method",
682                                                               i+1, name, parameters.ParameterDesc (i)));
683                                         return null;
684                                 }
685                         }
686
687                         original_block = block;
688                         Block b = new Block (null);
689
690                         // return new InnerClass ()
691                         b.AddStatement (new NoCheckReturn (new NewInnerType (this, loc), loc));
692                         return b;
693                 }
694         }
695 }
696