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);
105 public class YieldBreak : Statement {
107 public YieldBreak (Location l)
112 public override bool Resolve (EmitContext ec)
114 if (!Yield.CheckContext (ec, loc, true))
117 ec.CurrentBranching.CurrentUsageVector.Goto ();
121 protected override void DoEmit (EmitContext ec)
123 ec.CurrentIterator.EmitYieldBreak (ec.ig);
127 public class IteratorHost : RootScopeInfo
129 public readonly Iterator Iterator;
131 TypeExpr iterator_type_expr;
134 MethodInfo dispose_method;
136 TypeExpr enumerator_type;
137 TypeExpr enumerable_type;
138 TypeArguments generic_args;
139 TypeExpr generic_enumerator_type;
140 TypeExpr generic_enumerable_type;
142 public IteratorHost (Iterator iterator)
143 : base (iterator.Container.Toplevel, iterator.Host, iterator.GenericMethod,
146 this.Iterator = iterator;
149 public override bool IsIterator {
153 public MethodInfo Dispose {
154 get { return dispose_method; }
158 get { return pc_field; }
161 public Field CurrentField {
162 get { return current_field; }
165 public Type IteratorType {
166 get { return iterator_type_expr.Type; }
169 public override TypeExpr [] GetClassBases (out TypeExpr base_class)
171 iterator_type_expr = InflateType (Iterator.OriginalIteratorType);
174 generic_args = new TypeArguments (Location);
175 generic_args.Add (iterator_type_expr);
178 ArrayList list = new ArrayList ();
179 if (Iterator.IsEnumerable) {
180 enumerable_type = new TypeExpression (
181 TypeManager.ienumerable_type, Location);
182 list.Add (enumerable_type);
185 generic_enumerable_type = new ConstructedType (
186 TypeManager.generic_ienumerable_type,
187 generic_args, Location);
188 list.Add (generic_enumerable_type);
192 enumerator_type = new TypeExpression (
193 TypeManager.ienumerator_type, Location);
194 list.Add (enumerator_type);
196 list.Add (new TypeExpression (TypeManager.idisposable_type, Location));
199 generic_enumerator_type = new ConstructedType (
200 TypeManager.generic_ienumerator_type,
201 generic_args, Location);
202 list.Add (generic_enumerator_type);
207 return base.GetClassBases (out base_class);
210 protected override bool DoResolveMembers ()
212 pc_field = CaptureVariable ("$PC", TypeManager.system_int32_expr);
213 current_field = CaptureVariable ("$current", iterator_type_expr);
216 Define_Current (true);
218 Define_Current (false);
219 new DisposeMethod (this);
222 if (Iterator.IsEnumerable) {
223 new GetEnumeratorMethod (this, false);
225 new GetEnumeratorMethod (this, true);
229 return base.DoResolveMembers ();
232 public void CaptureScopes ()
234 Report.Debug (128, "DEFINE ITERATOR HOST", this, scopes);
236 foreach (ScopeInfo si in scopes)
239 foreach (ScopeInfo si in scopes) {
241 throw new InternalErrorException ();
242 if (si.DefineType () == null)
243 throw new InternalErrorException ();
244 if (!si.ResolveType ())
245 throw new InternalErrorException ();
246 if (!si.ResolveMembers ())
247 throw new InternalErrorException ();
248 if (!si.DefineMembers ())
249 throw new InternalErrorException ();
253 protected override bool DoDefineMembers ()
255 if (!base.DoDefineMembers ())
258 FetchMethodDispose ();
263 protected override void EmitScopeConstructor (EmitContext ec)
265 ec.ig.Emit (OpCodes.Ldarg_0);
266 ec.ig.Emit (OpCodes.Ldarg_1);
267 ec.ig.Emit (OpCodes.Stfld, pc_field.FieldBuilder);
268 base.EmitScopeConstructor (ec);
271 void FetchMethodDispose ()
273 MemberList dispose_list;
275 dispose_list = FindMembers (
276 CurrentType != null ? CurrentType : TypeBuilder,
277 MemberTypes.Method, BindingFlags.Public | BindingFlags.Instance,
278 Type.FilterName, "Dispose");
280 if (dispose_list.Count != 1)
281 throw new InternalErrorException ("Cannot find Dipose() method.");
283 dispose_method = (MethodInfo) dispose_list [0];
286 void Define_Current (bool is_generic)
292 left = new MemberName (
293 "System.Collections.Generic.IEnumerator",
294 generic_args, Location);
295 type = iterator_type_expr;
297 left = new MemberName ("System.Collections.IEnumerator", Location);
298 type = TypeManager.system_object_expr;
301 MemberName name = new MemberName (left, "Current", null, Location);
303 ToplevelBlock get_block = new ToplevelBlock (Location);
304 get_block.AddStatement (new CurrentBlock (this, is_generic));
306 Accessor getter = new Accessor (get_block, 0, null, Location);
308 Property current = new Property (
309 this, type, 0, false, name, null, getter, null, false);
310 AddProperty (current);
315 Method reset = new Method (
316 this, null, TypeManager.system_void_expr, Modifiers.PUBLIC,
317 false, new MemberName ("Reset", Location),
318 Parameters.EmptyReadOnlyParameters, null);
321 reset.Block = new ToplevelBlock (Location);
322 reset.Block.AddStatement (Create_ThrowNotSupported ());
325 Statement Create_ThrowNotSupported ()
327 TypeExpr ex_type = new TypeExpression (
328 TypeManager.not_supported_exception_type, Location);
330 return new Throw (new New (ex_type, null, Location), Location);
333 ConstructorInfo GetInvalidOperationException ()
335 return TypeManager.GetConstructor (
336 TypeManager.invalid_operation_exception_type, Type.EmptyTypes);
339 protected override ScopeInitializer CreateScopeInitializer ()
341 return new IteratorHostInitializer (this);
344 protected class IteratorHostInitializer : RootScopeInitializer
346 new public readonly IteratorHost Host;
347 protected Iterator.State state;
349 public IteratorHostInitializer (IteratorHost host)
355 protected override bool DoResolveInternal (EmitContext ec)
357 if (this is EnumeratorScopeInitializer)
358 state = Iterator.State.Running;
359 else if (Host.Iterator.IsEnumerable)
360 state = Iterator.State.Uninitialized;
362 state = Iterator.State.Running;
364 return base.DoResolveInternal (ec);
367 protected override void EmitScopeConstructor (EmitContext ec)
369 ec.ig.Emit (OpCodes.Ldc_I4, (int) state);
370 base.EmitScopeConstructor (ec);
374 protected class GetEnumeratorMethod : Method
376 public IteratorHost Host;
378 static MemberName GetMemberName (IteratorHost host, bool is_generic)
382 left = new MemberName (
383 "System.Collections.Generic.IEnumerable",
384 host.generic_args, host.Location);
386 left = new MemberName (
387 "System.Collections.IEnumerable", host.Location);
390 return new MemberName (left, "GetEnumerator", host.Location);
393 public GetEnumeratorMethod (IteratorHost host, bool is_generic)
394 : base (host, null, is_generic ?
395 host.generic_enumerator_type : host.enumerator_type,
396 0, false, GetMemberName (host, is_generic),
397 Parameters.EmptyReadOnlyParameters, null)
401 host.AddMethod (this);
403 Block = new ToplevelBlock (host.Iterator.Container.Toplevel, null, Location);
404 Block.AddStatement (new GetEnumeratorStatement (host, Type));
407 public override EmitContext CreateEmitContext (DeclSpace tc, ILGenerator ig)
409 EmitContext ec = new EmitContext (
410 this, tc, this.ds, Location, ig, MemberType, ModFlags, false);
412 ec.CurrentAnonymousMethod = Host.Iterator;
416 protected class GetEnumeratorStatement : Statement
421 ExpressionStatement initializer;
425 public GetEnumeratorStatement (IteratorHost host, Expression type)
432 public override bool Resolve (EmitContext ec)
434 type = type.ResolveAsTypeTerminal (ec, false);
435 if ((type == null) || (type.Type == null))
438 initializer = host.GetEnumeratorInitializer (ec);
439 if (initializer == null)
442 cast = new ClassCast (initializer, type.Type);
444 ce = TypeManager.int_interlocked_compare_exchange;
446 ec.CurrentBranching.CurrentUsageVector.Return ();
450 protected override void DoEmit (EmitContext ec)
452 ILGenerator ig = ec.ig;
453 Label label_init = ig.DefineLabel ();
455 ig.Emit (OpCodes.Ldarg_0);
456 ig.Emit (OpCodes.Ldflda, host.PC.FieldBuilder);
457 ig.Emit (OpCodes.Ldc_I4, (int) Iterator.State.Running);
458 ig.Emit (OpCodes.Ldc_I4, (int) Iterator.State.Uninitialized);
459 ig.Emit (OpCodes.Call, ce);
461 ig.Emit (OpCodes.Ldc_I4, (int) Iterator.State.Uninitialized);
462 ig.Emit (OpCodes.Bne_Un, label_init);
464 ig.Emit (OpCodes.Ldarg_0);
465 ig.Emit (OpCodes.Ret);
467 ig.MarkLabel (label_init);
469 initializer.EmitStatement (ec);
471 ig.Emit (OpCodes.Ret);
476 protected class DisposeMethod : Method
478 public IteratorHost Host;
480 public DisposeMethod (IteratorHost host)
481 : base (host, null, TypeManager.system_void_expr, Modifiers.PUBLIC,
482 false, new MemberName ("Dispose", host.Location),
483 Parameters.EmptyReadOnlyParameters, null)
487 host.AddMethod (this);
489 Block = new ToplevelBlock (host.Iterator.Block, null, Location);
490 Block.AddStatement (new DisposeMethodStatement (Host.Iterator));
492 Report.Debug (64, "DISPOSE METHOD", host, Block);
495 public override EmitContext CreateEmitContext (DeclSpace tc, ILGenerator ig)
497 EmitContext ec = new EmitContext (
498 this, tc, this.ds, Location, ig, MemberType, ModFlags, false);
500 ec.CurrentAnonymousMethod = Host.Iterator;
504 protected class DisposeMethodStatement : Statement
508 public DisposeMethodStatement (Iterator iterator)
510 this.iterator = iterator;
511 this.loc = iterator.Location;
514 public override bool Resolve (EmitContext ec)
519 protected override void DoEmit (EmitContext ec)
521 iterator.EmitDispose (ec);
526 protected ScopeInitializer GetEnumeratorInitializer (EmitContext ec)
528 ScopeInitializer init = new EnumeratorScopeInitializer (this);
529 if (init.Resolve (ec) == null)
530 throw new InternalErrorException ();
534 protected class EnumeratorScopeInitializer : IteratorHostInitializer
538 public EnumeratorScopeInitializer (IteratorHost host)
544 protected override bool DoResolveInternal (EmitContext ec)
546 type = host.IsGeneric ? host.CurrentType : host.TypeBuilder;
547 return base.DoResolveInternal (ec);
550 protected override void DoEmit (EmitContext ec)
555 protected override bool IsGetEnumerator {
559 protected override void EmitParameterReference (EmitContext ec,
560 CapturedParameter cp)
562 ec.ig.Emit (OpCodes.Ldarg_0);
563 ec.ig.Emit (OpCodes.Ldfld, cp.Field.FieldBuilder);
567 protected class CurrentBlock : Statement {
571 public CurrentBlock (IteratorHost host, bool is_generic)
574 this.is_generic = is_generic;
578 public override bool Resolve (EmitContext ec)
580 ec.CurrentBranching.CurrentUsageVector.Return ();
584 protected override void DoEmit (EmitContext ec)
586 ILGenerator ig = ec.ig;
587 Label label_ok = ig.DefineLabel ();
589 ig.Emit (OpCodes.Ldarg_0);
590 ig.Emit (OpCodes.Ldfld, host.PC.FieldBuilder);
591 ig.Emit (OpCodes.Ldc_I4, (int) Iterator.State.Running);
592 ig.Emit (OpCodes.Bgt, label_ok);
594 ig.Emit (OpCodes.Newobj, host.GetInvalidOperationException ());
595 ig.Emit (OpCodes.Throw);
597 ig.MarkLabel (label_ok);
598 ig.Emit (OpCodes.Ldarg_0);
599 ig.Emit (OpCodes.Ldfld, host.CurrentField.FieldBuilder);
601 ig.Emit (OpCodes.Box, host.CurrentField.MemberType);
602 ig.Emit (OpCodes.Ret);
607 public class Iterator : AnonymousContainer {
608 protected readonly ToplevelBlock OriginalBlock;
609 protected readonly IMethodData OriginalMethod;
610 protected ToplevelBlock block;
612 public readonly bool IsEnumerable;
613 public readonly bool IsStatic;
616 // The state as we generate the iterator
618 Label move_next_ok, move_next_error;
619 ArrayList resume_points = new ArrayList ();
622 public readonly Type OriginalIteratorType;
623 public readonly IteratorHost IteratorHost;
631 public void EmitYieldBreak (ILGenerator ig)
633 ig.Emit (OpCodes.Ldarg_0);
634 IntConstant.EmitInt (ig, (int) State.After);
635 ig.Emit (OpCodes.Stfld, IteratorHost.PC.FieldBuilder);
636 ig.Emit (OpCodes.Br, move_next_error);
639 internal void EmitMoveNext (EmitContext ec, Block original_block)
641 ILGenerator ig = ec.ig;
643 move_next_ok = ig.DefineLabel ();
644 move_next_error = ig.DefineLabel ();
646 LocalBuilder retval = ec.GetTemporaryLocal (TypeManager.int32_type);
648 ig.BeginExceptionBlock ();
650 Label dispatcher = ig.DefineLabel ();
651 ig.Emit (OpCodes.Br, dispatcher);
653 ResumePoint entry_point = new ResumePoint (null);
654 resume_points.Add (entry_point);
655 entry_point.Define (ig);
657 original_block.Emit (ec);
661 ig.MarkLabel (dispatcher);
663 Label [] labels = new Label [resume_points.Count];
664 for (int i = 0; i < labels.Length; i++)
665 labels [i] = ((ResumePoint) resume_points [i]).Label;
667 ig.Emit (OpCodes.Ldarg_0);
668 ig.Emit (OpCodes.Ldfld, IteratorHost.PC.FieldBuilder);
669 ig.Emit (OpCodes.Switch, labels);
671 Label end = ig.DefineLabel ();
673 ig.MarkLabel (move_next_error);
674 ig.Emit (OpCodes.Ldc_I4_0);
675 ig.Emit (OpCodes.Stloc, retval);
676 ig.Emit (OpCodes.Leave, end);
678 ig.MarkLabel (move_next_ok);
679 ig.Emit (OpCodes.Ldc_I4_1);
680 ig.Emit (OpCodes.Stloc, retval);
681 ig.Emit (OpCodes.Leave, end);
683 ig.BeginFaultBlock ();
685 ig.Emit (OpCodes.Ldarg_0);
686 ig.Emit (OpCodes.Callvirt, IteratorHost.Dispose);
688 ig.EndExceptionBlock ();
691 ig.Emit (OpCodes.Ldloc, retval);
692 ig.Emit (OpCodes.Ret);
695 public void EmitDispose (EmitContext ec)
697 ILGenerator ig = ec.ig;
699 Label end = ig.DefineLabel ();
700 Label dispatcher = ig.DefineLabel ();
701 ig.Emit (OpCodes.Br, dispatcher);
703 Label [] labels = new Label [resume_points.Count];
704 for (int i = 0; i < labels.Length; i++) {
705 ResumePoint point = (ResumePoint) resume_points [i];
707 if (point.FinallyBlocks == null) {
712 labels [i] = ig.DefineLabel ();
713 ig.MarkLabel (labels [i]);
715 ig.BeginExceptionBlock ();
716 ig.BeginFinallyBlock ();
718 foreach (ExceptionStatement stmt in point.FinallyBlocks) {
720 stmt.EmitFinally (ec);
723 ig.EndExceptionBlock ();
724 ig.Emit (OpCodes.Br, end);
727 ig.MarkLabel (dispatcher);
728 ig.Emit (OpCodes.Ldarg_0);
729 ig.Emit (OpCodes.Ldfld, IteratorHost.PC.FieldBuilder);
730 ig.Emit (OpCodes.Switch, labels);
732 ig.Emit (OpCodes.Ldarg_0);
733 IntConstant.EmitInt (ig, (int) State.After);
734 ig.Emit (OpCodes.Stfld, IteratorHost.PC.FieldBuilder);
739 protected class ResumePoint
742 public readonly ExceptionStatement[] FinallyBlocks;
744 public ResumePoint (ArrayList list)
747 FinallyBlocks = new ExceptionStatement [list.Count];
748 list.CopyTo (FinallyBlocks, 0);
752 public void Define (ILGenerator ig)
754 Label = ig.DefineLabel ();
755 ig.MarkLabel (Label);
760 // Called back from Yield
762 public void MarkYield (EmitContext ec, Expression expr,
763 ArrayList finally_blocks)
765 ILGenerator ig = ec.ig;
767 // Store the new current
768 ig.Emit (OpCodes.Ldarg_0);
770 ig.Emit (OpCodes.Stfld, IteratorHost.CurrentField.FieldBuilder);
774 ig.Emit (OpCodes.Ldarg_0);
775 IntConstant.EmitInt (ig, pc);
776 ig.Emit (OpCodes.Stfld, IteratorHost.PC.FieldBuilder);
779 ig.Emit (OpCodes.Br, move_next_ok);
781 ResumePoint point = new ResumePoint (finally_blocks);
782 resume_points.Add (point);
786 public void MarkFinally (EmitContext ec, ArrayList finally_blocks)
788 ILGenerator ig = ec.ig;
792 ig.Emit (OpCodes.Ldarg_0);
793 IntConstant.EmitInt (ig, pc);
794 ig.Emit (OpCodes.Stfld, IteratorHost.PC.FieldBuilder);
796 ResumePoint point = new ResumePoint (finally_blocks);
797 resume_points.Add (point);
801 public override bool IsIterator {
805 public override RootScopeInfo RootScope {
806 get { return IteratorHost; }
809 public override ScopeInfo Scope {
810 get { return IteratorHost; }
816 private Iterator (IMethodData m_container, DeclSpace host, GenericMethod generic,
817 int modifiers, Type iterator_type, bool is_enumerable)
818 : base (null, host, generic, m_container.ParameterInfo,
819 new ToplevelBlock (m_container.ParameterInfo, m_container.Location),
820 m_container.Block, TypeManager.bool_type, modifiers,
821 m_container.Location)
823 this.OriginalBlock = m_container.Block;
824 this.OriginalMethod = m_container;
825 this.OriginalIteratorType = iterator_type;
826 this.IsEnumerable = is_enumerable;
828 Report.Debug (64, "NEW ITERATOR", host, generic, OriginalBlock,
831 IteratorHost = new IteratorHost (this);
832 Block.CreateIteratorHost (IteratorHost);
834 OriginalBlock.ReParent (Container.Toplevel);
836 m_container.Block = Container.Toplevel;
838 OriginalBlock.MakeIterator (this);
841 protected class TestStatement : Statement
843 public override bool Resolve (EmitContext ec)
848 protected override void DoEmit (EmitContext ec)
850 ec.ig.Emit (OpCodes.Nop);
851 ec.ig.Emit (OpCodes.Neg);
852 ec.ig.Emit (OpCodes.Pop);
853 ec.ig.Emit (OpCodes.Ret);
857 public override string GetSignatureForError ()
859 return OriginalMethod.GetSignatureForError ();
862 public override bool Resolve (EmitContext ec)
864 Report.Debug (64, "RESOLVE ITERATOR", this, Container, Block);
866 Parameters parameters = OriginalMethod.ParameterInfo;
867 for (int i = 0; i < parameters.Count; i++){
868 Parameter.Modifier mod = parameters.ParameterModifier (i);
869 if ((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) != 0){
870 Report.Error (1623, Location,
871 "Iterators cannot have ref or out parameters");
875 if ((mod & Parameter.Modifier.ARGLIST) != 0) {
876 Report.Error (1636, Location,
877 "__arglist is not allowed in parameter list " +
882 if (parameters.ParameterType (i).IsPointer) {
883 Report.Error (1637, Location,
884 "Iterators cannot have unsafe parameters or " +
890 if ((ModFlags & Modifiers.UNSAFE) != 0) {
891 Report.Error (1629, Location, "Unsafe code may not appear in iterators");
895 if (!base.Resolve (ec))
898 Report.Debug (64, "RESOLVE ITERATOR #1", this, method, method.Parent,
901 if (!RootScope.ResolveType ())
903 if (!RootScope.ResolveMembers ())
905 if (!RootScope.DefineMembers ())
908 ExpressionStatement scope_init = RootScope.GetScopeInitializer (ec);
909 Container.AddStatement (new StatementExpression (scope_init));
910 Expression cast = new ClassCast (scope_init, OriginalMethod.ReturnType);
911 Container.AddStatement (new NoCheckReturn (cast));
916 protected override Method DoCreateMethodHost (EmitContext ec)
918 Report.Debug (128, "CREATE METHOD HOST", this, IteratorHost);
920 IteratorHost.CaptureScopes ();
922 return new AnonymousMethodMethod (
923 this, RootScope, null, TypeManager.system_boolean_expr,
924 Modifiers.PUBLIC, new MemberName ("MoveNext", Location),
925 Parameters.EmptyReadOnlyParameters);
928 protected class MoveNextStatement : Statement {
931 public MoveNextStatement (Iterator iterator, Location loc)
934 this.iterator = iterator;
937 public override bool Resolve (EmitContext ec)
939 return iterator.OriginalBlock.Resolve (ec);
942 protected override void DoEmit (EmitContext ec)
944 iterator.EmitMoveNext (ec, iterator.Block);
948 public Type IteratorType {
949 get { return IteratorHost.IteratorType; }
953 // This return statement tricks return into not flagging an error for being
954 // used in a Yields method
956 class NoCheckReturn : Statement {
957 public Expression Expr;
959 public NoCheckReturn (Expression expr)
965 public override bool Resolve (EmitContext ec)
967 Expr = Expr.Resolve (ec);
971 ec.CurrentBranching.CurrentUsageVector.Return ();
976 protected override void DoEmit (EmitContext ec)
979 ec.ig.Emit (OpCodes.Ret);
983 public static Iterator CreateIterator (IMethodData method, DeclSpace parent,
984 GenericMethod generic, int modifiers)
989 if (!CheckType (method.ReturnType, out iterator_type, out is_enumerable)) {
990 Report.Error (1624, method.Location,
991 "The body of `{0}' cannot be an iterator block " +
992 "because `{1}' is not an iterator interface type",
993 method.GetSignatureForError (),
994 TypeManager.CSharpName (method.ReturnType));
998 return new Iterator (method, parent, generic, modifiers,
999 iterator_type, is_enumerable);
1002 static bool CheckType (Type ret, out Type original_iterator_type, out bool is_enumerable)
1004 original_iterator_type = null;
1005 is_enumerable = false;
1007 if (ret == TypeManager.ienumerable_type) {
1008 original_iterator_type = TypeManager.object_type;
1009 is_enumerable = true;
1012 if (ret == TypeManager.ienumerator_type) {
1013 original_iterator_type = TypeManager.object_type;
1014 is_enumerable = false;
1019 if (!ret.IsGenericType)
1022 Type[] args = TypeManager.GetTypeArguments (ret);
1023 if (args.Length != 1)
1026 Type gt = ret.GetGenericTypeDefinition ();
1027 if (gt == TypeManager.generic_ienumerable_type) {
1028 original_iterator_type = args [0];
1029 is_enumerable = true;
1031 } else if (gt == TypeManager.generic_ienumerator_type) {
1032 original_iterator_type = args [0];
1033 is_enumerable = false;