1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-06-11 04:52:21 +02:00

Improved type constraint checks constrained by other generic params

This commit is contained in:
Brian Fiete 2022-06-11 07:56:43 -07:00
parent 10682e67af
commit 06ceaf617b
3 changed files with 55 additions and 26 deletions

View file

@ -11877,21 +11877,28 @@ void BfExprEvaluator::Visit(BfDynamicCastExpression* dynCastExpr)
if (targetType->IsGenericParam())
{
wasGenericParamType = true;
//wasGenericParamType = false; // "was", not "is"
BfGenericParamInstance* origGenericParam = NULL;
int pass = 0;
while ((targetType != NULL) && (targetType->IsGenericParam()))
{
auto genericParamType = (BfGenericParamType*)targetType;
auto genericParam = mModule->GetGenericParamInstance(genericParamType);
if (pass == 0)
origGenericParam = genericParam;
auto typeConstraint = genericParam->mTypeConstraint;
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' or 'interface' constraint",
genericParam->GetGenericParamDef()->mName.c_str()), dynCastExpr->mTypeRef);
return;
targetType = typeConstraint;
if (++pass >= 100) // Sanity - but we should have caught circular error before
break;
}
targetType = typeConstraint;
if ((targetType == NULL) || (!targetType->IsObjectOrInterface()))
{
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",
origGenericParam->GetGenericParamDef()->mName.c_str()), dynCastExpr->mTypeRef);
return;
}
}
if (targetType->IsVar())
@ -11930,7 +11937,7 @@ void BfExprEvaluator::Visit(BfDynamicCastExpression* dynCastExpr)
auto _CheckResult = [&]()
{
if ((mResult) && (origTargetType->IsGenericParam()))
mResult = mModule->GetDefaultTypedValue(origTargetType);
mResult = mModule->GetDefaultTypedValue(origTargetType, false, BfDefaultValueKind_Undef);
};
if ((targetValue.mType->IsNullable()) && (targetType->IsInterface()))

View file

@ -1197,15 +1197,24 @@ void BfModule::TryInitVar(BfAstNode* checkNode, BfLocalVariable* localVar, BfTyp
bool isDynamicCast = false;
if (varType->IsGenericParam())
{
int pass = 0;
while (varType->IsGenericParam())
{
auto genericParamType = (BfGenericParamType*)varType;
auto genericParam = GetGenericParamInstance(genericParamType);
auto typeConstraint = genericParam->mTypeConstraint;
if ((typeConstraint == NULL) && (genericParam->mGenericParamFlags & BfGenericParamFlag_Class))
if ((typeConstraint == NULL) && (genericParam->mGenericParamFlags & (BfGenericParamFlag_Class | BfGenericParamFlag_Interface)))
typeConstraint = mContext->mBfObjectType;
if (typeConstraint != NULL)
varType = typeConstraint;
initValue = GetDefaultTypedValue(varType);
else
break;
if (++pass >= 100) // Sanity - but we should have caught circular error before
break;
}
initValue = GetDefaultTypedValue(varType, false, BfDefaultValueKind_Undef);
}
BfTypeInstance* srcTypeInstance = initValue.mType->ToTypeInstance();

View file

@ -165,6 +165,19 @@ namespace Tests
public static int GenClassMethodB(GenClass<int> a) { return a.test++; }
public static int GenClassMethodC<A>(A a) where A : GenClass<int> { return a.test += 1; }
public static TDerived AssertSubtype<TBase, TDerived>(TBase instance)
where TDerived : TBase
where TBase : class
{
if (instance == null)
Runtime.FatalError();
if (TDerived derived = instance as TDerived)
{
return derived;
}
Runtime.FatalError();
}
[Test]
public static void TestBasics()
{