//////////////////////////////////////////////////////////////////////////////// // Sets the isAssigned bit protected void markFieldAssigned(EXPR expr) { if (expr.isFIELD() && 0 != (expr.flags & EXPRFLAG.EXF_LVALUE)) { EXPRFIELD field; do { field = expr.asFIELD(); field.fwt.Field().isAssigned = true; expr = field.GetOptionalObject(); } while (field.fwt.Field().getClass().IsStruct() && !field.fwt.Field().isStatic && expr != null && expr.isFIELD()); } }
// 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; } }
private EXPR AdjustMemberObject(SymWithType swt, EXPR pObject, out bool pfConstrained, out bool pIsMatchingStatic) { // Assert that the type is present and is an instantiation of the member's parent. Debug.Assert(swt.GetType() != null && swt.GetType().getAggregate() == swt.Sym.parent.AsAggregateSymbol()); bool bIsMatchingStatic = IsMatchingStatic(swt, pObject); pIsMatchingStatic = bIsMatchingStatic; pfConstrained = false; bool isStatic = swt.Sym.isStatic; // If our static doesn't match, bail out of here. if (!bIsMatchingStatic) { if (isStatic) { // If we have a mismatched static, a static method, and the binding flag // that tells us we're binding simple names, then insert a type here instead. if ((pObject.flags & EXPRFLAG.EXF_SIMPLENAME) != 0) { // We've made the static match now. pIsMatchingStatic = true; return null; } else { ErrorContext.ErrorRef(ErrorCode.ERR_ObjectProhibited, swt); return null; } } else { ErrorContext.ErrorRef(ErrorCode.ERR_ObjectRequired, swt); return pObject; } } // At this point, all errors for static invocations have been reported, and // the object has been nulled out. So return out of here. if (isStatic) { return null; } // If we're in a constructor, then bail. if (swt.Sym.IsMethodSymbol() && swt.Meth().IsConstructor()) { return pObject; } if (pObject == null) { if (InFieldInitializer() && !InStaticMethod() && ContainingAgg() == swt.Sym.parent) { ErrorContext.ErrorRef(ErrorCode.ERR_FieldInitRefNonstatic, swt); // give better error message for common mistake <BUGNUM>See VS7:119218</BUGNUM> } else if (InAnonymousMethod() && !InStaticMethod() && ContainingAgg() == swt.Sym.parent && ContainingAgg().IsStruct()) { ErrorContext.Error(ErrorCode.ERR_ThisStructNotInAnonMeth); } else { return null; } // For fields or structs, make a this pointer for us to use. EXPRTHISPOINTER thisExpr = GetExprFactory().CreateThis(Context.GetThisPointer(), true); thisExpr.SetMismatchedStaticBit(); if (thisExpr.type == null) { thisExpr.setType(GetTypes().GetErrorSym()); } return thisExpr; } CType typeObj = pObject.type; CType typeTmp; if (typeObj.IsNullableType() && (typeTmp = typeObj.AsNullableType().GetAts(GetErrorContext())) != null && typeTmp != swt.GetType()) { typeObj = typeTmp; } if (typeObj.IsTypeParameterType() || typeObj.IsAggregateType()) { AggregateSymbol aggCalled = null; aggCalled = swt.Sym.parent.AsAggregateSymbol(); Debug.Assert(swt.GetType().getAggregate() == aggCalled); // If we're invoking code on a struct-valued field, mark the struct as assigned (to // avoid warning CS0649). if (pObject.isFIELD() && !pObject.asFIELD().fwt.Field().isAssigned && !swt.Sym.IsFieldSymbol() && typeObj.isStructType() && !typeObj.isPredefined()) { pObject.asFIELD().fwt.Field().isAssigned = true; } if (pfConstrained && (typeObj.IsTypeParameterType() || typeObj.isStructType() && swt.GetType().IsRefType() && swt.Sym.IsVirtual())) { // For calls on type parameters or virtual calls on struct types (not enums), // use the constrained prefix. pfConstrained = true; } EXPR objNew = tryConvert(pObject, swt.GetType(), CONVERTTYPE.NOUDC); // This check ensures that we do not bind to methods in an outer class // which are visible, but whose this pointer is of an incorrect type... // ... also handles case of calling an pObject method on a RefAny value. // WE don't give a great message for this, but it'll do. if (objNew == null) { if (!pObject.type.isSpecialByRefType()) { ErrorContext.Error(ErrorCode.ERR_WrongNestedThis, swt.GetType(), pObject.type); } else { ErrorContext.Error(ErrorCode.ERR_NoImplicitConv, pObject.type, swt.GetType()); } } pObject = objNew; } return pObject; }