**** Merged r41364 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 DoResolveLValue (EmitContext ec, Expression right_side)
808                         {
809                                 return DoResolve (ec);
810                         }
811
812                         public override Expression DoResolve (EmitContext ec)
813                         {
814                                 FieldExpr fexpr = new FieldExpr (field.FieldBuilder, loc);
815                                 fexpr.InstanceExpression = ec.GetThis (loc);
816                                 return fexpr.Resolve (ec);
817                         }
818
819                         public override void Emit (EmitContext ec)
820                         {
821                                 throw new InvalidOperationException ();
822                         }
823                 }
824
825                 protected class MoveNextMethod : Statement {
826                         Iterator iterator;
827
828                         public MoveNextMethod (Iterator iterator, Location loc)
829                         {
830                                 this.loc = loc;
831                                 this.iterator = iterator;
832                         }
833
834                         public override bool Resolve (EmitContext ec)
835                         {
836                                 ec.CurrentBranching.CurrentUsageVector.Return ();
837                                 return true;
838                         }
839
840                         protected override void DoEmit (EmitContext ec)
841                         {
842                                 int code_flags = Modifiers.METHOD_YIELDS;
843                                 if (iterator.is_static)
844                                         code_flags |= Modifiers.STATIC;
845
846                                 EmitContext new_ec = new EmitContext (
847                                         iterator.container, loc, ec.ig,
848                                         TypeManager.int32_type, code_flags);
849
850                                 new_ec.CurrentIterator = iterator;
851
852                                 iterator.EmitMoveNext (new_ec);
853                         }
854                 }
855
856                 protected class DisposeMethod : Statement {
857                         Iterator iterator;
858
859                         public DisposeMethod (Iterator iterator, Location loc)
860                         {
861                                 this.loc = loc;
862                                 this.iterator = iterator;
863                         }
864
865                         public override bool Resolve (EmitContext ec)
866                         {
867                                 return true;
868                         }
869
870                         protected override void DoEmit (EmitContext ec)
871                         {
872                                 iterator.EmitDispose (ec);
873                         }
874                 }
875
876                 protected class StatementList : Statement {
877                         ArrayList statements;
878
879                         public StatementList (Location loc)
880                         {
881                                 this.loc = loc;
882                                 statements = new ArrayList ();
883                         }
884
885                         public void Add (Statement statement)
886                         {
887                                 statements.Add (statement);
888                         }
889
890                         public override bool Resolve (EmitContext ec)
891                         {
892                                 foreach (Statement stmt in statements) {
893                                         if (!stmt.Resolve (ec))
894                                                 return false;
895                                 }
896
897                                 return true;
898                         }
899
900                         protected override void DoEmit (EmitContext ec)
901                         {
902                                 foreach (Statement stmt in statements)
903                                         stmt.Emit (ec);
904                         }
905                 }
906
907                 protected class SetState : Statement
908                 {
909                         Iterator iterator;
910                         State state;
911
912                         public SetState (Iterator iterator, State state, Location loc)
913                         {
914                                 this.iterator = iterator;
915                                 this.state = state;
916                                 this.loc = loc;
917                         }
918
919                         public override bool Resolve (EmitContext ec)
920                         {
921                                 return true;
922                         }
923
924                         protected override void DoEmit (EmitContext ec)
925                         {
926                                 ec.ig.Emit (OpCodes.Ldarg_0);
927                                 IntConstant.EmitInt (ec.ig, (int) state);
928                                 ec.ig.Emit (OpCodes.Stfld, iterator.pc_field.FieldBuilder);
929                         }
930                 }
931
932                 void Define_Reset ()
933                 {
934                         Method reset = new Method (
935                                 this, null, TypeManager.system_void_expr, Modifiers.PUBLIC,
936                                 false, new MemberName ("Reset"),
937                                 Parameters.EmptyReadOnlyParameters, null, Location);
938                         AddMethod (reset);
939
940                         reset.Block = new ToplevelBlock (Location);
941                         reset.Block.AddStatement (Create_ThrowNotSupported ());
942                 }
943
944                 void Define_Dispose ()
945                 {
946                         dispose = new Method (
947                                 this, null, TypeManager.system_void_expr, Modifiers.PUBLIC,
948                                 false, new MemberName ("Dispose"),
949                                 Parameters.EmptyReadOnlyParameters, null, Location);
950                         AddMethod (dispose);
951
952                         dispose.Block = new ToplevelBlock (Location);
953                         dispose.Block.AddStatement (new DisposeMethod (this, Location));
954                 }
955
956                 public ToplevelBlock Block {
957                         get { return block; }
958                 }
959
960                 public Type IteratorType {
961                         get { return iterator_type; }
962                 }
963
964                 //
965                 // This return statement tricks return into not flagging an error for being
966                 // used in a Yields method
967                 //
968                 class NoCheckReturn : Return {
969                         public NoCheckReturn (Expression expr, Location loc) : base (expr, loc)
970                         {
971                         }
972
973                         public override bool Resolve (EmitContext ec)
974                         {
975                                 ec.InIterator = false;
976                                 bool ret_val = base.Resolve (ec);
977                                 ec.InIterator = true;
978
979                                 return ret_val;
980                         }
981                 }
982
983                 bool CheckType (Type t)
984                 {
985                         if (t == TypeManager.ienumerable_type) {
986                                 iterator_type = TypeManager.object_type;
987                                 is_enumerable = true;
988                                 return true;
989                         } else if (t == TypeManager.ienumerator_type) {
990                                 iterator_type = TypeManager.object_type;
991                                 is_enumerable = false;
992                                 return true;
993                         }
994
995                         if (!t.IsGenericInstance)
996                                 return false;
997
998                         Type[] args = TypeManager.GetTypeArguments (t);
999                         if (args.Length != 1)
1000                                 return false;
1001
1002                         Type gt = t.GetGenericTypeDefinition ();
1003                         if (gt == TypeManager.generic_ienumerable_type) {
1004                                 iterator_type = args [0];
1005                                 is_enumerable = true;
1006                                 return true;
1007                         } else if (gt == TypeManager.generic_ienumerator_type) {
1008                                 iterator_type = args [0];
1009                                 is_enumerable = false;
1010                                 return true;
1011                         }
1012
1013                         return false;
1014                 }
1015         }
1016 }
1017