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