diff --git a/IDEHelper/Compiler/BfModule.cpp b/IDEHelper/Compiler/BfModule.cpp index 8ab5af5e..fff86946 100644 --- a/IDEHelper/Compiler/BfModule.cpp +++ b/IDEHelper/Compiler/BfModule.cpp @@ -6648,11 +6648,11 @@ bool BfModule::CheckGenericConstraints(const BfGenericParamSource& genericParamS bool implementsInterface = false; if (origCheckArgType != checkArgType) { - implementsInterface = CanImplicitlyCast(origCheckArgType, convCheckConstraint); + implementsInterface = CanImplicitlyCast(BfTypedValue(BfIRValue::sValueless, origCheckArgType), convCheckConstraint); } if (!implementsInterface) - implementsInterface = CanImplicitlyCast(checkArgType, convCheckConstraint); + implementsInterface = CanImplicitlyCast(BfTypedValue(BfIRValue::sValueless, checkArgType), convCheckConstraint); if ((!implementsInterface) && (origCheckArgType->IsWrappableType())) { diff --git a/IDEHelper/Compiler/BfModuleTypeUtils.cpp b/IDEHelper/Compiler/BfModuleTypeUtils.cpp index 584caced..eaea6d0e 100644 --- a/IDEHelper/Compiler/BfModuleTypeUtils.cpp +++ b/IDEHelper/Compiler/BfModuleTypeUtils.cpp @@ -7694,941 +7694,15 @@ BfType* BfModule::ResolveTypeRef(BfAstNode* astNode, const BfSizedArrayIsRef()) && (toType->IsRef()))) - { - auto fromRefType = (BfRefType*)typedVal.mType; - auto toRefType = (BfRefType*)toType; - if (fromRefType->mRefKind == toRefType->mRefKind) - checkUnderlying = true; - else if ((fromRefType->mRefKind == BfRefType::RefKind_Ref) && (toRefType->mRefKind == BfRefType::RefKind_Mut)) - checkUnderlying = true; // Allow a ref-to-mut implicit conversion - } - - if ((typedVal.mType->IsPointer()) && (toType->IsPointer())) - checkUnderlying = true; - - if (checkUnderlying) - { - auto fromInner = typedVal.mType->GetUnderlyingType(); - auto toInner = toType->GetUnderlyingType(); - - if (fromInner == toInner) - return true; - - // ref int <-> ref int64/int32 (of same size) - if (((fromInner->IsInteger()) && (toInner->IsInteger())) && - (fromInner->mSize == toInner->mSize) && - (fromInner->IsSigned() == toInner->IsSigned())) - return true; - } - } - - // Generic param -> * - if ((typedVal.mType->IsGenericParam()) && (!toType->IsGenericParam())) - { - if (toType == mContext->mBfObjectType) - { - //auto resolvedType = ResolveGenericType(typedVal.mType); - //auto resolvedType = typedVal.mType; - /*if (!resolvedType->IsGenericParam()) - return CanImplicitlyCast(BfTypedValue(typedVal.mValue, resolvedType), toType);*/ - // Can we never NOT do this? - return true; - } - - // For these casts, it's just important we get *A* value to work with here, - // as this is just use for unspecialized parsing. We don't use the generated code - auto genericParamInst = GetGenericParamInstance((BfGenericParamType*)typedVal.mType); - if ((genericParamInst->mGenericParamFlags & BfGenericParamFlag_Var) != 0) - { - return true; - } - if (toType->IsInterface()) - { - for (auto iface : genericParamInst->mInterfaceConstraints) - if (TypeIsSubTypeOf(iface, toType->ToTypeInstance())) - return true; - } - - if (genericParamInst->mTypeConstraint != NULL) - { - auto defaultFromValue = GetDefaultTypedValue(genericParamInst->mTypeConstraint); - auto result = CanImplicitlyCast(defaultFromValue, toType); - - if ((result) && (genericParamInst->mTypeConstraint->IsDelegate()) && (toType->IsDelegate())) - { - // Don't allow cast when we are constrained by a delegate type, because BfMethodRefs can match and we require an actual alloc - return false; - } - return result; - } - - // Generic constrained with class or pointer type -> void* - if (toType->IsVoidPtr()) - { - if ((genericParamInst->mGenericParamFlags & (BfGenericParamFlag_Class | BfGenericParamFlag_StructPtr)) || - ((genericParamInst->mTypeConstraint != NULL) && - ((genericParamInst->mTypeConstraint->IsPointer()) || (genericParamInst->mTypeConstraint->IsObjectOrInterface())))) - { - return true; - } - } - } - - // * -> Generic param - if (toType->IsGenericParam()) - { - auto genericParamInst = GetGenericParamInstance((BfGenericParamType*)toType); - if (genericParamInst->mGenericParamFlags & BfGenericParamFlag_Var) - return true; - if (typedVal.mType->IsNull()) - { - bool allowCast = (genericParamInst->mGenericParamFlags & BfGenericParamFlag_Class) || (genericParamInst->mGenericParamFlags & BfGenericParamFlag_StructPtr); - if ((!allowCast) && (genericParamInst->mTypeConstraint != NULL)) - allowCast = genericParamInst->mTypeConstraint->IsObject() || genericParamInst->mTypeConstraint->IsPointer(); - if (allowCast) - return true; - } - - if (genericParamInst->mTypeConstraint != NULL) - { - if (CanImplicitlyCast(typedVal, genericParamInst->mTypeConstraint)) - return true; - } - } - - // Struct truncate - if ((fromType->IsStruct()) && (toType->IsStruct())) - { - auto fromTypeInstance = fromType->ToTypeInstance(); - auto toTypeInstance = toType->ToTypeInstance(); - if (TypeIsSubTypeOf(fromTypeInstance, toTypeInstance)) - return true; - } - - if ((fromType->IsVar()) || (toType->IsVar())) - return true; - - // Null -> ObjectInst|IFace|ptr - if ((fromType->IsNull()) && - ((toType->IsObjectOrInterface()) || (toType->IsPointer()) || (toType->IsPointer()))) - { - return true; - } - - // Object/struct -> object/struct|IFace - if ((fromType->IsTypeInstance()) && ((toType->IsTypeInstance() || (toType->IsInterface())))) - { - auto fromTypeInstance = fromType->ToTypeInstance(); - auto toTypeInstance = toType->ToTypeInstance(); - - if (TypeIsSubTypeOf(fromTypeInstance, toTypeInstance)) - return true; - } - - // concrete IFace -> object|IFace - if ((fromType->IsConcreteInterfaceType()) && ((toType->IsObject() || (toType->IsInterface())))) - { - auto concreteInterfaceType = (BfConcreteInterfaceType*)fromType; - if ((toType->IsObject()) || (concreteInterfaceType->mInterface == toType)) - return true; - } - - // IFace -> object - if ((fromType->IsInterface()) && (toType == mContext->mBfObjectType)) - return true; - - if (toType->IsPointer()) - { - // Ptr -> Ptr - if (fromType->IsPointer()) - { - bool allowCast = false; - auto fromPointerType = (BfPointerType*)typedVal.mType; - auto toPointerType = (BfPointerType*)toType; - - auto fromUnderlying = fromPointerType->mElementType; - auto toUnderlying = toPointerType->mElementType; - - // Allow cast from T[size]* to T* implicitly - // And from T* to T[size]* explicitly - if (fromUnderlying->IsSizedArray()) - fromUnderlying = fromUnderlying->GetUnderlyingType(); - // if ((toUnderlying->IsSizedArray()) && (explicitCast)) - // toUnderlying = toUnderlying->GetUnderlyingType(); - - if ((fromUnderlying == toUnderlying) || - (TypeIsSubTypeOf(fromUnderlying->ToTypeInstance(), toUnderlying->ToTypeInstance())) || - (toUnderlying->IsVoid())) - allowCast = true; - - if (allowCast) - return true; - } - else if (fromType->IsObject()) - { - auto fromTypeInst = fromType->ToTypeInstance(); - auto charType = GetPrimitiveType(BfTypeCode_Char8); - auto charPtrType = CreatePointerType(charType); - if ((fromTypeInst->mTypeDef == mCompiler->mStringTypeDef) && (toType == charPtrType)) - { - // String Object -> char* literal - return true; - } - } - /*else if (typedVal.mType->IsSizedArray()) - { - if (typedVal.IsAddr()) - { - BfSizedArrayType* arrayType = (BfSizedArrayType*)typedVal.mType; - BfTypedValue returnPointer(typedVal.mValue, CreatePointerType(arrayType->mElementType)); - return CanImplicitlyCast(returnPointer, toType); - } - }*/ - } - - // Boxing? - if (((fromType->IsValueType()) || (fromType->IsPointer()) || (fromType->IsValuelessType())) && - ((toType->IsInterface()) || (toType == mContext->mBfObjectType))) - { - // if (fromType->IsPointer()) - // { - // if (toType == mContext->mBfObjectType) - // return true; - // return false; - // } - - if (toType == mContext->mBfObjectType) - return true; - - BfTypeInstance* fromStructTypeInstance = NULL; - fromStructTypeInstance = fromType->ToTypeInstance(); - if (fromStructTypeInstance == NULL) - { - if (fromType->IsPrimitiveType()) - { - auto primType = (BfPrimitiveType*)fromType; - fromStructTypeInstance = GetPrimitiveStructType(primType->mTypeDef->mTypeCode); - } - else - return false; - } - - auto toTypeInstance = toType->ToTypeInstance(); - // Need to box it - if (TypeIsSubTypeOf(fromStructTypeInstance, toTypeInstance)) - return true; - } - - // Null -> Nullable - if ((typedVal.mType->IsNull()) && (toType->IsNullable())) - { - return true; - } - - // Nullable -> Nullable - if ((typedVal.mType->IsNullable()) && (toType->IsNullable())) - { - auto fromNullableType = (BfGenericTypeInstance*)typedVal.mType; - auto toNullableType = (BfGenericTypeInstance*)toType; - - return CanImplicitlyCast(BfTypedValue(mBfIRBuilder->GetFakeVal(), fromNullableType->mTypeGenericArguments[0]), toNullableType->mTypeGenericArguments[0], castFlags); - } - - // Tuple -> Tuple - if ((typedVal.mType->IsTuple()) && (toType->IsTuple())) - { - auto fromTupleType = (BfTupleType*)typedVal.mType; - auto toTupleType = (BfTupleType*)toType; - if (fromTupleType->mFieldInstances.size() == toTupleType->mFieldInstances.size()) - { - bool canCast = true; - - BfIRValue curTupleValue = mBfIRBuilder->CreateUndefValue(mBfIRBuilder->MapType(toTupleType)); - for (int valueIdx = 0; valueIdx < (int)fromTupleType->mFieldInstances.size(); valueIdx++) - { - BfFieldInstance* fromFieldInstance = &fromTupleType->mFieldInstances[valueIdx]; - BfFieldInstance* toFieldInstance = &toTupleType->mFieldInstances[valueIdx]; - - // - { - BfFieldDef* fromFieldDef = fromFieldInstance->GetFieldDef(); - BfFieldDef* toFieldDef = toFieldInstance->GetFieldDef(); - - // Either the names have to match or one has to be unnamed - if ((!fromFieldDef->IsUnnamedTupleField()) && (!toFieldDef->IsUnnamedTupleField()) && - (fromFieldDef->mName != toFieldDef->mName)) - { - curTupleValue = BfIRValue(); - break; - } - } - - auto fromFieldType = fromFieldInstance->GetResolvedType(); - auto toFieldType = toFieldInstance->GetResolvedType(); - - if (toFieldType->IsVoid()) - continue; // Allow sinking to void - - BfIRValue fromFieldValue; - bool canCastField = CanImplicitlyCast(BfTypedValue(mBfIRBuilder->GetFakeVal(), fromFieldType), toFieldType, (BfCastFlags)(castFlags | BfCastFlags_Explicit)); - if (!canCastField) - { - canCast = false; - break; - } - } - - if (canCast) - return false; - } - } - - /*if (fromType->IsRef()) - { - if (toType->IsRef()) - { - BfTypedValue unrefValue = BfTypedValue(typedVal.mValue, fromType->GetUnderlyingType(), true); - return CanImplicitlyCast(unrefValue, toType->GetUnderlyingType()); - } - else - { - // ref T -> T - return fromType->GetUnderlyingType() == toType; - } - }*/ - - // Int -> Enum - if ((typedVal.mType->IsIntegral()) && (toType->IsEnum())) - { - // Allow implicit cast of zero - if (typedVal.mValue) - { - auto constant = mBfIRBuilder->GetConstant(typedVal.mValue); - if ((constant != NULL) && (BfIRBuilder::IsInt(constant->mTypeCode))) - { - int64 srcVal = constant->mInt64; - if (srcVal == 0) - return true; - } - } - } - - // Tuple -> Tuple - if ((typedVal.mType->IsTuple()) && (toType->IsTuple())) - { - auto fromTupleType = (BfTupleType*)typedVal.mType; - auto toTupleType = (BfTupleType*)toType; - if (fromTupleType->mFieldInstances.size() == toTupleType->mFieldInstances.size()) - { - for (int valueIdx = 0; valueIdx < (int)fromTupleType->mFieldInstances.size(); valueIdx++) - { - BfFieldInstance* fromFieldInstance = &fromTupleType->mFieldInstances[valueIdx]; - BfFieldInstance* toFieldInstance = &toTupleType->mFieldInstances[valueIdx]; - - BfFieldDef* fromFieldDef = fromFieldInstance->GetFieldDef(); - BfFieldDef* toFieldDef = toFieldInstance->GetFieldDef(); - - auto fromFieldType = fromFieldInstance->GetResolvedType(); - auto toFieldType = toFieldInstance->GetResolvedType(); - - // Either the names have to match or one has to be unnamed - if ((!fromFieldDef->IsUnnamedTupleField()) && (!toFieldDef->IsUnnamedTupleField()) && - (fromFieldDef->mName != toFieldDef->mName)) - return false; - - if (toFieldType->IsVoid()) - continue; // Allow sinking to void - - if (!CanImplicitlyCast(GetFakeTypedValue(fromFieldType), toFieldType)) - return false; - } - - return true; - } - } - - // -> const - if (toType->IsConstExprValue()) - { - auto constant = mBfIRBuilder->GetConstant(typedVal.mValue); - if (constant != NULL) - { - BfConstExprValueType* toConstExprValueType = (BfConstExprValueType*)toType; - - auto variantVal = TypedValueToVariant(NULL, typedVal); - if ((mBfIRBuilder->IsInt(variantVal.mTypeCode)) && (mBfIRBuilder->IsInt(toConstExprValueType->mValue.mTypeCode))) - { - if (variantVal.mInt64 == toConstExprValueType->mValue.mInt64) - return true; - } - else if ((mBfIRBuilder->IsFloat(variantVal.mTypeCode)) && (mBfIRBuilder->IsFloat(toConstExprValueType->mValue.mTypeCode))) - { - if (variantVal.ToDouble() == toConstExprValueType->mValue.ToDouble()) - return true; - } - } - } - - if ((fromType->IsPrimitiveType()) && (toType->IsPrimitiveType())) - { - auto fromPrimType = (BfPrimitiveType*)fromType; - auto toPrimType = (BfPrimitiveType*)toType; - - BfTypeCode fromTypeCode = fromPrimType->mTypeDef->mTypeCode; - BfTypeCode toTypeCode = toPrimType->mTypeDef->mTypeCode; - - // Must be from a default int to do an implicit constant cast, not casted by user, ie: (ushort)123 - if ((toType->IsIntegral()) && (typedVal.mValue)) - { - // Allow constant ints to be implicitly casted to a smaller type if they fit - auto constant = mBfIRBuilder->GetConstant(typedVal.mValue); - if (constant != NULL) - { - if (BfIRBuilder::IsInt(constant->mTypeCode)) - { - int64 srcVal = constant->mInt64; - - if (toPrimType->IsChar()) - { - if (srcVal == 0) - return true; - } - else if ((fromPrimType->IsChar()) && (!toPrimType->IsChar())) - { - // Never allow this - } - else if ((constant->mTypeCode == BfTypeCode_UInt64) && (srcVal < 0)) - { - // There's nothing that this could fit into - } - else if (toType->IsSigned()) - { - if (toType->mSize == 8) // int64 - return true; - else - { - int64 minVal = -(1LL << (8 * toType->mSize - 1)); - int64 maxVal = (1LL << (8 * toType->mSize - 1)) - 1; - if ((srcVal >= minVal) && (srcVal <= maxVal)) - return true; - } - } - else if (toType->mSize == 8) // ulong - { - if (srcVal >= 0) - return true; - } - else - { - int64 minVal = 0; - int64 maxVal = (1LL << (8 * toType->mSize)) - 1; - if ((srcVal >= minVal) && (srcVal <= maxVal)) - return true; - } - } - else if (constant->mConstType == BfConstType_Undef) - { - BF_ASSERT(mBfIRBuilder->mIgnoreWrites); - - auto undefConst = (BfConstantUndef*)constant; - - auto fakeVal = GetFakeTypedValue(GetPrimitiveType(undefConst->mTypeCode)); - if (CanImplicitlyCast(fakeVal, toType)) - return true; - } - } - } - - switch (toTypeCode) - { - case BfTypeCode_UInt8: - switch (fromTypeCode) - { - case BfTypeCode_UInt8: - return true; - default: break; - } - break; - case BfTypeCode_Char16: - switch (fromTypeCode) - { - case BfTypeCode_Char8: - return true; - default: break; - } - break; - case BfTypeCode_Int16: - switch (fromTypeCode) - { - case BfTypeCode_Int8: - return true; - case BfTypeCode_UInt8: - return true; - default: break; - } - break; - case BfTypeCode_UInt16: - switch (fromTypeCode) - { - case BfTypeCode_UInt8: - return true; - default: break; - } - break; - case BfTypeCode_Int32: - switch (fromTypeCode) - { - case BfTypeCode_Int8: - case BfTypeCode_Int16: - return true; - case BfTypeCode_IntPtr: - if (mCompiler->mSystem->mPtrSize == 4) - return true; - break; - case BfTypeCode_UInt8: - case BfTypeCode_UInt16: - return true; - default: break; - } - break; - case BfTypeCode_Char32: - switch (fromTypeCode) - { - case BfTypeCode_Char8: - case BfTypeCode_Char16: - return true; - default: break; - } - break; - case BfTypeCode_UInt32: - switch (fromTypeCode) - { - case BfTypeCode_UInt8: - case BfTypeCode_UInt16: - case BfTypeCode_UInt32: - return true; - case BfTypeCode_UIntPtr: - if (mCompiler->mSystem->mPtrSize == 4) - return true; - break; - default: break; - } - break; - case BfTypeCode_Int64: - switch (fromTypeCode) - { - case BfTypeCode_Int8: - case BfTypeCode_Int16: - case BfTypeCode_Int32: - case BfTypeCode_IntPtr: - return true; - case BfTypeCode_UInt8: - case BfTypeCode_UInt16: - case BfTypeCode_UInt32: - return true; - default: break; - } - break; - case BfTypeCode_UInt64: - switch (fromTypeCode) - { - case BfTypeCode_UInt8: - case BfTypeCode_UInt16: - case BfTypeCode_UInt32: - case BfTypeCode_UIntPtr: - return true; - default: break; - } - break; - case BfTypeCode_IntPtr: - switch (fromTypeCode) - { - case BfTypeCode_Int8: - case BfTypeCode_Int16: - case BfTypeCode_Int32: - return true; - case BfTypeCode_UInt8: - case BfTypeCode_UInt16: - return true; - case BfTypeCode_UInt32: - case BfTypeCode_Int64: - if (mCompiler->mSystem->mPtrSize == 8) - return true; - break; - default: break; - } - break; - case BfTypeCode_UIntPtr: - switch (fromTypeCode) - { - case BfTypeCode_UInt8: - case BfTypeCode_UInt16: - case BfTypeCode_UInt32: - return true; - case BfTypeCode_UInt64: - if (mCompiler->mSystem->mPtrSize == 8) - return true; - break; - default: break; - } - break; - case BfTypeCode_Single: - switch (fromTypeCode) - { - case BfTypeCode_Int8: - case BfTypeCode_Int16: - case BfTypeCode_Int32: - case BfTypeCode_Int64: - case BfTypeCode_IntPtr: - case BfTypeCode_IntUnknown: - return true; - case BfTypeCode_UInt8: - case BfTypeCode_UInt16: - case BfTypeCode_UInt32: - case BfTypeCode_UInt64: - case BfTypeCode_UIntPtr: - case BfTypeCode_UIntUnknown: - return true; - default: break; - } - break; - case BfTypeCode_Double: - switch (fromTypeCode) - { - case BfTypeCode_Int8: - case BfTypeCode_Int16: - case BfTypeCode_Int32: - case BfTypeCode_Int64: - case BfTypeCode_IntPtr: - case BfTypeCode_IntUnknown: - return true; - case BfTypeCode_UInt8: - case BfTypeCode_UInt16: - case BfTypeCode_UInt32: - case BfTypeCode_UInt64: - case BfTypeCode_UIntPtr: - case BfTypeCode_UIntUnknown: - return true; - case BfTypeCode_Single: - return true; - default: break; - } - break; - default: break; - } - } - - // wrappable -> struct -// if ((fromType->IsWrappableType()) && (toType->IsStruct())) -// { -// auto wrappableType = GetWrappedStructType(fromType); -// if (TypeIsSubTypeOf(wrappableType, toType->ToTypeInstance())) -// return true; -// } - - // Check user-defined operators -// { -// auto fromTypeInstance = fromType->ToTypeInstance(); -// auto toTypeInstance = toType->ToTypeInstance(); -// -// int bestFromDist = INT_MAX; -// BfType* bestFromType = NULL; -// int bestNegFromDist = INT_MAX; -// BfType* bestNegFromType = NULL; -// -// int bestToDist = INT_MAX; -// BfType* bestToType = NULL; -// int bestNegToDist = INT_MAX; -// BfType* bestNegToType = NULL; -// -// for (int pass = 0; pass < 2; pass++) -// { -// BfBaseClassWalker baseClassWalker(fromType, toType, this); -// while (true) -// { -// auto entry = baseClassWalker.Next(); -// auto checkInstance = entry.mTypeInstance; -// if (checkInstance == NULL) -// break; -// -// for (auto operatorDef : checkInstance->mTypeDef->mOperators) -// { -// if (operatorDef->mOperatorDeclaration->mIsConvOperator) -// { -// if ((operatorDef->mOperatorDeclaration->mExplicitToken != NULL) && -// (operatorDef->mOperatorDeclaration->mExplicitToken->GetToken() == BfToken_Explicit)) -// continue; -// -// // Get in native module so our module doesn't get a reference to it - we may not end up calling it at all! -// auto methodInst = checkInstance->mModule->GetRawMethodInstanceAtIdx(checkInstance, operatorDef->mIdx); -// -// if (methodInst->GetParamCount() != 1) -// { -// //AssertErrorState(); -// continue; -// } -// -// auto checkFromType = methodInst->GetParamType(0); -// if (checkFromType->IsSelf()) -// checkFromType = entry.mSrcType; -// -// // Selection pass -// if (pass == 0) -// { -// int fromDist = GetTypeDistance(checkFromType, fromType); -// int toDist = GetTypeDistance(toType, methodInst->mReturnType); -// -// if ((fromDist == INT_MAX) || (toDist == INT_MAX)) -// continue; -// -// if ((fromDist >= 0) && (toDist >= 0)) -// { -// if ((fromDist >= 0) && (fromDist < bestFromDist)) -// { -// bestFromDist = fromDist; -// bestFromType = checkFromType; -// } -// -// if ((fromDist >= 0) && (toDist < bestToDist)) -// { -// bestToDist = toDist; -// bestToType = methodInst->mReturnType; -// } -// } -// } -// else // Execution Pass -// { -// auto returnType = methodInst->mReturnType; -// if (returnType->IsSelf()) -// returnType = entry.mSrcType; -// -// if ((checkFromType == bestFromType) && (methodInst->mReturnType == bestToType)) -// { -// return true; -// } -// } -// } -// } -// } -// -// if (bestFromType == NULL) -// bestFromType = bestNegFromType; -// if (bestToType == NULL) -// bestToType = bestNegToType; -// -// if ((bestFromType == NULL) || (bestToType == NULL)) -// break; -// } -// } - - // Check user-defined operators - if ((castFlags & BfCastFlags_NoConversionOperator) == 0) - { - auto fromType = typedVal.mType; - auto fromTypeInstance = fromType->ToTypeInstance(); - auto toTypeInstance = toType->ToTypeInstance(); - - auto liftedFromType = ((fromTypeInstance != NULL) && fromTypeInstance->IsNullable()) ? fromTypeInstance->GetUnderlyingType() : NULL; - auto liftedToType = ((toTypeInstance != NULL) && toTypeInstance->IsNullable()) ? toTypeInstance->GetUnderlyingType() : NULL; - - int bestFromDist = INT_MAX; - BfType* bestFromType = NULL; - int bestNegFromDist = INT_MAX; - BfType* bestNegFromType = NULL; - - int bestToDist = INT_MAX; - BfType* bestToType = NULL; - int bestNegToDist = INT_MAX; - BfType* bestNegToType = NULL; - bool isAmbiguousCast = false; - - BfIRValue conversionResult; - BfMethodInstance* opMethodInstance = NULL; - BfType* opMethodSrcType = NULL; - - // Normal, lifted, execute - for (int pass = 0; pass < 3; pass++) - { - auto checkToType = toType; - auto checkFromType = fromType; - - if (pass == 1) - { - if ((bestFromType != NULL) && (bestToType != NULL)) - continue; - - if (liftedFromType != NULL) - checkFromType = liftedFromType; - if (liftedToType != NULL) - checkToType = liftedToType; - } - else if (pass == 2) - { - if ((bestFromType == NULL) || (bestToType == NULL)) - break; - } - - BfBaseClassWalker baseClassWalker(fromType, toType, this); - - while (true) - { - auto entry = baseClassWalker.Next(); - auto checkInstance = entry.mTypeInstance; - if (checkInstance == NULL) - break; - - for (auto operatorDef : checkInstance->mTypeDef->mOperators) - { - if (operatorDef->mOperatorDeclaration->mIsConvOperator) - { - if ((operatorDef->mOperatorDeclaration->mExplicitToken != NULL) && - (operatorDef->mOperatorDeclaration->mExplicitToken->GetToken() == BfToken_Explicit)) - continue; - - auto methodInst = GetRawMethodInstanceAtIdx(checkInstance, operatorDef->mIdx); - - if (methodInst->GetParamCount() != 1) - { - BF_ASSERT(mCompiler->mPassInstance->HasFailed()); - continue; - } - - auto methodFromType = methodInst->GetParamType(0); - auto methodToType = methodInst->mReturnType; - - if (methodFromType->IsSelf()) - methodFromType = entry.mSrcType; - if (methodToType->IsSelf()) - methodToType = entry.mSrcType; - - // Selection pass - if (pass < 2) - { - auto methodCheckFromType = methodFromType; - auto methodCheckToType = methodToType; - if (pass == 1) - { - // Only check inner type on lifted types when we aren't checking conversions within lifted class - // This avoid some infinite conversions - if ((methodCheckFromType->IsNullable()) && (!checkInstance->IsNullable())) - methodCheckFromType = methodCheckFromType->GetUnderlyingType(); - if ((methodCheckToType->IsNullable()) && (!checkInstance->IsNullable())) - methodCheckToType = methodCheckToType->GetUnderlyingType(); - } - - int fromDist = GetTypeDistance(methodCheckFromType, checkFromType); - if (fromDist < 0) - { - // Allow us to cast a constant int to a smaller type if it satisfies the cast operator - if ((typedVal.mValue.IsConst()) && (methodCheckFromType != toType) && (CanImplicitlyCast(typedVal, methodCheckFromType))) - { - fromDist = 0; - } - } - - int toDist = GetTypeDistance(methodCheckToType, checkToType); - - if ((fromDist == INT_MAX) || (toDist == INT_MAX)) - continue; - - if ((fromDist >= 0) && (toDist >= 0)) - { - if ((fromDist >= 0) && (fromDist < bestFromDist)) - { - bestFromDist = fromDist; - bestFromType = methodFromType; - } - - if ((toDist >= 0) && (toDist < bestToDist)) - { - bestToDist = toDist; - bestToType = methodToType; - } - } - } - else if (pass == 2) // Execution Pass - { - if ((methodFromType == bestFromType) && (methodToType == bestToType)) - { - return CanImplicitlyCast(BfTypedValue(BfIRValue::sValueless, bestToType), toType, castFlags); - } - } - } - } - - if (isAmbiguousCast) - break; - } - - if (bestFromType == NULL) - bestFromType = bestNegFromType; - if (bestToType == NULL) - bestToType = bestNegToType; - } - } - - // Prim -> TypedPrimitive - if ((typedVal.mType->IsPrimitiveType()) && (toType->IsTypedPrimitive())) - { - bool allowCast = false; - if (toType == mCurTypeInstance) - allowCast = true; - if ((!allowCast) && (typedVal.mType->IsIntegral()) /*&& (!toType->IsEnum())*/) - { - // Allow implicit cast of zero - auto constant = mBfIRBuilder->GetConstant(typedVal.mValue); - if ((constant != NULL) && (mBfIRBuilder->IsInt(constant->mTypeCode))) - { - allowCast = constant->mInt64 == 0; - } - } - if (allowCast) - { - return CanImplicitlyCast(typedVal, toType->GetUnderlyingType(), castFlags); - } - } - - return false; -} - // This flow should mirror CastToValue bool BfModule::CanImplicitlyCast(BfTypedValue typedVal, BfType* toType, BfCastFlags castFlags) { BP_ZONE("BfModule::CanImplicitlyCast"); - //return DoCanImplicitlyCast(typedVal, toType, castFlags); - - bool canCastToValue; - { - SetAndRestoreValue prevIgnoreWrites(mBfIRBuilder->mIgnoreWrites, true); - canCastToValue = CastToValue(NULL, typedVal, toType, (BfCastFlags)(castFlags | BfCastFlags_SilentFail)); - return canCastToValue; - } - - return canCastToValue; - - bool sideCanCast = DoCanImplicitlyCast(typedVal, toType, castFlags); - if (canCastToValue != sideCanCast) - { - NOP; - } - //BF_ASSERT(canCastToValue == sideCanCast); - return sideCanCast; + SetAndRestoreValue prevIgnoreWrites(mBfIRBuilder->mIgnoreWrites, true); + return CastToValue(NULL, typedVal, toType, (BfCastFlags)(castFlags | BfCastFlags_SilentFail)); } - bool BfModule::AreSplatsCompatible(BfType* fromType, BfType* toType, bool* outNeedsMemberCasting) { if ((fromType->IsTypeInstance()) && (!fromType->IsSplattable())) diff --git a/IDEHelper/Tests/src/Boxing.bf b/IDEHelper/Tests/src/Boxing.bf index 85cd548b..6dffbf20 100644 --- a/IDEHelper/Tests/src/Boxing.bf +++ b/IDEHelper/Tests/src/Boxing.bf @@ -94,13 +94,13 @@ namespace Tests IHashable ihB = valB; IHashable ihC = valC; - Test.Assert(ihA.GetHashCode() == (int)valA); - Test.Assert(ihB.GetHashCode() == (int)valB); - Test.Assert(ihC.GetHashCode() == (int)valC); + Test.Assert(ihA.GetHashCode() == (int)(void*)valA); + Test.Assert(ihB.GetHashCode() == (int)(void*)valB); + Test.Assert(ihC.GetHashCode() == (int)(void*)valC); - Test.Assert(GetHash(ihA) == (int)valA); - Test.Assert(GetHash(ihB) == (int)valB); - Test.Assert(GetHash(ihC) == (int)valC); + Test.Assert(GetHash(ihA) == (int)(void*)valA); + Test.Assert(GetHash(ihB) == (int)(void*)valB); + Test.Assert(GetHash(ihC) == (int)(void*)valC); } } }