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 : Statement {
26 ArrayList finally_blocks;
28 public Yield (Expression expr, Location l)
34 public static bool CheckContext (EmitContext ec, Location loc, bool isYieldBreak)
37 Report.Error (1625, loc, "Cannot yield in the body of a " +
42 for (Block block = ec.CurrentBlock; block != null; block = block.Parent) {
46 Report.Error (1629, loc, "Unsafe code may not appear in iterators");
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");
61 if (ec.CurrentBranching.InTryWithCatch () && (!isYieldBreak || !ec.InCatch)) {
63 Report.Error (1626, loc, "Cannot yield a value in the body " +
64 "of a try block with a catch clause");
66 Report.Error (1631, loc, "Cannot yield a value in the body " +
74 public override bool Resolve (EmitContext ec)
76 Report.Debug (64, "RESOLVE YIELD", this, ec, expr, expr.GetType ());
77 expr = expr.Resolve (ec);
81 Report.Debug (64, "RESOLVE YIELD #1", this, ec, expr, expr.GetType (),
82 ec.CurrentAnonymousMethod, ec.CurrentIterator);
84 if (!CheckContext (ec, loc, false))
87 Iterator iterator = ec.CurrentIterator;
88 if (expr.Type != iterator.IteratorType) {
89 expr = Convert.ImplicitConversionRequired (
90 ec, expr, iterator.IteratorType, loc);
95 ec.CurrentBranching.StealFinallyClauses (ref finally_blocks);
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)
119 public override bool Resolve (EmitContext ec)
121 if (!Yield.CheckContext (ec, loc, true))
124 ec.CurrentBranching.CurrentUsageVector.Goto ();
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;
141 MethodInfo dispose_method;
143 TypeExpr enumerator_type;
144 TypeExpr enumerable_type;
145 TypeArguments generic_args;
146 TypeExpr generic_enumerator_type;
148 TypeExpr generic_enumerable_type;
151 public IteratorHost (Iterator iterator)
152 : base (iterator.Container.Toplevel, iterator.Host, iterator.GenericMethod,
155 this.Iterator = iterator;
158 public override bool IsIterator {
162 public MethodInfo Dispose {
163 get { return dispose_method; }
167 get { return pc_field; }
170 public Field CurrentField {
171 get { return current_field; }
174 public Type IteratorType {
175 get { return iterator_type_expr.Type; }
178 public override TypeExpr [] GetClassBases (out TypeExpr base_class)
180 iterator_type_expr = InflateType (Iterator.OriginalIteratorType);
183 generic_args = new TypeArguments (Location);
184 generic_args.Add (iterator_type_expr);
187 ArrayList list = new ArrayList ();
188 if (Iterator.IsEnumerable) {
189 enumerable_type = new TypeExpression (
190 TypeManager.ienumerable_type, Location);
191 list.Add (enumerable_type);
194 generic_enumerable_type = new ConstructedType (
195 TypeManager.generic_ienumerable_type,
196 generic_args, Location);
197 list.Add (generic_enumerable_type);
201 enumerator_type = new TypeExpression (
202 TypeManager.ienumerator_type, Location);
203 list.Add (enumerator_type);
205 list.Add (new TypeExpression (TypeManager.idisposable_type, Location));
208 generic_enumerator_type = new ConstructedType (
209 TypeManager.generic_ienumerator_type,
210 generic_args, Location);
211 list.Add (generic_enumerator_type);
216 return base.GetClassBases (out base_class);
219 protected override bool DoResolveMembers ()
221 pc_field = CaptureVariable ("$PC", TypeManager.system_int32_expr);
222 current_field = CaptureVariable ("$current", iterator_type_expr);
225 Define_Current (true);
227 Define_Current (false);
228 new DisposeMethod (this);
231 if (Iterator.IsEnumerable) {
232 new GetEnumeratorMethod (this, false);
234 new GetEnumeratorMethod (this, true);
238 return base.DoResolveMembers ();
241 public void CaptureScopes ()
243 Report.Debug (128, "DEFINE ITERATOR HOST", this, scopes);
245 foreach (ScopeInfo si in scopes)
248 foreach (ScopeInfo si in scopes) {
250 throw new InternalErrorException ();
251 if (si.DefineType () == null)
252 throw new InternalErrorException ();
253 if (!si.ResolveType ())
254 throw new InternalErrorException ();
255 if (!si.ResolveMembers ())
256 throw new InternalErrorException ();
257 if (!si.DefineMembers ())
258 throw new InternalErrorException ();
262 protected override bool DoDefineMembers ()
264 if (!base.DoDefineMembers ())
267 FetchMethodDispose ();
272 protected override void EmitScopeConstructor (EmitContext ec)
274 ec.ig.Emit (OpCodes.Ldarg_0);
275 ec.ig.Emit (OpCodes.Ldarg_1);
276 ec.ig.Emit (OpCodes.Stfld, pc_field.FieldBuilder);
277 base.EmitScopeConstructor (ec);
280 void FetchMethodDispose ()
282 MemberList dispose_list;
284 dispose_list = FindMembers (
285 CurrentType != null ? CurrentType : TypeBuilder,
286 MemberTypes.Method, BindingFlags.Public | BindingFlags.Instance,
287 Type.FilterName, "Dispose");
289 if (dispose_list.Count != 1)
290 throw new InternalErrorException ("Cannot find Dipose() method.");
292 dispose_method = (MethodInfo) dispose_list [0];
295 void Define_Current (bool is_generic)
301 left = new MemberName (
302 "System.Collections.Generic.IEnumerator",
303 generic_args, Location);
304 type = iterator_type_expr;
306 left = new MemberName ("System.Collections.IEnumerator", Location);
307 type = TypeManager.system_object_expr;
310 MemberName name = new MemberName (left, "Current", null, Location);
312 ToplevelBlock get_block = new ToplevelBlock (Location);
313 get_block.AddStatement (new CurrentBlock (this, is_generic));
315 Accessor getter = new Accessor (get_block, 0, null, Location);
317 Property current = new Property (
318 this, type, 0, false, name, null, getter, null, false);
319 AddProperty (current);
324 Method reset = new Method (
325 this, null, TypeManager.system_void_expr, Modifiers.PUBLIC,
326 false, new MemberName ("Reset", Location),
327 Parameters.EmptyReadOnlyParameters, null);
330 reset.Block = new ToplevelBlock (Location);
331 reset.Block.AddStatement (Create_ThrowNotSupported ());
334 Statement Create_ThrowNotSupported ()
336 TypeExpr ex_type = new TypeLookupExpression ("System.NotSupportedException");
338 return new Throw (new New (ex_type, null, Location), Location);
341 protected override ScopeInitializer CreateScopeInitializer ()
343 return new IteratorHostInitializer (this);
346 protected class IteratorHostInitializer : RootScopeInitializer
348 new public readonly IteratorHost Host;
349 protected Iterator.State state;
351 public IteratorHostInitializer (IteratorHost host)
357 protected override bool DoResolveInternal (EmitContext ec)
359 if (this is EnumeratorScopeInitializer)
360 state = Iterator.State.Running;
361 else if (Host.Iterator.IsEnumerable)
362 state = Iterator.State.Uninitialized;
364 state = Iterator.State.Running;
366 return base.DoResolveInternal (ec);
369 protected override void EmitScopeConstructor (EmitContext ec)
371 ec.ig.Emit (OpCodes.Ldc_I4, (int) state);
372 base.EmitScopeConstructor (ec);
376 protected class GetEnumeratorMethod : Method
378 public IteratorHost Host;
380 static MemberName GetMemberName (IteratorHost host, bool is_generic)
384 left = new MemberName (
385 "System.Collections.Generic.IEnumerable",
386 host.generic_args, host.Location);
388 left = new MemberName (
389 "System.Collections.IEnumerable", host.Location);
392 return new MemberName (left, "GetEnumerator", host.Location);
395 public GetEnumeratorMethod (IteratorHost host, bool is_generic)
396 : base (host, null, is_generic ?
397 host.generic_enumerator_type : host.enumerator_type,
398 0, false, GetMemberName (host, is_generic),
399 Parameters.EmptyReadOnlyParameters, null)
403 host.AddMethod (this);
405 Block = new ToplevelBlock (host.Iterator.Container.Toplevel, null, Location);
406 Block.AddStatement (new GetEnumeratorStatement (host, Type));
409 public override EmitContext CreateEmitContext (DeclSpace tc, ILGenerator ig)
411 EmitContext ec = new EmitContext (
412 this, tc, this.ds, Location, ig, MemberType, ModFlags, false);
414 ec.CurrentAnonymousMethod = Host.Iterator;
418 protected class GetEnumeratorStatement : Statement
423 ExpressionStatement initializer;
427 public GetEnumeratorStatement (IteratorHost host, Expression type)
434 public override bool Resolve (EmitContext ec)
436 type = type.ResolveAsTypeTerminal (ec, false);
437 if ((type == null) || (type.Type == null))
440 initializer = host.GetEnumeratorInitializer (ec);
441 if (initializer == null)
444 cast = new ClassCast (initializer, type.Type);
446 if (TypeManager.int_interlocked_compare_exchange == null) {
447 Type t = TypeManager.CoreLookupType ("System.Threading", "Interlocked", Kind.Class, true);
449 TypeManager.int_interlocked_compare_exchange = TypeManager.GetPredefinedMethod (
450 t, "CompareExchange", loc, TypeManager.GetReferenceType (TypeManager.int32_type),
451 TypeManager.int32_type, TypeManager.int32_type);
455 ce = TypeManager.int_interlocked_compare_exchange;
457 ec.CurrentBranching.CurrentUsageVector.Goto ();
461 protected override void DoEmit (EmitContext ec)
463 ILGenerator ig = ec.ig;
464 Label label_init = ig.DefineLabel ();
466 ig.Emit (OpCodes.Ldarg_0);
467 ig.Emit (OpCodes.Ldflda, host.PC.FieldBuilder);
468 ig.Emit (OpCodes.Ldc_I4, (int) Iterator.State.Running);
469 ig.Emit (OpCodes.Ldc_I4, (int) Iterator.State.Uninitialized);
470 ig.Emit (OpCodes.Call, ce);
472 ig.Emit (OpCodes.Ldc_I4, (int) Iterator.State.Uninitialized);
473 ig.Emit (OpCodes.Bne_Un, label_init);
475 ig.Emit (OpCodes.Ldarg_0);
476 ig.Emit (OpCodes.Ret);
478 ig.MarkLabel (label_init);
480 initializer.EmitStatement (ec);
482 ig.Emit (OpCodes.Ret);
487 protected class DisposeMethod : Method
489 public IteratorHost Host;
491 public DisposeMethod (IteratorHost host)
492 : base (host, null, TypeManager.system_void_expr, Modifiers.PUBLIC,
493 false, new MemberName ("Dispose", host.Location),
494 Parameters.EmptyReadOnlyParameters, null)
498 host.AddMethod (this);
500 Block = new ToplevelBlock (host.Iterator.Block, null, Location);
501 Block.AddStatement (new DisposeMethodStatement (Host.Iterator));
503 Report.Debug (64, "DISPOSE METHOD", host, Block);
506 public override EmitContext CreateEmitContext (DeclSpace tc, ILGenerator ig)
508 EmitContext ec = new EmitContext (
509 this, tc, this.ds, Location, ig, MemberType, ModFlags, false);
511 ec.CurrentAnonymousMethod = Host.Iterator;
515 protected class DisposeMethodStatement : Statement
519 public DisposeMethodStatement (Iterator iterator)
521 this.iterator = iterator;
522 this.loc = iterator.Location;
525 public override bool Resolve (EmitContext ec)
530 protected override void DoEmit (EmitContext ec)
532 iterator.EmitDispose (ec);
537 protected ScopeInitializer GetEnumeratorInitializer (EmitContext ec)
539 ScopeInitializer init = new EnumeratorScopeInitializer (this);
540 if (init.Resolve (ec) == null)
541 throw new InternalErrorException ();
545 protected class EnumeratorScopeInitializer : IteratorHostInitializer
549 public EnumeratorScopeInitializer (IteratorHost host)
555 protected override bool DoResolveInternal (EmitContext ec)
557 type = host.IsGeneric ? host.CurrentType : host.TypeBuilder;
558 return base.DoResolveInternal (ec);
561 protected override void DoEmit (EmitContext ec)
566 protected override bool IsGetEnumerator {
570 protected override void EmitParameterReference (EmitContext ec,
571 CapturedParameter cp)
573 ec.ig.Emit (OpCodes.Ldarg_0);
574 ec.ig.Emit (OpCodes.Ldfld, cp.Field.FieldBuilder);
578 protected class CurrentBlock : Statement {
582 public CurrentBlock (IteratorHost host, bool is_generic)
585 this.is_generic = is_generic;
589 public override bool Resolve (EmitContext ec)
591 if (TypeManager.invalid_operation_exception_ctor == null) {
592 Type t = TypeManager.CoreLookupType ("System", "InvalidOperationException", Kind.Class, true);
594 TypeManager.invalid_operation_exception_ctor = TypeManager.GetPredefinedConstructor (t, loc, Type.EmptyTypes);
597 ec.CurrentBranching.CurrentUsageVector.Goto ();
601 protected override void DoEmit (EmitContext ec)
603 ILGenerator ig = ec.ig;
604 Label label_ok = ig.DefineLabel ();
606 ig.Emit (OpCodes.Ldarg_0);
607 ig.Emit (OpCodes.Ldfld, host.PC.FieldBuilder);
608 ig.Emit (OpCodes.Ldc_I4, (int) Iterator.State.Running);
609 ig.Emit (OpCodes.Bgt, label_ok);
611 ig.Emit (OpCodes.Newobj, TypeManager.invalid_operation_exception_ctor);
612 ig.Emit (OpCodes.Throw);
614 ig.MarkLabel (label_ok);
615 ig.Emit (OpCodes.Ldarg_0);
616 ig.Emit (OpCodes.Ldfld, host.CurrentField.FieldBuilder);
618 ig.Emit (OpCodes.Box, host.CurrentField.MemberType);
619 ig.Emit (OpCodes.Ret);
624 public class Iterator : AnonymousContainer {
625 protected readonly ToplevelBlock OriginalBlock;
626 protected readonly IMethodData OriginalMethod;
627 protected ToplevelBlock block;
629 public readonly bool IsEnumerable;
630 public readonly bool IsStatic;
633 // The state as we generate the iterator
635 Label move_next_ok, move_next_error;
636 ArrayList resume_points = new ArrayList ();
639 public readonly Type OriginalIteratorType;
640 public readonly IteratorHost IteratorHost;
648 public void EmitYieldBreak (ILGenerator ig)
650 ig.Emit (OpCodes.Ldarg_0);
651 IntConstant.EmitInt (ig, (int) State.After);
652 ig.Emit (OpCodes.Stfld, IteratorHost.PC.FieldBuilder);
653 ig.Emit (OpCodes.Br, move_next_error);
656 internal void EmitMoveNext (EmitContext ec, Block original_block)
658 ILGenerator ig = ec.ig;
660 move_next_ok = ig.DefineLabel ();
661 move_next_error = ig.DefineLabel ();
663 LocalBuilder retval = ec.GetTemporaryLocal (TypeManager.int32_type);
665 ig.BeginExceptionBlock ();
667 Label dispatcher = ig.DefineLabel ();
668 ig.Emit (OpCodes.Br, dispatcher);
670 ResumePoint entry_point = new ResumePoint (null);
671 resume_points.Add (entry_point);
672 entry_point.Define (ig);
674 SymbolWriter.StartIteratorBody (ec.ig);
676 original_block.Emit (ec);
678 SymbolWriter.EndIteratorBody (ec.ig);
682 SymbolWriter.StartIteratorDispatcher (ec.ig);
684 ig.MarkLabel (dispatcher);
686 Label [] labels = new Label [resume_points.Count];
687 for (int i = 0; i < labels.Length; i++)
688 labels [i] = ((ResumePoint) resume_points [i]).Label;
690 ig.Emit (OpCodes.Ldarg_0);
691 ig.Emit (OpCodes.Ldfld, IteratorHost.PC.FieldBuilder);
692 ig.Emit (OpCodes.Switch, labels);
694 SymbolWriter.EndIteratorDispatcher (ec.ig);
696 Label end = ig.DefineLabel ();
698 SymbolWriter.StartIteratorDispatcher (ec.ig);
700 ig.MarkLabel (move_next_error);
701 ig.Emit (OpCodes.Ldc_I4_0);
702 ig.Emit (OpCodes.Stloc, retval);
703 ig.Emit (OpCodes.Leave, end);
705 ig.MarkLabel (move_next_ok);
706 ig.Emit (OpCodes.Ldc_I4_1);
707 ig.Emit (OpCodes.Stloc, retval);
708 ig.Emit (OpCodes.Leave, end);
710 SymbolWriter.EndIteratorDispatcher (ec.ig);
712 ig.BeginFaultBlock ();
714 ig.Emit (OpCodes.Ldarg_0);
715 ig.Emit (OpCodes.Callvirt, IteratorHost.Dispose);
717 ig.EndExceptionBlock ();
720 ig.Emit (OpCodes.Ldloc, retval);
721 ig.Emit (OpCodes.Ret);
724 public void EmitDispose (EmitContext ec)
726 ILGenerator ig = ec.ig;
728 Label end = ig.DefineLabel ();
729 Label dispatcher = ig.DefineLabel ();
730 ig.Emit (OpCodes.Br, dispatcher);
732 Label [] labels = new Label [resume_points.Count];
733 for (int i = 0; i < labels.Length; i++) {
734 ResumePoint point = (ResumePoint) resume_points [i];
736 if (point.FinallyBlocks == null) {
741 labels [i] = ig.DefineLabel ();
742 ig.MarkLabel (labels [i]);
744 ig.BeginExceptionBlock ();
745 ig.BeginFinallyBlock ();
747 foreach (ExceptionStatement stmt in point.FinallyBlocks) {
749 stmt.EmitFinally (ec);
752 ig.EndExceptionBlock ();
753 ig.Emit (OpCodes.Br, end);
756 ig.MarkLabel (dispatcher);
757 ig.Emit (OpCodes.Ldarg_0);
758 ig.Emit (OpCodes.Ldfld, IteratorHost.PC.FieldBuilder);
759 ig.Emit (OpCodes.Switch, labels);
761 ig.Emit (OpCodes.Ldarg_0);
762 IntConstant.EmitInt (ig, (int) State.After);
763 ig.Emit (OpCodes.Stfld, IteratorHost.PC.FieldBuilder);
768 protected class ResumePoint
771 public readonly ExceptionStatement[] FinallyBlocks;
773 public ResumePoint (ArrayList list)
776 FinallyBlocks = new ExceptionStatement [list.Count];
777 list.CopyTo (FinallyBlocks, 0);
781 public void Define (ILGenerator ig)
783 Label = ig.DefineLabel ();
784 ig.MarkLabel (Label);
789 // Called back from Yield
791 public void MarkYield (EmitContext ec, Expression expr,
792 ArrayList finally_blocks)
794 ILGenerator ig = ec.ig;
796 // Store the new current
797 ig.Emit (OpCodes.Ldarg_0);
799 ig.Emit (OpCodes.Stfld, IteratorHost.CurrentField.FieldBuilder);
803 ig.Emit (OpCodes.Ldarg_0);
804 IntConstant.EmitInt (ig, pc);
805 ig.Emit (OpCodes.Stfld, IteratorHost.PC.FieldBuilder);
808 ig.Emit (OpCodes.Br, move_next_ok);
810 ResumePoint point = new ResumePoint (finally_blocks);
811 resume_points.Add (point);
815 public void MarkFinally (EmitContext ec, ArrayList finally_blocks)
817 ILGenerator ig = ec.ig;
821 ig.Emit (OpCodes.Ldarg_0);
822 IntConstant.EmitInt (ig, pc);
823 ig.Emit (OpCodes.Stfld, IteratorHost.PC.FieldBuilder);
825 ResumePoint point = new ResumePoint (finally_blocks);
826 resume_points.Add (point);
830 public override string ContainerType {
831 get { return "iterator"; }
834 public override bool IsIterator {
838 public override RootScopeInfo RootScope {
839 get { return IteratorHost; }
842 public override ScopeInfo Scope {
843 get { return IteratorHost; }
849 private Iterator (IMethodData m_container, DeclSpace host, GenericMethod generic,
850 int modifiers, Type iterator_type, bool is_enumerable)
851 : base (host, generic, m_container.ParameterInfo,
852 new ToplevelBlock (m_container.ParameterInfo, m_container.Location),
853 m_container.Block, TypeManager.bool_type, modifiers,
854 m_container.Location)
856 this.OriginalBlock = m_container.Block;
857 this.OriginalMethod = m_container;
858 this.OriginalIteratorType = iterator_type;
859 this.IsEnumerable = is_enumerable;
861 Report.Debug (64, "NEW ITERATOR", host, generic, OriginalBlock,
864 IteratorHost = new IteratorHost (this);
865 Block.CreateIteratorHost (IteratorHost);
867 OriginalBlock.ReParent (Container.Toplevel);
869 m_container.Block = Container.Toplevel;
871 OriginalBlock.MakeIterator (this);
874 protected class TestStatement : Statement
876 public override bool Resolve (EmitContext ec)
881 protected override void DoEmit (EmitContext ec)
883 ec.ig.Emit (OpCodes.Nop);
884 ec.ig.Emit (OpCodes.Neg);
885 ec.ig.Emit (OpCodes.Pop);
886 ec.ig.Emit (OpCodes.Ret);
890 public override string GetSignatureForError ()
892 return OriginalMethod.GetSignatureForError ();
895 public override bool Define (EmitContext ec)
897 Report.Debug (64, "RESOLVE ITERATOR", this, Container, Block);
899 Parameters parameters = OriginalMethod.ParameterInfo;
900 for (int i = 0; i < parameters.Count; i++){
901 Parameter.Modifier mod = parameters.ParameterModifier (i);
902 if ((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) != 0){
903 Report.Error (1623, Location,
904 "Iterators cannot have ref or out parameters");
908 if ((mod & Parameter.Modifier.ARGLIST) != 0) {
909 Report.Error (1636, Location,
910 "__arglist is not allowed in parameter list " +
915 if (parameters.ParameterType (i).IsPointer) {
916 Report.Error (1637, Location,
917 "Iterators cannot have unsafe parameters or " +
923 if ((ModFlags & Modifiers.UNSAFE) != 0) {
924 Report.Error (1629, Location, "Unsafe code may not appear in iterators");
928 if (!base.Define (ec))
931 Report.Debug (64, "RESOLVE ITERATOR #1", this, method, method.Parent,
934 if (!RootScope.ResolveType ())
936 if (!RootScope.ResolveMembers ())
938 if (!RootScope.DefineMembers ())
941 ExpressionStatement scope_init = RootScope.GetScopeInitializer (ec);
942 Container.AddStatement (new StatementExpression (scope_init));
943 Expression cast = new ClassCast (scope_init, OriginalMethod.ReturnType);
944 Container.AddStatement (new NoCheckReturn (cast));
949 protected override Method DoCreateMethodHost (EmitContext ec)
951 Report.Debug (128, "CREATE METHOD HOST", this, IteratorHost);
953 MemberCore mc = ec.ResolveContext as MemberCore;
955 IteratorHost.CaptureScopes ();
957 return new AnonymousMethodMethod (
958 this, RootScope, null, TypeManager.system_boolean_expr,
959 Modifiers.PUBLIC, mc.GetSignatureForError (),
960 new MemberName ("MoveNext", Location),
961 Parameters.EmptyReadOnlyParameters);
964 public override Expression DoResolve (EmitContext ec)
966 throw new NotSupportedException ();
969 protected class MoveNextStatement : Statement {
972 public MoveNextStatement (Iterator iterator, Location loc)
975 this.iterator = iterator;
978 public override bool Resolve (EmitContext ec)
980 return iterator.OriginalBlock.Resolve (ec);
983 protected override void DoEmit (EmitContext ec)
985 iterator.EmitMoveNext (ec, iterator.Block);
989 public Type IteratorType {
990 get { return IteratorHost.IteratorType; }
994 // This return statement tricks return into not flagging an error for being
995 // used in a Yields method
997 class NoCheckReturn : Statement {
998 public Expression Expr;
1000 public NoCheckReturn (Expression expr)
1003 loc = expr.Location;
1006 public override bool Resolve (EmitContext ec)
1008 Expr = Expr.Resolve (ec);
1012 ec.CurrentBranching.CurrentUsageVector.Goto ();
1017 protected override void DoEmit (EmitContext ec)
1020 ec.ig.Emit (OpCodes.Ret);
1024 public static Iterator CreateIterator (IMethodData method, DeclSpace parent,
1025 GenericMethod generic, int modifiers)
1030 Type ret = method.ReturnType;
1034 if (!CheckType (ret, out iterator_type, out is_enumerable)) {
1035 Report.Error (1624, method.Location,
1036 "The body of `{0}' cannot be an iterator block " +
1037 "because `{1}' is not an iterator interface type",
1038 method.GetSignatureForError (),
1039 TypeManager.CSharpName (ret));
1043 return new Iterator (method, parent, generic, modifiers,
1044 iterator_type, is_enumerable);
1047 static bool CheckType (Type ret, out Type original_iterator_type, out bool is_enumerable)
1049 original_iterator_type = null;
1050 is_enumerable = false;
1052 if (ret == TypeManager.ienumerable_type) {
1053 original_iterator_type = TypeManager.object_type;
1054 is_enumerable = true;
1057 if (ret == TypeManager.ienumerator_type) {
1058 original_iterator_type = TypeManager.object_type;
1059 is_enumerable = false;
1064 if (!ret.IsGenericType)
1067 Type[] args = TypeManager.GetTypeArguments (ret);
1068 if (args.Length != 1)
1071 Type gt = ret.GetGenericTypeDefinition ();
1072 if (gt == TypeManager.generic_ienumerable_type) {
1073 original_iterator_type = args [0];
1074 is_enumerable = true;
1076 } else if (gt == TypeManager.generic_ienumerator_type) {
1077 original_iterator_type = args [0];
1078 is_enumerable = false;