2 // iterators.cs: Support for implementing iterators
5 // Miguel de Icaza (miguel@ximian.com)
7 // (C) 2003 Ximian, Inc.
10 // Flow analysis for Yield.
11 // Emit calls to base object constructor.
14 // Current should be defined to return T, and IEnumerator.Current returns object
18 using System
.Collections
;
19 using System
.Reflection
;
20 using System
.Reflection
.Emit
;
22 namespace Mono
.CSharp
{
24 public class Yield
: Statement
{
26 ArrayList finally_blocks
;
28 public Yield (Expression expr
, Location l
)
34 public static bool CheckContext (EmitContext ec
, Location loc
, bool isYieldBreak
)
37 Report
.Error (1625, loc
, "Cannot yield in the body of a " +
42 for (Block block
= ec
.CurrentBlock
; block
!= null; block
= block
.Parent
) {
46 Report
.Error (1629, loc
, "Unsafe code may not appear in iterators");
51 // We can't use `ec.InUnsafe' here because it's allowed to have an iterator
52 // inside an unsafe class. See test-martin-29.cs for an example.
54 if (!ec
.CurrentAnonymousMethod
.IsIterator
) {
55 Report
.Error (1621, loc
,
56 "The yield statement cannot be used inside " +
57 "anonymous method blocks");
61 if (ec
.CurrentBranching
.InTryWithCatch () && (!isYieldBreak
|| !ec
.InCatch
)) {
63 Report
.Error (1626, loc
, "Cannot yield a value in the body " +
64 "of a try block with a catch clause");
66 Report
.Error (1631, loc
, "Cannot yield a value in the body " +
74 public override bool Resolve (EmitContext ec
)
76 Report
.Debug (64, "RESOLVE YIELD", this, ec
, expr
, expr
.GetType ());
77 expr
= expr
.Resolve (ec
);
81 Report
.Debug (64, "RESOLVE YIELD #1", this, ec
, expr
, expr
.GetType (),
82 ec
.CurrentAnonymousMethod
, ec
.CurrentIterator
);
84 if (!CheckContext (ec
, loc
, false))
87 Iterator iterator
= ec
.CurrentIterator
;
88 if (expr
.Type
!= iterator
.IteratorType
) {
89 expr
= Convert
.ImplicitConversionRequired (
90 ec
, expr
, iterator
.IteratorType
, loc
);
95 ec
.CurrentBranching
.StealFinallyClauses (ref finally_blocks
);
99 protected override void DoEmit (EmitContext ec
)
101 ec
.CurrentIterator
.MarkYield (ec
, expr
, finally_blocks
);
104 protected override void CloneTo (CloneContext clonectx
, Statement t
)
106 Yield target
= (Yield
) t
;
108 target
.expr
= expr
.Clone (clonectx
);
112 public class YieldBreak
: Statement
{
114 public YieldBreak (Location l
)
119 public override bool Resolve (EmitContext ec
)
121 if (!Yield
.CheckContext (ec
, loc
, true))
124 ec
.CurrentBranching
.CurrentUsageVector
.Goto ();
128 protected override void DoEmit (EmitContext ec
)
130 ec
.CurrentIterator
.EmitYieldBreak (ec
.ig
);
134 public class IteratorHost
: RootScopeInfo
136 public readonly Iterator Iterator
;
138 TypeExpr iterator_type_expr
;
141 MethodInfo dispose_method
;
143 TypeExpr enumerator_type
;
144 TypeExpr enumerable_type
;
145 TypeArguments generic_args
;
146 TypeExpr generic_enumerator_type
;
147 TypeExpr generic_enumerable_type
;
149 public IteratorHost (Iterator iterator
)
150 : base (iterator
.Container
.Toplevel
, iterator
.Host
, iterator
.GenericMethod
,
153 this.Iterator
= iterator
;
156 public override bool IsIterator
{
160 public MethodInfo Dispose
{
161 get { return dispose_method; }
165 get { return pc_field; }
168 public Field CurrentField
{
169 get { return current_field; }
172 public Type IteratorType
{
173 get { return iterator_type_expr.Type; }
176 public override TypeExpr
[] GetClassBases (out TypeExpr base_class
)
178 iterator_type_expr
= InflateType (Iterator
.OriginalIteratorType
);
181 generic_args
= new TypeArguments (Location
);
182 generic_args
.Add (iterator_type_expr
);
185 ArrayList list
= new ArrayList ();
186 if (Iterator
.IsEnumerable
) {
187 enumerable_type
= new TypeExpression (
188 TypeManager
.ienumerable_type
, Location
);
189 list
.Add (enumerable_type
);
192 generic_enumerable_type
= new ConstructedType (
193 TypeManager
.generic_ienumerable_type
,
194 generic_args
, Location
);
195 list
.Add (generic_enumerable_type
);
199 enumerator_type
= new TypeExpression (
200 TypeManager
.ienumerator_type
, Location
);
201 list
.Add (enumerator_type
);
203 list
.Add (new TypeExpression (TypeManager
.idisposable_type
, Location
));
206 generic_enumerator_type
= new ConstructedType (
207 TypeManager
.generic_ienumerator_type
,
208 generic_args
, Location
);
209 list
.Add (generic_enumerator_type
);
214 return base.GetClassBases (out base_class
);
217 protected override bool DoResolveMembers ()
219 pc_field
= CaptureVariable ("$PC", TypeManager
.system_int32_expr
);
220 current_field
= CaptureVariable ("$current", iterator_type_expr
);
223 Define_Current (true);
225 Define_Current (false);
226 new DisposeMethod (this);
229 if (Iterator
.IsEnumerable
) {
230 new GetEnumeratorMethod (this, false);
232 new GetEnumeratorMethod (this, true);
236 return base.DoResolveMembers ();
239 public void CaptureScopes ()
241 Report
.Debug (128, "DEFINE ITERATOR HOST", this, scopes
);
243 foreach (ScopeInfo si
in scopes
)
246 foreach (ScopeInfo si
in scopes
) {
248 throw new InternalErrorException ();
249 if (si
.DefineType () == null)
250 throw new InternalErrorException ();
251 if (!si
.ResolveType ())
252 throw new InternalErrorException ();
253 if (!si
.ResolveMembers ())
254 throw new InternalErrorException ();
255 if (!si
.DefineMembers ())
256 throw new InternalErrorException ();
260 protected override bool DoDefineMembers ()
262 if (!base.DoDefineMembers ())
265 FetchMethodDispose ();
270 protected override void EmitScopeConstructor (EmitContext ec
)
272 ec
.ig
.Emit (OpCodes
.Ldarg_0
);
273 ec
.ig
.Emit (OpCodes
.Ldarg_1
);
274 ec
.ig
.Emit (OpCodes
.Stfld
, pc_field
.FieldBuilder
);
275 base.EmitScopeConstructor (ec
);
278 void FetchMethodDispose ()
280 MemberList dispose_list
;
282 dispose_list
= FindMembers (
283 CurrentType
!= null ? CurrentType
: TypeBuilder
,
284 MemberTypes
.Method
, BindingFlags
.Public
| BindingFlags
.Instance
,
285 Type
.FilterName
, "Dispose");
287 if (dispose_list
.Count
!= 1)
288 throw new InternalErrorException ("Cannot find Dipose() method.");
290 dispose_method
= (MethodInfo
) dispose_list
[0];
293 void Define_Current (bool is_generic
)
299 left
= new MemberName (
300 "System.Collections.Generic.IEnumerator",
301 generic_args
, Location
);
302 type
= iterator_type_expr
;
304 left
= new MemberName ("System.Collections.IEnumerator", Location
);
305 type
= TypeManager
.system_object_expr
;
308 MemberName name
= new MemberName (left
, "Current", null, Location
);
310 ToplevelBlock get_block
= new ToplevelBlock (Location
);
311 get_block
.AddStatement (new CurrentBlock (this, is_generic
));
313 Accessor getter
= new Accessor (get_block
, 0, null, Location
);
315 Property current
= new Property (
316 this, type
, 0, false, name
, null, getter
, null, false);
317 AddProperty (current
);
322 Method reset
= new Method (
323 this, null, TypeManager
.system_void_expr
, Modifiers
.PUBLIC
,
324 false, new MemberName ("Reset", Location
),
325 Parameters
.EmptyReadOnlyParameters
, null);
328 reset
.Block
= new ToplevelBlock (Location
);
329 reset
.Block
.AddStatement (Create_ThrowNotSupported ());
332 Statement
Create_ThrowNotSupported ()
334 TypeExpr ex_type
= new TypeExpression (
335 TypeManager
.not_supported_exception_type
, Location
);
337 return new Throw (new New (ex_type
, null, Location
), Location
);
340 ConstructorInfo
GetInvalidOperationException ()
342 return TypeManager
.GetConstructor (
343 TypeManager
.invalid_operation_exception_type
, Type
.EmptyTypes
);
346 protected override ScopeInitializer
CreateScopeInitializer ()
348 return new IteratorHostInitializer (this);
351 protected class IteratorHostInitializer
: RootScopeInitializer
353 new public readonly IteratorHost Host
;
354 protected Iterator
.State state
;
356 public IteratorHostInitializer (IteratorHost host
)
362 protected override bool DoResolveInternal (EmitContext ec
)
364 if (this is EnumeratorScopeInitializer
)
365 state
= Iterator
.State
.Running
;
366 else if (Host
.Iterator
.IsEnumerable
)
367 state
= Iterator
.State
.Uninitialized
;
369 state
= Iterator
.State
.Running
;
371 return base.DoResolveInternal (ec
);
374 protected override void EmitScopeConstructor (EmitContext ec
)
376 ec
.ig
.Emit (OpCodes
.Ldc_I4
, (int) state
);
377 base.EmitScopeConstructor (ec
);
381 protected class GetEnumeratorMethod
: Method
383 public IteratorHost Host
;
385 static MemberName
GetMemberName (IteratorHost host
, bool is_generic
)
389 left
= new MemberName (
390 "System.Collections.Generic.IEnumerable",
391 host
.generic_args
, host
.Location
);
393 left
= new MemberName (
394 "System.Collections.IEnumerable", host
.Location
);
397 return new MemberName (left
, "GetEnumerator", host
.Location
);
400 public GetEnumeratorMethod (IteratorHost host
, bool is_generic
)
401 : base (host
, null, is_generic
?
402 host
.generic_enumerator_type
: host
.enumerator_type
,
403 0, false, GetMemberName (host
, is_generic
),
404 Parameters
.EmptyReadOnlyParameters
, null)
408 host
.AddMethod (this);
410 Block
= new ToplevelBlock (host
.Iterator
.Container
.Toplevel
, null, Location
);
411 Block
.AddStatement (new GetEnumeratorStatement (host
, Type
));
414 public override EmitContext
CreateEmitContext (DeclSpace tc
, ILGenerator ig
)
416 EmitContext ec
= new EmitContext (
417 this, tc
, this.ds
, Location
, ig
, MemberType
, ModFlags
, false);
419 ec
.CurrentAnonymousMethod
= Host
.Iterator
;
423 protected class GetEnumeratorStatement
: Statement
428 ExpressionStatement initializer
;
432 public GetEnumeratorStatement (IteratorHost host
, Expression type
)
439 public override bool Resolve (EmitContext ec
)
441 type
= type
.ResolveAsTypeTerminal (ec
, false);
442 if ((type
== null) || (type
.Type
== null))
445 initializer
= host
.GetEnumeratorInitializer (ec
);
446 if (initializer
== null)
449 cast
= new ClassCast (initializer
, type
.Type
);
451 ce
= TypeManager
.int_interlocked_compare_exchange
;
453 ec
.CurrentBranching
.CurrentUsageVector
.Goto ();
457 protected override void DoEmit (EmitContext ec
)
459 ILGenerator ig
= ec
.ig
;
460 Label label_init
= ig
.DefineLabel ();
462 ig
.Emit (OpCodes
.Ldarg_0
);
463 ig
.Emit (OpCodes
.Ldflda
, host
.PC
.FieldBuilder
);
464 ig
.Emit (OpCodes
.Ldc_I4
, (int) Iterator
.State
.Running
);
465 ig
.Emit (OpCodes
.Ldc_I4
, (int) Iterator
.State
.Uninitialized
);
466 ig
.Emit (OpCodes
.Call
, ce
);
468 ig
.Emit (OpCodes
.Ldc_I4
, (int) Iterator
.State
.Uninitialized
);
469 ig
.Emit (OpCodes
.Bne_Un
, label_init
);
471 ig
.Emit (OpCodes
.Ldarg_0
);
472 ig
.Emit (OpCodes
.Ret
);
474 ig
.MarkLabel (label_init
);
476 initializer
.EmitStatement (ec
);
478 ig
.Emit (OpCodes
.Ret
);
483 protected class DisposeMethod
: Method
485 public IteratorHost Host
;
487 public DisposeMethod (IteratorHost host
)
488 : base (host
, null, TypeManager
.system_void_expr
, Modifiers
.PUBLIC
,
489 false, new MemberName ("Dispose", host
.Location
),
490 Parameters
.EmptyReadOnlyParameters
, null)
494 host
.AddMethod (this);
496 Block
= new ToplevelBlock (host
.Iterator
.Block
, null, Location
);
497 Block
.AddStatement (new DisposeMethodStatement (Host
.Iterator
));
499 Report
.Debug (64, "DISPOSE METHOD", host
, Block
);
502 public override EmitContext
CreateEmitContext (DeclSpace tc
, ILGenerator ig
)
504 EmitContext ec
= new EmitContext (
505 this, tc
, this.ds
, Location
, ig
, MemberType
, ModFlags
, false);
507 ec
.CurrentAnonymousMethod
= Host
.Iterator
;
511 protected class DisposeMethodStatement
: Statement
515 public DisposeMethodStatement (Iterator iterator
)
517 this.iterator
= iterator
;
518 this.loc
= iterator
.Location
;
521 public override bool Resolve (EmitContext ec
)
526 protected override void DoEmit (EmitContext ec
)
528 iterator
.EmitDispose (ec
);
533 protected ScopeInitializer
GetEnumeratorInitializer (EmitContext ec
)
535 ScopeInitializer init
= new EnumeratorScopeInitializer (this);
536 if (init
.Resolve (ec
) == null)
537 throw new InternalErrorException ();
541 protected class EnumeratorScopeInitializer
: IteratorHostInitializer
545 public EnumeratorScopeInitializer (IteratorHost host
)
551 protected override bool DoResolveInternal (EmitContext ec
)
553 type
= host
.IsGeneric
? host
.CurrentType
: host
.TypeBuilder
;
554 return base.DoResolveInternal (ec
);
557 protected override void DoEmit (EmitContext ec
)
562 protected override bool IsGetEnumerator
{
566 protected override void EmitParameterReference (EmitContext ec
,
567 CapturedParameter cp
)
569 ec
.ig
.Emit (OpCodes
.Ldarg_0
);
570 ec
.ig
.Emit (OpCodes
.Ldfld
, cp
.Field
.FieldBuilder
);
574 protected class CurrentBlock
: Statement
{
578 public CurrentBlock (IteratorHost host
, bool is_generic
)
581 this.is_generic
= is_generic
;
585 public override bool Resolve (EmitContext ec
)
587 ec
.CurrentBranching
.CurrentUsageVector
.Goto ();
591 protected override void DoEmit (EmitContext ec
)
593 ILGenerator ig
= ec
.ig
;
594 Label label_ok
= ig
.DefineLabel ();
596 ig
.Emit (OpCodes
.Ldarg_0
);
597 ig
.Emit (OpCodes
.Ldfld
, host
.PC
.FieldBuilder
);
598 ig
.Emit (OpCodes
.Ldc_I4
, (int) Iterator
.State
.Running
);
599 ig
.Emit (OpCodes
.Bgt
, label_ok
);
601 ig
.Emit (OpCodes
.Newobj
, host
.GetInvalidOperationException ());
602 ig
.Emit (OpCodes
.Throw
);
604 ig
.MarkLabel (label_ok
);
605 ig
.Emit (OpCodes
.Ldarg_0
);
606 ig
.Emit (OpCodes
.Ldfld
, host
.CurrentField
.FieldBuilder
);
608 ig
.Emit (OpCodes
.Box
, host
.CurrentField
.MemberType
);
609 ig
.Emit (OpCodes
.Ret
);
614 public class Iterator
: AnonymousContainer
{
615 protected readonly ToplevelBlock OriginalBlock
;
616 protected readonly IMethodData OriginalMethod
;
617 protected ToplevelBlock block
;
619 public readonly bool IsEnumerable
;
620 public readonly bool IsStatic
;
623 // The state as we generate the iterator
625 Label move_next_ok
, move_next_error
;
626 ArrayList resume_points
= new ArrayList ();
629 public readonly Type OriginalIteratorType
;
630 public readonly IteratorHost IteratorHost
;
638 public void EmitYieldBreak (ILGenerator ig
)
640 ig
.Emit (OpCodes
.Ldarg_0
);
641 IntConstant
.EmitInt (ig
, (int) State
.After
);
642 ig
.Emit (OpCodes
.Stfld
, IteratorHost
.PC
.FieldBuilder
);
643 ig
.Emit (OpCodes
.Br
, move_next_error
);
646 internal void EmitMoveNext (EmitContext ec
, Block original_block
)
648 ILGenerator ig
= ec
.ig
;
650 move_next_ok
= ig
.DefineLabel ();
651 move_next_error
= ig
.DefineLabel ();
653 LocalBuilder retval
= ec
.GetTemporaryLocal (TypeManager
.int32_type
);
655 ig
.BeginExceptionBlock ();
657 Label dispatcher
= ig
.DefineLabel ();
658 ig
.Emit (OpCodes
.Br
, dispatcher
);
660 ResumePoint entry_point
= new ResumePoint (null);
661 resume_points
.Add (entry_point
);
662 entry_point
.Define (ig
);
664 original_block
.Emit (ec
);
668 ig
.MarkLabel (dispatcher
);
670 Label
[] labels
= new Label
[resume_points
.Count
];
671 for (int i
= 0; i
< labels
.Length
; i
++)
672 labels
[i
] = ((ResumePoint
) resume_points
[i
]).Label
;
674 ig
.Emit (OpCodes
.Ldarg_0
);
675 ig
.Emit (OpCodes
.Ldfld
, IteratorHost
.PC
.FieldBuilder
);
676 ig
.Emit (OpCodes
.Switch
, labels
);
678 Label end
= ig
.DefineLabel ();
680 ig
.MarkLabel (move_next_error
);
681 ig
.Emit (OpCodes
.Ldc_I4_0
);
682 ig
.Emit (OpCodes
.Stloc
, retval
);
683 ig
.Emit (OpCodes
.Leave
, end
);
685 ig
.MarkLabel (move_next_ok
);
686 ig
.Emit (OpCodes
.Ldc_I4_1
);
687 ig
.Emit (OpCodes
.Stloc
, retval
);
688 ig
.Emit (OpCodes
.Leave
, end
);
690 ig
.BeginFaultBlock ();
692 ig
.Emit (OpCodes
.Ldarg_0
);
693 ig
.Emit (OpCodes
.Callvirt
, IteratorHost
.Dispose
);
695 ig
.EndExceptionBlock ();
698 ig
.Emit (OpCodes
.Ldloc
, retval
);
699 ig
.Emit (OpCodes
.Ret
);
702 public void EmitDispose (EmitContext ec
)
704 ILGenerator ig
= ec
.ig
;
706 Label end
= ig
.DefineLabel ();
707 Label dispatcher
= ig
.DefineLabel ();
708 ig
.Emit (OpCodes
.Br
, dispatcher
);
710 Label
[] labels
= new Label
[resume_points
.Count
];
711 for (int i
= 0; i
< labels
.Length
; i
++) {
712 ResumePoint point
= (ResumePoint
) resume_points
[i
];
714 if (point
.FinallyBlocks
== null) {
719 labels
[i
] = ig
.DefineLabel ();
720 ig
.MarkLabel (labels
[i
]);
722 ig
.BeginExceptionBlock ();
723 ig
.BeginFinallyBlock ();
725 foreach (ExceptionStatement stmt
in point
.FinallyBlocks
) {
727 stmt
.EmitFinally (ec
);
730 ig
.EndExceptionBlock ();
731 ig
.Emit (OpCodes
.Br
, end
);
734 ig
.MarkLabel (dispatcher
);
735 ig
.Emit (OpCodes
.Ldarg_0
);
736 ig
.Emit (OpCodes
.Ldfld
, IteratorHost
.PC
.FieldBuilder
);
737 ig
.Emit (OpCodes
.Switch
, labels
);
739 ig
.Emit (OpCodes
.Ldarg_0
);
740 IntConstant
.EmitInt (ig
, (int) State
.After
);
741 ig
.Emit (OpCodes
.Stfld
, IteratorHost
.PC
.FieldBuilder
);
746 protected class ResumePoint
749 public readonly ExceptionStatement
[] FinallyBlocks
;
751 public ResumePoint (ArrayList list
)
754 FinallyBlocks
= new ExceptionStatement
[list
.Count
];
755 list
.CopyTo (FinallyBlocks
, 0);
759 public void Define (ILGenerator ig
)
761 Label
= ig
.DefineLabel ();
762 ig
.MarkLabel (Label
);
767 // Called back from Yield
769 public void MarkYield (EmitContext ec
, Expression expr
,
770 ArrayList finally_blocks
)
772 ILGenerator ig
= ec
.ig
;
774 // Store the new current
775 ig
.Emit (OpCodes
.Ldarg_0
);
777 ig
.Emit (OpCodes
.Stfld
, IteratorHost
.CurrentField
.FieldBuilder
);
781 ig
.Emit (OpCodes
.Ldarg_0
);
782 IntConstant
.EmitInt (ig
, pc
);
783 ig
.Emit (OpCodes
.Stfld
, IteratorHost
.PC
.FieldBuilder
);
786 ig
.Emit (OpCodes
.Br
, move_next_ok
);
788 ResumePoint point
= new ResumePoint (finally_blocks
);
789 resume_points
.Add (point
);
793 public void MarkFinally (EmitContext ec
, ArrayList finally_blocks
)
795 ILGenerator ig
= ec
.ig
;
799 ig
.Emit (OpCodes
.Ldarg_0
);
800 IntConstant
.EmitInt (ig
, pc
);
801 ig
.Emit (OpCodes
.Stfld
, IteratorHost
.PC
.FieldBuilder
);
803 ResumePoint point
= new ResumePoint (finally_blocks
);
804 resume_points
.Add (point
);
808 public override bool IsIterator
{
812 public override RootScopeInfo RootScope
{
813 get { return IteratorHost; }
816 public override ScopeInfo Scope
{
817 get { return IteratorHost; }
823 private Iterator (IMethodData m_container
, DeclSpace host
, GenericMethod generic
,
824 int modifiers
, Type iterator_type
, bool is_enumerable
)
825 : base (null, host
, generic
, m_container
.ParameterInfo
,
826 new ToplevelBlock (m_container
.ParameterInfo
, m_container
.Location
),
827 m_container
.Block
, TypeManager
.bool_type
, modifiers
,
828 m_container
.Location
)
830 this.OriginalBlock
= m_container
.Block
;
831 this.OriginalMethod
= m_container
;
832 this.OriginalIteratorType
= iterator_type
;
833 this.IsEnumerable
= is_enumerable
;
835 Report
.Debug (64, "NEW ITERATOR", host
, generic
, OriginalBlock
,
838 IteratorHost
= new IteratorHost (this);
839 Block
.CreateIteratorHost (IteratorHost
);
841 OriginalBlock
.ReParent (Container
.Toplevel
);
843 m_container
.Block
= Container
.Toplevel
;
845 OriginalBlock
.MakeIterator (this);
848 protected class TestStatement
: Statement
850 public override bool Resolve (EmitContext ec
)
855 protected override void DoEmit (EmitContext ec
)
857 ec
.ig
.Emit (OpCodes
.Nop
);
858 ec
.ig
.Emit (OpCodes
.Neg
);
859 ec
.ig
.Emit (OpCodes
.Pop
);
860 ec
.ig
.Emit (OpCodes
.Ret
);
864 public override string GetSignatureForError ()
866 return OriginalMethod
.GetSignatureForError ();
869 public override bool Resolve (EmitContext ec
)
871 Report
.Debug (64, "RESOLVE ITERATOR", this, Container
, Block
);
873 Parameters parameters
= OriginalMethod
.ParameterInfo
;
874 for (int i
= 0; i
< parameters
.Count
; i
++){
875 Parameter
.Modifier mod
= parameters
.ParameterModifier (i
);
876 if ((mod
& (Parameter
.Modifier
.REF
| Parameter
.Modifier
.OUT
)) != 0){
877 Report
.Error (1623, Location
,
878 "Iterators cannot have ref or out parameters");
882 if ((mod
& Parameter
.Modifier
.ARGLIST
) != 0) {
883 Report
.Error (1636, Location
,
884 "__arglist is not allowed in parameter list " +
889 if (parameters
.ParameterType (i
).IsPointer
) {
890 Report
.Error (1637, Location
,
891 "Iterators cannot have unsafe parameters or " +
897 if ((ModFlags
& Modifiers
.UNSAFE
) != 0) {
898 Report
.Error (1629, Location
, "Unsafe code may not appear in iterators");
902 if (!base.Resolve (ec
))
905 Report
.Debug (64, "RESOLVE ITERATOR #1", this, method
, method
.Parent
,
908 if (!RootScope
.ResolveType ())
910 if (!RootScope
.ResolveMembers ())
912 if (!RootScope
.DefineMembers ())
915 ExpressionStatement scope_init
= RootScope
.GetScopeInitializer (ec
);
916 Container
.AddStatement (new StatementExpression (scope_init
));
917 Expression cast
= new ClassCast (scope_init
, OriginalMethod
.ReturnType
);
918 Container
.AddStatement (new NoCheckReturn (cast
));
923 protected override Method
DoCreateMethodHost (EmitContext ec
)
925 Report
.Debug (128, "CREATE METHOD HOST", this, IteratorHost
);
927 IteratorHost
.CaptureScopes ();
929 return new AnonymousMethodMethod (
930 this, RootScope
, null, TypeManager
.system_boolean_expr
,
931 Modifiers
.PUBLIC
, new MemberName ("MoveNext", Location
),
932 Parameters
.EmptyReadOnlyParameters
);
935 protected class MoveNextStatement
: Statement
{
938 public MoveNextStatement (Iterator iterator
, Location loc
)
941 this.iterator
= iterator
;
944 public override bool Resolve (EmitContext ec
)
946 return iterator
.OriginalBlock
.Resolve (ec
);
949 protected override void DoEmit (EmitContext ec
)
951 iterator
.EmitMoveNext (ec
, iterator
.Block
);
955 public Type IteratorType
{
956 get { return IteratorHost.IteratorType; }
960 // This return statement tricks return into not flagging an error for being
961 // used in a Yields method
963 class NoCheckReturn
: Statement
{
964 public Expression Expr
;
966 public NoCheckReturn (Expression expr
)
972 public override bool Resolve (EmitContext ec
)
974 Expr
= Expr
.Resolve (ec
);
978 ec
.CurrentBranching
.CurrentUsageVector
.Goto ();
983 protected override void DoEmit (EmitContext ec
)
986 ec
.ig
.Emit (OpCodes
.Ret
);
990 public static Iterator
CreateIterator (IMethodData method
, DeclSpace parent
,
991 GenericMethod generic
, int modifiers
)
996 Type ret
= method
.ReturnType
;
1000 if (!CheckType (ret
, out iterator_type
, out is_enumerable
)) {
1001 Report
.Error (1624, method
.Location
,
1002 "The body of `{0}' cannot be an iterator block " +
1003 "because `{1}' is not an iterator interface type",
1004 method
.GetSignatureForError (),
1005 TypeManager
.CSharpName (ret
));
1009 return new Iterator (method
, parent
, generic
, modifiers
,
1010 iterator_type
, is_enumerable
);
1013 static bool CheckType (Type ret
, out Type original_iterator_type
, out bool is_enumerable
)
1015 original_iterator_type
= null;
1016 is_enumerable
= false;
1018 if (ret
== TypeManager
.ienumerable_type
) {
1019 original_iterator_type
= TypeManager
.object_type
;
1020 is_enumerable
= true;
1023 if (ret
== TypeManager
.ienumerator_type
) {
1024 original_iterator_type
= TypeManager
.object_type
;
1025 is_enumerable
= false;
1030 if (!ret
.IsGenericType
)
1033 Type
[] args
= TypeManager
.GetTypeArguments (ret
);
1034 if (args
.Length
!= 1)
1037 Type gt
= ret
.GetGenericTypeDefinition ();
1038 if (gt
== TypeManager
.generic_ienumerable_type
) {
1039 original_iterator_type
= args
[0];
1040 is_enumerable
= true;
1042 } else if (gt
== TypeManager
.generic_ienumerator_type
) {
1043 original_iterator_type
= args
[0];
1044 is_enumerable
= false;