using System;
using System.Collections.Generic;
+using Mono.CompilerServices.SymbolWriter;
+using System.Diagnostics;
#if STATIC
using IKVM.Reflection;
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;
{
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
{
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) {
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)
// Unique storey ID
public readonly int ID;
- public readonly Block OriginalSourceBlock;
+ public readonly ExplicitBlock OriginalSourceBlock;
// A list of StoreyFieldPair with local field keeping parent storey instance
List<StoreyFieldPair> used_parent_storeys;
// A list of hoisted parameters
protected List<HoistedParameter> hoisted_params;
+ List<HoistedParameter> hoisted_local_params;
protected List<HoistedVariable> hoisted_locals;
// Hoisted this
// Local variable which holds this storey instance
public Expression Instance;
- public AnonymousMethodStorey (Block block, TypeDefinition parent, MemberBase host, TypeParameters tparams, string name)
+ 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, Modifiers.SEALED)
+ tparams, 0, kind)
{
OriginalSourceBlock = block;
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)
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;
+ }
- HoistedVariable var = new HoistedLocalVariable (this, local_info, GetVariableMangledName (local_info));
- local_info.HoistedVariant = var;
+ if (hoisted == null) {
+ hoisted = new HoistedLocalVariable (this, localVariable, GetVariableMangledName (localVariable));
+ localVariable.HoistedVariant = hoisted;
- if (hoisted_locals == null)
- hoisted_locals = new List<HoistedVariable> ();
+ if (hoisted_locals == null)
+ hoisted_locals = new List<HoistedVariable> ();
- hoisted_locals.Add (var);
+ hoisted_locals.Add (hoisted);
+ }
+
+ 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 (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;
- if (hoisted_params == null)
- hoisted_params = new List<HoistedParameter> (2);
+ hoisted = new HoistedParameter (storey, parameterReference);
+ parameterInfo.Parameter.HoistedVariant = hoisted;
+
+ if (storey.hoisted_params == null)
+ storey.hoisted_params = new List<HoistedParameter> ();
+
+ 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<HoistedParameter> ();
+
+ hoisted_local_params.Add (hoisted);
+ hoisted = null;
+ }
+ }
- var expr = new HoistedParameter (this, param_ref);
- param_ref.Parameter.HoistedVariant = expr;
- hoisted_params.Add (expr);
+ if (hoisted == null) {
+ hoisted = new HoistedParameter (this, parameterReference);
+ parameterInfo.Parameter.HoistedVariant = hoisted;
+
+ if (hoisted_params == null)
+ hoisted_params = new List<HoistedParameter> ();
+
+ 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)
if (Instance != null)
throw new InternalErrorException ();
- SymbolWriter.OpenCompilerGeneratedBlock (ec);
-
//
// Create an instance of this storey
//
// 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
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;
}
// TODO: Implement properly
//SymbolWriter.DefineScopeVariable (ID, Instance.Builder);
-
- SymbolWriter.CloseCompilerGeneratedBlock (ec);
}
void EmitHoistedFieldsInitialization (ResolveContext rc, EmitContext ec)
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);
}
//
- // 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));
}
ec.CurrentAnonymousMethod = ae;
}
- protected virtual void EmitHoistedParameters (EmitContext ec, IList<HoistedParameter> hoisted)
+ protected virtual void EmitHoistedParameters (EmitContext ec, List<HoistedParameter> 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);
}
}
}
public HoistedThis HoistedThis {
- get { return hoisted_this; }
+ get {
+ return hoisted_this;
+ }
+ set {
+ hoisted_this = value;
+ }
}
public IList<ExplicitBlock> ReferencesFromChildrenBlock {
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)
this.field = field;
}
+ public AnonymousMethodStorey Storey {
+ get {
+ return storey;
+ }
+ }
+
public void AddressOf (EmitContext ec, AddressOp mode)
{
GetFieldExpression (ec).AddressOf (ec, mode);
return inner_access;
}
- public abstract void EmitSymbolInfo ();
-
public void Emit (EmitContext ec, bool leave_copy)
{
GetFieldExpression (ec).Emit (ec, leave_copy);
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)
{
}
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);
- }
}
public class HoistedThis : HoistedVariable
{
}
- 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;
+ }
}
}
}
}
+ public ReportPrinter TypeInferenceReportPrinter {
+ get; set;
+ }
+
#endregion
//
{
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;
}
}
}
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;
}
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;
}
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;
}
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;
}
}
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) {
- if (type_inference.ExactInference (Parameters.Types[i], d_params.Types[i]) == 0)
+ 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;
+
return false;
+ }
}
return true;
}
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)
} 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);
}
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);
}
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",
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)
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;
}
}
}
- protected ParametersBlock block;
+ protected readonly ParametersBlock block;
public TypeSpec ReturnType;
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);
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;
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
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;
}
public override AnonymousMethodStorey Storey {
- get { return storey; }
+ get {
+ return storey;
+ }
}
#endregion
//
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;
- string name = CompilerGeneratedClass.MakeName (parent != storey ? block_name : null,
+ string name = CompilerGeneratedContainer.MakeName (parent != storey ? block_name : null,
"m", null, ec.Module.CounterAnonymousMethods++);
MemberName member_name;
//
method = DoCreateMethodHost (ec);
method.Define ();
+ method.PrepareEmit ();
}
bool is_static = (method.ModFlags & Modifiers.STATIC) != 0;
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 {
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;
// 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);
}
public override string GetSignatureForError ()
{
- return TypeManager.CSharpName (type);
+ return type.GetSignatureForError ();
}
}
//
// Anonymous type container
//
- public class AnonymousTypeClass : CompilerGeneratedClass
+ public class AnonymousTypeClass : CompilerGeneratedContainer
{
public const string ClassNamePrefix = "<>__AnonType";
public const string SignatureForError = "anonymous type";
readonly IList<AnonymousTypeParameter> parameters;
private AnonymousTypeClass (ModuleContainer parent, MemberName name, IList<AnonymousTypeParameter> parameters, Location loc)
- : base (parent, name, (parent.Evaluator != null ? Modifiers.PUBLIC : 0) | Modifiers.SEALED)
+ : base (parent, name, parent.Evaluator != null ? Modifiers.PUBLIC : Modifiers.INTERNAL)
{
this.parameters = parameters;
}
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)) {
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);
string_concat,
new Binary (Binary.Operator.Addition,
new StringConstant (Compiler.BuiltinTypes, " " + p.Name + " = ", loc),
- field_to_string,
- loc),
- loc);
+ field_to_string));
continue;
}
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
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);
//
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);
//
tostring_block.AddStatement (new Return (string_concat, loc));
tostring.Block = tostring_block;
tostring.Define ();
+ tostring.PrepareEmit ();
Members.Add (tostring);
return true;