public class Yield : Statement {
public Expression expr;
- bool in_exc;
+ ArrayList finally_blocks;
public Yield (Expression expr, Location l)
{
if (!CheckContext (ec, loc))
return false;
- in_exc = ec.CurrentBranching.InTryOrCatch (false);
- Type iterator_type = ec.CurrentIterator.IteratorType;
- if (expr.Type != iterator_type){
- expr = Convert.ImplicitConversionRequired (ec, expr, iterator_type, loc);
+ Iterator iterator = ec.CurrentIterator;
+ if (expr.Type != iterator.IteratorType){
+ expr = Convert.ImplicitConversionRequired (
+ ec, expr, iterator.IteratorType, loc);
if (expr == null)
return false;
}
+
+ ec.CurrentBranching.StealFinallyClauses (ref finally_blocks);
return true;
}
protected override void DoEmit (EmitContext ec)
{
- ec.CurrentIterator.MarkYield (ec, expr, in_exc);
+ ec.CurrentIterator.MarkYield (ec, expr, finally_blocks);
}
}
protected override void DoEmit (EmitContext ec)
{
- ec.CurrentIterator.EmitYieldBreak (ec.ig, true);
+ ec.CurrentIterator.EmitYieldBreak (ec.ig);
}
}
public class Iterator : Class {
+ string original_name;
Block original_block;
Block block;
bool is_enumerable;
bool is_static;
+ Hashtable fields;
+
//
// The state as we generate the iterator
//
- ArrayList resume_labels = new ArrayList ();
+ Label move_next_ok, move_next_error;
+ ArrayList resume_points = new ArrayList ();
int pc;
//
Type [] param_types;
InternalParameters parameters;
+ Expression enumerator_type;
+ Expression enumerable_type;
+ Expression generic_enumerator_type;
+ Expression generic_enumerable_type;
+ TypeArguments generic_args;
+
+ protected enum State {
+ Uninitialized = -2,
+ After,
+ Running
+ }
+
static int proxy_count;
- public void EmitYieldBreak (ILGenerator ig, bool add_return)
+ public void EmitYieldBreak (ILGenerator ig)
{
ig.Emit (OpCodes.Ldarg_0);
- IntConstant.EmitInt (ig, -1);
- ig.Emit (OpCodes.Stfld, pc_field.FieldBuilder);
- if (add_return){
- ig.Emit (OpCodes.Ldc_I4_0);
- ig.Emit (OpCodes.Ret);
- }
+ IntConstant.EmitInt (ig, (int) State.After);
+ ig.Emit (OpCodes.Br, move_next_error);
}
public void EmitMoveNext (EmitContext ec)
{
ILGenerator ig = ec.ig;
+ move_next_ok = ig.DefineLabel ();
+ move_next_error = ig.DefineLabel ();
+
+ LocalBuilder retval = ec.GetTemporaryLocal (TypeManager.int32_type);
+
+ ig.BeginExceptionBlock ();
+
Label dispatcher = ig.DefineLabel ();
ig.Emit (OpCodes.Br, dispatcher);
- Label entry_point = ig.DefineLabel ();
- ig.MarkLabel (entry_point);
- resume_labels.Add (entry_point);
-
- ec.EmitTopBlock (original_block, parameters, Location);
- EmitYieldBreak (ig, true);
+ ResumePoint entry_point = new ResumePoint (null);
+ resume_points.Add (entry_point);
+ entry_point.Define (ig);
+
+ ec.EmitTopBlock (original_block, parameters, Location);
+ EmitYieldBreak (ig);
- //
- // FIXME: Split the switch in blocks that can be consumed
- // by switch.
- //
ig.MarkLabel (dispatcher);
- Label [] labels = new Label [resume_labels.Count];
- resume_labels.CopyTo (labels);
+ Label [] labels = new Label [resume_points.Count];
+ for (int i = 0; i < labels.Length; i++)
+ labels [i] = ((ResumePoint) resume_points [i]).Label;
+
ig.Emit (OpCodes.Ldarg_0);
ig.Emit (OpCodes.Ldfld, pc_field.FieldBuilder);
ig.Emit (OpCodes.Switch, labels);
- ig.Emit (OpCodes.Ldc_I4_0);
+
+ Label end = ig.DefineLabel ();
+
+ ig.MarkLabel (move_next_error);
+ ig.Emit (OpCodes.Ldc_I4_0);
+ ig.Emit (OpCodes.Stloc, retval);
+ ig.Emit (OpCodes.Leave, end);
+
+ ig.MarkLabel (move_next_ok);
+ ig.Emit (OpCodes.Ldc_I4_1);
+ ig.Emit (OpCodes.Stloc, retval);
+ ig.Emit (OpCodes.Leave, end);
+
+ ig.BeginFaultBlock ();
+
+ ig.Emit (OpCodes.Ldarg_0);
+ ig.Emit (OpCodes.Callvirt, dispose.MethodBuilder);
+
+ ig.EndExceptionBlock ();
+
+ ig.MarkLabel (end);
+ ig.Emit (OpCodes.Ldloc, retval);
ig.Emit (OpCodes.Ret);
}
+ public void EmitDispose (EmitContext ec)
+ {
+ ILGenerator ig = ec.ig;
+
+ Label end = ig.DefineLabel ();
+ Label dispatcher = ig.DefineLabel ();
+ ig.Emit (OpCodes.Br, dispatcher);
+
+ Label [] labels = new Label [resume_points.Count];
+ for (int i = 0; i < labels.Length; i++) {
+ ResumePoint point = (ResumePoint) resume_points [i];
+
+ if (point.FinallyBlocks == null) {
+ labels [i] = end;
+ continue;
+ }
+
+ labels [i] = ig.DefineLabel ();
+ ig.MarkLabel (labels [i]);
+
+ ig.BeginExceptionBlock ();
+ ig.BeginFinallyBlock ();
+
+ foreach (ExceptionStatement stmt in point.FinallyBlocks) {
+ if (stmt != null)
+ stmt.EmitFinally (ec);
+ }
+
+ ig.EndExceptionBlock ();
+ ig.Emit (OpCodes.Br, end);
+ }
+
+ ig.MarkLabel (dispatcher);
+ ig.Emit (OpCodes.Ldarg_0);
+ ig.Emit (OpCodes.Ldfld, pc_field.FieldBuilder);
+ ig.Emit (OpCodes.Switch, labels);
+
+ ig.Emit (OpCodes.Ldarg_0);
+ IntConstant.EmitInt (ig, (int) State.After);
+ ig.Emit (OpCodes.Stfld, pc_field.FieldBuilder);
+
+ ig.MarkLabel (end);
+ }
+
+ protected class ResumePoint
+ {
+ public Label Label;
+ public readonly ExceptionStatement[] FinallyBlocks;
+
+ public ResumePoint (ArrayList list)
+ {
+ if (list != null) {
+ FinallyBlocks = new ExceptionStatement [list.Count];
+ list.CopyTo (FinallyBlocks, 0);
+ }
+ }
+
+ public void Define (ILGenerator ig)
+ {
+ Label = ig.DefineLabel ();
+ ig.MarkLabel (Label);
+ }
+ }
+
//
// Invoked when a local variable declaration needs to be mapped to
// a field in our proxy class
//
public FieldBuilder MapVariable (string pfx, string name, Type t)
{
- return TypeBuilder.DefineField (pfx + name, t, FieldAttributes.Public);
+ string full_name = pfx + name;
+ FieldBuilder fb = (FieldBuilder) fields [full_name];
+ if (fb != null)
+ return fb;
+
+ fb = TypeBuilder.DefineField (full_name, t, FieldAttributes.Private);
+ fields.Add (full_name, fb);
+ return fb;
}
-
+
//
// Called back from Yield
//
- public void MarkYield (EmitContext ec, Expression expr, bool in_exc)
+ public void MarkYield (EmitContext ec, Expression expr,
+ ArrayList finally_blocks)
{
ILGenerator ig = ec.ig;
ig.Emit (OpCodes.Stfld, pc_field.FieldBuilder);
// Return ok
- ig.Emit (OpCodes.Ldc_I4_1);
-
- // Find out how to "leave"
- if (in_exc || !ec.IsLastStatement){
- Type old = ec.ReturnType;
- ec.ReturnType = TypeManager.int32_type;
- ig.Emit (OpCodes.Stloc, ec.TemporaryReturn ());
- ec.ReturnType = old;
- }
-
- if (in_exc){
- ec.NeedReturnLabel ();
- ig.Emit (OpCodes.Leave, ec.ReturnLabel);
- } else if (ec.IsLastStatement){
- ig.Emit (OpCodes.Ret);
- } else {
- ec.NeedReturnLabel ();
- ig.Emit (OpCodes.Br, ec.ReturnLabel);
- }
-
- Label resume_point = ig.DefineLabel ();
- ig.MarkLabel (resume_point);
- resume_labels.Add (resume_point);
+ ig.Emit (OpCodes.Br, move_next_ok);
+
+ ResumePoint point = new ResumePoint (finally_blocks);
+ resume_points.Add (point);
+ point.Define (ig);
+ }
+
+ public void MarkFinally (EmitContext ec, ArrayList finally_blocks)
+ {
+ ILGenerator ig = ec.ig;
+
+ // increment pc
+ pc++;
+ ig.Emit (OpCodes.Ldarg_0);
+ IntConstant.EmitInt (ig, pc);
+ ig.Emit (OpCodes.Stfld, pc_field.FieldBuilder);
+
+ ResumePoint point = new ResumePoint (finally_blocks);
+ resume_points.Add (point);
+ point.Define (ig);
+ }
+
+ private static MemberName MakeProxyName (string name)
+ {
+ int pos = name.LastIndexOf ('.');
+ if (pos > 0)
+ name = name.Substring (pos + 1);
+
+ return new MemberName ("<" + name + ">__" + (proxy_count++));
}
//
public Iterator (TypeContainer container, string name, Type return_type,
Type [] param_types, InternalParameters parameters,
int modifiers, Block block, Location loc)
- : base (container.NamespaceEntry, container,
- "<Iterator:" + name + (proxy_count++) + ":>",
+ : base (container.NamespaceEntry, container, MakeProxyName (name),
Modifiers.PRIVATE, null, loc)
{
this.container = container;
this.return_type = return_type;
this.param_types = param_types;
this.parameters = parameters;
+ this.original_name = name;
this.original_block = block;
this.block = new Block (null);
- is_static = (modifiers & Modifiers.STATIC) != 0;
+ fields = new Hashtable ();
- container.AddIterator (this);
+ is_static = (modifiers & Modifiers.STATIC) != 0;
}
- public bool Define ()
+ public bool DefineIterator ()
{
if (!CheckType (return_type)) {
Report.Error (
1624, Location,
"The body of `{0}' cannot be an iterator block " +
"because '{1}' is not an iterator interface type",
- Name, TypeManager.CSharpName (return_type));
+ original_name, TypeManager.CSharpName (return_type));
return false;
}
}
}
+ generic_args = new TypeArguments (Location);
+ generic_args.Add (new TypeExpression (iterator_type, Location));
+
ArrayList list = new ArrayList ();
- if (is_enumerable)
- list.Add (new TypeExpression (
- TypeManager.ienumerable_type, Location));
- list.Add (new TypeExpression (TypeManager.ienumerator_type, Location));
+ if (is_enumerable) {
+ enumerable_type = new TypeExpression (
+ TypeManager.ienumerable_type, Location);
+ list.Add (enumerable_type);
+
+ generic_enumerable_type = new ConstructedType (
+ TypeManager.generic_ienumerable_type,
+ generic_args, Location);
+ list.Add (generic_enumerable_type);
+ }
+
+ enumerator_type = new TypeExpression (
+ TypeManager.ienumerator_type, Location);
+ list.Add (enumerator_type);
+
list.Add (new TypeExpression (TypeManager.idisposable_type, Location));
+ generic_enumerator_type = new ConstructedType (
+ TypeManager.generic_ienumerator_type,
+ generic_args, Location);
+ list.Add (generic_enumerator_type);
+
iterator_type_expr = new TypeExpression (iterator_type, Location);
+ container.AddIterator (this);
+
Bases = list;
return true;
}
//
// Returns the new block for the method, or null on failure
//
- protected override bool DoDefineType ()
+ protected override bool DefineNestedTypes ()
{
Define_Fields ();
Define_Constructor ();
- Define_Current ();
+ Define_Current (false);
+ Define_Current (true);
Define_MoveNext ();
Define_Reset ();
Define_Dispose ();
- if (is_enumerable)
- Define_GetEnumerator ();
+ if (is_enumerable) {
+ Define_GetEnumerator (false);
+ Define_GetEnumerator (true);
+ }
Create_Block ();
- return true;
+ return base.DefineNestedTypes ();
}
Field pc_field;
Field current_field;
+ Method dispose;
+
public Field this_field;
public Field[] parameter_fields;
if (!is_static) {
Type t = container.TypeBuilder;
args.Add (new Argument (
- new SimpleParameterReference (t, 0, Location),
- Argument.AType.Expression));
+ new ThisParameterReference (t, 0, Location)));
}
+ args.Add (new Argument (new BoolLiteral (false)));
+
for (int i = 0; i < parameters.Count; i++) {
Type t = parameters.ParameterType (i);
args.Add (new Argument (
- new SimpleParameterReference (t, first + i, Location),
- Argument.AType.Expression));
+ new SimpleParameterReference (t, first + i, Location)));
}
Expression new_expr = new New (
Location loc = Location.Null;
pc_field = new Field (
- TypeManager.system_int32_expr, Modifiers.PRIVATE, "PC",
+ this, TypeManager.system_int32_expr, Modifiers.PRIVATE, "PC",
null, null, loc);
AddField (pc_field);
current_field = new Field (
- iterator_type_expr, Modifiers.PRIVATE, "current",
+ this, iterator_type_expr, Modifiers.PRIVATE, "current",
null, null, loc);
AddField (current_field);
if (!is_static) {
this_field = new Field (
+ this,
new TypeExpression (container.TypeBuilder, Location),
Modifiers.PRIVATE, "this", null, null, loc);
AddField (this_field);
"field{0}_{1}", i, parameters.ParameterName (i));
parameter_fields [i] = new Field (
+ this,
new TypeExpression (parameters.ParameterType (i), loc),
Modifiers.PRIVATE, fname, null, null, loc);
AddField (parameter_fields [i]);
{
Parameters ctor_params;
- if (!is_static) {
- Parameter this_param = new Parameter (
+ ArrayList list = new ArrayList ();
+
+ if (!is_static)
+ list.Add (new Parameter (
new TypeExpression (container.TypeBuilder, Location),
- "this", Parameter.Modifier.NONE, null);
+ "this", Parameter.Modifier.NONE, null));
+ list.Add (new Parameter (
+ TypeManager.system_boolean_expr, "initialized",
+ Parameter.Modifier.NONE, null));
- Parameter[] old_fixed = parameters.Parameters.FixedParameters;
- Parameter[] fixed_params = new Parameter [old_fixed.Length + 1];
- fixed_params [0] = this_param;
- old_fixed.CopyTo (fixed_params, 1);
+ Parameter[] old_fixed = parameters.Parameters.FixedParameters;
+ if (old_fixed != null)
+ list.AddRange (old_fixed);
- ctor_params = new Parameters (
- fixed_params, parameters.Parameters.ArrayParameter,
- Location);
- } else
- ctor_params = parameters.Parameters;
+ Parameter[] fixed_params = new Parameter [list.Count];
+ list.CopyTo (fixed_params);
+
+ ctor_params = new Parameters (
+ fixed_params, parameters.Parameters.ArrayParameter,
+ Location);
Constructor ctor = new Constructor (
this, Name, Modifiers.PUBLIC, ctor_params,
block.AddStatement (new StatementExpression (assign, Location));
}
- int first = is_static ? 1 : 2;
+ int first = is_static ? 2 : 3;
for (int i = 0; i < parameters.Count; i++) {
Type t = parameters.ParameterType (i);
block.AddStatement (new StatementExpression (assign, Location));
}
+
+ State initial = is_enumerable ? State.Uninitialized : State.Running;
+ block.AddStatement (new SetState (this, initial, Location));
+
+ block.AddStatement (new If (
+ new SimpleParameterReference (
+ TypeManager.bool_type, first - 1, Location),
+ new SetState (this, State.Running, Location),
+ Location));
}
Statement Create_ThrowInvalidOperation ()
return new Throw (new New (ex_type, null, Location), Location);
}
- void Define_Current ()
+ void Define_Current (bool is_generic)
{
+ MemberName left;
+ Expression type;
+ if (is_generic) {
+ left = new MemberName (
+ "System.Collections.Generic.IEnumerator",
+ generic_args);
+ type = iterator_type_expr;
+ } else {
+ left = new MemberName ("System.Collections.IEnumerator");
+ type = TypeManager.system_object_expr;
+ }
+
+ MemberName name = new MemberName (left, "Current", null);
+
Block get_block = new Block (null);
get_block.AddStatement (new If (
new Binary (
Binary.Operator.LessThanOrEqual,
new FieldExpression (pc_field),
- new IntLiteral (0), Location),
+ new IntLiteral ((int) State.Running), Location),
Create_ThrowInvalidOperation (),
new Return (
new FieldExpression (current_field), Location),
Accessor getter = new Accessor (get_block, null);
Property current = new Property (
- this, iterator_type_expr, Modifiers.PUBLIC,
- false, "Current", null, getter, null, Location);
+ this, type, 0, false, name, null, getter, null, Location);
AddProperty (current);
}
void Define_MoveNext ()
{
Method move_next = new Method (
- this, TypeManager.system_boolean_expr,
- Modifiers.PUBLIC, false, "MoveNext",
+ this, null, TypeManager.system_boolean_expr,
+ Modifiers.PUBLIC, false, new MemberName ("MoveNext"),
Parameters.EmptyReadOnlyParameters, null,
Location.Null);
AddMethod (move_next);
block.AddStatement (inline);
}
- void Define_GetEnumerator ()
+ void Define_GetEnumerator (bool is_generic)
{
+ MemberName left;
+ Expression type;
+ if (is_generic) {
+ left = new MemberName (
+ "System.Collections.Generic.IEnumerable",
+ generic_args);
+ type = generic_enumerator_type;
+ } else {
+ left = new MemberName ("System.Collections.IEnumerable");
+ type = enumerator_type;
+ }
+
+ MemberName name = new MemberName (left, "GetEnumerator", null);
+
Method get_enumerator = new Method (
- this,
- new TypeExpression (TypeManager.ienumerator_type, Location),
- Modifiers.PUBLIC, false, "GetEnumerator",
+ this, null, type, 0, false, name,
Parameters.EmptyReadOnlyParameters, null,
Location.Null);
AddMethod (get_enumerator);
get_enumerator.Block = new Block (null);
- This the_this = new This (block, Location);
- get_enumerator.Block.AddStatement (new Return (the_this, Location));
+ Expression ce = new MemberAccess (
+ new SimpleName ("System.Threading.Interlocked", Location),
+ "CompareExchange", Location);
+
+ Expression pc = new FieldExpression (pc_field);
+ Expression before = new IntLiteral ((int) State.Running);
+ Expression uninitialized = new IntLiteral ((int) State.Uninitialized);
+
+ ArrayList args = new ArrayList ();
+ args.Add (new Argument (pc, Argument.AType.Ref));
+ args.Add (new Argument (before, Argument.AType.Expression));
+ args.Add (new Argument (uninitialized, Argument.AType.Expression));
+
+ get_enumerator.Block.AddStatement (new If (
+ new Binary (
+ Binary.Operator.Equality,
+ new Invocation (ce, args, Location),
+ uninitialized, Location),
+ new Return (new This (block, Location), Location),
+ Location));
+
+ args = new ArrayList ();
+ if (!is_static)
+ args.Add (new Argument (new FieldExpression (this_field)));
+
+ args.Add (new Argument (new BoolLiteral (true)));
+
+ for (int i = 0; i < parameters.Count; i++)
+ args.Add (new Argument (
+ new FieldExpression (parameter_fields [i])));
+
+ Expression new_expr = new New (
+ new TypeExpression (TypeBuilder, Location), args, Location);
+ get_enumerator.Block.AddStatement (new Return (new_expr, Location));
}
protected class SimpleParameterReference : Expression
}
public override void Emit (EmitContext ec)
+ {
+ DoEmit (ec);
+ }
+
+ protected virtual void DoEmit (EmitContext ec)
{
ParameterReference.EmitLdArg (ec.ig, idx);
}
}
+ protected class ThisParameterReference : SimpleParameterReference
+ {
+ public ThisParameterReference (Type type, int idx, Location loc)
+ : base (type, idx, loc)
+ { }
+
+ protected override void DoEmit (EmitContext ec)
+ {
+ base.DoEmit (ec);
+ if (ec.TypeContainer is Struct)
+ ec.ig.Emit (OpCodes.Ldobj, type);
+ }
+ }
+
protected class FieldExpression : Expression
{
Field field;
}
}
- public class MoveNextMethod : Statement {
+ protected class MoveNextMethod : Statement {
Iterator iterator;
public MoveNextMethod (Iterator iterator, Location loc)
code_flags |= Modifiers.STATIC;
EmitContext new_ec = new EmitContext (
- iterator, loc, ec.ig, iterator.return_type,
- code_flags);
+ iterator.container, loc, ec.ig,
+ TypeManager.int32_type, code_flags);
new_ec.CurrentIterator = iterator;
}
}
- protected class DoYieldBreak : Statement
+ protected class DisposeMethod : Statement {
+ Iterator iterator;
+
+ public DisposeMethod (Iterator iterator, Location loc)
+ {
+ this.loc = loc;
+ this.iterator = iterator;
+ }
+
+ public override bool Resolve (EmitContext ec)
+ {
+ return true;
+ }
+
+ protected override void DoEmit (EmitContext ec)
+ {
+ iterator.EmitDispose (ec);
+ }
+ }
+
+ protected class StatementList : Statement {
+ ArrayList statements;
+
+ public StatementList (Location loc)
+ {
+ this.loc = loc;
+ statements = new ArrayList ();
+ }
+
+ public void Add (Statement statement)
+ {
+ statements.Add (statement);
+ }
+
+ public override bool Resolve (EmitContext ec)
+ {
+ foreach (Statement stmt in statements) {
+ if (!stmt.Resolve (ec))
+ return false;
+ }
+
+ return true;
+ }
+
+ protected override void DoEmit (EmitContext ec)
+ {
+ foreach (Statement stmt in statements)
+ stmt.Emit (ec);
+ }
+ }
+
+ protected class SetState : Statement
{
Iterator iterator;
- bool add_return;
+ State state;
- public DoYieldBreak (Iterator iterator, bool add_return,
- Location loc)
+ public SetState (Iterator iterator, State state, Location loc)
{
this.iterator = iterator;
- this.add_return = add_return;
+ this.state = state;
this.loc = loc;
}
public override bool Resolve (EmitContext ec)
{
- if (add_return)
- ec.CurrentBranching.CurrentUsageVector.Return ();
return true;
}
protected override void DoEmit (EmitContext ec)
{
- iterator.EmitYieldBreak (ec.ig, add_return);
+ ec.ig.Emit (OpCodes.Ldarg_0);
+ IntConstant.EmitInt (ec.ig, (int) state);
+ ec.ig.Emit (OpCodes.Stfld, iterator.pc_field.FieldBuilder);
}
}
void Define_Reset ()
{
Method reset = new Method (
- this, TypeManager.system_void_expr, Modifiers.PUBLIC,
- false, "Reset", Parameters.EmptyReadOnlyParameters,
- null, Location);
+ this, null, TypeManager.system_void_expr, Modifiers.PUBLIC,
+ false, new MemberName ("Reset"),
+ Parameters.EmptyReadOnlyParameters, null, Location);
AddMethod (reset);
reset.Block = new Block (null);
void Define_Dispose ()
{
- Method dispose = new Method (
- this, TypeManager.system_void_expr, Modifiers.PUBLIC,
- false, "Dispose", Parameters.EmptyReadOnlyParameters,
- null, Location);
+ dispose = new Method (
+ this, null, TypeManager.system_void_expr, Modifiers.PUBLIC,
+ false, new MemberName ("Dispose"),
+ Parameters.EmptyReadOnlyParameters, null, Location);
AddMethod (dispose);
dispose.Block = new Block (null);
- dispose.Block.AddStatement (new DoYieldBreak (this, false, Location));
- dispose.Block.AddStatement (new Return (null, Location));
+ dispose.Block.AddStatement (new DisposeMethod (this, Location));
}
public Block Block {
return true;
}
+ if (!t.IsGenericInstance)
+ return false;
+
+ Type[] args = TypeManager.GetTypeArguments (t);
+ if (args.Length != 1)
+ return false;
+
+ Type gt = t.GetGenericTypeDefinition ();
+ if (gt == TypeManager.generic_ienumerable_type) {
+ iterator_type = args [0];
+ is_enumerable = true;
+ return true;
+ } else if (gt == TypeManager.generic_ienumerator_type) {
+ iterator_type = args [0];
+ is_enumerable = false;
+ return true;
+ }
+
return false;
}
}