2 // iterators.cs: Support for implementing iterators
5 // Miguel de Icaza (miguel@ximian.com)
7 // (C) 2003 Ximian, Inc.
10 // Flow analysis for Yield.
11 // Emit calls to base object constructor.
14 // Current should be defined to return T, and IEnumerator.Current returns object
18 using System.Collections;
19 using System.Reflection;
20 using System.Reflection.Emit;
22 namespace Mono.CSharp {
24 public class Yield : ResumableStatement {
30 public Yield (Expression expr, Location l)
36 public static bool CheckContext (EmitContext ec, Location loc, bool isYieldBreak)
38 for (Block block = ec.CurrentBlock; block != null; block = block.Parent) {
42 Report.Error (1629, loc, "Unsafe code may not appear in iterators");
47 // We can't use `ec.InUnsafe' here because it's allowed to have an iterator
48 // inside an unsafe class. See test-martin-29.cs for an example.
50 if (!ec.CurrentAnonymousMethod.IsIterator) {
51 Report.Error (1621, loc,
52 "The yield statement cannot be used inside " +
53 "anonymous method blocks");
60 public override bool Resolve (EmitContext ec)
62 Report.Debug (64, "RESOLVE YIELD", this, ec, expr, expr.GetType ());
63 expr = expr.Resolve (ec);
67 Report.Debug (64, "RESOLVE YIELD #1", this, ec, expr, expr.GetType (),
68 ec.CurrentAnonymousMethod, ec.CurrentIterator);
70 if (!CheckContext (ec, loc, false))
73 Iterator iterator = ec.CurrentIterator;
74 if (expr.Type != iterator.IteratorType) {
75 expr = Convert.ImplicitConversionRequired (
76 ec, expr, iterator.IteratorType, loc);
81 unwind_protect = ec.CurrentBranching.AddResumePoint (this, loc, out resume_pc);
86 protected override void DoEmit (EmitContext ec)
88 ec.CurrentIterator.MarkYield (ec, expr, resume_pc, unwind_protect, resume_point);
91 protected override void CloneTo (CloneContext clonectx, Statement t)
93 Yield target = (Yield) t;
95 target.expr = expr.Clone (clonectx);
99 public class YieldBreak : ExitStatement {
100 public YieldBreak (Location l)
105 public override void Error_FinallyClause ()
107 Report.Error (1625, loc, "Cannot yield in the body of a finally clause");
110 protected override bool DoResolve (EmitContext ec)
112 return Yield.CheckContext (ec, loc, true);
115 protected override void DoEmit (EmitContext ec)
117 ec.CurrentIterator.EmitYieldBreak (ec.ig, unwind_protect);
121 public class IteratorHost : RootScopeInfo
123 public readonly Iterator Iterator;
125 TypeExpr iterator_type_expr;
128 MethodInfo dispose_method;
130 TypeExpr enumerator_type;
131 TypeExpr enumerable_type;
132 TypeArguments generic_args;
133 TypeExpr generic_enumerator_type;
135 TypeExpr generic_enumerable_type;
138 public IteratorHost (Iterator iterator)
139 : base (iterator.Container.Toplevel, iterator.Host, iterator.GenericMethod,
142 this.Iterator = iterator;
145 public override bool IsIterator {
149 public MethodInfo Dispose {
150 get { return dispose_method; }
154 get { return pc_field; }
157 public Field CurrentField {
158 get { return current_field; }
161 public Type IteratorType {
162 get { return iterator_type_expr.Type; }
165 public override TypeExpr [] GetClassBases (out TypeExpr base_class)
167 iterator_type_expr = InflateType (Iterator.OriginalIteratorType);
170 generic_args = new TypeArguments (Location);
171 generic_args.Add (iterator_type_expr);
174 ArrayList list = new ArrayList ();
175 if (Iterator.IsEnumerable) {
176 enumerable_type = new TypeExpression (
177 TypeManager.ienumerable_type, Location);
178 list.Add (enumerable_type);
181 generic_enumerable_type = new ConstructedType (
182 TypeManager.generic_ienumerable_type,
183 generic_args, Location);
184 list.Add (generic_enumerable_type);
188 enumerator_type = new TypeExpression (
189 TypeManager.ienumerator_type, Location);
190 list.Add (enumerator_type);
192 list.Add (new TypeExpression (TypeManager.idisposable_type, Location));
195 generic_enumerator_type = new ConstructedType (
196 TypeManager.generic_ienumerator_type,
197 generic_args, Location);
198 list.Add (generic_enumerator_type);
203 return base.GetClassBases (out base_class);
206 protected override bool DoResolveMembers ()
208 pc_field = CaptureVariable ("$PC", TypeManager.system_int32_expr);
209 current_field = CaptureVariable ("$current", iterator_type_expr);
212 Define_Current (true);
214 Define_Current (false);
215 new DisposeMethod (this);
218 if (Iterator.IsEnumerable) {
219 new GetEnumeratorMethod (this, false);
221 new GetEnumeratorMethod (this, true);
225 return base.DoResolveMembers ();
228 public void CaptureScopes ()
230 Report.Debug (128, "DEFINE ITERATOR HOST", this, scopes);
232 foreach (ScopeInfo si in scopes)
235 foreach (ScopeInfo si in scopes) {
237 throw new InternalErrorException ();
238 if (si.DefineType () == null)
239 throw new InternalErrorException ();
240 if (!si.ResolveType ())
241 throw new InternalErrorException ();
242 if (!si.ResolveMembers ())
243 throw new InternalErrorException ();
244 if (!si.DefineMembers ())
245 throw new InternalErrorException ();
249 protected override bool DoDefineMembers ()
251 if (!base.DoDefineMembers ())
254 FetchMethodDispose ();
259 protected override void EmitScopeConstructor (EmitContext ec)
261 ec.ig.Emit (OpCodes.Ldarg_0);
262 ec.ig.Emit (OpCodes.Ldarg_1);
263 ec.ig.Emit (OpCodes.Stfld, pc_field.FieldBuilder);
264 base.EmitScopeConstructor (ec);
267 void FetchMethodDispose ()
269 MemberList dispose_list;
271 dispose_list = FindMembers (
272 CurrentType != null ? CurrentType : TypeBuilder,
273 MemberTypes.Method, BindingFlags.Public | BindingFlags.Instance,
274 Type.FilterName, "Dispose");
276 if (dispose_list.Count != 1)
277 throw new InternalErrorException ("Cannot find Dipose() method.");
279 dispose_method = (MethodInfo) dispose_list [0];
282 void Define_Current (bool is_generic)
288 left = new MemberName (
289 "System.Collections.Generic.IEnumerator",
290 generic_args, Location);
291 type = iterator_type_expr;
293 left = new MemberName ("System.Collections.IEnumerator", Location);
294 type = TypeManager.system_object_expr;
297 MemberName name = new MemberName (left, "Current", null, Location);
299 ToplevelBlock get_block = new ToplevelBlock (Location);
300 get_block.AddStatement (new CurrentBlock (this, is_generic));
302 Accessor getter = new Accessor (get_block, 0, null, Location);
304 Property current = new Property (
305 this, type, 0, false, name, null, getter, null, false);
306 AddProperty (current);
311 Method reset = new Method (
312 this, null, TypeManager.system_void_expr, Modifiers.PUBLIC,
313 false, new MemberName ("Reset", Location),
314 Parameters.EmptyReadOnlyParameters, null);
317 reset.Block = new ToplevelBlock (Location);
318 reset.Block.AddStatement (Create_ThrowNotSupported ());
321 Statement Create_ThrowNotSupported ()
323 TypeExpr ex_type = new TypeLookupExpression ("System.NotSupportedException");
325 return new Throw (new New (ex_type, null, Location), Location);
328 protected override ScopeInitializer CreateScopeInitializer ()
330 return new IteratorHostInitializer (this);
333 protected class IteratorHostInitializer : RootScopeInitializer
335 new public readonly IteratorHost Host;
336 protected Iterator.State state;
338 public IteratorHostInitializer (IteratorHost host)
344 protected override bool DoResolveInternal (EmitContext ec)
346 if (this is EnumeratorScopeInitializer)
347 state = Iterator.State.Start;
348 else if (Host.Iterator.IsEnumerable)
349 state = Iterator.State.Uninitialized;
351 state = Iterator.State.Start;
353 return base.DoResolveInternal (ec);
356 protected override void EmitScopeConstructor (EmitContext ec)
358 ec.ig.Emit (OpCodes.Ldc_I4, (int) state);
359 base.EmitScopeConstructor (ec);
363 protected class GetEnumeratorMethod : Method
365 public IteratorHost Host;
367 static MemberName GetMemberName (IteratorHost host, bool is_generic)
371 left = new MemberName (
372 "System.Collections.Generic.IEnumerable",
373 host.generic_args, host.Location);
375 left = new MemberName (
376 "System.Collections.IEnumerable", host.Location);
379 return new MemberName (left, "GetEnumerator", host.Location);
382 public GetEnumeratorMethod (IteratorHost host, bool is_generic)
383 : base (host, null, is_generic ?
384 host.generic_enumerator_type : host.enumerator_type,
385 0, false, GetMemberName (host, is_generic),
386 Parameters.EmptyReadOnlyParameters, null)
390 host.AddMethod (this);
392 Block = new ToplevelBlock (host.Iterator.Container.Toplevel, null, Location);
393 Block.AddStatement (new GetEnumeratorStatement (host, Type));
396 public override EmitContext CreateEmitContext (DeclSpace tc, ILGenerator ig)
398 EmitContext ec = new EmitContext (
399 this, tc, this.ds, Location, ig, MemberType, ModFlags, false);
401 ec.CurrentAnonymousMethod = Host.Iterator;
405 protected class GetEnumeratorStatement : Statement
410 ExpressionStatement initializer;
414 public GetEnumeratorStatement (IteratorHost host, Expression type)
421 public override bool Resolve (EmitContext ec)
423 type = type.ResolveAsTypeTerminal (ec, false);
424 if ((type == null) || (type.Type == null))
427 initializer = host.GetEnumeratorInitializer (ec);
428 if (initializer == null)
431 cast = new ClassCast (initializer, type.Type);
433 if (TypeManager.int_interlocked_compare_exchange == null) {
434 Type t = TypeManager.CoreLookupType ("System.Threading", "Interlocked", Kind.Class, true);
436 TypeManager.int_interlocked_compare_exchange = TypeManager.GetPredefinedMethod (
437 t, "CompareExchange", loc, TypeManager.GetReferenceType (TypeManager.int32_type),
438 TypeManager.int32_type, TypeManager.int32_type);
442 ce = TypeManager.int_interlocked_compare_exchange;
444 ec.CurrentBranching.CurrentUsageVector.Goto ();
448 protected override void DoEmit (EmitContext ec)
450 ILGenerator ig = ec.ig;
451 Label label_init = ig.DefineLabel ();
453 ig.Emit (OpCodes.Ldarg_0);
454 ig.Emit (OpCodes.Ldflda, host.PC.FieldBuilder);
455 ig.Emit (OpCodes.Ldc_I4, (int) Iterator.State.Start);
456 ig.Emit (OpCodes.Ldc_I4, (int) Iterator.State.Uninitialized);
457 ig.Emit (OpCodes.Call, ce);
459 ig.Emit (OpCodes.Ldc_I4, (int) Iterator.State.Uninitialized);
460 ig.Emit (OpCodes.Bne_Un, label_init);
462 ig.Emit (OpCodes.Ldarg_0);
463 ig.Emit (OpCodes.Ret);
465 ig.MarkLabel (label_init);
467 initializer.EmitStatement (ec);
469 ig.Emit (OpCodes.Ret);
474 protected class DisposeMethod : Method
476 public IteratorHost Host;
478 public DisposeMethod (IteratorHost host)
479 : base (host, null, TypeManager.system_void_expr, Modifiers.PUBLIC,
480 false, new MemberName ("Dispose", host.Location),
481 Parameters.EmptyReadOnlyParameters, null)
485 host.AddMethod (this);
487 Block = new ToplevelBlock (host.Iterator.Block, null, Location);
488 Block.AddStatement (new DisposeMethodStatement (Host.Iterator));
490 Report.Debug (64, "DISPOSE METHOD", host, Block);
493 public override EmitContext CreateEmitContext (DeclSpace tc, ILGenerator ig)
495 EmitContext ec = new EmitContext (
496 this, tc, this.ds, Location, ig, MemberType, ModFlags, false);
498 ec.CurrentAnonymousMethod = Host.Iterator;
502 protected class DisposeMethodStatement : Statement
506 public DisposeMethodStatement (Iterator iterator)
508 this.iterator = iterator;
509 this.loc = iterator.Location;
512 public override bool Resolve (EmitContext ec)
517 protected override void DoEmit (EmitContext ec)
519 iterator.EmitDispose (ec);
524 protected ScopeInitializer GetEnumeratorInitializer (EmitContext ec)
526 ScopeInitializer init = new EnumeratorScopeInitializer (this);
527 if (init.Resolve (ec) == null)
528 throw new InternalErrorException ();
532 protected class EnumeratorScopeInitializer : IteratorHostInitializer
536 public EnumeratorScopeInitializer (IteratorHost host)
542 protected override bool DoResolveInternal (EmitContext ec)
544 type = host.IsGeneric ? host.CurrentType : host.TypeBuilder;
545 return base.DoResolveInternal (ec);
548 protected override void DoEmit (EmitContext ec)
553 protected override bool IsGetEnumerator {
557 protected override void EmitParameterReference (EmitContext ec,
558 CapturedParameter cp)
560 ec.ig.Emit (OpCodes.Ldarg_0);
561 ec.ig.Emit (OpCodes.Ldfld, cp.Field.FieldBuilder);
565 protected class CurrentBlock : Statement {
569 public CurrentBlock (IteratorHost host, bool is_generic)
572 this.is_generic = is_generic;
576 public override bool Resolve (EmitContext ec)
578 if (TypeManager.invalid_operation_exception_ctor == null) {
579 Type t = TypeManager.CoreLookupType ("System", "InvalidOperationException", Kind.Class, true);
581 TypeManager.invalid_operation_exception_ctor = TypeManager.GetPredefinedConstructor (t, loc, Type.EmptyTypes);
584 ec.CurrentBranching.CurrentUsageVector.Goto ();
588 protected override void DoEmit (EmitContext ec)
590 ILGenerator ig = ec.ig;
591 Label label_ok = ig.DefineLabel ();
593 ig.Emit (OpCodes.Ldarg_0);
594 ig.Emit (OpCodes.Ldfld, host.PC.FieldBuilder);
595 ig.Emit (OpCodes.Ldc_I4, (int) Iterator.State.Start);
596 ig.Emit (OpCodes.Bgt, label_ok);
598 ig.Emit (OpCodes.Newobj, TypeManager.invalid_operation_exception_ctor);
599 ig.Emit (OpCodes.Throw);
601 ig.MarkLabel (label_ok);
602 ig.Emit (OpCodes.Ldarg_0);
603 ig.Emit (OpCodes.Ldfld, host.CurrentField.FieldBuilder);
605 ig.Emit (OpCodes.Box, host.CurrentField.MemberType);
606 ig.Emit (OpCodes.Ret);
611 public class Iterator : AnonymousContainer {
612 protected readonly ToplevelBlock OriginalBlock;
613 protected readonly IMethodData OriginalMethod;
614 protected ToplevelBlock block;
616 public readonly bool IsEnumerable;
617 public readonly bool IsStatic;
620 // The state as we generate the iterator
622 Label move_next_ok, move_next_error;
623 LocalBuilder skip_finally, current_pc;
625 public LocalBuilder SkipFinally {
626 get { return skip_finally; }
629 public LocalBuilder CurrentPC {
630 get { return current_pc; }
633 public readonly Type OriginalIteratorType;
634 public readonly IteratorHost IteratorHost;
637 Running = -3, // Used only in CurrentPC, never stored into $PC
643 public void EmitYieldBreak (ILGenerator ig, bool unwind_protect)
645 ig.Emit (OpCodes.Ldarg_0);
646 IntConstant.EmitInt (ig, (int) State.After);
647 ig.Emit (OpCodes.Stfld, IteratorHost.PC.FieldBuilder);
648 ig.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, move_next_error);
651 void EmitMoveNext_NoResumePoints (EmitContext ec, Block original_block)
653 ILGenerator ig = ec.ig;
655 ig.Emit (OpCodes.Ldarg_0);
656 ig.Emit (OpCodes.Ldfld, IteratorHost.PC.FieldBuilder);
658 ig.Emit (OpCodes.Ldarg_0);
659 IntConstant.EmitInt (ig, (int) State.After);
660 ig.Emit (OpCodes.Stfld, IteratorHost.PC.FieldBuilder);
662 // We only care if the PC is zero (start executing) or non-zero (don't do anything)
663 ig.Emit (OpCodes.Brtrue, move_next_error);
665 SymbolWriter.StartIteratorBody (ec.ig);
666 original_block.Emit (ec);
667 SymbolWriter.EndIteratorBody (ec.ig);
669 ig.MarkLabel (move_next_error);
670 ig.Emit (OpCodes.Ldc_I4_0);
671 ig.Emit (OpCodes.Ret);
674 internal void EmitMoveNext (EmitContext ec, Block original_block)
676 ILGenerator ig = ec.ig;
678 move_next_ok = ig.DefineLabel ();
679 move_next_error = ig.DefineLabel ();
681 if (resume_points == null) {
682 EmitMoveNext_NoResumePoints (ec, original_block);
686 current_pc = ec.GetTemporaryLocal (TypeManager.uint32_type);
687 ig.Emit (OpCodes.Ldarg_0);
688 ig.Emit (OpCodes.Ldfld, IteratorHost.PC.FieldBuilder);
689 ig.Emit (OpCodes.Stloc, current_pc);
691 Label [] labels = new Label [1 + resume_points.Count];
692 labels [0] = ig.DefineLabel ();
694 bool need_skip_finally = false;
695 for (int i = 0; i < resume_points.Count; ++i) {
696 ResumableStatement s = (ResumableStatement) resume_points [i];
697 need_skip_finally |= s is ExceptionStatement;
698 labels [i+1] = s.PrepareForEmit (ec);
701 if (need_skip_finally) {
702 skip_finally = ec.GetTemporaryLocal (TypeManager.bool_type);
703 ig.Emit (OpCodes.Ldc_I4_0);
704 ig.Emit (OpCodes.Stloc, skip_finally);
707 ig.BeginExceptionBlock ();
709 SymbolWriter.StartIteratorDispatcher (ec.ig);
710 ig.Emit (OpCodes.Ldloc, current_pc);
711 ig.Emit (OpCodes.Switch, labels);
713 ig.Emit (OpCodes.Br, move_next_error);
714 SymbolWriter.EndIteratorDispatcher (ec.ig);
716 ig.MarkLabel (labels [0]);
718 SymbolWriter.StartIteratorBody (ec.ig);
719 original_block.Emit (ec);
720 SymbolWriter.EndIteratorBody (ec.ig);
722 SymbolWriter.StartIteratorDispatcher (ec.ig);
724 ig.Emit (OpCodes.Ldarg_0);
725 IntConstant.EmitInt (ig, (int) State.After);
726 ig.Emit (OpCodes.Stfld, IteratorHost.PC.FieldBuilder);
728 Label end = ig.DefineLabel ();
729 LocalBuilder retval = ec.GetTemporaryLocal (TypeManager.int32_type);
731 ig.MarkLabel (move_next_error);
732 ig.Emit (OpCodes.Ldc_I4_0);
733 ig.Emit (OpCodes.Stloc, retval);
734 ig.Emit (OpCodes.Leave_S, end);
736 ig.MarkLabel (move_next_ok);
737 ig.Emit (OpCodes.Ldc_I4_1);
738 ig.Emit (OpCodes.Stloc, retval);
739 //ig.Emit (OpCodes.Leave_S, end); // SRE automatically emits a Leave on the BeginFaultBlock
741 SymbolWriter.EndIteratorDispatcher (ec.ig);
743 ig.BeginFaultBlock ();
745 ig.Emit (OpCodes.Ldarg_0);
746 ig.Emit (OpCodes.Callvirt, IteratorHost.Dispose);
748 ig.EndExceptionBlock ();
751 ig.Emit (OpCodes.Ldloc, retval);
752 ig.Emit (OpCodes.Ret);
755 public void EmitDispose (EmitContext ec)
757 ILGenerator ig = ec.ig;
759 Label end = ig.DefineLabel ();
761 Label [] labels = null;
762 int n_resume_points = resume_points == null ? 0 : resume_points.Count;
763 for (int i = 0; i < n_resume_points; ++i) {
764 ResumableStatement s = (ResumableStatement) resume_points [i];
765 Label ret = s.PrepareForDispose (ec, end);
766 if (ret.Equals (end) && labels == null)
768 if (labels == null) {
769 labels = new Label [resume_points.Count + 1];
770 for (int j = 0; j <= i; ++j)
776 if (labels != null) {
777 current_pc = ec.GetTemporaryLocal (TypeManager.uint32_type);
778 ig.Emit (OpCodes.Ldarg_0);
779 ig.Emit (OpCodes.Ldfld, IteratorHost.PC.FieldBuilder);
780 ig.Emit (OpCodes.Stloc, current_pc);
783 ig.Emit (OpCodes.Ldarg_0);
784 IntConstant.EmitInt (ig, (int) State.After);
785 ig.Emit (OpCodes.Stfld, IteratorHost.PC.FieldBuilder);
787 if (labels != null) {
788 //SymbolWriter.StartIteratorDispatcher (ec.ig);
789 ig.Emit (OpCodes.Ldloc, current_pc);
790 ig.Emit (OpCodes.Switch, labels);
791 //SymbolWriter.EndIteratorDispatcher (ec.ig);
793 foreach (ResumableStatement s in resume_points)
794 s.EmitForDispose (ec, this, end, true);
800 ArrayList resume_points;
801 public int AddResumePoint (ResumableStatement stmt, Location loc)
803 if (resume_points == null)
804 resume_points = new ArrayList ();
805 resume_points.Add (stmt);
806 return resume_points.Count;
810 // Called back from Yield
812 public void MarkYield (EmitContext ec, Expression expr, int resume_pc, bool unwind_protect, Label resume_point)
814 ILGenerator ig = ec.ig;
816 // Store the new current
817 ig.Emit (OpCodes.Ldarg_0);
819 ig.Emit (OpCodes.Stfld, IteratorHost.CurrentField.FieldBuilder);
821 // store resume program-counter
822 ig.Emit (OpCodes.Ldarg_0);
823 IntConstant.EmitInt (ig, resume_pc);
824 ig.Emit (OpCodes.Stfld, IteratorHost.PC.FieldBuilder);
826 // mark finally blocks as disabled
827 if (unwind_protect && skip_finally != null) {
828 ig.Emit (OpCodes.Ldc_I4_1);
829 ig.Emit (OpCodes.Stloc, skip_finally);
833 ig.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, move_next_ok);
835 ig.MarkLabel (resume_point);
838 public override string ContainerType {
839 get { return "iterator"; }
842 public override bool IsIterator {
846 public override RootScopeInfo RootScope {
847 get { return IteratorHost; }
850 public override ScopeInfo Scope {
851 get { return IteratorHost; }
857 private Iterator (IMethodData m_container, DeclSpace host, GenericMethod generic,
858 int modifiers, Type iterator_type, bool is_enumerable)
859 : base (host, generic, m_container.ParameterInfo,
860 new ToplevelBlock (m_container.ParameterInfo, m_container.Location),
861 m_container.Block, TypeManager.bool_type, modifiers,
862 m_container.Location)
864 this.OriginalBlock = m_container.Block;
865 this.OriginalMethod = m_container;
866 this.OriginalIteratorType = iterator_type;
867 this.IsEnumerable = is_enumerable;
869 Report.Debug (64, "NEW ITERATOR", host, generic, OriginalBlock,
872 IteratorHost = new IteratorHost (this);
873 Block.CreateIteratorHost (IteratorHost);
875 OriginalBlock.ReParent (Container.Toplevel);
877 m_container.Block = Container.Toplevel;
879 OriginalBlock.MakeIterator (this);
882 protected class TestStatement : Statement
884 public override bool Resolve (EmitContext ec)
889 protected override void DoEmit (EmitContext ec)
891 ec.ig.Emit (OpCodes.Nop);
892 ec.ig.Emit (OpCodes.Neg);
893 ec.ig.Emit (OpCodes.Pop);
894 ec.ig.Emit (OpCodes.Ret);
898 public override string GetSignatureForError ()
900 return OriginalMethod.GetSignatureForError ();
903 public override bool Define (EmitContext ec)
905 Report.Debug (64, "RESOLVE ITERATOR", this, Container, Block);
907 Parameters parameters = OriginalMethod.ParameterInfo;
908 for (int i = 0; i < parameters.Count; i++){
909 Parameter.Modifier mod = parameters.ParameterModifier (i);
910 if ((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) != 0){
911 Report.Error (1623, Location,
912 "Iterators cannot have ref or out parameters");
916 if ((mod & Parameter.Modifier.ARGLIST) != 0) {
917 Report.Error (1636, Location,
918 "__arglist is not allowed in parameter list " +
923 if (parameters.ParameterType (i).IsPointer) {
924 Report.Error (1637, Location,
925 "Iterators cannot have unsafe parameters or " +
931 if ((ModFlags & Modifiers.UNSAFE) != 0) {
932 Report.Error (1629, Location, "Unsafe code may not appear in iterators");
936 if (!base.Define (ec))
939 Report.Debug (64, "RESOLVE ITERATOR #1", this, method, method.Parent,
942 if (!RootScope.ResolveType ())
944 if (!RootScope.ResolveMembers ())
946 if (!RootScope.DefineMembers ())
949 ExpressionStatement scope_init = RootScope.GetScopeInitializer (ec);
950 Container.AddStatement (new StatementExpression (scope_init));
951 Expression cast = new ClassCast (scope_init, OriginalMethod.ReturnType);
952 Container.AddStatement (new NoCheckReturn (cast));
957 protected override Method DoCreateMethodHost (EmitContext ec)
959 Report.Debug (128, "CREATE METHOD HOST", this, IteratorHost);
961 MemberCore mc = ec.ResolveContext as MemberCore;
963 IteratorHost.CaptureScopes ();
965 return new AnonymousMethodMethod (
966 this, RootScope, null, TypeManager.system_boolean_expr,
967 Modifiers.PUBLIC, mc.GetSignatureForError (),
968 new MemberName ("MoveNext", Location),
969 Parameters.EmptyReadOnlyParameters);
972 public override Expression DoResolve (EmitContext ec)
974 throw new NotSupportedException ();
977 public Type IteratorType {
978 get { return IteratorHost.IteratorType; }
982 // This return statement tricks return into not flagging an error for being
983 // used in a Yields method
985 class NoCheckReturn : Statement {
986 public Expression Expr;
988 public NoCheckReturn (Expression expr)
994 public override bool Resolve (EmitContext ec)
996 Expr = Expr.Resolve (ec);
1000 ec.CurrentBranching.CurrentUsageVector.Goto ();
1005 protected override void DoEmit (EmitContext ec)
1008 ec.ig.Emit (OpCodes.Ret);
1012 public static Iterator CreateIterator (IMethodData method, DeclSpace parent,
1013 GenericMethod generic, int modifiers)
1018 Type ret = method.ReturnType;
1022 if (!CheckType (ret, out iterator_type, out is_enumerable)) {
1023 Report.Error (1624, method.Location,
1024 "The body of `{0}' cannot be an iterator block " +
1025 "because `{1}' is not an iterator interface type",
1026 method.GetSignatureForError (),
1027 TypeManager.CSharpName (ret));
1031 return new Iterator (method, parent, generic, modifiers,
1032 iterator_type, is_enumerable);
1035 static bool CheckType (Type ret, out Type original_iterator_type, out bool is_enumerable)
1037 original_iterator_type = null;
1038 is_enumerable = false;
1040 if (ret == TypeManager.ienumerable_type) {
1041 original_iterator_type = TypeManager.object_type;
1042 is_enumerable = true;
1045 if (ret == TypeManager.ienumerator_type) {
1046 original_iterator_type = TypeManager.object_type;
1047 is_enumerable = false;
1052 if (!ret.IsGenericType)
1055 Type[] args = TypeManager.GetTypeArguments (ret);
1056 if (args.Length != 1)
1059 Type gt = ret.GetGenericTypeDefinition ();
1060 if (gt == TypeManager.generic_ienumerable_type) {
1061 original_iterator_type = args [0];
1062 is_enumerable = true;
1064 } else if (gt == TypeManager.generic_ienumerator_type) {
1065 original_iterator_type = args [0];
1066 is_enumerable = false;