protected bool IsNullableValueAccess(EXPR pExpr, EXPR pObject) { Debug.Assert(pExpr != null); return pExpr.isPROP() && (pExpr.asPROP().GetMemberGroup().GetOptionalObject() == pObject) && pObject.type.IsNullableType(); }
private EXPR ReorderArgumentsForNamedAndOptional(EXPR callingObject, EXPR pResult) { EXPR arguments; AggregateType type; MethodOrPropertySymbol methprop; EXPRMEMGRP memgroup; TypeArray typeArgs; if (pResult.isCALL()) { EXPRCALL call = pResult.asCALL(); arguments = call.GetOptionalArguments(); type = call.mwi.Ats; methprop = call.mwi.Meth(); memgroup = call.GetMemberGroup(); typeArgs = call.mwi.TypeArgs; } else { Debug.Assert(pResult.isPROP()); EXPRPROP prop = pResult.asPROP(); arguments = prop.GetOptionalArguments(); type = prop.pwtSlot.Ats; methprop = prop.pwtSlot.Prop(); memgroup = prop.GetMemberGroup(); typeArgs = null; } ArgInfos argInfo = new ArgInfos(); bool b; argInfo.carg = ExpressionBinder.CountArguments(arguments, out b); _binder.FillInArgInfoFromArgList(argInfo, arguments); // We need to substitute type parameters BEFORE getting the most derived one because // we're binding against the base method, and the derived method may change the // generic arguments. TypeArray parameters = SymbolLoader.GetTypeManager().SubstTypeArray(methprop.Params, type, typeArgs); methprop = ExpressionBinder.GroupToArgsBinder.FindMostDerivedMethod(SymbolLoader, methprop, callingObject.type); ExpressionBinder.GroupToArgsBinder.ReOrderArgsForNamedArguments( methprop, parameters, type, memgroup, argInfo, _semanticChecker.GetTypeManager(), _exprFactory, SymbolLoader); { EXPR pList = null; // We reordered, so make a new list of them and set them on the constructor. // Go backwards cause lists are right-flushed. // Also perform the conversions to the right types. for (int i = argInfo.carg - 1; i >= 0; i--) { EXPR pArg = argInfo.prgexpr[i]; // Strip the name-ness away, since we don't need it. pArg = StripNamedArgument(pArg); // Perform the correct conversion. pArg = _binder.tryConvert(pArg, parameters[i]); if (pList == null) { pList = pArg; } else { pList = _exprFactory.CreateList(pArg, pList); } } if (pResult.isCALL()) { pResult.asCALL().SetOptionalArguments(pList); } else { pResult.asPROP().SetOptionalArguments(pList); } } return pResult; }
// 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; } }
//////////////////////////////////////////////////////////////////////////////// // A false return means not to process the expr any further - it's totally out // of place. For example - a method group or an anonymous method. internal bool checkLvalue(EXPR expr, CheckLvalueKind kind) { if (!expr.isOK()) return false; if (expr.isLvalue()) { if (expr.isPROP()) { CheckLvalueProp(expr.asPROP()); } markFieldAssigned(expr); return true; } switch (expr.kind) { case ExpressionKind.EK_PROP: if (kind == CheckLvalueKind.OutParameter) { // passing a property as ref or out ErrorContext.Error(ErrorCode.ERR_RefProperty); return true; } if (!expr.asPROP().mwtSet) { // Assigning to a property without a setter. // If we have // bool? b = true; (bool)b = false; // then this is realized immediately as // b.Value = false; // and no ExpressionKind.EK_CAST is generated. We'd rather not give a "you're writing // to a read-only property" error in the case where the property access // is not explicit in the source code. Fortunately in this case the // cast is still hanging around in the parse tree, so we can look for it. // POSSIBLE ERROR: It would be nice to also give this error for other situations // POSSIBLE ERROR: in which the user is attempting to assign to a value, such as // POSSIBLE ERROR: an explicit (bool)b.Value = false; // POSSIBLE ERROR: Unfortunately we cannot use this trick in that situation because // POSSIBLE ERROR: we've already discarded the OperatorKind.OP_CAST node. (This is an SyntaxKind.Dot). // SPEC VIOLATION: More generally: // SPEC VIOLATION: The spec states that the result of any cast is a value, not a // SPEC VIOLATION: variable. Unfortunately we do not correctly implement this // SPEC VIOLATION: and we probably should not start implementing it because this // SPEC VIOLATION: would be a breaking change. We currently discard "no op" casts // SPEC VIOLATION: very aggressively rather than generating an ExpressionKind.EK_CAST node. ErrorContext.Error(ErrorCode.ERR_AssgReadonlyProp, expr.asPROP().pwtSlot); return true; } break; case ExpressionKind.EK_ARRAYLENGTH: if (kind == CheckLvalueKind.OutParameter) { // passing a property as ref or out ErrorContext.Error(ErrorCode.ERR_RefProperty); } else { // Special case, the length property of an array ErrorContext.Error(ErrorCode.ERR_AssgReadonlyProp, GetSymbolLoader().getPredefinedMembers().GetProperty(PREDEFPROP.PP_ARRAY_LENGTH)); } return true; case ExpressionKind.EK_BOUNDLAMBDA: case ExpressionKind.EK_UNBOUNDLAMBDA: case ExpressionKind.EK_CONSTANT: ErrorContext.Error(GetStandardLvalueError(kind)); return false; case ExpressionKind.EK_MEMGRP: { ErrorCode err = (kind == CheckLvalueKind.OutParameter) ? ErrorCode.ERR_RefReadonlyLocalCause : ErrorCode.ERR_AssgReadonlyLocalCause; ErrorContext.Error(err, expr.asMEMGRP().name, new ErrArgIds(MessageID.MethodGroup)); return false; } default: break; } return !TryReportLvalueFailure(expr, kind); }