Index: report.cs =================================================================== --- report.cs (revision 63019) +++ report.cs (working copy) @@ -634,6 +634,10 @@ : base (message) { } + + public InternalErrorException (string message, params object[] args) + : base (String.Format (message, args)) + { } } /// Index: generic.cs =================================================================== --- generic.cs (revision 63019) +++ generic.cs (working copy) @@ -151,11 +151,14 @@ } public override string TypeParameter { - get { - return name; - } + get { return name; } } + public Constraints Clone () + { + return new Constraints (name, constraints, loc); + } + GenericParameterAttributes attrs; TypeExpr class_constraint; ArrayList iface_constraints; @@ -739,7 +742,7 @@ TypeManager.CSharpName (mparam), TypeManager.CSharpSignature (mb)); return false; } - } else if (DeclSpace is Iterator) { + } else if (DeclSpace is CompilerGeneratedClass) { TypeParameter[] tparams = DeclSpace.TypeParameters; Type[] types = new Type [tparams.Length]; for (int i = 0; i < tparams.Length; i++) @@ -2622,7 +2625,7 @@ Argument a = (Argument) arguments [i]; if ((a.Expr is NullLiteral) || (a.Expr is MethodGroupExpr) || - (a.Expr is AnonymousMethod)) + (a.Expr is AnonymousMethodExpression)) continue; arg_types [i] = a.Type; Index: typemanager.cs =================================================================== --- typemanager.cs (revision 63019) +++ typemanager.cs (working copy) @@ -71,6 +71,7 @@ static public Type asynccallback_type; static public Type intptr_type; static public Type monitor_type; + static public Type interlocked_type; static public Type runtime_field_handle_type; static public Type runtime_argument_handle_type; static public Type attribute_type; @@ -974,6 +975,7 @@ icloneable_type = CoreLookupType ("System", "ICloneable"); iconvertible_type = CoreLookupType ("System", "IConvertible"); monitor_type = CoreLookupType ("System.Threading", "Monitor"); + interlocked_type = CoreLookupType ("System.Threading", "Interlocked"); intptr_type = CoreLookupType ("System", "IntPtr"); attribute_type = CoreLookupType ("System", "Attribute"); Index: parameter.cs =================================================================== --- parameter.cs (revision 63019) +++ parameter.cs (working copy) @@ -212,6 +212,11 @@ protected Type parameter_type; public readonly Location Location; + Variable var; + public Variable Variable { + get { return var; } + } + IResolveContext resolve_context; public Parameter (Expression type, string name, Modifier mod, Attributes attrs, Location loc) @@ -335,6 +340,15 @@ return true; } + public void ResolveVariable (EmitContext ec, int idx) + { + Report.Debug (64, "PARAMETER RESOLVE VARIABLE", ParameterType, Name, Location); + var = ec.GetCapturedParameter (this); + Report.Debug (64, "PARAMETER RESOLVE VARIABLE #1", var, ec.IsStatic, idx); + if (var == null) + var = new ParameterVariable (this, idx); + } + public Type ExternalType () { if ((ModFlags & Parameter.Modifier.ISBYREF) != 0) @@ -452,6 +466,78 @@ return attribute_targets; } } + + protected class ParameterVariable : Variable + { + public readonly Parameter Parameter; + public readonly int Idx; + public readonly bool IsRef; + + public ParameterVariable (Parameter par, int idx) + { + this.Parameter = par; + this.Idx = idx; + this.IsRef = (par.ModFlags & Parameter.Modifier.ISBYREF) != 0; + } + + public override Type Type { + get { return Parameter.ParameterType; } + } + + public override bool HasInstance { + get { return false; } + } + + public override bool NeedsTemporary { + get { return false; } + } + + public override void EmitInstance (EmitContext ec) + { + } + + public override void Emit (EmitContext ec) + { + int arg_idx = Idx; + if (!ec.MethodIsStatic) + arg_idx++; + + ParameterReference.EmitLdArg (ec.ig, arg_idx); + } + + public override void EmitAssign (EmitContext ec) + { + int arg_idx = Idx; + if (!ec.MethodIsStatic) + arg_idx++; + + if (arg_idx <= 255) + ec.ig.Emit (OpCodes.Starg_S, (byte) arg_idx); + else + ec.ig.Emit (OpCodes.Starg, arg_idx); + } + + public override void EmitAddressOf (EmitContext ec) + { + int arg_idx = Idx; + + if (!ec.MethodIsStatic) + arg_idx++; + + if (IsRef) { + if (arg_idx <= 255) + ec.ig.Emit (OpCodes.Ldarg_S, (byte) arg_idx); + else + ec.ig.Emit (OpCodes.Ldarg, arg_idx); + } else { + if (arg_idx <= 255) + ec.ig.Emit (OpCodes.Ldarga_S, (byte) arg_idx); + else + ec.ig.Emit (OpCodes.Ldarga, arg_idx); + } + } + } + } /// @@ -607,6 +693,14 @@ return ok; } + public void ResolveVariable (EmitContext ec) + { + for (int i = 0; i < FixedParameters.Length; ++i) { + Parameter p = FixedParameters [i]; + p.ResolveVariable (ec, i); + } + } + public CallingConventions CallingConvention { get { @@ -665,7 +759,7 @@ } } - Parameter this [int pos] + public Parameter this [int pos] { get { if (pos >= count && (HasArglist || HasParams)) { Index: rootcontext.cs =================================================================== --- rootcontext.cs (revision 63019) +++ rootcontext.cs (working copy) @@ -377,6 +377,7 @@ "System.Runtime.CompilerServices.RuntimeHelpers", "System.Reflection.DefaultMemberAttribute", "System.Threading.Monitor", + "System.Threading.Interlocked", "System.AttributeUsageAttribute", "System.Runtime.InteropServices.DllImportAttribute", Index: ecore.cs =================================================================== --- ecore.cs (revision 63019) +++ ecore.cs (working copy) @@ -4007,10 +4007,10 @@ } } - public class TemporaryVariable : Expression, IMemoryLocation { LocalInfo li; + Variable var; public TemporaryVariable (Type type, Location loc) { @@ -4028,64 +4028,46 @@ li = ec.CurrentBlock.AddTemporaryVariable (te, loc); if (!li.Resolve (ec)) return null; + + if (ec.MustCaptureVariable (li)) { + var = ec.CaptureVariable (li); + type = var.Type; + } - AnonymousContainer am = ec.CurrentAnonymousMethod; - if ((am != null) && am.IsIterator) - ec.CaptureVariable (li); - return this; } + + public Variable Variable { + get { return var != null ? var : li.Variable; } + } public override void Emit (EmitContext ec) { - ILGenerator ig = ec.ig; - - if (li.FieldBuilder != null) { - ig.Emit (OpCodes.Ldarg_0); - ig.Emit (OpCodes.Ldfld, li.FieldBuilder); - } else { - ig.Emit (OpCodes.Ldloc, li.LocalBuilder); - } + Variable.EmitInstance (ec); + Variable.Emit (ec); } public void EmitLoadAddress (EmitContext ec) { - ILGenerator ig = ec.ig; - - if (li.FieldBuilder != null) { - ig.Emit (OpCodes.Ldarg_0); - ig.Emit (OpCodes.Ldflda, li.FieldBuilder); - } else { - ig.Emit (OpCodes.Ldloca, li.LocalBuilder); - } + Variable.EmitInstance (ec); + Variable.EmitAddressOf (ec); } public void Store (EmitContext ec, Expression right_side) { - if (li.FieldBuilder != null) - ec.ig.Emit (OpCodes.Ldarg_0); - + Variable.EmitInstance (ec); right_side.Emit (ec); - if (li.FieldBuilder != null) { - ec.ig.Emit (OpCodes.Stfld, li.FieldBuilder); - } else { - ec.ig.Emit (OpCodes.Stloc, li.LocalBuilder); - } + Variable.EmitAssign (ec); } public void EmitThis (EmitContext ec) { - if (li.FieldBuilder != null) { - ec.ig.Emit (OpCodes.Ldarg_0); - } + Variable.EmitInstance (ec); } - public void EmitStore (ILGenerator ig) + public void EmitStore (EmitContext ec) { - if (li.FieldBuilder != null) - ig.Emit (OpCodes.Stfld, li.FieldBuilder); - else - ig.Emit (OpCodes.Stloc, li.LocalBuilder); + Variable.EmitAssign (ec); } public void AddressOf (EmitContext ec, AddressOp mode) @@ -4093,5 +4075,5 @@ EmitLoadAddress (ec); } } - + } Index: class.cs =================================================================== --- class.cs (revision 63019) +++ class.cs (working copy) @@ -429,8 +429,8 @@ // Holds the operators MemberCoreArrayList operators; - // Holds the iterators - ArrayList iterators; + // Holds the compiler generated classes + ArrayList compiler_generated; // // Pointers to the default constructor and the default static constructor @@ -772,12 +772,14 @@ operators.Add (op); } - public void AddIterator (Iterator i) + public void AddCompilerGeneratedClass (CompilerGeneratedClass c) { - if (iterators == null) - iterators = new ArrayList (); + Report.Debug (64, "ADD COMPILER GENERATED CLASS", this, c); - iterators.Add (i); + if (compiler_generated == null) + compiler_generated = new ArrayList (); + + compiler_generated.Add (c); } public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder cb) @@ -822,9 +824,9 @@ } } - public ArrayList Iterators { + public ArrayList CompilerGenerated { get { - return iterators; + return compiler_generated; } } @@ -1202,7 +1204,7 @@ // Let's do it as soon as possible, since code below can call DefineType() on classes // that depend on us to be populated before they are. // - if (!(this is Iterator)) + if (!(this is Iterator) && !(this is CompilerGeneratedClass)) RootContext.RegisterOrder (this); if (base_type != null) { @@ -1329,6 +1331,20 @@ public bool ResolveType () { + if (!DoResolveType ()) + return false; + + if (compiler_generated != null) { + foreach (CompilerGeneratedClass c in compiler_generated) + if (!c.ResolveType ()) + return false; + } + + return true; + } + + protected virtual bool DoResolveType () + { if ((base_type != null) && (base_type.ResolveAsTypeTerminal (this, false) == null)) { error = true; @@ -1413,6 +1429,13 @@ return false; } + if (compiler_generated != null) { + foreach (CompilerGeneratedClass c in compiler_generated) { + if (c.DefineType () == null) + return false; + } + } + return true; } @@ -1541,18 +1564,7 @@ part.member_cache = member_cache; } #endif - if (iterators != null) { - foreach (Iterator iterator in iterators) { - if (iterator.DefineType () == null) - return false; - } - foreach (Iterator iterator in iterators) { - if (!iterator.DefineMembers ()) - return false; - } - } - return true; } @@ -1564,9 +1576,9 @@ public override bool Define () { - if (iterators != null) { - foreach (Iterator iterator in iterators) { - if (!iterator.Define ()) + if (compiler_generated != null) { + foreach (CompilerGeneratedClass c in compiler_generated) { + if (!c.Define ()) return false; } } @@ -2239,7 +2251,7 @@ if (default_static_constructor != null) default_static_constructor.Emit (); - + if (methods != null){ foreach (Method m in methods) m.Emit (); @@ -2282,9 +2294,14 @@ if (pending.VerifyPendingMethods ()) return; - if (iterators != null) - foreach (Iterator iterator in iterators) - iterator.EmitType (); + if (compiler_generated != null) { + foreach (CompilerGeneratedClass c in compiler_generated) { + if (!c.DefineMembers ()) + throw new InternalErrorException (); + } + foreach (CompilerGeneratedClass c in compiler_generated) + c.EmitType (); + } } public override void CloseType () @@ -2324,9 +2341,9 @@ foreach (Delegate d in Delegates) d.CloseType (); - if (Iterators != null) - foreach (Iterator i in Iterators) - i.CloseType (); + if (CompilerGenerated != null) + foreach (CompilerGeneratedClass c in CompilerGenerated) + c.CloseType (); types = null; properties = null; @@ -2341,7 +2358,7 @@ events = null; indexers = null; operators = null; - iterators = null; + compiler_generated = null; default_constructor = null; default_static_constructor = null; type_bases = null; @@ -3702,16 +3719,10 @@ } } - public EmitContext CreateEmitContext (DeclSpace tc, ILGenerator ig) + public virtual EmitContext CreateEmitContext (DeclSpace tc, ILGenerator ig) { - EmitContext ec = new EmitContext (this, - tc, this.ds, Location, ig, MemberType, ModFlags, false); - - Iterator iterator = tc as Iterator; - if (iterator != null) - ec.CurrentAnonymousMethod = iterator.Host; - - return ec; + return new EmitContext ( + this, tc, this.ds, Location, ig, MemberType, ModFlags, false); } public override bool Define () @@ -3821,6 +3832,10 @@ } } + public abstract Iterator Iterator { + get; + } + public new Location Location { get { return base.Location; @@ -3981,6 +3996,12 @@ Modifiers.METHOD_YIELDS | Modifiers.EXTERN; + Iterator iterator; + + public override Iterator Iterator { + get { return iterator; } + } + const int AllowedInterfaceModifiers = Modifiers.NEW | Modifiers.UNSAFE; @@ -4118,6 +4139,8 @@ // public override bool Define () { + Report.Debug (64, "METHOD DEFINE", this, Name); + if (!base.Define ()) return false; @@ -4135,11 +4158,11 @@ // Setup iterator if we are one // if ((ModFlags & Modifiers.METHOD_YIELDS) != 0){ - Iterator iterator = new Iterator ( - this, Parent, GenericMethod, ModFlags); + iterator = Iterator.CreateIterator ( + this, (TypeContainer) Parent, GenericMethod, ModFlags); - if (!iterator.DefineIterator ()) - return false; + if (iterator == null) + throw new InternalErrorException (); } // @@ -4179,6 +4202,7 @@ // public override void Emit () { + Report.Debug (64, "METHOD EMIT", this, MethodBuilder, Location, Block, MethodData); MethodData.Emit (Parent); base.Emit (); @@ -4360,6 +4384,10 @@ static string[] attribute_targets = new string [] { "method" }; + public Iterator Iterator { + get { return null; } + } + bool has_compliant_args = false; // // The spec claims that static is not permitted, but @@ -4710,6 +4738,8 @@ GenericMethod GenericMethod { get; } Parameters ParameterInfo { get; } + Iterator Iterator { get; } + Attributes OptAttributes { get; } ToplevelBlock Block { get; set; } @@ -5032,6 +5062,20 @@ SourceMethod source = SourceMethod.Create (parent, MethodBuilder, method.Block); + Report.Debug (64, "METHOD DATA EMIT", this, MethodBuilder, + method, method.Iterator, block); + +#if FIXME + if (method.Iterator != null) { + if (!method.Iterator.Resolve (ec)) + throw new InternalErrorException (); + // method.Iterator.EmitMethod (ec); + } +#endif + + Report.Debug (64, "METHOD DATA EMIT #1", this, MethodBuilder, + method, method.Iterator, block); + // // Handle destructors specially // @@ -5934,6 +5978,10 @@ #region IMethodData Members + public Iterator Iterator { + get { return null; } + } + public ToplevelBlock Block { get { return block; @@ -6285,9 +6333,10 @@ // Setup iterator if we are one // if (yields) { - Iterator iterator = new Iterator (this, Parent as TypeContainer, null, ModFlags); - - if (!iterator.DefineIterator ()) + Iterator iterator = Iterator.CreateIterator ( + this, (TypeContainer) Parent, null, ModFlags); + + if (iterator == null) return null; } @@ -7323,10 +7372,10 @@ // Setup iterator if we are one // if ((ModFlags & Modifiers.METHOD_YIELDS) != 0){ - Iterator iterator = new Iterator ( - Get, Parent, null, ModFlags); + Iterator iterator = Iterator.CreateIterator ( + Get, (TypeContainer) Parent, null, ModFlags); - if (!iterator.DefineIterator ()) + if (iterator == null) return false; } } @@ -7444,6 +7493,10 @@ Block = block; } + public override Iterator Iterator { + get { return null; } + } + public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder cb) { if (a.Type == TypeManager.conditional_attribute_type) { Index: decl.cs =================================================================== --- decl.cs (revision 63019) +++ decl.cs (working copy) @@ -525,6 +525,7 @@ caching_flags |= Flags.ClsCompliantAttributeTrue; return true; } + return false; } Index: delegate.cs =================================================================== --- delegate.cs (revision 63019) +++ delegate.cs (working copy) @@ -816,8 +816,8 @@ Expression e = a.Expr; - if (e is AnonymousMethod && RootContext.Version != LanguageVersion.ISO_1) - return ((AnonymousMethod) e).Compatible (ec, type); + if (e is AnonymousMethodExpression && RootContext.Version != LanguageVersion.ISO_1) + return ((AnonymousMethodExpression) e).Compatible (ec, type); MethodGroupExpr mg = e as MethodGroupExpr; if (mg != null) Index: iterators.cs =================================================================== --- iterators.cs (revision 63019) +++ iterators.cs (working copy) @@ -71,16 +71,19 @@ public override bool Resolve (EmitContext ec) { + Report.Debug (64, "RESOLVE YIELD", this, ec, expr, expr.GetType ()); expr = expr.Resolve (ec); if (expr == null) return false; + Report.Debug (64, "RESOLVE YIELD #1", this, ec, expr, expr.GetType (), + ec.CurrentAnonymousMethod, ec.CurrentIterator); + if (!CheckContext (ec, loc, false)) return false; Iterator iterator = ec.CurrentIterator; - - if (expr.Type != iterator.IteratorType){ + if (expr.Type != iterator.IteratorType) { expr = Convert.ImplicitConversionRequired ( ec, expr, iterator.IteratorType, loc); if (expr == null) @@ -119,13 +122,512 @@ } } - public class Iterator : Class { - protected ToplevelBlock original_block; + public class IteratorHost : AnonymousMethodHost + { + public readonly Iterator Iterator; + + TypeExpr iterator_type_expr; + Field pc_field; + Field current_field; + Method dispose; + MethodInfo dispose_method; + + TypeExpr enumerator_type; + TypeExpr enumerable_type; + TypeExpr generic_enumerator_type; + TypeExpr generic_enumerable_type; + TypeArguments generic_args; + + public IteratorHost (Iterator iterator) + : base (iterator.Block.CaptureContext, iterator.Block, + iterator.Host, iterator.GenericMethod) + { + this.Iterator = iterator; + } + + public MethodInfo Dispose { + get { return dispose_method; } + } + + public Field PC { + get { return pc_field; } + } + + public Field CurrentField { + get { return current_field; } + } + + public Type IteratorType { + get { return iterator_type_expr.Type; } + } + + public override TypeExpr [] GetClassBases (out TypeExpr base_class) + { + iterator_type_expr = InflateType (Iterator.OriginalIteratorType); + + generic_args = new TypeArguments (Location); + generic_args.Add (iterator_type_expr); + + ArrayList list = new ArrayList (); + if (Iterator.IsEnumerable) { + 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); + + Bases = list; + + return base.GetClassBases (out base_class); + } + + protected override bool DoDefineMembers () + { + pc_field = CaptureVariable ("$PC", TypeManager.int32_type); + current_field = CaptureVariable ("$current", Iterator.OriginalIteratorType); + + Define_Current (true); + Define_Current (false); + Define_Dispose (); + Define_Reset (); + + if (Iterator.IsEnumerable) { + Define_GetEnumerator (false); + Define_GetEnumerator (true); + } + + if (!base.DoDefineMembers ()) + return false; + + FetchMethodDispose (); + return true; + } + + protected override void EmitScopeConstructor (EmitContext ec) + { + ec.ig.Emit (OpCodes.Ldarg_0); + ec.ig.Emit (OpCodes.Ldarg_1); + ec.ig.Emit (OpCodes.Stfld, pc_field.FieldBuilder); + base.EmitScopeConstructor (ec); + } + + void FetchMethodDispose () + { + MemberList dispose_list; + + dispose_list = FindMembers ( + CurrentType != null ? CurrentType : TypeBuilder, + MemberTypes.Method, BindingFlags.Public | BindingFlags.Instance, + Type.FilterName, "Dispose"); + + if (dispose_list.Count != 1) + throw new InternalErrorException ("Cannot find Dipose() method."); + + dispose_method = (MethodInfo) dispose_list [0]; + } + + void Define_Current (bool is_generic) + { + MemberName left; + Expression type; + + if (is_generic) { + left = new MemberName ( + "System.Collections.Generic.IEnumerator", + generic_args, Location); + type = iterator_type_expr; + } else { + left = new MemberName ("System.Collections.IEnumerator", Location); + type = TypeManager.system_object_expr; + } + + MemberName name = new MemberName (left, "Current", null, Location); + + ToplevelBlock get_block = new ToplevelBlock (Location); + get_block.AddStatement (new CurrentBlock (this, is_generic)); + + Accessor getter = new Accessor (get_block, 0, null, Location); + + Property current = new Property ( + this, type, 0, false, name, null, getter, null); + AddProperty (current); + } + + void Define_GetEnumerator (bool is_generic) + { + MemberName left; + Expression type; + if (is_generic) { + left = new MemberName ( + "System.Collections.Generic.IEnumerable", + generic_args, Location); + type = generic_enumerator_type; + } else { + left = new MemberName ("System.Collections.IEnumerable", Location); + type = enumerator_type; + } + + MemberName name = new MemberName (left, "GetEnumerator", Location); + + Method get_enumerator = new Method ( + this, null, type, 0, false, name, + Parameters.EmptyReadOnlyParameters, null); + + AddMethod (get_enumerator); + get_enumerator.Block = new ToplevelBlock (Location); + get_enumerator.Block.AddStatement (new GetEnumeratorBlock (this, type, is_generic)); + + +#if FIXME + Expression ce = new MemberAccess ( + new SimpleName ("System.Threading.Interlocked", Location), + "CompareExchange"); + + Expression pc = new FieldExpression (this, pc_field); + Expression before = new IntLiteral ((int) State.Running, Location); + Expression uninitialized = new IntLiteral ((int) State.Uninitialized, Location); + + 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), + uninitialized), + new Return (new ThisParameterReference (type.Type, Location), + Location), + Location)); + + args = new ArrayList (); + if (!IsStatic) { + args.Add (new Argument (new CapturedThisReference (this, Location))); + } + + args.Add (new Argument (new BoolLiteral (true, Location))); + + for (int i = 0; i < parameters.Count; i++) { + Expression cp = new CapturedParameterReference ( + this, parameters.ParameterType (i), + parameters.ParameterName (i), Location); + args.Add (new Argument (cp)); + } + + Expression new_expr = new New (current_type, args, Location); + get_enumerator.Block.AddStatement (new Return (new_expr, Location)); +#endif + } + + void Define_Dispose () + { +#if FIXME + dispose = new Method ( + this, null, TypeManager.system_void_expr, Modifiers.PUBLIC, + false, new MemberName ("Dispose", Location), + Parameters.EmptyReadOnlyParameters, null); + AddMethod (dispose); +#else + dispose = new DisposeMethod (this); +#endif + +#if FIXME + dispose.Block = new ToplevelBlock (null, Location); + dispose.Block.SetHaveAnonymousMethods (Location, Iterator); + dispose.Block.AddStatement (new DisposeMethod (Iterator, Location)); +#endif + } + + void Define_Reset () + { + Method reset = new Method ( + this, null, TypeManager.system_void_expr, Modifiers.PUBLIC, + false, new MemberName ("Reset", Location), + Parameters.EmptyReadOnlyParameters, null); + AddMethod (reset); + + reset.Block = new ToplevelBlock (Location); + reset.Block.AddStatement (Create_ThrowNotSupported ()); + } + + Statement Create_ThrowNotSupported () + { + TypeExpr ex_type = new TypeExpression ( + TypeManager.not_supported_exception_type, Location); + + return new Throw (new New (ex_type, null, Location), Location); + } + + ConstructorInfo GetInvalidOperationException () + { + MethodGroupExpr mg = (MethodGroupExpr) Expression.MemberLookup ( + TypeBuilder, TypeManager.invalid_operation_exception_type, + ".ctor", Location); + if (mg == null) + throw new InternalErrorException (); + return (ConstructorInfo) mg.Methods [0]; + } + + MethodInfo GetCompareExchange () + { + MethodGroupExpr mg = (MethodGroupExpr) Expression.MemberLookup ( + TypeBuilder, TypeManager.interlocked_type, + "CompareExchange", Location); + if (mg == null) + throw new InternalErrorException (); + return (MethodInfo) mg.Methods [0]; + } + + protected override ScopeInitializerBase CreateScopeInitializer () + { + return new IteratorHostInitializer (this); + } + + protected class IteratorHostInitializer : AnonymousMethodHostInitializer + { + new public readonly IteratorHost Host; + protected Iterator.State state; + + public IteratorHostInitializer (IteratorHost host) + : base (host) + { + this.Host = host; + } + + protected override bool DoResolveInternal (EmitContext ec) + { + if (this is EnumeratorScopeInitializer) + state = Iterator.State.Running; + else if (Host.Iterator.IsEnumerable) + state = Iterator.State.Uninitialized; + else + state = Iterator.State.Running; + + return base.DoResolveInternal (ec); + } + + protected override void EmitScopeConstructor (EmitContext ec) + { + ec.ig.Emit (OpCodes.Ldc_I4, (int) state); + base.EmitScopeConstructor (ec); + } + } + + protected class DisposeMethod : Method + { + public IteratorHost Host; + + public DisposeMethod (IteratorHost host) + : base (host, null, TypeManager.system_void_expr, Modifiers.PUBLIC, + false, new MemberName ("Dispose", host.Location), + Parameters.EmptyReadOnlyParameters, null) + { + this.Host = host; + + host.AddMethod (this); + + Block = new ToplevelBlock (host.Iterator.Container, null, Location); + // Block.SetHaveAnonymousMethods (Location, Host.Iterator); + + // Block = Host.Iterator.DisposeBlock; + + // Block = new ToplevelBlock (Location); + // Block.SetHaveAnonymousMethods (Location, Host.Iterator); + + Block.AddStatement (new DisposeMethodStatement (Host.Iterator)); + + Report.Debug (64, "DISPOSE METHOD", host, Block); + } + + public override EmitContext CreateEmitContext (DeclSpace tc, ILGenerator ig) + { + EmitContext ec = new EmitContext ( + this, tc, this.ds, Location, ig, MemberType, ModFlags, false); + + ec.capture_context = Host.Iterator.Block.CaptureContext; + ec.CurrentAnonymousMethod = Host.Iterator; + return ec; + } + + protected class DisposeMethodStatement : Statement + { + Iterator iterator; + + public DisposeMethodStatement (Iterator iterator) + { + this.iterator = iterator; + this.loc = iterator.Location; + } + + public override bool Resolve (EmitContext ec) + { + return true; + } + + protected override void DoEmit (EmitContext ec) + { + iterator.EmitDispose (ec); + } + } + } + + protected ScopeInitializer GetEnumeratorInitializer (EmitContext ec) + { + ScopeInitializer init = new EnumeratorScopeInitializer (this); + if (init.Resolve (ec) == null) + throw new InternalErrorException (); + return init; + } + + protected class EnumeratorScopeInitializer : IteratorHostInitializer + { + IteratorHost host; + ExpressionStatement initializer; + + public EnumeratorScopeInitializer (IteratorHost host) + : base (host) + { + this.host = host; + } + + protected override bool DoResolveInternal (EmitContext ec) + { + initializer = host.GetScopeInitializer (ec); + type = host.IsGeneric ? host.CurrentType : host.TypeBuilder; + return base.DoResolveInternal (ec); + } + + protected override void EmitParameterReference (EmitContext ec, + CapturedParameter cp) + { + Report.Debug (64, "EMIT THE PARAM", this, cp, host, + initializer, host.CaptureContext.captured_parameters); + ec.ig.Emit (OpCodes.Ldarg_0); + ec.ig.Emit (OpCodes.Ldfld, cp.Field.FieldBuilder); + } + } + + protected class CurrentBlock : Statement { + IteratorHost host; + bool is_generic; + + public CurrentBlock (IteratorHost host, bool is_generic) + { + this.host = host; + this.is_generic = is_generic; + loc = host.Location; + } + + public override bool Resolve (EmitContext ec) + { + ec.CurrentBranching.CurrentUsageVector.Return (); + return true; + } + + protected override void DoEmit (EmitContext ec) + { + ILGenerator ig = ec.ig; + Label label_ok = ig.DefineLabel (); + + ig.Emit (OpCodes.Ldarg_0); + ig.Emit (OpCodes.Ldfld, host.PC.FieldBuilder); + ig.Emit (OpCodes.Ldc_I4, (int) Iterator.State.Running); + ig.Emit (OpCodes.Bgt, label_ok); + + ig.Emit (OpCodes.Newobj, host.GetInvalidOperationException ()); + ig.Emit (OpCodes.Throw); + + ig.MarkLabel (label_ok); + ig.Emit (OpCodes.Ldarg_0); + ig.Emit (OpCodes.Ldfld, host.CurrentField.FieldBuilder); + if (!is_generic) + ig.Emit (OpCodes.Box, host.CurrentField.MemberType); + ig.Emit (OpCodes.Ret); + } + } + + protected class GetEnumeratorBlock : Statement { + IteratorHost host; + Expression type; + bool is_generic; + + Expression initializer, cast; + MethodInfo ce; + + public GetEnumeratorBlock (IteratorHost host, Expression type, + bool is_generic) + { + this.host = host; + this.type = type; + this.is_generic = is_generic; + loc = host.Location; + } + + public override bool Resolve (EmitContext ec) + { + type = type.ResolveAsTypeTerminal (ec, false); + if ((type == null) || (type.Type == null)) + return false; + + initializer = host.GetEnumeratorInitializer (ec); + if (initializer == null) + return false; + + cast = new ClassCast (initializer, type.Type); + + ce = host.GetCompareExchange (); + + ec.CurrentBranching.CurrentUsageVector.Return (); + return true; + } + + protected override void DoEmit (EmitContext ec) + { + ILGenerator ig = ec.ig; + Label label_init = ig.DefineLabel (); + + ig.Emit (OpCodes.Ldarg_0); + ig.Emit (OpCodes.Ldflda, host.PC.FieldBuilder); + ig.Emit (OpCodes.Ldc_I4, (int) Iterator.State.Running); + ig.Emit (OpCodes.Ldc_I4, (int) Iterator.State.Uninitialized); + ig.Emit (OpCodes.Call, ce); + + ig.Emit (OpCodes.Ldc_I4, (int) Iterator.State.Uninitialized); + ig.Emit (OpCodes.Bne_Un, label_init); + + ig.Emit (OpCodes.Ldarg_0); + ig.Emit (OpCodes.Ret); + + ig.MarkLabel (label_init); + + cast.Emit (ec); + ig.Emit (OpCodes.Ret); + } + } + } + + public class Iterator : AnonymousContainer { + protected readonly ToplevelBlock OriginalBlock; + protected readonly IMethodData OriginalMethod; protected ToplevelBlock block; - Type original_iterator_type; - TypeExpr iterator_type_expr; - bool is_enumerable; + public readonly bool IsEnumerable; public readonly bool IsStatic; // @@ -139,7 +641,6 @@ // Context from the original method // GenericMethod generic_method; - TypeContainer container; TypeExpr current_type; Type this_type; Parameters parameters; @@ -147,7 +648,7 @@ IMethodData orig_method; MethodInfo dispose_method; - MoveNextMethod move_next_method; + Method move_next_method; Constructor ctor; CaptureContext cc; @@ -156,25 +657,25 @@ Expression generic_enumerator_type; Expression generic_enumerable_type; TypeArguments generic_args; - EmitContext ec; - protected enum State { + public readonly Type OriginalIteratorType; + public readonly IteratorHost IteratorHost; + + public enum State { Uninitialized = -2, After, Running } - static int proxy_count; - public void EmitYieldBreak (ILGenerator ig) { ig.Emit (OpCodes.Ldarg_0); IntConstant.EmitInt (ig, (int) State.After); - ig.Emit (OpCodes.Stfld, pc_field.FieldBuilder); + ig.Emit (OpCodes.Stfld, IteratorHost.PC.FieldBuilder); ig.Emit (OpCodes.Br, move_next_error); } - public void EmitMoveNext (EmitContext ec) + internal void EmitMoveNext (EmitContext ec, Block original_block) { ILGenerator ig = ec.ig; @@ -192,7 +693,7 @@ resume_points.Add (entry_point); entry_point.Define (ig); - ec.EmitTopBlock (orig_method, original_block); + original_block.Emit (ec); EmitYieldBreak (ig); @@ -203,7 +704,7 @@ labels [i] = ((ResumePoint) resume_points [i]).Label; ig.Emit (OpCodes.Ldarg_0); - ig.Emit (OpCodes.Ldfld, pc_field.FieldBuilder); + ig.Emit (OpCodes.Ldfld, IteratorHost.PC.FieldBuilder); ig.Emit (OpCodes.Switch, labels); Label end = ig.DefineLabel (); @@ -221,7 +722,7 @@ ig.BeginFaultBlock (); ig.Emit (OpCodes.Ldarg_0); - ig.Emit (OpCodes.Callvirt, dispose_method); + ig.Emit (OpCodes.Callvirt, IteratorHost.Dispose); ig.EndExceptionBlock (); @@ -264,12 +765,12 @@ ig.MarkLabel (dispatcher); ig.Emit (OpCodes.Ldarg_0); - ig.Emit (OpCodes.Ldfld, pc_field.FieldBuilder); + ig.Emit (OpCodes.Ldfld, IteratorHost.PC.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.Emit (OpCodes.Stfld, IteratorHost.PC.FieldBuilder); ig.MarkLabel (end); } @@ -305,13 +806,13 @@ // Store the new current ig.Emit (OpCodes.Ldarg_0); expr.Emit (ec); - ig.Emit (OpCodes.Stfld, current_field.FieldBuilder); + ig.Emit (OpCodes.Stfld, IteratorHost.CurrentField.FieldBuilder); // increment pc pc++; ig.Emit (OpCodes.Ldarg_0); IntConstant.EmitInt (ig, pc); - ig.Emit (OpCodes.Stfld, pc_field.FieldBuilder); + ig.Emit (OpCodes.Stfld, IteratorHost.PC.FieldBuilder); // Return ok ig.Emit (OpCodes.Br, move_next_ok); @@ -329,75 +830,103 @@ pc++; ig.Emit (OpCodes.Ldarg_0); IntConstant.EmitInt (ig, pc); - ig.Emit (OpCodes.Stfld, pc_field.FieldBuilder); + ig.Emit (OpCodes.Stfld, IteratorHost.PC.FieldBuilder); ResumePoint point = new ResumePoint (finally_blocks); resume_points.Add (point); point.Define (ig); } - private static MemberName MakeProxyName (string name, GenericMethod generic, Location loc) - { - int pos = name.LastIndexOf ('.'); - if (pos > 0) - name = name.Substring (pos + 1); + public override bool IsIterator { + get { return true; } + } - string proxy_name = "<" + name + ">__" + (proxy_count++); - - if (generic != null) { - TypeArguments args = new TypeArguments (loc); - foreach (TypeParameter tparam in generic.CurrentTypeParameters) - args.Add (new SimpleName (tparam.Name, loc)); - return new MemberName (proxy_name, args, loc); - } else - return new MemberName (proxy_name, loc); + public override AnonymousMethodHost RootScope { + get { return IteratorHost; } } + ToplevelBlock TheBlock; + // public ToplevelBlock DisposeBlock; + // // Our constructor // - public Iterator (IMethodData m_container, DeclSpace parent, GenericMethod generic, - int modifiers) - : base (parent.NamespaceEntry, parent, - MakeProxyName (m_container.MethodName.Name, generic, m_container.Location), - (modifiers & Modifiers.UNSAFE) | Modifiers.PRIVATE, null) + public Iterator (IMethodData m_container, TypeContainer host, GenericMethod generic, + ToplevelBlock container, ToplevelBlock block, int modifiers, + Type iterator_type, bool is_enumerable) + : base (null, host, generic, m_container.ParameterInfo, + block, m_container.Block, TypeManager.bool_type, modifiers, + m_container.Location) { - this.orig_method = m_container; + this.OriginalBlock = m_container.Block; + this.OriginalMethod = m_container; + this.OriginalIteratorType = iterator_type; + this.IsEnumerable = is_enumerable; + this.TheBlock = block; - this.generic_method = generic; - this.container = ((TypeContainer) parent).PartialContainer; - this.original_parameters = m_container.ParameterInfo; - this.original_block = orig_method.Block; - this.block = new ToplevelBlock (orig_method.Block, parameters, orig_method.Location); + // Block.ReParent (Container); - if (generic != null) { - ArrayList constraints = new ArrayList (); - foreach (TypeParameter tparam in generic.TypeParameters) - constraints.Add (tparam.Constraints); + // Container.SetHaveAnonymousMethods (Location, this); + Block.SetHaveAnonymousMethods (Location, this); - SetParameterInfo (constraints); + // DisposeBlock = new ToplevelBlock (Block, null, Location); + // DisposeBlock.SetHaveAnonymousMethods (Location, this); + + // OriginalBlock.ReParent (Block); + // OriginalBlock.SetHaveAnonymousMethods (Location, this); + + Report.Debug (64, "NEW ITERATOR", host, generic, OriginalBlock, + Container, Block, block); + + IteratorHost = new IteratorHost (this); + Block.CreateIteratorHost (IteratorHost); + + OriginalBlock.ReParent (Container); + + m_container.Block = TheBlock; + // block.AddStatement (new TestStatement ()); + + OriginalBlock.MakeIterator (this); + + // MoveNextStatement inline = new MoveNextStatement (this, Location); + // Container.AddStatement (inline); + } + + protected class TestStatement : Statement + { + public override bool Resolve (EmitContext ec) + { + return true; } - IsStatic = (modifiers & Modifiers.STATIC) != 0; + protected override void DoEmit (EmitContext ec) + { + ec.ig.Emit (OpCodes.Nop); + ec.ig.Emit (OpCodes.Neg); + ec.ig.Emit (OpCodes.Pop); + ec.ig.Emit (OpCodes.Ret); + } } - public AnonymousContainer Host { - get { return move_next_method; } + protected override CaptureContext ContainerCaptureContext { + get { return OriginalBlock.CaptureContext; } } - public bool DefineIterator () + protected override CaptureContext CaptureContext { + get { return OriginalBlock.CaptureContext; } + } + +#if FIXME + public override ConstructorInfo Constructor { + get { return ctor.ConstructorBuilder; } + } + + protected bool DefineIterator () { ec = new EmitContext (this, this, Location, null, null, ModFlags); - ec.CurrentAnonymousMethod = move_next_method; + ec.CurrentAnonymousMethod = this; ec.InIterator = true; - if (!CheckType ()) { - Report.Error (1624, Location, - "The body of `{0}' cannot be an iterator block because `{1}' is not an iterator interface type", - orig_method.GetSignatureForError (), TypeManager.CSharpName (orig_method.ReturnType)); - return false; - } - for (int i = 0; i < original_parameters.Count; i++){ Parameter.Modifier mod = original_parameters.ParameterModifier (i); if ((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) != 0){ @@ -423,12 +952,50 @@ else this_type = container.TypeBuilder; - container.AddIterator (this); + orig_method.Block = block; - orig_method.Block = block; + return Resolve (ec); + } +#endif + + public override bool Resolve (EmitContext ec) + { + Report.Debug (64, "RESOLVE ITERATOR", this, Container, Block, TheBlock); + + if (!base.Resolve (ec)) + return false; + + Report.Debug (64, "RESOLVE ITERATOR #1", this, method, method.Parent, RootScope); + + if (!RootScope.DefineMembers ()) + return false; + + Expression scope_init = RootScope.GetScopeInitializer (ec); + Expression cast = new ClassCast (scope_init, OriginalMethod.ReturnType); + Container.AddStatement (new NoCheckReturn (cast)); + return true; } + protected override Method DoCreateMethodHost (EmitContext ec) + { + return new AnonymousMethodMethod ( + this, null, TypeManager.system_boolean_expr, + Modifiers.PUBLIC, new MemberName ("MoveNext", Location), + Parameters.EmptyReadOnlyParameters); + } + +#if FIXME + + public override CompilerGeneratedClass CreateScopeType (ScopeInfo scope) + { + return this; + } + + public override bool IsIterator { + get { return true; } + } + MethodInfo FetchMethodDispose () { MemberList dispose_list; @@ -447,7 +1014,7 @@ protected override bool DoDefineMembers () { ec.InIterator = true; - ec.CurrentAnonymousMethod = move_next_method; + ec.CurrentAnonymousMethod = this; ec.capture_context = cc; if (!base.DoDefineMembers ()) @@ -457,6 +1024,8 @@ if (dispose_method == null) return false; + Report.Debug (64, "ITERATOR DEFINE MEMBERS", this); + return true; } @@ -466,7 +1035,7 @@ return false; ec.InIterator = true; - ec.CurrentAnonymousMethod = move_next_method; + ec.CurrentAnonymousMethod = this; ec.capture_context = cc; ec.TypeContainer = ec.TypeContainer.Parent; @@ -476,7 +1045,7 @@ else ec.ContainerType = ec.TypeContainer.TypeBuilder; - ec.ig = move_next_method.method.MethodBuilder.GetILGenerator (); + // ec.ig = move_next_method.method.MethodBuilder.GetILGenerator (); if (!ctor.Define ()) return false; @@ -489,38 +1058,13 @@ if (!ec.ResolveTopBlock (null, block, parameters, orig_method, out unreachable)) return false; - original_block.CompleteContexts (); + original_block.CompleteContexts (ec); cc.EmitAnonymousHelperClasses (ec); - return true; - } + ComputeMethodHost (); - TypeExpr InflateType (Type it) - { - if (generic_method == null) - return new TypeExpression (it, Location); - - if (it.IsGenericParameter && (it.DeclaringMethod != null)) { - int pos = it.GenericParameterPosition; - it = CurrentTypeParameters [pos].Type; - } else if (it.IsGenericType) { - Type[] args = it.GetGenericArguments (); - - TypeArguments inflated = new TypeArguments (Location); - foreach (Type t in args) - inflated.Add (InflateType (t)); - - return new ConstructedType (it, inflated, Location); - } else if (it.IsArray) { - TypeExpr et_expr = InflateType (it.GetElementType ()); - int rank = it.GetArrayRank (); - - Type et = et_expr.ResolveAsTypeTerminal (ec, false).Type; - it = et.MakeArrayType (rank); - } - - return new TypeExpression (it, Location); + return DefineMembers (); } Parameter InflateParameter (Parameter param) @@ -587,11 +1131,6 @@ else current_type = new TypeExpression (TypeBuilder, Location); - if (IsGeneric) { - foreach (TypeParameter tparam in TypeParameters) - tparam.InflateConstraints (current_type.Type); - } - parameters = InflateParameters (original_parameters, ec); if (!parameters.Resolve (ec)) { // TODO: @@ -600,7 +1139,6 @@ Define_Fields (); Define_Current (false); Define_Current (true); - Define_MoveNext (); Define_Reset (); Define_Dispose (); @@ -616,14 +1154,12 @@ return base.DefineNestedTypes (); } - Field pc_field; - Field current_field; Method dispose; void Create_Block () { - original_block.SetHaveAnonymousMethods (Location, move_next_method); - block.SetHaveAnonymousMethods (Location, move_next_method); + original_block.SetHaveAnonymousMethods (Location, this); + block.SetHaveAnonymousMethods (Location, this); cc = original_block.CaptureContext; @@ -634,7 +1170,7 @@ Type t = this_type; args.Add (new Argument ( new ThisParameterReference (t, Location))); - cc.CaptureThis (move_next_method); + cc.CaptureThis (this); } args.Add (new Argument (new BoolLiteral (false, Location))); @@ -647,7 +1183,11 @@ args.Add (new Argument ( new SimpleParameterReference (t, first + i, Location))); - cc.AddParameterToContext (move_next_method, name, inflated, first + i); + Report.Debug (64, "ITERATOR ADD PARAMETER", this, i, t, name, + inflated); + + cc.AddParameterToContext ( + this, parameters [i], first + i, Location); } TypeExpr proxy_type; @@ -665,7 +1205,7 @@ proxy_type = current_type; Expression new_expr = new New (proxy_type, args, Location); - block.AddStatement (new NoCheckReturn (new_expr, Location)); + block.AddStatement (new NoCheckReturn (new_expr)); } void Define_Fields () @@ -723,7 +1263,8 @@ new SetState (this, State.Running, Location), Location)); - ctor.Block.AddStatement (new InitScope (this, Location)); + ExpressionStatement init_scope = GetScopeInitializer (Location); + ctor.Block.AddStatement (new StatementExpression (init_scope)); } Statement Create_ThrowInvalidOperation () @@ -778,17 +1319,6 @@ AddProperty (current); } - void Define_MoveNext () - { - move_next_method = new MoveNextMethod (this, Location); - - original_block.ReParent (block, move_next_method); - - move_next_method.CreateMethod (ec); - - AddMethod (move_next_method.method); - } - void Define_GetEnumerator (bool is_generic) { MemberName left; @@ -820,7 +1350,7 @@ get_enumerator.Block = new ToplevelBlock ( block, parameters, Location); - get_enumerator.Block.SetHaveAnonymousMethods (Location, move_next_method); + get_enumerator.Block.SetHaveAnonymousMethods (Location, this); Expression ce = new MemberAccess ( new SimpleName ("System.Threading.Interlocked", Location), @@ -934,7 +1464,7 @@ public override void Emit (EmitContext ec) { - ec.CurrentAnonymousMethod = iterator.move_next_method; + ec.CurrentAnonymousMethod = iterator; LocalTemporary dummy = null; @@ -995,62 +1525,8 @@ throw new InvalidOperationException (); } } +#endif - protected class MoveNextMethod : AnonymousContainer - { - Iterator iterator; - - public MoveNextMethod (Iterator iterator, Location loc) - : base (iterator.parameters, iterator.original_block, loc) - { - this.iterator = iterator; - } - - protected override bool CreateMethodHost (EmitContext ec) - { - method = new Method ( - iterator, null, TypeManager.system_boolean_expr, - Modifiers.PUBLIC, false, new MemberName ("MoveNext", loc), - Parameters.EmptyReadOnlyParameters, null); - - method.Block = Block; - - MoveNextStatement inline = new MoveNextStatement (iterator, loc); - Block.AddStatement (inline); - - return true; - } - - public bool CreateMethod (EmitContext ec) - { - return CreateMethodHost (ec); - } - - public override Iterator Iterator { - get { return iterator; } - } - - public void ComputeHost () - { - ComputeMethodHost (); - } - - public override bool IsIterator { - get { return true; } - } - - public override void CreateScopeType (EmitContext ec, ScopeInfo scope) - { - scope.ScopeTypeBuilder = iterator.TypeBuilder; - scope.ScopeConstructor = iterator.ctor.ConstructorBuilder; - } - - public override void Emit (EmitContext ec) - { - throw new InternalErrorException (); - } - } - protected class MoveNextStatement : Statement { Iterator iterator; @@ -1062,19 +1538,16 @@ public override bool Resolve (EmitContext ec) { - return true; + return iterator.OriginalBlock.Resolve (ec); } protected override void DoEmit (EmitContext ec) { - iterator.move_next_method.ComputeHost (); - ec.CurrentAnonymousMethod = iterator.move_next_method; - ec.InIterator = true; - - iterator.EmitMoveNext (ec); + iterator.EmitMoveNext (ec, iterator.Block); } } +#if FIXME protected class DisposeMethod : Statement { Iterator iterator; @@ -1151,27 +1624,6 @@ } } - protected class InitScope : Statement - { - Iterator iterator; - - public InitScope (Iterator iterator, Location loc) - { - this.iterator = iterator; - this.loc = loc; - } - - public override bool Resolve (EmitContext ec) - { - return true; - } - - protected override void DoEmit (EmitContext ec) - { - iterator.cc.EmitInitScope (ec); - } - } - void Define_Reset () { Method reset = new Method ( @@ -1182,7 +1634,7 @@ reset.Block = new ToplevelBlock (Location); reset.Block = new ToplevelBlock (block, parameters, Location); - reset.Block.SetHaveAnonymousMethods (Location, move_next_method); + reset.Block.SetHaveAnonymousMethods (Location, this); reset.Block.AddStatement (Create_ThrowNotSupported ()); } @@ -1196,13 +1648,14 @@ AddMethod (dispose); dispose.Block = new ToplevelBlock (block, parameters, Location); - dispose.Block.SetHaveAnonymousMethods (Location, move_next_method); + dispose.Block.SetHaveAnonymousMethods (Location, this); dispose.Block.AddStatement (new DisposeMethod (this, Location)); } +#endif public Type IteratorType { - get { return iterator_type_expr.Type; } + get { return IteratorHost.IteratorType; } } // @@ -1212,10 +1665,10 @@ class NoCheckReturn : Statement { public Expression Expr; - public NoCheckReturn (Expression expr, Location l) + public NoCheckReturn (Expression expr) { Expr = expr; - loc = l; + loc = expr.Location; } public override bool Resolve (EmitContext ec) @@ -1236,10 +1689,53 @@ } } - bool CheckType () + public static Iterator CreateIterator (IMethodData method, TypeContainer parent, + GenericMethod generic, int modifiers) { - Type ret = orig_method.ReturnType; + bool is_enumerable; + Type iterator_type; + if (!CheckType (method.ReturnType, out iterator_type, out is_enumerable)) { + Report.Error (1624, method.Location, + "The body of `{0}' cannot be an iterator block " + + "because `{1}' is not an iterator interface type", + method.GetSignatureForError (), + TypeManager.CSharpName (method.ReturnType)); + return null; + } + + Report.Debug (64, "CREATE ITERATOR", parent, method, method.Block); + +#if FIXME + ToplevelBlock container = new ToplevelBlock ( + method.Block, method.ParameterInfo, method.Location); +#endif + + ToplevelBlock block = new ToplevelBlock (method.ParameterInfo, method.Location); + // method.Block.ReParent (block); + + Iterator iterator = new Iterator ( + method, parent, generic, null, block, modifiers, + iterator_type, is_enumerable); + + if (!iterator.RootScope.Define ()) + return null; + if (iterator.RootScope.DefineType () == null) + return null; + if (!iterator.RootScope.ResolveType ()) + return null; + + Report.Debug (64, "CREATE ITERATOR #1", iterator, iterator.RootScope, + iterator.RootScope.IsGeneric, iterator.RootScope.TypeBuilder); + + return iterator; + } + + static bool CheckType (Type ret, out Type original_iterator_type, out bool is_enumerable) + { + original_iterator_type = null; + is_enumerable = false; + if (ret == TypeManager.ienumerable_type) { original_iterator_type = TypeManager.object_type; is_enumerable = true; Index: cs-parser.jay =================================================================== --- cs-parser.jay (revision 63019) +++ cs-parser.jay (working copy) @@ -45,6 +45,9 @@ Delegate current_delegate; + GenericMethod current_generic_method; + AnonymousMethodExpression current_anonymous_method; + /// /// This is used by the unary_expression code to resolve /// a name against a parameter. @@ -1074,6 +1077,7 @@ method.Block = (ToplevelBlock) $3; current_container.AddMethod (method); + current_generic_method = null; current_local_parameters = null; iterator_container = null; @@ -1133,6 +1137,7 @@ name, (Parameters) $6, (Attributes) $1); current_local_parameters = (Parameters) $6; + current_generic_method = generic; if (RootContext.Documentation != null) method.DocComment = Lexer.consume_doc_comment (); @@ -1169,6 +1174,7 @@ (int) $2, false, name, (Parameters) $6, (Attributes) $1); current_local_parameters = (Parameters) $6; + current_generic_method = generic; if (RootContext.Documentation != null) method.DocComment = Lexer.consume_doc_comment (); @@ -3396,6 +3402,7 @@ if (oob_stack == null) oob_stack = new Stack (6); + oob_stack.Push (current_anonymous_method); oob_stack.Push (current_local_parameters); current_local_parameters = (Parameters)$2; @@ -3403,7 +3410,12 @@ oob_stack.Push (current_block); oob_stack.Push (top_current_block); current_block = null; - } + + Location loc = (Location) $1; + current_anonymous_method = new AnonymousMethodExpression ( + current_anonymous_method, current_generic_method, current_container, + (Parameters) $2, (ToplevelBlock) top_current_block, loc); + } block { Location loc = (Location) $1; @@ -3416,11 +3428,16 @@ ToplevelBlock anon_block = (ToplevelBlock) $4; anon_block.Parent = current_block; - $$ = new AnonymousMethod (current_container, (Parameters) $2, (ToplevelBlock) top_current_block, - anon_block, loc); + + current_anonymous_method.Block = anon_block; + anon_block.SetHaveAnonymousMethods (loc, current_anonymous_method); + + $$ = current_anonymous_method; } - current_local_parameters = (Parameters) oob_stack.Pop (); - } + + current_local_parameters = (Parameters) oob_stack.Pop (); + current_anonymous_method = (AnonymousMethodExpression) oob_stack.Pop (); + } ; opt_anonymous_method_signature @@ -4000,7 +4017,8 @@ : OPEN_BRACE { if (current_block == null){ - current_block = new ToplevelBlock ((ToplevelBlock) top_current_block, current_local_parameters, (Location) $1); + current_block = new ToplevelBlock ((ToplevelBlock) top_current_block, current_local_parameters, + current_generic_method, (Location) $1); top_current_block = current_block; } else { current_block = new Block (current_block, (Location) $1, Location.Null); Index: convert.cs =================================================================== --- convert.cs (revision 63019) +++ convert.cs (working copy) @@ -838,8 +838,8 @@ if (!TypeManager.IsDelegateType (target_type)) return false; - AnonymousMethod am = (AnonymousMethod) expr; - return am.ImplicitStandardConversionExists (target_type); + AnonymousMethodExpression ame = (AnonymousMethodExpression) expr; + return ame.ImplicitStandardConversionExists (target_type); } return false; @@ -1325,10 +1325,11 @@ return null; } - AnonymousMethod am = (AnonymousMethod) expr; + AnonymousMethodExpression ame = (AnonymousMethodExpression) expr; + int errors = Report.Errors; - Expression conv = am.Compatible (ec, target_type); + Expression conv = ame.Compatible (ec, target_type); if (conv != null) return conv; Index: anonymous.cs =================================================================== --- anonymous.cs (revision 63019) +++ anonymous.cs (working copy) @@ -20,297 +20,721 @@ namespace Mono.CSharp { - public abstract class AnonymousContainer : Expression + public abstract class CompilerGeneratedClass : Class { - // Used to generate unique method names. - protected static int anonymous_method_count; - - // An array list of AnonymousMethodParameter or null - public Parameters Parameters; - - // - // The block that makes up the body for the anonymous mehtod - // - public ToplevelBlock Block; + GenericMethod generic_method; + static int next_index = 0; - // - // The container block for this anonymous method. - // - public Block ContainingBlock; + private static MemberName MakeProxyName (GenericMethod generic, Location loc) + { + string name = String.Format ("<>c__CompilerGenerated{0}", ++next_index); + if (generic != null) { + TypeArguments args = new TypeArguments (loc); + foreach (TypeParameter tparam in generic.CurrentTypeParameters) + args.Add (new SimpleName (tparam.Name, loc)); + return new MemberName (name, args, loc); + } else + return new MemberName (name, loc); + } - // - // The implicit method we create - // - public Method method; + protected string MakeName (string prefix) + { + return String.Format ("<>c__{0}{1}", prefix, ++next_index); + } - protected MethodInfo invoke_mb; - - // The emit context for the anonymous method - public EmitContext aec; - public string[] TypeParameters; - public Type[] TypeArguments; - protected bool unreachable; + protected CompilerGeneratedClass (TypeContainer parent, GenericMethod generic, + int mod, Location loc) + : base (parent.NamespaceEntry, parent, + MakeProxyName (generic, loc), mod, null) + { + this.generic_method = generic; - // The method scope - ScopeInfo method_scope; - bool computed_method_scope = false; - - // - // The modifiers applied to the method, we aggregate them - // - protected int method_modifiers = Modifiers.PRIVATE; - - // - // Track the scopes that this method has used. At the - // end this is used to determine the ScopeInfo that will - // host the method - // - ArrayList scopes_used = new ArrayList (); - - // - // Points to our container anonymous method if its present - // - public AnonymousContainer ContainerAnonymousMethod; + if (generic != null) { + ArrayList list = new ArrayList (); + foreach (TypeParameter tparam in generic.TypeParameters) { + if (tparam.Constraints != null) + list.Add (tparam.Constraints.Clone ()); + } + SetParameterInfo (list); + } - protected AnonymousContainer (Parameters parameters, ToplevelBlock container, - ToplevelBlock block, Location l) + parent.AddCompilerGeneratedClass (this); + } + + protected override bool DefineNestedTypes () { - Parameters = parameters; - Block = block; - loc = l; + RootContext.RegisterCompilerGeneratedType (TypeBuilder); + return base.DefineNestedTypes (); + } - // - // The order is important: this setups the CaptureContext tree hierarchy. - // - if (container == null) { - return; + protected override bool DoDefineMembers () + { + if (!PopulateType ()) + throw new InternalErrorException (); + + members_defined = true; + + if (!base.DoDefineMembers ()) + return false; + + if (CompilerGenerated != null) { + foreach (CompilerGeneratedClass c in CompilerGenerated) { + if (!c.DefineMembers ()) + throw new InternalErrorException (); + } } - container.SetHaveAnonymousMethods (l, this); - block.SetHaveAnonymousMethods (l, this); + + return true; } - protected AnonymousContainer (Parameters parameters, ToplevelBlock container, - Location l): - this (parameters, container, new ToplevelBlock (container, parameters, l), l) + protected virtual bool PopulateType () { + if (type_populated) + return true; + + type_populated = true; + + if (!DoPopulateType ()) + return false; + + if (CompilerGenerated != null) { + foreach (CompilerGeneratedClass c in CompilerGenerated) { + if (!c.PopulateType ()) + return false; + } + } + + return true; } - public override Expression DoResolve (EmitContext ec) + protected virtual bool DoPopulateType () { - // - // Set class type, set type - // + return true; + } - eclass = ExprClass.Value; + public GenericMethod GenericMethod { + get { return generic_method; } + } - // - // This hack means `The type is not accessible - // anywhere', we depend on special conversion - // rules. - // - type = TypeManager.anonymous_method_type; + protected TypeExpr InflateType (Type it) + { + if (generic_method == null) + return new TypeExpression (it, Location); - return this; + if (it.IsGenericParameter && (it.DeclaringMethod != null)) { + int pos = it.GenericParameterPosition; + it = CurrentTypeParameters [pos].Type; + } else if (it.IsGenericType) { + Type[] args = it.GetGenericArguments (); + + TypeArguments inflated = new TypeArguments (Location); + foreach (Type t in args) + inflated.Add (InflateType (t)); + + return new ConstructedType (it, inflated, Location); + } else if (it.IsArray) { + TypeExpr et_expr = InflateType (it.GetElementType ()); + int rank = it.GetArrayRank (); + + Type et = et_expr.ResolveAsTypeTerminal (this, false).Type; + it = et.MakeArrayType (rank); + } + + return new TypeExpression (it, Location); } - public void RegisterScope (ScopeInfo scope) + public Field CaptureVariable (string name, Type type) { - if (scopes_used.Contains (scope)) - return; - scopes_used.Add (scope); + if (members_defined) + throw new InternalErrorException ("Helper class already defined!"); + if (type == null) + throw new ArgumentNullException (); + + return new CapturedVariable (this, name, InflateType (type)); } - // Returns the deepest of two scopes - ScopeInfo Deepest (ScopeInfo a, ScopeInfo b) + bool type_populated; + bool members_defined; + + internal void CheckMembersDefined () { - ScopeInfo p; + if (members_defined) + throw new InternalErrorException ("Helper class already defined!"); + } - if (a == null) - return b; - if (b == null) - return a; - if (a == b) - return a; + public override void EmitType () + { + Report.Debug (64, "COMPILER GENERATED EMIT TYPE", this, CompilerGenerated); + base.EmitType (); + } - // - // If they Scopes are on the same CaptureContext, we do the double - // checks just so if there is an invariant change in the future, - // we get the exception at the end - // - for (p = a; p != null; p = p.ParentScope) - if (p == b) - return a; - - for (p = b; p != null; p = p.ParentScope) - if (p == a) - return b; + protected class CapturedVariable : Field + { + public CapturedVariable (CompilerGeneratedClass helper, string name, + TypeExpr type) + : base (helper, type, Modifiers.INTERNAL, name, null, helper.Location) + { + helper.AddField (this); + } + } + } - CaptureContext ca = a.CaptureContext; - CaptureContext cb = b.CaptureContext; + public abstract class ScopeInfoBase : CompilerGeneratedClass + { + public CaptureContext CaptureContext; - for (CaptureContext c = ca; c != null; c = c.ParentCaptureContext) - if (c == cb) - return a; + protected ScopeInfoBase (TypeContainer parent, GenericMethod generic, + int mod, Location loc) + : base (parent, generic, mod, loc) + { } - for (CaptureContext c = cb; c != null; c = c.ParentCaptureContext) - if (c == ca) - return b; - throw new Exception ("Should never be reached"); + TypeExpr scope_type; + Field scope_instance; + ScopeInitializerBase scope_initializer; + + public abstract AnonymousMethodHost Host { + get; } - // - // Determines the proper host for a method considering the - // scopes it references - // - public void ComputeMethodHost () + public Field ScopeInstance { + get { return scope_instance; } + } + + public Type ScopeType { + get { return scope_type.Type; } + } + + public void EmitScopeInstance (EmitContext ec) { - if (computed_method_scope) - return; - - method_scope = null; - int top = scopes_used.Count; - computed_method_scope = true; + if (scope_initializer == null) { + // + // This is needed if someone overwrites the Emit method + // of Statement and manually calls Block.Emit without + // this snippet first: + // + // ec.EmitScopeInitFromBlock (The_Block); + // The_Block.Emit (ec); + // + throw new InternalErrorException (); + } - if (top == 0) - return; - - method_scope = (ScopeInfo) scopes_used [0]; - if (top == 1) - return; - - for (int i = 1; i < top; i++) - method_scope = Deepest (method_scope, (ScopeInfo) scopes_used [i]); + Report.Debug (64, "EMIT SCOPE INSTANCE", this, GetType (), scope_initializer); + if (this is IteratorHost) + ec.ig.Emit (OpCodes.Ldarg_0); + else + scope_initializer.Emit (ec); } - public ScopeInfo Scope { - get { - if (computed_method_scope) - return method_scope; + public ExpressionStatement GetScopeInitializer (EmitContext ec) + { + Report.Debug (64, "GET SCOPE INITIALIZER", this, GetType (), scope_initializer); + if (scope_initializer == null) { + scope_initializer = CreateScopeInitializer (); + if (scope_initializer.Resolve (ec) == null) + throw new InternalErrorException (); + } - // - // This means that ComputeMethodHost is not being called, most - // likely by someone who overwrote the CreateMethodHost method - // - throw new Exception ("Internal error, AnonymousContainer.Scope is being used before its container is computed"); + return scope_initializer; + } + + protected abstract ScopeInitializerBase CreateScopeInitializer (); + + protected override bool DoPopulateType () + { + Report.Debug (64, "SCOPE INFO RESOLVE TYPE", this, GetType (), IsGeneric, + Parent.IsGeneric, GenericMethod); + + if (IsGeneric) { + TypeArguments targs = new TypeArguments (Location); + if (Parent.IsGeneric) + foreach (TypeParameter t in Parent.TypeParameters) + targs.Add (new TypeParameterExpr (t, Location)); + if (GenericMethod != null) + foreach (TypeParameter t in GenericMethod.TypeParameters) + targs.Add (new TypeParameterExpr (t, Location)); + + scope_type = new ConstructedType (TypeBuilder, targs, Location); + scope_type = scope_type.ResolveAsTypeTerminal (this, false); + if ((scope_type == null) || (scope_type.Type == null)) + return false; + } else { + scope_type = new TypeExpression (TypeBuilder, Location); } + + if (Host != this) + scope_instance = Host.CaptureVariable (MakeName ("scope"), ScopeType); + + return base.DoPopulateType (); } - - - protected abstract bool CreateMethodHost (EmitContext ec); - public abstract void CreateScopeType (EmitContext ec, ScopeInfo scope); + protected abstract class ScopeInitializerBase : ExpressionStatement + { + ScopeInfoBase scope; + protected Variable scope_instance; + ConstructorInfo scope_ctor; - public abstract Iterator Iterator { - get; + bool initialized; + + protected ScopeInitializerBase (ScopeInfoBase scope) + { + this.scope = scope; + this.loc = scope.Location; + eclass = ExprClass.Value; + } + + public ScopeInfoBase Scope { + get { return scope; } + } + + public override Expression DoResolve (EmitContext ec) + { + if (scope_ctor != null) + return this; + + Report.Debug (64, "RESOLVE SCOPE INITIALIZER BASE", this, Scope); + + type = Scope.ScopeType; + + if (!DoResolveInternal (ec)) + throw new InternalErrorException (); + + return this; + } + + protected virtual bool DoResolveInternal (EmitContext ec) + { + MethodGroupExpr mg = (MethodGroupExpr) Expression.MemberLookupFinal ( + ec, ec.ContainerType, type, ".ctor", MemberTypes.Constructor, + AllBindingFlags | BindingFlags.DeclaredOnly, loc); + if (mg == null) + throw new InternalErrorException (); + + scope_ctor = (ConstructorInfo) mg.Methods [0]; + + if (Scope.ScopeInstance != null) + scope_instance = new CapturedField (Scope.ScopeInstance); + else { + LocalBuilder local = ec.ig.DeclareLocal (type); + scope_instance = new CapturedTemporary (Scope, local); + } + return true; + } + + static int next_id; + int id = ++next_id; + + protected void DoEmit (EmitContext ec) + { + if (initialized) + return; + initialized = true; + + Report.Debug (64, "EMIT SCOPE INIT", this, id, + Scope, scope_instance, ec); + + ec.ig.Emit (OpCodes.Nop); + ec.ig.Emit (OpCodes.Ldc_I4, id); + ec.ig.Emit (OpCodes.Pop); + ec.ig.Emit (OpCodes.Nop); + + DoEmitInternal (ec); + } + + protected virtual void EmitScopeConstructor (EmitContext ec) + { + ec.ig.Emit (OpCodes.Newobj, scope_ctor); + } + + protected virtual void DoEmitInternal (EmitContext ec) + { + scope_instance.EmitInstance (ec); + EmitScopeConstructor (ec); + scope_instance.EmitAssign (ec); + } + + public override void Emit (EmitContext ec) + { + DoEmit (ec); + scope_instance.EmitInstance (ec); + scope_instance.Emit (ec); + } + + public override void EmitStatement (EmitContext ec) + { + DoEmit (ec); + } } - public abstract bool IsIterator { - get; + protected class CapturedTemporary : Variable { + public readonly ScopeInfoBase Scope; + public readonly LocalBuilder Local; + + public CapturedTemporary (ScopeInfoBase scope, LocalBuilder local) + { + this.Scope = scope; + this.Local = local; + } + + public override Type Type { + get { return Local.LocalType; } + } + + public override bool HasInstance { + get { return false; } + } + + public override bool NeedsTemporary { + get { return false; } + } + + public override void EmitInstance (EmitContext ec) + { } + + public override void Emit (EmitContext ec) + { + ec.ig.Emit (OpCodes.Ldloc, Local); + } + + public override void EmitAssign (EmitContext ec) + { + ec.ig.Emit (OpCodes.Stloc, Local); + } + + public override void EmitAddressOf (EmitContext ec) + { + ec.ig.Emit (OpCodes.Ldloca, Local); + } } + + protected class CapturedField : Variable { + public readonly Field Field; + + public CapturedField (Field field) + { + this.Field = field; + } + + public override Type Type { + get { return Field.MemberType; } + } + + public override bool HasInstance { + get { return true; } + } + + public override bool NeedsTemporary { + get { return true; } + } + + public override void EmitInstance (EmitContext ec) + { + ec.ig.Emit (OpCodes.Ldarg_0); + } + + public override void Emit (EmitContext ec) + { + ec.ig.Emit (OpCodes.Ldfld, Field.FieldBuilder); + } + + public override void EmitAssign (EmitContext ec) + { + ec.ig.Emit (OpCodes.Stfld, Field.FieldBuilder); + } + + public override void EmitAddressOf (EmitContext ec) + { + ec.ig.Emit (OpCodes.Ldflda, Field.FieldBuilder); + } + } } - public class AnonymousMethod : AnonymousContainer + public class AnonymousMethodHost : ScopeInfo { - TypeContainer host; + public AnonymousMethodHost (CaptureContext cc, ToplevelBlock toplevel, + TypeContainer parent, GenericMethod generic) + : base (cc, toplevel, parent, generic) + { } - // - // The value return by the Compatible call, this ensure that - // the code works even if invoked more than once (Resolve called - // more than once, due to the way Convert.ImplicitConversion works - // - Expression anonymous_delegate; + public bool HostsParameters = false; - public AnonymousMethod (TypeContainer host, Parameters parameters, ToplevelBlock container, - ToplevelBlock block, Location l) - : base (parameters, container, block, l) + TypeExpr parent_type; + CapturedVariable parent_link; + CapturedVariable this_field; + + public override AnonymousMethodHost Host { + get { return this; } + } + + public AnonymousMethodHost ParentHost { + get { return Parent as AnonymousMethodHost; } + } + + public Type ParentType { + get { return parent_type.Type; } + } + + public Field ParentLink { + get { return parent_link; } + } + + public Field THIS { + get { return this_field; } + } + + public Field CaptureThis () { - this.host = host; + CheckMembersDefined (); + if (Parent is CompilerGeneratedClass) + throw new InternalErrorException ("CaptureThis called in inner class!"); + + if (this_field == null) + this_field = new CapturedVariable (this, "<>THIS", parent_type); + return this_field; } - public override Iterator Iterator { - get { return null; } + protected override ScopeInitializerBase CreateScopeInitializer () + { + return new AnonymousMethodHostInitializer (this); } - public override bool IsIterator { - get { return false; } + protected override bool DefineNestedTypes () + { + Report.Debug (64, "ANONYMOUS METHOD HOST NESTED", + this, Name, Parent, Parent.Name, Parent.IsGeneric); + + if (Parent.IsGeneric) { + parent_type = new ConstructedType ( + Parent.TypeBuilder, Parent.TypeParameters, Location); + parent_type = parent_type.ResolveAsTypeTerminal (this, false); + if ((parent_type == null) || (parent_type.Type == null)) + return false; + } else { + parent_type = new TypeExpression (Parent.TypeBuilder, Location); + } + + CompilerGeneratedClass parent = Parent as CompilerGeneratedClass; + if (parent != null) + parent_link = new CapturedVariable (this, "<>parent", parent_type); + + return base.DefineNestedTypes (); } - public override void Emit (EmitContext ec) + protected override bool DoDefineMembers () { - // nothing, as we only exist to not do anything. + Report.Debug (64, "ANONYMOUS METHOD HOST DEFINE MEMBERS", + this, Name, Parent, CompilerGenerated); + + ArrayList args = new ArrayList (); + if (this is IteratorHost) + args.Add (new Parameter ( + TypeManager.int32_type, "$PC", Parameter.Modifier.NONE, + null, Location)); + + Field pfield = Parent is CompilerGeneratedClass ? parent_link : this_field; + if (pfield != null) + args.Add (new Parameter ( + pfield.MemberType, "parent", Parameter.Modifier.NONE, + null, Location)); + + if (HostsParameters) { + Hashtable hash = CaptureContext.captured_parameters; + foreach (CapturedParameter cp in hash.Values) { + args.Add (new Parameter ( + cp.Field.MemberType, cp.Field.Name, + Parameter.Modifier.NONE, null, Location)); + } + } + + Parameter[] ctor_params = new Parameter [args.Count]; + args.CopyTo (ctor_params, 0); + Constructor ctor = new Constructor ( + this, MemberName.Name, Modifiers.PUBLIC, + new Parameters (ctor_params), + new GeneratedBaseInitializer (Location), + Location); + AddConstructor (ctor); + + ctor.Block = new ToplevelBlock (null, Location); + ctor.Block.AddStatement (new TheCtor (this)); + + return base.DoDefineMembers (); } - // - // Creates the host for the anonymous method - // - protected override bool CreateMethodHost (EmitContext ec) + protected virtual void EmitScopeConstructor (EmitContext ec) { - ComputeMethodHost (); + int pos = (this is IteratorHost) ? 2 : 1; + Field pfield = Parent is CompilerGeneratedClass ? parent_link : this_field; + if (pfield != null) { + ec.ig.Emit (OpCodes.Ldarg_0); + ec.ig.Emit (OpCodes.Ldarg_1); + ec.ig.Emit (OpCodes.Stfld, pfield.FieldBuilder); + pos++; + } - // - // Crude hack follows: we replace the TypeBuilder during the - // definition to get the method hosted in the right class - // - TypeBuilder current_type = ec.TypeContainer.TypeBuilder; - TypeBuilder type_host = (Scope == null ) ? current_type : Scope.ScopeTypeBuilder; + if (HostsParameters) { + Hashtable hash = CaptureContext.captured_parameters; + foreach (CapturedParameter cp in hash.Values) { + ec.ig.Emit (OpCodes.Ldarg_0); + ParameterReference.EmitLdArg (ec.ig, pos++); + ec.ig.Emit (OpCodes.Stfld, cp.Field.FieldBuilder); + } + } + } - if (current_type == null) - throw new Exception ("The current_type is null"); - - if (type_host == null) - throw new Exception (String.Format ("Type host is null, method_host is {0}", Scope == null ? "null" : "Not null")); + protected class TheCtor : Statement + { + AnonymousMethodHost host; - if (current_type != type_host) - method_modifiers = Modifiers.INTERNAL; + public TheCtor (AnonymousMethodHost host) + { + this.host = host; + } - if (current_type == type_host && ec.IsStatic){ - method_modifiers |= Modifiers.STATIC; - current_type = null; - } + public override bool Resolve (EmitContext ec) + { + return true; + } - string name = "<#AnonymousMethod>" + anonymous_method_count++; - MemberName member_name; + protected override void DoEmit (EmitContext ec) + { + host.EmitScopeConstructor (ec); + } + } - GenericMethod generic_method = null; - if (TypeParameters != null) { - TypeArguments args = new TypeArguments (loc); - foreach (string t in TypeParameters) - args.Add (new SimpleName (t, loc)); + protected class AnonymousMethodHostInitializer : ScopeInitializer + { + AnonymousMethodHost host; + ExpressionStatement parent_init; - member_name = new MemberName (name, args, loc); + public AnonymousMethodHostInitializer (AnonymousMethodHost host) + : base (host) + { + this.host = host; + } - generic_method = new GenericMethod ( - ec.DeclContainer.NamespaceEntry, - (TypeContainer) ec.TypeContainer, member_name, - new TypeExpression (invoke_mb.ReturnType, loc), - Parameters); + public AnonymousMethodHost Host { + get { return host; } + } - generic_method.SetParameterInfo (null); - } else - member_name = new MemberName (name, loc); + protected override bool DoResolveInternal (EmitContext ec) + { + Report.Debug (64, "RESOLVE ANONYMOUS METHOD HOST INITIALIZER", + this, Host, Host.ScopeType, Host.ParentType, loc); - method = new Method ( - (TypeContainer) ec.TypeContainer, generic_method, - new TypeExpression (invoke_mb.ReturnType, loc), - method_modifiers, false, member_name, Parameters, null); - method.Block = Block; + // + // Copy the parameter values, if any + // + if (Host.HostsParameters){ + Hashtable hash = Host.CaptureContext.captured_parameters; + foreach (CapturedParameter cp in hash.Values) { + FieldExpr fe = (FieldExpr) Expression.MemberLookup ( + ec.ContainerType, type, cp.Field.Name, loc); + if (fe == null) + throw new InternalErrorException (); - // - // Swap the TypeBuilder while we define the method, then restore - // - if (current_type != null) - ec.TypeContainer.TypeBuilder = type_host; - bool res = method.Define (); - if (current_type != null) - ec.TypeContainer.TypeBuilder = current_type; + fe.InstanceExpression = this; + cp.FieldInstance = fe; + } + } - return res; + return base.DoResolveInternal (ec); + } + + protected override void EmitScopeConstructor (EmitContext ec) + { + if ((host.THIS != null) || (host.ParentLink != null)) + ec.ig.Emit (OpCodes.Ldarg_0); + + if (Host.HostsParameters) { + Hashtable hash = Host.CaptureContext.captured_parameters; + foreach (CapturedParameter cp in hash.Values) { + EmitParameterReference (ec, cp); + } + } + + base.EmitScopeConstructor (ec); + } } + } + + public interface IAnonymousContainer + { + ToplevelBlock Container { + get; + } + + GenericMethod GenericMethod { + get; + } + + AnonymousMethodHost RootScope { + get; + } + + bool IsIterator { + get; + } + } + + public class AnonymousMethodExpression : Expression, IAnonymousContainer + { + public readonly AnonymousMethodExpression Parent; + public readonly TypeContainer Host; + public readonly Parameters Parameters; + + public ToplevelBlock Block; + protected AnonymousMethod anonymous; + + protected readonly ToplevelBlock container; + protected readonly GenericMethod generic; + + public ToplevelBlock Container { + get { return container; } + } + + public GenericMethod GenericMethod { + get { return generic; } + } + + public AnonymousMethod AnonymousMethod { + get { return anonymous; } + } + + public AnonymousMethodHost RootScope { + get { return container.AnonymousMethodHost; } + } + + public AnonymousMethodExpression (AnonymousMethodExpression parent, + GenericMethod generic, TypeContainer host, + Parameters parameters, ToplevelBlock container, + Location loc) + { + this.Parent = parent; + this.generic = parent != null ? null : generic; + this.Host = host; + this.Parameters = parameters; + this.container = container; + this.loc = loc; + + Report.Debug (64, "NEW ANONYMOUS METHOD EXPRESSION", this, parent, host, + container, loc); + + container.SetHaveAnonymousMethods (loc, this); + container.CreateAnonymousMethodHost (Host); + } + + public override string ExprClassName { + get { + return "anonymous method"; + } + } + void Error_ParameterMismatch (Type t) { Report.Error (1661, loc, "Anonymous method could not be converted to delegate `" + - "{0}' since there is a parameter mismatch", TypeManager.CSharpName (t)); + "{0}' since there is a parameter mismatch", + TypeManager.CSharpName (t)); } public bool ImplicitStandardConversionExists (Type delegate_type) @@ -318,8 +742,9 @@ if (Parameters == null) return true; - MethodGroupExpr invoke_mg = Delegate.GetInvokeMethod (host.TypeBuilder, delegate_type, loc); - invoke_mb = (MethodInfo) invoke_mg.Methods [0]; + MethodGroupExpr invoke_mg = Delegate.GetInvokeMethod ( + Host.TypeBuilder, delegate_type, loc); + MethodInfo invoke_mb = (MethodInfo) invoke_mg.Methods [0]; ParameterData invoke_pd = TypeManager.GetParameterData (invoke_mb); if (Parameters.Count != invoke_pd.Count) @@ -338,31 +763,20 @@ // public Expression Compatible (EmitContext ec, Type delegate_type) { - if (anonymous_delegate != null) - return anonymous_delegate; - + if (anonymous != null) + return anonymous.AnonymousDelegate; + // // At this point its the first time we know the return type that is // needed for the anonymous method. We create the method here. // - MethodGroupExpr invoke_mg = Delegate.GetInvokeMethod (ec.ContainerType, delegate_type, loc); - invoke_mb = (MethodInfo) invoke_mg.Methods [0]; + MethodGroupExpr invoke_mg = Delegate.GetInvokeMethod ( + ec.ContainerType, delegate_type, loc); + MethodInfo invoke_mb = (MethodInfo) invoke_mg.Methods [0]; ParameterData invoke_pd = TypeManager.GetParameterData (invoke_mb); - if (delegate_type.IsGenericType) { - Type def = delegate_type.GetGenericTypeDefinition (); - - if (def != delegate_type) { - Type[] tparam = TypeManager.GetTypeArguments (def); - - TypeArguments = TypeManager.GetTypeArguments (delegate_type); - TypeParameters = new string [tparam.Length]; - for (int i = 0; i < tparam.Length; i++) - TypeParameters [i] = tparam [i].Name; - } - } - + Parameters parameters; if (Parameters == null) { // // We provide a set of inaccessible parameters @@ -375,7 +789,9 @@ "+" + i, invoke_pd.ParameterModifier (i), null, loc); } - Parameters = new Parameters (fixedpars); + parameters = new Parameters (fixedpars); + if (!parameters.Resolve (ec)) + return null; } else { if (Parameters.Count != invoke_pd.Count) { Report.SymbolRelatedToPreviousError (delegate_type); @@ -407,8 +823,10 @@ return null; } } + + parameters = Parameters; } - + // // Second: the return type of the delegate must be compatible with // the anonymous type. Instead of doing a pass to examine the block @@ -419,135 +837,329 @@ //MethodBuilder builder = method_data.MethodBuilder; //ILGenerator ig = builder.GetILGenerator (); - aec = new EmitContext (ec.ResolveContext, - ec.TypeContainer, ec.DeclContainer, loc, null, - invoke_mb.ReturnType, - /* REVIEW */ (ec.InIterator ? Modifiers.METHOD_YIELDS : 0) | - (ec.InUnsafe ? Modifiers.UNSAFE : 0) | - (ec.IsStatic ? Modifiers.STATIC : 0), - /* No constructor */ false); + Report.Debug (64, "COMPATIBLE", this, Parent, GenericMethod, Host, + Container, Block, invoke_mb.ReturnType, delegate_type, + delegate_type.IsGenericType, loc); - aec.CurrentAnonymousMethod = this; - ContainerAnonymousMethod = ec.CurrentAnonymousMethod; - ContainingBlock = ec.CurrentBlock; + anonymous = new AnonymousMethod ( + Parent != null ? Parent.AnonymousMethod : null, Host, + GenericMethod, parameters, Container, Block, invoke_mb.ReturnType, + delegate_type, loc); - if (aec.ResolveTopBlock (ec, Block, Parameters, null, out unreachable)){ - anonymous_delegate = new AnonymousDelegate ( - this, delegate_type, loc).Resolve (ec); - return anonymous_delegate; - } - return null; + if (!anonymous.Resolve (ec)) + return null; + + return anonymous.AnonymousDelegate; } public override Expression DoResolve (EmitContext ec) { - if (!ec.IsAnonymousMethodAllowed) { - Report.Error (1706, loc, "Anonymous methods are not allowed in the attribute declaration"); - return null; - } + // + // Set class type, set type + // - if (Parameters != null && !Parameters.Resolve (ec)) { + eclass = ExprClass.Value; + + // + // This hack means `The type is not accessible + // anywhere', we depend on special conversion + // rules. + // + type = TypeManager.anonymous_method_type; + + if ((Parameters != null) && !Parameters.Resolve (ec)) return null; - } - return base.DoResolve (ec); + return this; } + public override void Emit (EmitContext ec) + { + // nothing, as we only exist to not do anything. + } - public override string ExprClassName { - get { - return "anonymous method"; - } + public bool IsIterator { + get { return false; } } + } - public MethodInfo GetMethodBuilder () + public abstract class AnonymousContainer : IAnonymousContainer + { + // Used to generate unique method names. + protected static int anonymous_method_count; + + public readonly Location Location; + + // An array list of AnonymousMethodParameter or null + public readonly Parameters Parameters; + + // + // The block that makes up the body for the anonymous mehtod + // + public readonly ToplevelBlock Block; + + public readonly Type ReturnType; + public readonly TypeContainer Host; + + // + // The implicit method we create + // + protected Method method; + protected EmitContext aec; + + // The emit context for the anonymous method + protected bool unreachable; + protected readonly Location loc; + protected readonly ToplevelBlock container; + protected readonly GenericMethod generic; + protected readonly AnonymousMethodHost root_scope; + + // + // Points to our container anonymous method if its present + // + public readonly AnonymousContainer ContainerAnonymousMethod; + + protected AnonymousContainer (AnonymousContainer parent, TypeContainer host, + GenericMethod generic, Parameters parameters, + ToplevelBlock container, ToplevelBlock block, + Type return_type, int mod, Location loc) { - MethodInfo builder = method.MethodBuilder; - if (TypeArguments != null) - return builder.MakeGenericMethod (TypeArguments); - else - return builder; + this.ContainerAnonymousMethod = parent; + this.ReturnType = return_type; + this.Host = host; + + this.container = container; + this.generic = parent != null ? null : generic; + this.root_scope = container.AnonymousMethodHost; + this.Parameters = parameters; + this.Block = block; + this.loc = loc; } - public override string GetSignatureForError () +#if FIXME + protected AnonymousContainer (TypeContainer host, GenericMethod generic, + Parameters parameters, ToplevelBlock container, + int mod, Location loc) + : this (null, generic, host, parameters, container, null, mod, loc) { - string s = TypeManager.CSharpSignature (invoke_mb); - return s.Substring (0, s.IndexOf (".Invoke(")); + Block = new ToplevelBlock (container, parameters, loc); + Block.SetHaveAnonymousMethods (loc, this); } - - public bool EmitMethod (EmitContext ec) +#endif + + public Method Method { + get { return method; } + } + + public virtual AnonymousMethodHost RootScope { + get { return root_scope; } + } + + public ScopeInfo Scope { + get { return ContainerCaptureContext.Scope; } + } + + public string GetSignatureForError () { - if (!CreateMethodHost (ec)) + return RootScope.GetSignatureForError (); + } + + protected virtual CaptureContext ContainerCaptureContext { + get { return Container.CaptureContext; } + } + + protected virtual CaptureContext CaptureContext { + get { return Block.CaptureContext; } + } + + public virtual bool Resolve (EmitContext ec) + { + if (!ec.IsAnonymousMethodAllowed) { + Report.Error (1706, loc, + "Anonymous methods are not allowed in the " + + "attribute declaration"); return false; + } - MethodBuilder builder = method.MethodBuilder; - ILGenerator ig = builder.GetILGenerator (); - aec.ig = ig; + Report.Debug (64, "RESOLVE ANONYMOUS METHOD", this, loc, ec, + RootScope, Parameters, ec.IsStatic); - Parameters.ApplyAttributes (builder); + aec = new EmitContext ( + ec.ResolveContext, ec.TypeContainer, RootScope, loc, null, ReturnType, + /* REVIEW */ (ec.InIterator ? Modifiers.METHOD_YIELDS : 0) | + (ec.InUnsafe ? Modifiers.UNSAFE : 0), /* No constructor */ false); - // - // Adjust based on the computed state of the - // method from CreateMethodHost - - aec.MethodIsStatic = (method_modifiers & Modifiers.STATIC) != 0; - - aec.EmitMeta (Block); - aec.EmitResolvedTopBlock (Block, unreachable); + aec.capture_context = CaptureContext; + aec.CurrentAnonymousMethod = this; + + Report.Debug (64, "RESOLVE ANONYMOUS METHOD #1", this, loc, ec, aec, + RootScope, Parameters, Block, Block.CaptureContext); + + bool unreachable; + if (!aec.ResolveTopBlock (ec, Block, Parameters, null, out unreachable)) + return false; + + Report.Debug (64, "RESOLVE ANONYMOUS METHOD #3", this, ec, aec, Block, + ec.capture_context); + + ContainerCaptureContext.ComputeMethodHost (); + + Report.Debug (64, "RESOLVE ANONYMOUS METHOD #4", this, Scope); + + if (Scope == null) + throw new InternalErrorException (); + + method = DoCreateMethodHost (ec); + return true; } - public override void CreateScopeType (EmitContext ec, ScopeInfo scope) + protected abstract Method DoCreateMethodHost (EmitContext ec); + + public ToplevelBlock Container { + get { return container; } + } + + public GenericMethod GenericMethod { + get { return generic; } + } + + public abstract bool IsIterator { + get; + } + +#if FIXME + public override string ToString () { - TypeBuilder container = ec.TypeContainer.TypeBuilder; - string name = String.Format ("<>AnonHelp<{0}>", scope.id); + return String.Format ("{0} ({1})", GetType (), Name); + } +#endif - scope.ScopeTypeBuilder = container.DefineNestedType (name, - TypeAttributes.Sealed | TypeAttributes.BeforeFieldInit | TypeAttributes.NestedPrivate, - TypeManager.object_type); + protected class AnonymousMethodMethod : Method + { + public AnonymousContainer AnonymousMethod; - Type [] constructor_types = Type.EmptyTypes; - ConstructorBuilder ctor = scope.ScopeTypeBuilder.DefineConstructor ( - MethodAttributes.Public | MethodAttributes.HideBySig | - MethodAttributes.SpecialName | MethodAttributes.RTSpecialName, - CallingConventions.HasThis, constructor_types); - TypeManager.RegisterMethod (ctor, Parameters.EmptyReadOnlyParameters); + public AnonymousMethodMethod (AnonymousContainer am, GenericMethod generic, + TypeExpr return_type, int mod, MemberName name, + Parameters parameters) + : base (am.RootScope, generic, return_type, mod, false, + name, parameters, null) + { + this.AnonymousMethod = am; - ILGenerator cig = ctor.GetILGenerator (); - cig.Emit (OpCodes.Ldarg_0); - cig.Emit (OpCodes.Call, TypeManager.object_ctor); - cig.Emit (OpCodes.Ret); + am.RootScope.CheckMembersDefined (); + am.Scope.AddMethod (this); + Block = am.Block; + } - if (ec.TypeContainer.IsGeneric) { - TypeParameter[] tparam = ec.TypeContainer.TypeParameters; - string[] names = new string [tparam.Length]; - Type[] types = new Type [tparam.Length]; + public override EmitContext CreateEmitContext (DeclSpace tc, ILGenerator ig) + { + EmitContext aec = AnonymousMethod.aec; + aec.ig = ig; + return aec; + } + } + } - for (int i = 0; i < names.Length; i++) { - names [i] = tparam [i].Name; - types [i] = tparam [i].Type; - } + public class AnonymousMethod : AnonymousContainer + { + public readonly Type DelegateType; - scope.ScopeTypeBuilder.DefineGenericParameters (names); - scope.ScopeTypeBuilder.GetGenericTypeDefinition (); + // + // The value return by the Compatible call, this ensure that + // the code works even if invoked more than once (Resolve called + // more than once, due to the way Convert.ImplicitConversion works + // + Expression anonymous_delegate; - scope.ScopeType = scope.ScopeTypeBuilder.MakeGenericType (types); + public AnonymousMethod (AnonymousMethod parent, TypeContainer host, + GenericMethod generic, Parameters parameters, + ToplevelBlock container, ToplevelBlock block, + Type return_type, Type delegate_type, Location loc) + : base (parent, host, generic, parameters, container, block, + return_type, 0, loc) + { + this.DelegateType = delegate_type; + + // Container.CaptureContext.RegisterScope (RootScope); + } + + public override bool IsIterator { + get { return false; } + } + + public Expression AnonymousDelegate { + get { return anonymous_delegate; } + } + + // + // Creates the host for the anonymous method + // + protected override Method DoCreateMethodHost (EmitContext ec) + { + string name = "<>c__AnonymousMethod" + anonymous_method_count++; + MemberName member_name; + + GenericMethod generic_method = null; + if (DelegateType.IsGenericType) { + TypeArguments args = new TypeArguments (loc); + + Type[] tparam = TypeManager.GetTypeArguments (DelegateType); + for (int i = 0; i < tparam.Length; i++) + args.Add (new SimpleName (tparam [i].Name, loc)); + + member_name = new MemberName (name, args, loc); + + generic_method = new GenericMethod ( + Scope.NamespaceEntry, Scope, member_name, + new TypeExpression (ReturnType, loc), Parameters); + + generic_method.SetParameterInfo (null); } else - scope.ScopeType = scope.ScopeTypeBuilder; + member_name = new MemberName (name, loc); + return new AnonymousMethodMethod ( + this, generic_method, new TypeExpression (ReturnType, loc), + Modifiers.INTERNAL, member_name, Parameters); + } - if (ec.TypeContainer.IsGeneric) - scope.ScopeConstructor = TypeBuilder.GetConstructor ( - scope.ScopeType, ctor); - else - scope.ScopeConstructor = ctor; + public override bool Resolve (EmitContext ec) + { + if (!base.Resolve (ec)) + return false; + + anonymous_delegate = new AnonymousDelegate (this, DelegateType, loc).Resolve (ec); + if (anonymous_delegate == null) + return false; + + return true; } + public MethodInfo GetMethodBuilder (EmitContext ec) + { + MethodInfo builder = method.MethodBuilder; + if (RootScope.IsGeneric) { + MethodGroupExpr mg = (MethodGroupExpr) Expression.MemberLookup ( + ec.ContainerType, RootScope.ScopeType, builder.Name, loc); + + if (mg == null) + throw new InternalErrorException (); + builder = (MethodInfo) mg.Methods [0]; + } + + if (!DelegateType.IsGenericType) + return builder; + + Type[] targs = TypeManager.GetTypeArguments (DelegateType); + return builder.MakeGenericMethod (targs); + } + public static void Error_AddressOfCapturedVar (string name, Location loc) { Report.Error (1686, loc, - "Local variable `{0}' or its members cannot have their address taken and be used inside an anonymous method block", - name); + "Local variable `{0}' or its members cannot have their " + + "address taken and be used inside an anonymous method block", + name); } } @@ -573,69 +1185,41 @@ public override void Emit (EmitContext ec) { - if (!am.EmitMethod (ec)) - return; + Report.Debug (64, "ANONYMOUS DELEGATE", this, am, ec.ContainerType, type, + ec, ec.capture_context, loc); // // Now emit the delegate creation. // - if ((am.method.ModFlags & Modifiers.STATIC) == 0) - delegate_instance_expression = new AnonymousInstance (am); - + if ((am.Method.ModFlags & Modifiers.STATIC) == 0) { + delegate_instance_expression = am.RootScope.GetScopeInitializer (ec); + Report.Debug (64, "ANONYMOUS DELEGATE #0", this, + delegate_instance_expression); + + if (delegate_instance_expression == null) + throw new InternalErrorException (); + } + Expression ml = Expression.MemberLookup (ec.ContainerType, type, ".ctor", loc); constructor_method = ((MethodGroupExpr) ml).Methods [0]; - delegate_method = am.GetMethodBuilder (); + delegate_method = am.GetMethodBuilder (ec); + Report.Debug (64, "ANONYMOUS DELEGATE #1", constructor_method, delegate_method, + delegate_method.GetType (), delegate_instance_expression); base.Emit (ec); } - - class AnonymousInstance : Expression { - AnonymousMethod am; - - public AnonymousInstance (AnonymousMethod am) - { - this.am = am; - eclass = ExprClass.Value; - } - - public override Expression DoResolve (EmitContext ec) - { - return this; - } - - public override void Emit (EmitContext ec) - { - am.aec.EmitMethodHostInstance (ec, am); - } - } } - class CapturedParameter { - public Type Type; - public FieldBuilder FieldBuilder; - public int Idx; - - public CapturedParameter (Type type, int idx) - { - Type = type; - Idx = idx; - } - } - // // Here we cluster all the variables captured on a given scope, we also // keep some extra information that might be required on each scope. // - public class ScopeInfo { - public CaptureContext CaptureContext; + public class ScopeInfo : ScopeInfoBase { public ScopeInfo ParentScope; public Block ScopeBlock; - public bool NeedThis = false; - public bool HostsParameters = false; // For tracking the number of scopes created. public int id; static int count; - bool inited = false; ArrayList locals = new ArrayList (); ArrayList children = new ArrayList (); @@ -643,40 +1227,59 @@ // // The types and fields generated // - public TypeBuilder ScopeTypeBuilder; - public Type ScopeType; - public ConstructorInfo ScopeConstructor; - public FieldBuilder THIS; - public FieldBuilder ParentLink; + public readonly Location loc; - // - // Points to the object of type `ScopeTypeBuilder' that - // holds the data for the scope - // - LocalBuilder scope_instance; - - public ScopeInfo (CaptureContext cc, Block b) + public ScopeInfo (CaptureContext cc, Block block) + : base (cc.Host.RootScope, cc.Host.GenericMethod, + Modifiers.PUBLIC, cc.loc) { CaptureContext = cc; - ScopeBlock = b; + ScopeBlock = block; + loc = cc.loc; id = count++; + Report.Debug (64, "NEW SCOPE", this); + cc.RegisterCaptureContext (); + +#if FIXME + if (!Define ()) + throw new InternalErrorException (); + if (DefineType () == null) + throw new InternalErrorException (); +#endif } - public void AddLocal (LocalInfo li) + public ScopeInfo (CaptureContext cc, ToplevelBlock toplevel, TypeContainer parent, + GenericMethod generic) + : base (parent, generic, 0, toplevel.StartLocation) { - if (locals.Contains (li)) - return; + CaptureContext = cc; + ScopeBlock = toplevel; + loc = cc.loc; + id = count++; - locals.Add (li); -} - - public bool IsCaptured (LocalInfo li) + Report.Debug (64, "NEW ROOT SCOPE", this); + + cc.RegisterCaptureContext (); + } + + public override AnonymousMethodHost Host { + get { return CaptureContext.Host.RootScope; } + } + + public Variable AddLocal (LocalInfo local) { - return locals.Contains (li); + CapturedLocal cl = new CapturedLocal (this, local); + locals.Add (cl); + return cl; } - + + public Variable AddParameter (Parameter par, int idx) + { + return new CapturedParameter (this, par, idx); + } + internal void AddChild (ScopeInfo si) { if (children.Contains (si)) @@ -703,7 +1306,7 @@ children.Remove (child); } } - } + } static int indent = 0; @@ -719,8 +1322,6 @@ Pad (); Console.WriteLine ("START"); indent++; - Pad (); - Console.WriteLine ("NeedThis=" + NeedThis); foreach (LocalInfo li in locals){ Pad (); Console.WriteLine ("var {0}", MakeFieldName (li.Name)); @@ -733,168 +1334,18 @@ Console.WriteLine ("END"); } - private string MakeFieldName (string local_name) + protected string MakeFieldName (string local_name) { return "<" + id + ":" + local_name + ">"; } - public void EmitScopeType (EmitContext ec) - { - // EmitDebug (); + bool resolved; - if (ScopeTypeBuilder != null) - return; - - Type container; - if (ec.TypeContainer.CurrentType != null) - container = ec.TypeContainer.CurrentType; - else - container = ec.TypeContainer.TypeBuilder; - - CaptureContext.Host.CreateScopeType (ec, this); - - if (NeedThis) - THIS = ScopeTypeBuilder.DefineField ("<>THIS", container, FieldAttributes.Assembly); - - if (ParentScope != null){ - if (ParentScope.ScopeTypeBuilder == null){ - throw new Exception (String.Format ("My parent has not been initialized {0} and {1}", ParentScope, this)); - } - - if (ParentScope.ScopeTypeBuilder != ScopeTypeBuilder) - ParentLink = ScopeTypeBuilder.DefineField ( - "<>parent", ParentScope.ScopeType, FieldAttributes.Assembly); - } - - if (NeedThis && ParentScope != null) - throw new Exception ("I was not expecting THIS && having a parent"); - - foreach (LocalInfo info in locals) - info.FieldBuilder = ScopeTypeBuilder.DefineField ( - MakeFieldName (info.Name), info.VariableType, FieldAttributes.Assembly); - - if (HostsParameters){ - Hashtable captured_parameters = CaptureContext.captured_parameters; - - foreach (DictionaryEntry de in captured_parameters){ - string name = (string) de.Key; - CapturedParameter cp = (CapturedParameter) de.Value; - FieldBuilder fb; - - fb = ScopeTypeBuilder.DefineField ("", cp.Type, FieldAttributes.Assembly); - cp.FieldBuilder = fb; - } - } - - foreach (ScopeInfo si in children){ - si.EmitScopeType (ec); - } - } - - public void CloseTypes () + protected override ScopeInitializerBase CreateScopeInitializer () { - RootContext.RegisterCompilerGeneratedType (ScopeTypeBuilder); - foreach (ScopeInfo si in children) - si.CloseTypes (); + return new ScopeInitializer (this); } - // - // Emits the initialization code for the scope - // - public void EmitInitScope (EmitContext ec) - { - ILGenerator ig = ec.ig; - - if (inited) - return; - - if (ScopeConstructor == null) - throw new Exception ("ScopeConstructor is null for" + this.ToString ()); - - if (!CaptureContext.Host.IsIterator) { - scope_instance = ig.DeclareLocal (ScopeType); - ig.Emit (OpCodes.Newobj, ScopeConstructor); - ig.Emit (OpCodes.Stloc, scope_instance); - } - - if (THIS != null){ - if (CaptureContext.Host.IsIterator) { - ig.Emit (OpCodes.Ldarg_0); - ig.Emit (OpCodes.Ldarg_1); - } else { - ig.Emit (OpCodes.Ldloc, scope_instance); - ig.Emit (OpCodes.Ldarg_0); - } - ig.Emit (OpCodes.Stfld, THIS); - } - - // - // Copy the parameter values, if any - // - int extra = ec.IsStatic ? 0 : 1; - if (CaptureContext.Host.IsIterator) - extra++; - if (HostsParameters){ - Hashtable captured_parameters = CaptureContext.captured_parameters; - - foreach (DictionaryEntry de in captured_parameters){ - CapturedParameter cp = (CapturedParameter) de.Value; - - EmitScopeInstance (ig); - ParameterReference.EmitLdArg (ig, cp.Idx + extra); - ig.Emit (OpCodes.Stfld, cp.FieldBuilder); - } - } - - if (ParentScope != null){ - if (!ParentScope.inited) - ParentScope.EmitInitScope (ec); - - if (ParentScope.ScopeTypeBuilder != ScopeTypeBuilder) { - // - // Only emit initialization in our capturecontext world - // - if (ParentScope.CaptureContext == CaptureContext){ - EmitScopeInstance (ig); - ParentScope.EmitScopeInstance (ig); - ig.Emit (OpCodes.Stfld, ParentLink); - } else { - EmitScopeInstance (ig); - ig.Emit (OpCodes.Ldarg_0); - ig.Emit (OpCodes.Stfld, ParentLink); - } - } - } - inited = true; - } - - public void EmitScopeInstance (ILGenerator ig) - { - if (CaptureContext.Host.IsIterator) - ig.Emit (OpCodes.Ldarg_0); - else { - if (scope_instance == null){ - // - // This is needed if someone overwrites the Emit method - // of Statement and manually calls Block.Emit without - // this snippet first: - // - // ec.EmitScopeInitFromBlock (The_Block); - // The_Block.Emit (ec); - // - - Console.WriteLine ( - "The scope_instance has not been emitted, this typically means\n" + - "that inside the compiler someone is calling Block.Emit without\n" + - "first calling EmitScopeInitFromBlock for the block. See compiler" + - "source code for an explanation"); - throw new Exception ("Internal compiler error"); - - } - ig.Emit (OpCodes.Ldloc, scope_instance); - } - } - public static void CheckCycles (string msg, ScopeInfo s) { ArrayList l = new ArrayList (); @@ -935,6 +1386,174 @@ return sb.ToString (); } + + protected class CapturedParameter : Variable { + public readonly ScopeInfo Scope; + public readonly Parameter Parameter; + public readonly Field Field; + public readonly int Idx; + + public FieldExpr FieldInstance; + + public CapturedParameter (ScopeInfo scope, Parameter par, int idx) + { + this.Scope = scope; + this.Parameter = par; + this.Idx = idx; + Field = scope.CaptureVariable ( + "", par.ParameterType); + } + + public override Type Type { + get { return Field.MemberType; } + } + + public override bool HasInstance { + get { return true; } + } + + public override bool NeedsTemporary { + get { return true; } + } + + protected FieldInfo GetField (EmitContext ec) + { + if ((Scope.Host is IteratorHost) || + (ec.capture_context != Scope.CaptureContext)) + return Field.FieldBuilder; + else + return FieldInstance.FieldInfo; + } + + public override void EmitInstance (EmitContext ec) + { + ec.capture_context.EmitParameterInstance (ec, Parameter); + } + + public override void Emit (EmitContext ec) + { + ec.ig.Emit (OpCodes.Ldfld, GetField (ec)); + } + + public override void EmitAssign (EmitContext ec) + { + ec.ig.Emit (OpCodes.Stfld, GetField (ec)); + } + + public override void EmitAddressOf (EmitContext ec) + { + ec.ig.Emit (OpCodes.Ldflda, GetField (ec)); + } + + public override string ToString () + { + return String.Format ("{0} ({1})", GetType (), Field); + } + } + + protected class CapturedLocal : Variable { + public readonly ScopeInfo Scope; + public readonly LocalInfo Local; + public readonly Field Field; + + public FieldExpr FieldInstance; + + public CapturedLocal (ScopeInfo scope, LocalInfo local) + { + this.Scope = scope; + this.Local = local; + Field = scope.CaptureVariable ( + scope.MakeFieldName (local.Name), local.VariableType); + } + + public override Type Type { + get { return Field.MemberType; } + } + + public override bool HasInstance { + get { return true; } + } + + public override bool NeedsTemporary { + get { return true; } + } + + public override void EmitInstance (EmitContext ec) + { + ec.capture_context.EmitCapturedVariableInstance ( + ec, Local.Block, ec.CurrentAnonymousMethod); + } + + public override void Emit (EmitContext ec) + { + if (ec.capture_context == Scope.CaptureContext) + ec.ig.Emit (OpCodes.Ldfld, FieldInstance.FieldInfo); + else + ec.ig.Emit (OpCodes.Ldfld, Field.FieldBuilder); + } + + public override void EmitAssign (EmitContext ec) + { + if (ec.capture_context == Scope.CaptureContext) + ec.ig.Emit (OpCodes.Stfld, FieldInstance.FieldInfo); + else + ec.ig.Emit (OpCodes.Stfld, Field.FieldBuilder); + } + + public override void EmitAddressOf (EmitContext ec) + { + if (ec.capture_context == Scope.CaptureContext) + ec.ig.Emit (OpCodes.Ldflda, FieldInstance.FieldInfo); + else + ec.ig.Emit (OpCodes.Ldflda, Field.FieldBuilder); + } + } + + protected class ScopeInitializer : ScopeInitializerBase + { + ScopeInfo scope; + + public ScopeInitializer (ScopeInfo scope) + : base (scope) + { + this.scope = scope; + } + + new public ScopeInfo Scope { + get { return scope; } + } + + protected override bool DoResolveInternal (EmitContext ec) + { + Report.Debug (64, "RESOLVE SCOPE INITIALIZER", this, Scope, + Scope.ParentScope, Scope.ScopeType, ec, + ec.TypeContainer.Name, ec.DeclContainer, + ec.DeclContainer.Name, ec.DeclContainer.IsGeneric); + + foreach (CapturedLocal local in Scope.locals) { + FieldExpr fe = (FieldExpr) Expression.MemberLookup ( + ec.ContainerType, type, local.Field.Name, loc); + Report.Debug (64, "RESOLVE SCOPE INITIALIZER #2", this, Scope, + Scope, ec, ec.ContainerType, type, + local.Field, local.Field.Name, loc, fe); + if (fe == null) + throw new InternalErrorException (); + + fe.InstanceExpression = this; + local.FieldInstance = fe; + } + + return base.DoResolveInternal (ec); + } + + protected virtual void EmitParameterReference (EmitContext ec, + CapturedParameter cp) + { + int extra = ec.IsStatic ? 0 : 1; + ParameterReference.EmitLdArg (ec.ig, cp.Idx + extra); + } + + } } // @@ -952,7 +1571,8 @@ // // Points to the toplevel block that owns this CaptureContext // - ToplevelBlock toplevel_owner; + public readonly ToplevelBlock ToplevelOwner; + public readonly IAnonymousContainer Host; // // All the scopes we capture @@ -965,25 +1585,23 @@ ArrayList roots = new ArrayList (); bool have_captured_vars = false; - bool referenced_this = false; // // Captured fields // Hashtable captured_fields = new Hashtable (); Hashtable captured_variables = new Hashtable (); - public Hashtable captured_parameters = new Hashtable (); - public AnonymousContainer Host; - + internal Hashtable captured_parameters = new Hashtable (); + public CaptureContext (ToplevelBlock toplevel_owner, Location loc, - AnonymousContainer host) + IAnonymousContainer host) { cc_id = count++; - this.toplevel_owner = toplevel_owner; + this.ToplevelOwner = toplevel_owner; + this.Host = host; this.loc = loc; - if (host != null) - Host = host; + Report.Debug (64, "NEW CAPTURE CONTEXT", this, toplevel_owner, loc); } void DoPath (StringBuilder sb, CaptureContext cc) @@ -995,17 +1613,6 @@ sb.Append (cc.cc_id.ToString ()); } - public void ReParent (ToplevelBlock new_toplevel, AnonymousContainer new_host) - { - toplevel_owner = new_toplevel; - Host = new_host; - - for (CaptureContext cc = ParentCaptureContext; cc != null; - cc = cc.ParentCaptureContext) { - cc.Host = new_host; - } - } - public override string ToString () { StringBuilder sb = new StringBuilder (); @@ -1017,7 +1624,7 @@ public ToplevelBlock ParentToplevel { get { - return toplevel_owner.Container; + return ToplevelOwner.Container; } } @@ -1029,124 +1636,264 @@ } } - ScopeInfo GetScopeForBlock (Block block) + // The method scope + ScopeInfo method_scope; + bool computed_method_scope = false; + + // + // Track the scopes that this method has used. At the + // end this is used to determine the ScopeInfo that will + // host the method + // + ArrayList scopes_used = new ArrayList (); + + public void RegisterScope (ScopeInfo scope) { + if (scopes_used.Contains (scope)) + return; + scopes_used.Add (scope); + } + + // Returns the deepest of two scopes + ScopeInfo Deepest (ScopeInfo a, ScopeInfo b) + { + ScopeInfo p; + + Report.Debug (64, "DEEPEST", this, a, a.ParentScope, b, b.ParentScope); + + if (a == null) + return b; + if (b == null) + return a; + if (a == b) + return a; + + // + // If they Scopes are on the same CaptureContext, we do the double + // checks just so if there is an invariant change in the future, + // we get the exception at the end + // + for (p = a; p != null; p = p.ParentScope) + if (p == b) + return a; + + for (p = b; p != null; p = p.ParentScope) + if (p == a) + return b; + + CaptureContext ca = a.CaptureContext; + CaptureContext cb = b.CaptureContext; + + for (CaptureContext c = ca; c != null; c = c.ParentCaptureContext) + if (c == cb) + return a; + + for (CaptureContext c = cb; c != null; c = c.ParentCaptureContext) + if (c == ca) + return b; + throw new Exception ("Should never be reached"); + } + + // + // Determines the proper host for a method considering the + // scopes it references + // + public void ComputeMethodHost () + { + Report.Debug (64, "COMPUTE METHOD HOST", this, computed_method_scope, + method_scope, scopes_used); + + if (computed_method_scope) + return; + + LinkScopes (); + + method_scope = null; + int top = scopes_used.Count; + computed_method_scope = true; + + if (top == 0) + return; + + method_scope = (ScopeInfo) scopes_used [0]; + if (top == 1) + return; + + Report.Debug (64, "COMPUTE METHOD HOST #1", this, method_scope, + scopes_used); + + for (int i = 1; i < top; i++) + method_scope = Deepest (method_scope, (ScopeInfo) scopes_used [i]); + } + + public ScopeInfo Scope { + get { + if (computed_method_scope) + return method_scope; + + // + // This means that ComputeMethodHost is not being called, most + // likely by someone who overwrote the CreateMethodHost method + // + throw new InternalErrorException ( + "AnonymousContainer.Scope is being used before its " + + "container is computed"); + } + } + + internal AnonymousMethodHost CreateRootScope (TypeContainer parent, GenericMethod generic) + { + Report.Debug (64, "CREATE ROOT SCOPE", this, parent.Name, ToplevelOwner, + ToplevelOwner.ScopeInfo); + + AnonymousMethodHost root_scope = new AnonymousMethodHost ( + this, ToplevelOwner, parent, generic); + AddRootScope (root_scope); + return root_scope; + } + + internal void AddRootScope (ScopeInfo root_scope) + { + if (ToplevelOwner.ScopeInfo != null) + throw new InternalErrorException (); + + ToplevelOwner.ScopeInfo = root_scope; + scopes.Add (ToplevelOwner.ID, root_scope); + RegisterScope (root_scope); + } + + internal ScopeInfo GetScopeForBlock (Block block) + { + while (block.Implicit) + block = block.Parent; + ScopeInfo si = (ScopeInfo) scopes [block.ID]; + Report.Debug (64, "GET SCOPE FOR BLOCK", this, block, + block.ScopeInfo, block.Parent, si); if (si != null) return si; - si = new ScopeInfo (this, block); + + block.ScopeInfo = si = new ScopeInfo (this, block); scopes [block.ID] = si; return si; } - - public void AddLocal (AnonymousContainer am, LocalInfo li) + + public Variable AddLocal (LocalInfo li) { - if (li.Block.Toplevel != toplevel_owner){ - ParentCaptureContext.AddLocal (am, li); - return; - } + Report.Debug (64, "ADD LOCAL", this, li.Name, loc, li.Block, + li.Block.Toplevel, ToplevelOwner); + + if (li.Block.Toplevel != ToplevelOwner) + return ParentCaptureContext.AddLocal (li); + ScopeInfo scope = GetScopeForBlock (li.Block); // // Adjust the owner // - if (Host != null) - Host.RegisterScope (scope); + RegisterScope (scope); +#if FIXME // // Adjust the user // am.RegisterScope (scope); - - if (captured_variables [li] != null) - return; - +#endif + + Variable var = (Variable) captured_variables [li]; + Report.Debug (64, "ADD LOCAL #1", this, li.Name, scope, var); + if (var == null) { + var = scope.AddLocal (li); + captured_variables.Add (li, var); + } + have_captured_vars = true; - captured_variables [li] = li; - scope.AddLocal (li); + return var; } // - // Retursn the CaptureContext for the block that defines the parameter `name' + // Returns the CaptureContext for the block that defines the parameter `name' // - static CaptureContext _ContextForParameter (ToplevelBlock current, string name) + static CaptureContext _ContextForParameter (ToplevelBlock current, Parameter par) { ToplevelBlock container = current.Container; if (container != null){ - CaptureContext cc = _ContextForParameter (container, name); + CaptureContext cc = _ContextForParameter (container, par); if (cc != null) return cc; } - if (current.IsParameterReference (name)) + if (current.IsParameterReference (par.Name)) return current.ToplevelBlockCaptureContext; return null; } - static CaptureContext ContextForParameter (ToplevelBlock current, string name) + static CaptureContext ContextForParameter (ToplevelBlock current, Parameter par) { - CaptureContext cc = _ContextForParameter (current, name); + CaptureContext cc = _ContextForParameter (current, par); if (cc == null) - throw new Exception (String.Format ("request for parameteter {0} failed: not found", name)); + throw new InternalErrorException ( + "Request for parameteter {0} failed: not found", par.Name); return cc; } - + // // Records the captured parameter at the appropriate CaptureContext // - public void AddParameter (EmitContext ec, AnonymousContainer am, - string name, Type t, int idx) + public Variable AddParameter (EmitContext ec, Parameter par, int idx) { - CaptureContext cc = ContextForParameter (ec.CurrentBlock.Toplevel, name); - - cc.AddParameterToContext (am, name, t, idx); + CaptureContext cc = ContextForParameter (ec.CurrentBlock.Toplevel, par); + return cc.AddParameterToContext (par, idx); } // // Records the parameters in the context // - public void AddParameterToContext (AnonymousContainer am, string name, Type t, int idx) + public Variable AddParameterToContext (Parameter par, int idx) { if (captured_parameters == null) captured_parameters = new Hashtable (); - if (captured_parameters [name] == null) - captured_parameters [name] = new CapturedParameter (t, idx); - ScopeInfo scope = GetScopeForBlock (toplevel_owner); - scope.HostsParameters = true; - am.RegisterScope (scope); + AnonymousMethodHost host = ToplevelOwner.AnonymousMethodHost; + host.HostsParameters = true; + + Variable var = (Variable) captured_parameters [par]; + if (var == null) { + var = host.AddParameter (par, idx); + captured_parameters.Add (par, var); + } + + return var; } // // Captured fields are only recorded on the topmost CaptureContext, because that // one is the one linked to the owner of instance fields // - public void AddField (EmitContext ec, AnonymousContainer am, FieldExpr fe) + public void AddField (EmitContext ec, FieldExpr fe) { if (fe.FieldInfo.IsStatic) - throw new Exception ("Attempt to register a static field as a captured field"); + throw new InternalErrorException ( + "Attempt to register a static field as a captured field"); + CaptureContext parent = ParentCaptureContext; if (parent != null) { - parent.AddField (ec, am, fe); + parent.AddField (ec, fe); return; } - ScopeInfo scope = GetScopeForBlock (toplevel_owner); - am.RegisterScope (scope); + ScopeInfo scope = GetScopeForBlock (ToplevelOwner); + RegisterScope (scope); } - public void CaptureThis (AnonymousContainer am) + public void CaptureThis () { - if (am == null) - throw new Exception ("Internal Compiler error: Capturethis called with a null method"); CaptureContext parent = ParentCaptureContext; if (parent != null) { - parent.CaptureThis (am); + parent.CaptureThis (); return; } - referenced_this = true; - ScopeInfo scope = GetScopeForBlock (toplevel_owner); - am.RegisterScope (scope); + Host.RootScope.CaptureThis (); } public bool HaveCapturedVariables { @@ -1164,21 +1911,23 @@ } } - public bool IsCaptured (LocalInfo local) + public Variable GetCapturedVariable (LocalInfo local) { - foreach (ScopeInfo si in scopes.Values){ - if (si.IsCaptured (local)) - return true; - } - return false; + return (Variable) captured_variables [local]; } + public Variable GetCapturedParameter (Parameter par) + { + return (Variable) captured_parameters [par]; + } + // // Returns whether the parameter is captured // public bool IsParameterCaptured (string name) { - if (ParentCaptureContext != null && ParentCaptureContext.IsParameterCaptured (name)) + if ((ParentCaptureContext != null) && + ParentCaptureContext.IsParameterCaptured (name)) return true; if (captured_parameters != null) @@ -1186,88 +1935,58 @@ return false; } - public void EmitAnonymousHelperClasses (EmitContext ec) + public ExpressionStatement GetScopeInitializerForBlock (EmitContext ec, Block b) { - if (roots.Count != 0){ - foreach (ScopeInfo root in roots){ - // - // FIXME: We really should do this in a per-ScopeInfo - // basis, instead of having the NeedThis applied to - // all of the roots. - // - root.NeedThis = HaveCapturedFields || referenced_this; - - root.EmitScopeType (ec); - } - } - } - - public void CloseAnonymousHelperClasses () - { - if (roots.Count != 0) - foreach (ScopeInfo root in roots) - root.CloseTypes (); - } - - public void EmitInitScope (EmitContext ec) - { - EmitAnonymousHelperClasses (ec); - if (roots.Count != 0) - foreach (ScopeInfo root in roots) - root.EmitInitScope (ec); } - - // - // This is called externally when we start emitting code for a block - // if the block has a ScopeInfo associated, emit the init code - // - public void EmitScopeInitFromBlock (EmitContext ec, Block b) - { + Report.Debug (64, "GET SCOPE INIT FOR BLOCK", this, Host, b); ScopeInfo si = (ScopeInfo) scopes [b.ID]; if (si == null) - return; + return null; - si.EmitInitScope (ec); + Report.Debug (64, "GET SCOPE INIT FOR BLOCK #1", this, Host, b, si); + return si.GetScopeInitializer (ec); } // // Emits the opcodes necessary to load the instance of the captured // variable in `li' // - public void EmitCapturedVariableInstance (EmitContext ec, LocalInfo li, + public void EmitCapturedVariableInstance (EmitContext ec, Block block, AnonymousContainer am) { ILGenerator ig = ec.ig; ScopeInfo si; - if (li.Block.Toplevel == toplevel_owner){ - si = (ScopeInfo) scopes [li.Block.ID]; - si.EmitScopeInstance (ig); + Report.Debug (64, "EMIT CAPTURED VARIABLE INSTANCE", this, + am, block.ID, block.Toplevel.ID, ToplevelOwner.ID, + block, block.Toplevel, ToplevelOwner); + + while (block.Implicit) + block = block.Parent; + + if (block.Toplevel == ToplevelOwner){ + si = (ScopeInfo) scopes [block.ID]; + si.EmitScopeInstance (ec); return; } - si = am.Scope; + Report.Debug (64, "EMIT CAPTURED VARIABLE INSTANCE #1", this, + am, block.Toplevel, ToplevelOwner, am.Scope); + + AnonymousMethodHost host = am.RootScope; ig.Emit (OpCodes.Ldarg_0); - if (si != null){ - if (am.IsIterator && (si.ScopeBlock.Toplevel == li.Block.Toplevel)) { - return; - } + if (host != null) { + Report.Debug (64, "EMIT CAPTURED VARIABLE INSTANCE #2", this, + host, host.ParentLink, host.ScopeBlock, + block, block.Toplevel); - while (si.ScopeBlock.ID != li.Block.ID){ - if (si.ParentLink != null) - ig.Emit (OpCodes.Ldfld, si.ParentLink); - si = si.ParentScope; - if (si == null) { - si = am.Scope; - Console.WriteLine ("Target: {0} {1}", li.Block.ID, li.Name); - while (si.ScopeBlock.ID != li.Block.ID){ - Console.WriteLine ("Trying: {0}", si.ScopeBlock.ID); - si = si.ParentScope; - } - - throw new Exception ( - String.Format ("Never found block {0} starting at {1} while looking up {2}", - li.Block.ID, am.Scope.ScopeBlock.ID, li.Name)); - } + while (host.ScopeBlock.ID != block.ID){ + if (host.ParentLink != null) + ig.Emit (OpCodes.Ldfld, host.ParentLink.FieldBuilder); + host = host.ParentHost; + if (host == null) + throw new InternalErrorException ( + "Never found block {0} starting at {1}", + block.ID, am.RootScope.ScopeBlock.ID); } } } @@ -1275,135 +1994,34 @@ // // Internal routine that loads the instance to reach parameter `name' // - void EmitParameterInstance (EmitContext ec, string name) + public void EmitParameterInstance (EmitContext ec, Parameter par) { - CaptureContext cc = ContextForParameter (ec.CurrentBlock.Toplevel, name); + CaptureContext cc = ContextForParameter (ec.CurrentBlock.Toplevel, par); if (cc != this){ - cc.EmitParameterInstance (ec, name); + cc.EmitParameterInstance (ec, par); return; } - CapturedParameter par_info = (CapturedParameter) captured_parameters [name]; - if (par_info != null){ - // - // FIXME: implementing this. - // + if (ec.CurrentBlock.Toplevel == ToplevelOwner) { + ScopeInfo si = (ScopeInfo) scopes [ToplevelOwner.ID]; + si.EmitScopeInstance (ec); + return; } - ILGenerator ig = ec.ig; - ScopeInfo si; + AnonymousMethodHost host = ec.CurrentAnonymousMethod.RootScope; + ec.ig.Emit (OpCodes.Ldarg_0); - if (ec.CurrentBlock.Toplevel == toplevel_owner) { - si = (ScopeInfo) scopes [toplevel_owner.ID]; - si.EmitScopeInstance (ig); - } else { - si = ec.CurrentAnonymousMethod.Scope; - ig.Emit (OpCodes.Ldarg_0); - } - - if (si != null){ - while (si.ParentLink != null) { - ig.Emit (OpCodes.Ldfld, si.ParentLink); - si = si.ParentScope; + if (host != null) { + while (host.ParentLink != null) { + ec.ig.Emit (OpCodes.Ldfld, host.ParentLink.FieldBuilder); + host = host.ParentHost; } } } - // - // Emits the code necessary to load the parameter named `name' within - // an anonymous method. - // - public void EmitParameter (EmitContext ec, string name, bool leave_copy, bool prepared, ref LocalTemporary temp) - { - CaptureContext cc = ContextForParameter (ec.CurrentBlock.Toplevel, name); - if (cc != this){ - cc.EmitParameter (ec, name, leave_copy, prepared, ref temp); - return; - } - if (!prepared) - EmitParameterInstance (ec, name); - CapturedParameter par_info = (CapturedParameter) captured_parameters [name]; - if (par_info != null){ - // - // FIXME: implementing this. - // - } - ec.ig.Emit (OpCodes.Ldfld, par_info.FieldBuilder); - - if (leave_copy){ - ec.ig.Emit (OpCodes.Dup); - temp = new LocalTemporary (par_info.FieldBuilder.FieldType); - temp.Store (ec); - } - } - - // - // Implements the assignment of `source' to the paramenter named `name' within - // an anonymous method. - // - public void EmitAssignParameter (EmitContext ec, string name, Expression source, bool leave_copy, bool prepare_for_load, ref LocalTemporary temp) - { - CaptureContext cc = ContextForParameter (ec.CurrentBlock.Toplevel, name); - if (cc != this){ - cc.EmitAssignParameter (ec, name, source, leave_copy, prepare_for_load, ref temp); - return; - } - ILGenerator ig = ec.ig; - CapturedParameter par_info = (CapturedParameter) captured_parameters [name]; - - EmitParameterInstance (ec, name); - if (prepare_for_load) - ig.Emit (OpCodes.Dup); - source.Emit (ec); - if (leave_copy){ - ig.Emit (OpCodes.Dup); - temp = new LocalTemporary (par_info.FieldBuilder.FieldType); - temp.Store (ec); - } - ig.Emit (OpCodes.Stfld, par_info.FieldBuilder); - if (temp != null) - temp.Emit (ec); - } - - // - // Emits the address for the parameter named `name' within - // an anonymous method. - // - public void EmitAddressOfParameter (EmitContext ec, string name) - { - CaptureContext cc = ContextForParameter (ec.CurrentBlock.Toplevel, name); - if (cc != this){ - cc.EmitAddressOfParameter (ec, name); - return; - } - EmitParameterInstance (ec, name); - CapturedParameter par_info = (CapturedParameter) captured_parameters [name]; - ec.ig.Emit (OpCodes.Ldflda, par_info.FieldBuilder); - } - - // - // The following methods are only invoked on the host for the - // anonymous method. - // - public void EmitMethodHostInstance (EmitContext target, AnonymousContainer am) - { - ILGenerator ig = target.ig; - ScopeInfo si = am.Scope; - - AnonymousContainer container = am.ContainerAnonymousMethod; - - if ((si == null) || ((container != null) && (si == container.Scope))) { - ig.Emit (OpCodes.Ldarg_0); - return; - } - - si.EmitInitScope (target); - si.EmitScopeInstance (ig); - } - public void RegisterCaptureContext () { - toplevel_owner.RegisterCaptureContext (this); + ToplevelOwner.RegisterCaptureContext (this); } // @@ -1412,7 +2030,10 @@ // bool IsAncestor (ScopeInfo probe, ScopeInfo scope) { + Report.Debug (64, "IS ANCESTOR", scope, scope.ScopeBlock, + scope.ScopeBlock.Parent, probe, probe.ScopeBlock); for (Block b = scope.ScopeBlock.Parent; b != null; b = b.Parent){ + Report.Debug (64, "IS ANCESTOR #1", b, probe.ScopeBlock); if (probe.ScopeBlock == b) return true; } @@ -1474,7 +2095,7 @@ } return parent; } - + // // Links all the scopes // @@ -1483,7 +2104,9 @@ { if (linked) return; - + + Report.Debug (64, "LINK SCOPES", this, ParentCaptureContext); + linked = true; if (ParentCaptureContext != null) ParentCaptureContext.LinkScopes (); @@ -1492,9 +2115,14 @@ ScopeInfo [] scope_list = new ScopeInfo [scope_count]; scopes.Values.CopyTo (scope_list, 0); + Report.Debug (64, "LINK SCOPES #1", this, scope_list); + for (int i = 0; i < scope_count; i++){ ScopeInfo parent = GetParentScope (scope_list [i], scope_list); + Report.Debug (64, "LINK SCOPES #2", this, scope_list, i, + scope_list [i], parent); + if (parent == null){ roots.Add (scope_list [i]); continue; @@ -1504,17 +2132,28 @@ parent.AddChild (scope_list [i]); } + Report.Debug (64, "LINK SCOPES #3", this, ParentCaptureContext, roots); + // // Link the roots to their parent containers if any. // if (ParentCaptureContext != null && roots.Count != 0){ ScopeInfo one_root = (ScopeInfo) roots [0]; bool found = false; - + + Report.Debug (64, "LINK SCOPES #4", this, one_root, + ParentCaptureContext.roots); + foreach (ScopeInfo a_parent_root in ParentCaptureContext.roots){ + Report.Debug (64, "LINK SCOPES #5", this, a_parent_root, + one_root); + if (!IsAncestor (a_parent_root, one_root)) continue; + Report.Debug (64, "LINK SCOPES #6", this, a_parent_root, + one_root, roots); + found = true; // Found, link all the roots to this root @@ -1533,6 +2172,13 @@ throw new Exception ("Internal compiler error: Did not find the parent for the root in the chain"); } } + + foreach (ScopeInfo si in scope_list) { + if (!si.Define ()) + throw new InternalErrorException (); + if (si.DefineType () == null) + throw new InternalErrorException (); + } } } } Index: expression.cs =================================================================== --- expression.cs (revision 63019) +++ expression.cs (working copy) @@ -3309,6 +3309,7 @@ bool is_readonly; bool prepared; LocalTemporary temp; + Variable variable; public LocalVariableReference (Block block, string name, Location l) { @@ -3363,20 +3364,18 @@ if (!VerifyAssigned (ec)) return null; - if (ec.CurrentAnonymousMethod != null){ - // - // If we are referencing a variable from the external block - // flag it for capturing - // - if ((local_info.Block.Toplevel != ec.CurrentBlock.Toplevel) || - ec.CurrentAnonymousMethod.IsIterator) - { - if (local_info.AddressTaken){ - AnonymousMethod.Error_AddressOfCapturedVar (local_info.Name, loc); - return null; - } - ec.CaptureVariable (local_info); + // + // If we are referencing a variable from the external block + // flag it for capturing + // + if (ec.MustCaptureVariable (local_info)) { + if (local_info.AddressTaken){ + AnonymousMethod.Error_AddressOfCapturedVar (local_info.Name, loc); + return null; } + + variable = ec.CaptureVariable (local_info); + type = variable.Type; } return this; @@ -3439,90 +3438,56 @@ return Name == lvr.Name && Block == lvr.Block; } + public Variable Variable { + get { return variable != null ? variable : local_info.Variable; } + } + public override void Emit (EmitContext ec) { - ILGenerator ig = ec.ig; - - if (local_info.FieldBuilder == null){ - // - // A local variable on the local CLR stack - // - ig.Emit (OpCodes.Ldloc, local_info.LocalBuilder); - } else { - // - // A local variable captured by anonymous methods. - // - if (!prepared) - ec.EmitCapturedVariableInstance (local_info); - - ig.Emit (OpCodes.Ldfld, local_info.FieldBuilder); - } + Report.Debug (64, "EMIT LOCAL VARIABLE REFERENCE", this, ec, Variable, loc); + if (!prepared) + Variable.EmitInstance (ec); + Variable.Emit (ec); } public void Emit (EmitContext ec, bool leave_copy) { Emit (ec); - if (leave_copy){ + if (leave_copy) { ec.ig.Emit (OpCodes.Dup); - if (local_info.FieldBuilder != null){ + if (Variable.NeedsTemporary) { temp = new LocalTemporary (Type); temp.Store (ec); } } } - - public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load) + + public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, + bool prepare_for_load) { ILGenerator ig = ec.ig; prepared = prepare_for_load; - if (local_info.FieldBuilder == null){ - // - // A local variable on the local CLR stack - // - if (local_info.LocalBuilder == null) - throw new Exception ("This should not happen: both Field and Local are null"); - - source.Emit (ec); - if (leave_copy) - ec.ig.Emit (OpCodes.Dup); - ig.Emit (OpCodes.Stloc, local_info.LocalBuilder); - } else { - // - // A local variable captured by anonymous methods or itereators. - // - ec.EmitCapturedVariableInstance (local_info); - - if (prepare_for_load) - ig.Emit (OpCodes.Dup); - source.Emit (ec); - if (leave_copy){ - ig.Emit (OpCodes.Dup); + Variable.EmitInstance (ec); + if (prepare_for_load && Variable.HasInstance) + ig.Emit (OpCodes.Dup); + source.Emit (ec); + if (leave_copy) { + ig.Emit (OpCodes.Dup); + if (Variable.NeedsTemporary) { temp = new LocalTemporary (Type); temp.Store (ec); } - ig.Emit (OpCodes.Stfld, local_info.FieldBuilder); - if (temp != null) - temp.Emit (ec); } + Variable.EmitAssign (ec); + if (temp != null) + temp.Emit (ec); } public void AddressOf (EmitContext ec, AddressOp mode) { - ILGenerator ig = ec.ig; - - if (local_info.FieldBuilder == null){ - // - // A local variable on the local CLR stack - // - ig.Emit (OpCodes.Ldloca, local_info.LocalBuilder); - } else { - // - // A local variable captured by anonymous methods or iterators - // - ec.EmitCapturedVariableInstance (local_info); - ig.Emit (OpCodes.Ldflda, local_info.FieldBuilder); - } + Variable.EmitInstance (ec); + Variable.EmitAddressOf (ec); } public override string ToString () @@ -3562,6 +3527,7 @@ } LocalTemporary temp; + Variable variable; public ParameterReference (Parameter par, Block block, int idx, Location loc) { @@ -3577,6 +3543,10 @@ get { return vi; } } + public Variable Variable { + get { return variable != null ? variable : par.Variable; } + } + public bool VerifyFixed () { // A parameter is fixed if it's a value parameter (i.e., no modifier like out, ref, param). @@ -3636,15 +3606,6 @@ par.Name); return false; } - - // - // If we are referencing the parameter from the external block - // flag it for capturing - // - //Console.WriteLine ("Is parameter `{0}' local? {1}", name, block.IsLocalParameter (name)); - if (!block.Toplevel.IsLocalParameter (name)){ - ec.CaptureParameter (name, type, idx); - } } return true; @@ -3681,9 +3642,15 @@ if (!DoResolveBase (ec)) return null; - if (is_out && ec.DoFlowAnalysis && (!ec.OmitStructFlowAnalysis || !vi.TypeInfo.IsStruct) && !IsAssigned (ec, loc)) + if (is_out && ec.DoFlowAnalysis && + (!ec.OmitStructFlowAnalysis || !vi.TypeInfo.IsStruct) && !IsAssigned (ec, loc)) return null; + if (ec.MustCaptureParameter (block, name)) { + variable = ec.CaptureParameter (par, idx); + type = variable.Type; + } + return this; } @@ -3694,6 +3661,11 @@ SetAssigned (ec); + if (ec.MustCaptureParameter (block, name)) { + variable = ec.CaptureParameter (par, idx); + type = variable.Type; + } + return this; } @@ -3731,7 +3703,68 @@ // FIXME: Review for anonymous methods // } + + public override void Emit (EmitContext ec) + { + Emit (ec, false); + } + public void Emit (EmitContext ec, bool leave_copy) + { + if (!prepared) + Variable.EmitInstance (ec); + Variable.Emit (ec); + + if (is_ref) { + if (prepared) + ec.ig.Emit (OpCodes.Dup); + + // + // If we are a reference, we loaded on the stack a pointer + // Now lets load the real value + // + LoadFromPtr (ec.ig, type); + } + + if (leave_copy) { + ec.ig.Emit (OpCodes.Dup); + + if (is_ref || Variable.NeedsTemporary) { + temp = new LocalTemporary (Type); + temp.Store (ec); + } + } + } + + public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, + bool prepare_for_load) + { + ILGenerator ig = ec.ig; + prepared = prepare_for_load; + + Variable.EmitInstance (ec); + if (prepare_for_load) + ig.Emit (OpCodes.Dup); + source.Emit (ec); + if (leave_copy) { + ig.Emit (OpCodes.Dup); + if (Variable.NeedsTemporary) { + temp = new LocalTemporary (Type); + temp.Store (ec); + } + } + Variable.EmitAssign (ec); + if (temp != null) + temp.Emit (ec); + } + + public void AddressOf (EmitContext ec, AddressOp mode) + { + Variable.EmitInstance (ec); + Variable.EmitAddressOf (ec); + } + +#if FIXME public override void Emit (EmitContext ec) { Emit (ec, false); @@ -3742,8 +3775,11 @@ ILGenerator ig = ec.ig; int arg_idx = idx; - if (ec.HaveCaptureInfo && ec.IsParameterCaptured (name)){ - ec.EmitParameter (name, leave_copy, prepared, ref temp); + Report.Debug (64, "EMIT PARAMETER REF", this, name, ec.capture_context, + ec.CurrentBlock, ec.CurrentBlock.Toplevel, loc); + + if (ec.HaveCaptureInfo && ec.IsParameterCaptured (name)) { + ec.capture_context.EmitParameter (ec, name, leave_copy, prepared, ref temp); return; } @@ -3772,20 +3808,19 @@ } } } - + public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load) { prepared = prepare_for_load; if (ec.HaveCaptureInfo && ec.IsParameterCaptured (name)){ - ec.EmitAssignParameter (name, source, leave_copy, prepare_for_load, ref temp); + ec.capture_context.EmitAssignParameter ( + ec, name, source, leave_copy, prepare_for_load, ref temp); return; } ILGenerator ig = ec.ig; int arg_idx = idx; - - - + if (!ec.MethodIsStatic) arg_idx++; @@ -3818,7 +3853,7 @@ public void AddressOf (EmitContext ec, AddressOp mode) { if (ec.HaveCaptureInfo && ec.IsParameterCaptured (name)){ - ec.EmitAddressOfParameter (name); + ec.capture_context.EmitAddressOfParameter (ec, name); return; } @@ -3839,6 +3874,7 @@ ec.ig.Emit (OpCodes.Ldarga, arg_idx); } } +#endif public override string ToString () { Index: codegen.cs =================================================================== --- codegen.cs (revision 63019) +++ codegen.cs (working copy) @@ -9,7 +9,7 @@ // #if !DEBUG - #define PRODUCTION +// #define PRODUCTION #endif using System; @@ -363,12 +363,7 @@ /// The current iterator /// public Iterator CurrentIterator { - get { - if (CurrentAnonymousMethod != null) - return CurrentAnonymousMethod.Iterator; - else - return null; - } + get { return CurrentAnonymousMethod as Iterator; } } /// @@ -529,12 +524,6 @@ get { return capture_context != null; } } - public void EmitScopeInitFromBlock (Block b) - { - if (capture_context != null) - capture_context.EmitScopeInitFromBlock (this, b); - } - // // Starts a new code branching. This inherits the state of all local // variables and parameters from the current branching. @@ -618,29 +607,28 @@ current_flow_branching = current_flow_branching.Parent; } - public void CaptureVariable (LocalInfo li) + public Variable CaptureVariable (LocalInfo li) { - capture_context.AddLocal (CurrentAnonymousMethod, li); li.IsCaptured = true; + return capture_context.AddLocal (li); } - public void CaptureParameter (string name, Type t, int idx) + public Variable CaptureParameter (Parameter par, int idx) { - capture_context.AddParameter (this, CurrentAnonymousMethod, name, t, idx); + return capture_context.AddParameter (this, par, idx); } public void CaptureThis () { - capture_context.CaptureThis (CurrentAnonymousMethod); - } + capture_context.CaptureThis (); + } - // // Use to register a field as captured // public void CaptureField (FieldExpr fe) { - capture_context.AddField (this, CurrentAnonymousMethod, fe); + capture_context.AddField (this, fe); } // @@ -664,25 +652,21 @@ } // - // Emits the instance pointer for the host method + // Returns whether the `local' variable has been captured by an anonymous + // method // - public void EmitMethodHostInstance (EmitContext target, AnonymousMethod am) + public Variable GetCapturedVariable (LocalInfo local) { if (capture_context != null) - capture_context.EmitMethodHostInstance (target, am); - else if (IsStatic) - target.ig.Emit (OpCodes.Ldnull); - else - target.ig.Emit (OpCodes.Ldarg_0); + return capture_context.GetCapturedVariable (local); + return null; } - // - // Returns whether the `local' variable has been captured by an anonymous - // method - // - public bool IsCaptured (LocalInfo local) + public Variable GetCapturedParameter (Parameter par) { - return capture_context.IsCaptured (local); + if (capture_context != null) + return capture_context.GetCapturedParameter (par); + return null; } public bool IsParameterCaptured (string name) @@ -691,11 +675,28 @@ return capture_context.IsParameterCaptured (name); return false; } + + public bool MustCaptureParameter (Block block, string name) + { + if (CurrentAnonymousMethod == null) + return false; + if (CurrentAnonymousMethod.IsIterator) + return true; + else + return !block.Toplevel.IsLocalParameter (name); + } + + public bool MustCaptureVariable (LocalInfo local) + { + if (CurrentAnonymousMethod == null) + return false; + if (CurrentAnonymousMethod.IsIterator) + return true; + return local.Block.Toplevel != CurrentBlock.Toplevel; + } public void EmitMeta (ToplevelBlock b) { - if (capture_context != null) - capture_context.EmitAnonymousHelperClasses (this); b.EmitMeta (this); if (HasReturnLabel) @@ -734,7 +735,8 @@ if (resolved) return true; - capture_context = block.CaptureContext; + if (capture_context == null) + capture_context = block.CaptureContext; if (!loc.IsNull) CurrentFile = loc.File; @@ -745,6 +747,11 @@ if (!block.ResolveMeta (this, ip)) return false; + if ((md != null) && (md.Iterator != null)) { + if (!md.Iterator.Resolve (this)) + throw new InternalErrorException (); + } + using (this.With (EmitContext.Flags.DoFlowAnalysis, true)) { FlowBranchingToplevel top_level; if (anonymous_method_host != null) @@ -783,12 +790,14 @@ return false; } else if (!CurrentAnonymousMethod.IsIterator) { Report.Error (1643, CurrentAnonymousMethod.Location, "Not all code paths return a value in anonymous method of type `{0}'", - CurrentAnonymousMethod.GetSignatureForError ()); + CurrentAnonymousMethod.GetSignatureForError ()); return false; } } - block.CompleteContexts (); + if (!block.CompleteContexts (this)) + return false; + resolved = true; return true; } @@ -829,12 +838,6 @@ ig.Emit (OpCodes.Ret); } } - - // - // Close pending helper classes if we are the toplevel - // - if (capture_context != null && capture_context.ParentToplevel == null) - capture_context.CloseAnonymousHelperClasses (); } /// @@ -995,6 +998,8 @@ HasReturnLabel = true; } + static int next_temp = 0; + // // Emits the proper object to address fields on a remapped // variable/parameter to field in anonymous-method/iterator proxy classes. @@ -1003,49 +1008,30 @@ { ig.Emit (OpCodes.Ldarg_0); if (capture_context != null && CurrentAnonymousMethod != null){ - ScopeInfo si = CurrentAnonymousMethod.Scope; - while (si != null){ - if (si.ParentLink != null) - ig.Emit (OpCodes.Ldfld, si.ParentLink); - if (si.THIS != null){ - if (need_address && TypeManager.IsValueType (si.THIS.FieldType)) - ig.Emit (OpCodes.Ldflda, si.THIS); + AnonymousMethodHost host = CurrentAnonymousMethod.RootScope; + ig.Emit (OpCodes.Ldc_I4, ++next_temp); + ig.Emit (OpCodes.Pop); + Report.Debug (64, "EMIT THIS", this, capture_context, + CurrentAnonymousMethod, next_temp, host); + + while (host != null){ + Report.Debug (64, "EMIT THIS #1", this, capture_context, + CurrentAnonymousMethod, next_temp, host, + host.THIS, host.ParentLink); + if (host.ParentLink != null) + ig.Emit (OpCodes.Ldfld, host.ParentLink.FieldBuilder); + if (host.THIS != null){ + if (need_address && TypeManager.IsValueType (host.THIS.MemberType)) + ig.Emit (OpCodes.Ldflda, host.THIS.FieldBuilder); else - ig.Emit (OpCodes.Ldfld, si.THIS); + ig.Emit (OpCodes.Ldfld, host.THIS.FieldBuilder); break; } - si = si.ParentScope; + host = host.ParentHost; } } } - // - // Emits the code necessary to load the instance required - // to access the captured LocalInfo - // - public void EmitCapturedVariableInstance (LocalInfo li) - { - if (capture_context == null) - throw new Exception ("Calling EmitCapturedContext when there is no capture_context"); - - capture_context.EmitCapturedVariableInstance (this, li, CurrentAnonymousMethod); - } - - public void EmitParameter (string name, bool leave_copy, bool prepared, ref LocalTemporary temp) - { - capture_context.EmitParameter (this, name, leave_copy, prepared, ref temp); - } - - public void EmitAssignParameter (string name, Expression source, bool leave_copy, bool prepare_for_load, ref LocalTemporary temp) - { - capture_context.EmitAssignParameter (this, name, source, leave_copy, prepare_for_load, ref temp); - } - - public void EmitAddressOfParameter (string name) - { - capture_context.EmitAddressOfParameter (this, name); - } - public Expression GetThis (Location loc) { This my_this; Index: statement.cs =================================================================== --- statement.cs (revision 63019) +++ statement.cs (working copy) @@ -962,23 +962,35 @@ } } + public abstract class Variable + { + public abstract Type Type { + get; + } + + public abstract bool HasInstance { + get; + } + + public abstract bool NeedsTemporary { + get; + } + + public abstract void EmitInstance (EmitContext ec); + + public abstract void Emit (EmitContext ec); + + public abstract void EmitAssign (EmitContext ec); + + public abstract void EmitAddressOf (EmitContext ec); + } + // // The information about a user-perceived local variable // public class LocalInfo { public Expression Type; - // - // Most of the time a variable will be stored in a LocalBuilder - // - // But sometimes, it will be stored in a field (variables that have been - // hoisted by iterators or by anonymous methods). The context of the field will - // be stored in the EmitContext - // - // - public LocalBuilder LocalBuilder; - public FieldBuilder FieldBuilder; - public Type VariableType; public readonly string Name; public readonly Location Location; @@ -986,6 +998,11 @@ public VariableInfo VariableInfo; + Variable var; + public Variable Variable { + get { return var; } + } + [Flags] enum Flags : byte { Used = 1, @@ -1022,18 +1039,23 @@ Location = l; } - public void DeclareLocal (ILGenerator ig) + public void ResolveVariable (EmitContext ec) { - if (Pinned) { - // - // This is needed to compile on both .NET 1.x and .NET 2.x - // the later introduced `DeclareLocal (Type t, bool pinned)' - // - LocalBuilder = TypeManager.DeclareLocalPinned (ig, VariableType); - return; + var = ec.GetCapturedVariable (this); + Report.Debug (64, "LOCAL RESOLVE VARIABLE", this, var); + if (var == null) { + LocalBuilder builder; + if (Pinned) + // + // This is needed to compile on both .NET 1.x and .NET 2.x + // the later introduced `DeclareLocal (Type t, bool pinned)' + // + builder = TypeManager.DeclareLocalPinned (ec.ig, VariableType); + else + builder = ec.ig.DeclareLocal (VariableType); + + var = new LocalVariable (this, builder); } - if (!IsThis && !IsConstant) - LocalBuilder = ig.DeclareLocal (VariableType); } public bool IsThisAssigned (EmitContext ec, Location loc) @@ -1185,6 +1207,50 @@ flags = value ? (flags | Flags.IsThis) : (flags & ~Flags.IsThis); } } + + protected class LocalVariable : Variable + { + public readonly LocalInfo LocalInfo; + LocalBuilder builder; + + public LocalVariable (LocalInfo local, LocalBuilder builder) + { + this.LocalInfo = local; + this.builder = builder; + } + + public override Type Type { + get { return LocalInfo.VariableType; } + } + + public override bool HasInstance { + get { return false; } + } + + public override bool NeedsTemporary { + get { return false; } + } + + public override void EmitInstance (EmitContext ec) + { + // Do nothing. + } + + public override void Emit (EmitContext ec) + { + ec.ig.Emit (OpCodes.Ldloc, builder); + } + + public override void EmitAssign (EmitContext ec) + { + ec.ig.Emit (OpCodes.Stloc, builder); + } + + public override void EmitAddressOf (EmitContext ec) + { + ec.ig.Emit (OpCodes.Ldloca, builder); + } + } } /// @@ -1239,7 +1305,7 @@ // // The statements in this block // - ArrayList statements; + protected ArrayList statements; int num_statements; // @@ -1275,6 +1341,8 @@ // Block switch_block; + ExpressionStatement scope_init; + protected static int id; int this_id; @@ -1589,6 +1657,8 @@ public LocalInfo AddTemporaryVariable (TypeExpr te, Location loc) { + Report.Debug (64, "ADD TEMPORARY", this, Toplevel, loc); + if (temporary_variables == null) temporary_variables = new ArrayList (); @@ -1679,6 +1749,8 @@ } } + public ScopeInfo ScopeInfo; + /// /// Emits the variable declarations and labels. /// @@ -1688,6 +1760,8 @@ /// public void ResolveMeta (ToplevelBlock toplevel, EmitContext ec, Parameters ip) { + Report.Debug (64, "BLOCK RESOLVE META", this, Parent, toplevel); + // If some parent block was unsafe, we remain unsafe even if this block // isn't explicitly marked as such. using (ec.With (EmitContext.Flags.InUnsafe, ec.InUnsafe | Unsafe)) { @@ -1791,39 +1865,19 @@ // // Emits the local variable declarations for a block // - public void EmitMeta (EmitContext ec) + public virtual void EmitMeta (EmitContext ec) { - ILGenerator ig = ec.ig; - + if (ec.capture_context != null) + scope_init = ec.capture_context.GetScopeInitializerForBlock (ec, this); + if (variables != null){ - bool have_captured_vars = ec.HaveCapturedVariables (); - - foreach (DictionaryEntry de in variables){ - LocalInfo vi = (LocalInfo) de.Value; - - if (have_captured_vars && ec.IsCaptured (vi)) - continue; - - vi.DeclareLocal (ig); - } + foreach (LocalInfo vi in variables.Values) + vi.ResolveVariable (ec); } if (temporary_variables != null) { - AnonymousContainer am = ec.CurrentAnonymousMethod; - TypeBuilder scope = null; - if ((am != null) && am.IsIterator) { - scope = am.Scope.ScopeTypeBuilder; - if (scope == null) - throw new InternalErrorException (); - } - foreach (LocalInfo vi in temporary_variables) { - if (scope != null) { - if (vi.FieldBuilder == null) - vi.FieldBuilder = scope.DefineField ( - vi.Name, vi.VariableType, FieldAttributes.Assembly); - } else - vi.LocalBuilder = ig.DeclareLocal (vi.VariableType); - } + foreach (LocalInfo vi in temporary_variables) + vi.ResolveVariable (ec); } if (children != null){ @@ -2031,15 +2085,18 @@ string name = (string) de.Key; LocalInfo vi = (LocalInfo) de.Value; +#if FIXME if (vi.LocalBuilder == null) continue; ec.DefineLocalVariable (name, vi.LocalBuilder); +#endif } } } ec.Mark (StartLocation, true); - ec.EmitScopeInitFromBlock (this); + if (scope_init != null) + scope_init.EmitStatement (ec); DoEmit (ec); ec.Mark (EndLocation, true); @@ -2083,12 +2140,13 @@ // Pointer to the host of this anonymous method, or null // if we are the topmost block // - ToplevelBlock container; + GenericMethod generic; + ToplevelBlock container, child; CaptureContext capture_context; FlowBranchingToplevel top_level_branching; + AnonymousMethodHost anonymous_method_host; Hashtable capture_contexts; - ArrayList children; public bool HasVarargs { get { return (flags & Flags.HasVarargs) != 0; } @@ -2105,21 +2163,42 @@ public void RegisterCaptureContext (CaptureContext cc) { + Report.Debug (64, "TOPLEVEL REGISTER CONTEXT", this, capture_contexts, cc); + if (capture_contexts == null) capture_contexts = new Hashtable (); capture_contexts [cc] = cc; } - public void CompleteContexts () + public bool CompleteContexts (EmitContext ec) { - if (capture_contexts == null) - return; + Report.Debug (64, "TOPLEVEL COMPLETE CONTEXTS", this, capture_contexts, + container, anonymous_method_host); - foreach (CaptureContext cc in capture_contexts.Keys){ - cc.LinkScopes (); + if (capture_contexts != null) { + foreach (CaptureContext cc in capture_contexts.Keys) + cc.LinkScopes (); } + + if ((container == null) && (anonymous_method_host != null)) { + Report.Debug (64, "TOPLEVEL COMPLETE CONTEXTS #1", this, + anonymous_method_host); + + if (anonymous_method_host.DefineType () == null) + return false; + if (!anonymous_method_host.ResolveType ()) + return false; + if (!anonymous_method_host.DefineMembers ()) + return false; + } + + return true; } + public GenericMethod GenericMethod { + get { return generic; } + } + public CaptureContext ToplevelBlockCaptureContext { get { return capture_context; } } @@ -2128,14 +2207,6 @@ get { return container; } } - protected void AddChild (ToplevelBlock block) - { - if (children == null) - children = new ArrayList (); - - children.Add (block); - } - // // Parent is only used by anonymous blocks to link back to their // parents @@ -2144,6 +2215,13 @@ this (container, (Flags) 0, parameters, start) { } + + public ToplevelBlock (ToplevelBlock container, Parameters parameters, GenericMethod generic, + Location start) : + this (container, parameters, start) + { + this.generic = generic; + } public ToplevelBlock (Parameters parameters, Location start) : this (null, (Flags) 0, parameters, start) @@ -2160,16 +2238,42 @@ { this.parameters = parameters == null ? Parameters.EmptyReadOnlyParameters : parameters; this.container = container; + } + public ToplevelBlock (Location loc) : this (null, (Flags) 0, null, loc) + { + } + + public void CreateAnonymousMethodHost (TypeContainer host) + { + if (anonymous_method_host != null) + return; if (container != null) - container.AddChild (this); + anonymous_method_host = capture_context.CreateRootScope ( + container.anonymous_method_host, null); + else + anonymous_method_host = capture_context.CreateRootScope ( + host, generic); } - public ToplevelBlock (Location loc) : this (null, (Flags) 0, null, loc) + public void CreateIteratorHost (AnonymousMethodHost root_scope) { + Report.Debug (64, "CREATE ITERATOR HOST", this, container, + anonymous_method_host, root_scope); + if ((container != null) || (anonymous_method_host != null)) + throw new InternalErrorException (); + + capture_context.AddRootScope (root_scope); + anonymous_method_host = root_scope; } - public void SetHaveAnonymousMethods (Location loc, AnonymousContainer host) + public AnonymousMethodHost AnonymousMethodHost { + get { + return anonymous_method_host; + } + } + + public void SetHaveAnonymousMethods (Location loc, IAnonymousContainer host) { if (capture_context == null) capture_context = new CaptureContext (this, loc, host); @@ -2192,15 +2296,12 @@ // null. Later on, when resolving the iterator, we need to move the // anonymous method into that iterator. // - public void ReParent (ToplevelBlock new_parent, AnonymousContainer new_host) + public void ReParent (ToplevelBlock new_parent) { - foreach (ToplevelBlock block in children) { - if (block.CaptureContext == null) - continue; - - block.container = new_parent; - block.CaptureContext.ReParent (new_parent, new_host); - } + Report.Debug (64, "TOPLEVEL REPARENT", this, Parent, new_parent); + container = new_parent; + Parent = new_parent; + new_parent.child = this; } // @@ -2290,10 +2391,58 @@ ResolveMeta (this, ec, ip); + if (child != null) + child.ResolveMeta (this, ec, ip); + top_level_branching = ec.StartFlowBranching (this); return Report.Errors == errors; } + + public override void EmitMeta (EmitContext ec) + { + base.EmitMeta (ec); + parameters.ResolveVariable (ec); + } + + public void MakeIterator (Iterator iterator) + { + Report.Debug (64, "TOPLEVEL MAKE ITERATOR", this, statements); + + Block block = new Block (this); + foreach (Statement stmt in statements) + block.AddStatement (stmt); + statements = new ArrayList (); + statements.Add (new MoveNextStatement (iterator, block)); + } + + protected class MoveNextStatement : Statement { + Iterator iterator; + Block block; + + public MoveNextStatement (Iterator iterator, Block block) + { + this.iterator = iterator; + this.block = block; + this.loc = iterator.Location; + } + + public override bool Resolve (EmitContext ec) + { + return block.Resolve (ec); + } + + protected override void DoEmit (EmitContext ec) + { + iterator.EmitMoveNext (ec, block); + } + } + + public override string ToString () + { + return String.Format ("{0} ({1}:{2}{3}:{4})", GetType (), ID, StartLocation, + capture_context, anonymous_method_host); + } } public class SwitchLabel { @@ -3299,7 +3448,7 @@ } public abstract void Emit (EmitContext ec); - public abstract void EmitExit (ILGenerator ig); + public abstract void EmitExit (EmitContext ec); } class ExpressionEmitter : Emitter { @@ -3313,14 +3462,14 @@ // Store pointer in pinned location // converted.Emit (ec); - ec.ig.Emit (OpCodes.Stloc, vi.LocalBuilder); + vi.Variable.EmitAssign (ec); } - public override void EmitExit (ILGenerator ig) + public override void EmitExit (EmitContext ec) { - ig.Emit (OpCodes.Ldc_I4_0); - ig.Emit (OpCodes.Conv_U); - ig.Emit (OpCodes.Stloc, vi.LocalBuilder); + ec.ig.Emit (OpCodes.Ldc_I4_0); + ec.ig.Emit (OpCodes.Conv_U); + vi.Variable.EmitAssign (ec); } } @@ -3350,13 +3499,13 @@ return; converted.Emit (ec); - ig.Emit (OpCodes.Stloc, vi.LocalBuilder); + vi.Variable.EmitAssign (ec); } - public override void EmitExit(ILGenerator ig) + public override void EmitExit (EmitContext ec) { - ig.Emit (OpCodes.Ldnull); - ig.Emit (OpCodes.Stloc, pinned_string); + ec.ig.Emit (OpCodes.Ldnull); + ec.ig.Emit (OpCodes.Stloc, pinned_string); } } @@ -3554,13 +3703,11 @@ if (has_ret) return; - ILGenerator ig = ec.ig; - // // Clear the pinned variable // for (int i = 0; i < data.Length; i++) { - data [i].EmitExit (ig); + data [i].EmitExit (ec); } } } @@ -3772,22 +3919,24 @@ ig.BeginCatchBlock (c.CatchType); +#if FIXME if (c.VarBlock != null) ec.EmitScopeInitFromBlock (c.VarBlock); +#endif if (c.Name != null){ vi = c.Block.GetLocalInfo (c.Name); if (vi == null) throw new Exception ("Variable does not exist in this block"); - if (vi.IsCaptured){ + if (vi.Variable.NeedsTemporary) { LocalBuilder e = ig.DeclareLocal (vi.VariableType); ig.Emit (OpCodes.Stloc, e); - - ec.EmitCapturedVariableInstance (vi); + + vi.Variable.EmitInstance (ec); ig.Emit (OpCodes.Ldloc, e); - ig.Emit (OpCodes.Stfld, vi.FieldBuilder); + vi.Variable.EmitAssign (ec); } else - ig.Emit (OpCodes.Stloc, vi.LocalBuilder); + vi.Variable.EmitAssign (ec); } else ig.Emit (OpCodes.Pop); @@ -4164,7 +4313,7 @@ Type var_type = texpr.Type; - if (expr.eclass == ExprClass.MethodGroup || expr is AnonymousMethod) { + if (expr.eclass == ExprClass.MethodGroup || expr is AnonymousMethodExpression) { Report.Error (446, expr.Location, "Foreach statement cannot operate on a `{0}'", expr.ExprClassName); return false; @@ -4220,7 +4369,7 @@ { EmitThis (ec); ec.ig.Emit (OpCodes.Ldc_I4_0); - EmitStore (ec.ig); + EmitStore (ec); } public void Increment (EmitContext ec) @@ -4229,7 +4378,7 @@ Emit (ec); ec.ig.Emit (OpCodes.Ldc_I4_1); ec.ig.Emit (OpCodes.Add); - EmitStore (ec.ig); + EmitStore (ec); } } @@ -4323,7 +4472,7 @@ lengths [i].EmitThis (ec); ((ArrayAccess) access).EmitGetLength (ec, i); - lengths [i].EmitStore (ig); + lengths [i].EmitStore (ec); } for (int i = 0; i < rank; i++) {