// Return true if we actually report a failure.
protected bool TryReportLvalueFailure(EXPR expr, CheckLvalueKind kind)
{
Debug.Assert(expr != null);
// We have a lvalue failure. Was the reason because this field
// was marked readonly? Give special messages for this case.
bool isNested = false; // Did we recurse on a field or property to give a better error?
EXPR walk = expr;
while (true)
{
Debug.Assert(walk != null);
if (walk.isANYLOCAL_OK())
{
ReportLocalError(walk.asANYLOCAL().local, kind, isNested);
return(true);
}
EXPR pObject = null;
if (walk.isPROP())
{
// We've already reported read-only-property errors.
Debug.Assert(walk.asPROP().mwtSet != null);
pObject = walk.asPROP().GetMemberGroup().GetOptionalObject();
}
else if (walk.isFIELD())
{
EXPRFIELD field = walk.asFIELD();
if (field.fwt.Field().isReadOnly)
{
ReportReadOnlyError(field, kind, isNested);
return(true);
}
if (!field.fwt.Field().isStatic)
{
pObject = field.GetOptionalObject();
}
}
if (pObject != null && pObject.type.isStructOrEnum())
{
if (pObject.isCALL() || pObject.isPROP())
{
// assigning to RHS of method or property getter returning a value-type on the stack or
// passing RHS of method or property getter returning a value-type on the stack, as ref or out
ErrorContext.Error(ErrorCode.ERR_ReturnNotLValue, pObject.GetSymWithType());
return(true);
}
if (pObject.isCAST())
{
// An unboxing conversion.
//
// In the static compiler, we give the following error here:
// ErrorContext.Error(pObject.GetTree(), ErrorCode.ERR_UnboxNotLValue);
//
// But in the runtime, we allow this - mark that we're doing an
// unbox here, so that we gen the correct expression tree for it.
pObject.flags |= EXPRFLAG.EXF_UNBOXRUNTIME;
return(false);
}
}
// everything else
if (pObject != null && !pObject.isLvalue() && (walk.isFIELD() || (!isNested && walk.isPROP())))
{
Debug.Assert(pObject.type.isStructOrEnum());
walk = pObject;
}
else
{
ErrorContext.Error(GetStandardLvalueError(kind));
return(true);
}
isNested = true;
}
}