public SubstTypeArray ( |
||
taSrc | ||
atsCls | ||
Résultat |
private static bool CheckSingleConstraint(Symbol symErr, TypeParameterType var, CType arg, TypeArray typeArgsCls, TypeArray typeArgsMeth, CheckConstraintsFlags flags) { Debug.Assert(!(arg is PointerType)); Debug.Assert(!arg.IsStaticClass); bool fReportErrors = 0 == (flags & CheckConstraintsFlags.NoErrors); if (var.HasRefConstraint && !arg.IsReferenceType) { if (fReportErrors) { throw ErrorHandling.Error(ErrorCode.ERR_RefConstraintNotSatisfied, symErr, new ErrArgNoRef(var), arg); } return(false); } TypeArray bnds = TypeManager.SubstTypeArray(var.Bounds, typeArgsCls, typeArgsMeth); int itypeMin = 0; if (var.HasValConstraint) { // If we have a type variable that is constrained to a value type, then we // want to check if its a nullable type, so that we can report the // constraint error below. In order to do this however, we need to check // that either the type arg is not a value type, or it is a nullable type. // // To check whether or not its a nullable type, we need to get the resolved // bound from the type argument and check against that. if (!arg.IsNonNullableValueType) { if (fReportErrors) { throw ErrorHandling.Error(ErrorCode.ERR_ValConstraintNotSatisfied, symErr, new ErrArgNoRef(var), arg); } return(false); } // Since FValCon() is set it is redundant to check System.ValueType as well. if (bnds.Count != 0 && bnds[0].IsPredefType(PredefinedType.PT_VALUE)) { itypeMin = 1; } } for (int j = itypeMin; j < bnds.Count; j++) { CType typeBnd = bnds[j]; if (!SatisfiesBound(arg, typeBnd)) { if (fReportErrors) { // The bound isn't satisfied because of a constraint type. Explain to the user why not. // There are 4 main cases, based on the type of the supplied type argument: // - reference type, or type parameter known to be a reference type // - nullable type, from which there is a boxing conversion to the constraint type(see below for details) // - type variable // - value type // These cases are broken out because: a) The sets of conversions which can be used // for constraint satisfaction is different based on the type argument supplied, // and b) Nullable is one funky type, and user's can use all the help they can get // when using it. ErrorCode error; if (arg.IsReferenceType) { // A reference type can only satisfy bounds to types // to which they have an implicit reference conversion error = ErrorCode.ERR_GenericConstraintNotSatisfiedRefType; } else if (arg is NullableType nubArg && SymbolLoader.HasBaseConversion(nubArg.UnderlyingType, typeBnd)) // This is inlining FBoxingConv { // nullable types do not satisfy bounds to every type that they are boxable to // They only satisfy bounds of object and ValueType if (typeBnd.IsPredefType(PredefinedType.PT_ENUM) || nubArg.UnderlyingType == typeBnd) { // Nullable types don't satisfy bounds of EnumType, or the underlying type of the enum // even though the conversion from Nullable to these types is a boxing conversion // This is a rare case, because these bounds can never be directly stated ... // These bounds can only occur when one type paramter is constrained to a second type parameter // and the second type parameter is instantiated with Enum or the underlying type of the first type // parameter error = ErrorCode.ERR_GenericConstraintNotSatisfiedNullableEnum; } else { // Nullable types don't satisfy the bounds of any interface type // even when there is a boxing conversion from the Nullable type to // the interface type. This will be a relatively common scenario // so we cal it out separately from the previous case. Debug.Assert(typeBnd.IsInterfaceType); error = ErrorCode.ERR_GenericConstraintNotSatisfiedNullableInterface; } } else { // Value types can only satisfy bounds through boxing conversions. // Note that the exceptional case of Nullable types and boxing is handled above. error = ErrorCode.ERR_GenericConstraintNotSatisfiedValType; } throw ErrorHandling.Error(error, new ErrArg(symErr), new ErrArg(typeBnd, ErrArgFlags.Unique), var, new ErrArg(arg, ErrArgFlags.Unique)); } return(false); } }
internal static bool ReOrderArgsForNamedArguments( MethodOrPropertySymbol methprop, TypeArray pCurrentParameters, AggregateType pCurrentType, EXPRMEMGRP pGroup, ArgInfos pArguments, TypeManager typeManager, ExprFactory exprFactory, SymbolLoader symbolLoader) { // We use the param count from pCurrentParameters because they may have been resized // for param arrays. int numParameters = pCurrentParameters.size; EXPR[] pExprArguments = new EXPR[numParameters]; // Now go through the parameters. First set all positional arguments in the new argument // set, then for the remainder, look for a named argument with a matching name. int index = 0; EXPR paramArrayArgument = null; TypeArray @params = typeManager.SubstTypeArray( pCurrentParameters, pCurrentType, pGroup.typeArgs); foreach (Name name in methprop.ParameterNames) { // This can happen if we had expanded our param array to size 0. if (index >= pCurrentParameters.size) { break; } // If: // (1) we have a param array method // (2) we're on the last arg // (3) the thing we have is an array init thats generated for param array // then let us through. if (methprop.isParamArray && index < pArguments.carg && pArguments.prgexpr[index].isARRINIT() && pArguments.prgexpr[index].asARRINIT().GeneratedForParamArray) { paramArrayArgument = pArguments.prgexpr[index]; } // Positional. if (index < pArguments.carg && !pArguments.prgexpr[index].isNamedArgumentSpecification() && !(pArguments.prgexpr[index].isARRINIT() && pArguments.prgexpr[index].asARRINIT().GeneratedForParamArray)) { pExprArguments[index] = pArguments.prgexpr[index++]; continue; } // Look for names. EXPR pNewArg = FindArgumentWithName(pArguments, name); if (pNewArg == null) { if (methprop.IsParameterOptional(index)) { pNewArg = GenerateOptionalArgument(symbolLoader, exprFactory, methprop, @params.Item(index), index); } else if (paramArrayArgument != null && index == methprop.Params.Count - 1) { // If we have a param array argument and we're on the last one, then use it. pNewArg = paramArrayArgument; } else { // No name and no default value. return false; } } pExprArguments[index++] = pNewArg; } // Here we've found all the arguments, or have default values for them. CType[] prgTypes = new CType[pCurrentParameters.size]; for (int i = 0; i < numParameters; i++) { if (i < pArguments.prgexpr.Count) { pArguments.prgexpr[i] = pExprArguments[i]; } else { pArguments.prgexpr.Add(pExprArguments[i]); } prgTypes[i] = pArguments.prgexpr[i].type; } pArguments.carg = pCurrentParameters.size; pArguments.types = symbolLoader.getBSymmgr().AllocParams(pCurrentParameters.size, prgTypes); return true; }