// Return true if we actually report a failure. private 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().MethWithTypeSet != null); pObject = walk.asPROP().MemberGroup.OptionalObject; } else if (walk.isFIELD()) { ExprField field = walk.asFIELD(); if (field.FieldWithType.Field().isReadOnly) { ReportReadOnlyError(field, kind, isNested); return(true); } if (!field.FieldWithType.Field().isStatic) { pObject = field.OptionalObject; } } 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; } }