X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fmcs%2Fanonymous.cs;h=85fa42058ca1994702bcf568b21ae44e09f196ea;hb=60979ce4a41d1be8f9d3d4d38162c0803207b4d5;hp=81154c37f46f6283568448dad22b7f5cc2039298;hpb=4e27e86d537d8487c07153581efe762dcb7a5b7c;p=mono.git diff --git a/mcs/mcs/anonymous.cs b/mcs/mcs/anonymous.cs index 81154c37f46..85fa42058ca 100644 --- a/mcs/mcs/anonymous.cs +++ b/mcs/mcs/anonymous.cs @@ -12,6 +12,8 @@ using System; using System.Collections.Generic; +using Mono.CompilerServices.SymbolWriter; +using System.Diagnostics; #if STATIC using IKVM.Reflection; @@ -23,19 +25,37 @@ using System.Reflection.Emit; namespace Mono.CSharp { - public abstract class CompilerGeneratedClass : Class + public abstract class CompilerGeneratedContainer : ClassOrStruct { - protected CompilerGeneratedClass (TypeContainer parent, MemberName name, Modifiers mod) - : base (parent, name, mod | Modifiers.COMPILER_GENERATED, null) + protected CompilerGeneratedContainer (TypeContainer parent, MemberName name, Modifiers mod) + : this (parent, name, mod, MemberKind.Class) { } + protected CompilerGeneratedContainer (TypeContainer parent, MemberName name, Modifiers mod, MemberKind kind) + : base (parent, name, null, kind) + { + Debug.Assert ((mod & Modifiers.AccessibilityMask) != 0); + + ModFlags = mod | Modifiers.COMPILER_GENERATED | Modifiers.SEALED; + spec = new TypeSpec (Kind, null, this, null, ModFlags); + } + protected void CheckMembersDefined () { if (HasMembersDefined) throw new InternalErrorException ("Helper class already defined!"); } + protected override bool DoDefineMembers () + { + if (Kind == MemberKind.Class && !IsStatic && !PartialContainer.HasInstanceConstructor) { + DefineDefaultConstructor (false); + } + + return base.DoDefineMembers (); + } + protected static MemberName MakeMemberName (MemberBase host, string name, int unique_id, TypeParameters tparams, Location loc) { string host_name = host == null ? null : host is InterfaceMemberBase ? ((InterfaceMemberBase)host).GetFullName (host.MemberName) : host.MemberName.Name; @@ -57,9 +77,17 @@ namespace Mono.CSharp { { return "<" + host + ">" + typePrefix + "__" + name + id.ToString ("X"); } + + protected override TypeSpec[] ResolveBaseTypes (out FullNamedExpression base_class) + { + base_type = Compiler.BuiltinTypes.Object; + + base_class = null; + return null; + } } - public class HoistedStoreyClass : CompilerGeneratedClass + public class HoistedStoreyClass : CompilerGeneratedContainer { public sealed class HoistedField : Field { @@ -84,8 +112,8 @@ namespace Mono.CSharp { protected TypeParameterMutator mutator; - public HoistedStoreyClass (TypeDefinition parent, MemberName name, TypeParameters tparams, Modifiers mod) - : base (parent, name, mod | Modifiers.PRIVATE) + public HoistedStoreyClass (TypeDefinition parent, MemberName name, TypeParameters tparams, Modifiers mods, MemberKind kind) + : base (parent, name, mods | Modifiers.PRIVATE, kind) { if (tparams != null) { @@ -171,7 +199,7 @@ namespace Mono.CSharp { protected override void DoEmit (EmitContext ec) { - hoisted_this.EmitHoistingAssignment (ec); + hoisted_this.EmitAssign (ec, new CompilerGeneratedThis (ec.CurrentType, loc), false, false); } protected override void CloneTo (CloneContext clonectx, Statement target) @@ -182,9 +210,8 @@ namespace Mono.CSharp { // Unique storey ID public readonly int ID; - static int unique_id; - public readonly Block OriginalSourceBlock; + public readonly ExplicitBlock OriginalSourceBlock; // A list of StoreyFieldPair with local field keeping parent storey instance List used_parent_storeys; @@ -192,6 +219,7 @@ namespace Mono.CSharp { // A list of hoisted parameters protected List hoisted_params; + List hoisted_local_params; protected List hoisted_locals; // Hoisted this @@ -200,29 +228,23 @@ namespace Mono.CSharp { // Local variable which holds this storey instance public Expression Instance; - public AnonymousMethodStorey (Block block, TypeDefinition parent, MemberBase host, TypeParameters tparams, string name) - : base (parent, MakeMemberName (host, name, unique_id, tparams, block.StartLocation), - tparams, Modifiers.SEALED) + bool initialize_hoisted_this; + + public AnonymousMethodStorey (ExplicitBlock block, TypeDefinition parent, MemberBase host, TypeParameters tparams, string name, MemberKind kind) + : base (parent, MakeMemberName (host, name, parent.Module.CounterAnonymousContainers, tparams, block.StartLocation), + tparams, 0, kind) { OriginalSourceBlock = block; - ID = unique_id++; + ID = parent.Module.CounterAnonymousContainers++; } public void AddCapturedThisField (EmitContext ec) { TypeExpr type_expr = new TypeExpression (ec.CurrentType, Location); - Field f = AddCompilerGeneratedField ("<>f__this", type_expr); - f.Define (); + Field f = AddCompilerGeneratedField ("$this", type_expr); hoisted_this = new HoistedThis (this, f); - // Inflated type instance has to be updated manually - if (Instance.Type is InflatedTypeSpec) { - var inflator = new TypeParameterInflator (this, Instance.Type, TypeParameterSpec.EmptyTypes, TypeSpec.EmptyTypes); - Instance.Type.MemberCache.AddMember (f.Spec.InflateMember (inflator)); - - inflator = new TypeParameterInflator (this, f.Parent.CurrentType, TypeParameterSpec.EmptyTypes, TypeSpec.EmptyTypes); - f.Parent.CurrentType.MemberCache.AddMember (f.Spec.InflateMember (inflator)); - } + initialize_hoisted_this = true; } public Field AddCapturedVariable (string name, TypeSpec type) @@ -282,38 +304,93 @@ namespace Mono.CSharp { used_parent_storeys.Add (new StoreyFieldPair (storey, f)); } - public void CaptureLocalVariable (ResolveContext ec, LocalVariable local_info) + public void CaptureLocalVariable (ResolveContext ec, LocalVariable localVariable) { - ec.CurrentBlock.Explicit.HasCapturedVariable = true; - if (ec.CurrentBlock.Explicit != local_info.Block.Explicit) - AddReferenceFromChildrenBlock (ec.CurrentBlock.Explicit); + if (this is StateMachine) { + if (ec.CurrentBlock.ParametersBlock != localVariable.Block.ParametersBlock) + ec.CurrentBlock.Explicit.HasCapturedVariable = true; + } else { + ec.CurrentBlock.Explicit.HasCapturedVariable = true; + } - if (local_info.HoistedVariant != null) - return; + var hoisted = localVariable.HoistedVariant; + if (hoisted != null && hoisted.Storey != this && hoisted.Storey is StateMachine) { + // TODO: It's too late the field is defined in HoistedLocalVariable ctor + hoisted.Storey.hoisted_locals.Remove (hoisted); + hoisted = null; + } + + if (hoisted == null) { + hoisted = new HoistedLocalVariable (this, localVariable, GetVariableMangledName (localVariable)); + localVariable.HoistedVariant = hoisted; - HoistedVariable var = new HoistedLocalVariable (this, local_info, GetVariableMangledName (local_info)); - local_info.HoistedVariant = var; + if (hoisted_locals == null) + hoisted_locals = new List (); - if (hoisted_locals == null) - hoisted_locals = new List (); + hoisted_locals.Add (hoisted); + } - hoisted_locals.Add (var); + if (ec.CurrentBlock.Explicit != localVariable.Block.Explicit && !(hoisted.Storey is StateMachine)) + hoisted.Storey.AddReferenceFromChildrenBlock (ec.CurrentBlock.Explicit); } - public void CaptureParameter (ResolveContext ec, ParameterReference param_ref) + public void CaptureParameter (ResolveContext ec, ParametersBlock.ParameterInfo parameterInfo, ParameterReference parameterReference) { - ec.CurrentBlock.Explicit.HasCapturedVariable = true; - AddReferenceFromChildrenBlock (ec.CurrentBlock.Explicit); + if (!(this is StateMachine)) { + ec.CurrentBlock.Explicit.HasCapturedVariable = true; + } - if (param_ref.GetHoistedVariable (ec) != null) - return; + var hoisted = parameterInfo.Parameter.HoistedVariant; - if (hoisted_params == null) - hoisted_params = new List (2); + if (parameterInfo.Block.StateMachine != null) { + // + // Another storey in same block exists but state machine does not + // have parameter captured. We need to add it there as well to + // proxy parameter value correctly. + // + if (hoisted == null && parameterInfo.Block.StateMachine != this) { + var storey = parameterInfo.Block.StateMachine; - var expr = new HoistedParameter (this, param_ref); - param_ref.Parameter.HoistedVariant = expr; - hoisted_params.Add (expr); + hoisted = new HoistedParameter (storey, parameterReference); + parameterInfo.Parameter.HoistedVariant = hoisted; + + if (storey.hoisted_params == null) + storey.hoisted_params = new List (); + + storey.hoisted_params.Add (hoisted); + } + + // + // Lift captured parameter from value type storey to reference type one. Otherwise + // any side effects would be done on a copy + // + if (hoisted != null && hoisted.Storey != this && hoisted.Storey is StateMachine) { + if (hoisted_local_params == null) + hoisted_local_params = new List (); + + hoisted_local_params.Add (hoisted); + hoisted = null; + } + } + + if (hoisted == null) { + hoisted = new HoistedParameter (this, parameterReference); + parameterInfo.Parameter.HoistedVariant = hoisted; + + if (hoisted_params == null) + hoisted_params = new List (); + + hoisted_params.Add (hoisted); + } + + // + // Register link between current block and parameter storey. It will + // be used when setting up storey definition to deploy storey reference + // when parameters are used from multiple blocks + // + if (ec.CurrentBlock.Explicit != parameterInfo.Block) { + hoisted.Storey.AddReferenceFromChildrenBlock (ec.CurrentBlock.Explicit); + } } TypeExpr CreateStoreyTypeExpression (EmitContext ec) @@ -397,8 +474,6 @@ namespace Mono.CSharp { if (Instance != null) throw new InternalErrorException (); - SymbolWriter.OpenCompilerGeneratedBlock (ec); - // // Create an instance of this storey // @@ -412,7 +487,7 @@ namespace Mono.CSharp { // When the current context is async (or iterator) lift local storey // instantiation to the currect storey // - if (ec.CurrentAnonymousMethod is StateMachineInitializer) { + if (ec.CurrentAnonymousMethod is StateMachineInitializer && (block.HasYield || block.HasAwait)) { // // Unfortunately, normal capture mechanism could not be used because we are // too late in the pipeline and standart assign cannot be used either due to @@ -427,11 +502,14 @@ namespace Mono.CSharp { var fexpr = new FieldExpr (field, Location); fexpr.InstanceExpression = new CompilerGeneratedThis (ec.CurrentType, Location); fexpr.EmitAssign (ec, source, false, false); - Instance = fexpr; } else { var local = TemporaryVariableReference.Create (source.Type, block, Location); - local.EmitAssign (ec, source); + if (source.Type.IsStruct) { + local.LocalInfo.CreateBuilder (ec); + } else { + local.EmitAssign (ec, source); + } Instance = local; } @@ -440,8 +518,6 @@ namespace Mono.CSharp { // TODO: Implement properly //SymbolWriter.DefineScopeVariable (ID, Instance.Builder); - - SymbolWriter.CloseCompilerGeneratedBlock (ec); } void EmitHoistedFieldsInitialization (ResolveContext rc, EmitContext ec) @@ -462,6 +538,7 @@ namespace Mono.CSharp { FieldExpr f_set_expr = new FieldExpr (fs, Location); f_set_expr.InstanceExpression = instace_expr; + // TODO: CompilerAssign expression SimpleAssign a = new SimpleAssign (f_set_expr, sf.Storey.GetStoreyInstanceExpression (ec)); if (a.Resolve (rc) != null) a.EmitStatement (ec); @@ -469,10 +546,10 @@ namespace Mono.CSharp { } // - // Define hoisted `this' in top-level storey only + // Initialize hoisted `this' only once, everywhere else will be + // referenced indirectly // - if (OriginalSourceBlock.Explicit.HasCapturedThis && !(Parent is AnonymousMethodStorey)) { - AddCapturedThisField (ec); + if (initialize_hoisted_this) { rc.CurrentBlock.AddScopeStatement (new ThisInitializer (hoisted_this)); } @@ -489,36 +566,24 @@ namespace Mono.CSharp { ec.CurrentAnonymousMethod = ae; } - protected virtual void EmitHoistedParameters (EmitContext ec, IList hoisted) + protected virtual void EmitHoistedParameters (EmitContext ec, List hoisted) { foreach (HoistedParameter hp in hoisted) { - hp.EmitHoistingAssignment (ec); - } - } - - public override void Emit () - { - base.Emit (); - - SymbolWriter.DefineAnonymousScope (ID); - - if (hoisted_this != null) - hoisted_this.EmitSymbolInfo (); - - if (hoisted_locals != null) { - foreach (HoistedVariable local in hoisted_locals) - local.EmitSymbolInfo (); - } - - if (hoisted_params != null) { - foreach (HoistedParameter param in hoisted_params) - param.EmitSymbolInfo (); - } + if (hp == null) + continue; - if (used_parent_storeys != null) { - foreach (StoreyFieldPair sf in used_parent_storeys) { - SymbolWriter.DefineCapturedScope (ID, sf.Storey.ID, sf.Field.Name); + // + // Parameters could be proxied via local fields for value type storey + // + if (hoisted_local_params != null) { + var local_param = hoisted_local_params.Find (l => l.Parameter.Parameter == hp.Parameter.Parameter); + var source = new FieldExpr (local_param.Field, Location); + source.InstanceExpression = new CompilerGeneratedThis (CurrentType, Location); + hp.EmitAssign (ec, source, false, false); + continue; } + + hp.EmitHoistingAssignment (ec); } } @@ -590,17 +655,17 @@ namespace Mono.CSharp { } public HoistedThis HoistedThis { - get { return hoisted_this; } + get { + return hoisted_this; + } + set { + hoisted_this = value; + } } public IList ReferencesFromChildrenBlock { get { return children_references; } } - - public static void Reset () - { - unique_id = 0; - } } public abstract class HoistedVariable @@ -639,7 +704,7 @@ namespace Mono.CSharp { public override void Emit (EmitContext ec) { ResolveContext rc = new ResolveContext (ec.MemberContext); - Expression e = hv.GetFieldExpression (ec).CreateExpressionTree (rc); + Expression e = hv.GetFieldExpression (ec).CreateExpressionTree (rc, false); // This should never fail e = e.Resolve (rc); if (e != null) @@ -663,6 +728,12 @@ namespace Mono.CSharp { this.field = field; } + public AnonymousMethodStorey Storey { + get { + return storey; + } + } + public void AddressOf (EmitContext ec, AddressOp mode) { GetFieldExpression (ec).AddressOf (ec, mode); @@ -731,8 +802,6 @@ namespace Mono.CSharp { return inner_access; } - public abstract void EmitSymbolInfo (); - public void Emit (EmitContext ec, bool leave_copy) { GetFieldExpression (ec).Emit (ec, leave_copy); @@ -746,10 +815,10 @@ namespace Mono.CSharp { public class HoistedParameter : HoistedVariable { - sealed class HoistedFieldAssign : Assign + sealed class HoistedFieldAssign : CompilerAssign { public HoistedFieldAssign (Expression target, Expression source) - : base (target, source, source.Location) + : base (target, source, target.Location) { } @@ -777,52 +846,44 @@ namespace Mono.CSharp { this.parameter = hp.parameter; } + #region Properties + + public Field Field { + get { + return field; + } + } + + public bool IsAssigned { get; set; } + + public ParameterReference Parameter { + get { + return parameter; + } + } + + #endregion + public void EmitHoistingAssignment (EmitContext ec) { // // Remove hoisted redirection to emit assignment from original parameter // - HoistedVariable temp = parameter.Parameter.HoistedVariant; + var temp = parameter.Parameter.HoistedVariant; parameter.Parameter.HoistedVariant = null; - Assign a = new HoistedFieldAssign (GetFieldExpression (ec), parameter); - if (a.Resolve (new ResolveContext (ec.MemberContext)) != null) - a.EmitStatement (ec); + var a = new HoistedFieldAssign (GetFieldExpression (ec), parameter); + a.EmitStatement (ec); parameter.Parameter.HoistedVariant = temp; } - - public override void EmitSymbolInfo () - { - SymbolWriter.DefineCapturedParameter (storey.ID, field.Name, field.Name); - } - - public Field Field { - get { return field; } - } } class HoistedLocalVariable : HoistedVariable { - readonly string name; - public HoistedLocalVariable (AnonymousMethodStorey storey, LocalVariable local, string name) : base (storey, name, local.Type) { - this.name = local.Name; - } - - // - // For compiler generated local variables - // - public HoistedLocalVariable (AnonymousMethodStorey storey, Field field) - : base (storey, field) - { - } - - public override void EmitSymbolInfo () - { - SymbolWriter.DefineCapturedLocal (storey.ID, name, field.Name); } } @@ -833,20 +894,10 @@ namespace Mono.CSharp { { } - public void EmitHoistingAssignment (EmitContext ec) - { - SimpleAssign a = new SimpleAssign (GetFieldExpression (ec), new CompilerGeneratedThis (ec.CurrentType, field.Location)); - if (a.Resolve (new ResolveContext (ec.MemberContext)) != null) - a.EmitStatement (ec); - } - - public override void EmitSymbolInfo () - { - SymbolWriter.DefineCapturedThis (storey.ID, field.Name); - } - public Field Field { - get { return field; } + get { + return field; + } } } @@ -914,6 +965,10 @@ namespace Mono.CSharp { } } + public ReportPrinter TypeInferenceReportPrinter { + get; set; + } + #endregion // @@ -924,7 +979,13 @@ namespace Mono.CSharp { { using (ec.With (ResolveContext.Options.InferReturnType, false)) { using (ec.Set (ResolveContext.Options.ProbingMode)) { - return Compatible (ec, delegate_type) != null; + var prev = ec.Report.SetPrinter (TypeInferenceReportPrinter ?? new NullReportPrinter ()); + + var res = Compatible (ec, delegate_type) != null; + + ec.Report.SetPrinter (prev); + + return res; } } } @@ -940,12 +1001,12 @@ namespace Mono.CSharp { return delegate_type; ec.Report.Error (835, loc, "Cannot convert `{0}' to an expression tree of non-delegate type `{1}'", - GetSignatureForError (), TypeManager.CSharpName (delegate_type)); + GetSignatureForError (), delegate_type.GetSignatureForError ()); return null; } ec.Report.Error (1660, loc, "Cannot convert `{0}' to non-delegate type `{1}'", - GetSignatureForError (), TypeManager.CSharpName (delegate_type)); + GetSignatureForError (), delegate_type.GetSignatureForError ()); return null; } @@ -957,7 +1018,7 @@ namespace Mono.CSharp { if (!ec.IsInProbingMode) ec.Report.Error (1661, loc, "Cannot convert `{0}' to delegate type `{1}' since there is a parameter mismatch", - GetSignatureForError (), TypeManager.CSharpName (delegate_type)); + GetSignatureForError (), delegate_type.GetSignatureForError ()); return false; } @@ -969,7 +1030,7 @@ namespace Mono.CSharp { return false; ec.Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments", - TypeManager.CSharpName (delegate_type), Parameters.Count.ToString ()); + delegate_type.GetSignatureForError (), Parameters.Count.ToString ()); return false; } @@ -1009,8 +1070,8 @@ namespace Mono.CSharp { ec.Report.Error (1678, loc, "Parameter `{0}' is declared as type `{1}' but should be `{2}'", (i+1).ToString (), - TypeManager.CSharpName (Parameters.Types [i]), - TypeManager.CSharpName (invoke_pd.Types [i])); + Parameters.Types [i].GetSignatureForError (), + invoke_pd.Types [i].GetSignatureForError ()); error = true; } } @@ -1039,17 +1100,21 @@ namespace Mono.CSharp { if (d_params.Count != Parameters.Count) return false; + var ptypes = Parameters.Types; + var dtypes = d_params.Types; for (int i = 0; i < Parameters.Count; ++i) { - TypeSpec itype = d_params.Types [i]; - if (!TypeManager.IsGenericParameter (itype)) { - if (!TypeManager.HasElementType (itype)) + if (type_inference.ExactInference (ptypes[i], dtypes[i]) == 0) { + // + // Continue when 0 (quick path) does not mean inference failure. Checking for + // same type handles cases like int -> int + // + if (ptypes[i] == dtypes[i]) continue; - - if (!TypeManager.IsGenericParameter (TypeManager.GetElementType (itype))) - continue; + + return false; } - type_inference.ExactInference (Parameters.Types [i], itype); } + return true; } @@ -1064,16 +1129,23 @@ namespace Mono.CSharp { } using (ec.Set (ResolveContext.Options.ProbingMode | ResolveContext.Options.InferReturnType)) { - var body = CompatibleMethodBody (ec, tic, InternalType.Arglist, delegate_type); - if (body != null) { - if (Block.IsAsync) { - AsyncInitializer.Create (ec, body.Block, body.Parameters, ec.CurrentMemberDefinition.Parent.PartialContainer, null, loc); - } + ReportPrinter prev; + if (TypeInferenceReportPrinter != null) { + prev = ec.Report.SetPrinter (TypeInferenceReportPrinter); + } else { + prev = null; + } + var body = CompatibleMethodBody (ec, tic, null, delegate_type); + if (body != null) { am = body.Compatible (ec, body); } else { am = null; } + + if (TypeInferenceReportPrinter != null) { + ec.Report.SetPrinter (prev); + } } if (am == null) @@ -1141,6 +1213,10 @@ namespace Mono.CSharp { } else { int errors = ec.Report.Errors; + if (Block.IsAsync) { + ec.Report.Error (1989, loc, "Async lambda expressions cannot be converted to expression trees"); + } + using (ec.Set (ResolveContext.Options.ExpressionTreeConversion)) { am = body.Compatible (ec); } @@ -1152,22 +1228,23 @@ namespace Mono.CSharp { am = CreateExpressionTree (ec, delegate_type); } } else { - if (Block.IsAsync) { - var rt = body.ReturnType; - if (rt.Kind != MemberKind.Void && - rt != ec.Module.PredefinedTypes.Task.TypeSpec && - !rt.IsGenericTask) { - ec.Report.Error (4010, loc, "Cannot convert async {0} to delegate type `{1}'", - GetSignatureForError (), type.GetSignatureForError ()); - } + am = body.Compatible (ec); - AsyncInitializer.Create (ec, body.Block, body.Parameters, ec.CurrentMemberDefinition.Parent.PartialContainer, rt, loc); + if (body.DirectMethodGroupConversion != null) { + var errors_printer = new SessionReportPrinter (); + var old = ec.Report.SetPrinter (errors_printer); + var expr = new ImplicitDelegateCreation (delegate_type, body.DirectMethodGroupConversion, loc) { + AllowSpecialMethodsInvocation = true + }.Resolve (ec); + ec.Report.SetPrinter (old); + if (expr != null && errors_printer.ErrorsCount == 0) + am = expr; } - - am = body.Compatible (ec); } } catch (CompletionResult) { throw; + } catch (FatalException) { + throw; } catch (Exception e) { throw new InternalErrorException (e, loc); } @@ -1202,7 +1279,7 @@ namespace Mono.CSharp { for (int i = 0; i < delegate_parameters.Count; i++) { Parameter.Modifier i_mod = delegate_parameters.FixedParameters [i].ModFlags; - if (i_mod == Parameter.Modifier.OUT) { + if ((i_mod & Parameter.Modifier.OUT) != 0) { if (!ec.IsInProbingMode) { ec.Report.Error (1688, loc, "Cannot convert anonymous method block without a parameter list to delegate type `{0}' because it has one or more `out' parameters", @@ -1289,7 +1366,19 @@ namespace Mono.CSharp { ParametersBlock b = ec.IsInProbingMode ? (ParametersBlock) Block.PerformClone () : Block; - return CompatibleMethodFactory (return_type, delegate_type, p, b); + if (b.IsAsync) { + var rt = return_type; + if (rt != null && rt.Kind != MemberKind.Void && rt != ec.Module.PredefinedTypes.Task.TypeSpec && !rt.IsGenericTask) { + ec.Report.Error (4010, loc, "Cannot convert async {0} to delegate type `{1}'", + GetSignatureForError (), delegate_type.GetSignatureForError ()); + + return null; + } + + b = b.ConvertToAsyncTask (ec, ec.CurrentMemberDefinition.Parent.PartialContainer, p, return_type, delegate_type, loc); + } + + return CompatibleMethodFactory (return_type ?? InternalType.ErrorType, delegate_type, p, b); } protected virtual AnonymousMethodBody CompatibleMethodFactory (TypeSpec return_type, TypeSpec delegate_type, ParametersCompiled p, ParametersBlock b) @@ -1319,26 +1408,24 @@ namespace Mono.CSharp { { public readonly AnonymousExpression AnonymousMethod; public readonly AnonymousMethodStorey Storey; - readonly string RealName; public AnonymousMethodMethod (TypeDefinition parent, AnonymousExpression am, AnonymousMethodStorey storey, TypeExpr return_type, - Modifiers mod, string real_name, MemberName name, + Modifiers mod, MemberName name, ParametersCompiled parameters) : base (parent, return_type, mod | Modifiers.COMPILER_GENERATED, name, parameters, null) { this.AnonymousMethod = am; this.Storey = storey; - this.RealName = real_name; Parent.PartialContainer.Members.Add (this); Block = new ToplevelBlock (am.block, parameters); } - public override EmitContext CreateEmitContext (ILGenerator ig) + public override EmitContext CreateEmitContext (ILGenerator ig, SourceMethodBuilder sourceMethod) { - EmitContext ec = new EmitContext (this, ig, ReturnType); + EmitContext ec = new EmitContext (this, ig, ReturnType, sourceMethod); ec.CurrentAnonymousMethod = AnonymousMethod; return ec; } @@ -1374,14 +1461,9 @@ namespace Mono.CSharp { base.Emit (); } - - public override void EmitExtraSymbolInfo (SourceMethod source) - { - source.SetRealMethodName (RealName); - } } - protected ParametersBlock block; + protected readonly ParametersBlock block; public TypeSpec ReturnType; @@ -1396,6 +1478,15 @@ namespace Mono.CSharp { public abstract bool IsIterator { get; } public abstract AnonymousMethodStorey Storey { get; } + // + // The block that makes up the body for the anonymous method + // + public ParametersBlock Block { + get { + return block; + } + } + public AnonymousExpression Compatible (ResolveContext ec) { return Compatible (ec, this); @@ -1410,24 +1501,15 @@ namespace Mono.CSharp { BlockContext aec = new BlockContext (ec, block, ReturnType); aec.CurrentAnonymousMethod = ae; - ResolveContext.Options flags = 0; - var am = this as AnonymousMethodBody; if (ec.HasSet (ResolveContext.Options.InferReturnType) && am != null) { am.ReturnTypeInference = new TypeInferenceContext (); } - if (ec.IsInProbingMode) - flags |= ResolveContext.Options.ProbingMode; - - if (ec.HasSet (ResolveContext.Options.FieldInitializerScope)) - flags |= ResolveContext.Options.FieldInitializerScope; - - if (ec.HasSet (ResolveContext.Options.ExpressionTreeConversion)) - flags |= ResolveContext.Options.ExpressionTreeConversion; - - aec.Set (flags); + var bc = ec as BlockContext; + if (bc != null) + aec.FlowOffset = bc.FlowOffset; var errors = ec.Report.Errors; @@ -1469,16 +1551,6 @@ namespace Mono.CSharp { b = b.Parent == null ? null : b.Parent.Explicit; } while (b != null); } - - // - // The block that makes up the body for the anonymous method - // - public ParametersBlock Block { - get { - return block; - } - } - } public class AnonymousMethodBody : AnonymousExpression @@ -1491,8 +1563,6 @@ namespace Mono.CSharp { string block_name; TypeInferenceContext return_inference; - static int unique_id; - public AnonymousMethodBody (ParametersCompiled parameters, ParametersBlock block, TypeSpec return_type, TypeSpec delegate_type, Location loc) @@ -1508,6 +1578,14 @@ namespace Mono.CSharp { get { return "anonymous method"; } } + // + // Method-group instance for lambdas which can be replaced with + // simple method group call + // + public MethodGroupExpr DirectMethodGroupConversion { + get; set; + } + public override bool IsIterator { get { return false; @@ -1530,7 +1608,9 @@ namespace Mono.CSharp { } public override AnonymousMethodStorey Storey { - get { return storey; } + get { + return storey; + } } #endregion @@ -1568,21 +1648,54 @@ namespace Mono.CSharp { // Modifiers modifiers; - if (Block.HasCapturedVariable || Block.HasCapturedThis) { - storey = FindBestMethodStorey (); + TypeDefinition parent = null; + + var src_block = Block.Original.Explicit; + if (src_block.HasCapturedVariable || src_block.HasCapturedThis) { + parent = storey = FindBestMethodStorey (); + + if (storey == null) { + var top_block = src_block.ParametersBlock.TopBlock; + var sm = top_block.StateMachine; + + if (src_block.HasCapturedThis) { + // + // Remove hoisted 'this' request when simple instance method is + // enough (no hoisted variables only 'this') + // + if (src_block.ParametersBlock.StateMachine == null) + top_block.RemoveThisReferenceFromChildrenBlock (src_block); + + // + // Special case where parent class is used to emit instance method + // because currect storey is of value type (async host). We cannot + // use ldftn on non-boxed instances either to share mutated state + // + if (sm != null && sm.Kind == MemberKind.Struct) { + parent = sm.Parent.PartialContainer; + } + } + + // + // For iterators we can host everything in one class + // + if (sm is IteratorStorey) + parent = storey = sm; + } + modifiers = storey != null ? Modifiers.INTERNAL : Modifiers.PRIVATE; } else { if (ec.CurrentAnonymousMethod != null) - storey = ec.CurrentAnonymousMethod.Storey; + parent = storey = ec.CurrentAnonymousMethod.Storey; modifiers = Modifiers.STATIC | Modifiers.PRIVATE; } - var parent = storey != null ? storey : ec.CurrentTypeDefinition.Parent.PartialContainer; + if (parent == null) + parent = ec.CurrentTypeDefinition.Parent.PartialContainer; - MemberCore mc = ec.MemberContext as MemberCore; - string name = CompilerGeneratedClass.MakeName (parent != storey ? block_name : null, - "m", null, unique_id++); + string name = CompilerGeneratedContainer.MakeName (parent != storey ? block_name : null, + "m", null, ec.Module.CounterAnonymousMethods++); MemberName member_name; if (storey == null && ec.CurrentTypeParameters != null) { @@ -1598,13 +1711,9 @@ namespace Mono.CSharp { member_name = new MemberName (name, Location); } - string real_name = String.Format ( - "{0}~{1}{2}", mc.GetSignatureForError (), GetSignatureForError (), - parameters.GetSignatureForError ()); - return new AnonymousMethodMethod (parent, this, storey, new TypeExpression (ReturnType, Location), modifiers, - real_name, member_name, parameters); + member_name, parameters); } protected override Expression DoResolve (ResolveContext ec) @@ -1629,6 +1738,7 @@ namespace Mono.CSharp { // method = DoCreateMethodHost (ec); method.Define (); + method.PrepareEmit (); } bool is_static = (method.ModFlags & Modifiers.STATIC) != 0; @@ -1643,7 +1753,7 @@ namespace Mono.CSharp { am_cache = new Field (parent, new TypeExpression (cache_type, loc), Modifiers.STATIC | Modifiers.PRIVATE | Modifiers.COMPILER_GENERATED, - new MemberName (CompilerGeneratedClass.MakeName (null, "f", "am$cache", id), loc), null); + new MemberName (CompilerGeneratedContainer.MakeName (null, "f", "am$cache", id), loc), null); am_cache.Define (); parent.AddField (am_cache); } else { @@ -1683,10 +1793,22 @@ namespace Mono.CSharp { ec.EmitNull (); } else if (storey != null) { Expression e = storey.GetStoreyInstanceExpression (ec).Resolve (new ResolveContext (ec.MemberContext)); - if (e != null) + if (e != null) { e.Emit (ec); + } } else { ec.EmitThis (); + + // + // Special case for value type storey where this is not lifted but + // droped off to parent class + // + for (var b = Block.Parent; b != null; b = b.Parent) { + if (b.ParametersBlock.StateMachine != null) { + ec.Emit (OpCodes.Ldfld, b.ParametersBlock.StateMachine.HoistedThis.Field.Spec); + break; + } + } } var delegate_method = method.Spec; @@ -1697,9 +1819,7 @@ namespace Mono.CSharp { // 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.Mutator != null) { + if (ec.IsAnonymousStoreyMutateRequired) { t = storey.Mutator.Mutate (t); } @@ -1745,35 +1865,29 @@ namespace Mono.CSharp { public override string GetSignatureForError () { - return TypeManager.CSharpName (type); - } - - public static void Reset () - { - unique_id = 0; + return type.GetSignatureForError (); } } // // Anonymous type container // - public class AnonymousTypeClass : CompilerGeneratedClass + public class AnonymousTypeClass : CompilerGeneratedContainer { - static int types_counter; public const string ClassNamePrefix = "<>__AnonType"; public const string SignatureForError = "anonymous type"; readonly IList parameters; - private AnonymousTypeClass (TypeContainer parent, MemberName name, IList parameters, Location loc) - : base (parent, name, (parent.Module.Evaluator != null ? Modifiers.PUBLIC : 0) | Modifiers.SEALED) + private AnonymousTypeClass (ModuleContainer parent, MemberName name, IList parameters, Location loc) + : base (parent, name, parent.Evaluator != null ? Modifiers.PUBLIC : Modifiers.INTERNAL) { this.parameters = parameters; } public static AnonymousTypeClass Create (TypeContainer parent, IList parameters, Location loc) { - string name = ClassNamePrefix + types_counter++; + string name = ClassNamePrefix + parent.Module.CounterAnonymousTypes++; ParametersCompiled all_parameters; TypeParameters tparams = null; @@ -1819,13 +1933,13 @@ namespace Mono.CSharp { c.Block = new ToplevelBlock (parent.Module.Compiler, c.ParameterInfo, loc); // - // Create fields and contructor body with field initialization + // Create fields and constructor body with field initialization // bool error = false; for (int i = 0; i < parameters.Count; ++i) { AnonymousTypeParameter p = parameters [i]; - Field f = new Field (a_type, t_args [i], Modifiers.PRIVATE | Modifiers.READONLY, + Field f = new Field (a_type, t_args [i], Modifiers.PRIVATE | Modifiers.READONLY | Modifiers.DEBUGGER_HIDDEN, new MemberName ("<" + p.Name + ">", p.Location), null); if (!a_type.AddField (f)) { @@ -1855,11 +1969,6 @@ namespace Mono.CSharp { return a_type; } - public static void Reset () - { - types_counter = 0; - } - protected override bool DoDefineMembers () { if (!base.DoDefineMembers ()) @@ -1927,11 +2036,11 @@ namespace Mono.CSharp { IntConstant FNV_prime = new IntConstant (Compiler.BuiltinTypes, 16777619, loc); rs_hashcode = new Binary (Binary.Operator.Multiply, - new Binary (Binary.Operator.ExclusiveOr, rs_hashcode, field_hashcode, loc), - FNV_prime, loc); + new Binary (Binary.Operator.ExclusiveOr, rs_hashcode, field_hashcode), + FNV_prime); Expression field_to_string = new Conditional (new BooleanExpression (new Binary (Binary.Operator.Inequality, - new MemberAccess (new This (f.Location), f.Name), new NullLiteral (loc), loc)), + 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 (Compiler.BuiltinTypes, string.Empty, loc), loc); @@ -1942,9 +2051,7 @@ namespace Mono.CSharp { string_concat, new Binary (Binary.Operator.Addition, new StringConstant (Compiler.BuiltinTypes, " " + p.Name + " = ", loc), - field_to_string, - loc), - loc); + field_to_string)); continue; } @@ -1954,18 +2061,15 @@ namespace Mono.CSharp { string_concat = new Binary (Binary.Operator.Addition, new Binary (Binary.Operator.Addition, string_concat, - new StringConstant (Compiler.BuiltinTypes, ", " + p.Name + " = ", loc), - loc), - field_to_string, - loc); + new StringConstant (Compiler.BuiltinTypes, ", " + p.Name + " = ", loc)), + field_to_string); - rs_equals = new Binary (Binary.Operator.LogicalAnd, rs_equals, field_equal, loc); + rs_equals = new Binary (Binary.Operator.LogicalAnd, rs_equals, field_equal); } string_concat = new Binary (Binary.Operator.Addition, string_concat, - new StringConstant (Compiler.BuiltinTypes, " }", loc), - loc); + new StringConstant (Compiler.BuiltinTypes, " }", loc)); // // Equals (object obj) override @@ -1976,13 +2080,14 @@ namespace Mono.CSharp { new As (equals_block.GetParameterReference (0, loc), current_type, loc), loc))); - Expression equals_test = new Binary (Binary.Operator.Inequality, other_variable, new NullLiteral (loc), loc); + Expression equals_test = new Binary (Binary.Operator.Inequality, other_variable, new NullLiteral (loc)); if (rs_equals != null) - equals_test = new Binary (Binary.Operator.LogicalAnd, equals_test, rs_equals, loc); + equals_test = new Binary (Binary.Operator.LogicalAnd, equals_test, rs_equals); equals_block.AddStatement (new Return (equals_test, loc)); equals.Block = equals_block; equals.Define (); + equals.PrepareEmit (); Members.Add (equals); // @@ -2020,23 +2125,24 @@ namespace Mono.CSharp { var hash_variable = new LocalVariableReference (li_hash, loc); hashcode_block.AddStatement (new StatementExpression ( new CompoundAssign (Binary.Operator.Addition, hash_variable, - new Binary (Binary.Operator.LeftShift, hash_variable, new IntConstant (Compiler.BuiltinTypes, 13, loc), loc), loc))); + new Binary (Binary.Operator.LeftShift, hash_variable, new IntConstant (Compiler.BuiltinTypes, 13, loc))))); hashcode_block.AddStatement (new StatementExpression ( new CompoundAssign (Binary.Operator.ExclusiveOr, hash_variable, - new Binary (Binary.Operator.RightShift, hash_variable, new IntConstant (Compiler.BuiltinTypes, 7, loc), loc), loc))); + new Binary (Binary.Operator.RightShift, hash_variable, new IntConstant (Compiler.BuiltinTypes, 7, loc))))); hashcode_block.AddStatement (new StatementExpression ( new CompoundAssign (Binary.Operator.Addition, hash_variable, - new Binary (Binary.Operator.LeftShift, hash_variable, new IntConstant (Compiler.BuiltinTypes, 3, loc), loc), loc))); + new Binary (Binary.Operator.LeftShift, hash_variable, new IntConstant (Compiler.BuiltinTypes, 3, loc))))); hashcode_block.AddStatement (new StatementExpression ( new CompoundAssign (Binary.Operator.ExclusiveOr, hash_variable, - new Binary (Binary.Operator.RightShift, hash_variable, new IntConstant (Compiler.BuiltinTypes, 17, loc), loc), loc))); + new Binary (Binary.Operator.RightShift, hash_variable, new IntConstant (Compiler.BuiltinTypes, 17, loc))))); hashcode_block.AddStatement (new StatementExpression ( new CompoundAssign (Binary.Operator.Addition, hash_variable, - new Binary (Binary.Operator.LeftShift, hash_variable, new IntConstant (Compiler.BuiltinTypes, 5, loc), loc), loc))); + new Binary (Binary.Operator.LeftShift, hash_variable, new IntConstant (Compiler.BuiltinTypes, 5, loc))))); hashcode_block.AddStatement (new Return (hash_variable, loc)); hashcode.Block = hashcode_top; hashcode.Define (); + hashcode.PrepareEmit (); Members.Add (hashcode); // @@ -2047,6 +2153,7 @@ namespace Mono.CSharp { tostring_block.AddStatement (new Return (string_concat, loc)); tostring.Block = tostring_block; tostring.Define (); + tostring.PrepareEmit (); Members.Add (tostring); return true; @@ -2057,6 +2164,11 @@ namespace Mono.CSharp { return SignatureForError; } + public override CompilationSourceFile GetCompilationSourceFile () + { + return null; + } + public IList Parameters { get { return parameters;