2 // iterators.cs: Support for implementing iterators
5 // Miguel de Icaza (miguel@ximian.com)
7 // Copyright 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_name));
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 public override void EmitExtraSymbolInfo (SourceMethod source)
407 source.SetCompilerGenerated ();
410 protected class GetEnumeratorStatement : Statement
415 ExpressionStatement initializer;
419 public GetEnumeratorStatement (IteratorHost host, Expression type)
426 public override bool Resolve (EmitContext ec)
428 type = type.ResolveAsTypeTerminal (ec, false);
429 if ((type == null) || (type.Type == null))
432 initializer = host.GetEnumeratorInitializer (ec);
433 if (initializer == null)
436 cast = new ClassCast (initializer, type.Type);
438 if (TypeManager.int_interlocked_compare_exchange == null) {
439 Type t = TypeManager.CoreLookupType ("System.Threading", "Interlocked", Kind.Class, true);
441 TypeManager.int_interlocked_compare_exchange = TypeManager.GetPredefinedMethod (
442 t, "CompareExchange", loc, TypeManager.GetReferenceType (TypeManager.int32_type),
443 TypeManager.int32_type, TypeManager.int32_type);
447 ce = TypeManager.int_interlocked_compare_exchange;
449 ec.CurrentBranching.CurrentUsageVector.Goto ();
453 protected override void DoEmit (EmitContext ec)
455 ILGenerator ig = ec.ig;
456 Label label_init = ig.DefineLabel ();
458 ig.Emit (OpCodes.Ldarg_0);
459 ig.Emit (OpCodes.Ldflda, host.PC.FieldBuilder);
460 ig.Emit (OpCodes.Ldc_I4, (int) Iterator.State.Start);
461 ig.Emit (OpCodes.Ldc_I4, (int) Iterator.State.Uninitialized);
462 ig.Emit (OpCodes.Call, ce);
464 ig.Emit (OpCodes.Ldc_I4, (int) Iterator.State.Uninitialized);
465 ig.Emit (OpCodes.Bne_Un, label_init);
467 ig.Emit (OpCodes.Ldarg_0);
468 ig.Emit (OpCodes.Ret);
470 ig.MarkLabel (label_init);
472 initializer.EmitStatement (ec);
474 ig.Emit (OpCodes.Ret);
479 protected class DisposeMethod : Method
481 public IteratorHost Host;
483 public DisposeMethod (IteratorHost host)
484 : base (host, null, TypeManager.system_void_expr, Modifiers.PUBLIC,
485 false, new MemberName ("Dispose", host.Location),
486 Parameters.EmptyReadOnlyParameters, null)
490 host.AddMethod (this);
492 Block = new ToplevelBlock (host.Iterator.Block, null, Location);
493 Block.AddStatement (new DisposeMethodStatement (Host.Iterator));
495 Report.Debug (64, "DISPOSE METHOD", host, Block);
498 public override EmitContext CreateEmitContext (DeclSpace tc, ILGenerator ig)
500 EmitContext ec = new EmitContext (
501 this, tc, this.ds, Location, ig, MemberType, ModFlags, false);
503 ec.CurrentAnonymousMethod = Host.Iterator;
507 public override void EmitExtraSymbolInfo (SourceMethod source)
509 source.SetCompilerGenerated ();
512 protected class DisposeMethodStatement : Statement
516 public DisposeMethodStatement (Iterator iterator)
518 this.iterator = iterator;
519 this.loc = iterator.Location;
522 public override bool Resolve (EmitContext ec)
527 protected override void DoEmit (EmitContext ec)
529 iterator.EmitDispose (ec);
534 protected ScopeInitializer GetEnumeratorInitializer (EmitContext ec)
536 ScopeInitializer init = new EnumeratorScopeInitializer (this);
537 if (init.Resolve (ec) == null)
538 throw new InternalErrorException ();
542 protected class EnumeratorScopeInitializer : IteratorHostInitializer
546 public EnumeratorScopeInitializer (IteratorHost host)
552 protected override bool DoResolveInternal (EmitContext ec)
554 type = host.IsGeneric ? host.CurrentType : host.TypeBuilder;
555 return base.DoResolveInternal (ec);
558 protected override void DoEmit (EmitContext ec)
563 protected override bool IsGetEnumerator {
567 protected override void EmitParameterReference (EmitContext ec,
568 CapturedParameter cp)
570 ec.ig.Emit (OpCodes.Ldarg_0);
571 ec.ig.Emit (OpCodes.Ldfld, cp.Field.FieldBuilder);
575 protected class CurrentBlock : Statement {
579 public CurrentBlock (IteratorHost host, bool is_generic)
582 this.is_generic = is_generic;
586 public override bool Resolve (EmitContext ec)
588 // We emit a 'ret', so prevent the enclosing TopLevelBlock from emitting one too
589 ec.CurrentBranching.CurrentUsageVector.Goto ();
593 protected override void DoEmit (EmitContext ec)
595 ILGenerator ig = ec.ig;
597 ig.Emit (OpCodes.Ldarg_0);
598 ig.Emit (OpCodes.Ldfld, host.CurrentField.FieldBuilder);
600 ig.Emit (OpCodes.Box, host.CurrentField.MemberType);
601 ig.Emit (OpCodes.Ret);
606 public class Iterator : AnonymousContainer {
607 protected readonly ToplevelBlock OriginalBlock;
608 protected readonly IMethodData OriginalMethod;
609 protected ToplevelBlock block;
611 public readonly bool IsEnumerable;
612 public readonly bool IsStatic;
615 // The state as we generate the iterator
617 Label move_next_ok, move_next_error;
618 LocalBuilder skip_finally, current_pc;
620 public LocalBuilder SkipFinally {
621 get { return skip_finally; }
624 public LocalBuilder CurrentPC {
625 get { return current_pc; }
628 public readonly Type OriginalIteratorType;
629 public readonly IteratorHost IteratorHost;
632 Running = -3, // Used only in CurrentPC, never stored into $PC
638 public void EmitYieldBreak (ILGenerator ig, bool unwind_protect)
640 ig.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, move_next_error);
643 void EmitMoveNext_NoResumePoints (EmitContext ec, Block original_block)
645 ILGenerator ig = ec.ig;
647 ig.Emit (OpCodes.Ldarg_0);
648 ig.Emit (OpCodes.Ldfld, IteratorHost.PC.FieldBuilder);
650 ig.Emit (OpCodes.Ldarg_0);
651 IntConstant.EmitInt (ig, (int) State.After);
652 ig.Emit (OpCodes.Stfld, IteratorHost.PC.FieldBuilder);
654 // We only care if the PC is zero (start executing) or non-zero (don't do anything)
655 ig.Emit (OpCodes.Brtrue, move_next_error);
657 SymbolWriter.StartIteratorBody (ec.ig);
658 original_block.Emit (ec);
659 SymbolWriter.EndIteratorBody (ec.ig);
661 ig.MarkLabel (move_next_error);
662 ig.Emit (OpCodes.Ldc_I4_0);
663 ig.Emit (OpCodes.Ret);
666 internal void EmitMoveNext (EmitContext ec, Block original_block)
668 ILGenerator ig = ec.ig;
670 move_next_ok = ig.DefineLabel ();
671 move_next_error = ig.DefineLabel ();
673 if (resume_points == null) {
674 EmitMoveNext_NoResumePoints (ec, original_block);
678 current_pc = ec.GetTemporaryLocal (TypeManager.uint32_type);
679 ig.Emit (OpCodes.Ldarg_0);
680 ig.Emit (OpCodes.Ldfld, IteratorHost.PC.FieldBuilder);
681 ig.Emit (OpCodes.Stloc, current_pc);
683 // We're actually in state 'running', but this is as good a PC value as any if there's an abnormal exit
684 ig.Emit (OpCodes.Ldarg_0);
685 IntConstant.EmitInt (ig, (int) State.After);
686 ig.Emit (OpCodes.Stfld, IteratorHost.PC.FieldBuilder);
688 Label [] labels = new Label [1 + resume_points.Count];
689 labels [0] = ig.DefineLabel ();
691 bool need_skip_finally = false;
692 for (int i = 0; i < resume_points.Count; ++i) {
693 ResumableStatement s = (ResumableStatement) resume_points [i];
694 need_skip_finally |= s is ExceptionStatement;
695 labels [i+1] = s.PrepareForEmit (ec);
698 if (need_skip_finally) {
699 skip_finally = ec.GetTemporaryLocal (TypeManager.bool_type);
700 ig.Emit (OpCodes.Ldc_I4_0);
701 ig.Emit (OpCodes.Stloc, skip_finally);
704 SymbolWriter.StartIteratorDispatcher (ec.ig);
705 ig.Emit (OpCodes.Ldloc, current_pc);
706 ig.Emit (OpCodes.Switch, labels);
708 ig.Emit (OpCodes.Br, move_next_error);
709 SymbolWriter.EndIteratorDispatcher (ec.ig);
711 ig.MarkLabel (labels [0]);
713 SymbolWriter.StartIteratorBody (ec.ig);
714 original_block.Emit (ec);
715 SymbolWriter.EndIteratorBody (ec.ig);
717 SymbolWriter.StartIteratorDispatcher (ec.ig);
719 ig.Emit (OpCodes.Ldarg_0);
720 IntConstant.EmitInt (ig, (int) State.After);
721 ig.Emit (OpCodes.Stfld, IteratorHost.PC.FieldBuilder);
723 ig.MarkLabel (move_next_error);
724 ig.Emit (OpCodes.Ldc_I4_0);
725 ig.Emit (OpCodes.Ret);
727 ig.MarkLabel (move_next_ok);
728 ig.Emit (OpCodes.Ldc_I4_1);
729 ig.Emit (OpCodes.Ret);
731 SymbolWriter.EndIteratorDispatcher (ec.ig);
734 public void EmitDispose (EmitContext ec)
736 ILGenerator ig = ec.ig;
738 Label end = ig.DefineLabel ();
740 Label [] labels = null;
741 int n_resume_points = resume_points == null ? 0 : resume_points.Count;
742 for (int i = 0; i < n_resume_points; ++i) {
743 ResumableStatement s = (ResumableStatement) resume_points [i];
744 Label ret = s.PrepareForDispose (ec, end);
745 if (ret.Equals (end) && labels == null)
747 if (labels == null) {
748 labels = new Label [resume_points.Count + 1];
749 for (int j = 0; j <= i; ++j)
755 if (labels != null) {
756 current_pc = ec.GetTemporaryLocal (TypeManager.uint32_type);
757 ig.Emit (OpCodes.Ldarg_0);
758 ig.Emit (OpCodes.Ldfld, IteratorHost.PC.FieldBuilder);
759 ig.Emit (OpCodes.Stloc, current_pc);
762 ig.Emit (OpCodes.Ldarg_0);
763 IntConstant.EmitInt (ig, (int) State.After);
764 ig.Emit (OpCodes.Stfld, IteratorHost.PC.FieldBuilder);
766 if (labels != null) {
767 //SymbolWriter.StartIteratorDispatcher (ec.ig);
768 ig.Emit (OpCodes.Ldloc, current_pc);
769 ig.Emit (OpCodes.Switch, labels);
770 //SymbolWriter.EndIteratorDispatcher (ec.ig);
772 foreach (ResumableStatement s in resume_points)
773 s.EmitForDispose (ec, this, end, true);
779 ArrayList resume_points;
780 public int AddResumePoint (ResumableStatement stmt, Location loc)
782 if (resume_points == null)
783 resume_points = new ArrayList ();
784 resume_points.Add (stmt);
785 return resume_points.Count;
789 // Called back from Yield
791 public void MarkYield (EmitContext ec, Expression expr, int resume_pc, bool unwind_protect, Label resume_point)
793 ILGenerator ig = ec.ig;
795 // Store the new current
796 ig.Emit (OpCodes.Ldarg_0);
798 ig.Emit (OpCodes.Stfld, IteratorHost.CurrentField.FieldBuilder);
800 // store resume program-counter
801 ig.Emit (OpCodes.Ldarg_0);
802 IntConstant.EmitInt (ig, resume_pc);
803 ig.Emit (OpCodes.Stfld, IteratorHost.PC.FieldBuilder);
805 // mark finally blocks as disabled
806 if (unwind_protect && skip_finally != null) {
807 ig.Emit (OpCodes.Ldc_I4_1);
808 ig.Emit (OpCodes.Stloc, skip_finally);
812 ig.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, move_next_ok);
814 ig.MarkLabel (resume_point);
817 public override string ContainerType {
818 get { return "iterator"; }
821 public override bool IsIterator {
825 public override RootScopeInfo RootScope {
826 get { return IteratorHost; }
829 public override ScopeInfo Scope {
830 get { return IteratorHost; }
836 private Iterator (IMethodData m_container, DeclSpace host, GenericMethod generic,
837 int modifiers, Type iterator_type, bool is_enumerable)
838 : base (host, generic, m_container.ParameterInfo,
839 new ToplevelBlock (m_container.ParameterInfo, m_container.Location),
840 m_container.Block, TypeManager.bool_type, modifiers,
841 m_container.Location)
843 this.OriginalBlock = m_container.Block;
844 this.OriginalMethod = m_container;
845 this.OriginalIteratorType = iterator_type;
846 this.IsEnumerable = is_enumerable;
848 Report.Debug (64, "NEW ITERATOR", host, generic, OriginalBlock,
851 IteratorHost = new IteratorHost (this);
852 Block.CreateIteratorHost (IteratorHost);
854 OriginalBlock.ReParent (Container.Toplevel);
856 m_container.Block = Container.Toplevel;
858 OriginalBlock.MakeIterator (this);
861 protected class TestStatement : Statement
863 public override bool Resolve (EmitContext ec)
868 protected override void DoEmit (EmitContext ec)
870 ec.ig.Emit (OpCodes.Nop);
871 ec.ig.Emit (OpCodes.Neg);
872 ec.ig.Emit (OpCodes.Pop);
873 ec.ig.Emit (OpCodes.Ret);
877 public override string GetSignatureForError ()
879 return OriginalMethod.GetSignatureForError ();
882 public override bool Define (EmitContext ec)
884 Report.Debug (64, "RESOLVE ITERATOR", this, Container, Block);
886 Parameters parameters = OriginalMethod.ParameterInfo;
887 for (int i = 0; i < parameters.Count; i++){
888 Parameter.Modifier mod = parameters.ParameterModifier (i);
889 if ((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) != 0){
890 Report.Error (1623, Location,
891 "Iterators cannot have ref or out parameters");
895 if ((mod & Parameter.Modifier.ARGLIST) != 0) {
896 Report.Error (1636, Location,
897 "__arglist is not allowed in parameter list " +
902 if (parameters.ParameterType (i).IsPointer) {
903 Report.Error (1637, Location,
904 "Iterators cannot have unsafe parameters or " +
910 if ((ModFlags & Modifiers.UNSAFE) != 0) {
911 Report.Error (1629, Location, "Unsafe code may not appear in iterators");
915 if (!base.Define (ec))
918 Report.Debug (64, "RESOLVE ITERATOR #1", this, method, method.Parent,
921 if (!RootScope.ResolveType ())
923 if (!RootScope.ResolveMembers ())
925 if (!RootScope.DefineMembers ())
928 ExpressionStatement scope_init = RootScope.GetScopeInitializer (ec);
929 Container.AddStatement (new StatementExpression (scope_init));
930 Expression cast = new ClassCast (scope_init, OriginalMethod.ReturnType);
931 Container.AddStatement (new NoCheckReturn (cast));
936 protected override Method DoCreateMethodHost (EmitContext ec)
938 Report.Debug (128, "CREATE METHOD HOST", this, IteratorHost);
940 MemberCore mc = ec.ResolveContext as MemberCore;
942 IteratorHost.CaptureScopes ();
944 return new AnonymousMethodMethod (
945 this, RootScope, null, TypeManager.system_boolean_expr,
946 Modifiers.PUBLIC, mc.GetSignatureForError (),
947 new MemberName ("MoveNext", Location),
948 Parameters.EmptyReadOnlyParameters);
951 public override Expression DoResolve (EmitContext ec)
953 throw new NotSupportedException ();
956 public Type IteratorType {
957 get { return IteratorHost.IteratorType; }
961 // This return statement tricks return into not flagging an error for being
962 // used in a Yields method
964 class NoCheckReturn : Statement {
965 public Expression Expr;
967 public NoCheckReturn (Expression expr)
973 public override bool Resolve (EmitContext ec)
975 Expr = Expr.Resolve (ec);
979 ec.CurrentBranching.CurrentUsageVector.Goto ();
984 protected override void DoEmit (EmitContext ec)
987 ec.ig.Emit (OpCodes.Ret);
991 public override Expression CreateExpressionTree (EmitContext ec)
993 throw new NotSupportedException ("ET");
996 public static Iterator CreateIterator (IMethodData method, DeclSpace parent,
997 GenericMethod generic, int modifiers)
1002 Type ret = method.ReturnType;
1006 if (!CheckType (ret, out iterator_type, out is_enumerable)) {
1007 Report.Error (1624, method.Location,
1008 "The body of `{0}' cannot be an iterator block " +
1009 "because `{1}' is not an iterator interface type",
1010 method.GetSignatureForError (),
1011 TypeManager.CSharpName (ret));
1015 return new Iterator (method, parent, generic, modifiers,
1016 iterator_type, is_enumerable);
1019 static bool CheckType (Type ret, out Type original_iterator_type, out bool is_enumerable)
1021 original_iterator_type = null;
1022 is_enumerable = false;
1024 if (ret == TypeManager.ienumerable_type) {
1025 original_iterator_type = TypeManager.object_type;
1026 is_enumerable = true;
1029 if (ret == TypeManager.ienumerator_type) {
1030 original_iterator_type = TypeManager.object_type;
1031 is_enumerable = false;
1036 if (!ret.IsGenericType)
1039 Type[] args = TypeManager.GetTypeArguments (ret);
1040 if (args.Length != 1)
1043 Type gt = ret.GetGenericTypeDefinition ();
1044 if (gt == TypeManager.generic_ienumerable_type) {
1045 original_iterator_type = args [0];
1046 is_enumerable = true;
1048 } else if (gt == TypeManager.generic_ienumerator_type) {
1049 original_iterator_type = args [0];
1050 is_enumerable = false;