2 // iterators.cs: Support for implementing iterators
5 // Miguel de Icaza (miguel@ximian.com)
6 // Marek Safar (marek.safar@gmail.com)
8 // Dual licensed under the terms of the MIT X11 or GNU GPL
9 // Copyright 2003 Ximian, Inc.
10 // Copyright 2003-2008 Novell, Inc.
14 // Flow analysis for Yield.
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)
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 void MutateHoistedGenericType (AnonymousMethodStorey storey)
62 expr.MutateHoistedGenericType (storey);
65 public override bool Resolve (EmitContext ec)
67 expr = expr.Resolve (ec);
71 Report.Debug (64, "RESOLVE YIELD #1", this, ec, expr, expr.GetType (),
72 ec.CurrentAnonymousMethod, ec.CurrentIterator);
74 if (!CheckContext (ec, loc))
77 Iterator iterator = ec.CurrentIterator;
78 if (expr.Type != iterator.OriginalIteratorType) {
79 expr = Convert.ImplicitConversionRequired (
80 ec, expr, iterator.OriginalIteratorType, loc);
85 if (!ec.CurrentBranching.CurrentUsageVector.IsUnreachable)
86 unwind_protect = ec.CurrentBranching.AddResumePoint (this, loc, out resume_pc);
91 protected override void DoEmit (EmitContext ec)
93 ec.CurrentIterator.MarkYield (ec, expr, resume_pc, unwind_protect, resume_point);
96 protected override void CloneTo (CloneContext clonectx, Statement t)
98 Yield target = (Yield) t;
100 target.expr = expr.Clone (clonectx);
104 public class YieldBreak : ExitStatement {
105 public YieldBreak (Location l)
110 public override void Error_FinallyClause ()
112 Report.Error (1625, loc, "Cannot yield in the body of a finally clause");
115 protected override void CloneTo (CloneContext clonectx, Statement target)
117 throw new NotSupportedException ();
120 protected override bool DoResolve (EmitContext ec)
122 return Yield.CheckContext (ec, loc);
125 protected override void DoEmit (EmitContext ec)
127 ec.CurrentIterator.EmitYieldBreak (ec.ig, unwind_protect);
130 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
137 // Wraps method block into iterator wrapper block
139 class IteratorStatement : Statement
142 ExplicitBlock original_block;
144 public IteratorStatement (Iterator iterator, ExplicitBlock original_block)
146 this.iterator = iterator;
147 this.original_block = original_block;
148 this.loc = iterator.Location;
151 protected override void CloneTo (CloneContext clonectx, Statement target)
153 IteratorStatement t = (IteratorStatement) target;
154 t.original_block = (ExplicitBlock) original_block.Clone (clonectx);
155 t.iterator = (Iterator) iterator.Clone (clonectx);
158 public override bool Resolve (EmitContext ec)
160 ec.StartFlowBranching (iterator);
161 bool ok = original_block.Resolve (ec);
162 ec.EndFlowBranching ();
166 protected override void DoEmit (EmitContext ec)
168 iterator.EmitMoveNext (ec, original_block);
171 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
173 original_block.MutateHoistedGenericType (storey);
174 iterator.MutateHoistedGenericType (storey);
178 public class IteratorStorey : AnonymousMethodStorey
180 class IteratorMethod : Method
182 readonly IteratorStorey host;
184 public IteratorMethod (IteratorStorey host, FullNamedExpression returnType, int mod, MemberName name)
185 : base (host, null, returnType, mod | Modifiers.DEBUGGER_HIDDEN | Modifiers.COMPILER_GENERATED,
186 name, Parameters.EmptyReadOnlyParameters, null)
190 Block = new ToplevelBlock (host.Iterator.Container.Toplevel, null, Location);
193 public override EmitContext CreateEmitContext (DeclSpace tc, ILGenerator ig)
195 EmitContext ec = new EmitContext (
196 this, tc, this.ds, Location, ig, MemberType, ModFlags, false);
198 ec.CurrentAnonymousMethod = host.Iterator;
203 class GetEnumeratorMethod : IteratorMethod
205 sealed class GetEnumeratorStatement : Statement
212 public GetEnumeratorStatement (IteratorStorey host, Expression type)
219 protected override void CloneTo (CloneContext clonectx, Statement target)
221 throw new NotSupportedException ();
224 public override bool Resolve (EmitContext ec)
226 type = type.ResolveAsTypeTerminal (ec, false);
227 if ((type == null) || (type.Type == null))
230 TypeExpression storey_type_expr = new TypeExpression (host.TypeBuilder, loc);
231 Expression new_storey;
232 ArrayList init = null;
233 if (host.hoisted_this != null) {
234 init = new ArrayList (host.hoisted_params == null ? 1 : host.HoistedParameters.Count + 1);
235 HoistedThis ht = host.hoisted_this;
236 FieldExpr from = new FieldExpr (ht.Field.FieldBuilder, loc);
237 from.InstanceExpression = CompilerGeneratedThis.Instance;
238 init.Add (new ElementInitializer (ht.Field.Name, from, loc));
241 if (host.hoisted_params != null) {
243 init = new ArrayList (host.HoistedParameters.Count);
245 foreach (HoistedParameter hp in host.HoistedParameters) {
246 FieldExpr from = new FieldExpr (hp.Field.FieldBuilder, loc);
247 from.InstanceExpression = CompilerGeneratedThis.Instance;
248 init.Add (new ElementInitializer (hp.Field.Name, from, loc));
253 new_storey = new NewInitialize (storey_type_expr, new ArrayList (0),
254 new CollectionOrObjectInitializers (init, loc), loc);
256 new_storey = new New (storey_type_expr, new ArrayList (0), loc);
259 new_storey = new_storey.Resolve (ec);
260 if (new_storey != null)
261 cast = Convert.ImplicitConversionRequired (ec, new_storey, type.Type, loc);
263 if (TypeManager.int_interlocked_compare_exchange == null) {
264 Type t = TypeManager.CoreLookupType ("System.Threading", "Interlocked", Kind.Class, true);
266 TypeManager.int_interlocked_compare_exchange = TypeManager.GetPredefinedMethod (
267 t, "CompareExchange", loc, TypeManager.int32_type,
268 TypeManager.int32_type, TypeManager.int32_type);
272 ec.CurrentBranching.CurrentUsageVector.Goto ();
276 protected override void DoEmit (EmitContext ec)
278 ILGenerator ig = ec.ig;
279 Label label_init = ig.DefineLabel ();
281 ig.Emit (OpCodes.Ldarg_0);
282 ig.Emit (OpCodes.Ldflda, host.PC.FieldBuilder);
283 ig.Emit (OpCodes.Ldc_I4, (int) Iterator.State.Start);
284 ig.Emit (OpCodes.Ldc_I4, (int) Iterator.State.Uninitialized);
285 ig.Emit (OpCodes.Call, TypeManager.int_interlocked_compare_exchange);
287 ig.Emit (OpCodes.Ldc_I4, (int) Iterator.State.Uninitialized);
288 ig.Emit (OpCodes.Bne_Un, label_init);
290 ig.Emit (OpCodes.Ldarg_0);
291 ig.Emit (OpCodes.Ret);
293 ig.MarkLabel (label_init);
296 ig.Emit (OpCodes.Ret);
299 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
301 throw new NotSupportedException ();
305 public GetEnumeratorMethod (IteratorStorey host, FullNamedExpression returnType, MemberName name)
306 : base (host, returnType, 0, name)
308 Block.AddStatement (new GetEnumeratorStatement (host, type_name));
312 class DisposeMethod : IteratorMethod
314 sealed class DisposeMethodStatement : Statement
318 public DisposeMethodStatement (Iterator iterator)
320 this.iterator = iterator;
321 this.loc = iterator.Location;
324 protected override void CloneTo (CloneContext clonectx, Statement target)
326 throw new NotSupportedException ();
329 public override bool Resolve (EmitContext ec)
334 protected override void DoEmit (EmitContext ec)
336 iterator.EmitDispose (ec);
339 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
341 throw new NotSupportedException ();
345 public DisposeMethod (IteratorStorey host)
346 : base (host, TypeManager.system_void_expr, Modifiers.PUBLIC, new MemberName ("Dispose", host.Location))
348 host.AddMethod (this);
350 Block = new ToplevelBlock (host.Iterator.Container, null, Location);
351 Block.AddStatement (new DisposeMethodStatement (host.Iterator));
356 // Uses Method as method info
358 class DynamicMethodGroupExpr : MethodGroupExpr
360 readonly Method method;
362 public DynamicMethodGroupExpr (Method method, Location loc)
365 this.method = method;
368 public override Expression DoResolve (EmitContext ec)
370 Methods = new MethodBase [] { method.MethodBuilder };
371 type = method.Parent.TypeBuilder;
372 InstanceExpression = new CompilerGeneratedThis (type, Location);
373 return base.DoResolve (ec);
377 public readonly Iterator Iterator;
379 TypeExpr iterator_type_expr;
383 TypeExpr enumerator_type;
384 TypeExpr enumerable_type;
386 TypeArguments generic_args;
387 TypeExpr generic_enumerator_type;
388 TypeExpr generic_enumerable_type;
390 const TypeArguments generic_args = null;
395 public IteratorStorey (Iterator iterator)
396 : base (iterator.Container.Toplevel, iterator.Host,
397 iterator.OriginalMethod as MemberBase, iterator.GenericMethod, "Iterator")
399 this.Iterator = iterator;
400 HasHoistedVariables = true;
404 get { return pc_field; }
407 public Field CurrentField {
408 get { return current_field; }
411 public ArrayList HoistedParameters {
412 get { return hoisted_params; }
415 protected override TypeExpr [] ResolveBaseTypes (out TypeExpr base_class)
417 iterator_type_expr = new TypeExpression (MutateType (Iterator.OriginalIteratorType), Location);
420 generic_args = new TypeArguments (Location);
421 generic_args.Add (iterator_type_expr);
424 ArrayList list = new ArrayList ();
425 if (Iterator.IsEnumerable) {
426 enumerable_type = new TypeExpression (
427 TypeManager.ienumerable_type, Location);
428 list.Add (enumerable_type);
431 generic_enumerable_type = new ConstructedType (
432 TypeManager.generic_ienumerable_type,
433 generic_args, Location);
434 list.Add (generic_enumerable_type);
438 enumerator_type = new TypeExpression (
439 TypeManager.ienumerator_type, Location);
440 list.Add (enumerator_type);
442 list.Add (new TypeExpression (TypeManager.idisposable_type, Location));
445 generic_enumerator_type = new ConstructedType (
446 TypeManager.generic_ienumerator_type,
447 generic_args, Location);
448 list.Add (generic_enumerator_type);
453 return base.ResolveBaseTypes (out base_class);
456 protected override string GetVariableMangledName (LocalInfo local_info)
458 return "<" + local_info.Name + ">__" + local_name_idx++.ToString ();
461 public void DefineIteratorMembers ()
463 pc_field = AddCompilerGeneratedField ("$PC", TypeManager.system_int32_expr);
464 current_field = AddCompilerGeneratedField ("$current", iterator_type_expr);
467 Define_Current (true);
469 Define_Current (false);
470 new DisposeMethod (this);
473 if (Iterator.IsEnumerable) {
474 MemberName name = new MemberName (
475 new MemberName ("System.Collections.IEnumerable", Location), "GetEnumerator", Location);
478 Method get_enumerator = new IteratorMethod (this, enumerator_type, 0, name);
480 name = new MemberName (
481 new MemberName ("System.Collections.Generic.IEnumerable", generic_args, Location), "GetEnumerator", Location);
482 Method gget_enumerator = new GetEnumeratorMethod (this, generic_enumerator_type, name);
485 // Just call generic GetEnumerator implementation
487 get_enumerator.Block.AddStatement (
488 new Return (new Invocation (new DynamicMethodGroupExpr (gget_enumerator, Location), new ArrayList (0)), Location));
490 AddMethod (get_enumerator);
491 AddMethod (gget_enumerator);
493 AddMethod (new GetEnumeratorMethod (this, enumerator_type, name));
498 void Define_Current (bool is_generic)
504 left = new MemberName (
505 "System.Collections.Generic.IEnumerator",
506 generic_args, Location);
507 type = iterator_type_expr;
509 left = new MemberName ("System.Collections.IEnumerator", Location);
510 type = TypeManager.system_object_expr;
513 MemberName name = new MemberName (left, "Current", null, Location);
515 ToplevelBlock get_block = new ToplevelBlock (Location);
516 get_block.AddStatement (new CurrentBlock (this, is_generic));
518 Accessor getter = new Accessor (get_block, 0, null, null, Location);
520 Property current = new Property (
521 this, type, Modifiers.DEBUGGER_HIDDEN, name, null, getter, null, false);
522 AddProperty (current);
527 Method reset = new Method (
528 this, null, TypeManager.system_void_expr,
529 Modifiers.PUBLIC | Modifiers.DEBUGGER_HIDDEN,
530 new MemberName ("Reset", Location),
531 Parameters.EmptyReadOnlyParameters, null);
534 reset.Block = new ToplevelBlock (Location);
535 reset.Block.AddStatement (Create_ThrowNotSupported ());
538 Statement Create_ThrowNotSupported ()
540 TypeExpr ex_type = new TypeLookupExpression ("System.NotSupportedException");
542 return new Throw (new New (ex_type, null, Location), Location);
545 protected class CurrentBlock : Statement {
549 public CurrentBlock (IteratorStorey host, bool is_generic)
552 this.is_generic = is_generic;
556 protected override void CloneTo (CloneContext clonectx, Statement target)
558 throw new NotSupportedException ();
561 public override bool Resolve (EmitContext ec)
563 // We emit a 'ret', so prevent the enclosing TopLevelBlock from emitting one too
564 ec.CurrentBranching.CurrentUsageVector.Goto ();
568 protected override void DoEmit (EmitContext ec)
570 ILGenerator ig = ec.ig;
572 ig.Emit (OpCodes.Ldarg_0);
573 ig.Emit (OpCodes.Ldfld, host.CurrentField.FieldBuilder);
575 ig.Emit (OpCodes.Box, host.CurrentField.MemberType);
576 ig.Emit (OpCodes.Ret);
579 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
581 throw new NotSupportedException ();
587 // Iterators are implemented as hidden anonymous block
589 public class Iterator : AnonymousExpression {
590 public readonly IMethodData OriginalMethod;
591 AnonymousMethodMethod method;
592 public readonly TypeContainer Host;
593 public readonly bool IsEnumerable;
596 // The state as we generate the iterator
598 Label move_next_ok, move_next_error;
599 LocalBuilder skip_finally, current_pc;
601 public LocalBuilder SkipFinally {
602 get { return skip_finally; }
605 public LocalBuilder CurrentPC {
606 get { return current_pc; }
609 public Block Container {
610 get { return OriginalMethod.Block; }
613 public GenericMethod GenericMethod {
614 get { return OriginalMethod.GenericMethod; }
617 public readonly Type OriginalIteratorType;
619 readonly IteratorStorey IteratorHost;
622 Running = -3, // Used only in CurrentPC, never stored into $PC
628 public override void AddStoreyReference (AnonymousMethodStorey storey)
633 public void EmitYieldBreak (ILGenerator ig, bool unwind_protect)
635 ig.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, move_next_error);
638 void EmitMoveNext_NoResumePoints (EmitContext ec, Block original_block)
640 ILGenerator ig = ec.ig;
642 ig.Emit (OpCodes.Ldarg_0);
643 ig.Emit (OpCodes.Ldfld, IteratorHost.PC.FieldBuilder);
645 ig.Emit (OpCodes.Ldarg_0);
646 IntConstant.EmitInt (ig, (int) State.After);
647 ig.Emit (OpCodes.Stfld, IteratorHost.PC.FieldBuilder);
649 // We only care if the PC is zero (start executing) or non-zero (don't do anything)
650 ig.Emit (OpCodes.Brtrue, move_next_error);
652 SymbolWriter.StartIteratorBody (ec.ig);
653 original_block.Emit (ec);
654 SymbolWriter.EndIteratorBody (ec.ig);
656 ig.MarkLabel (move_next_error);
657 ig.Emit (OpCodes.Ldc_I4_0);
658 ig.Emit (OpCodes.Ret);
661 internal void EmitMoveNext (EmitContext ec, Block original_block)
663 ILGenerator ig = ec.ig;
665 move_next_ok = ig.DefineLabel ();
666 move_next_error = ig.DefineLabel ();
668 if (resume_points == null) {
669 EmitMoveNext_NoResumePoints (ec, original_block);
673 current_pc = ec.GetTemporaryLocal (TypeManager.uint32_type);
674 ig.Emit (OpCodes.Ldarg_0);
675 ig.Emit (OpCodes.Ldfld, IteratorHost.PC.FieldBuilder);
676 ig.Emit (OpCodes.Stloc, current_pc);
678 // We're actually in state 'running', but this is as good a PC value as any if there's an abnormal exit
679 ig.Emit (OpCodes.Ldarg_0);
680 IntConstant.EmitInt (ig, (int) State.After);
681 ig.Emit (OpCodes.Stfld, IteratorHost.PC.FieldBuilder);
683 Label [] labels = new Label [1 + resume_points.Count];
684 labels [0] = ig.DefineLabel ();
686 bool need_skip_finally = false;
687 for (int i = 0; i < resume_points.Count; ++i) {
688 ResumableStatement s = (ResumableStatement) resume_points [i];
689 need_skip_finally |= s is ExceptionStatement;
690 labels [i+1] = s.PrepareForEmit (ec);
693 if (need_skip_finally) {
694 skip_finally = ec.GetTemporaryLocal (TypeManager.bool_type);
695 ig.Emit (OpCodes.Ldc_I4_0);
696 ig.Emit (OpCodes.Stloc, skip_finally);
699 SymbolWriter.StartIteratorDispatcher (ec.ig);
700 ig.Emit (OpCodes.Ldloc, current_pc);
701 ig.Emit (OpCodes.Switch, labels);
703 ig.Emit (OpCodes.Br, move_next_error);
704 SymbolWriter.EndIteratorDispatcher (ec.ig);
706 ig.MarkLabel (labels [0]);
708 SymbolWriter.StartIteratorBody (ec.ig);
709 original_block.Emit (ec);
710 SymbolWriter.EndIteratorBody (ec.ig);
712 SymbolWriter.StartIteratorDispatcher (ec.ig);
714 ig.Emit (OpCodes.Ldarg_0);
715 IntConstant.EmitInt (ig, (int) State.After);
716 ig.Emit (OpCodes.Stfld, IteratorHost.PC.FieldBuilder);
718 ig.MarkLabel (move_next_error);
719 ig.Emit (OpCodes.Ldc_I4_0);
720 ig.Emit (OpCodes.Ret);
722 ig.MarkLabel (move_next_ok);
723 ig.Emit (OpCodes.Ldc_I4_1);
724 ig.Emit (OpCodes.Ret);
726 SymbolWriter.EndIteratorDispatcher (ec.ig);
729 public void EmitDispose (EmitContext ec)
731 ILGenerator ig = ec.ig;
733 Label end = ig.DefineLabel ();
735 Label [] labels = null;
736 int n_resume_points = resume_points == null ? 0 : resume_points.Count;
737 for (int i = 0; i < n_resume_points; ++i) {
738 ResumableStatement s = (ResumableStatement) resume_points [i];
739 Label ret = s.PrepareForDispose (ec, end);
740 if (ret.Equals (end) && labels == null)
742 if (labels == null) {
743 labels = new Label [resume_points.Count + 1];
744 for (int j = 0; j <= i; ++j)
750 if (labels != null) {
751 current_pc = ec.GetTemporaryLocal (TypeManager.uint32_type);
752 ig.Emit (OpCodes.Ldarg_0);
753 ig.Emit (OpCodes.Ldfld, IteratorHost.PC.FieldBuilder);
754 ig.Emit (OpCodes.Stloc, current_pc);
757 ig.Emit (OpCodes.Ldarg_0);
758 IntConstant.EmitInt (ig, (int) State.After);
759 ig.Emit (OpCodes.Stfld, IteratorHost.PC.FieldBuilder);
761 if (labels != null) {
762 //SymbolWriter.StartIteratorDispatcher (ec.ig);
763 ig.Emit (OpCodes.Ldloc, current_pc);
764 ig.Emit (OpCodes.Switch, labels);
765 //SymbolWriter.EndIteratorDispatcher (ec.ig);
767 foreach (ResumableStatement s in resume_points)
768 s.EmitForDispose (ec, this, end, true);
775 ArrayList resume_points;
776 public int AddResumePoint (ResumableStatement stmt)
778 if (resume_points == null)
779 resume_points = new ArrayList ();
780 resume_points.Add (stmt);
781 return resume_points.Count;
785 // Called back from Yield
787 public void MarkYield (EmitContext ec, Expression expr, int resume_pc, bool unwind_protect, Label resume_point)
789 ILGenerator ig = ec.ig;
791 // Store the new current
792 ig.Emit (OpCodes.Ldarg_0);
794 ig.Emit (OpCodes.Stfld, IteratorHost.CurrentField.FieldBuilder);
796 // store resume program-counter
797 ig.Emit (OpCodes.Ldarg_0);
798 IntConstant.EmitInt (ig, resume_pc);
799 ig.Emit (OpCodes.Stfld, IteratorHost.PC.FieldBuilder);
801 // mark finally blocks as disabled
802 if (unwind_protect && skip_finally != null) {
803 ig.Emit (OpCodes.Ldc_I4_1);
804 ig.Emit (OpCodes.Stloc, skip_finally);
808 ig.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, move_next_ok);
810 ig.MarkLabel (resume_point);
813 public override string ContainerType {
814 get { return "iterator"; }
817 public override bool IsIterator {
821 public override AnonymousMethodStorey Storey {
822 get { return IteratorHost; }
828 private Iterator (IMethodData method, TypeContainer host, Type iterator_type, bool is_enumerable)
830 new ToplevelBlock (method.Block, Parameters.EmptyReadOnlyParameters, method.Block.StartLocation),
831 TypeManager.bool_type,
834 this.OriginalMethod = method;
835 this.OriginalIteratorType = iterator_type;
836 this.IsEnumerable = is_enumerable;
839 IteratorHost = Block.ChangeToIterator (this, method.Block);
842 public override string GetSignatureForError ()
844 return OriginalMethod.GetSignatureForError ();
847 public override Expression DoResolve (EmitContext ec)
849 method = new AnonymousMethodMethod (Storey,
850 this, Storey, null, TypeManager.system_boolean_expr,
851 Modifiers.PUBLIC, OriginalMethod.GetSignatureForError (),
852 new MemberName ("MoveNext", Location),
853 Parameters.EmptyReadOnlyParameters);
855 if (!Compatible (ec))
858 IteratorHost.DefineIteratorMembers ();
860 eclass = ExprClass.Value;
861 type = ec.ReturnType;
865 public override void Emit (EmitContext ec)
868 // Load Iterator storey instance
870 method.Storey.Instance.Emit (ec);
873 // Initialize iterator PC when it's unitialized
876 ILGenerator ig = ec.ig;
877 ig.Emit (OpCodes.Dup);
878 IntConstant.EmitInt (ig, (int)State.Uninitialized);
880 FieldInfo field = IteratorHost.PC.FieldBuilder;
882 if (Storey.MemberName.IsGeneric)
883 field = TypeBuilder.GetField (Storey.Instance.Type, field);
885 ig.Emit (OpCodes.Stfld, field);
889 public override Expression CreateExpressionTree (EmitContext ec)
891 throw new NotSupportedException ("ET");
894 public static void CreateIterator (IMethodData method, TypeContainer parent, int modifiers)
899 Type ret = method.ReturnType;
903 if (!CheckType (ret, out iterator_type, out is_enumerable)) {
904 Report.Error (1624, method.Location,
905 "The body of `{0}' cannot be an iterator block " +
906 "because `{1}' is not an iterator interface type",
907 method.GetSignatureForError (),
908 TypeManager.CSharpName (ret));
912 Parameters parameters = method.ParameterInfo;
913 for (int i = 0; i < parameters.Count; i++) {
914 Parameter p = parameters [i];
915 Parameter.Modifier mod = p.ModFlags;
916 if ((mod & Parameter.Modifier.ISBYREF) != 0) {
917 Report.Error (1623, p.Location,
918 "Iterators cannot have ref or out parameters");
922 if ((mod & Parameter.Modifier.ARGLIST) != 0) {
923 Report.Error (1636, method.Location,
924 "__arglist is not allowed in parameter list of iterators");
928 if (parameters.Types [i].IsPointer) {
929 Report.Error (1637, p.Location,
930 "Iterators cannot have unsafe parameters or " +
936 if ((modifiers & Modifiers.UNSAFE) != 0) {
937 Report.Error (1629, method.Location, "Unsafe code may not appear in iterators");
941 Iterator iter = new Iterator (method, parent, iterator_type, is_enumerable);
942 iter.Storey.DefineType ();
945 static bool CheckType (Type ret, out Type original_iterator_type, out bool is_enumerable)
947 original_iterator_type = null;
948 is_enumerable = false;
950 if (ret == TypeManager.ienumerable_type) {
951 original_iterator_type = TypeManager.object_type;
952 is_enumerable = true;
955 if (ret == TypeManager.ienumerator_type) {
956 original_iterator_type = TypeManager.object_type;
957 is_enumerable = false;
961 if (!TypeManager.IsGenericType (ret))
964 Type[] args = TypeManager.GetTypeArguments (ret);
965 if (args.Length != 1)
968 Type gt = TypeManager.DropGenericTypeArguments (ret);
969 if (gt == TypeManager.generic_ienumerable_type) {
970 original_iterator_type = args [0];
971 is_enumerable = true;
975 if (gt == TypeManager.generic_ienumerator_type) {
976 original_iterator_type = args [0];
977 is_enumerable = false;