//
// Copyright 2001, 2002, 2003 Ximian, Inc.
// Copyright 2003-2008 Novell, Inc.
+// Copyright 2011 Xamarin Inc.
//
//
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)
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;
}
//
// Store the result to temporary field when we
- // cannot load this directly
+ // cannot load `this' directly
//
var field = ec.GetTemporaryField (type);
if (needs_temporary) {
//
- // Create temporary local (we cannot load this before Emit)
+ // Create temporary local (we cannot load `this' before Emit)
//
var temp = ec.GetTemporaryLocal (type);
ec.Emit (OpCodes.Stloc, temp);
}
var r = new OverloadResolver (ctors, OverloadResolver.Restrictions.NoBaseMembers, loc);
- var ctor = r.ResolveMember<MethodSpec> (rc, ref args);
- if (ctor == null)
- return null;
-
- if ((ctor.Modifiers & Modifiers.PROTECTED) != 0 && !rc.HasSet (ResolveContext.Options.BaseInitializer)) {
- MemberExpr.CheckProtectedMemberAccess (rc, ctor, ctor.DeclaringType, loc);
+ if (!rc.HasSet (ResolveContext.Options.BaseInitializer)) {
+ r.InstanceQualifier = new ConstructorInstanceQualifier (type);
}
- return ctor;
+ return r.ResolveMember<MethodSpec> (rc, ref args);
}
[Flags]
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;
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.
//
{
throw new NotImplementedException ("MakeExpression for " + GetType ());
}
+
+ public virtual object Accept (StructuralVisitor visitor)
+ {
+ return visitor.Visit (this);
+ }
}
/// <summary>
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
return new SimpleName (Name, targs, loc);
}
- protected override Expression DoResolve (ResolveContext ec)
+ protected override Expression DoResolve (ResolveContext rc)
{
- return SimpleNameResolve (ec, null, false);
+ 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)
//if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
return e;
}
+
+ public override object Accept (StructuralVisitor visitor)
+ {
+ return visitor.Visit (this);
+ }
}
/// <summary>
/// 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;
}
+ TypeSpec OverloadResolver.IInstanceQualifier.InstanceType {
+ get {
+ return InstanceExpression.Type;
+ }
+ }
+
//
// Converts best base candidate for virtual method starting from QueriedBaseType
//
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)) {
- CheckProtectedMemberAccess (rc, member, InstanceExpression.Type, loc);
+ if (!CheckProtectedMemberAccess (rc, member, InstanceExpression.Type)) {
+ Error_ProtectedMemberAccess (rc, member, InstanceExpression.Type, loc);
+ }
}
}
- public static void CheckProtectedMemberAccess<T> (ResolveContext rc, T member, TypeSpec qualifier, Location loc) where T : MemberSpec
+ bool OverloadResolver.IInstanceQualifier.CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
+ {
+ if (InstanceExpression == null)
+ return true;
+
+ 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;
+ return true;
if ((member.Modifiers & Modifiers.INTERNAL) != 0 && member.DeclaringType.MemberDefinition.IsInternalAsPublic (ct.MemberDefinition.DeclaringAssembly))
- return;
+ return true;
qualifier = qualifier.GetDefinition ();
if (ct != qualifier && !IsSameOrBaseQualifier (ct, qualifier)) {
- 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 (), ct.GetSignatureForError ());
+ return false;
}
+
+ return true;
}
public override bool ContainsEmitWithAwait ()
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
//
"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");
}
if (InstanceExpression is IMemoryLocation) {
((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);
t.AddressOf (ec, AddressOp.Store);
- t.Release (ec);
}
} else {
InstanceExpression.Emit (ec);
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);
#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;
// better conversion is performed between underlying types Y1 and Y2
//
if (p.IsGenericTask || q.IsGenericTask) {
- if (p.IsGenericTask != q.IsGenericTask) {
- return 0;
- }
-
var async_am = a.Expr as AnonymousMethodExpression;
- if (async_am == null || !async_am.IsAsync)
- return 0;
+ if (async_am != null && async_am.Block.IsAsync) {
- q = q.TypeArguments[0];
- p = p.TypeArguments[0];
+ if (p.IsGenericTask != q.IsGenericTask) {
+ return 0;
+ }
+
+ q = q.TypeArguments[0];
+ p = p.TypeArguments[0];
+ }
}
//
// 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
//
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;
}
+
+ 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 override string GetSignatureForError ()
{
- return TypeManager.GetFullNameSignature (spec);
+ return spec.GetSignatureForError ();
}
public bool IsMarshalByRefAccess (ResolveContext rc)
public void SetHasAddressTaken ()
{
IVariableReference vr = InstanceExpression as IVariableReference;
- if (vr != null)
+ if (vr != null) {
vr.SetHasAddressTaken ();
+ }
}
public override Expression CreateExpressionTree (ResolveContext ec)
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) {
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 ();
#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);
}
// 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) {
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)
+ {
}
}