2007-04-19 Chris Toshok <toshok@ximian.com>
[mcs.git] / mcs / iterators.cs
blobc3ccc1d61b108b37956965856b2c497893c8ef8e
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.
13 // Generics note:
14 // Current should be defined to return T, and IEnumerator.Current returns object
17 using System;
18 using System.Collections;
19 using System.Reflection;
20 using System.Reflection.Emit;
22 namespace Mono.CSharp {
24 public class Yield : Statement {
25 Expression expr;
26 ArrayList finally_blocks;
28 public Yield (Expression expr, Location l)
30 this.expr = expr;
31 loc = l;
34 public static bool CheckContext (EmitContext ec, Location loc, bool isYieldBreak)
36 if (ec.InFinally) {
37 Report.Error (1625, loc, "Cannot yield in the body of a " +
38 "finally clause");
39 return false;
42 for (Block block = ec.CurrentBlock; block != null; block = block.Parent) {
43 if (!block.Unsafe)
44 continue;
46 Report.Error (1629, loc, "Unsafe code may not appear in iterators");
47 return false;
51 // We can't use `ec.InUnsafe' here because it's allowed to have an iterator
52 // inside an unsafe class. See test-martin-29.cs for an example.
54 if (!ec.CurrentAnonymousMethod.IsIterator) {
55 Report.Error (1621, loc,
56 "The yield statement cannot be used inside " +
57 "anonymous method blocks");
58 return false;
61 if (ec.CurrentBranching.InTryWithCatch () && (!isYieldBreak || !ec.InCatch)) {
62 if (!ec.InCatch)
63 Report.Error (1626, loc, "Cannot yield a value in the body " +
64 "of a try block with a catch clause");
65 else
66 Report.Error (1631, loc, "Cannot yield a value in the body " +
67 "of a catch clause");
68 return false;
71 return true;
74 public override bool Resolve (EmitContext ec)
76 Report.Debug (64, "RESOLVE YIELD", this, ec, expr, expr.GetType ());
77 expr = expr.Resolve (ec);
78 if (expr == null)
79 return false;
81 Report.Debug (64, "RESOLVE YIELD #1", this, ec, expr, expr.GetType (),
82 ec.CurrentAnonymousMethod, ec.CurrentIterator);
84 if (!CheckContext (ec, loc, false))
85 return false;
87 Iterator iterator = ec.CurrentIterator;
88 if (expr.Type != iterator.IteratorType) {
89 expr = Convert.ImplicitConversionRequired (
90 ec, expr, iterator.IteratorType, loc);
91 if (expr == null)
92 return false;
95 ec.CurrentBranching.StealFinallyClauses (ref finally_blocks);
96 return true;
99 protected override void DoEmit (EmitContext ec)
101 ec.CurrentIterator.MarkYield (ec, expr, finally_blocks);
104 protected override void CloneTo (CloneContext clonectx, Statement t)
106 Yield target = (Yield) t;
108 target.expr = expr.Clone (clonectx);
112 public class YieldBreak : Statement {
114 public YieldBreak (Location l)
116 loc = l;
119 public override bool Resolve (EmitContext ec)
121 if (!Yield.CheckContext (ec, loc, true))
122 return false;
124 ec.CurrentBranching.CurrentUsageVector.Goto ();
125 return true;
128 protected override void DoEmit (EmitContext ec)
130 ec.CurrentIterator.EmitYieldBreak (ec.ig);
134 public class IteratorHost : RootScopeInfo
136 public readonly Iterator Iterator;
138 TypeExpr iterator_type_expr;
139 Field pc_field;
140 Field current_field;
141 MethodInfo dispose_method;
143 TypeExpr enumerator_type;
144 TypeExpr enumerable_type;
145 TypeArguments generic_args;
146 TypeExpr generic_enumerator_type;
147 TypeExpr generic_enumerable_type;
149 public IteratorHost (Iterator iterator)
150 : base (iterator.Container.Toplevel, iterator.Host, iterator.GenericMethod,
151 iterator.Location)
153 this.Iterator = iterator;
156 public override bool IsIterator {
157 get { return true; }
160 public MethodInfo Dispose {
161 get { return dispose_method; }
164 public Field PC {
165 get { return pc_field; }
168 public Field CurrentField {
169 get { return current_field; }
172 public Type IteratorType {
173 get { return iterator_type_expr.Type; }
176 public override TypeExpr [] GetClassBases (out TypeExpr base_class)
178 iterator_type_expr = InflateType (Iterator.OriginalIteratorType);
180 #if GMCS_SOURCE
181 generic_args = new TypeArguments (Location);
182 generic_args.Add (iterator_type_expr);
183 #endif
185 ArrayList list = new ArrayList ();
186 if (Iterator.IsEnumerable) {
187 enumerable_type = new TypeExpression (
188 TypeManager.ienumerable_type, Location);
189 list.Add (enumerable_type);
191 #if GMCS_SOURCE
192 generic_enumerable_type = new ConstructedType (
193 TypeManager.generic_ienumerable_type,
194 generic_args, Location);
195 list.Add (generic_enumerable_type);
196 #endif
199 enumerator_type = new TypeExpression (
200 TypeManager.ienumerator_type, Location);
201 list.Add (enumerator_type);
203 list.Add (new TypeExpression (TypeManager.idisposable_type, Location));
205 #if GMCS_SOURCE
206 generic_enumerator_type = new ConstructedType (
207 TypeManager.generic_ienumerator_type,
208 generic_args, Location);
209 list.Add (generic_enumerator_type);
210 #endif
212 Bases = list;
214 return base.GetClassBases (out base_class);
217 protected override bool DoResolveMembers ()
219 pc_field = CaptureVariable ("$PC", TypeManager.system_int32_expr);
220 current_field = CaptureVariable ("$current", iterator_type_expr);
222 #if GMCS_SOURCE
223 Define_Current (true);
224 #endif
225 Define_Current (false);
226 new DisposeMethod (this);
227 Define_Reset ();
229 if (Iterator.IsEnumerable) {
230 new GetEnumeratorMethod (this, false);
231 #if GMCS_SOURCE
232 new GetEnumeratorMethod (this, true);
233 #endif
236 return base.DoResolveMembers ();
239 public void CaptureScopes ()
241 Report.Debug (128, "DEFINE ITERATOR HOST", this, scopes);
243 foreach (ScopeInfo si in scopes)
244 CaptureScope (si);
246 foreach (ScopeInfo si in scopes) {
247 if (!si.Define ())
248 throw new InternalErrorException ();
249 if (si.DefineType () == null)
250 throw new InternalErrorException ();
251 if (!si.ResolveType ())
252 throw new InternalErrorException ();
253 if (!si.ResolveMembers ())
254 throw new InternalErrorException ();
255 if (!si.DefineMembers ())
256 throw new InternalErrorException ();
260 protected override bool DoDefineMembers ()
262 if (!base.DoDefineMembers ())
263 return false;
265 FetchMethodDispose ();
267 return true;
270 protected override void EmitScopeConstructor (EmitContext ec)
272 ec.ig.Emit (OpCodes.Ldarg_0);
273 ec.ig.Emit (OpCodes.Ldarg_1);
274 ec.ig.Emit (OpCodes.Stfld, pc_field.FieldBuilder);
275 base.EmitScopeConstructor (ec);
278 void FetchMethodDispose ()
280 MemberList dispose_list;
282 dispose_list = FindMembers (
283 CurrentType != null ? CurrentType : TypeBuilder,
284 MemberTypes.Method, BindingFlags.Public | BindingFlags.Instance,
285 Type.FilterName, "Dispose");
287 if (dispose_list.Count != 1)
288 throw new InternalErrorException ("Cannot find Dipose() method.");
290 dispose_method = (MethodInfo) dispose_list [0];
293 void Define_Current (bool is_generic)
295 MemberName left;
296 Expression type;
298 if (is_generic) {
299 left = new MemberName (
300 "System.Collections.Generic.IEnumerator",
301 generic_args, Location);
302 type = iterator_type_expr;
303 } else {
304 left = new MemberName ("System.Collections.IEnumerator", Location);
305 type = TypeManager.system_object_expr;
308 MemberName name = new MemberName (left, "Current", null, Location);
310 ToplevelBlock get_block = new ToplevelBlock (Location);
311 get_block.AddStatement (new CurrentBlock (this, is_generic));
313 Accessor getter = new Accessor (get_block, 0, null, Location);
315 Property current = new Property (
316 this, type, 0, false, name, null, getter, null, false);
317 AddProperty (current);
320 void Define_Reset ()
322 Method reset = new Method (
323 this, null, TypeManager.system_void_expr, Modifiers.PUBLIC,
324 false, new MemberName ("Reset", Location),
325 Parameters.EmptyReadOnlyParameters, null);
326 AddMethod (reset);
328 reset.Block = new ToplevelBlock (Location);
329 reset.Block.AddStatement (Create_ThrowNotSupported ());
332 Statement Create_ThrowNotSupported ()
334 TypeExpr ex_type = new TypeExpression (
335 TypeManager.not_supported_exception_type, Location);
337 return new Throw (new New (ex_type, null, Location), Location);
340 ConstructorInfo GetInvalidOperationException ()
342 return TypeManager.GetConstructor (
343 TypeManager.invalid_operation_exception_type, Type.EmptyTypes);
346 protected override ScopeInitializer CreateScopeInitializer ()
348 return new IteratorHostInitializer (this);
351 protected class IteratorHostInitializer : RootScopeInitializer
353 new public readonly IteratorHost Host;
354 protected Iterator.State state;
356 public IteratorHostInitializer (IteratorHost host)
357 : base (host)
359 this.Host = host;
362 protected override bool DoResolveInternal (EmitContext ec)
364 if (this is EnumeratorScopeInitializer)
365 state = Iterator.State.Running;
366 else if (Host.Iterator.IsEnumerable)
367 state = Iterator.State.Uninitialized;
368 else
369 state = Iterator.State.Running;
371 return base.DoResolveInternal (ec);
374 protected override void EmitScopeConstructor (EmitContext ec)
376 ec.ig.Emit (OpCodes.Ldc_I4, (int) state);
377 base.EmitScopeConstructor (ec);
381 protected class GetEnumeratorMethod : Method
383 public IteratorHost Host;
385 static MemberName GetMemberName (IteratorHost host, bool is_generic)
387 MemberName left;
388 if (is_generic) {
389 left = new MemberName (
390 "System.Collections.Generic.IEnumerable",
391 host.generic_args, host.Location);
392 } else {
393 left = new MemberName (
394 "System.Collections.IEnumerable", host.Location);
397 return new MemberName (left, "GetEnumerator", host.Location);
400 public GetEnumeratorMethod (IteratorHost host, bool is_generic)
401 : base (host, null, is_generic ?
402 host.generic_enumerator_type : host.enumerator_type,
403 0, false, GetMemberName (host, is_generic),
404 Parameters.EmptyReadOnlyParameters, null)
406 this.Host = host;
408 host.AddMethod (this);
410 Block = new ToplevelBlock (host.Iterator.Container.Toplevel, null, Location);
411 Block.AddStatement (new GetEnumeratorStatement (host, Type));
414 public override EmitContext CreateEmitContext (DeclSpace tc, ILGenerator ig)
416 EmitContext ec = new EmitContext (
417 this, tc, this.ds, Location, ig, MemberType, ModFlags, false);
419 ec.CurrentAnonymousMethod = Host.Iterator;
420 return ec;
423 protected class GetEnumeratorStatement : Statement
425 IteratorHost host;
426 Expression type;
428 ExpressionStatement initializer;
429 Expression cast;
430 MethodInfo ce;
432 public GetEnumeratorStatement (IteratorHost host, Expression type)
434 this.host = host;
435 this.type = type;
436 loc = host.Location;
439 public override bool Resolve (EmitContext ec)
441 type = type.ResolveAsTypeTerminal (ec, false);
442 if ((type == null) || (type.Type == null))
443 return false;
445 initializer = host.GetEnumeratorInitializer (ec);
446 if (initializer == null)
447 return false;
449 cast = new ClassCast (initializer, type.Type);
451 ce = TypeManager.int_interlocked_compare_exchange;
453 ec.CurrentBranching.CurrentUsageVector.Goto ();
454 return true;
457 protected override void DoEmit (EmitContext ec)
459 ILGenerator ig = ec.ig;
460 Label label_init = ig.DefineLabel ();
462 ig.Emit (OpCodes.Ldarg_0);
463 ig.Emit (OpCodes.Ldflda, host.PC.FieldBuilder);
464 ig.Emit (OpCodes.Ldc_I4, (int) Iterator.State.Running);
465 ig.Emit (OpCodes.Ldc_I4, (int) Iterator.State.Uninitialized);
466 ig.Emit (OpCodes.Call, ce);
468 ig.Emit (OpCodes.Ldc_I4, (int) Iterator.State.Uninitialized);
469 ig.Emit (OpCodes.Bne_Un, label_init);
471 ig.Emit (OpCodes.Ldarg_0);
472 ig.Emit (OpCodes.Ret);
474 ig.MarkLabel (label_init);
476 initializer.EmitStatement (ec);
477 cast.Emit (ec);
478 ig.Emit (OpCodes.Ret);
483 protected class DisposeMethod : Method
485 public IteratorHost Host;
487 public DisposeMethod (IteratorHost host)
488 : base (host, null, TypeManager.system_void_expr, Modifiers.PUBLIC,
489 false, new MemberName ("Dispose", host.Location),
490 Parameters.EmptyReadOnlyParameters, null)
492 this.Host = host;
494 host.AddMethod (this);
496 Block = new ToplevelBlock (host.Iterator.Block, null, Location);
497 Block.AddStatement (new DisposeMethodStatement (Host.Iterator));
499 Report.Debug (64, "DISPOSE METHOD", host, Block);
502 public override EmitContext CreateEmitContext (DeclSpace tc, ILGenerator ig)
504 EmitContext ec = new EmitContext (
505 this, tc, this.ds, Location, ig, MemberType, ModFlags, false);
507 ec.CurrentAnonymousMethod = Host.Iterator;
508 return ec;
511 protected class DisposeMethodStatement : Statement
513 Iterator iterator;
515 public DisposeMethodStatement (Iterator iterator)
517 this.iterator = iterator;
518 this.loc = iterator.Location;
521 public override bool Resolve (EmitContext ec)
523 return true;
526 protected override void DoEmit (EmitContext ec)
528 iterator.EmitDispose (ec);
533 protected ScopeInitializer GetEnumeratorInitializer (EmitContext ec)
535 ScopeInitializer init = new EnumeratorScopeInitializer (this);
536 if (init.Resolve (ec) == null)
537 throw new InternalErrorException ();
538 return init;
541 protected class EnumeratorScopeInitializer : IteratorHostInitializer
543 IteratorHost host;
545 public EnumeratorScopeInitializer (IteratorHost host)
546 : base (host)
548 this.host = host;
551 protected override bool DoResolveInternal (EmitContext ec)
553 type = host.IsGeneric ? host.CurrentType : host.TypeBuilder;
554 return base.DoResolveInternal (ec);
557 protected override void DoEmit (EmitContext ec)
559 DoEmitInstance (ec);
562 protected override bool IsGetEnumerator {
563 get { return true; }
566 protected override void EmitParameterReference (EmitContext ec,
567 CapturedParameter cp)
569 ec.ig.Emit (OpCodes.Ldarg_0);
570 ec.ig.Emit (OpCodes.Ldfld, cp.Field.FieldBuilder);
574 protected class CurrentBlock : Statement {
575 IteratorHost host;
576 bool is_generic;
578 public CurrentBlock (IteratorHost host, bool is_generic)
580 this.host = host;
581 this.is_generic = is_generic;
582 loc = host.Location;
585 public override bool Resolve (EmitContext ec)
587 ec.CurrentBranching.CurrentUsageVector.Goto ();
588 return true;
591 protected override void DoEmit (EmitContext ec)
593 ILGenerator ig = ec.ig;
594 Label label_ok = ig.DefineLabel ();
596 ig.Emit (OpCodes.Ldarg_0);
597 ig.Emit (OpCodes.Ldfld, host.PC.FieldBuilder);
598 ig.Emit (OpCodes.Ldc_I4, (int) Iterator.State.Running);
599 ig.Emit (OpCodes.Bgt, label_ok);
601 ig.Emit (OpCodes.Newobj, host.GetInvalidOperationException ());
602 ig.Emit (OpCodes.Throw);
604 ig.MarkLabel (label_ok);
605 ig.Emit (OpCodes.Ldarg_0);
606 ig.Emit (OpCodes.Ldfld, host.CurrentField.FieldBuilder);
607 if (!is_generic)
608 ig.Emit (OpCodes.Box, host.CurrentField.MemberType);
609 ig.Emit (OpCodes.Ret);
614 public class Iterator : AnonymousContainer {
615 protected readonly ToplevelBlock OriginalBlock;
616 protected readonly IMethodData OriginalMethod;
617 protected ToplevelBlock block;
619 public readonly bool IsEnumerable;
620 public readonly bool IsStatic;
623 // The state as we generate the iterator
625 Label move_next_ok, move_next_error;
626 ArrayList resume_points = new ArrayList ();
627 int pc;
629 public readonly Type OriginalIteratorType;
630 public readonly IteratorHost IteratorHost;
632 public enum State {
633 Uninitialized = -2,
634 After,
635 Running
638 public void EmitYieldBreak (ILGenerator ig)
640 ig.Emit (OpCodes.Ldarg_0);
641 IntConstant.EmitInt (ig, (int) State.After);
642 ig.Emit (OpCodes.Stfld, IteratorHost.PC.FieldBuilder);
643 ig.Emit (OpCodes.Br, move_next_error);
646 internal void EmitMoveNext (EmitContext ec, Block original_block)
648 ILGenerator ig = ec.ig;
650 move_next_ok = ig.DefineLabel ();
651 move_next_error = ig.DefineLabel ();
653 LocalBuilder retval = ec.GetTemporaryLocal (TypeManager.int32_type);
655 ig.BeginExceptionBlock ();
657 Label dispatcher = ig.DefineLabel ();
658 ig.Emit (OpCodes.Br, dispatcher);
660 ResumePoint entry_point = new ResumePoint (null);
661 resume_points.Add (entry_point);
662 entry_point.Define (ig);
664 original_block.Emit (ec);
666 EmitYieldBreak (ig);
668 ig.MarkLabel (dispatcher);
670 Label [] labels = new Label [resume_points.Count];
671 for (int i = 0; i < labels.Length; i++)
672 labels [i] = ((ResumePoint) resume_points [i]).Label;
674 ig.Emit (OpCodes.Ldarg_0);
675 ig.Emit (OpCodes.Ldfld, IteratorHost.PC.FieldBuilder);
676 ig.Emit (OpCodes.Switch, labels);
678 Label end = ig.DefineLabel ();
680 ig.MarkLabel (move_next_error);
681 ig.Emit (OpCodes.Ldc_I4_0);
682 ig.Emit (OpCodes.Stloc, retval);
683 ig.Emit (OpCodes.Leave, end);
685 ig.MarkLabel (move_next_ok);
686 ig.Emit (OpCodes.Ldc_I4_1);
687 ig.Emit (OpCodes.Stloc, retval);
688 ig.Emit (OpCodes.Leave, end);
690 ig.BeginFaultBlock ();
692 ig.Emit (OpCodes.Ldarg_0);
693 ig.Emit (OpCodes.Callvirt, IteratorHost.Dispose);
695 ig.EndExceptionBlock ();
697 ig.MarkLabel (end);
698 ig.Emit (OpCodes.Ldloc, retval);
699 ig.Emit (OpCodes.Ret);
702 public void EmitDispose (EmitContext ec)
704 ILGenerator ig = ec.ig;
706 Label end = ig.DefineLabel ();
707 Label dispatcher = ig.DefineLabel ();
708 ig.Emit (OpCodes.Br, dispatcher);
710 Label [] labels = new Label [resume_points.Count];
711 for (int i = 0; i < labels.Length; i++) {
712 ResumePoint point = (ResumePoint) resume_points [i];
714 if (point.FinallyBlocks == null) {
715 labels [i] = end;
716 continue;
719 labels [i] = ig.DefineLabel ();
720 ig.MarkLabel (labels [i]);
722 ig.BeginExceptionBlock ();
723 ig.BeginFinallyBlock ();
725 foreach (ExceptionStatement stmt in point.FinallyBlocks) {
726 if (stmt != null)
727 stmt.EmitFinally (ec);
730 ig.EndExceptionBlock ();
731 ig.Emit (OpCodes.Br, end);
734 ig.MarkLabel (dispatcher);
735 ig.Emit (OpCodes.Ldarg_0);
736 ig.Emit (OpCodes.Ldfld, IteratorHost.PC.FieldBuilder);
737 ig.Emit (OpCodes.Switch, labels);
739 ig.Emit (OpCodes.Ldarg_0);
740 IntConstant.EmitInt (ig, (int) State.After);
741 ig.Emit (OpCodes.Stfld, IteratorHost.PC.FieldBuilder);
743 ig.MarkLabel (end);
746 protected class ResumePoint
748 public Label Label;
749 public readonly ExceptionStatement[] FinallyBlocks;
751 public ResumePoint (ArrayList list)
753 if (list != null) {
754 FinallyBlocks = new ExceptionStatement [list.Count];
755 list.CopyTo (FinallyBlocks, 0);
759 public void Define (ILGenerator ig)
761 Label = ig.DefineLabel ();
762 ig.MarkLabel (Label);
767 // Called back from Yield
769 public void MarkYield (EmitContext ec, Expression expr,
770 ArrayList finally_blocks)
772 ILGenerator ig = ec.ig;
774 // Store the new current
775 ig.Emit (OpCodes.Ldarg_0);
776 expr.Emit (ec);
777 ig.Emit (OpCodes.Stfld, IteratorHost.CurrentField.FieldBuilder);
779 // increment pc
780 pc++;
781 ig.Emit (OpCodes.Ldarg_0);
782 IntConstant.EmitInt (ig, pc);
783 ig.Emit (OpCodes.Stfld, IteratorHost.PC.FieldBuilder);
785 // Return ok
786 ig.Emit (OpCodes.Br, move_next_ok);
788 ResumePoint point = new ResumePoint (finally_blocks);
789 resume_points.Add (point);
790 point.Define (ig);
793 public void MarkFinally (EmitContext ec, ArrayList finally_blocks)
795 ILGenerator ig = ec.ig;
797 // increment pc
798 pc++;
799 ig.Emit (OpCodes.Ldarg_0);
800 IntConstant.EmitInt (ig, pc);
801 ig.Emit (OpCodes.Stfld, IteratorHost.PC.FieldBuilder);
803 ResumePoint point = new ResumePoint (finally_blocks);
804 resume_points.Add (point);
805 point.Define (ig);
808 public override bool IsIterator {
809 get { return true; }
812 public override RootScopeInfo RootScope {
813 get { return IteratorHost; }
816 public override ScopeInfo Scope {
817 get { return IteratorHost; }
821 // Our constructor
823 private Iterator (IMethodData m_container, DeclSpace host, GenericMethod generic,
824 int modifiers, Type iterator_type, bool is_enumerable)
825 : base (null, host, generic, m_container.ParameterInfo,
826 new ToplevelBlock (m_container.ParameterInfo, m_container.Location),
827 m_container.Block, TypeManager.bool_type, modifiers,
828 m_container.Location)
830 this.OriginalBlock = m_container.Block;
831 this.OriginalMethod = m_container;
832 this.OriginalIteratorType = iterator_type;
833 this.IsEnumerable = is_enumerable;
835 Report.Debug (64, "NEW ITERATOR", host, generic, OriginalBlock,
836 Container, Block);
838 IteratorHost = new IteratorHost (this);
839 Block.CreateIteratorHost (IteratorHost);
841 OriginalBlock.ReParent (Container.Toplevel);
843 m_container.Block = Container.Toplevel;
845 OriginalBlock.MakeIterator (this);
848 protected class TestStatement : Statement
850 public override bool Resolve (EmitContext ec)
852 return true;
855 protected override void DoEmit (EmitContext ec)
857 ec.ig.Emit (OpCodes.Nop);
858 ec.ig.Emit (OpCodes.Neg);
859 ec.ig.Emit (OpCodes.Pop);
860 ec.ig.Emit (OpCodes.Ret);
864 public override string GetSignatureForError ()
866 return OriginalMethod.GetSignatureForError ();
869 public override bool Resolve (EmitContext ec)
871 Report.Debug (64, "RESOLVE ITERATOR", this, Container, Block);
873 Parameters parameters = OriginalMethod.ParameterInfo;
874 for (int i = 0; i < parameters.Count; i++){
875 Parameter.Modifier mod = parameters.ParameterModifier (i);
876 if ((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) != 0){
877 Report.Error (1623, Location,
878 "Iterators cannot have ref or out parameters");
879 return false;
882 if ((mod & Parameter.Modifier.ARGLIST) != 0) {
883 Report.Error (1636, Location,
884 "__arglist is not allowed in parameter list " +
885 "of iterators");
886 return false;
889 if (parameters.ParameterType (i).IsPointer) {
890 Report.Error (1637, Location,
891 "Iterators cannot have unsafe parameters or " +
892 "yield types");
893 return false;
897 if ((ModFlags & Modifiers.UNSAFE) != 0) {
898 Report.Error (1629, Location, "Unsafe code may not appear in iterators");
899 return false;
902 if (!base.Resolve (ec))
903 return false;
905 Report.Debug (64, "RESOLVE ITERATOR #1", this, method, method.Parent,
906 RootScope, ec);
908 if (!RootScope.ResolveType ())
909 return false;
910 if (!RootScope.ResolveMembers ())
911 return false;
912 if (!RootScope.DefineMembers ())
913 return false;
915 ExpressionStatement scope_init = RootScope.GetScopeInitializer (ec);
916 Container.AddStatement (new StatementExpression (scope_init));
917 Expression cast = new ClassCast (scope_init, OriginalMethod.ReturnType);
918 Container.AddStatement (new NoCheckReturn (cast));
920 return true;
923 protected override Method DoCreateMethodHost (EmitContext ec)
925 Report.Debug (128, "CREATE METHOD HOST", this, IteratorHost);
927 IteratorHost.CaptureScopes ();
929 return new AnonymousMethodMethod (
930 this, RootScope, null, TypeManager.system_boolean_expr,
931 Modifiers.PUBLIC, new MemberName ("MoveNext", Location),
932 Parameters.EmptyReadOnlyParameters);
935 protected class MoveNextStatement : Statement {
936 Iterator iterator;
938 public MoveNextStatement (Iterator iterator, Location loc)
940 this.loc = loc;
941 this.iterator = iterator;
944 public override bool Resolve (EmitContext ec)
946 return iterator.OriginalBlock.Resolve (ec);
949 protected override void DoEmit (EmitContext ec)
951 iterator.EmitMoveNext (ec, iterator.Block);
955 public Type IteratorType {
956 get { return IteratorHost.IteratorType; }
960 // This return statement tricks return into not flagging an error for being
961 // used in a Yields method
963 class NoCheckReturn : Statement {
964 public Expression Expr;
966 public NoCheckReturn (Expression expr)
968 Expr = expr;
969 loc = expr.Location;
972 public override bool Resolve (EmitContext ec)
974 Expr = Expr.Resolve (ec);
975 if (Expr == null)
976 return false;
978 ec.CurrentBranching.CurrentUsageVector.Goto ();
980 return true;
983 protected override void DoEmit (EmitContext ec)
985 Expr.Emit (ec);
986 ec.ig.Emit (OpCodes.Ret);
990 public static Iterator CreateIterator (IMethodData method, DeclSpace parent,
991 GenericMethod generic, int modifiers)
993 bool is_enumerable;
994 Type iterator_type;
996 Type ret = method.ReturnType;
997 if (ret == null)
998 return null;
1000 if (!CheckType (ret, out iterator_type, out is_enumerable)) {
1001 Report.Error (1624, method.Location,
1002 "The body of `{0}' cannot be an iterator block " +
1003 "because `{1}' is not an iterator interface type",
1004 method.GetSignatureForError (),
1005 TypeManager.CSharpName (ret));
1006 return null;
1009 return new Iterator (method, parent, generic, modifiers,
1010 iterator_type, is_enumerable);
1013 static bool CheckType (Type ret, out Type original_iterator_type, out bool is_enumerable)
1015 original_iterator_type = null;
1016 is_enumerable = false;
1018 if (ret == TypeManager.ienumerable_type) {
1019 original_iterator_type = TypeManager.object_type;
1020 is_enumerable = true;
1021 return true;
1023 if (ret == TypeManager.ienumerator_type) {
1024 original_iterator_type = TypeManager.object_type;
1025 is_enumerable = false;
1026 return true;
1029 #if GMCS_SOURCE
1030 if (!ret.IsGenericType)
1031 return false;
1033 Type[] args = TypeManager.GetTypeArguments (ret);
1034 if (args.Length != 1)
1035 return false;
1037 Type gt = ret.GetGenericTypeDefinition ();
1038 if (gt == TypeManager.generic_ienumerable_type) {
1039 original_iterator_type = args [0];
1040 is_enumerable = true;
1041 return true;
1042 } else if (gt == TypeManager.generic_ienumerator_type) {
1043 original_iterator_type = args [0];
1044 is_enumerable = false;
1045 return true;
1047 #endif
1049 return false;