1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-06-09 03:52:19 +02:00

Fixed dynamic cast from class/interface constraint

This commit is contained in:
Brian Fiete 2020-11-17 17:37:09 -08:00
parent a67a964142
commit 16a4b36b17
2 changed files with 29 additions and 12 deletions

View file

@ -9510,6 +9510,8 @@ void BfExprEvaluator::Visit(BfDynamicCastExpression* dynCastExpr)
autoComplete->CheckTypeRef(dynCastExpr->mTypeRef, false, true);
}
auto origTargetType = targetType;
if (!targetValue)
return;
if (!targetType)
@ -9547,24 +9549,23 @@ void BfExprEvaluator::Visit(BfDynamicCastExpression* dynCastExpr)
auto genericParamType = (BfGenericParamType*) targetType;
auto genericParam = mModule->GetGenericParamInstance(genericParamType);
auto typeConstraint = genericParam->mTypeConstraint;
if ((typeConstraint == NULL) && (genericParam->mGenericParamFlags & BfGenericParamFlag_Class))
if ((typeConstraint == NULL) && (genericParam->mGenericParamFlags & (BfGenericParamFlag_Class | BfGenericParamFlag_Interface)))
typeConstraint = mModule->mContext->mBfObjectType;
if ((typeConstraint == NULL) || (!typeConstraint->IsObject()))
{
mModule->Fail(StrFormat("The type parameter '%s' cannot be used with the 'as' operator because it does not have a class type constraint nor a 'class' constraint",
mModule->Fail(StrFormat("The type parameter '%s' cannot be used with the 'as' operator because it does not have a class type constraint nor a 'class' or 'interface' constraint",
genericParam->GetGenericParamDef()->mName.c_str()), dynCastExpr->mTypeRef);
return;
}
targetType = typeConstraint;
targetValue = mModule->GetDefaultTypedValue(targetType);
}
if ((!targetType->IsObjectOrInterface()) && (!targetType->IsNullable()))
{
mModule->Fail(StrFormat("The as operator must be used with a reference type or nullable type ('%s' is a non-nullable value type)",
mModule->TypeToString(targetType).c_str()), dynCastExpr->mTypeRef);
mModule->TypeToString(origTargetType).c_str()), dynCastExpr->mTypeRef);
return;
}
@ -9583,21 +9584,27 @@ void BfExprEvaluator::Visit(BfDynamicCastExpression* dynCastExpr)
return;
}
//targetType = typeConstraint;
targetValue = mModule->GetDefaultTypedValue(typeConstraint);
}
auto boolType = mModule->GetPrimitiveType(BfTypeCode_Boolean);
auto _CheckResult = [&]()
{
if ((mResult) && (origTargetType->IsGenericParam()))
mResult = mModule->GetDefaultTypedValue(origTargetType);
};
if ((targetValue.mType->IsNullable()) && (targetType->IsInterface()))
{
mResult = mModule->Cast(dynCastExpr, targetValue, targetType, BfCastFlags_SilentFail);
if (!mResult)
{
mModule->Warn(0, StrFormat("Conversion from '%s' to '%s' will always be null",
mModule->TypeToString(targetValue.mType).c_str(), mModule->TypeToString(targetType).c_str()), dynCastExpr->mAsToken);
mResult = BfTypedValue(mModule->GetDefaultValue(targetType), targetType);
mModule->TypeToString(targetValue.mType).c_str(), mModule->TypeToString(origTargetType).c_str()), dynCastExpr->mAsToken);
mResult = BfTypedValue(mModule->GetDefaultValue(origTargetType), origTargetType);
}
_CheckResult();
return;
}
@ -9624,6 +9631,7 @@ void BfExprEvaluator::Visit(BfDynamicCastExpression* dynCastExpr)
hasValueAddr = mModule->mBfIRBuilder->CreateInBoundsGEP(allocaInst, 0, 0); // value
mModule->mBfIRBuilder->CreateStore(targetValue.mValue, hasValueAddr);
mResult = BfTypedValue(allocaInst, targetType, true);
_CheckResult();
return;
}
}
@ -9643,6 +9651,7 @@ void BfExprEvaluator::Visit(BfDynamicCastExpression* dynCastExpr)
}
else
mResult = BfTypedValue(mModule->GetDefaultValue(targetType), targetType);
_CheckResult();
return;
}
@ -9689,7 +9698,7 @@ void BfExprEvaluator::Visit(BfDynamicCastExpression* dynCastExpr)
mModule->AddBasicBlock(endBB);
mResult = BfTypedValue(allocaInst, targetType, true);
_CheckResult();
return;
}
@ -9721,6 +9730,7 @@ void BfExprEvaluator::Visit(BfDynamicCastExpression* dynCastExpr)
auto castedValue = mModule->mBfIRBuilder->CreateBitCast(targetValue.mValue, mModule->mBfIRBuilder->MapType(targetTypeInstance));
mResult = BfTypedValue(castedValue, targetTypeInstance);
_CheckResult();
return;
}
else if ((!targetType->IsInterface()) && (!mModule->TypeIsSubTypeOf(targetTypeInstance, srcTypeInstance)))
@ -9732,6 +9742,7 @@ void BfExprEvaluator::Visit(BfDynamicCastExpression* dynCastExpr)
if (autoComplete != NULL)
{
mResult = mModule->GetDefaultTypedValue(targetType);
_CheckResult();
return;
}
@ -9755,6 +9766,7 @@ void BfExprEvaluator::Visit(BfDynamicCastExpression* dynCastExpr)
mModule->AddBasicBlock(endBB);
mResult = BfTypedValue(irb->CreateLoad(targetVal), targetType);
_CheckResult();
}
void BfExprEvaluator::Visit(BfCastExpression* castExpr)

View file

@ -190,6 +190,11 @@ namespace Tests
}
}
public void TestCast<T, TI>(T val) where T : class where TI : interface
{
TI iface = val as TI;
}
[Test]
public static void TestBasics()
{