//
// Copyright 2001, 2002, 2003 Ximian, Inc.
// Copyright 2003-2008 Novell, Inc.
+// Copyright 2011 Xamarin Inc.
//
//
set { type = value; }
}
- public Location Location {
- get { return loc; }
+ public virtual bool IsSideEffectFree {
+ get {
+ return false;
+ }
}
- public virtual string GetSignatureForError ()
- {
- return type.GetDefinition ().GetSignatureForError ();
+ public Location Location {
+ get { return loc; }
}
public virtual bool IsNull {
}
}
+ //
+ // Returns true when the expression during Emit phase breaks stack
+ // by using await expression
+ //
+ public virtual bool ContainsEmitWithAwait ()
+ {
+ return false;
+ }
+
/// <summary>
/// Performs semantic analysis on the Expression
/// </summary>
// This is used if the expression should be resolved as a type or namespace name.
// the default implementation fails.
//
- public virtual FullNamedExpression ResolveAsTypeStep (IMemberContext rc, bool silent)
+ public virtual TypeSpec ResolveAsType (IMemberContext mc)
{
- if (!silent) {
- ResolveContext ec = new ResolveContext (rc);
- Expression e = Resolve (ec);
- if (e != null)
- e.Error_UnexpectedKind (ec, ResolveFlags.Type, loc);
- }
+ ResolveContext ec = new ResolveContext (mc);
+ Expression e = Resolve (ec);
+ if (e != null)
+ e.Error_UnexpectedKind (ec, ResolveFlags.Type, loc);
return null;
}
- //
- // This is used to resolve the expression as a type, a null
- // value will be returned if the expression is not a type
- // reference
- //
- public virtual TypeExpr ResolveAsTypeTerminal (IMemberContext ec , bool silent)
- {
- // FIXME: THIS IS TOO SLOW and it should not be needed either
- int errors = ec.Module.Compiler.Report.Errors;
-
- FullNamedExpression fne = ResolveAsTypeStep (ec, silent);
-
- if (fne == null)
- return null;
-
- TypeExpr te = fne as TypeExpr;
- if (te == null) {
- if (!silent && errors == ec.Module.Compiler.Report.Errors)
- fne.Error_UnexpectedKind (ec.Module.Compiler.Report, null, "type", loc);
- return null;
- }
-
- if (!te.type.IsAccessible (ec)) {
- ec.Module.Compiler.Report.SymbolRelatedToPreviousError (te.Type);
- ErrorIsInaccesible (ec, te.Type.GetSignatureForError (), loc);
- }
-
- te.loc = loc;
-
- var dep = te.type.GetMissingDependencies ();
- if (dep != null) {
- ImportedTypeDefinition.Error_MissingDependency (ec, dep, loc);
- }
-
- //
- // Obsolete checks cannot be done when resolving base context as they
- // require type dependecies to be set but we are just resolving them
- //
- if (!silent && !(ec is TypeContainer.BaseContext)) {
- ObsoleteAttribute obsolete_attr = te.Type.GetAttributeObsolete ();
- if (obsolete_attr != null && !ec.IsObsolete) {
- AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location, ec.Module.Compiler.Report);
- }
- }
-
- return te;
- }
-
public static void ErrorIsInaccesible (IMemberContext rc, string member, Location loc)
{
rc.Module.Compiler.Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", member);
string from_type = type.GetSignatureForError ();
string to_type = target.GetSignatureForError ();
if (from_type == to_type) {
- from_type = string.Format ("{0} [{1}]", from_type, type.MemberDefinition.DeclaringAssembly.FullName);
- to_type = string.Format ("{0} [{1}]", to_type, target.MemberDefinition.DeclaringAssembly.FullName);
+ from_type = type.GetSignatureForErrorIncludingAssemblyName ();
+ to_type = target.GetSignatureForErrorIncludingAssemblyName ();
}
if (expl) {
}
}
- public void Error_TypeArgumentsCannotBeUsed (Report report, Location loc, MemberSpec member, int arity)
+ public void Error_TypeArgumentsCannotBeUsed (IMemberContext context, MemberSpec member, int arity, Location loc)
{
// Better message for possible generic expressions
if (member != null && (member.Kind & MemberKind.GenericMask) != 0) {
+ var report = context.Module.Compiler.Report;
report.SymbolRelatedToPreviousError (member);
if (member is TypeSpec)
member = ((TypeSpec) member).GetDefinition ();
name, member.GetSignatureForError ());
}
} else {
- Error_TypeArgumentsCannotBeUsed (report, ExprClassName, GetSignatureForError (), loc);
+ Error_TypeArgumentsCannotBeUsed (context, ExprClassName, GetSignatureForError (), loc);
}
}
- public void Error_TypeArgumentsCannotBeUsed (Report report, string exprType, string name, Location loc)
+ public void Error_TypeArgumentsCannotBeUsed (IMemberContext context, string exprType, string name, Location loc)
{
- report.Error (307, loc, "The {0} `{1}' cannot be used with type arguments",
+ context.Module.Compiler.Report.Error (307, loc, "The {0} `{1}' cannot be used with type arguments",
exprType, name);
}
TypeManager.CSharpName (type), name);
}
- protected static void Error_ValueAssignment (ResolveContext ec, Location loc)
+ public void Error_ValueAssignment (ResolveContext rc, Expression rhs)
{
- ec.Report.Error (131, loc, "The left-hand side of an assignment must be a variable, a property or an indexer");
+ if (rhs == EmptyExpression.LValueMemberAccess || rhs == EmptyExpression.LValueMemberOutAccess) {
+ rc.Report.SymbolRelatedToPreviousError (type);
+ if (rc.CurrentInitializerVariable != null) {
+ rc.Report.Error (1918, loc, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
+ type.GetSignatureForError (), GetSignatureForError ());
+ } else {
+ rc.Report.Error (1612, loc, "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
+ GetSignatureForError ());
+ }
+ } else {
+ rc.Report.Error (131, loc, "The left-hand side of an assignment must be a variable, a property or an indexer");
+ }
}
protected void Error_VoidPointerOperation (ResolveContext rc)
}
}
}
+
+ public virtual string GetSignatureForError ()
+ {
+ return type.GetDefinition ().GetSignatureForError ();
+ }
/// <summary>
/// Resolves an expression and performs semantic analysis on it.
throw;
ec.Report.Error (584, loc, "Internal compiler error: {0}", ex.Message);
- return EmptyExpression.Null; // TODO: Add location
+ return ErrorExpression.Instance; // TODO: Add location
}
}
if (out_access)
ec.Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
else
- Error_ValueAssignment (ec, loc);
+ Error_ValueAssignment (ec, right_side);
}
return null;
}
ec.Emit (OpCodes.Pop);
}
+ //
+ // Emits the expression into temporary field variable. The method
+ // should be used for await expressions only
+ //
+ public virtual Expression EmitToField (EmitContext ec)
+ {
+ //
+ // This is the await prepare Emit method. When emitting code like
+ // a + b we emit code like
+ //
+ // a.Emit ()
+ // b.Emit ()
+ // Opcodes.Add
+ //
+ // For await a + await b we have to interfere the flow to keep the
+ // stack clean because await yields from the expression. The emit
+ // then changes to
+ //
+ // a = a.EmitToField () // a is changed to temporary field access
+ // b = b.EmitToField ()
+ // a.Emit ()
+ // b.Emit ()
+ // Opcodes.Add
+ //
+ //
+ // The idea is to emit expression and leave the stack empty with
+ // result value still available.
+ //
+ // Expressions should override this default implementation when
+ // optimized version can be provided (e.g. FieldExpr)
+ //
+ //
+ // We can optimize for side-effect free expressions, they can be
+ // emitted out of order
+ //
+ if (IsSideEffectFree)
+ return this;
+
+ bool needs_temporary = ContainsEmitWithAwait ();
+ if (!needs_temporary)
+ ec.EmitThis ();
+
+ // Emit original code
+ EmitToFieldSource (ec);
+
+ //
+ // Store the result to temporary field when we
+ // cannot load `this' directly
+ //
+ var field = ec.GetTemporaryField (type);
+ if (needs_temporary) {
+ //
+ // Create temporary local (we cannot load `this' before Emit)
+ //
+ var temp = ec.GetTemporaryLocal (type);
+ ec.Emit (OpCodes.Stloc, temp);
+
+ ec.EmitThis ();
+ ec.Emit (OpCodes.Ldloc, temp);
+ field.EmitAssignFromStack (ec);
+
+ ec.FreeTemporaryLocal (temp, type);
+ } else {
+ field.EmitAssignFromStack (ec);
+ }
+
+ return field;
+ }
+
+ protected virtual void EmitToFieldSource (EmitContext ec)
+ {
+ //
+ // Default implementation calls Emit method
+ //
+ Emit (ec);
+ }
+
+ protected static void EmitExpressionsList (EmitContext ec, List<Expression> expressions)
+ {
+ if (ec.HasSet (BuilderContext.Options.AsyncBody)) {
+ bool contains_await = false;
+
+ for (int i = 1; i < expressions.Count; ++i) {
+ if (expressions[i].ContainsEmitWithAwait ()) {
+ contains_await = true;
+ break;
+ }
+ }
+
+ if (contains_await) {
+ for (int i = 0; i < expressions.Count; ++i) {
+ expressions[i] = expressions[i].EmitToField (ec);
+ }
+ }
+ }
+
+ for (int i = 0; i < expressions.Count; ++i) {
+ expressions[i].Emit (ec);
+ }
+ }
+
/// <summary>
/// Protected constructor. Only derivate types should
/// be able to be created
return null;
}
- protected static MethodSpec ConstructorLookup (ResolveContext rc, TypeSpec type, ref Arguments args, Location loc)
+ public static MethodSpec ConstructorLookup (ResolveContext rc, TypeSpec type, ref Arguments args, Location loc)
{
var ctors = MemberCache.FindMembers (type, Constructor.ConstructorName, true);
if (ctors == null) {
}
var r = new OverloadResolver (ctors, OverloadResolver.Restrictions.NoBaseMembers, loc);
+ if (!rc.HasSet (ResolveContext.Options.BaseInitializer)) {
+ r.InstanceQualifier = new ConstructorInstanceQualifier (type);
+ }
+
return r.ResolveMember<MethodSpec> (rc, ref args);
}
if ((member.Modifiers & Modifiers.OVERRIDE) != 0 && member.Kind != MemberKind.Event)
continue;
+ if ((member.Modifiers & Modifiers.BACKING_FIELD) != 0)
+ continue;
+
if ((arity > 0 || (restrictions & MemberLookupRestrictions.ExactArity) != 0) && member.Arity != arity)
continue;
continue;
}
- if (non_method == null || member is MethodSpec) {
+ if (non_method == null || member is MethodSpec || non_method.IsNotCSharpCompatible) {
non_method = member;
- } else if (!errorMode) {
+ } else if (!errorMode && !member.IsNotCSharpCompatible) {
ambig_non_method = member;
}
}
throw new NotImplementedException ();
}
+ public virtual void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
+ {
+ rc.Report.Error (23, loc, "The `{0}' operator cannot be applied to operand of type `{1}'",
+ oper, t.GetSignatureForError ());
+ }
+
protected void Error_PointerInsideExpressionTree (ResolveContext ec)
{
ec.Report.Error (1944, loc, "An expression tree cannot contain an unsafe pointer operation");
name, was, expected);
}
- public void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
+ public virtual void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
{
string [] valid = new string [4];
int count = 0;
Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
}
- protected void Error_CannotModifyIntermediateExpressionValue (ResolveContext ec)
- {
- ec.Report.SymbolRelatedToPreviousError (type);
- if (ec.CurrentInitializerVariable != null) {
- ec.Report.Error (1918, loc, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
- TypeManager.CSharpName (type), GetSignatureForError ());
- } else {
- ec.Report.Error (1612, loc, "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
- GetSignatureForError ());
- }
- }
-
//
// Converts `source' to an int, uint, long or ulong.
//
protected static TypeExpr CreateExpressionTypeExpression (ResolveContext ec, Location loc)
{
- var t = ec.Module.PredefinedTypes.Expression.Resolve (loc);
+ var t = ec.Module.PredefinedTypes.Expression.Resolve ();
if (t == null)
return null;
{
throw new NotImplementedException ("MakeExpression for " + GetType ());
}
+
+ public virtual object Accept (StructuralVisitor visitor)
+ {
+ return visitor.Visit (this);
+ }
}
/// <summary>
}
}
+ public override bool ContainsEmitWithAwait ()
+ {
+ return child.ContainsEmitWithAwait ();
+ }
+
public override Expression CreateExpressionTree (ResolveContext ec)
{
Arguments args = new Arguments (2);
args.Add (new Argument (child.CreateExpressionTree (ec)));
- args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
+ args.Add (new Argument (new TypeOf (type, loc)));
if (type.IsPointer || child.Type.IsPointer)
Error_PointerInsideExpressionTree (ec);
{
Arguments args = Arguments.CreateForExpressionTree (ec, null,
child.CreateExpressionTree (ec),
- new TypeOf (new TypeExpression (type, loc), loc));
+ new TypeOf (type, loc));
if (type.IsPointer)
Error_PointerInsideExpressionTree (ec);
get { return child.IsOneInteger; }
}
+ public override bool IsSideEffectFree {
+ get {
+ return child.IsSideEffectFree;
+ }
+ }
+
public override bool IsZeroInteger {
get { return child.IsZeroInteger; }
}
}
}
+ public override bool IsSideEffectFree {
+ get {
+ return Child.IsSideEffectFree;
+ }
+ }
+
public override bool IsZeroInteger {
get { return Child.IsZeroInteger; }
}
c = new ReducedConstantExpression (c, orig_expr);
return c;
}
+
+ public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
+ {
+ //
+ // LAMESPEC: Reduced conditional expression is allowed as an attribute argument
+ //
+ if (orig_expr is Conditional)
+ child.EncodeAttributeValue (rc, enc, targetType);
+ else
+ base.EncodeAttributeValue (rc, enc, targetType);
+ }
}
sealed class ReducedExpressionStatement : ExpressionStatement
this.loc = orig.Location;
}
+ public override bool ContainsEmitWithAwait ()
+ {
+ return stm.ContainsEmitWithAwait ();
+ }
+
public override Expression CreateExpressionTree (ResolveContext ec)
{
return orig_expr.CreateExpressionTree (ec);
#endregion
+ public override bool ContainsEmitWithAwait ()
+ {
+ return expr.ContainsEmitWithAwait ();
+ }
+
//
// Creates fully resolved expression switcher
//
this.loc = expr.Location;
}
- public override Expression CreateExpressionTree (ResolveContext ec)
+ public override bool ContainsEmitWithAwait ()
{
- return expr.CreateExpressionTree (ec);
+ return expr.ContainsEmitWithAwait ();
+ }
+
+ public override Expression CreateExpressionTree (ResolveContext rc)
+ {
+ return expr.CreateExpressionTree (rc);
}
public Expression Child {
get { return expr; }
}
- protected override Expression DoResolve (ResolveContext ec)
+ protected override Expression DoResolve (ResolveContext rc)
{
- expr = expr.Resolve (ec);
+ expr = expr.Resolve (rc);
if (expr != null) {
type = expr.Type;
eclass = expr.eclass;
this.expr = expr;
}
+ public Expression Expr {
+ get {
+ return expr;
+ }
+ }
+
protected override void CloneTo (CloneContext clonectx, Expression t)
{
if (expr == null)
target.expr = expr.Clone (clonectx);
}
+ public override bool ContainsEmitWithAwait ()
+ {
+ return expr.ContainsEmitWithAwait ();
+ }
+
public override Expression CreateExpressionTree (ResolveContext ec)
{
throw new NotSupportedException ("ET");
throw new InternalErrorException ("Missing Resolve call");
}
- public Expression Expr {
- get { return expr; }
- }
}
//
return new SimpleName (Name, targs, loc);
}
- protected virtual void Error_TypeOrNamespaceNotFound (IMemberContext ec)
+ protected override Expression DoResolve (ResolveContext rc)
+ {
+ var e = SimpleNameResolve (rc, null, false);
+
+ var fe = e as FieldExpr;
+ if (fe != null) {
+ fe.VerifyAssignedStructField (rc, null);
+ }
+
+ return e;
+ }
+
+ public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
+ {
+ return SimpleNameResolve (ec, right_side, false);
+ }
+
+ protected virtual void Error_TypeOrNamespaceNotFound (IMemberContext ctx)
{
- if (ec.CurrentType != null) {
- if (ec.CurrentMemberDefinition != null) {
- MemberCore mc = ec.CurrentMemberDefinition.Parent.GetDefinition (Name);
+ if (ctx.CurrentType != null) {
+ if (ctx.CurrentMemberDefinition != null) {
+ MemberCore mc = ctx.CurrentMemberDefinition.Parent.GetDefinition (Name);
if (mc != null) {
- Error_UnexpectedKind (ec.Module.Compiler.Report, mc, "type", GetMemberType (mc), loc);
+ Error_UnexpectedKind (ctx.Module.Compiler.Report, mc, "type", GetMemberType (mc), loc);
return;
}
}
-
- /*
- // TODO MemberCache: Implement
-
- string ns = ec.CurrentType.Namespace;
- string fullname = (ns.Length > 0) ? ns + "." + Name : Name;
- foreach (Assembly a in GlobalRootNamespace.Instance.Assemblies) {
- var type = a.GetType (fullname);
- if (type != null) {
- ec.Compiler.Report.SymbolRelatedToPreviousError (type);
- Expression.ErrorIsInaccesible (loc, TypeManager.CSharpName (type), ec.Compiler.Report);
- return;
- }
- }
-
- if (ec.CurrentTypeDefinition != null) {
- TypeSpec t = ec.CurrentTypeDefinition.LookupAnyGeneric (Name);
- if (t != null) {
- Namespace.Error_InvalidNumberOfTypeArguments (ec.Compiler.Report, t, loc);
- return;
- }
- }
- */
}
- FullNamedExpression retval = ec.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), loc, true);
+ var retval = ctx.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
if (retval != null) {
- Error_TypeArgumentsCannotBeUsed (ec.Module.Compiler.Report, loc, retval.Type, Arity);
-/*
- var te = retval as TypeExpr;
- if (HasTypeArguments && te != null && !te.Type.IsGeneric)
- retval.Error_TypeArgumentsCannotBeUsed (ec.Compiler.Report, loc);
- else
- Namespace.Error_InvalidNumberOfTypeArguments (ec.Compiler.Report, retval.Type, loc);
-*/
+ ctx.Module.Compiler.Report.SymbolRelatedToPreviousError (retval.Type);
+ ErrorIsInaccesible (ctx, retval.GetSignatureForError (), loc);
return;
}
- NamespaceEntry.Error_NamespaceNotFound (loc, Name, ec.Module.Compiler.Report);
- }
-
- protected override Expression DoResolve (ResolveContext ec)
- {
- return SimpleNameResolve (ec, null, false);
- }
+ retval = ctx.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
+ if (retval != null) {
+ Error_TypeArgumentsCannotBeUsed (ctx, retval.Type, Arity, loc);
+ return;
+ }
- public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
- {
- return SimpleNameResolve (ec, right_side, false);
+ NamespaceContainer.Error_NamespaceNotFound (loc, Name, ctx.Module.Compiler.Report);
}
- public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
+ public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext ec)
{
- int errors = ec.Module.Compiler.Report.Errors;
- FullNamedExpression fne = ec.LookupNamespaceOrType (Name, Arity, loc, /*ignore_cs0104=*/ false);
+ FullNamedExpression fne = ec.LookupNamespaceOrType (Name, Arity, LookupMode.Normal, loc);
if (fne != null) {
if (fne.Type != null && Arity > 0) {
if (HasTypeArguments) {
GenericTypeExpr ct = new GenericTypeExpr (fne.Type, targs, loc);
- return ct.ResolveAsTypeStep (ec, false);
+ if (ct.ResolveAsType (ec) == null)
+ return null;
+
+ return ct;
}
return new GenericOpenTypeExpr (fne.Type, loc);
ec.Module.PredefinedAttributes.Dynamic.GetSignatureForError ());
}
- return new DynamicTypeExpr (loc).ResolveAsTypeStep (ec, silent);
+ fne = new DynamicTypeExpr (loc);
+ fne.ResolveAsType (ec);
}
if (fne != null)
return fne;
- if (silent || errors != ec.Module.Compiler.Report.Errors)
- return null;
-
Error_TypeOrNamespaceNotFound (ec);
return null;
}
+ public bool IsPossibleTypeOrNamespace (IMemberContext mc)
+ {
+ return mc.LookupNamespaceOrType (Name, Arity, LookupMode.Probing, loc) != null;
+ }
+
public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
{
int lookup_arity = Arity;
e = variable.CreateReferenceExpression (rc, loc);
if (e != null) {
if (Arity > 0)
- Error_TypeArgumentsCannotBeUsed (rc.Report, "variable", Name, loc);
+ Error_TypeArgumentsCannotBeUsed (rc, "variable", Name, loc);
return e;
}
// Stage 3: Lookup nested types, namespaces and type parameters in the context
//
if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0 && !variable_found) {
- e = ResolveAsTypeStep (rc, lookup_arity == 0 || !errorMode);
- if (e != null) {
+ if (IsPossibleTypeOrNamespace (rc)) {
if (variable != null) {
rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
}
- return e;
+ return ResolveAsTypeOrNamespace (rc);
}
}
if (variable_found) {
rc.Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", Name);
} else {
+ if (Arity > 0) {
+ TypeParameter[] tparams = rc.CurrentTypeParameters;
+ if (tparams != null) {
+ foreach (var ctp in tparams) {
+ if (ctp.Name == Name) {
+ Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
+ return null;
+ }
+ }
+ }
+
+ var ct = rc.CurrentType;
+ do {
+ if (ct.MemberDefinition.TypeParametersCount > 0) {
+ foreach (var ctp in ct.MemberDefinition.TypeParameters) {
+ if (ctp.Name == Name) {
+ Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
+ return null;
+ }
+ }
+ }
+
+ ct = ct.DeclaringType;
+ } while (ct != null);
+ }
+
+ if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0) {
+ e = rc.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
+ if (e != null) {
+ rc.Report.SymbolRelatedToPreviousError (e.Type);
+ ErrorIsInaccesible (rc, e.GetSignatureForError (), loc);
+ return e;
+ }
+ }
+
+ e = rc.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
+ if (e != null) {
+ if (!(e is TypeExpr) || (restrictions & MemberLookupRestrictions.InvocableOnly) == 0 || !e.Type.IsDelegate) {
+ Error_TypeArgumentsCannotBeUsed (rc, e.Type, Arity, loc);
+ return e;
+ }
+ }
+
rc.Report.Error (103, loc, "The name `{0}' does not exist in the current context", Name);
}
- return null;
+ return ErrorExpression.Instance;
}
if (rc.Module.Evaluator != null) {
}
lookup_arity = 0;
- restrictions &= ~MemberLookupRestrictions.InvocableOnly;
errorMode = true;
}
}
//if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
return e;
}
+
+ public override object Accept (StructuralVisitor visitor)
+ {
+ return visitor.Visit (this);
+ }
}
/// <summary>
// resolved to different type
}
+ public override bool ContainsEmitWithAwait ()
+ {
+ return false;
+ }
+
public override Expression CreateExpressionTree (ResolveContext ec)
{
throw new NotSupportedException ("ET");
}
- public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
+ public abstract FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc);
+
+ //
+ // This is used to resolve the expression as a type, a null
+ // value will be returned if the expression is not a type
+ // reference
+ //
+ public override TypeSpec ResolveAsType (IMemberContext mc)
{
- return this;
+ FullNamedExpression fne = ResolveAsTypeOrNamespace (mc);
+
+ if (fne == null)
+ return null;
+
+ TypeExpr te = fne as TypeExpr;
+ if (te == null) {
+ fne.Error_UnexpectedKind (mc.Module.Compiler.Report, null, "type", loc);
+ return null;
+ }
+
+ te.loc = loc;
+
+ type = te.Type;
+
+ var dep = type.GetMissingDependencies ();
+ if (dep != null) {
+ ImportedTypeDefinition.Error_MissingDependency (mc, dep, loc);
+ }
+
+ //
+ // Obsolete checks cannot be done when resolving base context as they
+ // require type dependencies to be set but we are in process of resolving them
+ //
+ if (!(mc is TypeContainer.BaseContext)) {
+ ObsoleteAttribute obsolete_attr = type.GetAttributeObsolete ();
+ if (obsolete_attr != null && !mc.IsObsolete) {
+ AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location, mc.Module.Compiler.Report);
+ }
+ }
+
+ return type;
}
+
public override void Emit (EmitContext ec)
{
throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
/// <summary>
/// Expression that evaluates to a type
/// </summary>
- public abstract class TypeExpr : FullNamedExpression {
- public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
+ public abstract class TypeExpr : FullNamedExpression
+ {
+ public sealed override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc)
{
- TypeExpr t = DoResolveAsTypeStep (ec);
- if (t == null)
- return null;
-
- eclass = ExprClass.Type;
- return t;
+ ResolveAsType (mc);
+ return this;
}
- protected override Expression DoResolve (ResolveContext ec)
+ protected sealed override Expression DoResolve (ResolveContext ec)
{
- return ResolveAsTypeTerminal (ec, false);
+ ResolveAsType (ec);
+ return this;
}
- protected abstract TypeExpr DoResolveAsTypeStep (IMemberContext ec);
-
public override bool Equals (object obj)
{
TypeExpr tobj = obj as TypeExpr;
/// <summary>
/// Fully resolved Expression that already evaluated to a type
/// </summary>
- public class TypeExpression : TypeExpr {
+ public class TypeExpression : TypeExpr
+ {
public TypeExpression (TypeSpec t, Location l)
{
Type = t;
loc = l;
}
- protected override TypeExpr DoResolveAsTypeStep (IMemberContext ec)
- {
- return this;
- }
-
- public override TypeExpr ResolveAsTypeTerminal (IMemberContext ec, bool silent)
+ public sealed override TypeSpec ResolveAsType (IMemberContext ec)
{
- return this;
+ return type;
}
}
/// This class denotes an expression which evaluates to a member
/// of a struct or a class.
/// </summary>
- public abstract class MemberExpr : Expression
+ public abstract class MemberExpr : Expression, OverloadResolver.IInstanceQualifier
{
//
// An instance expression associated with this member, if it's a
get;
}
- // TODO: Not needed
protected abstract TypeSpec DeclaringType {
get;
}
+ TypeSpec OverloadResolver.IInstanceQualifier.InstanceType {
+ get {
+ return InstanceExpression.Type;
+ }
+ }
+
//
// Converts best base candidate for virtual method starting from QueriedBaseType
//
// Overload resulution works on virtual or non-virtual members only (no overrides). That
// means for base.member access we have to find the closest match after we found best candidate
//
- if ((method.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL | Modifiers.STATIC)) != Modifiers.STATIC) {
+ if ((method.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL | Modifiers.OVERRIDE)) != 0) {
//
// The method could already be what we are looking for
//
return method;
}
- protected void CheckProtectedMemberAccess<T> (ResolveContext rc, T member) where T : MemberSpec
+ protected void CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
{
if (InstanceExpression == null)
return;
if ((member.Modifiers & Modifiers.PROTECTED) != 0 && !(InstanceExpression is This)) {
- var ct = rc.CurrentType;
- var expr_type = InstanceExpression.Type;
- if (ct == expr_type)
- return;
+ if (!CheckProtectedMemberAccess (rc, member, InstanceExpression.Type)) {
+ Error_ProtectedMemberAccess (rc, member, InstanceExpression.Type, loc);
+ }
+ }
+ }
- if ((member.Modifiers & Modifiers.INTERNAL) != 0 && member.DeclaringType.MemberDefinition.IsInternalAsPublic (ct.MemberDefinition.DeclaringAssembly))
- return;
+ bool OverloadResolver.IInstanceQualifier.CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
+ {
+ if (InstanceExpression == null)
+ return true;
- expr_type = expr_type.GetDefinition ();
- if (ct != expr_type && !IsSameOrBaseQualifier (ct, expr_type)) {
- rc.Report.SymbolRelatedToPreviousError (member);
- rc.Report.Error (1540, loc,
- "Cannot access protected member `{0}' via a qualifier of type `{1}'. The qualifier must be of type `{2}' or derived from it",
- member.GetSignatureForError (), expr_type.GetSignatureForError (), ct.GetSignatureForError ());
- }
+ return InstanceExpression is This || CheckProtectedMemberAccess (rc, member, InstanceExpression.Type);
+ }
+
+ public static bool CheckProtectedMemberAccess<T> (ResolveContext rc, T member, TypeSpec qualifier) where T : MemberSpec
+ {
+ var ct = rc.CurrentType;
+ if (ct == qualifier)
+ return true;
+
+ if ((member.Modifiers & Modifiers.INTERNAL) != 0 && member.DeclaringType.MemberDefinition.IsInternalAsPublic (ct.MemberDefinition.DeclaringAssembly))
+ return true;
+
+ qualifier = qualifier.GetDefinition ();
+ if (ct != qualifier && !IsSameOrBaseQualifier (ct, qualifier)) {
+ return false;
}
+
+ return true;
+ }
+
+ public override bool ContainsEmitWithAwait ()
+ {
+ return InstanceExpression != null && InstanceExpression.ContainsEmitWithAwait ();
}
static bool IsSameOrBaseQualifier (TypeSpec type, TypeSpec qtype)
rc.Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
}
+ public static void Error_ProtectedMemberAccess (ResolveContext rc, MemberSpec member, TypeSpec qualifier, Location loc)
+ {
+ rc.Report.SymbolRelatedToPreviousError (member);
+ rc.Report.Error (1540, loc,
+ "Cannot access protected member `{0}' via a qualifier of type `{1}'. The qualifier must be of type `{2}' or derived from it",
+ member.GetSignatureForError (), qualifier.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
+ }
+
//
// Implements identicial simple name and type-name
//
// a constant, field, property, local variable, or parameter with the same type as the meaning of E as a type-name
if (left is MemberExpr || left is VariableReference) {
- rc.Report.DisableReporting ();
- Expression identical_type = rc.LookupNamespaceOrType (name.Name, 0, loc, true) as TypeExpr;
- rc.Report.EnableReporting ();
+ var identical_type = rc.LookupNamespaceOrType (name.Name, 0, LookupMode.Probing, loc) as TypeExpr;
if (identical_type != null && identical_type.Type == left.Type)
return identical_type;
}
"An object reference is required to access non-static member `{0}'",
GetSignatureForError ());
+ InstanceExpression = new CompilerGeneratedThis (type, loc).Resolve (rc);
return false;
}
}
InstanceExpression = new This (loc);
- if (this is FieldExpr && rc.CurrentType.IsStruct) {
+ if (this is FieldExpr && rc.CurrentBlock.ParametersBlock.TopBlock.ThisVariable != null) {
using (rc.Set (ResolveContext.Options.OmitStructFlowAnalysis)) {
InstanceExpression = InstanceExpression.Resolve (rc);
}
// the expression is not field expression which is the only
// expression which can use uninitialized this
//
- if (InstanceExpression is This && !(this is FieldExpr) && rc.CurrentType.IsStruct) {
+ if (InstanceExpression is This && !(this is FieldExpr) && rc.CurrentBlock.ParametersBlock.TopBlock.ThisVariable != null) {
((This)InstanceExpression).CheckStructThisDefiniteAssignment (rc);
}
// Additional checks for l-value member access
//
if (rhs != null) {
- //
- // TODO: It should be recursive but that would break csc compatibility
- //
if (InstanceExpression is UnboxCast) {
rc.Report.Error (445, InstanceExpression.Location, "Cannot modify the result of an unboxing conversion");
}
public virtual MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
{
- if (left != null && left.IsNull && TypeManager.IsReferenceType (left.Type)) {
+ if (left != null && left.IsNull && TypeSpec.IsReferenceType (left.Type)) {
ec.Report.Warning (1720, 1, left.Location,
"Expression will always cause a `{0}'", "System.NullReferenceException");
}
protected void EmitInstance (EmitContext ec, bool prepare_for_load)
{
TypeSpec instance_type = InstanceExpression.Type;
- if (TypeManager.IsValueType (instance_type)) {
+ if (TypeSpec.IsValueType (instance_type)) {
if (InstanceExpression is IMemoryLocation) {
- ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.LoadStore);
+ ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.Load);
} else {
+ // Cannot release the temporary variable when its address
+ // is required to be on stack for any parent
LocalTemporary t = new LocalTemporary (instance_type);
InstanceExpression.Emit (ec);
t.Store (ec);
InstanceExpression.Emit (ec);
// Only to make verifier happy
- if (instance_type.IsGenericParameter && !(InstanceExpression is This) && TypeManager.IsReferenceType (instance_type))
+ if (instance_type.IsGenericParameter && !(InstanceExpression is This) && TypeSpec.IsReferenceType (instance_type))
ec.Emit (OpCodes.Box, instance_type);
}
public abstract void SetTypeArguments (ResolveContext ec, TypeArguments ta);
}
+ public class ExtensionMethodCandidates
+ {
+ NamespaceContainer container;
+ Namespace ns;
+ IList<MethodSpec> methods;
+
+ public ExtensionMethodCandidates (IList<MethodSpec> methods, NamespaceContainer nsContainer)
+ : this (methods, nsContainer, null)
+ {
+ }
+
+ public ExtensionMethodCandidates (IList<MethodSpec> methods, NamespaceContainer nsContainer, Namespace ns)
+ {
+ this.methods = methods;
+ this.container = nsContainer;
+ this.ns = ns;
+ }
+
+ public NamespaceContainer Container {
+ get {
+ return container;
+ }
+ }
+
+ public bool HasUninspectedMembers { get; set; }
+
+ public Namespace Namespace {
+ get {
+ return ns;
+ }
+ }
+
+ public IList<MethodSpec> Methods {
+ get {
+ return methods;
+ }
+ }
+ }
+
//
// Represents a group of extension method candidates for whole namespace
//
class ExtensionMethodGroupExpr : MethodGroupExpr, OverloadResolver.IErrorHandler
{
- NamespaceEntry namespace_entry;
+ ExtensionMethodCandidates candidates;
public readonly Expression ExtensionExpression;
- public ExtensionMethodGroupExpr (IList<MethodSpec> list, NamespaceEntry n, Expression extensionExpr, Location l)
- : base (list.Cast<MemberSpec>().ToList (), extensionExpr.Type, l)
+ public ExtensionMethodGroupExpr (ExtensionMethodCandidates candidates, Expression extensionExpr, Location loc)
+ : base (candidates.Methods.Cast<MemberSpec>().ToList (), extensionExpr.Type, loc)
{
- this.namespace_entry = n;
+ this.candidates = candidates;
this.ExtensionExpression = extensionExpr;
}
get { return true; }
}
+ //
+ // For extension methodgroup we are not looking for base members but parent
+ // namespace extension methods
+ //
public override IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
{
- if (namespace_entry == null)
+ // TODO: candidates are null only when doing error reporting, that's
+ // incorrect. We have to discover same extension methods in error mode
+ if (candidates == null)
return null;
+ int arity = type_arguments == null ? 0 : type_arguments.Count;
+
//
- // For extension methodgroup we are not looking for base members but parent
- // namespace extension methods
+ // Here we try to resume the search for extension method at the point
+ // where the last bunch of candidates was found. It's more tricky than
+ // it seems as we have to check both namespace containers and namespace
+ // in correct order.
//
- int arity = type_arguments == null ? 0 : type_arguments.Count;
- var found = namespace_entry.LookupExtensionMethod (DeclaringType, Name, arity, ref namespace_entry);
- if (found == null)
+ // Consider:
+ //
+ // namespace A {
+ // using N1;
+ // namespace B.C.D {
+ // <our first search found candidates in A.B.C.D
+ // }
+ // }
+ //
+ // In the example above namespace A.B.C.D, A.B.C and A.B have to be
+ // checked before we hit A.N1 using
+ //
+ if (candidates.Namespace == null) {
+ Namespace scope;
+ var methods = candidates.Container.NS.LookupExtensionMethod (candidates.Container, ExtensionExpression.Type, Name, arity, out scope);
+ if (methods != null) {
+ candidates = new ExtensionMethodCandidates (null, candidates.Container, scope);
+ return methods.Cast<MemberSpec> ().ToList ();
+ }
+ }
+
+ var ns_container = candidates.HasUninspectedMembers ? candidates.Container : candidates.Container.Parent;
+ if (ns_container == null)
+ return null;
+
+ candidates = ns_container.LookupExtensionMethod (ExtensionExpression.Type, Name, arity);
+ if (candidates == null)
return null;
- return found.Cast<MemberSpec> ().ToList ();
+ return candidates.Methods.Cast<MemberSpec> ().ToList ();
}
public override MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
}
}
+ public IList<MemberSpec> Candidates {
+ get {
+ return Methods;
+ }
+ }
+
protected override TypeSpec DeclaringType {
get {
return queried_type;
public void EmitCall (EmitContext ec, Arguments arguments)
{
- Invocation.EmitCall (ec, InstanceExpression, best_candidate, arguments, loc);
+ var call = new CallEmitter ();
+ call.InstanceExpression = InstanceExpression;
+ call.Emit (ec, best_candidate, arguments, loc);
}
public override void Error_ValueCannotBeConverted (ResolveContext ec, Location loc, TypeSpec target, bool expl)
var r = new OverloadResolver (Methods, type_arguments, restr, loc);
if ((restr & OverloadResolver.Restrictions.NoBaseMembers) == 0) {
r.BaseMembersProvider = this;
+ r.InstanceQualifier = this;
}
if (cerrors != null)
}
ResolveInstanceExpression (ec, null);
- if (InstanceExpression != null)
- CheckProtectedMemberAccess (ec, best_candidate);
}
var base_override = CandidateToBaseOverride (ec, best_candidate);
return null;
int arity = type_arguments == null ? 0 : type_arguments.Count;
- NamespaceEntry methods_scope = null;
- var methods = rc.LookupExtensionMethod (InstanceExpression.Type, Methods[0].Name, arity, ref methods_scope);
+ var methods = rc.LookupExtensionMethod (InstanceExpression.Type, Methods[0].Name, arity);
if (methods == null)
return null;
- var emg = new ExtensionMethodGroupExpr (methods, methods_scope, InstanceExpression, loc);
+ var emg = new ExtensionMethodGroupExpr (methods, InstanceExpression, loc);
emg.SetTypeArguments (rc, type_arguments);
return emg;
}
#endregion
}
+ struct ConstructorInstanceQualifier : OverloadResolver.IInstanceQualifier
+ {
+ public ConstructorInstanceQualifier (TypeSpec type)
+ : this ()
+ {
+ InstanceType = type;
+ }
+
+ public TypeSpec InstanceType { get; private set; }
+
+ public bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
+ {
+ return MemberExpr.CheckProtectedMemberAccess (rc, member, InstanceType);
+ }
+ }
+
public struct OverloadResolver
{
[Flags]
bool TypeInferenceFailed (ResolveContext rc, MemberSpec best);
}
+ public interface IInstanceQualifier
+ {
+ TypeSpec InstanceType { get; }
+ bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member);
+ }
+
sealed class NoBaseMembers : IBaseMembersProvider
{
public static readonly IBaseMembersProvider Instance = new NoBaseMembers ();
TypeArguments type_arguments;
IBaseMembersProvider base_provider;
IErrorHandler custom_errors;
+ IInstanceQualifier instance_qualifier;
Restrictions restrictions;
MethodGroupExpr best_candidate_extension_group;
TypeSpec best_candidate_return_type;
}
}
+ public IInstanceQualifier InstanceQualifier {
+ get {
+ return instance_qualifier;
+ }
+ set {
+ instance_qualifier = value;
+ }
+ }
+
bool IsProbingOnly {
get {
return (restrictions & Restrictions.ProbingOnly) != 0;
//
// With identical parameter lists
//
- if (!TypeSpecComparer.Equals (p_m.Parameters.Types,q_m.Parameters.Types))
+ if (!TypeSpecComparer.Equals (p_m.Parameters.Types, q_m.Parameters.Types))
return 0;
p = p_m.ReturnType;
if (q.Kind == MemberKind.Void) {
return p.Kind != MemberKind.Void ? 1: 0;
}
+
+ //
+ // When anonymous method is an asynchronous, and P has a return type Task<Y1>, and Q has a return type Task<Y2>
+ // better conversion is performed between underlying types Y1 and Y2
+ //
+ if (p.IsGenericTask || q.IsGenericTask) {
+ var async_am = a.Expr as AnonymousMethodExpression;
+ if (async_am != null && async_am.Block.IsAsync) {
+
+ if (p.IsGenericTask != q.IsGenericTask) {
+ return 0;
+ }
+
+ q = q.TypeArguments[0];
+ p = p.TypeArguments[0];
+ }
+ }
+
+ //
+ // The parameters are identicial and return type is not void, use better type conversion
+ // on return type to determine better one
+ //
} else {
if (argument_type == p)
return 1;
// if the type matches
//
Expression e = pd.FixedParameters[i].DefaultValue;
- if (!(e is Constant) || e.Type.IsGenericOrParentIsGeneric) {
+ if (!(e is Constant) || e.Type.IsGenericOrParentIsGeneric || e.Type.IsGenericParameter) {
//
// LAMESPEC: No idea what the exact rules are for System.Reflection.Missing.Value instead of null
//
//
// Indentity, implicit reference or boxing conversion must exist for the extension parameter
//
+ // LAMESPEC: or implicit type parameter conversion
+ //
var at = a.Type;
if (at == pt || TypeSpecComparer.IsEqual (at, pt) ||
- Convert.ImplicitReferenceConversionExists (at, pt) ||
+ Convert.ImplicitReferenceConversionExists (at, pt, false) ||
Convert.ImplicitBoxingConversion (null, at, pt) != null) {
score = 0;
continue;
//
// Deploy custom error reporting for lambda methods. When probing lambda methods
// keep all errors reported in separate set and once we are done and no best
- // candidate found, this set is used to report more details about what was wrong
+ // candidate was found, this set is used to report more details about what was wrong
// with lambda body
//
if (argument.Expr.Type == InternalType.AnonymousMethod) {
}
}
+ //
+ // Use implicit conversion in all modes to return same candidates when the expression
+ // is used as argument or delegate conversion
+ //
if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
if (lambda_conv_msgs != null) {
lambda_conv_msgs.EndSession ();
var ac_p = p as ArrayContainer;
if (ac_p != null) {
- var ac_q = ((ArrayContainer) q);
+ var ac_q = q as ArrayContainer;
+ if (ac_q == null)
+ return null;
+
TypeSpec specific = MoreSpecific (ac_p.Element, ac_q.Element);
if (specific == ac_p.Element)
return p;
if (rc.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
continue;
+
+ if ((member.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
+ instance_qualifier != null && !instance_qualifier.CheckProtectedMemberAccess (rc, member)) {
+ continue;
+ }
}
IParametersMember pm = member as IParametersMember;
if (error_mode)
break;
+ if (lambda_conv_msgs != null && !lambda_conv_msgs.IsEmpty)
+ break;
+
lambda_conv_msgs = null;
error_mode = true;
}
return null;
}
+ //
+ // These flags indicates we are running delegate probing conversion. No need to
+ // do more expensive checks
+ //
+ if ((restrictions & (Restrictions.ProbingOnly | Restrictions.CovariantDelegate)) == (Restrictions.CovariantDelegate | Restrictions.ProbingOnly))
+ return (T) best_candidate;
+
if (ambiguous_candidates != null) {
//
// Now check that there are no ambiguities i.e the selected method
else
ec.Report.Error (1620, loc, "Argument `#{0}' is missing `{1}' modifier",
index, Parameter.GetModifierSignature (mod));
- } else {
+ } else if (a.Expr != ErrorExpression.Instance) {
string p1 = a.GetSignatureForError ();
string p2 = TypeManager.CSharpName (paramType);
if (p1 == p2) {
- ec.Report.ExtraInformation (loc, "(equally named types possibly from different assemblies in previous ");
- ec.Report.SymbolRelatedToPreviousError (a.Expr.Type);
- ec.Report.SymbolRelatedToPreviousError (paramType);
+ p1 = a.Type.GetSignatureForErrorIncludingAssemblyName ();
+ p2 = paramType.GetSignatureForErrorIncludingAssemblyName ();
}
ec.Report.Error (1503, loc,
if (ta_count != best_candidate.Arity && (ta_count > 0 || ((IParametersMember) best_candidate).Parameters.IsEmpty)) {
var mg = new MethodGroupExpr (new [] { best_candidate }, best_candidate.DeclaringType, loc);
- mg.Error_TypeArgumentsCannotBeUsed (rc.Report, loc, best_candidate, ta_count);
+ mg.Error_TypeArgumentsCannotBeUsed (rc, best_candidate, ta_count, loc);
return;
}
return;
}
+
+ if ((best_candidate.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
+ InstanceQualifier != null && !InstanceQualifier.CheckProtectedMemberAccess (rc, best_candidate)) {
+ MemberExpr.Error_ProtectedMemberAccess (rc, best_candidate, InstanceQualifier.InstanceType, loc);
+ }
+
//
// For candidates which match on parameters count report more details about incorrect arguments
//
public class ConstantExpr : MemberExpr
{
- ConstSpec constant;
+ readonly ConstSpec constant;
public ConstantExpr (ConstSpec constant, Location loc)
{
public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
{
- Error_TypeArgumentsCannotBeUsed (ec.Report, "constant", GetSignatureForError (), loc);
+ Error_TypeArgumentsCannotBeUsed (ec, "constant", GetSignatureForError (), loc);
}
}
- /// <summary>
- /// Fully resolved expression that evaluates to a Field
- /// </summary>
- public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference {
+ //
+ // Fully resolved expression that references a Field
+ //
+ public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference
+ {
protected FieldSpec spec;
VariableInfo variable_info;
public override string GetSignatureForError ()
{
- return TypeManager.GetFullNameSignature (spec);
+ return spec.GetSignatureForError ();
}
public bool IsMarshalByRefAccess (ResolveContext rc)
{
// Checks possible ldflda of field access expression
- return !spec.IsStatic && TypeManager.IsValueType (spec.MemberType) && !(InstanceExpression is This) &&
+ return !spec.IsStatic && TypeSpec.IsValueType (spec.MemberType) && !(InstanceExpression is This) &&
rc.Module.PredefinedTypes.MarshalByRefObject.Define () &&
TypeSpec.IsBaseClass (spec.DeclaringType, rc.Module.PredefinedTypes.MarshalByRefObject.TypeSpec, false);
}
public void SetHasAddressTaken ()
{
IVariableReference vr = InstanceExpression as IVariableReference;
- if (vr != null)
+ if (vr != null) {
vr.SetHasAddressTaken ();
+ }
}
public override Expression CreateExpressionTree (ResolveContext ec)
{
bool lvalue_instance = rhs != null && IsInstance && spec.DeclaringType.IsStruct;
- if (ResolveInstanceExpression (ec, rhs)) {
- // Resolve the field's instance expression while flow analysis is turned
- // off: when accessing a field "a.b", we must check whether the field
- // "a.b" is initialized, not whether the whole struct "a" is initialized.
+ if (rhs != this) {
+ if (ResolveInstanceExpression (ec, rhs)) {
+ // Resolve the field's instance expression while flow analysis is turned
+ // off: when accessing a field "a.b", we must check whether the field
+ // "a.b" is initialized, not whether the whole struct "a" is initialized.
- if (lvalue_instance) {
- using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
- bool out_access = rhs == EmptyExpression.OutAccess || rhs == EmptyExpression.LValueMemberOutAccess;
+ if (lvalue_instance) {
+ using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
+ bool out_access = rhs == EmptyExpression.OutAccess || rhs == EmptyExpression.LValueMemberOutAccess;
- Expression right_side =
- out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
+ Expression right_side =
+ out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
- InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
- }
- } else {
- using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
- InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
+ InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
+ }
+ } else {
+ using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
+ InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
+ }
}
+
+ if (InstanceExpression == null)
+ return null;
}
- if (InstanceExpression == null)
- return null;
+ DoBestMemberChecks (ec, spec);
}
- DoBestMemberChecks (ec, spec);
-
var fb = spec as FixedFieldSpec;
IVariableReference var = InstanceExpression as IVariableReference;
if (lvalue_instance && var != null && var.VariableInfo != null) {
- var.VariableInfo.SetFieldAssigned (ec, Name);
+ var.VariableInfo.SetStructFieldAssigned (ec, Name);
}
if (fb != null) {
} else if (var != null && var.IsHoisted) {
AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
}
-
+
return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
}
+ //
+ // Set flow-analysis variable info for struct member access. It will be check later
+ // for precise error reporting
+ //
+ if (var != null && var.VariableInfo != null && InstanceExpression.Type.IsStruct) {
+ variable_info = var.VariableInfo.GetStructFieldInfo (Name);
+ if (rhs != null && variable_info != null)
+ variable_info.SetStructFieldAssigned (ec, Name);
+ }
+
eclass = ExprClass.Variable;
+ return this;
+ }
- // If the instance expression is a local variable or parameter.
- if (var == null || var.VariableInfo == null)
- return this;
+ public void VerifyAssignedStructField (ResolveContext rc, Expression rhs)
+ {
+ var fe = this;
- VariableInfo vi = var.VariableInfo;
- if (!vi.IsFieldAssigned (ec, Name, loc))
- return null;
+ do {
+ var var = fe.InstanceExpression as IVariableReference;
+ if (var != null) {
+ var vi = var.VariableInfo;
- variable_info = vi.GetSubStruct (Name);
- return this;
+ if (vi != null && !vi.IsStructFieldAssigned (rc, fe.Name) && (rhs == null || !fe.type.IsStruct)) {
+ if (rhs != null) {
+ rc.Report.Warning (1060, 1, fe.loc, "Use of possibly unassigned field `{0}'", fe.Name);
+ } else {
+ rc.Report.Error (170, fe.loc, "Use of possibly unassigned field `{0}'", fe.Name);
+ }
+
+ return;
+ }
+ }
+
+ fe = fe.InstanceExpression as FieldExpr;
+
+ } while (fe != null);
}
static readonly int [] codes = {
public void Emit (EmitContext ec, bool leave_copy)
{
- bool is_volatile = false;
-
- if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
- is_volatile = true;
+ bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
spec.MemberDefinition.SetIsUsed ();
}
}
- public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
+ public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
{
- prepared = prepare_for_load && !(source is DynamicExpressionStatement);
- if (IsInstance)
+ bool has_await_source = ec.HasSet (BuilderContext.Options.AsyncBody) && source.ContainsEmitWithAwait ();
+ if (isCompound && !(source is DynamicExpressionStatement)) {
+ if (has_await_source) {
+ if (IsInstance)
+ InstanceExpression = InstanceExpression.EmitToField (ec);
+ } else {
+ prepared = true;
+ }
+ }
+
+ if (IsInstance) {
+ if (has_await_source)
+ source = source.EmitToField (ec);
+
EmitInstance (ec, prepared);
+ }
source.Emit (ec);
+
if (leave_copy) {
ec.Emit (OpCodes.Dup);
if (!IsStatic) {
}
}
+ //
+ // Emits store to field with prepared values on stack
+ //
+ public void EmitAssignFromStack (EmitContext ec)
+ {
+ if (IsStatic) {
+ ec.Emit (OpCodes.Stsfld, spec);
+ } else {
+ ec.Emit (OpCodes.Stfld, spec);
+ }
+ }
+
public override void Emit (EmitContext ec)
{
Emit (ec, false);
} else
need_copy = false;
- if (need_copy){
- LocalBuilder local;
+ if (need_copy) {
Emit (ec);
- local = ec.DeclareLocal (type, false);
- ec.Emit (OpCodes.Stloc, local);
- ec.Emit (OpCodes.Ldloca, local);
+ var temp = ec.GetTemporaryLocal (type);
+ ec.Emit (OpCodes.Stloc, temp);
+ ec.Emit (OpCodes.Ldloca, temp);
+ ec.FreeTemporaryLocal (temp, type);
return;
}
public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
{
- Error_TypeArgumentsCannotBeUsed (ec.Report, "field", GetSignatureForError (), loc);
+ Error_TypeArgumentsCannotBeUsed (ec, "field", GetSignatureForError (), loc);
}
}
- /// <summary>
- /// Expression that evaluates to a Property. The Assign class
- /// might set the `Value' expression if we are in an assignment.
- ///
- /// This is not an LValue because we need to re-write the expression, we
- /// can not take data from the stack and store it.
- /// </summary>
- class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
+ //
+ // Expression that evaluates to a Property.
+ //
+ // This is not an LValue because we need to re-write the expression. We
+ // can not take data from the stack and store it.
+ //
+ sealed class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
{
public PropertyExpr (PropertySpec spec, Location l)
: base (l)
#region Properties
+ protected override Arguments Arguments {
+ get {
+ return null;
+ }
+ set {
+ }
+ }
+
protected override TypeSpec DeclaringType {
get {
return best_candidate.DeclaringType;
#endregion
+ public static PropertyExpr CreatePredefined (PropertySpec spec, Location loc)
+ {
+ return new PropertyExpr (spec, loc) {
+ Getter = spec.Get,
+ Setter = spec.Set
+ };
+ }
+
public override Expression CreateExpressionTree (ResolveContext ec)
{
Arguments args;
return CreateExpressionFactoryCall (ec, "Property", args);
}
- public Expression CreateSetterTypeOfExpression ()
+ public Expression CreateSetterTypeOfExpression (ResolveContext rc)
{
+ DoResolveLValue (rc, null);
return new TypeOfMethod (Setter, loc);
}
// Special case: length of single dimension array property is turned into ldlen
//
if (IsSingleDimensionalArrayLength ()) {
- if (!prepared)
- EmitInstance (ec, false);
+ EmitInstance (ec, false);
ec.Emit (OpCodes.Ldlen);
ec.Emit (OpCodes.Conv_I4);
return;
}
- Invocation.EmitCall (ec, InstanceExpression, Getter, null, loc, prepared, false);
-
- if (leave_copy) {
- ec.Emit (OpCodes.Dup);
- if (!IsStatic) {
- temp = new LocalTemporary (this.Type);
- temp.Store (ec);
- }
- }
+ base.Emit (ec, leave_copy);
}
- public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
+ public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
{
Arguments args;
+ LocalTemporary await_source_arg = null;
- if (prepare_for_load && !(source is DynamicExpressionStatement)) {
- args = new Arguments (0);
- prepared = true;
+ if (isCompound && !(source is DynamicExpressionStatement)) {
+ emitting_compound_assignment = true;
source.Emit (ec);
-
- if (leave_copy) {
- ec.Emit (OpCodes.Dup);
- if (!IsStatic) {
+
+ if (has_await_arguments) {
+ await_source_arg = new LocalTemporary (Type);
+ await_source_arg.Store (ec);
+
+ args = new Arguments (1);
+ args.Add (new Argument (await_source_arg));
+
+ if (leave_copy) {
+ temp = await_source_arg;
+ }
+
+ has_await_arguments = false;
+ } else {
+ args = null;
+
+ if (leave_copy) {
+ ec.Emit (OpCodes.Dup);
temp = new LocalTemporary (this.Type);
temp.Store (ec);
}
}
}
- Invocation.EmitCall (ec, InstanceExpression, Setter, args, loc, false, prepared);
-
+ emitting_compound_assignment = false;
+
+ var call = new CallEmitter ();
+ call.InstanceExpression = InstanceExpression;
+ if (args == null)
+ call.InstanceExpressionOnStack = true;
+
+ call.Emit (ec, Setter, args, loc);
+
if (temp != null) {
temp.Emit (ec);
temp.Release (ec);
}
+
+ if (await_source_arg != null) {
+ await_source_arg.Release (ec);
+ }
}
protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
{
eclass = ExprClass.PropertyAccess;
- if (best_candidate.IsNotRealProperty) {
+ if (best_candidate.IsNotCSharpCompatible) {
Error_PropertyNotValid (rc);
}
public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
{
- Error_TypeArgumentsCannotBeUsed (ec.Report, "property", GetSignatureForError (), loc);
+ Error_TypeArgumentsCannotBeUsed (ec, "property", GetSignatureForError (), loc);
}
}
protected T best_candidate;
protected LocalTemporary temp;
- protected bool prepared;
+ protected bool emitting_compound_assignment;
+ protected bool has_await_arguments;
protected PropertyOrIndexerExpr (Location l)
{
#region Properties
+ protected abstract Arguments Arguments { get; set; }
+
public MethodSpec Getter {
get {
return getter;
// if the property/indexer returns a value type, and we try to set a field in it
if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
- Error_CannotModifyIntermediateExpressionValue (ec);
+ Error_ValueAssignment (ec, right_side);
}
if (eclass == ExprClass.Unresolved) {
//
// Implements the IAssignMethod interface for assignments
//
- public abstract void Emit (EmitContext ec, bool leave_copy);
- public abstract void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load);
+ public virtual void Emit (EmitContext ec, bool leave_copy)
+ {
+ var call = new CallEmitter ();
+ call.InstanceExpression = InstanceExpression;
+ if (has_await_arguments)
+ call.HasAwaitArguments = true;
+ else
+ call.DuplicateArguments = emitting_compound_assignment;
+
+ call.Emit (ec, Getter, Arguments, loc);
+
+ if (call.HasAwaitArguments) {
+ InstanceExpression = call.InstanceExpression;
+ Arguments = call.EmittedArguments;
+ has_await_arguments = true;
+ }
+
+ if (leave_copy) {
+ ec.Emit (OpCodes.Dup);
+ temp = new LocalTemporary (Type);
+ temp.Store (ec);
+ }
+ }
+
+ public abstract void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound);
public override void Emit (EmitContext ec)
{
Emit (ec, false);
}
+ protected override void EmitToFieldSource (EmitContext ec)
+ {
+ has_await_arguments = true;
+ Emit (ec, false);
+ }
+
public abstract SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source);
protected abstract Expression OverloadResolve (ResolveContext rc, Expression right_side);
throw new NotImplementedException ();
}
- public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
+ public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
{
- if (leave_copy || !prepare_for_load)
+ if (leave_copy || !isCompound)
throw new NotImplementedException ("EventExpr::EmitAssign");
Arguments args = new Arguments (1);
args.Add (new Argument (source));
- Invocation.EmitCall (ec, InstanceExpression, op, args, loc);
+
+ var call = new CallEmitter ();
+ call.InstanceExpression = InstanceExpression;
+ call.Emit (ec, op, args, loc);
}
#endregion
public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
{
- Error_TypeArgumentsCannotBeUsed (ec.Report, "event", GetSignatureForError (), loc);
+ Error_TypeArgumentsCannotBeUsed (ec, "event", GetSignatureForError (), loc);
}
}
return new TemporaryVariableReference (li, loc);
}
- public override Expression CreateExpressionTree (ResolveContext ec)
- {
- throw new NotSupportedException ("ET");
- }
-
protected override Expression DoResolve (ResolveContext ec)
{
eclass = ExprClass.Variable;
//
// Don't capture temporary variables except when using
- // iterator redirection
+ // state machine redirection
//
- if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod.IsIterator && ec.IsVariableCapturingRequired) {
+ if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod is StateMachineInitializer && ec.IsVariableCapturingRequired) {
AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
storey.CaptureLocalVariable (ec, li);
}
}
public override VariableInfo VariableInfo {
- get { throw new NotImplementedException (); }
+ get { return null; }
+ }
+
+ public override void VerifyAssigned (ResolveContext rc)
+ {
}
}