private static bool CanCastToClass(this TypeDesc thisType, TypeDesc otherType, StackOverflowProtect protect) { TypeDesc curType = thisType; if (curType.IsInterface && otherType.IsObject) { return(true); } // If the target type has variant type parameters, we take a slower path if (curType.HasVariance) { // First chase inheritance hierarchy until we hit a class that only differs in its instantiation do { if (curType == otherType) { return(true); } if (curType.CanCastByVarianceToInterfaceOrDelegate(otherType, protect)) { return(true); } curType = curType.BaseType; }while (curType != null); } else { // If there are no variant type parameters, just chase the hierarchy // Allow curType to be nullable, which means this method // will additionally return true if curType is Nullable<T> && ( // currType == otherType // OR otherType is System.ValueType or System.Object) // Always strip Nullable from the otherType, if present if (otherType.IsNullable && !curType.IsNullable) { return(thisType.CanCastTo(otherType.Instantiation[0])); } do { if (curType == otherType) { return(true); } curType = curType.BaseType; } while (curType != null); } return(false); }
private static bool VerifyGenericParamConstraint(InstantiationContext genericParamContext, GenericParameterDesc genericParam, InstantiationContext instantiationParamContext, TypeDesc instantiationParam) { GenericConstraints constraints = genericParam.Constraints; // Check class constraint if ((constraints & GenericConstraints.ReferenceTypeConstraint) != 0) { if (!instantiationParam.IsGCPointer && !CheckGenericSpecialConstraint(instantiationParam, GenericConstraints.ReferenceTypeConstraint)) { return(false); } } // Check default constructor constraint if ((constraints & GenericConstraints.DefaultConstructorConstraint) != 0) { if (!instantiationParam.HasExplicitOrImplicitDefaultConstructor() && !CheckGenericSpecialConstraint(instantiationParam, GenericConstraints.DefaultConstructorConstraint)) { return(false); } } // Check struct constraint if ((constraints & GenericConstraints.NotNullableValueTypeConstraint) != 0) { if ((!instantiationParam.IsValueType || instantiationParam.IsNullable) && !CheckGenericSpecialConstraint(instantiationParam, GenericConstraints.NotNullableValueTypeConstraint)) { return(false); } } var instantiatedConstraints = new ArrayBuilder <TypeDesc>(); GetInstantiatedConstraintsRecursive(instantiationParamContext, instantiationParam, ref instantiatedConstraints); foreach (var constraintType in genericParam.TypeConstraints) { var instantiatedType = constraintType.InstantiateSignature(genericParamContext.TypeInstantiation, genericParamContext.MethodInstantiation); if (CanCastConstraint(ref instantiatedConstraints, instantiatedType)) { continue; } if (!instantiationParam.CanCastTo(instantiatedType)) { return(false); } } return(true); }
private static bool VerifyGenericParamConstraint(Instantiation typeInstantiation, Instantiation methodInstantiation, GenericParameterDesc genericParam, TypeDesc instantiationParam) { // Check class constraint if (genericParam.HasReferenceTypeConstraint && !instantiationParam.IsGCPointer) { return(false); } // Check default constructor constraint if (genericParam.HasDefaultConstructorConstraint) { if (!instantiationParam.IsDefType) { return(false); } if (!instantiationParam.IsValueType && instantiationParam.GetDefaultConstructor() == null) { return(false); } } // Check struct constraint if (genericParam.HasNotNullableValueTypeConstraint) { if (!instantiationParam.IsValueType) { return(false); } if (instantiationParam.IsNullable) { return(false); } } foreach (var constraintType in genericParam.TypeConstraints) { var instantiatedType = constraintType.InstantiateSignature(typeInstantiation, methodInstantiation); if (!instantiationParam.CanCastTo(instantiatedType)) { return(false); } } return(true); }
/// <summary> /// Checks if two types are compatible according to compatible-with as described in ECMA 335 I.8.7.1 /// Most of the checks are performed by the CanCastTo, but some cases are pre-filtered out. /// </summary> public static bool IsCompatibleWith(this TypeDesc thisType, TypeDesc otherType) { // Structs can be cast to the interfaces they implement, but they are not compatible according to ECMA I.8.7.1 bool isCastFromValueTypeToReferenceType = otherType.IsValueType && !thisType.IsValueType; if (isCastFromValueTypeToReferenceType) { return(false); } // Managed pointers are compatible only if they are pointer-element-compatible-with as described in ECMA I.8.7.2 if (thisType.IsByRef && otherType.IsByRef) { return(AreVerificationTypesEqual(thisType.GetParameterType(), otherType.GetParameterType())); } // Unmanaged pointers are handled the same way as managed pointers if (thisType.IsPointer && otherType.IsPointer) { return(AreVerificationTypesEqual(thisType.GetParameterType(), otherType.GetParameterType())); } // Function pointers are compatible only if they are method-signature-compatible-with as described in ECMA I.8.7.1 if (thisType.IsFunctionPointer && otherType.IsFunctionPointer) { return(IsMethodSignatureCompatibleWith(thisType, otherType)); } // None of the types can be a managed pointer, a pointer or a function pointer here, // all the valid cases were handled above. if (thisType.IsByRef || otherType.IsByRef || thisType.IsPointer || otherType.IsPointer || thisType.IsFunctionPointer || otherType.IsFunctionPointer) { return(false); } // Nullable<T> can be cast to T, but this is not compatible according to ECMA I.8.7.1 bool isCastFromNullableOfTtoT = thisType.IsNullable && otherType.IsEquivalentTo(thisType.Instantiation[0]); if (isCastFromNullableOfTtoT) { return(false); } return(otherType.CanCastTo(thisType)); }
private static bool VerifyGenericParamConstraint(Instantiation typeInstantiation, Instantiation methodInstantiation, GenericParameterDesc genericParam, TypeDesc instantiationParam) { GenericConstraints constraints = genericParam.Constraints; // Check class constraint if ((constraints & GenericConstraints.ReferenceTypeConstraint) != 0) { if (!instantiationParam.IsGCPointer) { return(false); } } // Check default constructor constraint if ((constraints & GenericConstraints.DefaultConstructorConstraint) != 0) { if (!instantiationParam.HasExplicitOrImplicitDefaultConstructor()) { return(false); } } // Check struct constraint if ((constraints & GenericConstraints.NotNullableValueTypeConstraint) != 0) { if (!instantiationParam.IsValueType) { return(false); } if (instantiationParam.IsNullable) { return(false); } } foreach (var constraintType in genericParam.TypeConstraints) { var instantiatedType = constraintType.InstantiateSignature(typeInstantiation, methodInstantiation); if (!instantiationParam.CanCastTo(instantiatedType)) { return(false); } } return(true); }
public static bool IsCompatibleWith(this TypeDesc thisType, TypeDesc otherType) { // Structs can be cast to the interfaces they implement, but they are not compatible according to ECMA I.8.7.1 bool isCastFromValueTypeToReferenceType = otherType.IsValueType && !thisType.IsValueType; if (isCastFromValueTypeToReferenceType) { return(false); } // Nullable<T> can be cast to T, but this is not compatible according to ECMA I.8.7.1 bool isCastFromNullableOfTtoT = thisType.IsNullable && otherType.IsEquivalentTo(thisType.Instantiation[0]); if (isCastFromNullableOfTtoT) { return(false); } return(otherType.CanCastTo(thisType)); }