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:
parent
10682e67af
commit
06ceaf617b
3 changed files with 55 additions and 26 deletions
|
@ -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()))
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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()
|
||||
{
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue