//
-// anonymous.cs: Support for anonymous methods
+// anonymous.cs: Support for anonymous methods and types
//
// Author:
// Miguel de Icaza (miguel@ximain.com)
// Marek Safar (marek.safar@gmail.com)
//
-// (C) 2003, 2004 Novell, Inc.
-//
-// TODO: Ideally, we should have the helper classes emited as a hierarchy to map
-// their nesting, and have the visibility set to private, instead of NestedAssembly
-//
-//
+// Dual licensed under the terms of the MIT X11 or GNU GPL
+// Copyright 2003-2008 Novell, Inc.
//
using System;
using System.Text;
using System.Collections;
+using System.Collections.Specialized;
using System.Reflection;
using System.Reflection.Emit;
public abstract class CompilerGeneratedClass : Class
{
- GenericMethod generic_method;
- static int next_index = 0;
-
- private static MemberName MakeProxyName (GenericMethod generic, Location loc)
+ public static string MakeName (string host, string typePrefix, string name, int id)
{
- string name = MakeName (null, "CompilerGenerated");
- 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);
- }
-
- public static string MakeName (string host, string prefix)
- {
- return "<" + host + ">c__" + prefix + next_index++;
+ return "<" + host + ">" + typePrefix + "__" + name + id.ToString ("X");
}
- public static void Reset ()
+ protected CompilerGeneratedClass (DeclSpace parent, MemberName name, int mod)
+ : base (parent.NamespaceEntry, parent, name, mod | Modifiers.COMPILER_GENERATED | Modifiers.SEALED, null)
{
- next_index = 0;
}
- protected CompilerGeneratedClass (DeclSpace parent,
- MemberName name, int mod, Location loc) :
- base (parent.NamespaceEntry, parent, name, mod | Modifiers.COMPILER_GENERATED, null)
+ protected CompilerGeneratedClass (DeclSpace parent, GenericMethod generic, MemberName name, int mod)
+ : this (parent, name, mod)
{
- parent.PartialContainer.AddCompilerGeneratedClass (this);
- }
-
- protected CompilerGeneratedClass (DeclSpace parent, GenericMethod generic,
- int mod, Location loc)
- : this (parent, MakeProxyName (generic, loc), mod, loc)
- {
- this.generic_method = generic;
-
if (generic != null) {
ArrayList list = new ArrayList ();
foreach (TypeParameter tparam in generic.TypeParameters) {
}
SetParameterInfo (list);
}
-
}
- protected override bool DefineNestedTypes ()
+ protected void CheckMembersDefined ()
{
- RootContext.RegisterCompilerGeneratedType (TypeBuilder);
- return base.DefineNestedTypes ();
+ if (members_defined)
+ throw new InternalErrorException ("Helper class already defined!");
}
+ }
- protected override bool DoDefineMembers ()
- {
- members_defined = true;
-
- if (!base.DoDefineMembers ())
- return false;
+ //
+ // Anonymous method storey is created when an anonymous method uses
+ // variable or parameter from outer scope. They are then hoisted to
+ // anonymous method storey (captured)
+ //
+ public class AnonymousMethodStorey : CompilerGeneratedClass
+ {
+ class StoreyFieldPair {
+ public readonly AnonymousMethodStorey Storey;
+ public readonly Field Field;
- if (CompilerGenerated != null) {
- foreach (CompilerGeneratedClass c in CompilerGenerated) {
- if (!c.DefineMembers ())
- throw new InternalErrorException ();
- }
+ public StoreyFieldPair (AnonymousMethodStorey storey, Field field)
+ {
+ this.Storey = storey;
+ this.Field = field;
}
- return true;
- }
-
- protected override bool DoResolveMembers ()
- {
- if (CompilerGenerated != null) {
- foreach (CompilerGeneratedClass c in CompilerGenerated) {
- if (!c.ResolveMembers ())
- return false;
- }
+ public override int GetHashCode ()
+ {
+ return Storey.ID.GetHashCode ();
}
- return base.DoResolveMembers ();
- }
-
- public GenericMethod GenericMethod {
- get { return generic_method; }
- }
-
- public Parameters InflateParameters (Parameters ps)
- {
- if (generic_method == null)
- return ps;
-
- int n = ps.Count;
- if (n == 0)
- return ps;
-
- Parameter[] inflated_params = new Parameter [n];
- Type[] inflated_types = new Type [n];
-
- for (int i = 0; i < n; ++i) {
- Parameter p = ps [i];
- Type it = InflateType (p.ExternalType ()).ResolveAsTypeTerminal (this, false).Type;
- inflated_types [i] = it;
- inflated_params [i] = new Parameter (it, p.Name, p.ModFlags, p.OptAttributes, p.Location);
+ public override bool Equals (object obj)
+ {
+ return (AnonymousMethodStorey)obj == Storey;
}
- return Parameters.CreateFullyResolved (inflated_params, inflated_types);
}
- public TypeExpr InflateType (Type it)
+ sealed class HoistedGenericField : Field
{
-#if GMCS_SOURCE
- 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 ();
+ public HoistedGenericField (DeclSpace parent, FullNamedExpression type, int mod, string name,
+ Attributes attrs, Location loc)
+ : base (parent, type, mod, new MemberName (name, loc), attrs)
+ {
+ }
- TypeArguments inflated = new TypeArguments (Location);
- foreach (Type t in args)
- inflated.Add (InflateType (t));
+ protected override bool ResolveMemberType ()
+ {
+ if (!base.ResolveMemberType ())
+ return false;
- return new ConstructedType (it, inflated, Location);
- } else if (it.IsArray) {
- TypeExpr et_expr = InflateType (it.GetElementType ());
- int rank = it.GetArrayRank ();
+ AnonymousMethodStorey parent = ((AnonymousMethodStorey) Parent).GetGenericStorey ();
+ if (parent != null)
+ member_type = parent.MutateType (member_type);
- Type et = et_expr.ResolveAsTypeTerminal (this, false).Type;
- it = et.MakeArrayType (rank);
+ return true;
}
-#endif
-
- return new TypeExpression (it, Location);
}
- public Field CaptureVariable (string name, TypeExpr type)
+ //
+ // Needed to delay hoisted _this_ initialization. When an anonymous
+ // method is used inside ctor and _this_ is hoisted, base ctor has to
+ // be called first, otherwise _this_ will be initialized with
+ // uninitialized value.
+ //
+ sealed class ThisInitializer : Statement
{
- if (members_defined)
- throw new InternalErrorException ("Helper class already defined!");
- if (type == null)
- throw new ArgumentNullException ();
+ readonly HoistedThis hoisted_this;
- return new CapturedVariableField (this, name, type);
- }
+ public ThisInitializer (HoistedThis hoisted_this)
+ {
+ this.hoisted_this = hoisted_this;
+ }
- bool members_defined;
+ protected override void DoEmit (EmitContext ec)
+ {
+ hoisted_this.EmitHoistingAssignment (ec);
+ }
- internal void CheckMembersDefined ()
- {
- if (members_defined)
- throw new InternalErrorException ("Helper class already defined!");
- }
+ protected override void CloneTo (CloneContext clonectx, Statement target)
+ {
+ // Nothing to clone
+ }
- protected class CapturedVariableField : Field
- {
- public CapturedVariableField (CompilerGeneratedClass helper, string name,
- TypeExpr type)
- : base (helper, type, Modifiers.INTERNAL, name, null, helper.Location)
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
{
- helper.AddField (this);
+ // Nothing to mutate
}
}
- }
- public class ScopeInfo : CompilerGeneratedClass
- {
- protected readonly RootScopeInfo RootScope;
- new public readonly DeclSpace Parent;
- public readonly int ID = ++next_id;
- public readonly Block ScopeBlock;
- protected ScopeInitializer scope_initializer;
+ // Unique storey ID
+ public readonly int ID;
+ static int unique_id;
- readonly Hashtable locals = new Hashtable ();
- readonly Hashtable captured_scopes = new Hashtable ();
- Hashtable captured_params;
-
- static int next_id;
-
- public static ScopeInfo CreateScope (Block block)
- {
- ToplevelBlock toplevel = block.Toplevel;
- AnonymousContainer ac = toplevel.AnonymousContainer;
+ public readonly Block OriginalSourceBlock;
- Report.Debug (128, "CREATE SCOPE", block, block.ScopeInfo, toplevel, ac);
+ // A list of StoreyFieldPair with local field keeping parent storey instance
+ ArrayList used_parent_storeys;
+ ArrayList children_references;
- if (ac == null)
- return new ScopeInfo (block, toplevel.RootScope.Parent,
- toplevel.RootScope.GenericMethod);
+ // A list of hoisted parameters
+ protected ArrayList hoisted_params;
+ protected ArrayList hoisted_locals;
- Report.Debug (128, "CREATE SCOPE #1", ac, ac.Host, ac.Scope, ac.Block,
- ac.Container,
- ac.Location);
+ // Hoisted this
+ protected HoistedThis hoisted_this;
- Block b;
- ScopeInfo parent = null;
+ // Local variable which holds this storey instance
+ public LocalTemporary Instance;
- for (b = ac.Block; b != null; b = b.Parent) {
- if (b.ScopeInfo != null) {
- parent = b.ScopeInfo;
- break;
- }
- }
-
- Report.Debug (128, "CREATE SCOPE #2", parent);
-
- ScopeInfo new_scope = new ScopeInfo (block, parent, null);
-
- Report.Debug (128, "CREATE SCOPE #3", new_scope);
-
- return new_scope;
- }
-
- private static int default_modflags (DeclSpace parent)
- {
- return parent is CompilerGeneratedClass ? Modifiers.PUBLIC : Modifiers.PRIVATE;
- }
-
- protected ScopeInfo (Block block, DeclSpace parent, GenericMethod generic)
- : base (parent, generic, default_modflags (parent), block.StartLocation)
+ public AnonymousMethodStorey (Block block, DeclSpace parent, MemberBase host, GenericMethod generic, string name)
+ : base (parent, generic, MakeMemberName (host, name, generic, block.StartLocation), Modifiers.PRIVATE)
{
Parent = parent;
- RootScope = block.Toplevel.RootScope;
- ScopeBlock = block;
-
- Report.Debug (128, "NEW SCOPE", this, block,
- block.Parent, block.Toplevel);
-
- RootScope.AddScope (this);
+ OriginalSourceBlock = block;
+ ID = unique_id++;
}
- protected ScopeInfo (ToplevelBlock toplevel, DeclSpace parent,
- GenericMethod generic, Location loc)
- : base (parent, generic, default_modflags (parent), loc)
+ static MemberName MakeMemberName (MemberBase host, string name, GenericMethod generic, Location loc)
{
- Parent = parent;
- RootScope = (RootScopeInfo) this;
- ScopeBlock = toplevel;
-
- Report.Debug (128, "NEW ROOT SCOPE", this, toplevel, loc);
- }
-
- protected CapturedScope[] CapturedScopes {
- get {
- CapturedScope[] list = new CapturedScope [captured_scopes.Count];
- captured_scopes.Values.CopyTo (list, 0);
- return list;
+ string host_name = host == null ? null : host.Name;
+ string tname = MakeName (host_name, "c", name, unique_id);
+ TypeArguments args = null;
+ if (generic != null) {
+ args = new TypeArguments ();
+ foreach (TypeParameter tparam in generic.CurrentTypeParameters)
+ args.Add (new TypeParameterName (tparam.Name, null, loc));
}
- }
- protected CapturedVariable GetCapturedScope (ScopeInfo scope)
- {
- return (CapturedVariable) captured_scopes [scope];
+ return new MemberName (tname, args, loc);
}
- protected void EmitScopeInstance (EmitContext ec)
+ public void AddCapturedThisField (EmitContext ec)
{
- 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 ();
- }
-
- scope_initializer.Emit (ec);
+ TypeExpr type_expr = new TypeExpression (ec.ContainerType, Location);
+ Field f = AddCompilerGeneratedField ("<>f__this", type_expr);
+ f.Define ();
+ hoisted_this = new HoistedThis (this, f);
}
- public ExpressionStatement GetScopeInitializer (EmitContext ec)
+ public Field AddCapturedVariable (string name, Type type)
{
- Report.Debug (128, "GET SCOPE INITIALIZER",
- this, GetType (), scope_initializer, ScopeBlock);
-
- if (scope_initializer == null) {
- scope_initializer = CreateScopeInitializer ();
- if (scope_initializer.Resolve (ec) == null)
- throw new InternalErrorException ();
- }
-
- return scope_initializer;
- }
+ CheckMembersDefined ();
- public Type GetScopeType (EmitContext ec)
- {
+ FullNamedExpression field_type = new TypeExpression (type, Location);
if (!IsGeneric)
- return TypeBuilder;
-
- TypeArguments targs = new TypeArguments (Location);
+ return AddCompilerGeneratedField (name, field_type);
- if (ec.DeclContainer.Parent.IsGeneric)
- foreach (TypeParameter t in ec.DeclContainer.Parent.TypeParameters)
- targs.Add (new TypeParameterExpr (t, Location));
- if (ec.DeclContainer.IsGeneric)
- foreach (TypeParameter t in ec.DeclContainer.CurrentTypeParameters)
- targs.Add (new TypeParameterExpr (t, Location));
-
- Report.Debug (128, "GET SCOPE TYPE", this, TypeBuilder, targs,
- ec.DeclContainer, ec.DeclContainer.GetType (),
- ec.DeclContainer.Parent.Name);
-
- TypeExpr te = new ConstructedType (TypeBuilder, targs, Location);
- te = te.ResolveAsTypeTerminal (ec, false);
- if ((te == null) || (te.Type == null))
- return null;
- return te.Type;
+ const int mod = Modifiers.INTERNAL | Modifiers.COMPILER_GENERATED;
+ Field f = new HoistedGenericField (this, field_type, mod, name, null, Location);
+ AddField (f);
+ return f;
}
- protected override bool DoDefineMembers ()
+ protected Field AddCompilerGeneratedField (string name, FullNamedExpression type)
{
- Report.Debug (64, "SCOPE INFO DEFINE MEMBERS", this, GetType (), IsGeneric,
- Parent.IsGeneric, GenericMethod);
-
- foreach (CapturedScope child in CapturedScopes) {
- if (!child.DefineMembers ())
- return false;
- }
-
- return base.DoDefineMembers ();
+ const int mod = Modifiers.INTERNAL | Modifiers.COMPILER_GENERATED;
+ Field f = new Field (this, type, mod, new MemberName (name, Location), null);
+ AddField (f);
+ return f;
}
- protected override bool DoResolveMembers ()
+ //
+ // Creates a link between block and the anonymous method storey
+ //
+ // An anonymous method can reference variables from any outer block, but they are
+ // hoisted in their own ExplicitBlock. When more than one block is referenced we
+ // need to create another link between those variable storeys
+ //
+ public void AddReferenceFromChildrenBlock (ExplicitBlock block)
{
- Report.Debug (64, "SCOPE INFO RESOLVE MEMBERS", this, GetType (), IsGeneric,
- Parent.IsGeneric, GenericMethod);
+ if (children_references == null)
+ children_references = new ArrayList ();
- return base.DoResolveMembers ();
+ if (!children_references.Contains (block))
+ children_references.Add (block);
}
- public Variable CaptureScope (ScopeInfo child)
+ public void AddParentStoreyReference (AnonymousMethodStorey storey)
{
CheckMembersDefined ();
- Report.Debug (128, "CAPTURE SCOPE", this, GetType (), child, child.GetType ());
- if (child == this)
- throw new InternalErrorException ();
- CapturedScope captured = (CapturedScope) captured_scopes [child];
- if (captured == null) {
- captured = new CapturedScope (this, child);
- captured_scopes.Add (child, captured);
- }
- return captured;
- }
-
- public Variable AddLocal (LocalInfo local)
- {
- Report.Debug (128, "CAPTURE LOCAL", this, local);
- Variable var = (Variable) locals [local];
- if (var == null) {
- var = new CapturedLocal (this, local);
- locals.Add (local, var);
- local.IsCaptured = true;
- }
- return var;
- }
- public Variable GetCapturedVariable (LocalInfo local)
- {
- return (Variable) locals [local];
- }
+ if (used_parent_storeys == null)
+ used_parent_storeys = new ArrayList ();
+ else if (used_parent_storeys.IndexOf (storey) != -1)
+ return;
- public bool HostsParameters {
- get { return captured_params != null; }
+ TypeExpr type_expr = new TypeExpression (storey.TypeBuilder, Location);
+ Field f = AddCompilerGeneratedField ("<>f__ref$" + storey.ID, type_expr);
+ used_parent_storeys.Add (new StoreyFieldPair (storey, f));
}
- public Variable GetCapturedParameter (Parameter par)
+ public void CaptureLocalVariable (EmitContext ec, LocalInfo local_info)
{
- if (captured_params != null)
- return (Variable) captured_params [par];
- else
- return null;
- }
+ ec.CurrentBlock.Explicit.HasCapturedVariable = true;
+ if (ec.CurrentBlock.Explicit != local_info.Block.Explicit)
+ AddReferenceFromChildrenBlock (ec.CurrentBlock.Explicit);
- public Variable AddParameter (Parameter par, int idx)
- {
- if (captured_params == null)
- captured_params = new Hashtable ();
+ if (local_info.HoistedVariableReference != null)
+ return;
- Variable var = (Variable) captured_params [par];
- if (var == null) {
- var = new CapturedParameter (this, par, idx);
- captured_params.Add (par, var);
- par.IsCaptured = true;
- }
+ HoistedVariable var = new HoistedLocalVariable (this, local_info, GetVariableMangledName (local_info));
+ local_info.HoistedVariableReference = var;
+
+ if (hoisted_locals == null)
+ hoisted_locals = new ArrayList ();
- return var;
+ hoisted_locals.Add (var);
}
- public override void EmitType ()
+ public void CaptureParameter (EmitContext ec, ParameterReference param_ref)
{
- SymbolWriter.DefineAnonymousScope (ID);
- foreach (CapturedLocal local in locals.Values)
- local.EmitSymbolInfo ();
-
- if (captured_params != null) {
- foreach (CapturedParameter param in captured_params.Values)
- param.EmitSymbolInfo ();
- }
+ ec.CurrentBlock.Explicit.HasCapturedVariable = true;
+ AddReferenceFromChildrenBlock (ec.CurrentBlock.Explicit);
- foreach (CapturedScope scope in CapturedScopes) {
- scope.EmitSymbolInfo ();
- }
+ if (param_ref.GetHoistedVariable (ec) != null)
+ return;
- base.EmitType ();
- }
+ if (hoisted_params == null)
+ hoisted_params = new ArrayList (2);
- protected string MakeFieldName (string local_name)
- {
- return "<" + ID + ":" + local_name + ">";
+ HoistedVariable expr = new HoistedParameter (this, param_ref);
+ param_ref.Parameter.HoistedVariableReference = expr;
+ hoisted_params.Add (expr);
}
- protected virtual ScopeInitializer CreateScopeInitializer ()
+ public void ChangeParentStorey (AnonymousMethodStorey parentStorey)
{
- return new ScopeInitializer (this);
+ Parent = parentStorey;
+ type_params = null;
}
- protected abstract class CapturedVariable : Variable
+ //
+ // Initializes all hoisted variables
+ //
+ public void EmitStoreyInstantiation (EmitContext ec)
{
- public readonly ScopeInfo Scope;
- public readonly string Name;
+ // There can be only one instance variable for each storey type
+ if (Instance != null)
+ throw new InternalErrorException ();
- public FieldExpr FieldInstance;
- protected Field field;
+ SymbolWriter.OpenCompilerGeneratedBlock (ec.ig);
- protected CapturedVariable (ScopeInfo scope, string name)
- {
- this.Scope = scope;
- this.Name = name;
- }
+ //
+ // Create an instance of storey type
+ //
+ Expression storey_type_expr;
+ if (is_generic) {
+ //
+ // Use current method type parameter (MVAR) for top level storey only. All
+ // nested storeys use class type parameter (VAR)
+ //
+ TypeParameter[] tparams = ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod.Storey != null ?
+ ec.CurrentAnonymousMethod.Storey.TypeParameters :
+ ec.GenericDeclContainer.TypeParameters;
- protected CapturedVariable (ScopeInfo scope, string name, Type type)
- : this (scope, name)
- {
- this.field = scope.CaptureVariable (
- scope.MakeFieldName (name), scope.RootScope.InflateType (type));
- }
+ TypeArguments targs = new TypeArguments ();
- public Field Field {
- get { return field; }
- }
+ if (tparams.Length < CountTypeParameters) {
+ TypeParameter[] parent_tparams = ec.DeclContainer.Parent.PartialContainer.TypeParameters;
+ for (int i = 0; i < parent_tparams.Length; ++i)
+ targs.Add (new TypeParameterExpr (parent_tparams[i], Location));
+ }
+
+ for (int i = 0; i < tparams.Length; ++i)
+ targs.Add (new TypeParameterExpr (tparams[i], Location));
- public override Type Type {
- get { return Field.MemberType; }
+ storey_type_expr = new GenericTypeExpr (TypeBuilder, targs, Location);
+ } else {
+ storey_type_expr = new TypeExpression (TypeBuilder, Location);
}
- public override bool HasInstance {
- get { return true; }
- }
+ Expression e = new New (storey_type_expr, new ArrayList (0), Location).Resolve (ec);
+ e.Emit (ec);
- public override bool NeedsTemporary {
- get { return true; }
- }
+ Instance = new LocalTemporary (storey_type_expr.Type);
+ Instance.Store (ec);
- protected FieldInfo GetField (EmitContext ec)
- {
- if ((ec.CurrentBlock != null) &&
- (ec.CurrentBlock.Toplevel != Scope.ScopeBlock.Toplevel))
- return Field.FieldBuilder;
- else
- return FieldInstance.FieldInfo;
- }
+ EmitHoistedFieldsInitialization (ec);
- public abstract void EmitSymbolInfo ();
+ SymbolWriter.DefineScopeVariable (ID, Instance.Builder);
+ SymbolWriter.CloseCompilerGeneratedBlock (ec.ig);
+ }
- public override void EmitInstance (EmitContext ec)
- {
- if ((ec.CurrentAnonymousMethod != null) &&
- (ec.CurrentAnonymousMethod.Scope == Scope)) {
- ec.ig.Emit (OpCodes.Ldarg_0);
- return;
+ void EmitHoistedFieldsInitialization (EmitContext ec)
+ {
+ //
+ // Initialize all storey reference fields by using local or hoisted variables
+ //
+ if (used_parent_storeys != null) {
+ foreach (StoreyFieldPair sf in used_parent_storeys) {
+ //
+ // Setting local field
+ //
+ Expression instace_expr = GetStoreyInstanceExpression (ec);
+ FieldExpr f_set_expr = TypeManager.IsGenericType (instace_expr.Type) ?
+ new FieldExpr (sf.Field.FieldBuilder, instace_expr.Type, Location) :
+ new FieldExpr (sf.Field.FieldBuilder, Location);
+ f_set_expr.InstanceExpression = instace_expr;
+
+ SimpleAssign a = new SimpleAssign (f_set_expr, sf.Storey.GetStoreyInstanceExpression (ec));
+ if (a.Resolve (ec) != null)
+ a.EmitStatement (ec);
}
-
- Scope.EmitScopeInstance (ec);
}
- 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));
+ //
+ // Define hoisted `this' in top-level storey only
+ //
+ if (OriginalSourceBlock.Explicit.HasCapturedThis && !(Parent is AnonymousMethodStorey)) {
+ AddCapturedThisField (ec);
+ OriginalSourceBlock.AddScopeStatement (new ThisInitializer (hoisted_this));
}
- }
- protected class CapturedParameter : CapturedVariable {
- public readonly Parameter Parameter;
- public readonly int Idx;
+ //
+ // Setting currect anonymous method to null blocks any further variable hoisting
+ //
+ AnonymousExpression ae = ec.CurrentAnonymousMethod;
+ ec.CurrentAnonymousMethod = null;
- public CapturedParameter (ScopeInfo scope, Parameter par, int idx)
- : base (scope, par.Name, par.ParameterType)
- {
- this.Parameter = par;
- this.Idx = idx;
+ if (hoisted_params != null) {
+ EmitHoistedParameters (ec, hoisted_params);
}
- public override void EmitSymbolInfo ()
- {
- SymbolWriter.DefineCapturedParameter (
- Scope.ID, Parameter.Name, Field.Name);
- }
+ ec.CurrentAnonymousMethod = ae;
+ }
- public override string ToString ()
- {
- return String.Format ("{0} ({1}:{2}:{3})", GetType (), Field,
- Parameter.Name, Idx);
+ protected virtual void EmitHoistedParameters (EmitContext ec, ArrayList hoisted)
+ {
+ foreach (HoistedParameter hp in hoisted) {
+ hp.EmitHoistingAssignment (ec);
}
}
- protected class CapturedLocal : CapturedVariable {
- public readonly LocalInfo Local;
+ public override void EmitType ()
+ {
+ SymbolWriter.DefineAnonymousScope (ID);
- public CapturedLocal (ScopeInfo scope, LocalInfo local)
- : base (scope, local.Name, local.VariableType)
- {
- this.Local = local;
+ if (hoisted_this != null)
+ hoisted_this.EmitSymbolInfo ();
+
+ if (hoisted_locals != null) {
+ foreach (HoistedVariable local in hoisted_locals)
+ local.EmitSymbolInfo ();
}
- public override void EmitSymbolInfo ()
- {
- SymbolWriter.DefineCapturedLocal (
- Scope.ID, Local.Name, Field.Name);
+ if (hoisted_params != null) {
+ foreach (HoistedParameter param in hoisted_params)
+ param.EmitSymbolInfo ();
}
- public override string ToString ()
- {
- return String.Format ("{0} ({1}:{2})", GetType (), Field,
- Local.Name);
+ if (used_parent_storeys != null) {
+ foreach (StoreyFieldPair sf in used_parent_storeys) {
+ SymbolWriter.DefineCapturedScope (ID, sf.Storey.ID, sf.Field.Name);
+ }
}
+
+ base.EmitType ();
}
- protected class CapturedThis : CapturedVariable {
- public CapturedThis (RootScopeInfo host)
- : base (host, "<>THIS", host.ParentType)
- { }
+ public AnonymousMethodStorey GetGenericStorey ()
+ {
+ DeclSpace storey = this;
+ while (storey != null && storey.CurrentTypeParameters.Length == 0)
+ storey = storey.Parent;
- public override void EmitSymbolInfo ()
- {
- SymbolWriter.DefineCapturedThis (Scope.ID, Field.Name);
- }
+ return storey as AnonymousMethodStorey;
}
- protected class CapturedScope : CapturedVariable {
- public readonly ScopeInfo ChildScope;
+ //
+ // Returns a field which holds referenced storey instance
+ //
+ Field GetReferencedStoreyField (AnonymousMethodStorey storey)
+ {
+ if (used_parent_storeys == null)
+ return null;
- public CapturedScope (ScopeInfo root, ScopeInfo child)
- : base (root, "scope" + child.ID)
- {
- this.ChildScope = child;
+ foreach (StoreyFieldPair sf in used_parent_storeys) {
+ if (sf.Storey == storey)
+ return sf.Field;
}
- public override void EmitSymbolInfo ()
- {
- SymbolWriter.DefineCapturedScope (Scope.ID, ChildScope.ID, Field.Name);
- }
+ return null;
+ }
- public bool DefineMembers ()
- {
- Type type = ChildScope.IsGeneric ?
- ChildScope.CurrentType : ChildScope.TypeBuilder;
- Report.Debug (128, "CAPTURED SCOPE DEFINE MEMBERS", this, Scope,
- ChildScope, Name, type);
- if (type == null)
- throw new InternalErrorException ();
- field = Scope.CaptureVariable (
- Scope.MakeFieldName (Name), Scope.InflateType (type));
- return true;
- }
+ //
+ // Creates storey instance expression regardless of currect IP
+ //
+ public Expression GetStoreyInstanceExpression (EmitContext ec)
+ {
+ AnonymousExpression am = ec.CurrentAnonymousMethod;
- public override string ToString ()
- {
- return String.Format ("CapturedScope ({1} captured in {0})",
- Scope, ChildScope);
+ //
+ // Access from original block -> storey
+ //
+ if (am == null)
+ return Instance;
+
+ //
+ // Access from anonymous method implemented as a static -> storey
+ //
+ if (am.Storey == null)
+ return Instance;
+
+ Field f = am.Storey.GetReferencedStoreyField (this);
+ if (f == null) {
+ if (am.Storey == this) {
+ //
+ // Access inside of same storey (S -> S)
+ //
+ return new CompilerGeneratedThis (TypeBuilder, Location);
+ }
+ //
+ // External field access
+ //
+ return Instance;
}
+
+ //
+ // Storey was cached to local field
+ //
+ FieldExpr f_ind = new FieldExpr (f.FieldBuilder, Location);
+ f_ind.InstanceExpression = new CompilerGeneratedThis (TypeBuilder, Location);
+ return f_ind;
}
- static void DoPath (StringBuilder sb, ScopeInfo start)
+ protected virtual string GetVariableMangledName (LocalInfo local_info)
{
- sb.Append ((start.ID).ToString ());
+ //
+ // No need to mangle anonymous method hoisted variables cause they
+ // are hoisted in their own scopes
+ //
+ return local_info.Name;
}
-
- public override string ToString ()
- {
- StringBuilder sb = new StringBuilder ();
-
- sb.Append ("{");
- DoPath (sb, this);
- sb.Append ("}");
- return sb.ToString ();
+ public HoistedThis HoistedThis {
+ get { return hoisted_this; }
}
- protected class ScopeInitializer : ExpressionStatement
+ //
+ // Mutate type dispatcher
+ //
+ public Type MutateType (Type type)
{
- ScopeInfo scope;
- CapturedVariable captured_scope;
- LocalBuilder scope_instance;
- ConstructorInfo scope_ctor;
+#if GMCS_SOURCE
+ if (TypeManager.IsGenericType (type))
+ return MutateGenericType (type);
- bool initialized;
+ if (TypeManager.IsGenericParameter (type))
+ return MutateGenericArgument (type);
- public ScopeInitializer (ScopeInfo scope)
- {
- this.scope = scope;
- this.loc = scope.Location;
- eclass = ExprClass.Value;
- }
+ if (type.IsArray)
+ return MutateArrayType (type);
+#endif
+ return type;
+ }
- public ScopeInfo Scope {
- get { return scope; }
+ //
+ // Changes method type arguments (MVAR) to storey (VAR) type arguments
+ //
+ public MethodInfo MutateGenericMethod (MethodInfo method)
+ {
+#if GMCS_SOURCE
+ Type [] t_args = TypeManager.GetGenericArguments (method);
+ if (TypeManager.IsGenericType (method.DeclaringType)) {
+ Type t = MutateGenericType (method.DeclaringType);
+ if (t != method.DeclaringType) {
+ method = (MethodInfo) TypeManager.DropGenericMethodArguments (method);
+ if (method.Module == Module.Builder)
+ method = TypeBuilder.GetMethod (t, method);
+ else
+ method = (MethodInfo) MethodInfo.GetMethodFromHandle (method.MethodHandle, t.TypeHandle);
+ }
}
- public override Expression DoResolve (EmitContext ec)
- {
- if (scope_ctor != null)
- return this;
+ if (t_args == null || t_args.Length == 0)
+ return method;
- Report.Debug (64, "RESOLVE SCOPE INITIALIZER BASE", this, Scope,
- ec, ec.CurrentBlock);
+ for (int i = 0; i < t_args.Length; ++i)
+ t_args [i] = MutateType (t_args [i]);
- type = Scope.GetScopeType (ec);
- if (type == null)
- throw new InternalErrorException ();
-
- if (!DoResolveInternal (ec))
- throw new InternalErrorException ();
+ return method.GetGenericMethodDefinition ().MakeGenericMethod (t_args);
+#else
+ throw new NotSupportedException ();
+#endif
+ }
- return this;
+ public ConstructorInfo MutateConstructor (ConstructorInfo ctor)
+ {
+#if GMCS_SOURCE
+ if (TypeManager.IsGenericType (ctor.DeclaringType)) {
+ Type t = MutateGenericType (ctor.DeclaringType);
+ if (t != ctor.DeclaringType) {
+ ctor = (ConstructorInfo) TypeManager.DropGenericMethodArguments (ctor);
+ if (ctor.Module == Module.Builder)
+ return TypeBuilder.GetConstructor (t, ctor);
+
+ return (ConstructorInfo) ConstructorInfo.GetMethodFromHandle (ctor.MethodHandle, t.TypeHandle);
+ }
}
-
- protected virtual bool DoResolveInternal (EmitContext ec)
- {
- MethodGroupExpr mg = (MethodGroupExpr) MemberLookupFinal (
- ec, ec.ContainerType, type, ".ctor", MemberTypes.Constructor,
- AllBindingFlags | BindingFlags.DeclaredOnly, loc);
- if (mg == null)
- throw new InternalErrorException ();
-
- scope_ctor = (ConstructorInfo) mg.Methods [0];
-
- Report.Debug (128, "RESOLVE THE INIT", this, Scope, Scope.RootScope,
- Scope.RootScope.GetType ());
-
- ScopeInfo host = Scope.RootScope;
- if ((Scope != host) && (Scope.RootScope is IteratorHost)) {
- captured_scope = host.GetCapturedScope (Scope);
- Type root = host.GetScopeType (ec);
- FieldExpr fe = (FieldExpr) Expression.MemberLookup (
- type, root, captured_scope.Field.Name, loc);
- if (fe == null)
- throw new InternalErrorException ();
-
- fe.InstanceExpression = this;
- captured_scope.FieldInstance = fe;
-
- Report.Debug (128, "RESOLVE THE INIT #1", this,
- captured_scope, fe);
- } else {
- scope_instance = ec.ig.DeclareLocal (type);
- if (!Scope.RootScope.IsIterator)
- SymbolWriter.DefineScopeVariable (Scope.ID, scope_instance);
+#endif
+ return ctor;
+ }
+
+ public FieldInfo MutateField (FieldInfo field)
+ {
+#if GMCS_SOURCE
+ if (TypeManager.IsGenericType (field.DeclaringType)) {
+ Type t = MutateGenericType (field.DeclaringType);
+ if (t != field.DeclaringType) {
+ // TODO: It should throw on imported types
+ return TypeBuilder.GetField (t, field);
}
+ }
+#endif
+ return field;
+ }
- foreach (CapturedLocal local in Scope.locals.Values) {
- 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;
- }
+#if GMCS_SOURCE
+ protected Type MutateArrayType (Type array)
+ {
+ int rank = array.GetArrayRank ();
+ Type element = TypeManager.GetElementType (array);
+ if (element.IsArray) {
+ element = MutateArrayType (element);
+ } else if (TypeManager.IsGenericParameter (element)) {
+ element = MutateGenericArgument (element);
+ } else if (TypeManager.IsGenericType (element)) {
+ element = MutateGenericType (element);
+ } else {
+ return array;
+ }
- if (Scope.HostsParameters) {
- foreach (CapturedParameter cp in Scope.captured_params.Values) {
- FieldExpr fe = (FieldExpr) Expression.MemberLookup (
- ec.ContainerType, type, cp.Field.Name, loc);
- if (fe == null)
- throw new InternalErrorException ();
+ return element.MakeArrayType (rank);
+ }
- fe.InstanceExpression = this;
- cp.FieldInstance = fe;
- }
- }
+ protected Type MutateGenericType (Type type)
+ {
+ Type [] t_args = TypeManager.GetTypeArguments (type);
+ if (t_args == null || t_args.Length == 0)
+ return type;
- foreach (CapturedScope scope in Scope.CapturedScopes) {
- FieldExpr fe = (FieldExpr) Expression.MemberLookup (
- ec.ContainerType, type, scope.Field.Name, loc);
- Report.Debug (64, "RESOLVE SCOPE INITIALIZER #3", this, Scope,
- scope, ec, ec.ContainerType, type,
- scope.Field, scope.Field.Name, loc, fe);
- if (fe == null)
- throw new InternalErrorException ();
-
- fe.InstanceExpression = this;
- scope.FieldInstance = fe;
- }
+ for (int i = 0; i < t_args.Length; ++i)
+ t_args [i] = MutateType (t_args [i]);
- return true;
- }
+ return type.GetGenericTypeDefinition ().MakeGenericType (t_args);
+ }
+#endif
- protected virtual void EmitParameterReference (EmitContext ec,
- CapturedParameter cp)
- {
- int extra = ec.MethodIsStatic ? 0 : 1;
- ParameterReference.EmitLdArg (ec.ig, cp.Idx + extra);
+ //
+ // Changes method generic argument (MVAR) to type generic argument (VAR)
+ //
+ public Type MutateGenericArgument (Type type)
+ {
+ foreach (TypeParameter tp in CurrentTypeParameters) {
+ if (tp.Name == type.Name) {
+ return tp.Type;
+ }
}
- static int next_id;
- int id = ++next_id;
+ return type;
+ }
- protected virtual void DoEmit (EmitContext ec)
- {
- if ((ec.CurrentBlock != null) &&
- (ec.CurrentBlock.Toplevel != Scope.ScopeBlock.Toplevel)) {
- ec.ig.Emit (OpCodes.Ldarg_0);
-
- if (ec.CurrentAnonymousMethod != null) {
- ScopeInfo host = ec.CurrentAnonymousMethod.Scope;
- Variable captured = host.GetCapturedScope (scope);
- Report.Debug (128, "EMIT SCOPE INSTANCE #2",
- ec.CurrentAnonymousMethod, host,
- scope, captured);
- if (captured != null)
- captured.Emit (ec);
- }
- } else if (scope_instance != null)
- ec.ig.Emit (OpCodes.Ldloc, scope_instance);
- else {
- Report.Debug (128, "DO EMIT", this, Scope, ec,
- scope_instance, captured_scope);
- captured_scope.EmitInstance (ec);
- captured_scope.Emit (ec);
- }
- }
+ public ArrayList ReferencesFromChildrenBlock {
+ get { return children_references; }
+ }
- protected void DoEmitInstance (EmitContext ec)
- {
- Report.Debug (128, "DO EMIT INSTANCE", this, Scope, ec,
- scope_instance, captured_scope);
+ public static void Reset ()
+ {
+ unique_id = 0;
+ }
+ }
- if (scope_instance != null)
- ec.ig.Emit (OpCodes.Ldloc, scope_instance);
- else
- captured_scope.EmitInstance (ec);
- }
+ public abstract class HoistedVariable
+ {
+ class ExpressionTreeProxy : Expression
+ {
+ readonly HoistedVariable hv;
- protected virtual void EmitScopeConstructor (EmitContext ec)
+ public ExpressionTreeProxy (HoistedVariable hv)
{
- ec.ig.Emit (OpCodes.Newobj, scope_ctor);
+ this.hv = hv;
}
- public override void Emit (EmitContext ec)
+ public override Expression CreateExpressionTree (EmitContext ec)
{
- if (!initialized)
- throw new InternalErrorException (
- "Scope {0} not initialized yet", scope);
-
- DoEmit (ec);
+ throw new NotSupportedException ("ET");
}
- public override void EmitStatement (EmitContext ec)
+ public override Expression DoResolve (EmitContext ec)
{
- if (initialized)
- return;
-
- DoEmitStatement (ec);
- initialized = true;
+ eclass = ExprClass.Value;
+ type = TypeManager.expression_type_expr.Type;
+ return this;
}
- protected virtual void DoEmitStatement (EmitContext ec)
+ public override void Emit (EmitContext ec)
{
- Report.Debug (128, "EMIT SCOPE INITIALIZER STATEMENT", 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);
-
- if (scope_instance == null)
- ec.ig.Emit (OpCodes.Ldarg_0);
- EmitScopeConstructor (ec);
- if (scope_instance != null)
- ec.ig.Emit (OpCodes.Stloc, scope_instance);
- else
- captured_scope.EmitAssign (ec);
-
- if (Scope.HostsParameters) {
- foreach (CapturedParameter cp in Scope.captured_params.Values) {
- Report.Debug (128, "EMIT SCOPE INIT #6", this,
- ec, ec.IsStatic, Scope, cp, cp.Field.Name);
- DoEmitInstance (ec);
- EmitParameterReference (ec, cp);
- ec.ig.Emit (OpCodes.Stfld, cp.FieldInstance.FieldInfo);
- }
- }
-
- if (Scope is IteratorHost)
- return;
-
- foreach (CapturedScope scope in Scope.CapturedScopes) {
- ScopeInfo child = scope.ChildScope;
-
- Report.Debug (128, "EMIT SCOPE INIT #5", this, Scope,
- scope.Scope, scope.ChildScope);
-
- ExpressionStatement init = child.GetScopeInitializer (ec);
- init.EmitStatement (ec);
-
- DoEmit (ec);
- scope.ChildScope.EmitScopeInstance (ec);
- scope.EmitAssign (ec);
- }
+ Expression e = hv.GetFieldExpression (ec).CreateExpressionTree (ec);
+ // This should never fail
+ e = e.Resolve (ec);
+ if (e != null)
+ e.Emit (ec);
}
}
- }
+
+ protected readonly AnonymousMethodStorey storey;
+ protected Field field;
+ Hashtable cached_inner_access; // TODO: Hashtable is too heavyweight
+ FieldExpr cached_outer_access;
- public class RootScopeInfo : ScopeInfo
- {
- public RootScopeInfo (ToplevelBlock toplevel, DeclSpace parent,
- GenericMethod generic, Location loc)
- : base (toplevel, parent, generic, loc)
+ protected HoistedVariable (AnonymousMethodStorey storey, string name, Type type)
+ : this (storey, storey.AddCapturedVariable (name, type))
{
- scopes = new ArrayList ();
}
- TypeExpr parent_type;
- CapturedVariableField parent_link;
- CapturedThis this_variable;
- protected ArrayList scopes;
-
- public virtual bool IsIterator {
- get { return false; }
- }
-
- public RootScopeInfo ParentHost {
- get { return Parent.PartialContainer as RootScopeInfo; }
- }
-
- public Type ParentType {
- get { return parent_type.Type; }
- }
-
- public Field ParentLink {
- get { return parent_link; }
+ protected HoistedVariable (AnonymousMethodStorey storey, Field field)
+ {
+ this.storey = storey;
+ this.field = field;
}
- protected CapturedThis THIS {
- get { return this_variable; }
+ public void AddressOf (EmitContext ec, AddressOp mode)
+ {
+ GetFieldExpression (ec).AddressOf (ec, mode);
}
- public Variable CaptureThis ()
+ public Expression CreateExpressionTree (EmitContext ec)
{
- if (ParentHost != null)
- return ParentHost.CaptureThis ();
-
- CheckMembersDefined ();
- if (this_variable == null)
- this_variable = new CapturedThis (this);
- return this_variable;
+ return new ExpressionTreeProxy (this);
}
- public void AddScope (ScopeInfo scope)
+ public void Emit (EmitContext ec)
{
- scopes.Add (scope);
+ GetFieldExpression (ec).Emit (ec);
}
- bool linked;
- public void LinkScopes ()
+ //
+ // Creates field access expression for hoisted variable
+ //
+ protected FieldExpr GetFieldExpression (EmitContext ec)
{
- Report.Debug (128, "LINK SCOPES", this, linked, scopes);
+ if (ec.CurrentAnonymousMethod == null || ec.CurrentAnonymousMethod.Storey == null) {
+ if (cached_outer_access != null)
+ return cached_outer_access;
- if (linked)
- return;
-
- linked = true;
- if (ParentHost != null)
- ParentHost.LinkScopes ();
-
- foreach (ScopeInfo si in scopes) {
- if (!si.Define ())
- throw new InternalErrorException ();
- if (si.DefineType () == null)
- throw new InternalErrorException ();
- if (!si.ResolveType ())
- throw new InternalErrorException ();
- }
+ //
+ // When setting top-level hoisted variable in generic storey
+ // change storey generic types to method generic types (VAR -> MVAR)
+ //
+ cached_outer_access = storey.MemberName.IsGeneric ?
+ new FieldExpr (field.FieldBuilder, storey.Instance.Type, field.Location) :
+ new FieldExpr (field.FieldBuilder, field.Location);
- foreach (ScopeInfo si in scopes) {
- if (!si.ResolveMembers ())
- throw new InternalErrorException ();
- if (!si.DefineMembers ())
- throw new InternalErrorException ();
+ cached_outer_access.InstanceExpression = storey.GetStoreyInstanceExpression (ec);
+ cached_outer_access.Resolve (ec);
+ return cached_outer_access;
}
- }
- protected override ScopeInitializer CreateScopeInitializer ()
- {
- return new RootScopeInitializer (this);
- }
-
- protected override bool DefineNestedTypes ()
- {
- 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;
+ FieldExpr inner_access;
+ if (cached_inner_access != null) {
+ inner_access = (FieldExpr) cached_inner_access [ec.CurrentAnonymousMethod];
} else {
- parent_type = new TypeExpression (Parent.TypeBuilder, Location);
+ inner_access = null;
+ cached_inner_access = new Hashtable (4);
}
- CompilerGeneratedClass parent = Parent.PartialContainer as CompilerGeneratedClass;
- if (parent != null)
- parent_link = new CapturedVariableField (this, "<>parent", parent_type);
+ if (inner_access == null) {
+ inner_access = new FieldExpr (field.FieldBuilder, field.Location);
+ inner_access.InstanceExpression = storey.GetStoreyInstanceExpression (ec);
+ inner_access.Resolve (ec);
+ cached_inner_access.Add (ec.CurrentAnonymousMethod, inner_access);
+ }
- return base.DefineNestedTypes ();
+ return inner_access;
}
- protected override bool DoDefineMembers ()
- {
- ArrayList args = new ArrayList ();
- if (this is IteratorHost)
- args.Add (new Parameter (
- TypeManager.int32_type, "$PC", Parameter.Modifier.NONE,
- null, Location));
-
- Field pfield;
- if (Parent is CompilerGeneratedClass)
- pfield = parent_link;
- else
- pfield = this_variable != null ? this_variable.Field : null;
- if (pfield != null)
- args.Add (new Parameter (
- pfield.MemberType, "parent", 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));
+ public abstract void EmitSymbolInfo ();
- return base.DoDefineMembers ();
- }
-
- protected virtual void EmitScopeConstructor (EmitContext ec)
+ public void Emit (EmitContext ec, bool leave_copy)
{
- int pos = (this is IteratorHost) ? 2 : 1;
-
- Field pfield;
- if (Parent is CompilerGeneratedClass)
- pfield = parent_link;
- else
- pfield = this_variable != null ? this_variable.Field : null;
-
- if (pfield != null) {
- ec.ig.Emit (OpCodes.Ldarg_0);
- ec.ig.Emit (OpCodes.Ldarg, pos);
- ec.ig.Emit (OpCodes.Stfld, pfield.FieldBuilder);
- pos++;
- }
+ GetFieldExpression (ec).Emit (ec, leave_copy);
}
- public override void EmitType ()
+ public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
{
- base.EmitType ();
- if (THIS != null)
- THIS.EmitSymbolInfo ();
+ GetFieldExpression (ec).EmitAssign (ec, source, leave_copy, false);
}
+ }
- protected class TheCtor : Statement
+ class HoistedParameter : HoistedVariable
+ {
+ sealed class HoistedFieldAssign : Assign
{
- RootScopeInfo host;
-
- public TheCtor (RootScopeInfo host)
+ public HoistedFieldAssign (Expression target, Expression source)
+ : base (target, source, source.Location)
{
- this.host = host;
}
- public override bool Resolve (EmitContext ec)
+ protected override Expression ResolveConversions (EmitContext ec)
{
- return true;
- }
-
- protected override void DoEmit (EmitContext ec)
- {
- host.EmitScopeConstructor (ec);
+ //
+ // Implicit conversion check fails for hoisted type arguments
+ // as they are of different types (!!0 x !0)
+ //
+ return this;
}
}
- protected class RootScopeInitializer : ScopeInitializer
- {
- RootScopeInfo host;
-
- public RootScopeInitializer (RootScopeInfo host)
- : base (host)
- {
- this.host = host;
- }
-
- public RootScopeInfo Host {
- get { return host; }
- }
-
- protected override bool DoResolveInternal (EmitContext ec)
- {
- Report.Debug (64, "RESOLVE ANONYMOUS METHOD HOST INITIALIZER",
- this, Host, Host.ParentType, loc);
-
- if (Host.THIS != null) {
- FieldExpr fe = (FieldExpr) Expression.MemberLookup (
- ec.ContainerType, type, Host.THIS.Field.Name, loc);
- if (fe == null)
- throw new InternalErrorException ();
-
- fe.InstanceExpression = this;
- Host.THIS.FieldInstance = fe;
- }
-
- return base.DoResolveInternal (ec);
- }
+ readonly ParameterReference parameter;
- protected virtual bool IsGetEnumerator {
- get { return false; }
- }
-
- protected override void EmitScopeConstructor (EmitContext ec)
- {
- if (host.THIS != null) {
- ec.ig.Emit (OpCodes.Ldarg_0);
- if (IsGetEnumerator)
- ec.ig.Emit (OpCodes.Ldfld, host.THIS.Field.FieldBuilder);
- else if (host.THIS.Type.IsValueType)
- Expression.LoadFromPtr (ec.ig, host.THIS.Type);
- } else if (host.ParentLink != null)
- ec.ig.Emit (OpCodes.Ldarg_0);
+ public HoistedParameter (AnonymousMethodStorey scope, ParameterReference par)
+ : base (scope, par.Name, par.Type)
+ {
+ this.parameter = par;
+ }
- base.EmitScopeConstructor (ec);
- }
+ public HoistedParameter (HoistedParameter hp, string name)
+ : base (hp.storey, name, hp.parameter.Type)
+ {
+ this.parameter = hp.parameter;
}
- }
+ public void EmitHoistingAssignment (EmitContext ec)
+ {
+ //
+ // Remove hoisted redirection to emit assignment from original parameter
+ //
+ HoistedVariable temp = parameter.Parameter.HoistedVariableReference;
+ parameter.Parameter.HoistedVariableReference = null;
- public interface IAnonymousContainer
- {
- Block Container {
- get;
- }
+ Assign a = new HoistedFieldAssign (GetFieldExpression (ec), parameter);
+ if (a.Resolve (ec) != null)
+ a.EmitStatement (ec);
- GenericMethod GenericMethod {
- get;
+ parameter.Parameter.HoistedVariableReference = temp;
}
- RootScopeInfo RootScope {
- get;
+ public override void EmitSymbolInfo ()
+ {
+ SymbolWriter.DefineCapturedParameter (storey.ID, field.Name, field.Name);
}
- bool IsIterator {
- get;
+ public Field Field {
+ get { return field; }
}
}
- public interface IAnonymousHost
- {
- //
- // Invoked if a yield statement is found in the body
- //
- void SetYields ();
-
- //
- // Invoked if an anonymous method is found in the body
- //
- void AddAnonymousMethod (AnonymousMethodExpression anonymous);
- }
-
- public class AnonymousMethodExpression : Expression, IAnonymousContainer, IAnonymousHost
+ class HoistedLocalVariable : HoistedVariable
{
- public readonly AnonymousMethodExpression Parent;
- public readonly TypeContainer Host;
- public readonly Parameters Parameters;
+ readonly string name;
- public ToplevelBlock Block;
-
- protected Block container;
- protected readonly GenericMethod generic;
-
- public Block Container {
- get { return container; }
- }
-
- public GenericMethod GenericMethod {
- get { return generic; }
- }
-
- public RootScopeInfo RootScope {
- get { return root_scope; }
+ public HoistedLocalVariable (AnonymousMethodStorey scope, LocalInfo local, string name)
+ : base (scope, name, local.VariableType)
+ {
+ this.name = local.Name;
}
- public AnonymousMethodExpression (AnonymousMethodExpression parent,
- GenericMethod generic, TypeContainer host,
- Parameters parameters, Block container,
- Location loc)
+ public override void EmitSymbolInfo ()
{
- 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);
-
- if (parent != null)
- parent.AddAnonymousMethod (this);
+ SymbolWriter.DefineCapturedLocal (storey.ID, name, field.Name);
}
+ }
- ArrayList children;
- RootScopeInfo root_scope;
-
- static int next_index;
-
- void IAnonymousHost.SetYields ()
+ public class HoistedThis : HoistedVariable
+ {
+ public HoistedThis (AnonymousMethodStorey storey, Field field)
+ : base (storey, field)
{
- throw new InvalidOperationException ();
}
- public void AddAnonymousMethod (AnonymousMethodExpression anonymous)
+ public void EmitHoistingAssignment (EmitContext ec)
{
- if (children == null)
- children = new ArrayList ();
- children.Add (anonymous);
+ SimpleAssign a = new SimpleAssign (GetFieldExpression (ec), ec.GetThis (field.Location));
+ if (a.Resolve (ec) != null)
+ a.EmitStatement (ec);
}
- public bool CreateAnonymousHelpers ()
+ public override void EmitSymbolInfo ()
{
- // FIXME: this polutes expression trees implementation
-
- Report.Debug (64, "ANONYMOUS METHOD EXPRESSION CREATE ROOT SCOPE",
- this, Host, container, loc);
+ SymbolWriter.DefineCapturedThis (storey.ID, field.Name);
+ }
- if (container != null)
- root_scope = container.Toplevel.CreateRootScope (Host);
+ public Field Field {
+ get { return field; }
+ }
+ }
- if (children != null) {
- foreach (AnonymousMethodExpression child in children) {
- if (!child.CreateAnonymousHelpers ())
- return false;
- }
- }
+ //
+ // Anonymous method expression as created by parser
+ //
+ public class AnonymousMethodExpression : Expression
+ {
+ ListDictionary compatibles;
+ public ToplevelBlock Block;
- return true;
+ public AnonymousMethodExpression (Location loc)
+ {
+ this.loc = loc;
+ this.compatibles = new ListDictionary ();
}
public override string ExprClassName {
public virtual bool HasExplicitParameters {
get {
- return true;
+ return Parameters != ParametersCompiled.Undefined;
}
}
+
+ public ParametersCompiled Parameters {
+ get { return Block.Parameters; }
+ }
//
// Returns true if the body of lambda expression can be implicitly
// converted to the delegate of type `delegate_type'
//
- public bool ImplicitStandardConversionExists (Type delegate_type)
+ public bool ImplicitStandardConversionExists (EmitContext ec, Type delegate_type)
{
- EmitContext ec = EmitContext.TempEc;
- using (ec.Set (EmitContext.Flags.ProbingMode)) {
- return Compatible (ec, delegate_type) != null;
+ using (ec.With (EmitContext.Flags.InferReturnType, false)) {
+ using (ec.Set (EmitContext.Flags.ProbingMode)) {
+ return Compatible (ec, delegate_type) != null;
+ }
}
}
protected Type CompatibleChecks (EmitContext ec, Type delegate_type)
{
- if (!ec.IsAnonymousMethodAllowed) {
- Report.Error (1706, loc, "Anonymous methods and lambda expressions cannot be used in the current context");
- return null;
- }
-
if (TypeManager.IsDelegateType (delegate_type))
return delegate_type;
return null;
}
- protected bool VerifyExplicitParameters (Type delegate_type, ParameterData parameters, bool ignore_error)
+ protected bool VerifyExplicitParameters (Type delegate_type, AParametersCollection parameters, bool ignore_error)
{
if (VerifyParameterCompatibility (delegate_type, parameters, ignore_error))
return true;
return false;
}
- protected bool VerifyParameterCompatibility (Type delegate_type, ParameterData invoke_pd, bool ignore_errors)
+ protected bool VerifyParameterCompatibility (Type delegate_type, AParametersCollection invoke_pd, bool ignore_errors)
{
if (Parameters.Count != invoke_pd.Count) {
if (ignore_errors)
TypeManager.CSharpName (delegate_type), Parameters.Count.ToString ());
return false;
}
-
- if (!HasExplicitParameters)
- return true;
+ bool has_implicit_parameters = !HasExplicitParameters;
bool error = false;
+
for (int i = 0; i < Parameters.Count; ++i) {
- Parameter.Modifier p_mod = invoke_pd.ParameterModifier (i);
- if (Parameters.ParameterModifier (i) != p_mod && p_mod != Parameter.Modifier.PARAMS) {
+ Parameter.Modifier p_mod = invoke_pd.FixedParameters [i].ModFlags;
+ if (Parameters.FixedParameters [i].ModFlags != p_mod && p_mod != Parameter.Modifier.PARAMS) {
if (ignore_errors)
return false;
if (p_mod == Parameter.Modifier.NONE)
Report.Error (1677, loc, "Parameter `{0}' should not be declared with the `{1}' keyword",
- (i + 1).ToString (), Parameter.GetModifierSignature (Parameters.ParameterModifier (i)));
+ (i + 1).ToString (), Parameter.GetModifierSignature (Parameters.FixedParameters [i].ModFlags));
else
Report.Error (1676, loc, "Parameter `{0}' must be declared with the `{1}' keyword",
(i+1).ToString (), Parameter.GetModifierSignature (p_mod));
error = true;
- continue;
}
+ if (has_implicit_parameters)
+ continue;
+
Type type = invoke_pd.Types [i];
// We assume that generic parameters are always inflated
if (TypeManager.HasElementType (type) && TypeManager.IsGenericParameter (TypeManager.GetElementType (type)))
continue;
- if (invoke_pd.ParameterType (i) != Parameters.ParameterType (i)) {
+ if (invoke_pd.Types [i] != Parameters.Types [i]) {
if (ignore_errors)
return false;
Report.Error (1678, loc, "Parameter `{0}' is declared as type `{1}' but should be `{2}'",
(i+1).ToString (),
- TypeManager.CSharpName (Parameters.ParameterType (i)),
- TypeManager.CSharpName (invoke_pd.ParameterType (i)));
+ TypeManager.CSharpName (Parameters.Types [i]),
+ TypeManager.CSharpName (invoke_pd.Types [i]));
error = true;
}
}
#endif
}
- ParameterData d_params = TypeManager.GetDelegateParameters (delegate_type);
+ AParametersCollection d_params = TypeManager.GetDelegateParameters (delegate_type);
if (d_params.Count != Parameters.Count)
return false;
if (!TypeManager.HasElementType (itype))
continue;
- if (!TypeManager.IsGenericParameter (itype.GetElementType ()))
+ if (!TypeManager.IsGenericParameter (TypeManager.GetElementType (itype)))
continue;
}
- type_inference.ExactInference (Parameters.FixedParameters[i].ParameterType, itype);
+ type_inference.ExactInference (Parameters.Types [i], itype);
}
return true;
}
public Type InferReturnType (EmitContext ec, TypeInferenceContext tic, Type delegate_type)
{
- AnonymousMethod am;
+ AnonymousMethodBody am;
using (ec.Set (EmitContext.Flags.ProbingMode | EmitContext.Flags.InferReturnType)) {
am = CompatibleMethod (ec, tic, GetType (), delegate_type);
}
if (am == null)
return null;
+ // Stop referencing gmcs NullLiteral type
if (am.ReturnType == TypeManager.null_type)
am.ReturnType = null;
//
public Expression Compatible (EmitContext ec, Type type)
{
+ Expression am = (Expression) compatibles [type];
+ if (am != null)
+ return am;
+
Type delegate_type = CompatibleChecks (ec, type);
if (delegate_type == null)
return null;
// to be the delegate type return type.
//
- Report.Debug (64, "COMPATIBLE", this, Parent, GenericMethod, Host,
- Container, Block, return_type, delegate_type,
- TypeManager.IsGenericType (delegate_type), loc);
-
try {
int errors = Report.Errors;
- AnonymousMethod am = CompatibleMethod (ec, null, return_type, delegate_type);
+ am = CompatibleMethod (ec, null, return_type, delegate_type);
if (am != null && delegate_type != type && errors == Report.Errors)
- return CreateExpressionTree (ec, delegate_type);
+ am = CreateExpressionTree (ec, delegate_type);
+
+ if (!ec.IsInProbingMode)
+ compatibles.Add (type, am == null ? EmptyExpression.Null : am);
return am;
} catch (Exception e) {
}
protected virtual Expression CreateExpressionTree (EmitContext ec, Type delegate_type)
+ {
+ return CreateExpressionTree (ec);
+ }
+
+ public override Expression CreateExpressionTree (EmitContext ec)
{
Report.Error (1946, loc, "An anonymous method cannot be converted to an expression tree");
return null;
}
- protected virtual Parameters ResolveParameters (EmitContext ec, TypeInferenceContext tic, Type delegate_type)
+ protected virtual ParametersCompiled ResolveParameters (EmitContext ec, TypeInferenceContext tic, Type delegate_type)
{
- ParameterData delegate_parameters = TypeManager.GetDelegateParameters (delegate_type);
+ AParametersCollection delegate_parameters = TypeManager.GetDelegateParameters (delegate_type);
- if (Parameters == null) {
+ if (Parameters == ParametersCompiled.Undefined) {
//
// We provide a set of inaccessible parameters
//
Parameter[] fixedpars = new Parameter[delegate_parameters.Count];
for (int i = 0; i < delegate_parameters.Count; i++) {
- Parameter.Modifier i_mod = delegate_parameters.ParameterModifier (i);
- if ((i_mod & Parameter.Modifier.OUTMASK) != 0) {
+ Parameter.Modifier i_mod = delegate_parameters.FixedParameters [i].ModFlags;
+ if (i_mod == Parameter.Modifier.OUT) {
Report.Error (1688, loc, "Cannot convert anonymous " +
"method block without a parameter list " +
"to delegate type `{0}' because it has " +
return null;
}
fixedpars[i] = new Parameter (
- delegate_parameters.ParameterType (i), "+" + (++next_index),
- delegate_parameters.ParameterModifier (i), null, loc);
+ null, null,
+ delegate_parameters.FixedParameters [i].ModFlags, null, loc);
}
- return Parameters.CreateFullyResolved (fixedpars, delegate_parameters.Types);
+ return ParametersCompiled.CreateFullyResolved (fixedpars, delegate_parameters.Types);
}
if (!VerifyExplicitParameters (delegate_type, delegate_parameters, ec.IsInProbingMode)) {
return Parameters;
}
- public override Expression DoResolve (EmitContext ec)
- {
+ public override Expression DoResolve (EmitContext ec)
+ {
+ if (!ec.IsAnonymousMethodAllowed) {
+ Report.Error (1706, loc, "Anonymous methods and lambda expressions cannot be used in the current context");
+ return null;
+ }
+
//
// Set class type, set type
//
if ((Parameters != null) && !Parameters.Resolve (ec))
return null;
+ // FIXME: The emitted code isn't very careful about reachability
+ // so, ensure we have a 'ret' at the end
+ if (ec.CurrentBranching != null &&
+ ec.CurrentBranching.CurrentUsageVector.IsUnreachable)
+ ec.NeedReturnLabel ();
+
return this;
}
// nothing, as we only exist to not do anything.
}
- public override string GetSignatureForError ()
+ public static void Error_AddressOfCapturedVar (IVariableReference var, Location loc)
{
- return ExprClassName;
+ Report.Error (1686, loc,
+ "Local variable or parameter `{0}' cannot have their address taken and be used inside an anonymous method or lambda expression",
+ var.Name);
}
- public bool IsIterator {
- get { return false; }
+ public override string GetSignatureForError ()
+ {
+ return ExprClassName;
}
- protected AnonymousMethod CompatibleMethod (EmitContext ec, TypeInferenceContext tic, Type return_type, Type delegate_type)
+ protected AnonymousMethodBody CompatibleMethod (EmitContext ec, TypeInferenceContext tic, Type return_type, Type delegate_type)
{
- Parameters p = ResolveParameters (ec, tic, delegate_type);
+ ParametersCompiled p = ResolveParameters (ec, tic, delegate_type);
if (p == null)
return null;
ToplevelBlock b = ec.IsInProbingMode ? (ToplevelBlock) Block.PerformClone () : Block;
- AnonymousMethod anonymous = CompatibleMethodFactory (return_type, delegate_type, p, b);
+ AnonymousMethodBody anonymous = CompatibleMethodFactory (return_type, delegate_type, p, b);
if (!anonymous.Compatible (ec))
return null;
return anonymous;
}
- protected virtual AnonymousMethod CompatibleMethodFactory (Type return_type, Type delegate_type, Parameters p, ToplevelBlock b)
+ protected virtual AnonymousMethodBody CompatibleMethodFactory (Type return_type, Type delegate_type, ParametersCompiled p, ToplevelBlock b)
{
- return new AnonymousMethod (RootScope, Host,
- GenericMethod, p, Container, b, return_type,
- delegate_type, loc);
+ return new AnonymousMethodBody (p, b, return_type, delegate_type, loc);
}
protected override void CloneTo (CloneContext clonectx, Expression t)
AnonymousMethodExpression target = (AnonymousMethodExpression) t;
target.Block = (ToplevelBlock) clonectx.LookupBlock (Block);
- target.container = clonectx.LookupBlock (Block);
}
}
- public abstract class AnonymousContainer : Expression, IAnonymousContainer
+ //
+ // Abstract expression for any block which requires variables hoisting
+ //
+ public abstract class AnonymousExpression : Expression
{
- public Parameters Parameters;
+ protected class AnonymousMethodMethod : Method
+ {
+ public readonly AnonymousExpression AnonymousMethod;
+ public readonly AnonymousMethodStorey Storey;
+ readonly string RealName;
- //
- // The block that makes up the body for the anonymous mehtod
- //
- public readonly ToplevelBlock Block;
+ public AnonymousMethodMethod (DeclSpace parent, AnonymousExpression am, AnonymousMethodStorey storey,
+ GenericMethod generic, TypeExpr return_type,
+ int mod, string real_name, MemberName name,
+ ParametersCompiled parameters)
+ : base (parent, generic, return_type, mod | Modifiers.COMPILER_GENERATED,
+ name, parameters, null)
+ {
+ this.AnonymousMethod = am;
+ this.Storey = storey;
+ this.RealName = real_name;
- public readonly int ModFlags;
- public Type ReturnType;
- public readonly DeclSpace Host;
+ Parent.PartialContainer.AddMethod (this);
+ Block = am.Block;
+ }
- //
- // The implicit method we create
- //
- protected Method method;
- protected EmitContext aec;
+ public override EmitContext CreateEmitContext (DeclSpace tc, ILGenerator ig)
+ {
+ EmitContext aec = AnonymousMethod.aec;
+ aec.ig = ig;
+ aec.IsStatic = (ModFlags & Modifiers.STATIC) != 0;
+ return aec;
+ }
- // The emit context for the anonymous method
- protected bool unreachable;
- protected readonly Block container;
- protected readonly GenericMethod generic;
+ protected override bool ResolveMemberType ()
+ {
+ if (!base.ResolveMemberType ())
+ return false;
- protected AnonymousContainer (DeclSpace host,
- GenericMethod generic, Parameters parameters,
- Block container, ToplevelBlock block,
- Type return_type, int mod, Location loc)
- {
- this.ReturnType = return_type;
- this.ModFlags = mod | Modifiers.COMPILER_GENERATED;
- this.Host = host;
+ if (Storey != null && Storey.IsGeneric) {
+ AnonymousMethodStorey gstorey = Storey.GetGenericStorey ();
+ if (gstorey != null) {
+ if (!Parameters.IsEmpty) {
+ Type [] ptypes = Parameters.Types;
+ for (int i = 0; i < ptypes.Length; ++i)
+ ptypes [i] = gstorey.MutateType (ptypes [i]);
+ }
- this.container = container;
- this.generic = generic;
- this.Parameters = parameters;
- this.Block = block;
- this.loc = loc;
+ member_type = gstorey.MutateType (member_type);
+ }
+ }
- block.AnonymousContainer = this;
- }
+ return true;
+ }
- public Method Method {
- get { return method; }
- }
+ public override void Emit ()
+ {
+ //
+ // Before emitting any code we have to change all MVAR references to VAR
+ // when the method is of generic type and has hoisted variables
+ //
+ if (Storey == Parent && Storey.IsGeneric) {
+ AnonymousMethodStorey gstorey = Storey.GetGenericStorey ();
+ if (gstorey != null) {
+ AnonymousMethod.aec.ReturnType = gstorey.MutateType (ReturnType);
+ block.MutateHoistedGenericType (gstorey);
+ }
+ }
- public abstract string ContainerType {
- get;
- }
+ if (MethodBuilder == null) {
+ Define ();
+ }
- public abstract RootScopeInfo RootScope {
- get;
- }
+ base.Emit ();
+ }
- public abstract ScopeInfo Scope {
- get;
+ public override void EmitExtraSymbolInfo (SourceMethod source)
+ {
+ source.SetRealMethodName (RealName);
+ }
}
- public bool Compatible (EmitContext ec)
- {
- // REFACTOR: The method should be refactor, many of the
- // hacks can be handled in better way
+ //
+ // The block that makes up the body for the anonymous method
+ //
+ protected readonly ToplevelBlock Block;
- Report.Debug (64, "RESOLVE ANONYMOUS METHOD", this, Location, ec,
- RootScope, Parameters, ec.IsStatic);
+ public Type ReturnType;
+ protected EmitContext aec;
- if (ReturnType != null) {
- TypeExpr return_type_expr;
- if (RootScope != null)
- return_type_expr = RootScope.InflateType (ReturnType);
- else
- return_type_expr = new TypeExpression (ReturnType, Location);
- return_type_expr = return_type_expr.ResolveAsTypeTerminal (ec, false);
- if ((return_type_expr == null) || (return_type_expr.Type == null))
- return false;
- ReturnType = return_type_expr.Type;
- }
+ protected AnonymousExpression (ToplevelBlock block, Type return_type, Location loc)
+ {
+ this.ReturnType = return_type;
+ this.Block = block;
+ this.loc = loc;
+ }
- // Linq type inference is done differently
- if (RootScope != null && RootContext.Version != LanguageVersion.LINQ)
- Parameters = RootScope.InflateParameters (Parameters);
+ public abstract string ContainerType { get; }
+ public abstract bool IsIterator { get; }
+ public abstract AnonymousMethodStorey Storey { get; }
+ public bool Compatible (EmitContext ec)
+ {
+ // TODO: Implement clone
aec = new EmitContext (
- ec.ResolveContext, ec.TypeContainer,
- RootScope != null ? RootScope : Host, Location, null, ReturnType,
- /* REVIEW */ (ec.InIterator ? Modifiers.METHOD_YIELDS : 0) |
+ ec.ResolveContext, ec.TypeContainer, ec.DeclContainer,
+ Location, null, ReturnType,
(ec.InUnsafe ? Modifiers.UNSAFE : 0), /* No constructor */ false);
aec.CurrentAnonymousMethod = this;
aec.IsStatic = ec.IsStatic;
-
- //
- // HACK: Overwrite parent declaration container to currently resolved.
- // It's required for an anonymous container inside partial class.
- //
- if (RootScope != null)
- aec.DeclContainer.Parent = ec.TypeContainer;
IDisposable aec_dispose = null;
EmitContext.Flags flags = 0;
if (ec.InferReturnType)
flags |= EmitContext.Flags.InferReturnType;
-
+
if (ec.IsInProbingMode)
flags |= EmitContext.Flags.ProbingMode;
-
+
if (ec.IsInFieldInitializer)
flags |= EmitContext.Flags.InFieldInitializer;
-
+
+ if (ec.IsInUnsafeScope)
+ flags |= EmitContext.Flags.InUnsafe;
+
// HACK: Flag with 0 cannot be set
if (flags != 0)
aec_dispose = aec.Set (flags);
- Report.Debug (64, "RESOLVE ANONYMOUS METHOD #1", this, Location, ec, aec,
- RootScope, Parameters, Block);
-
bool unreachable;
- bool res = aec.ResolveTopBlock (ec, Block, Parameters, null, out unreachable);
+ bool res = aec.ResolveTopBlock (ec, Block, Block.Parameters, null, out unreachable);
if (ec.InferReturnType)
ReturnType = aec.ReturnType;
return res;
}
- public virtual bool Define (EmitContext ec)
- {
- Report.Debug (64, "DEFINE ANONYMOUS METHOD #3", this, ec, aec, Block);
-
- if (aec == null && !Compatible (ec))
- return false;
-
- // Don't define anything when we are in probing scope (nested anonymous methods)
- if (ec.IsInProbingMode)
- return true;
-
- method = DoCreateMethodHost (ec);
-
- if (Scope != null)
- return true;
-
- if (!method.ResolveMembers ())
- return false;
- return method.Define ();
- }
-
- protected abstract Method DoCreateMethodHost (EmitContext ec);
-
- public override void Emit (EmitContext ec)
- {
- throw new NotSupportedException ();
- }
-
- public Block Container {
- get { return container; }
- }
-
- public GenericMethod GenericMethod {
- get { return generic; }
- }
-
- public abstract bool IsIterator {
- get;
- }
-
- protected class AnonymousMethodMethod : Method
+ public void SetHasThisAccess ()
{
- public readonly AnonymousContainer AnonymousMethod;
- public readonly ScopeInfo Scope;
- public readonly string RealName;
-
- public AnonymousMethodMethod (AnonymousContainer am, ScopeInfo scope,
- GenericMethod generic, TypeExpr return_type,
- int mod, string real_name, MemberName name,
- Parameters parameters)
- : base (scope != null ? scope : am.Host,
- generic, return_type, mod | Modifiers.COMPILER_GENERATED, false, name, parameters, null)
- {
- this.AnonymousMethod = am;
- this.Scope = scope;
- this.RealName = real_name;
+ Block.HasCapturedThis = true;
+ ExplicitBlock b = Block.Parent.Explicit;
- if (scope != null) {
- scope.CheckMembersDefined ();
- scope.AddMethod (this);
- } else {
- ModFlags |= Modifiers.STATIC;
- am.Host.PartialContainer.AddMethod (this);
- }
- Block = am.Block;
- }
-
- public override EmitContext CreateEmitContext (DeclSpace tc, ILGenerator ig)
- {
- EmitContext aec = AnonymousMethod.aec;
- aec.ig = ig;
- aec.MethodIsStatic = Scope == null;
- return aec;
- }
+ while (b != null) {
+ if (b.HasCapturedThis)
+ return;
- public override void EmitExtraSymbolInfo ()
- {
- SymbolWriter.SetRealMethodName (RealName);
+ b.HasCapturedThis = true;
+ b = b.Parent == null ? null : b.Parent.Explicit;
}
}
}
- public class AnonymousMethod : AnonymousContainer
+ public class AnonymousMethodBody : AnonymousExpression
{
- Type DelegateType;
+ protected readonly ParametersCompiled parameters;
+ AnonymousMethodStorey storey;
- //
- // 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
- //
- RootScopeInfo root_scope;
- ScopeInfo scope;
+ AnonymousMethodMethod method;
+ Field am_cache;
+
+ static int unique_id;
- public AnonymousMethod (RootScopeInfo root_scope,
- DeclSpace host, GenericMethod generic,
- Parameters parameters, Block container,
+ public AnonymousMethodBody (ParametersCompiled parameters,
ToplevelBlock block, Type return_type, Type delegate_type,
Location loc)
- : base (host, generic, parameters, container, block,
- return_type, 0, loc)
+ : base (block, return_type, loc)
{
- this.DelegateType = delegate_type;
- this.root_scope = root_scope;
+ this.type = delegate_type;
+ this.parameters = parameters;
}
public override string ContainerType {
get { return "anonymous method"; }
}
- public override RootScopeInfo RootScope {
- get { return root_scope; }
- }
-
- public override ScopeInfo Scope {
- get { return scope; }
+ public override AnonymousMethodStorey Storey {
+ get { return storey; }
}
public override bool IsIterator {
get { return false; }
}
- public override string GetSignatureForError ()
+ public override Expression CreateExpressionTree (EmitContext ec)
{
- return TypeManager.CSharpName (DelegateType);
+ Report.Error (1945, loc, "An expression tree cannot contain an anonymous method expression");
+ return null;
}
- //
- // Creates the host for the anonymous method
- //
- protected override Method DoCreateMethodHost (EmitContext ec)
+ bool Define (EmitContext ec)
{
- MemberCore mc = ec.ResolveContext as MemberCore;
- string name = CompilerGeneratedClass.MakeName (mc.Name, null);
- MemberName member_name;
-
- Report.Debug (128, "CREATE METHOD HOST #0", RootScope);
-
- Block b;
- scope = RootScope;
+ if (aec == null && !Compatible (ec))
+ return false;
- Report.Debug (128, "CREATE METHOD HOST #1", this, Block, Block.ScopeInfo,
- RootScope, Location);
+ return true;
+ }
- for (b = Block.Parent; b != null; b = b.Parent) {
- Report.Debug (128, "CREATE METHOD HOST #2", this, Block,
- b, b.ScopeInfo);
- if (b.ScopeInfo != null) {
- scope = b.ScopeInfo;
- break;
- }
- }
+ //
+ // Creates a host for the anonymous method
+ //
+ AnonymousMethodMethod DoCreateMethodHost (EmitContext ec)
+ {
+ //
+ // Anonymous method body can be converted to
+ //
+ // 1, an instance method in current scope when only `this' is hoisted
+ // 2, a static method in current scope when neither `this' nor any variable is hoisted
+ // 3, an instance method in compiler generated storey when any hoisted variable exists
+ //
- if (scope != null)
- scope.CheckMembersDefined ();
+ int modifiers;
+ if (Block.HasCapturedVariable || Block.HasCapturedThis) {
+ storey = FindBestMethodStorey ();
+ modifiers = storey != null ? Modifiers.INTERNAL : Modifiers.PRIVATE;
+ } else {
+ if (ec.CurrentAnonymousMethod != null)
+ storey = ec.CurrentAnonymousMethod.Storey;
- ArrayList scopes = new ArrayList ();
- if (b != null) {
- for (b = b.Parent; b != null; b = b.Parent) {
- if (b.ScopeInfo != null)
- scopes.Add (b.ScopeInfo);
- }
+ modifiers = Modifiers.STATIC | Modifiers.PRIVATE;
}
- Report.Debug (128, "CREATE METHOD HOST #1", this, scope, scopes);
-
- foreach (ScopeInfo si in scopes)
- scope.CaptureScope (si);
-
- Report.Debug (128, "CREATE METHOD HOST", this, Block, container,
- RootScope, scope, scopes, Location);
-
- GenericMethod generic_method = null;
-#if GMCS_SOURCE
- if (TypeManager.IsGenericType (DelegateType)) {
- TypeArguments args = new TypeArguments (Location);
-
- Type dt = DelegateType.GetGenericTypeDefinition ();
+ DeclSpace parent = storey != null ? storey : ec.TypeContainer;
- Type[] tparam = TypeManager.GetTypeArguments (dt);
- for (int i = 0; i < tparam.Length; i++)
- args.Add (new SimpleName (tparam [i].Name, Location));
-
- member_name = new MemberName (name, args, Location);
+ MemberCore mc = ec.ResolveContext as MemberCore;
+ string name = CompilerGeneratedClass.MakeName (parent != storey ? mc.Name : null,
+ "m", null, unique_id++);
- Report.Debug (128, "CREATE METHOD HOST #5", this, DelegateType,
- TypeManager.GetTypeArguments (DelegateType),
- dt, tparam, args);
+ MemberName member_name;
+ GenericMethod generic_method;
+ if (storey == null && mc.MemberName.IsGeneric) {
+ member_name = new MemberName (name, mc.MemberName.TypeArguments.Clone (), Location);
- generic_method = new GenericMethod (
- Host.NamespaceEntry, scope, member_name,
- new TypeExpression (ReturnType, Location), Parameters);
+ generic_method = new GenericMethod (parent.NamespaceEntry, parent, member_name,
+ new TypeExpression (ReturnType, Location), parameters);
- generic_method.SetParameterInfo (null);
- } else
-#endif
+ ArrayList list = new ArrayList ();
+ foreach (TypeParameter tparam in ((IMethodData)mc).GenericMethod.CurrentTypeParameters) {
+ if (tparam.Constraints != null)
+ list.Add (tparam.Constraints.Clone ());
+ }
+ generic_method.SetParameterInfo (list);
+ } else {
member_name = new MemberName (name, Location);
+ generic_method = null;
+ }
string real_name = String.Format (
"{0}~{1}{2}", mc.GetSignatureForError (), GetSignatureForError (),
- Parameters.GetSignatureForError ());
+ parameters.GetSignatureForError ());
- return new AnonymousMethodMethod (
- this, scope, generic_method, new TypeExpression (ReturnType, Location),
- scope == null ? Modifiers.PRIVATE : Modifiers.INTERNAL,
- real_name, member_name, Parameters);
+ return new AnonymousMethodMethod (parent,
+ this, storey, generic_method, new TypeExpression (ReturnType, Location), modifiers,
+ real_name, member_name, parameters);
}
public override Expression DoResolve (EmitContext ec)
{
- if (!Define (ec))
- return null;
+ if (eclass == ExprClass.Invalid) {
+ if (!Define (ec))
+ return null;
+ }
- return new AnonymousDelegate (this, DelegateType, Location).Resolve (ec);
+ eclass = ExprClass.Value;
+ return this;
}
- public MethodInfo GetMethodBuilder (EmitContext ec)
+ public override void Emit (EmitContext ec)
{
- MethodInfo builder = method.MethodBuilder;
- if ((Scope != null) && Scope.IsGeneric) {
- Type scope_type = Scope.GetScopeType (ec);
- if (scope_type == null)
- throw new InternalErrorException ();
+ //
+ // Use same anonymous method implementation for scenarios where same
+ // code is used from multiple blocks, e.g. field initializers
+ //
+ if (method == null) {
+ //
+ // Delay an anonymous method definition to avoid emitting unused code
+ // for unreachable blocks or expression trees
+ //
+ method = DoCreateMethodHost (ec);
+ method.Define ();
+ }
- MethodGroupExpr mg = (MethodGroupExpr) Expression.MemberLookup (
- ec.ContainerType, scope_type, builder.Name,
- MemberTypes.Method, Expression.AllBindingFlags | BindingFlags.NonPublic, Location);
-
- if (mg == null)
- throw new InternalErrorException ();
- builder = (MethodInfo) mg.Methods [0];
+ bool is_static = (method.ModFlags & Modifiers.STATIC) != 0;
+ if (is_static && am_cache == null) {
+ //
+ // Creates a field cache to store delegate instance if it's not generic
+ //
+ if (!method.MemberName.IsGeneric) {
+ TypeContainer parent = method.Parent.PartialContainer;
+ int id = parent.Fields == null ? 0 : parent.Fields.Count;
+ am_cache = new Field (parent, new TypeExpression (type, loc),
+ Modifiers.STATIC | Modifiers.PRIVATE | Modifiers.COMPILER_GENERATED,
+ new MemberName (CompilerGeneratedClass.MakeName (null, "f", "am$cache", id), loc), null);
+ am_cache.Define ();
+ parent.AddField (am_cache);
+ } else {
+ // TODO: Implement caching of generated generic static methods
+ //
+ // Idea:
+ //
+ // Some extra class is needed to capture variable generic type
+ // arguments. Maybe we could re-use anonymous types, with a unique
+ // anonymous method id, but they are quite heavy.
+ //
+ // Consider : "() => typeof(T);"
+ //
+ // We need something like
+ // static class Wrap<Tn, Tm, DelegateType> {
+ // public static DelegateType cache;
+ // }
+ //
+ // We then specialize local variable to capture all generic parameters
+ // and delegate type, e.g. "Wrap<Ta, Tb, DelegateTypeInst> cache;"
+ //
+ }
+ }
+
+ ILGenerator ig = ec.ig;
+ Label l_initialized = ig.DefineLabel ();
+
+ if (am_cache != null) {
+ ig.Emit (OpCodes.Ldsfld, am_cache.FieldBuilder);
+ ig.Emit (OpCodes.Brtrue_S, l_initialized);
+ }
+
+ //
+ // Load method delegate implementation
+ //
+
+ if (is_static) {
+ ig.Emit (OpCodes.Ldnull);
+ } else if (storey != null) {
+ Expression e = storey.GetStoreyInstanceExpression (ec).Resolve (ec);
+ if (e != null)
+ e.Emit (ec);
+ } else {
+ ig.Emit (OpCodes.Ldarg_0);
}
+ MethodInfo delegate_method = method.MethodBuilder;
#if GMCS_SOURCE
- if (!DelegateType.IsGenericType)
- return builder;
+ if (storey != null && storey.MemberName.IsGeneric) {
+ Type t = storey.Instance.Type;
+
+ //
+ // Mutate anonymous method instance type if we are in nested
+ // hoisted generic anonymous method storey
+ //
+ if (ec.CurrentAnonymousMethod != null &&
+ ec.CurrentAnonymousMethod.Storey != null &&
+ ec.CurrentAnonymousMethod.Storey.IsGeneric) {
+ t = storey.GetGenericStorey ().MutateType (t);
+ }
- Type[] targs = TypeManager.GetTypeArguments (DelegateType);
- return builder.MakeGenericMethod (targs);
-#else
- return builder;
+ delegate_method = TypeBuilder.GetMethod (t, delegate_method);
+ }
#endif
- }
+ ig.Emit (OpCodes.Ldftn, delegate_method);
- 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);
- }
- }
+ ConstructorInfo constructor_method = Delegate.GetConstructor (ec.ContainerType, type);
+#if MS_COMPATIBLE
+ if (type.IsGenericType && type is TypeBuilder)
+ constructor_method = TypeBuilder.GetConstructor (type, constructor_method);
+#endif
+ ig.Emit (OpCodes.Newobj, constructor_method);
- //
- // This will emit the code for the delegate, as well delegate creation on the host
- //
- public class AnonymousDelegate : DelegateCreation {
- readonly AnonymousMethod am;
+ if (am_cache != null) {
+ ig.Emit (OpCodes.Stsfld, am_cache.FieldBuilder);
+ ig.MarkLabel (l_initialized);
+ ig.Emit (OpCodes.Ldsfld, am_cache.FieldBuilder);
+ }
+ }
//
- // if target_type is null, this means that we do not know the type
- // for this delegate, and we want to infer it from the various
- // returns (implicit and explicit) from the body of this anonymous
- // method.
- //
- // for example, the lambda: x => 1
+ // Look for the best storey for this anonymous method
//
- public AnonymousDelegate (AnonymousMethod am, Type target_type, Location l)
- {
- type = target_type;
- loc = l;
- this.am = am;
- }
-
- public override Expression DoResolve (EmitContext ec)
- {
- eclass = ExprClass.Value;
- return this;
- }
-
- public override void Emit (EmitContext ec)
+ AnonymousMethodStorey FindBestMethodStorey ()
{
- //ec.ig.Emit (OpCodes.Ldstr, "EMIT ANONYMOUS DELEGATE");
- //ec.ig.Emit (OpCodes.Pop);
-
//
- // Now emit the delegate creation.
+ // Use the nearest parent block which has a storey
//
- if ((am.Method.ModFlags & Modifiers.STATIC) == 0) {
- Report.Debug (128, "EMIT ANONYMOUS DELEGATE", this, am, am.Scope, loc);
- delegate_instance_expression = am.Scope.GetScopeInitializer (ec);
-
- if (delegate_instance_expression == null)
- throw new InternalErrorException ();
+ for (Block b = Block.Parent; b != null; b = b.Parent) {
+ AnonymousMethodStorey s = b.Explicit.AnonymousMethodStorey;
+ if (s != null)
+ return s;
}
+
+ return null;
+ }
- constructor_method = Delegate.GetConstructor (ec.ContainerType, type);
-#if MS_COMPATIBLE
- if (type.IsGenericType && type is TypeBuilder)
- constructor_method = TypeBuilder.GetConstructor (type, (ConstructorInfo)constructor_method);
-#endif
-
- delegate_method = am.GetMethodBuilder (ec);
- base.Emit (ec);
+ public override string GetSignatureForError ()
+ {
+ return TypeManager.CSharpName (type);
+ }
- //ec.ig.Emit (OpCodes.Ldstr, "EMIT ANONYMOUS DELEGATE DONE");
- //ec.ig.Emit (OpCodes.Pop);
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ {
+ type = storey.MutateType (type);
+ }
- Report.Debug (128, "EMIT ANONYMOUS DELEGATE DONE", this, am, am.Scope, loc);
+ public static void Reset ()
+ {
+ unique_id = 0;
}
}
//
public class AnonymousTypeClass : CompilerGeneratedClass
{
+ sealed class AnonymousParameters : ParametersCompiled
+ {
+ public AnonymousParameters (params Parameter[] parameters)
+ : base (parameters)
+ {
+ }
+
+ protected override void ErrorDuplicateName (Parameter p)
+ {
+ Report.Error (833, p.Location, "`{0}': An anonymous type cannot have multiple properties with the same name",
+ p.Name);
+ }
+ }
+
static int types_counter;
public const string ClassNamePrefix = "<>__AnonType";
public const string SignatureForError = "anonymous type";
readonly ArrayList parameters;
private AnonymousTypeClass (DeclSpace parent, MemberName name, ArrayList parameters, Location loc)
- : base (parent, name, Modifiers.SEALED, loc)
+ : base (parent, name, (RootContext.EvalMode ? Modifiers.PUBLIC : 0) | Modifiers.SEALED)
{
this.parameters = parameters;
}
{
if (RootContext.Version <= LanguageVersion.ISO_2)
Report.FeatureIsNotAvailable (loc, "anonymous types");
-
+
string name = ClassNamePrefix + types_counter++;
SimpleName [] t_args = new SimpleName [parameters.Count];
+ TypeParameterName [] t_params = new TypeParameterName [parameters.Count];
Parameter [] ctor_params = new Parameter [parameters.Count];
for (int i = 0; i < parameters.Count; ++i) {
AnonymousTypeParameter p = (AnonymousTypeParameter) parameters [i];
t_args [i] = new SimpleName ("<" + p.Name + ">__T", p.Location);
+ t_params [i] = new TypeParameterName (t_args [i].Name, null, p.Location);
ctor_params [i] = new Parameter (t_args [i], p.Name, 0, null, p.Location);
}
// named upon properties names
//
AnonymousTypeClass a_type = new AnonymousTypeClass (parent.NamespaceEntry.SlaveDeclSpace,
- new MemberName (name, new TypeArguments (loc, t_args), loc), parameters, loc);
+ new MemberName (name, new TypeArguments (t_params), loc), parameters, loc);
if (parameters.Count > 0)
a_type.SetParameterInfo (null);
- Constructor c = new Constructor (a_type, name, Modifiers.PUBLIC,
- new Parameters (ctor_params), null, loc);
- c.OptAttributes = a_type.GetDebuggerHiddenAttribute ();
+ Constructor c = new Constructor (a_type, name, Modifiers.PUBLIC | Modifiers.DEBUGGER_HIDDEN,
+ null, new AnonymousParameters (ctor_params), null, loc);
c.Block = new ToplevelBlock (c.Parameters, loc);
//
AnonymousTypeParameter p = (AnonymousTypeParameter) parameters [i];
Field f = new Field (a_type, t_args [i], Modifiers.PRIVATE | Modifiers.READONLY,
- "<" + p.Name + ">", null, p.Location);
+ new MemberName ("<" + p.Name + ">", p.Location), null);
if (!a_type.AddField (f)) {
error = true;
- Report.Error (833, p.Location, "`{0}': An anonymous type cannot have multiple properties with the same name",
- p.Name);
continue;
}
c.Block.AddStatement (new StatementExpression (
- new Assign (new MemberAccess (new This (p.Location), f.Name),
+ new SimpleAssign (new MemberAccess (new This (p.Location), f.Name),
c.Block.GetParameterReference (p.Name, p.Location))));
ToplevelBlock get_block = new ToplevelBlock (p.Location);
get_block.AddStatement (new Return (
new MemberAccess (new This (p.Location), f.Name), p.Location));
- Accessor get_accessor = new Accessor (get_block, 0, null, p.Location);
- Property prop = new Property (a_type, t_args [i], Modifiers.PUBLIC, false,
+ Accessor get_accessor = new Accessor (get_block, 0, null, null, p.Location);
+ Property prop = new Property (a_type, t_args [i], Modifiers.PUBLIC,
new MemberName (p.Name, p.Location), null, get_accessor, null, false);
a_type.AddProperty (prop);
}
return a_type;
}
- public new static void Reset ()
+ public static void Reset ()
{
types_counter = 0;
}
Location loc = Location;
Method equals = new Method (this, null, TypeManager.system_boolean_expr,
- Modifiers.PUBLIC | Modifiers.OVERRIDE, false, new MemberName ("Equals", loc),
- new Parameters (new Parameter (TypeManager.system_object_expr, "obj", 0, null, loc)),
- GetDebuggerHiddenAttribute ());
+ Modifiers.PUBLIC | Modifiers.OVERRIDE | Modifiers.DEBUGGER_HIDDEN, new MemberName ("Equals", loc),
+ Mono.CSharp.ParametersCompiled.CreateFullyResolved (new Parameter (null, "obj", 0, null, loc), TypeManager.object_type), null);
Method tostring = new Method (this, null, TypeManager.system_string_expr,
- Modifiers.PUBLIC | Modifiers.OVERRIDE, false, new MemberName ("ToString", loc),
- Mono.CSharp.Parameters.EmptyReadOnlyParameters, GetDebuggerHiddenAttribute ());
+ Modifiers.PUBLIC | Modifiers.OVERRIDE | Modifiers.DEBUGGER_HIDDEN, new MemberName ("ToString", loc),
+ Mono.CSharp.ParametersCompiled.EmptyReadOnlyParameters, null);
ToplevelBlock equals_block = new ToplevelBlock (equals.Parameters, loc);
TypeExpr current_type;
if (IsGeneric)
- current_type = new ConstructedType (TypeBuilder, TypeParameters, loc);
+ current_type = new GenericTypeExpr (this, loc);
else
current_type = new TypeExpression (TypeBuilder, loc);
LocalVariableReference other_variable = new LocalVariableReference (equals_block, "other", loc);
MemberAccess system_collections_generic = new MemberAccess (new MemberAccess (
- new SimpleName ("System", loc), "Collections", loc), "Generic", loc);
+ new QualifiedAliasMember ("global", "System", loc), "Collections", loc), "Generic", loc);
Expression rs_equals = null;
- Expression string_concat = new StringConstant ("<empty type>", loc);
+ Expression string_concat = new StringConstant ("{", loc);
Expression rs_hashcode = new IntConstant (-2128831035, loc);
for (int i = 0; i < parameters.Count; ++i) {
AnonymousTypeParameter p = (AnonymousTypeParameter) parameters [i];
MemberAccess equality_comparer = new MemberAccess (new MemberAccess (
system_collections_generic, "EqualityComparer",
- new TypeArguments (loc, new SimpleName (TypeParameters [i].Name, loc)), loc),
+ new TypeArguments (new SimpleName (TypeParameters [i].Name, loc)), loc),
"Default", loc);
ArrayList arguments_equal = new ArrayList (2);
new MemberAccess (new This (f.Location), f.Name), new NullLiteral (loc)),
new Invocation (new MemberAccess (
new MemberAccess (new This (f.Location), f.Name), "ToString"), null),
- new StringConstant ("<null>", loc));
+ new StringConstant (string.Empty, loc));
if (rs_equals == null) {
rs_equals = field_equal;
string_concat = new Binary (Binary.Operator.Addition,
- new StringConstant (p.Name + " = ", loc),
- field_to_string);
+ string_concat,
+ new Binary (Binary.Operator.Addition,
+ new StringConstant (" " + p.Name + " = ", loc),
+ field_to_string));
continue;
}
rs_equals = new Binary (Binary.Operator.LogicalAnd, rs_equals, field_equal);
}
+ string_concat = new Binary (Binary.Operator.Addition,
+ string_concat,
+ new StringConstant (" }", loc));
+
//
// Equals (object obj) override
//
equals_block.AddStatement (new StatementExpression (
- new Assign (other_variable,
+ new SimpleAssign (other_variable,
new As (equals_block.GetParameterReference ("obj", loc),
current_type, loc), loc)));
equals_block.AddStatement (new Return (equals_test, loc));
equals.Block = equals_block;
- equals.ResolveMembers ();
+ equals.Define ();
AddMethod (equals);
//
// GetHashCode () override
//
Method hashcode = new Method (this, null, TypeManager.system_int32_expr,
- Modifiers.PUBLIC | Modifiers.OVERRIDE, false, new MemberName ("GetHashCode", loc),
- Mono.CSharp.Parameters.EmptyReadOnlyParameters, GetDebuggerHiddenAttribute ());
+ Modifiers.PUBLIC | Modifiers.OVERRIDE | Modifiers.DEBUGGER_HIDDEN,
+ new MemberName ("GetHashCode", loc),
+ Mono.CSharp.ParametersCompiled.EmptyReadOnlyParameters, null);
//
// Modified FNV with good avalanche behavior and uniform
// hash ^= hash >> 17;
// hash += hash << 5;
- ToplevelBlock hashcode_block = new ToplevelBlock (loc);
+ ToplevelBlock hashcode_top = new ToplevelBlock (loc);
+ Block hashcode_block = new Block (hashcode_top);
+ hashcode_top.AddStatement (new Unchecked (hashcode_block));
+
hashcode_block.AddVariable (TypeManager.system_int32_expr, "hash", loc);
LocalVariableReference hash_variable = new LocalVariableReference (hashcode_block, "hash", loc);
hashcode_block.AddStatement (new StatementExpression (
- new Assign (hash_variable, rs_hashcode)));
+ new SimpleAssign (hash_variable, rs_hashcode)));
hashcode_block.AddStatement (new StatementExpression (
new CompoundAssign (Binary.Operator.Addition, hash_variable,
new Binary (Binary.Operator.LeftShift, hash_variable, new IntConstant (5, loc)))));
hashcode_block.AddStatement (new Return (hash_variable, loc));
- hashcode.Block = hashcode_block;
- hashcode.ResolveMembers ();
+ hashcode.Block = hashcode_top;
+ hashcode.Define ();
AddMethod (hashcode);
//
ToplevelBlock tostring_block = new ToplevelBlock (loc);
tostring_block.AddStatement (new Return (string_concat, loc));
tostring.Block = tostring_block;
- tostring.ResolveMembers ();
+ tostring.Define ();
AddMethod (tostring);
}
- public override bool DefineMembers ()
+ public override bool Define ()
{
- DefineOverrides ();
-
- return base.DefineMembers ();
- }
+ if (!base.Define ())
+ return false;
- Attributes GetDebuggerHiddenAttribute ()
- {
- return new Attributes (new Attribute (null, null,
- "System.Diagnostics.DebuggerHiddenAttribute", null, Location, false));
+ DefineOverrides ();
+ return true;
}
public override string GetSignatureForError ()