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
|
@ -11835,8 +11835,8 @@ void BfExprEvaluator::Visit(BfDynamicCastExpression* dynCastExpr)
|
||||||
{
|
{
|
||||||
auto targetValue = mModule->CreateValueFromExpression(dynCastExpr->mTarget);
|
auto targetValue = mModule->CreateValueFromExpression(dynCastExpr->mTarget);
|
||||||
auto targetType = mModule->ResolveTypeRefAllowUnboundGenerics(dynCastExpr->mTypeRef, BfPopulateType_Data, false);
|
auto targetType = mModule->ResolveTypeRefAllowUnboundGenerics(dynCastExpr->mTypeRef, BfPopulateType_Data, false);
|
||||||
|
|
||||||
auto autoComplete = GetAutoComplete();
|
auto autoComplete = GetAutoComplete();
|
||||||
if (autoComplete != NULL)
|
if (autoComplete != NULL)
|
||||||
{
|
{
|
||||||
autoComplete->CheckTypeRef(dynCastExpr->mTypeRef, false, true);
|
autoComplete->CheckTypeRef(dynCastExpr->mTypeRef, false, true);
|
||||||
|
@ -11873,25 +11873,32 @@ void BfExprEvaluator::Visit(BfDynamicCastExpression* dynCastExpr)
|
||||||
}
|
}
|
||||||
|
|
||||||
mModule->AddDependency(targetType, mModule->mCurTypeInstance, BfDependencyMap::DependencyFlag_ExprTypeReference);
|
mModule->AddDependency(targetType, mModule->mCurTypeInstance, BfDependencyMap::DependencyFlag_ExprTypeReference);
|
||||||
|
|
||||||
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;
|
||||||
auto genericParam = mModule->GetGenericParamInstance(genericParamType);
|
while ((targetType != NULL) && (targetType->IsGenericParam()))
|
||||||
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",
|
auto genericParamType = (BfGenericParamType*)targetType;
|
||||||
genericParam->GetGenericParamDef()->mName.c_str()), dynCastExpr->mTypeRef);
|
auto genericParam = mModule->GetGenericParamInstance(genericParamType);
|
||||||
return;
|
if (pass == 0)
|
||||||
|
origGenericParam = genericParam;
|
||||||
|
auto typeConstraint = genericParam->mTypeConstraint;
|
||||||
|
if ((typeConstraint == NULL) && (genericParam->mGenericParamFlags & (BfGenericParamFlag_Class | BfGenericParamFlag_Interface)))
|
||||||
|
typeConstraint = mModule->mContext->mBfObjectType;
|
||||||
|
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())
|
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()))
|
||||||
|
@ -12053,7 +12060,7 @@ void BfExprEvaluator::Visit(BfDynamicCastExpression* dynCastExpr)
|
||||||
mModule->Fail("Invalid dynamic cast type", dynCastExpr->mTypeRef);
|
mModule->Fail("Invalid dynamic cast type", dynCastExpr->mTypeRef);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
BfTypeInstance* srcTypeInstance = targetValue.mType->ToTypeInstance();
|
BfTypeInstance* srcTypeInstance = targetValue.mType->ToTypeInstance();
|
||||||
BfTypeInstance* targetTypeInstance = targetType->ToTypeInstance();
|
BfTypeInstance* targetTypeInstance = targetType->ToTypeInstance();
|
||||||
|
|
||||||
|
|
|
@ -1197,15 +1197,24 @@ void BfModule::TryInitVar(BfAstNode* checkNode, BfLocalVariable* localVar, BfTyp
|
||||||
bool isDynamicCast = false;
|
bool isDynamicCast = false;
|
||||||
|
|
||||||
if (varType->IsGenericParam())
|
if (varType->IsGenericParam())
|
||||||
{
|
{
|
||||||
auto genericParamType = (BfGenericParamType*) varType;
|
int pass = 0;
|
||||||
auto genericParam = GetGenericParamInstance(genericParamType);
|
while (varType->IsGenericParam())
|
||||||
auto typeConstraint = genericParam->mTypeConstraint;
|
{
|
||||||
if ((typeConstraint == NULL) && (genericParam->mGenericParamFlags & BfGenericParamFlag_Class))
|
auto genericParamType = (BfGenericParamType*)varType;
|
||||||
typeConstraint = mContext->mBfObjectType;
|
|
||||||
if (typeConstraint != NULL)
|
auto genericParam = GetGenericParamInstance(genericParamType);
|
||||||
varType = typeConstraint;
|
auto typeConstraint = genericParam->mTypeConstraint;
|
||||||
initValue = GetDefaultTypedValue(varType);
|
if ((typeConstraint == NULL) && (genericParam->mGenericParamFlags & (BfGenericParamFlag_Class | BfGenericParamFlag_Interface)))
|
||||||
|
typeConstraint = mContext->mBfObjectType;
|
||||||
|
if (typeConstraint != NULL)
|
||||||
|
varType = typeConstraint;
|
||||||
|
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();
|
||||||
|
|
|
@ -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()
|
||||||
{
|
{
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue