浏览代码

Fixed dynamic cast from class/interface constraint

Brian Fiete 4 年之前
父节点
当前提交
16a4b36b17
共有 2 个文件被更改,包括 29 次插入12 次删除
  1. 24 12
      IDEHelper/Compiler/BfExprEvaluator.cpp
  2. 5 0
      IDEHelper/Tests/src/Generics.bf

+ 24 - 12
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)

+ 5 - 0
IDEHelper/Tests/src/Generics.bf

@@ -190,6 +190,11 @@ namespace Tests
 		    }
 		}
 
+		public void TestCast<T, TI>(T val) where T : class where TI : interface
+		{
+			TI iface = val as TI;
+		}
+
 		[Test]
 		public static void TestBasics()
 		{