1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-06-12 21:34:11 +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()) if (targetType->IsGenericParam())
{ {
wasGenericParamType = true; wasGenericParamType = true;
//wasGenericParamType = false; // "was", not "is" BfGenericParamInstance* origGenericParam = NULL;
auto genericParamType = (BfGenericParamType*) targetType; int pass = 0;
while ((targetType != NULL) && (targetType->IsGenericParam()))
{
auto genericParamType = (BfGenericParamType*)targetType;
auto genericParam = mModule->GetGenericParamInstance(genericParamType); auto genericParam = mModule->GetGenericParamInstance(genericParamType);
if (pass == 0)
origGenericParam = genericParam;
auto typeConstraint = genericParam->mTypeConstraint; auto typeConstraint = genericParam->mTypeConstraint;
if ((typeConstraint == NULL) && (genericParam->mGenericParamFlags & (BfGenericParamFlag_Class | BfGenericParamFlag_Interface))) if ((typeConstraint == NULL) && (genericParam->mGenericParamFlags & (BfGenericParamFlag_Class | BfGenericParamFlag_Interface)))
typeConstraint = mModule->mContext->mBfObjectType; typeConstraint = mModule->mContext->mBfObjectType;
targetType = typeConstraint;
if ((typeConstraint == NULL) || (!typeConstraint->IsObject())) if (++pass >= 100) // Sanity - but we should have caught circular error before
{ break;
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 ((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()) if (targetType->IsVar())
@ -11930,7 +11937,7 @@ void BfExprEvaluator::Visit(BfDynamicCastExpression* dynCastExpr)
auto _CheckResult = [&]() auto _CheckResult = [&]()
{ {
if ((mResult) && (origTargetType->IsGenericParam())) if ((mResult) && (origTargetType->IsGenericParam()))
mResult = mModule->GetDefaultTypedValue(origTargetType); mResult = mModule->GetDefaultTypedValue(origTargetType, false, BfDefaultValueKind_Undef);
}; };
if ((targetValue.mType->IsNullable()) && (targetType->IsInterface())) if ((targetValue.mType->IsNullable()) && (targetType->IsInterface()))

View file

@ -1198,14 +1198,23 @@ void BfModule::TryInitVar(BfAstNode* checkNode, BfLocalVariable* localVar, BfTyp
if (varType->IsGenericParam()) if (varType->IsGenericParam())
{ {
auto genericParamType = (BfGenericParamType*) varType; int pass = 0;
while (varType->IsGenericParam())
{
auto genericParamType = (BfGenericParamType*)varType;
auto genericParam = GetGenericParamInstance(genericParamType); auto genericParam = 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 = mContext->mBfObjectType; typeConstraint = mContext->mBfObjectType;
if (typeConstraint != NULL) if (typeConstraint != NULL)
varType = typeConstraint; 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(); 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 GenClassMethodB(GenClass<int> a) { return a.test++; }
public static int GenClassMethodC<A>(A a) where A : GenClass<int> { return a.test += 1; } 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] [Test]
public static void TestBasics() public static void TestBasics()
{ {