protected virtual EXPR GenerateQuestionMarkOperand(EXPR pExpr) { Debug.Assert(pExpr != null); // We must not optimize away compiler-generated reference casts because // the expression tree API insists that the CType of both sides be identical. if (pExpr.isCAST()) { return GenerateConversion(pExpr.asCAST().GetArgument(), pExpr.type, pExpr.isChecked()); } return Visit(pExpr); }
// 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 object GetObject(EXPR pExpr) { if (pExpr.isCAST()) { return GetObject(pExpr.asCAST().GetArgument()); } else if (pExpr.isTYPEOF()) { return pExpr.asTYPEOF().SourceType.type.AssociatedSystemType; } else if (pExpr.isMETHODINFO()) { return GetMethodInfoFromExpr(pExpr.asMETHODINFO()); } else if (pExpr.isCONSTANT()) { CONSTVAL val = pExpr.asCONSTANT().Val; CType underlyingType = pExpr.type; object objval; if (pExpr.type.IsNullType()) { return null; } if (pExpr.type.isEnumType()) { underlyingType = underlyingType.getAggregate().GetUnderlyingType(); } switch (underlyingType.AssociatedSystemType.GetTypeCode()) { case TypeCode.Boolean: objval = val.boolVal; break; case TypeCode.SByte: objval = val.sbyteVal; break; case TypeCode.Byte: objval = val.byteVal; break; case TypeCode.Int16: objval = val.shortVal; break; case TypeCode.UInt16: objval = val.ushortVal; break; case TypeCode.Int32: objval = val.iVal; break; case TypeCode.UInt32: objval = val.uiVal; break; case TypeCode.Int64: objval = val.longVal; break; case TypeCode.UInt64: objval = val.ulongVal; break; case TypeCode.Single: objval = val.floatVal; break; case TypeCode.Double: objval = val.doubleVal; break; case TypeCode.Decimal: objval = val.decVal; break; case TypeCode.Char: objval = val.cVal; break; case TypeCode.String: objval = val.strVal; break; default: objval = val.objectVal; break; } if (pExpr.type.isEnumType()) { objval = Enum.ToObject(pExpr.type.AssociatedSystemType, objval); } return objval; } else if (pExpr.isZEROINIT()) { if (pExpr.asZEROINIT().OptionalArgument != null) { return GetObject(pExpr.asZEROINIT().OptionalArgument); } return System.Activator.CreateInstance(pExpr.type.AssociatedSystemType); } Debug.Assert(false, "Invalid EXPR in GetObject"); throw Error.InternalCompilerError(); }
//////////////////////////////////////////////////////////////////////////////// // Bind the simple assignment operator =. public EXPR bindAssignment(EXPR op1, EXPR op2, bool allowExplicit) { bool fOp2NotAddrOp = false; bool fOp2WasCast = false; if (!op1.isANYLOCAL_OK()) { if (!checkLvalue(op1, CheckLvalueKind.Assignment)) { EXPR rval = GetExprFactory().CreateAssignment(op1, op2); rval.SetError(); return rval; } } else { if (op2.type.IsArrayType()) { return BindPtrToArray(op1.asANYLOCAL(), op2); } if (op2.type == GetReqPDT(PredefinedType.PT_STRING)) { op2 = bindPtrToString(op2); } else if (op2.kind == ExpressionKind.EK_ADDR) { op2.flags |= EXPRFLAG.EXF_ADDRNOCONV; } else if (op2.isOK()) { fOp2NotAddrOp = true; fOp2WasCast = (op2.isCAST()); } } op2 = GenerateAssignmentConversion(op1, op2, allowExplicit); if (op2.isOK() && fOp2NotAddrOp) { // Only report these errors if the convert succeeded if (fOp2WasCast) { ErrorContext.Error(ErrorCode.ERR_BadCastInFixed); } else { ErrorContext.Error(ErrorCode.ERR_FixedNotNeeded); } } return GenerateOptimizedAssignment(op1, op2); }
/* Handles enum unary operator (~). */ private EXPR BindEnumUnaOp(ExpressionKind ek, EXPRFLAG flags, EXPR arg) { Debug.Assert(ek == ExpressionKind.EK_BITNOT); Debug.Assert(arg.isCAST()); Debug.Assert(arg.asCAST().GetArgument().type.isEnumType()); PredefinedType ptOp; CType typeEnum = arg.asCAST().GetArgument().type; switch (typeEnum.fundType()) { default: // Promote all smaller types to int. ptOp = PredefinedType.PT_INT; break; case FUNDTYPE.FT_U4: ptOp = PredefinedType.PT_UINT; break; case FUNDTYPE.FT_I8: ptOp = PredefinedType.PT_LONG; break; case FUNDTYPE.FT_U8: ptOp = PredefinedType.PT_ULONG; break; } CType typeOp = GetReqPDT(ptOp); arg = mustCast(arg, typeOp, CONVERTTYPE.NOUDC); EXPR exprRes = BindIntOp(ek, flags, arg, null, ptOp); if (!exprRes.isOK()) { return exprRes; } return mustCastInUncheckedContext(exprRes, typeEnum, CONVERTTYPE.NOUDC); }