**** Merged r37880 from MCS ****
[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 base 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                 ArrayList finally_blocks;
35                 
36                 public Yield (Expression expr, Location l)
37                 {
38                         this.expr = expr;
39                         loc = l;
40                 }
41
42                 public static bool CheckContext (EmitContext ec, Location loc)
43                 {
44                         if (ec.CurrentBranching.InFinally (true)){
45                                 Report.Error (1625, loc, "Cannot yield in the body of a " +
46                                               "finally clause");
47                                 return false;
48                         }
49                         if (ec.CurrentBranching.InCatch ()){
50                                 Report.Error (1631, loc, "Cannot yield in the body of a " +
51                                               "catch clause");
52                                 return false;
53                         }
54                         if (ec.CurrentAnonymousMethod != null){
55                                 Report.Error (1621, loc, "yield statement can not appear inside an anonymoud method");
56                                 return false;
57                         }
58
59                         //
60                         // FIXME: Missing check for Yield inside try block that contains catch clauses
61                         //
62                         return true;
63                 }
64                 
65                 public override bool Resolve (EmitContext ec)
66                 {
67                         expr = expr.Resolve (ec);
68                         if (expr == null)
69                                 return false;
70                         if (!CheckContext (ec, loc))
71                                 return false;
72
73                         Iterator iterator = ec.CurrentIterator;
74                         if (expr.Type != iterator.IteratorType){
75                                 expr = Convert.ImplicitConversionRequired (
76                                         ec, expr, iterator.IteratorType, loc);
77                                 if (expr == null)
78                                         return false;
79                         }
80
81                         ec.CurrentBranching.StealFinallyClauses (ref finally_blocks);
82                         return true;
83                 }
84
85                 protected override void DoEmit (EmitContext ec)
86                 {
87                         ec.CurrentIterator.MarkYield (ec, expr, finally_blocks);
88                 }
89         }
90
91         public class YieldBreak : Statement {
92
93                 public YieldBreak (Location l)
94                 {
95                         loc = l;
96                 }
97
98                 public override bool Resolve (EmitContext ec)
99                 {
100                         if (!Yield.CheckContext (ec, loc))
101                                 return false;
102
103                         ec.CurrentBranching.CurrentUsageVector.Goto ();
104                         return true;
105                 }
106
107                 protected override void DoEmit (EmitContext ec)
108                 {
109                         ec.CurrentIterator.EmitYieldBreak (ec.ig);
110                 }
111         }
112
113         public class Iterator : Class {
114                 ToplevelBlock original_block;
115                 ToplevelBlock block;
116                 string original_name;
117
118                 Type iterator_type;
119                 TypeExpr iterator_type_expr;
120                 bool is_enumerable;
121                 bool is_static;
122
123                 Hashtable fields;
124
125                 //
126                 // The state as we generate the iterator
127                 //
128                 Label move_next_ok, move_next_error;
129                 ArrayList resume_points = new ArrayList ();
130                 int pc;
131                 
132                 //
133                 // Context from the original method
134                 //
135                 TypeContainer container;
136                 TypeExpr current_type;
137                 Type this_type;
138                 Type return_type;
139                 Type [] param_types;
140                 InternalParameters parameters;
141
142                 MethodInfo dispose_method;
143
144                 Expression enumerator_type;
145                 Expression enumerable_type;
146                 Expression generic_enumerator_type;
147                 Expression generic_enumerable_type;
148                 TypeArguments generic_args;
149
150                 protected enum State {
151                         Uninitialized   = -2,
152                         After,
153                         Running
154                 }
155
156                 static int proxy_count;
157
158                 public void EmitYieldBreak (ILGenerator ig)
159                 {
160                         ig.Emit (OpCodes.Ldarg_0);
161                         IntConstant.EmitInt (ig, (int) State.After);
162                         ig.Emit (OpCodes.Stfld, pc_field.FieldBuilder);
163                         ig.Emit (OpCodes.Br, move_next_error);
164                 }
165
166                 public void EmitMoveNext (EmitContext ec)
167                 {
168                         ILGenerator ig = ec.ig;
169
170                         move_next_ok = ig.DefineLabel ();
171                         move_next_error = ig.DefineLabel ();
172
173                         LocalBuilder retval = ec.GetTemporaryLocal (TypeManager.int32_type);
174
175                         ig.BeginExceptionBlock ();
176
177                         Label dispatcher = ig.DefineLabel ();
178                         ig.Emit (OpCodes.Br, dispatcher);
179
180                         ResumePoint entry_point = new ResumePoint (null);
181                         resume_points.Add (entry_point);
182                         entry_point.Define (ig);
183
184                         ec.EmitTopBlock (original_block, parameters, Location);
185                         EmitYieldBreak (ig);
186
187                         ig.MarkLabel (dispatcher);
188
189                         Label [] labels = new Label [resume_points.Count];
190                         for (int i = 0; i < labels.Length; i++)
191                                 labels [i] = ((ResumePoint) resume_points [i]).Label;
192
193                         ig.Emit (OpCodes.Ldarg_0);
194                         ig.Emit (OpCodes.Ldfld, pc_field.FieldBuilder);
195                         ig.Emit (OpCodes.Switch, labels);
196
197                         Label end = ig.DefineLabel ();
198
199                         ig.MarkLabel (move_next_error);
200                         ig.Emit (OpCodes.Ldc_I4_0); 
201                         ig.Emit (OpCodes.Stloc, retval);
202                         ig.Emit (OpCodes.Leave, end);
203
204                         ig.MarkLabel (move_next_ok);
205                         ig.Emit (OpCodes.Ldc_I4_1);
206                         ig.Emit (OpCodes.Stloc, retval);
207                         ig.Emit (OpCodes.Leave, end);
208
209                         ig.BeginFaultBlock ();
210
211                         ig.Emit (OpCodes.Ldarg_0);
212                         ig.Emit (OpCodes.Callvirt, dispose_method);
213
214                         ig.EndExceptionBlock ();
215
216                         ig.MarkLabel (end);
217                         ig.Emit (OpCodes.Ldloc, retval);
218                         ig.Emit (OpCodes.Ret);
219                 }
220
221                 public void EmitDispose (EmitContext ec)
222                 {
223                         ILGenerator ig = ec.ig;
224
225                         Label end = ig.DefineLabel ();
226                         Label dispatcher = ig.DefineLabel ();
227                         ig.Emit (OpCodes.Br, dispatcher);
228
229                         ec.RemapToProxy = true;
230                         Label [] labels = new Label [resume_points.Count];
231                         for (int i = 0; i < labels.Length; i++) {
232                                 ResumePoint point = (ResumePoint) resume_points [i];
233
234                                 if (point.FinallyBlocks == null) {
235                                         labels [i] = end;
236                                         continue;
237                                 }
238
239                                 labels [i] = ig.DefineLabel ();
240                                 ig.MarkLabel (labels [i]);
241
242                                 ig.BeginExceptionBlock ();
243                                 ig.BeginFinallyBlock ();
244
245                                 foreach (ExceptionStatement stmt in point.FinallyBlocks) {
246                                         if (stmt != null)
247                                                 stmt.EmitFinally (ec);
248                                 }
249
250                                 ig.EndExceptionBlock ();
251                                 ig.Emit (OpCodes.Br, end);
252                         }
253                         ec.RemapToProxy = false;
254
255                         ig.MarkLabel (dispatcher);
256                         ig.Emit (OpCodes.Ldarg_0);
257                         ig.Emit (OpCodes.Ldfld, pc_field.FieldBuilder);
258                         ig.Emit (OpCodes.Switch, labels);
259
260                         ig.Emit (OpCodes.Ldarg_0);
261                         IntConstant.EmitInt (ig, (int) State.After);
262                         ig.Emit (OpCodes.Stfld, pc_field.FieldBuilder);
263
264                         ig.MarkLabel (end);
265                 }
266
267                 protected class ResumePoint
268                 {
269                         public Label Label;
270                         public readonly ExceptionStatement[] FinallyBlocks;
271
272                         public ResumePoint (ArrayList list)
273                         {
274                                 if (list != null) {
275                                         FinallyBlocks = new ExceptionStatement [list.Count];
276                                         list.CopyTo (FinallyBlocks, 0);
277                                 }
278                         }
279
280                         public void Define (ILGenerator ig)
281                         {
282                                 Label = ig.DefineLabel ();
283                                 ig.MarkLabel (Label);
284                         }
285                 }
286
287                 // 
288                 // Invoked when a local variable declaration needs to be mapped to
289                 // a field in our proxy class
290                 //
291                 // Prefixes registered:
292                 //   v_   for EmitContext.MapVariable
293                 //   s_   for Storage
294                 //
295                 public FieldBuilder MapVariable (string pfx, string name, Type t)
296                 {
297                         string full_name = pfx + name;
298                         FieldBuilder fb = (FieldBuilder) fields [full_name];
299                         if (fb != null)
300                                 return fb;
301
302                         fb = TypeBuilder.DefineField (full_name, t, FieldAttributes.Private);
303                         fields.Add (full_name, fb);
304                         return fb;
305                 }
306
307                 //
308                 // Called back from Yield
309                 //
310                 public void MarkYield (EmitContext ec, Expression expr,
311                                        ArrayList finally_blocks)
312                 {
313                         ILGenerator ig = ec.ig;
314
315                         // Store the new current
316                         ig.Emit (OpCodes.Ldarg_0);
317                         expr.Emit (ec);
318                         ig.Emit (OpCodes.Stfld, current_field.FieldBuilder);
319
320                         // increment pc
321                         pc++;
322                         ig.Emit (OpCodes.Ldarg_0);
323                         IntConstant.EmitInt (ig, pc);
324                         ig.Emit (OpCodes.Stfld, pc_field.FieldBuilder);
325
326                         // Return ok
327                         ig.Emit (OpCodes.Br, move_next_ok);
328
329                         ResumePoint point = new ResumePoint (finally_blocks);
330                         resume_points.Add (point);
331                         point.Define (ig);
332                 }
333
334                 public void MarkFinally (EmitContext ec, ArrayList finally_blocks)
335                 {
336                         ILGenerator ig = ec.ig;
337
338                         // increment pc
339                         pc++;
340                         ig.Emit (OpCodes.Ldarg_0);
341                         IntConstant.EmitInt (ig, pc);
342                         ig.Emit (OpCodes.Stfld, pc_field.FieldBuilder);
343
344                         ResumePoint point = new ResumePoint (finally_blocks);
345                         resume_points.Add (point);
346                         point.Define (ig);
347                 }
348
349                 private static MemberName MakeProxyName (string name)
350                 {
351                         int pos = name.LastIndexOf ('.');
352                         if (pos > 0)
353                                 name = name.Substring (pos + 1);
354
355                         return new MemberName ("<" + name + ">__" + (proxy_count++));
356                 }
357
358                 //
359                 // Our constructor
360                 //
361                 public Iterator (TypeContainer container, string name, Type return_type,
362                                  Type [] param_types, InternalParameters parameters,
363                                  int modifiers, ToplevelBlock block, Location loc)
364                         : base (container.NamespaceEntry, container, MakeProxyName (name),
365                                 Modifiers.PRIVATE, null, loc)
366                 {
367                         this.container = container;
368                         this.return_type = return_type;
369                         this.param_types = param_types;
370                         this.parameters = parameters;
371                         this.original_name = name;
372                         this.original_block = block;
373                         this.block = new ToplevelBlock (loc);
374
375                         fields = new Hashtable ();
376
377                         is_static = (modifiers & Modifiers.STATIC) != 0;
378                 }
379
380                 public bool DefineIterator ()
381                 {
382                         ec = new EmitContext (this, Mono.CSharp.Location.Null, null, null, ModFlags);
383
384                         if (!CheckType (return_type)) {
385                                 Report.Error (
386                                         1624, Location,
387                                         "The body of `{0}' cannot be an iterator block " +
388                                         "because '{1}' is not an iterator interface type",
389                                         original_name, TypeManager.CSharpName (return_type));
390                                 return false;
391                         }
392
393                         for (int i = 0; i < parameters.Count; i++){
394                                 Parameter.Modifier mod = parameters.ParameterModifier (i);
395                                 if ((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) != 0){
396                                         Report.Error (
397                                                 1623, Location,
398                                                 "Iterators cannot have ref or out parameters");
399                                         return false;
400                                 }
401                         }
402
403                         if (container.CurrentType != null)
404                                 this_type = container.CurrentType;
405                         else
406                                 this_type = container.TypeBuilder;
407
408                         generic_args = new TypeArguments (Location);
409                         generic_args.Add (new TypeExpression (iterator_type, Location));
410
411                         ArrayList list = new ArrayList ();
412                         if (is_enumerable) {
413                                 enumerable_type = new TypeExpression (
414                                         TypeManager.ienumerable_type, Location);
415                                 list.Add (enumerable_type);
416
417                                 generic_enumerable_type = new ConstructedType (
418                                         TypeManager.generic_ienumerable_type,
419                                         generic_args, Location);
420                                 list.Add (generic_enumerable_type);
421                         }
422
423                         enumerator_type = new TypeExpression (
424                                 TypeManager.ienumerator_type, Location);
425                         list.Add (enumerator_type);
426
427                         list.Add (new TypeExpression (TypeManager.idisposable_type, Location));
428
429                         generic_enumerator_type = new ConstructedType (
430                                 TypeManager.generic_ienumerator_type,
431                                 generic_args, Location);
432                         list.Add (generic_enumerator_type);
433
434                         iterator_type_expr = new TypeExpression (iterator_type, Location);
435
436                         container.AddIterator (this);
437
438                         Bases = list;
439                         return true;
440                 }
441
442                 MethodInfo FetchMethodDispose ()
443                 {
444                         MemberList dispose_list;
445
446                         dispose_list = FindMembers (
447                                 current_type.Type,
448                                 MemberTypes.Method, BindingFlags.Public | BindingFlags.Instance,
449                                 Type.FilterName, "Dispose");
450
451                         if (dispose_list.Count != 1)
452                                 throw new InternalErrorException ("Cannot find Dipose() method.");
453
454                         return (MethodInfo) dispose_list [0];
455                 }
456
457                 protected override bool DoDefineMembers ()
458                 {
459                         if (!base.DoDefineMembers ())
460                                 return false;
461
462                         dispose_method = FetchMethodDispose ();
463                         if (dispose_method == null)
464                                 return false;
465
466                         return true;
467                 }
468
469                 //
470                 // Returns the new block for the method, or null on failure
471                 //
472                 protected override bool DefineNestedTypes ()
473                 {
474                         if (CurrentType != null)
475                                 current_type = new TypeExpression (CurrentType, Location);
476                         else
477                                 current_type = new TypeExpression (TypeBuilder, Location);
478
479                         Define_Fields ();
480                         Define_Constructor ();
481                         Define_Current (false);
482                         Define_Current (true);
483                         Define_MoveNext ();
484                         Define_Reset ();
485                         Define_Dispose ();
486
487                         if (is_enumerable) {
488                                 Define_GetEnumerator (false);
489                                 Define_GetEnumerator (true);
490                         }
491
492                         Create_Block ();
493
494                         return base.DefineNestedTypes ();
495                 }
496
497
498                 Field pc_field;
499                 Field current_field;
500                 Method dispose;
501
502                 public Field this_field;
503                 public Field[] parameter_fields;
504
505                 void Create_Block ()
506                 {
507                         int first = is_static ? 0 : 1;
508
509                         ArrayList args = new ArrayList ();
510                         if (!is_static) {
511                                 Type t = this_type;
512                                 args.Add (new Argument (
513                                         new ThisParameterReference (t, 0, Location)));
514                         }
515
516                         args.Add (new Argument (new BoolLiteral (false)));
517
518                         for (int i = 0; i < parameters.Count; i++) {
519                                 Type t = parameters.ParameterType (i);
520                                 args.Add (new Argument (
521                                         new SimpleParameterReference (t, first + i, Location)));
522                         }
523
524                         Expression new_expr = new New (current_type, args, Location);
525
526                         block.AddStatement (new NoCheckReturn (new_expr, Location));
527                 }
528
529                 void Define_Fields ()
530                 {
531                         Location loc = Location.Null;
532
533                         pc_field = new Field (
534                                 this, TypeManager.system_int32_expr, Modifiers.PRIVATE, "PC",
535                                 null, null, loc);
536                         AddField (pc_field);
537
538                         current_field = new Field (
539                                 this, iterator_type_expr, Modifiers.PRIVATE, "current",
540                                 null, null, loc);
541                         AddField (current_field);
542
543                         if (!is_static) {
544                                 this_field = new Field (
545                                         this, new TypeExpression (this_type, loc),
546                                         Modifiers.PRIVATE, "this", null, null, loc);
547                                 AddField (this_field);
548                         }
549
550                         parameter_fields = new Field [parameters.Count];
551                         for (int i = 0; i < parameters.Count; i++) {
552                                 string fname = String.Format (
553                                         "field{0}_{1}", i, parameters.ParameterName (i));
554
555                                 parameter_fields [i] = new Field (
556                                         this,
557                                         new TypeExpression (parameters.ParameterType (i), loc),
558                                         Modifiers.PRIVATE, fname, null, null, loc);
559                                 AddField (parameter_fields [i]);
560                         }
561                 }
562
563                 void Define_Constructor ()
564                 {
565                         Parameters ctor_params;
566
567                         ArrayList list = new ArrayList ();
568
569                         if (!is_static)
570                                 list.Add (new Parameter (
571                                         new TypeExpression (this_type, Location),
572                                         "this", Parameter.Modifier.NONE, null));
573                         list.Add (new Parameter (
574                                 TypeManager.system_boolean_expr, "initialized",
575                                 Parameter.Modifier.NONE, null));
576
577                         Parameter[] old_fixed = parameters.Parameters.FixedParameters;
578                         if (old_fixed != null)
579                                 list.AddRange (old_fixed);
580
581                         Parameter[] fixed_params = new Parameter [list.Count];
582                         list.CopyTo (fixed_params);
583
584                         ctor_params = new Parameters (
585                                 fixed_params, parameters.Parameters.ArrayParameter,
586                                 Location);
587
588                         Constructor ctor = new Constructor (
589                                 this, Name, Modifiers.PUBLIC, ctor_params,
590                                 new ConstructorBaseInitializer (
591                                         null, Parameters.EmptyReadOnlyParameters, Location),
592                                 Location);
593                         AddConstructor (ctor);
594
595                         ToplevelBlock block = ctor.Block = new ToplevelBlock (Location);
596
597                         if (!is_static) {
598                                 Type t = this_type;
599
600                                 Assign assign = new Assign (
601                                         new FieldExpression (this_field),
602                                         new SimpleParameterReference (t, 1, Location),
603                                         Location);
604
605                                 block.AddStatement (new StatementExpression (assign, Location));
606                         }
607
608                         int first = is_static ? 2 : 3;
609
610                         for (int i = 0; i < parameters.Count; i++) {
611                                 Type t = parameters.ParameterType (i);
612
613                                 Assign assign = new Assign (
614                                         new FieldExpression (parameter_fields [i]),
615                                         new SimpleParameterReference (t, first + i, Location),
616                                         Location);
617
618                                 block.AddStatement (new StatementExpression (assign, Location));
619                         }
620
621                         State initial = is_enumerable ? State.Uninitialized : State.Running;
622                         block.AddStatement (new SetState (this, initial, Location));
623
624                         block.AddStatement (new If (
625                                 new SimpleParameterReference (
626                                         TypeManager.bool_type, first - 1, Location),
627                                 new SetState (this, State.Running, Location),
628                                 Location));
629                 }
630
631                 Statement Create_ThrowInvalidOperation ()
632                 {
633                         TypeExpr ex_type = new TypeExpression (
634                                 TypeManager.invalid_operation_exception_type, Location);
635
636                         return new Throw (new New (ex_type, null, Location), Location);
637                 }
638
639                 Statement Create_ThrowNotSupported ()
640                 {
641                         TypeExpr ex_type = new TypeExpression (
642                                 TypeManager.not_supported_exception_type, Location);
643
644                         return new Throw (new New (ex_type, null, Location), Location);
645                 }
646
647                 void Define_Current (bool is_generic)
648                 {
649                         MemberName left;
650                         Expression type;
651                         if (is_generic) {
652                                 left = new MemberName (
653                                         "System.Collections.Generic.IEnumerator",
654                                         generic_args);
655                                 type = iterator_type_expr;
656                         } else {
657                                 left = new MemberName ("System.Collections.IEnumerator");
658                                 type = TypeManager.system_object_expr;
659                         }
660
661                         MemberName name = new MemberName (left, "Current", null);
662
663                         ToplevelBlock get_block = new ToplevelBlock (Location);
664
665                         get_block.AddStatement (new If (
666                                 new Binary (
667                                         Binary.Operator.LessThanOrEqual,
668                                         new FieldExpression (pc_field),
669                                         new IntLiteral ((int) State.Running), Location),
670                                 Create_ThrowInvalidOperation (),
671                                 new Return (
672                                         new FieldExpression (current_field), Location),
673                                 Location));
674
675                         Accessor getter = new Accessor (get_block, 0, null, Location);
676
677                         Property current = new Property (
678                                 this, type, 0, false, name, null, getter, null, Location);
679                         AddProperty (current);
680                 }
681
682                 void Define_MoveNext ()
683                 {
684                         Method move_next = new Method (
685                                 this, null, TypeManager.system_boolean_expr,
686                                 Modifiers.PUBLIC, false, new MemberName ("MoveNext"),
687                                 Parameters.EmptyReadOnlyParameters, null,
688                                 Location.Null);
689                         AddMethod (move_next);
690
691                         ToplevelBlock block = move_next.Block = new ToplevelBlock (Location);
692
693                         MoveNextMethod inline = new MoveNextMethod (this, Location);
694                         block.AddStatement (inline);
695                 }
696
697                 void Define_GetEnumerator (bool is_generic)
698                 {
699                         MemberName left;
700                         Expression type;
701                         if (is_generic) {
702                                 left = new MemberName (
703                                         "System.Collections.Generic.IEnumerable",
704                                         generic_args);
705                                 type = generic_enumerator_type;
706                         } else {
707                                 left = new MemberName ("System.Collections.IEnumerable");
708                                 type = enumerator_type;
709                         }
710
711                         MemberName name = new MemberName (left, "GetEnumerator", null);
712
713                         Method get_enumerator = new Method (
714                                 this, null, type, 0, false, name,
715                                 Parameters.EmptyReadOnlyParameters, null,
716                                 Location.Null);
717                         AddMethod (get_enumerator);
718
719                         get_enumerator.Block = new ToplevelBlock (Location);
720
721                         Expression ce = new MemberAccess (
722                                 new SimpleName ("System.Threading.Interlocked", Location),
723                                 "CompareExchange", Location);
724
725                         Expression pc = new FieldExpression (pc_field);
726                         Expression before = new IntLiteral ((int) State.Running);
727                         Expression uninitialized = new IntLiteral ((int) State.Uninitialized);
728
729                         ArrayList args = new ArrayList ();
730                         args.Add (new Argument (pc, Argument.AType.Ref));
731                         args.Add (new Argument (before, Argument.AType.Expression));
732                         args.Add (new Argument (uninitialized, Argument.AType.Expression));
733
734                         get_enumerator.Block.AddStatement (new If (
735                                 new Binary (
736                                         Binary.Operator.Equality,
737                                         new Invocation (ce, args, Location),
738                                         uninitialized, Location),
739                                 new Return (new This (block, Location), Location),
740                                 Location));
741
742                         args = new ArrayList ();
743                         if (!is_static)
744                                 args.Add (new Argument (new FieldExpression (this_field)));
745
746                         args.Add (new Argument (new BoolLiteral (true)));
747
748                         for (int i = 0; i < parameters.Count; i++)
749                                 args.Add (new Argument (
750                                                   new FieldExpression (parameter_fields [i])));
751
752                         Expression new_expr = new New (current_type, args, Location);
753                         get_enumerator.Block.AddStatement (new Return (new_expr, Location));
754                 }
755
756                 protected class SimpleParameterReference : Expression
757                 {
758                         int idx;
759
760                         public SimpleParameterReference (Type type, int idx, Location loc)
761                         {
762                                 this.idx = idx;
763                                 this.loc = loc;
764                                 this.type = type;
765                                 eclass = ExprClass.Variable;
766                         }
767
768                         public override Expression DoResolve (EmitContext ec)
769                         {
770                                 return this;
771                         }
772
773                         public override void Emit (EmitContext ec)
774                         {
775                                 DoEmit (ec);
776                         }
777
778                         protected virtual void DoEmit (EmitContext ec)
779                         {
780                                 ParameterReference.EmitLdArg (ec.ig, idx);
781                         }
782                 }
783
784                 protected class ThisParameterReference : SimpleParameterReference
785                 {
786                         public ThisParameterReference (Type type, int idx, Location loc)
787                                 : base (type, idx, loc)
788                         { }
789
790                         protected override void DoEmit (EmitContext ec)
791                         {
792                                 base.DoEmit (ec);
793                                 if (ec.TypeContainer is Struct)
794                                         ec.ig.Emit (OpCodes.Ldobj, type);
795                         }
796                 }
797
798                 protected class FieldExpression : Expression
799                 {
800                         Field field;
801
802                         public FieldExpression (Field field)
803                         {
804                                 this.field = field;
805                         }
806
807                         public override Expression DoResolve (EmitContext ec)
808                         {
809                                 FieldExpr fexpr = new FieldExpr (field.FieldBuilder, loc);
810                                 fexpr.InstanceExpression = ec.GetThis (loc);
811                                 return fexpr.Resolve (ec);
812                         }
813
814                         public override void Emit (EmitContext ec)
815                         {
816                                 throw new InvalidOperationException ();
817                         }
818                 }
819
820                 protected class MoveNextMethod : Statement {
821                         Iterator iterator;
822
823                         public MoveNextMethod (Iterator iterator, Location loc)
824                         {
825                                 this.loc = loc;
826                                 this.iterator = iterator;
827                         }
828
829                         public override bool Resolve (EmitContext ec)
830                         {
831                                 ec.CurrentBranching.CurrentUsageVector.Return ();
832                                 return true;
833                         }
834
835                         protected override void DoEmit (EmitContext ec)
836                         {
837                                 int code_flags = Modifiers.METHOD_YIELDS;
838                                 if (iterator.is_static)
839                                         code_flags |= Modifiers.STATIC;
840
841                                 EmitContext new_ec = new EmitContext (
842                                         iterator.container, loc, ec.ig,
843                                         TypeManager.int32_type, code_flags);
844
845                                 new_ec.CurrentIterator = iterator;
846
847                                 iterator.EmitMoveNext (new_ec);
848                         }
849                 }
850
851                 protected class DisposeMethod : Statement {
852                         Iterator iterator;
853
854                         public DisposeMethod (Iterator iterator, Location loc)
855                         {
856                                 this.loc = loc;
857                                 this.iterator = iterator;
858                         }
859
860                         public override bool Resolve (EmitContext ec)
861                         {
862                                 return true;
863                         }
864
865                         protected override void DoEmit (EmitContext ec)
866                         {
867                                 iterator.EmitDispose (ec);
868                         }
869                 }
870
871                 protected class StatementList : Statement {
872                         ArrayList statements;
873
874                         public StatementList (Location loc)
875                         {
876                                 this.loc = loc;
877                                 statements = new ArrayList ();
878                         }
879
880                         public void Add (Statement statement)
881                         {
882                                 statements.Add (statement);
883                         }
884
885                         public override bool Resolve (EmitContext ec)
886                         {
887                                 foreach (Statement stmt in statements) {
888                                         if (!stmt.Resolve (ec))
889                                                 return false;
890                                 }
891
892                                 return true;
893                         }
894
895                         protected override void DoEmit (EmitContext ec)
896                         {
897                                 foreach (Statement stmt in statements)
898                                         stmt.Emit (ec);
899                         }
900                 }
901
902                 protected class SetState : Statement
903                 {
904                         Iterator iterator;
905                         State state;
906
907                         public SetState (Iterator iterator, State state, Location loc)
908                         {
909                                 this.iterator = iterator;
910                                 this.state = state;
911                                 this.loc = loc;
912                         }
913
914                         public override bool Resolve (EmitContext ec)
915                         {
916                                 return true;
917                         }
918
919                         protected override void DoEmit (EmitContext ec)
920                         {
921                                 ec.ig.Emit (OpCodes.Ldarg_0);
922                                 IntConstant.EmitInt (ec.ig, (int) state);
923                                 ec.ig.Emit (OpCodes.Stfld, iterator.pc_field.FieldBuilder);
924                         }
925                 }
926
927                 void Define_Reset ()
928                 {
929                         Method reset = new Method (
930                                 this, null, TypeManager.system_void_expr, Modifiers.PUBLIC,
931                                 false, new MemberName ("Reset"),
932                                 Parameters.EmptyReadOnlyParameters, null, Location);
933                         AddMethod (reset);
934
935                         reset.Block = new ToplevelBlock (Location);
936                         reset.Block.AddStatement (Create_ThrowNotSupported ());
937                 }
938
939                 void Define_Dispose ()
940                 {
941                         dispose = new Method (
942                                 this, null, TypeManager.system_void_expr, Modifiers.PUBLIC,
943                                 false, new MemberName ("Dispose"),
944                                 Parameters.EmptyReadOnlyParameters, null, Location);
945                         AddMethod (dispose);
946
947                         dispose.Block = new ToplevelBlock (Location);
948                         dispose.Block.AddStatement (new DisposeMethod (this, Location));
949                 }
950
951                 public ToplevelBlock Block {
952                         get { return block; }
953                 }
954
955                 public Type IteratorType {
956                         get { return iterator_type; }
957                 }
958
959                 //
960                 // This return statement tricks return into not flagging an error for being
961                 // used in a Yields method
962                 //
963                 class NoCheckReturn : Return {
964                         public NoCheckReturn (Expression expr, Location loc) : base (expr, loc)
965                         {
966                         }
967
968                         public override bool Resolve (EmitContext ec)
969                         {
970                                 ec.InIterator = false;
971                                 bool ret_val = base.Resolve (ec);
972                                 ec.InIterator = true;
973
974                                 return ret_val;
975                         }
976                 }
977
978                 bool CheckType (Type t)
979                 {
980                         if (t == TypeManager.ienumerable_type) {
981                                 iterator_type = TypeManager.object_type;
982                                 is_enumerable = true;
983                                 return true;
984                         } else if (t == TypeManager.ienumerator_type) {
985                                 iterator_type = TypeManager.object_type;
986                                 is_enumerable = false;
987                                 return true;
988                         }
989
990                         if (!t.IsGenericInstance)
991                                 return false;
992
993                         Type[] args = TypeManager.GetTypeArguments (t);
994                         if (args.Length != 1)
995                                 return false;
996
997                         Type gt = t.GetGenericTypeDefinition ();
998                         if (gt == TypeManager.generic_ienumerable_type) {
999                                 iterator_type = args [0];
1000                                 is_enumerable = true;
1001                                 return true;
1002                         } else if (gt == TypeManager.generic_ienumerator_type) {
1003                                 iterator_type = args [0];
1004                                 is_enumerable = false;
1005                                 return true;
1006                         }
1007
1008                         return false;
1009                 }
1010         }
1011 }
1012