Переглянути джерело

Fixed constraint checks for inner types

Brian Fiete 3 роки тому
батько
коміт
bca82c231f

+ 32 - 0
IDE/Tests/CompileFail001/src/Generics.bf

@@ -119,6 +119,38 @@ namespace IDETest
 		{
 
 		}
+
+		public class TestExt<T> where T : struct
+		{
+			public struct InnerA
+			{
+
+			}
+
+			public struct InnerB<T2> where T2 : struct
+			{
+
+			}
+		}
+
+		extension TestExt<T>
+			where T : Int
+		{
+			public int a = 0;
+
+			public struct InnerC
+			{
+			}
+		}
+
+		static void TestExtMethod()
+		{
+			TestExt<String>.InnerA a; //FAIL
+			TestExt<String>.InnerB<int> b; //FAIL
+			TestExt<int>.InnerB<int> c;
+			TestExt<int>.InnerC d;
+			TestExt<float>.InnerC e; //FAIL
+		}
 	}
 }
 

+ 14 - 2
IDEHelper/Compiler/BfAutoComplete.cpp

@@ -713,15 +713,27 @@ const char* BfAutoComplete::GetTypeName(BfType* type)
 }
 
 void BfAutoComplete::AddInnerTypes(BfTypeInstance* typeInst, const StringImpl& filter, bool allowProtected, bool allowPrivate)
-{	
+{
 	if (typeInst->IsEnum())
 		AddEntry(AutoCompleteEntry("valuetype", "UnderlyingType"), filter);
 
 	for (auto innerType : typeInst->mTypeDef->mNestedTypes)
 	{
+		if (innerType->mOuterType->mTypeCode == BfTypeCode_Extension)
+		{
+			if (typeInst->mDefineState < BfTypeDefineState_Defined)
+				mModule->PopulateType(typeInst);
+
+			if ((typeInst->mGenericTypeInfo != NULL) && (typeInst->mGenericTypeInfo->mGenericExtensionInfo != NULL))
+			{
+				if (!typeInst->mGenericTypeInfo->mGenericExtensionInfo->mConstraintsPassedSet.IsSet(innerType->mOuterType->mPartialIdx))
+					continue;
+			}
+		}
+
 		if (CheckProtection(innerType->mProtection, innerType, allowProtected, allowPrivate))
 			AddTypeDef(innerType, filter);
-	}	
+	}
 
 	allowPrivate = false;
 	if (typeInst->mBaseType != NULL)

+ 30 - 4
IDEHelper/Compiler/BfModuleTypeUtils.cpp

@@ -9423,14 +9423,31 @@ BfType* BfModule::ResolveTypeResult(BfTypeReference* typeRef, BfType* resolvedTy
 	populateModule->PopulateType(resolvedTypeRef, populateType);
 	
 	if ((typeInstance != NULL) && (typeInstance->mTypeDef != NULL) && (typeInstance->mTypeDef->mProtection == BfProtection_Internal) && 
-		(typeInstance != mCurTypeInstance) && (typeInstance->mTypeDef->mOuterType == NULL) &&	(!typeRef->IsTemporary()))
+		(typeInstance != mCurTypeInstance) && (typeInstance->mTypeDef->mOuterType == NULL) && (!typeRef->IsTemporary()))
 	{
 		if (!CheckProtection(typeInstance->mTypeDef->mProtection, typeInstance->mTypeDef, false, false))
 			Fail(StrFormat("'%s' is inaccessible due to its protection level", TypeToString(typeInstance).c_str()), typeRef); // CS0122
 	}
 
-	if ((populateType > BfPopulateType_IdentityNoRemapAlias) && (!ResolveTypeResult_Validate(typeRef, resolvedTypeRef)))
-		return NULL;
+	// If the inner type is definted in an extension then we need to make sure the constraints are good
+	if ((typeInstance != NULL) && (typeInstance->mTypeDef != NULL) && (typeInstance->mTypeDef->mOuterType != NULL) && 
+		(typeInstance->mTypeDef->mOuterType->mTypeCode == BfTypeCode_Extension))
+	{
+		auto outerType = GetOuterType(typeInstance);
+		if ((outerType->mGenericTypeInfo != NULL) && (outerType->mGenericTypeInfo->mGenericExtensionInfo != NULL))
+		{
+			if (!outerType->mGenericTypeInfo->mGenericExtensionInfo->mConstraintsPassedSet.IsSet(typeInstance->mTypeDef->mOuterType->mPartialIdx))
+			{
+				Fail(StrFormat("'%s' is declared inside a type extension whose constraints were not met", TypeToString(typeInstance).c_str()), typeRef);
+			}
+		}
+	}
+
+	if (populateType > BfPopulateType_IdentityNoRemapAlias)
+	{
+		if (!ResolveTypeResult_Validate(typeRef, resolvedTypeRef))
+			return NULL;
+	}
 	
 	if ((populateType != BfPopulateType_TypeDef) && (populateType != BfPopulateType_IdentityNoRemapAlias))
 	{
@@ -10827,7 +10844,16 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula
 		if (leftType == NULL)
 		{
 			BfAutoParentNodeEntry autoParentNodeEntry(this, qualifiedTypeRef);
-			leftType = ResolveTypeRef(qualifiedTypeRef->mLeft, BfPopulateType_Identity, (BfResolveTypeRefFlags)((resolveFlags | BfResolveTypeRefFlag_IgnoreLookupError) & ~BfResolveTypeRefFlag_Attribute)); // We throw an error below if we can't find the type
+			
+			auto leftPopulateType = BfPopulateType_Identity;
+			if ((resolveFlags & BfResolveTypeRefFlag_AllowUnboundGeneric) == 0)
+			{
+				// We can't just pass 'Identity' here because it won't validate a generic type ref on the left
+				leftPopulateType = BfPopulateType_Declaration;
+			}
+
+			leftType = ResolveTypeRef(qualifiedTypeRef->mLeft, leftPopulateType,
+				(BfResolveTypeRefFlags)((resolveFlags | BfResolveTypeRefFlag_IgnoreLookupError) & ~BfResolveTypeRefFlag_Attribute)); // We throw an error below if we can't find the type
 		}
 				
 		if (leftType == NULL)