private static bool CanCastToInternal(this TypeDesc thisType, TypeDesc otherType, StackOverflowProtect protect) { if (thisType == otherType) { return true; } switch (thisType.Category) { case TypeFlags.GenericParameter: return ((GenericParameterDesc)thisType).CanCastGenericParameterTo(otherType, protect); case TypeFlags.Array: case TypeFlags.SzArray: return ((ArrayType)thisType).CanCastArrayTo(otherType, protect); default: Debug.Assert(thisType.IsDefType); return thisType.CanCastToClassOrInterface(otherType, protect); } }
private static bool CanCastGenericParameterTo(this GenericParameterDesc thisType, TypeDesc otherType, StackOverflowProtect protect) { // A boxed variable type can be cast to any of its constraints, or object, if none are specified if (otherType.IsObject) { return true; } if (thisType.HasNotNullableValueTypeConstraint && otherType.IsWellKnownType(WellKnownType.ValueType)) { return true; } foreach (var typeConstraint in thisType.TypeConstraints) { if (typeConstraint.CanCastToInternal(otherType, protect)) { return true; } } return false; }
private static bool CanCastArrayTo(this ArrayType thisType, TypeDesc otherType, StackOverflowProtect protect) { // Casting the array to one of the base types or interfaces? if (otherType.IsDefType) { return thisType.CanCastToClassOrInterface(otherType, protect); } // Casting array to something else (between SzArray and Array, for example)? if (thisType.Category != otherType.Category) { return false; } ArrayType otherArrayType = (ArrayType)otherType; // Check ranks if we're casting multidim arrays if (!thisType.IsSzArray && thisType.Rank != otherArrayType.Rank) { return false; } return thisType.CanCastParamTo(otherArrayType.ParameterType, protect); }
private static bool CanCastToClassOrInterface(this TypeDesc thisType, TypeDesc otherType, StackOverflowProtect protect) { if (otherType.IsInterface) { return(thisType.CanCastToInterface(otherType, protect)); } else { return(thisType.CanCastToClass(otherType, protect)); } }
private static bool CanCastParamTo(this ParameterizedType thisType, TypeDesc paramType, StackOverflowProtect protect) { // While boxed value classes inherit from object their // unboxed versions do not. Parameterized types have the // unboxed version, thus, if the from type parameter is value // class then only an exact match/equivalence works. if (thisType.ParameterType == paramType) { return(true); } TypeDesc curTypesParm = thisType.ParameterType; // Object parameters don't need an exact match but only inheritance, check for that TypeDesc fromParamUnderlyingType = curTypesParm.UnderlyingType; if (fromParamUnderlyingType.IsGCPointer) { return(curTypesParm.CanCastToInternal(paramType, protect)); } else if (curTypesParm.IsGenericParameter) { var genericVariableFromParam = (GenericParameterDesc)curTypesParm; if (genericVariableFromParam.HasReferenceTypeConstraint) { return(genericVariableFromParam.CanCastToInternal(paramType, protect)); } } else if (fromParamUnderlyingType.IsPrimitive) { TypeDesc toParamUnderlyingType = paramType.UnderlyingType; if (toParamUnderlyingType.IsPrimitive) { if (toParamUnderlyingType == fromParamUnderlyingType) { return(true); } if (ArePrimitveTypesEquivalentSize(fromParamUnderlyingType, toParamUnderlyingType)) { return(true); } } } // Anything else is not a match return(false); }
private static bool CanCastArrayTo(this ArrayType thisType, TypeDesc otherType, StackOverflowProtect protect) { // Casting the array to one of the base types or interfaces? if (otherType.IsDefType) { return(thisType.CanCastToClassOrInterface(otherType, protect)); } // Casting array to something else (between SzArray and Array, for example)? if (thisType.Category != otherType.Category) { // An SzArray is castable to MdArray rank 1. We follow the same casting rules as SzArray to SzArray. if (thisType.Category == TypeFlags.SzArray && otherType.Category == TypeFlags.Array && ((ArrayType)otherType).Rank == 1) { return(thisType.CanCastParamTo(((ArrayType)otherType).ParameterType, protect)); } return(false); } ArrayType otherArrayType = (ArrayType)otherType; // Check ranks if we're casting multidim arrays if (!thisType.IsSzArray && thisType.Rank != otherArrayType.Rank) { return(false); } return(thisType.CanCastParamTo(otherArrayType.ParameterType, protect)); }
private static bool CanCastGenericParameterTo(this GenericParameterDesc thisType, TypeDesc otherType, StackOverflowProtect protect) { // A boxed variable type can be cast to any of its constraints, or object, if none are specified if (otherType.IsObject) { return(true); } if (thisType.HasNotNullableValueTypeConstraint && otherType.IsWellKnownType(WellKnownType.ValueType)) { return(true); } foreach (var typeConstraint in thisType.TypeConstraints) { if (typeConstraint.CanCastToInternal(otherType, protect)) { return(true); } } return(false); }
private static bool CanCastToInterface(this TypeDesc thisType, TypeDesc otherType, StackOverflowProtect protect) { if (!otherType.HasVariance) { return thisType.CanCastToNonVariantInterface(otherType,protect); } else { if (thisType.CanCastByVarianceToInterfaceOrDelegate(otherType, protect)) { return true; } foreach (var interfaceType in thisType.RuntimeInterfaces) { if (interfaceType.CanCastByVarianceToInterfaceOrDelegate(otherType, protect)) { return true; } } } return false; }
private static bool IsBoxedAndCanCastTo(this TypeDesc thisType, TypeDesc otherType, StackOverflowProtect protect) { TypeDesc fromUnderlyingType = thisType.UnderlyingType; if (fromUnderlyingType.IsGCPointer) { return(thisType.CanCastToInternal(otherType, protect)); } else if (thisType.IsGenericParameter) { var genericVariableFromParam = (GenericParameterDesc)thisType; if (genericVariableFromParam.HasReferenceTypeConstraint) { return(genericVariableFromParam.CanCastToInternal(otherType, protect)); } } return(false); }
private static bool CanCastByVarianceToInterfaceOrDelegate(this TypeDesc thisType, TypeDesc otherType, StackOverflowProtect protectInput) { if (!thisType.HasSameTypeDefinition(otherType)) { return(false); } var stackOverflowProtectKey = new CastingPair(thisType, otherType); if (protectInput != null) { if (protectInput.Contains(stackOverflowProtectKey)) { return(false); } } StackOverflowProtect protect = new StackOverflowProtect(stackOverflowProtectKey, protectInput); Instantiation instantiationThis = thisType.Instantiation; Instantiation instantiationTarget = otherType.Instantiation; Instantiation instantiationOpen = thisType.GetTypeDefinition().Instantiation; Debug.Assert(instantiationThis.Length == instantiationTarget.Length && instantiationThis.Length == instantiationOpen.Length); for (int i = 0; i < instantiationThis.Length; i++) { TypeDesc arg = instantiationThis[i]; TypeDesc targetArg = instantiationTarget[i]; if (arg != targetArg) { GenericParameterDesc openArgType = (GenericParameterDesc)instantiationOpen[i]; switch (openArgType.Variance) { case GenericVariance.Covariant: if (!arg.IsBoxedAndCanCastTo(targetArg, protect)) { return(false); } break; case GenericVariance.Contravariant: if (!targetArg.IsBoxedAndCanCastTo(arg, protect)) { return(false); } break; default: // non-variant Debug.Assert(openArgType.Variance == GenericVariance.None); return(false); } } } return(true); }
public StackOverflowProtect(CastingPair value, StackOverflowProtect previous) { _value = value; _previous = previous; }
private static bool IsBoxedAndCanCastTo(this TypeDesc thisType, TypeDesc otherType, StackOverflowProtect protect) { TypeDesc fromUnderlyingType = thisType.UnderlyingType; if (fromUnderlyingType.IsGCPointer) { return thisType.CanCastToInternal(otherType, protect); } else if (thisType.IsGenericParameter) { var genericVariableFromParam = (GenericParameterDesc)thisType; if (genericVariableFromParam.HasReferenceTypeConstraint) { return genericVariableFromParam.CanCastToInternal(otherType, protect); } } return false; }
private static bool CanCastToClass(this TypeDesc thisType, TypeDesc otherType, StackOverflowProtect protect) { TypeDesc curType = thisType; // 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 CanCastByVarianceToInterfaceOrDelegate(this TypeDesc thisType, TypeDesc otherType, StackOverflowProtect protectInput) { if (!thisType.HasSameTypeDefinition(otherType)) { return false; } var stackOverflowProtectKey = new CastingPair(thisType, otherType); if (protectInput != null) { if (protectInput.Contains(stackOverflowProtectKey)) return false; } StackOverflowProtect protect = new StackOverflowProtect(stackOverflowProtectKey, protectInput); Instantiation instantiationThis = thisType.Instantiation; Instantiation instantiationTarget = otherType.Instantiation; Instantiation instantiationOpen = thisType.GetTypeDefinition().Instantiation; Debug.Assert(instantiationThis.Length == instantiationTarget.Length && instantiationThis.Length == instantiationOpen.Length); for (int i = 0; i < instantiationThis.Length; i++) { TypeDesc arg = instantiationThis[i]; TypeDesc targetArg = instantiationTarget[i]; if (arg != targetArg) { GenericParameterDesc openArgType = (GenericParameterDesc)instantiationOpen[i]; switch (openArgType.Variance) { case GenericVariance.Covariant: if (!arg.IsBoxedAndCanCastTo(targetArg, protect)) return false; break; case GenericVariance.Contravariant: if (!targetArg.IsBoxedAndCanCastTo(arg, protect)) return false; break; default: // non-variant Debug.Assert(openArgType.Variance == GenericVariance.None); return false; } } } return true; }
private static bool CanCastToNonVariantInterface(this TypeDesc thisType, TypeDesc otherType, StackOverflowProtect protect) { if (otherType == thisType) { return true; } foreach (var interfaceType in thisType.RuntimeInterfaces) { if (interfaceType == otherType) { return true; } } return false; }
private static bool CanCastToInterface(this TypeDesc thisType, TypeDesc otherType, StackOverflowProtect protect) { if (!otherType.HasVariance) { return(thisType.CanCastToNonVariantInterface(otherType, protect)); } else { if (thisType.CanCastByVarianceToInterfaceOrDelegate(otherType, protect)) { return(true); } foreach (var interfaceType in thisType.RuntimeInterfaces) { if (interfaceType.CanCastByVarianceToInterfaceOrDelegate(otherType, protect)) { return(true); } } } return(false); }
private static bool CanCastToNonVariantInterface(this TypeDesc thisType, TypeDesc otherType, StackOverflowProtect protect) { if (otherType == thisType) { return(true); } foreach (var interfaceType in thisType.RuntimeInterfaces) { if (interfaceType == otherType) { return(true); } } return(false); }
private static bool CanCastParamTo(this ParameterizedType thisType, TypeDesc paramType, StackOverflowProtect protect) { // While boxed value classes inherit from object their // unboxed versions do not. Parameterized types have the // unboxed version, thus, if the from type parameter is value // class then only an exact match/equivalence works. if (thisType.ParameterType == paramType) { return true; } TypeDesc curTypesParm = thisType.ParameterType; // Object parameters don't need an exact match but only inheritance, check for that TypeDesc fromParamUnderlyingType = curTypesParm.UnderlyingType; if (fromParamUnderlyingType.IsGCPointer) { return curTypesParm.CanCastToInternal(paramType, protect); } else if (curTypesParm.IsGenericParameter) { var genericVariableFromParam = (GenericParameterDesc)curTypesParm; if (genericVariableFromParam.HasReferenceTypeConstraint) { return genericVariableFromParam.CanCastToInternal(paramType, protect); } } else if (fromParamUnderlyingType.IsPrimitive) { TypeDesc toParamUnderlyingType = paramType.UnderlyingType; if (toParamUnderlyingType.IsPrimitive) { if (toParamUnderlyingType == fromParamUnderlyingType) { return true; } if (ArePrimitveTypesEquivalentSize(fromParamUnderlyingType, toParamUnderlyingType)) { return true; } } } // Anything else is not a match return false; }
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 CanCastToInternal(this TypeDesc thisType, TypeDesc otherType, StackOverflowProtect protect) { if (thisType == otherType) { return(true); } switch (thisType.Category) { case TypeFlags.GenericParameter: return(((GenericParameterDesc)thisType).CanCastGenericParameterTo(otherType, protect)); case TypeFlags.Array: case TypeFlags.SzArray: return(((ArrayType)thisType).CanCastArrayTo(otherType, protect)); default: Debug.Assert(thisType.IsDefType); return(thisType.CanCastToClassOrInterface(otherType, protect)); } }
private static bool CanCastToClassOrInterface(this TypeDesc thisType, TypeDesc otherType, StackOverflowProtect protect) { if (otherType.IsInterface) { return thisType.CanCastToInterface(otherType, protect); } else { return thisType.CanCastToClass(otherType, protect); } }