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 protected class GetEnumeratorStatement : Statement
410 ExpressionStatement initializer;
414 public GetEnumeratorStatement (IteratorHost host, Expression type)
421 public override bool Resolve (EmitContext ec)
423 type = type.ResolveAsTypeTerminal (ec, false);
424 if ((type == null) || (type.Type == null))
427 initializer = host.GetEnumeratorInitializer (ec);
428 if (initializer == null)
431 cast = new ClassCast (initializer, type.Type);
433 if (TypeManager.int_interlocked_compare_exchange == null) {
434 Type t = TypeManager.CoreLookupType ("System.Threading", "Interlocked", Kind.Class, true);
436 TypeManager.int_interlocked_compare_exchange = TypeManager.GetPredefinedMethod (
437 t, "CompareExchange", loc, TypeManager.GetReferenceType (TypeManager.int32_type),
438 TypeManager.int32_type, TypeManager.int32_type);
442 ce = TypeManager.int_interlocked_compare_exchange;
444 ec.CurrentBranching.CurrentUsageVector.Goto ();
448 protected override void DoEmit (EmitContext ec)
450 ILGenerator ig = ec.ig;
451 Label label_init = ig.DefineLabel ();
453 ig.Emit (OpCodes.Ldarg_0);
454 ig.Emit (OpCodes.Ldflda, host.PC.FieldBuilder);
455 ig.Emit (OpCodes.Ldc_I4, (int) Iterator.State.Start);
456 ig.Emit (OpCodes.Ldc_I4, (int) Iterator.State.Uninitialized);
457 ig.Emit (OpCodes.Call, ce);
459 ig.Emit (OpCodes.Ldc_I4, (int) Iterator.State.Uninitialized);
460 ig.Emit (OpCodes.Bne_Un, label_init);
462 ig.Emit (OpCodes.Ldarg_0);
463 ig.Emit (OpCodes.Ret);
465 ig.MarkLabel (label_init);
467 initializer.EmitStatement (ec);
469 ig.Emit (OpCodes.Ret);
474 protected class DisposeMethod : Method
476 public IteratorHost Host;
478 public DisposeMethod (IteratorHost host)
479 : base (host, null, TypeManager.system_void_expr, Modifiers.PUBLIC,
480 false, new MemberName ("Dispose", host.Location),
481 Parameters.EmptyReadOnlyParameters, null)
485 host.AddMethod (this);
487 Block = new ToplevelBlock (host.Iterator.Block, null, Location);
488 Block.AddStatement (new DisposeMethodStatement (Host.Iterator));
490 Report.Debug (64, "DISPOSE METHOD", host, Block);
493 public override EmitContext CreateEmitContext (DeclSpace tc, ILGenerator ig)
495 EmitContext ec = new EmitContext (
496 this, tc, this.ds, Location, ig, MemberType, ModFlags, false);
498 ec.CurrentAnonymousMethod = Host.Iterator;
502 protected class DisposeMethodStatement : Statement
506 public DisposeMethodStatement (Iterator iterator)
508 this.iterator = iterator;
509 this.loc = iterator.Location;
512 public override bool Resolve (EmitContext ec)
517 protected override void DoEmit (EmitContext ec)
519 iterator.EmitDispose (ec);
524 protected ScopeInitializer GetEnumeratorInitializer (EmitContext ec)
526 ScopeInitializer init = new EnumeratorScopeInitializer (this);
527 if (init.Resolve (ec) == null)
528 throw new InternalErrorException ();
532 protected class EnumeratorScopeInitializer : IteratorHostInitializer
536 public EnumeratorScopeInitializer (IteratorHost host)
542 protected override bool DoResolveInternal (EmitContext ec)
544 type = host.IsGeneric ? host.CurrentType : host.TypeBuilder;
545 return base.DoResolveInternal (ec);
548 protected override void DoEmit (EmitContext ec)
553 protected override bool IsGetEnumerator {
557 protected override void EmitParameterReference (EmitContext ec,
558 CapturedParameter cp)
560 ec.ig.Emit (OpCodes.Ldarg_0);
561 ec.ig.Emit (OpCodes.Ldfld, cp.Field.FieldBuilder);
565 protected class CurrentBlock : Statement {
569 public CurrentBlock (IteratorHost host, bool is_generic)
572 this.is_generic = is_generic;
576 public override bool Resolve (EmitContext ec)
578 if (TypeManager.invalid_operation_exception_ctor == null) {
579 Type t = TypeManager.CoreLookupType ("System", "InvalidOperationException", Kind.Class, true);
581 TypeManager.invalid_operation_exception_ctor = TypeManager.GetPredefinedConstructor (t, loc, Type.EmptyTypes);
584 ec.CurrentBranching.CurrentUsageVector.Goto ();
588 protected override void DoEmit (EmitContext ec)
590 ILGenerator ig = ec.ig;
591 Label label_ok = ig.DefineLabel ();
593 ig.Emit (OpCodes.Ldarg_0);
594 ig.Emit (OpCodes.Ldfld, host.PC.FieldBuilder);
595 ig.Emit (OpCodes.Ldc_I4, (int) Iterator.State.Start);
596 ig.Emit (OpCodes.Bgt, label_ok);
598 ig.Emit (OpCodes.Newobj, TypeManager.invalid_operation_exception_ctor);
599 ig.Emit (OpCodes.Throw);
601 ig.MarkLabel (label_ok);
602 ig.Emit (OpCodes.Ldarg_0);
603 ig.Emit (OpCodes.Ldfld, host.CurrentField.FieldBuilder);
605 ig.Emit (OpCodes.Box, host.CurrentField.MemberType);
606 ig.Emit (OpCodes.Ret);
611 public class Iterator : AnonymousContainer {
612 protected readonly ToplevelBlock OriginalBlock;
613 protected readonly IMethodData OriginalMethod;
614 protected ToplevelBlock block;
616 public readonly bool IsEnumerable;
617 public readonly bool IsStatic;
620 // The state as we generate the iterator
622 Label move_next_ok, move_next_error;
623 LocalBuilder skip_finally, current_pc;
625 public LocalBuilder SkipFinally {
626 get { return skip_finally; }
629 public LocalBuilder CurrentPC {
630 get { return current_pc; }
633 public readonly Type OriginalIteratorType;
634 public readonly IteratorHost IteratorHost;
637 Running = -3, // Used only in CurrentPC, never stored into $PC
643 public void EmitYieldBreak (ILGenerator ig, bool unwind_protect)
645 ig.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, move_next_error);
648 void EmitMoveNext_NoResumePoints (EmitContext ec, Block original_block)
650 ILGenerator ig = ec.ig;
652 ig.Emit (OpCodes.Ldarg_0);
653 ig.Emit (OpCodes.Ldfld, IteratorHost.PC.FieldBuilder);
655 ig.Emit (OpCodes.Ldarg_0);
656 IntConstant.EmitInt (ig, (int) State.After);
657 ig.Emit (OpCodes.Stfld, IteratorHost.PC.FieldBuilder);
659 // We only care if the PC is zero (start executing) or non-zero (don't do anything)
660 ig.Emit (OpCodes.Brtrue, move_next_error);
662 SymbolWriter.StartIteratorBody (ec.ig);
663 original_block.Emit (ec);
664 SymbolWriter.EndIteratorBody (ec.ig);
666 ig.MarkLabel (move_next_error);
667 ig.Emit (OpCodes.Ldc_I4_0);
668 ig.Emit (OpCodes.Ret);
671 internal void EmitMoveNext (EmitContext ec, Block original_block)
673 ILGenerator ig = ec.ig;
675 move_next_ok = ig.DefineLabel ();
676 move_next_error = ig.DefineLabel ();
678 if (resume_points == null) {
679 EmitMoveNext_NoResumePoints (ec, original_block);
683 current_pc = ec.GetTemporaryLocal (TypeManager.uint32_type);
684 ig.Emit (OpCodes.Ldarg_0);
685 ig.Emit (OpCodes.Ldfld, IteratorHost.PC.FieldBuilder);
686 ig.Emit (OpCodes.Stloc, current_pc);
688 // We're actually in state 'running', but this is as good a PC value as any if there's an abnormal exit
689 ig.Emit (OpCodes.Ldarg_0);
690 IntConstant.EmitInt (ig, (int) State.After);
691 ig.Emit (OpCodes.Stfld, IteratorHost.PC.FieldBuilder);
693 Label [] labels = new Label [1 + resume_points.Count];
694 labels [0] = ig.DefineLabel ();
696 bool need_skip_finally = false;
697 for (int i = 0; i < resume_points.Count; ++i) {
698 ResumableStatement s = (ResumableStatement) resume_points [i];
699 need_skip_finally |= s is ExceptionStatement;
700 labels [i+1] = s.PrepareForEmit (ec);
703 if (need_skip_finally) {
704 skip_finally = ec.GetTemporaryLocal (TypeManager.bool_type);
705 ig.Emit (OpCodes.Ldc_I4_0);
706 ig.Emit (OpCodes.Stloc, skip_finally);
709 SymbolWriter.StartIteratorDispatcher (ec.ig);
710 ig.Emit (OpCodes.Ldloc, current_pc);
711 ig.Emit (OpCodes.Switch, labels);
713 ig.Emit (OpCodes.Br, move_next_error);
714 SymbolWriter.EndIteratorDispatcher (ec.ig);
716 ig.MarkLabel (labels [0]);
718 SymbolWriter.StartIteratorBody (ec.ig);
719 original_block.Emit (ec);
720 SymbolWriter.EndIteratorBody (ec.ig);
722 SymbolWriter.StartIteratorDispatcher (ec.ig);
724 ig.Emit (OpCodes.Ldarg_0);
725 IntConstant.EmitInt (ig, (int) State.After);
726 ig.Emit (OpCodes.Stfld, IteratorHost.PC.FieldBuilder);
728 ig.MarkLabel (move_next_error);
729 ig.Emit (OpCodes.Ldc_I4_0);
730 ig.Emit (OpCodes.Ret);
732 ig.MarkLabel (move_next_ok);
733 ig.Emit (OpCodes.Ldc_I4_1);
734 ig.Emit (OpCodes.Ret);
736 SymbolWriter.EndIteratorDispatcher (ec.ig);
739 public void EmitDispose (EmitContext ec)
741 ILGenerator ig = ec.ig;
743 Label end = ig.DefineLabel ();
745 Label [] labels = null;
746 int n_resume_points = resume_points == null ? 0 : resume_points.Count;
747 for (int i = 0; i < n_resume_points; ++i) {
748 ResumableStatement s = (ResumableStatement) resume_points [i];
749 Label ret = s.PrepareForDispose (ec, end);
750 if (ret.Equals (end) && labels == null)
752 if (labels == null) {
753 labels = new Label [resume_points.Count + 1];
754 for (int j = 0; j <= i; ++j)
760 if (labels != null) {
761 current_pc = ec.GetTemporaryLocal (TypeManager.uint32_type);
762 ig.Emit (OpCodes.Ldarg_0);
763 ig.Emit (OpCodes.Ldfld, IteratorHost.PC.FieldBuilder);
764 ig.Emit (OpCodes.Stloc, current_pc);
767 ig.Emit (OpCodes.Ldarg_0);
768 IntConstant.EmitInt (ig, (int) State.After);
769 ig.Emit (OpCodes.Stfld, IteratorHost.PC.FieldBuilder);
771 if (labels != null) {
772 //SymbolWriter.StartIteratorDispatcher (ec.ig);
773 ig.Emit (OpCodes.Ldloc, current_pc);
774 ig.Emit (OpCodes.Switch, labels);
775 //SymbolWriter.EndIteratorDispatcher (ec.ig);
777 foreach (ResumableStatement s in resume_points)
778 s.EmitForDispose (ec, this, end, true);
784 ArrayList resume_points;
785 public int AddResumePoint (ResumableStatement stmt, Location loc)
787 if (resume_points == null)
788 resume_points = new ArrayList ();
789 resume_points.Add (stmt);
790 return resume_points.Count;
794 // Called back from Yield
796 public void MarkYield (EmitContext ec, Expression expr, int resume_pc, bool unwind_protect, Label resume_point)
798 ILGenerator ig = ec.ig;
800 // Store the new current
801 ig.Emit (OpCodes.Ldarg_0);
803 ig.Emit (OpCodes.Stfld, IteratorHost.CurrentField.FieldBuilder);
805 // store resume program-counter
806 ig.Emit (OpCodes.Ldarg_0);
807 IntConstant.EmitInt (ig, resume_pc);
808 ig.Emit (OpCodes.Stfld, IteratorHost.PC.FieldBuilder);
810 // mark finally blocks as disabled
811 if (unwind_protect && skip_finally != null) {
812 ig.Emit (OpCodes.Ldc_I4_1);
813 ig.Emit (OpCodes.Stloc, skip_finally);
817 ig.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, move_next_ok);
819 ig.MarkLabel (resume_point);
822 public override string ContainerType {
823 get { return "iterator"; }
826 public override bool IsIterator {
830 public override RootScopeInfo RootScope {
831 get { return IteratorHost; }
834 public override ScopeInfo Scope {
835 get { return IteratorHost; }
841 private Iterator (IMethodData m_container, DeclSpace host, GenericMethod generic,
842 int modifiers, Type iterator_type, bool is_enumerable)
843 : base (host, generic, m_container.ParameterInfo,
844 new ToplevelBlock (m_container.ParameterInfo, m_container.Location),
845 m_container.Block, TypeManager.bool_type, modifiers,
846 m_container.Location)
848 this.OriginalBlock = m_container.Block;
849 this.OriginalMethod = m_container;
850 this.OriginalIteratorType = iterator_type;
851 this.IsEnumerable = is_enumerable;
853 Report.Debug (64, "NEW ITERATOR", host, generic, OriginalBlock,
856 IteratorHost = new IteratorHost (this);
857 Block.CreateIteratorHost (IteratorHost);
859 OriginalBlock.ReParent (Container.Toplevel);
861 m_container.Block = Container.Toplevel;
863 OriginalBlock.MakeIterator (this);
866 protected class TestStatement : Statement
868 public override bool Resolve (EmitContext ec)
873 protected override void DoEmit (EmitContext ec)
875 ec.ig.Emit (OpCodes.Nop);
876 ec.ig.Emit (OpCodes.Neg);
877 ec.ig.Emit (OpCodes.Pop);
878 ec.ig.Emit (OpCodes.Ret);
882 public override string GetSignatureForError ()
884 return OriginalMethod.GetSignatureForError ();
887 public override bool Define (EmitContext ec)
889 Report.Debug (64, "RESOLVE ITERATOR", this, Container, Block);
891 Parameters parameters = OriginalMethod.ParameterInfo;
892 for (int i = 0; i < parameters.Count; i++){
893 Parameter.Modifier mod = parameters.ParameterModifier (i);
894 if ((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) != 0){
895 Report.Error (1623, Location,
896 "Iterators cannot have ref or out parameters");
900 if ((mod & Parameter.Modifier.ARGLIST) != 0) {
901 Report.Error (1636, Location,
902 "__arglist is not allowed in parameter list " +
907 if (parameters.ParameterType (i).IsPointer) {
908 Report.Error (1637, Location,
909 "Iterators cannot have unsafe parameters or " +
915 if ((ModFlags & Modifiers.UNSAFE) != 0) {
916 Report.Error (1629, Location, "Unsafe code may not appear in iterators");
920 if (!base.Define (ec))
923 Report.Debug (64, "RESOLVE ITERATOR #1", this, method, method.Parent,
926 if (!RootScope.ResolveType ())
928 if (!RootScope.ResolveMembers ())
930 if (!RootScope.DefineMembers ())
933 ExpressionStatement scope_init = RootScope.GetScopeInitializer (ec);
934 Container.AddStatement (new StatementExpression (scope_init));
935 Expression cast = new ClassCast (scope_init, OriginalMethod.ReturnType);
936 Container.AddStatement (new NoCheckReturn (cast));
941 protected override Method DoCreateMethodHost (EmitContext ec)
943 Report.Debug (128, "CREATE METHOD HOST", this, IteratorHost);
945 MemberCore mc = ec.ResolveContext as MemberCore;
947 IteratorHost.CaptureScopes ();
949 return new AnonymousMethodMethod (
950 this, RootScope, null, TypeManager.system_boolean_expr,
951 Modifiers.PUBLIC, mc.GetSignatureForError (),
952 new MemberName ("MoveNext", Location),
953 Parameters.EmptyReadOnlyParameters);
956 public override Expression DoResolve (EmitContext ec)
958 throw new NotSupportedException ();
961 public Type IteratorType {
962 get { return IteratorHost.IteratorType; }
966 // This return statement tricks return into not flagging an error for being
967 // used in a Yields method
969 class NoCheckReturn : Statement {
970 public Expression Expr;
972 public NoCheckReturn (Expression expr)
978 public override bool Resolve (EmitContext ec)
980 Expr = Expr.Resolve (ec);
984 ec.CurrentBranching.CurrentUsageVector.Goto ();
989 protected override void DoEmit (EmitContext ec)
992 ec.ig.Emit (OpCodes.Ret);
996 public override Expression CreateExpressionTree (EmitContext ec)
998 throw new NotSupportedException ("ET");
1001 public static Iterator CreateIterator (IMethodData method, DeclSpace parent,
1002 GenericMethod generic, int modifiers)
1007 Type ret = method.ReturnType;
1011 if (!CheckType (ret, out iterator_type, out is_enumerable)) {
1012 Report.Error (1624, method.Location,
1013 "The body of `{0}' cannot be an iterator block " +
1014 "because `{1}' is not an iterator interface type",
1015 method.GetSignatureForError (),
1016 TypeManager.CSharpName (ret));
1020 return new Iterator (method, parent, generic, modifiers,
1021 iterator_type, is_enumerable);
1024 static bool CheckType (Type ret, out Type original_iterator_type, out bool is_enumerable)
1026 original_iterator_type = null;
1027 is_enumerable = false;
1029 if (ret == TypeManager.ienumerable_type) {
1030 original_iterator_type = TypeManager.object_type;
1031 is_enumerable = true;
1034 if (ret == TypeManager.ienumerator_type) {
1035 original_iterator_type = TypeManager.object_type;
1036 is_enumerable = false;
1041 if (!ret.IsGenericType)
1044 Type[] args = TypeManager.GetTypeArguments (ret);
1045 if (args.Length != 1)
1048 Type gt = ret.GetGenericTypeDefinition ();
1049 if (gt == TypeManager.generic_ienumerable_type) {
1050 original_iterator_type = args [0];
1051 is_enumerable = true;
1053 } else if (gt == TypeManager.generic_ienumerator_type) {
1054 original_iterator_type = args [0];
1055 is_enumerable = false;