From 16a4b36b17a233bf314f74ea78786f4e188e3789 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Tue, 17 Nov 2020 17:37:09 -0800 Subject: [PATCH] Fixed dynamic cast from class/interface constraint --- IDEHelper/Compiler/BfExprEvaluator.cpp | 36 +++++++++++++++++--------- IDEHelper/Tests/src/Generics.bf | 5 ++++ 2 files changed, 29 insertions(+), 12 deletions(-) diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index 6dbab837..8afa8323 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/IDEHelper/Compiler/BfExprEvaluator.cpp @@ -9510,6 +9510,8 @@ void BfExprEvaluator::Visit(BfDynamicCastExpression* dynCastExpr) autoComplete->CheckTypeRef(dynCastExpr->mTypeRef, false, true); } + auto origTargetType = targetType; + if (!targetValue) return; if (!targetType) @@ -9547,24 +9549,23 @@ void BfExprEvaluator::Visit(BfDynamicCastExpression* dynCastExpr) auto genericParamType = (BfGenericParamType*) targetType; auto genericParam = mModule->GetGenericParamInstance(genericParamType); auto typeConstraint = genericParam->mTypeConstraint; - if ((typeConstraint == NULL) && (genericParam->mGenericParamFlags & BfGenericParamFlag_Class)) + 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' 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); return; } - targetType = typeConstraint; - targetValue = mModule->GetDefaultTypedValue(targetType); + targetType = typeConstraint; } 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->TypeToString(targetType).c_str()), dynCastExpr->mTypeRef); + mModule->TypeToString(origTargetType).c_str()), dynCastExpr->mTypeRef); return; } @@ -9582,23 +9583,29 @@ void BfExprEvaluator::Visit(BfDynamicCastExpression* dynCastExpr) mResult = mModule->GetDefaultTypedValue(targetType); return; } - - //targetType = typeConstraint; + targetValue = mModule->GetDefaultTypedValue(typeConstraint); } auto boolType = mModule->GetPrimitiveType(BfTypeCode_Boolean); + auto _CheckResult = [&]() + { + if ((mResult) && (origTargetType->IsGenericParam())) + mResult = mModule->GetDefaultTypedValue(origTargetType); + }; + if ((targetValue.mType->IsNullable()) && (targetType->IsInterface())) { mResult = mModule->Cast(dynCastExpr, targetValue, targetType, BfCastFlags_SilentFail); if (!mResult) { 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); - mResult = BfTypedValue(mModule->GetDefaultValue(targetType), targetType); - } - return; + mModule->TypeToString(targetValue.mType).c_str(), mModule->TypeToString(origTargetType).c_str()), dynCastExpr->mAsToken); + mResult = BfTypedValue(mModule->GetDefaultValue(origTargetType), origTargetType); + } + _CheckResult(); + return; } if (targetValue.mType->IsValueTypeOrValueTypePtr()) @@ -9624,6 +9631,7 @@ void BfExprEvaluator::Visit(BfDynamicCastExpression* dynCastExpr) hasValueAddr = mModule->mBfIRBuilder->CreateInBoundsGEP(allocaInst, 0, 0); // value mModule->mBfIRBuilder->CreateStore(targetValue.mValue, hasValueAddr); mResult = BfTypedValue(allocaInst, targetType, true); + _CheckResult(); return; } } @@ -9643,6 +9651,7 @@ void BfExprEvaluator::Visit(BfDynamicCastExpression* dynCastExpr) } else mResult = BfTypedValue(mModule->GetDefaultValue(targetType), targetType); + _CheckResult(); return; } @@ -9689,7 +9698,7 @@ void BfExprEvaluator::Visit(BfDynamicCastExpression* dynCastExpr) mModule->AddBasicBlock(endBB); mResult = BfTypedValue(allocaInst, targetType, true); - + _CheckResult(); return; } @@ -9721,6 +9730,7 @@ void BfExprEvaluator::Visit(BfDynamicCastExpression* dynCastExpr) auto castedValue = mModule->mBfIRBuilder->CreateBitCast(targetValue.mValue, mModule->mBfIRBuilder->MapType(targetTypeInstance)); mResult = BfTypedValue(castedValue, targetTypeInstance); + _CheckResult(); return; } else if ((!targetType->IsInterface()) && (!mModule->TypeIsSubTypeOf(targetTypeInstance, srcTypeInstance))) @@ -9732,6 +9742,7 @@ void BfExprEvaluator::Visit(BfDynamicCastExpression* dynCastExpr) if (autoComplete != NULL) { mResult = mModule->GetDefaultTypedValue(targetType); + _CheckResult(); return; } @@ -9755,6 +9766,7 @@ void BfExprEvaluator::Visit(BfDynamicCastExpression* dynCastExpr) mModule->AddBasicBlock(endBB); mResult = BfTypedValue(irb->CreateLoad(targetVal), targetType); + _CheckResult(); } void BfExprEvaluator::Visit(BfCastExpression* castExpr) diff --git a/IDEHelper/Tests/src/Generics.bf b/IDEHelper/Tests/src/Generics.bf index 53008abe..f5193c30 100644 --- a/IDEHelper/Tests/src/Generics.bf +++ b/IDEHelper/Tests/src/Generics.bf @@ -190,6 +190,11 @@ namespace Tests } } + public void TestCast(T val) where T : class where TI : interface + { + TI iface = val as TI; + } + [Test] public static void TestBasics() {