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); autoComplete->CheckTypeRef(dynCastExpr->mTypeRef, false, true);
} }
auto origTargetType = targetType;
if (!targetValue) if (!targetValue)
return; return;
if (!targetType) if (!targetType)
@ -9547,24 +9549,23 @@ void BfExprEvaluator::Visit(BfDynamicCastExpression* dynCastExpr)
auto genericParamType = (BfGenericParamType*) targetType; auto genericParamType = (BfGenericParamType*) targetType;
auto genericParam = mModule->GetGenericParamInstance(genericParamType); auto genericParam = mModule->GetGenericParamInstance(genericParamType);
auto typeConstraint = genericParam->mTypeConstraint; auto typeConstraint = genericParam->mTypeConstraint;
if ((typeConstraint == NULL) && (genericParam->mGenericParamFlags & BfGenericParamFlag_Class)) if ((typeConstraint == NULL) && (genericParam->mGenericParamFlags & (BfGenericParamFlag_Class | BfGenericParamFlag_Interface)))
typeConstraint = mModule->mContext->mBfObjectType; typeConstraint = mModule->mContext->mBfObjectType;
if ((typeConstraint == NULL) || (!typeConstraint->IsObject())) 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); genericParam->GetGenericParamDef()->mName.c_str()), dynCastExpr->mTypeRef);
return; return;
} }
targetType = typeConstraint; targetType = typeConstraint;
targetValue = mModule->GetDefaultTypedValue(targetType);
} }
if ((!targetType->IsObjectOrInterface()) && (!targetType->IsNullable())) 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->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; return;
} }
@ -9583,21 +9584,27 @@ void BfExprEvaluator::Visit(BfDynamicCastExpression* dynCastExpr)
return; return;
} }
//targetType = typeConstraint;
targetValue = mModule->GetDefaultTypedValue(typeConstraint); targetValue = mModule->GetDefaultTypedValue(typeConstraint);
} }
auto boolType = mModule->GetPrimitiveType(BfTypeCode_Boolean); auto boolType = mModule->GetPrimitiveType(BfTypeCode_Boolean);
auto _CheckResult = [&]()
{
if ((mResult) && (origTargetType->IsGenericParam()))
mResult = mModule->GetDefaultTypedValue(origTargetType);
};
if ((targetValue.mType->IsNullable()) && (targetType->IsInterface())) if ((targetValue.mType->IsNullable()) && (targetType->IsInterface()))
{ {
mResult = mModule->Cast(dynCastExpr, targetValue, targetType, BfCastFlags_SilentFail); mResult = mModule->Cast(dynCastExpr, targetValue, targetType, BfCastFlags_SilentFail);
if (!mResult) if (!mResult)
{ {
mModule->Warn(0, StrFormat("Conversion from '%s' to '%s' will always be null", 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); mModule->TypeToString(targetValue.mType).c_str(), mModule->TypeToString(origTargetType).c_str()), dynCastExpr->mAsToken);
mResult = BfTypedValue(mModule->GetDefaultValue(targetType), targetType); mResult = BfTypedValue(mModule->GetDefaultValue(origTargetType), origTargetType);
} }
_CheckResult();
return; return;
} }
@ -9624,6 +9631,7 @@ void BfExprEvaluator::Visit(BfDynamicCastExpression* dynCastExpr)
hasValueAddr = mModule->mBfIRBuilder->CreateInBoundsGEP(allocaInst, 0, 0); // value hasValueAddr = mModule->mBfIRBuilder->CreateInBoundsGEP(allocaInst, 0, 0); // value
mModule->mBfIRBuilder->CreateStore(targetValue.mValue, hasValueAddr); mModule->mBfIRBuilder->CreateStore(targetValue.mValue, hasValueAddr);
mResult = BfTypedValue(allocaInst, targetType, true); mResult = BfTypedValue(allocaInst, targetType, true);
_CheckResult();
return; return;
} }
} }
@ -9643,6 +9651,7 @@ void BfExprEvaluator::Visit(BfDynamicCastExpression* dynCastExpr)
} }
else else
mResult = BfTypedValue(mModule->GetDefaultValue(targetType), targetType); mResult = BfTypedValue(mModule->GetDefaultValue(targetType), targetType);
_CheckResult();
return; return;
} }
@ -9689,7 +9698,7 @@ void BfExprEvaluator::Visit(BfDynamicCastExpression* dynCastExpr)
mModule->AddBasicBlock(endBB); mModule->AddBasicBlock(endBB);
mResult = BfTypedValue(allocaInst, targetType, true); mResult = BfTypedValue(allocaInst, targetType, true);
_CheckResult();
return; return;
} }
@ -9721,6 +9730,7 @@ void BfExprEvaluator::Visit(BfDynamicCastExpression* dynCastExpr)
auto castedValue = mModule->mBfIRBuilder->CreateBitCast(targetValue.mValue, mModule->mBfIRBuilder->MapType(targetTypeInstance)); auto castedValue = mModule->mBfIRBuilder->CreateBitCast(targetValue.mValue, mModule->mBfIRBuilder->MapType(targetTypeInstance));
mResult = BfTypedValue(castedValue, targetTypeInstance); mResult = BfTypedValue(castedValue, targetTypeInstance);
_CheckResult();
return; return;
} }
else if ((!targetType->IsInterface()) && (!mModule->TypeIsSubTypeOf(targetTypeInstance, srcTypeInstance))) else if ((!targetType->IsInterface()) && (!mModule->TypeIsSubTypeOf(targetTypeInstance, srcTypeInstance)))
@ -9732,6 +9742,7 @@ void BfExprEvaluator::Visit(BfDynamicCastExpression* dynCastExpr)
if (autoComplete != NULL) if (autoComplete != NULL)
{ {
mResult = mModule->GetDefaultTypedValue(targetType); mResult = mModule->GetDefaultTypedValue(targetType);
_CheckResult();
return; return;
} }
@ -9755,6 +9766,7 @@ void BfExprEvaluator::Visit(BfDynamicCastExpression* dynCastExpr)
mModule->AddBasicBlock(endBB); mModule->AddBasicBlock(endBB);
mResult = BfTypedValue(irb->CreateLoad(targetVal), targetType); mResult = BfTypedValue(irb->CreateLoad(targetVal), targetType);
_CheckResult();
} }
void BfExprEvaluator::Visit(BfCastExpression* castExpr) 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] [Test]
public static void TestBasics() public static void TestBasics()
{ {