1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-06-09 20:12:21 +02:00

Partial recursive generic fixes, deferred constraint type validation

This commit is contained in:
Brian Fiete 2021-02-16 14:53:48 -08:00
parent 3681b521b5
commit eb86c717f0
9 changed files with 162 additions and 53 deletions

View file

@ -398,6 +398,7 @@ BfCompiler::BfCompiler(BfSystem* bfSystem, bool isResolveOnly)
mDbgRawAllocDataTypeDef = NULL; mDbgRawAllocDataTypeDef = NULL;
mDeferredCallTypeDef = NULL; mDeferredCallTypeDef = NULL;
mDelegateTypeDef = NULL; mDelegateTypeDef = NULL;
mFunctionTypeDef = NULL;
mActionTypeDef = NULL; mActionTypeDef = NULL;
mEnumTypeDef = NULL; mEnumTypeDef = NULL;
mFriendAttributeTypeDef = NULL; mFriendAttributeTypeDef = NULL;
@ -406,7 +407,6 @@ BfCompiler::BfCompiler(BfSystem* bfSystem, bool isResolveOnly)
mNoExtensionAttributeTypeDef = NULL; mNoExtensionAttributeTypeDef = NULL;
mCheckedAttributeTypeDef = NULL; mCheckedAttributeTypeDef = NULL;
mUncheckedAttributeTypeDef = NULL; mUncheckedAttributeTypeDef = NULL;
mFunctionTypeDef = NULL;
mGCTypeDef = NULL; mGCTypeDef = NULL;
mGenericIEnumerableTypeDef = NULL; mGenericIEnumerableTypeDef = NULL;
mGenericIEnumeratorTypeDef = NULL; mGenericIEnumeratorTypeDef = NULL;
@ -6665,6 +6665,7 @@ bool BfCompiler::DoCompile(const StringImpl& outputDirectory)
mDbgRawAllocDataTypeDef = _GetRequiredType("System.DbgRawAllocData"); mDbgRawAllocDataTypeDef = _GetRequiredType("System.DbgRawAllocData");
mDeferredCallTypeDef = _GetRequiredType("System.DeferredCall"); mDeferredCallTypeDef = _GetRequiredType("System.DeferredCall");
mDelegateTypeDef = _GetRequiredType("System.Delegate"); mDelegateTypeDef = _GetRequiredType("System.Delegate");
mFunctionTypeDef = _GetRequiredType("System.Function");
mActionTypeDef = _GetRequiredType("System.Action"); mActionTypeDef = _GetRequiredType("System.Action");
mEnumTypeDef = _GetRequiredType("System.Enum"); mEnumTypeDef = _GetRequiredType("System.Enum");
mFriendAttributeTypeDef = _GetRequiredType("System.FriendAttribute"); mFriendAttributeTypeDef = _GetRequiredType("System.FriendAttribute");
@ -6674,7 +6675,6 @@ bool BfCompiler::DoCompile(const StringImpl& outputDirectory)
mCheckedAttributeTypeDef = _GetRequiredType("System.CheckedAttribute"); mCheckedAttributeTypeDef = _GetRequiredType("System.CheckedAttribute");
mUncheckedAttributeTypeDef = _GetRequiredType("System.UncheckedAttribute"); mUncheckedAttributeTypeDef = _GetRequiredType("System.UncheckedAttribute");
mResultTypeDef = _GetRequiredType("System.Result", 1); mResultTypeDef = _GetRequiredType("System.Result", 1);
mFunctionTypeDef = _GetRequiredType("System.Function");
mGCTypeDef = _GetRequiredType("System.GC"); mGCTypeDef = _GetRequiredType("System.GC");
mGenericIEnumerableTypeDef = _GetRequiredType("System.Collections.IEnumerable", 1); mGenericIEnumerableTypeDef = _GetRequiredType("System.Collections.IEnumerable", 1);
mGenericIEnumeratorTypeDef = _GetRequiredType("System.Collections.IEnumerator", 1); mGenericIEnumeratorTypeDef = _GetRequiredType("System.Collections.IEnumerator", 1);

View file

@ -353,6 +353,7 @@ public:
BfTypeDef* mDbgRawAllocDataTypeDef; BfTypeDef* mDbgRawAllocDataTypeDef;
BfTypeDef* mDeferredCallTypeDef; BfTypeDef* mDeferredCallTypeDef;
BfTypeDef* mDelegateTypeDef; BfTypeDef* mDelegateTypeDef;
BfTypeDef* mFunctionTypeDef;
BfTypeDef* mActionTypeDef; BfTypeDef* mActionTypeDef;
BfTypeDef* mEnumTypeDef; BfTypeDef* mEnumTypeDef;
BfTypeDef* mStringTypeDef; BfTypeDef* mStringTypeDef;
@ -360,7 +361,6 @@ public:
BfTypeDef* mTypeTypeDef; BfTypeDef* mTypeTypeDef;
BfTypeDef* mValueTypeTypeDef; BfTypeDef* mValueTypeTypeDef;
BfTypeDef* mResultTypeDef; BfTypeDef* mResultTypeDef;
BfTypeDef* mFunctionTypeDef;
BfTypeDef* mGCTypeDef; BfTypeDef* mGCTypeDef;
BfTypeDef* mGenericIEnumerableTypeDef; BfTypeDef* mGenericIEnumerableTypeDef;
BfTypeDef* mGenericIEnumeratorTypeDef; BfTypeDef* mGenericIEnumeratorTypeDef;

View file

@ -3425,10 +3425,11 @@ void BfModule::AddDependency(BfType* usedType, BfType* userType, BfDependencyMap
BfModule* usedModule; BfModule* usedModule;
if (usedType->IsFunction()) if (usedType->IsFunction())
{ {
auto typeInst = usedType->ToTypeInstance(); if (mCompiler->mFunctionTypeDef != NULL)
if (typeInst->mBaseType == NULL) {
PopulateType(typeInst); auto functionType = ResolveTypeDef(mCompiler->mFunctionTypeDef)->ToTypeInstance();
usedModule = typeInst->mBaseType->GetModule(); usedModule = functionType->GetModule();
}
} }
else else
usedModule = usedType->GetModule(); usedModule = usedType->GetModule();
@ -7217,7 +7218,7 @@ BfIRFunction BfModule::GetBuiltInFunc(BfBuiltInFuncType funcTypeId)
return mBuiltInFuncs[(int)funcTypeId]; return mBuiltInFuncs[(int)funcTypeId];
} }
void BfModule::ResolveGenericParamConstraints(BfGenericParamInstance* genericParamInstance, bool isUnspecialized) void BfModule::ResolveGenericParamConstraints(BfGenericParamInstance* genericParamInstance, bool isUnspecialized, Array<BfTypeReference*>* deferredResolveTypes)
{ {
BfGenericParamDef* genericParamDef = genericParamInstance->GetGenericParamDef(); BfGenericParamDef* genericParamDef = genericParamInstance->GetGenericParamDef();
BfExternalConstraintDef* externConstraintDef = genericParamInstance->GetExternConstraintDef(); BfExternalConstraintDef* externConstraintDef = genericParamInstance->GetExternConstraintDef();
@ -7323,14 +7324,23 @@ void BfModule::ResolveGenericParamConstraints(BfGenericParamInstance* genericPar
if (bfAutocomplete != NULL) if (bfAutocomplete != NULL)
bfAutocomplete->CheckTypeRef(constraintTypeRef, true); bfAutocomplete->CheckTypeRef(constraintTypeRef, true);
//TODO: Constraints may refer to other generic params (of either type or method) //TODO: Constraints may refer to other generic params (of either type or method)
// TO allow resolution, perhaps move this generic param initalization into GetMethodInstance (passing a genericPass bool) // TO allow resolution, perhaps move this generic param initialization into GetMethodInstance (passing a genericPass bool)
BfResolveTypeRefFlags resolveFlags = BfResolveTypeRefFlag_AllowGenericMethodParamConstValue; BfResolveTypeRefFlags resolveFlags = BfResolveTypeRefFlag_AllowGenericMethodParamConstValue;
if (isUnspecialized) if (isUnspecialized)
resolveFlags = (BfResolveTypeRefFlags)(resolveFlags | BfResolveTypeRefFlag_DisallowComptime); resolveFlags = (BfResolveTypeRefFlags)(resolveFlags | BfResolveTypeRefFlag_DisallowComptime);
auto constraintType = ResolveTypeRef(constraintTypeRef, BfPopulateType_Declaration, resolveFlags); // We we have a deferredResolveTypes then we defer the generic validation, because we may have a case like
// `where T : Dictionay<TElem, int> and TElem : IHashable` and we don't want to throw the error on `T` before we build `TElem`
auto constraintType = ResolveTypeRef(constraintTypeRef, (deferredResolveTypes != NULL) ? BfPopulateType_Identity : BfPopulateType_Declaration, resolveFlags);
if (constraintType != NULL) if (constraintType != NULL)
{ {
if (deferredResolveTypes != NULL)
{
PopulateType(constraintType, BfPopulateType_Declaration);
if (constraintType->IsUnspecializedTypeVariation())
deferredResolveTypes->Add(constraintTypeRef);
}
if ((constraintDef->mGenericParamFlags & BfGenericParamFlag_Const) != 0) if ((constraintDef->mGenericParamFlags & BfGenericParamFlag_Const) != 0)
{ {
bool isValidTypeCode = false; bool isValidTypeCode = false;
@ -7515,7 +7525,7 @@ bool BfModule::CheckGenericConstraints(const BfGenericParamSource& genericParamS
int checkGenericParamFlags = 0; int checkGenericParamFlags = 0;
if (checkArgType->IsGenericParam()) if (checkArgType->IsGenericParam())
{ {
auto checkGenericParamInst = GetGenericParamInstance((BfGenericParamType*)checkArgType); BfGenericParamInstance* checkGenericParamInst = GetGenericParamInstance((BfGenericParamType*)checkArgType);
checkGenericParamFlags = checkGenericParamInst->mGenericParamFlags; checkGenericParamFlags = checkGenericParamInst->mGenericParamFlags;
if (checkGenericParamInst->mTypeConstraint != NULL) if (checkGenericParamInst->mTypeConstraint != NULL)
checkArgType = checkGenericParamInst->mTypeConstraint; checkArgType = checkGenericParamInst->mTypeConstraint;
@ -21616,6 +21626,7 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool
{ {
BfTypeInstance* unspecializedTypeInstance = NULL; BfTypeInstance* unspecializedTypeInstance = NULL;
Array<BfTypeReference*> deferredResolveTypes;
for (int genericParamIdx = 0; genericParamIdx < (int)methodInstance->mMethodInfoEx->mGenericParams.size(); genericParamIdx++) for (int genericParamIdx = 0; genericParamIdx < (int)methodInstance->mMethodInfoEx->mGenericParams.size(); genericParamIdx++)
{ {
auto genericParam = methodInstance->mMethodInfoEx->mGenericParams[genericParamIdx]; auto genericParam = methodInstance->mMethodInfoEx->mGenericParams[genericParamIdx];
@ -21640,7 +21651,7 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool
genericParam->mExternType = GetPrimitiveType(BfTypeCode_Var); genericParam->mExternType = GetPrimitiveType(BfTypeCode_Var);
} }
ResolveGenericParamConstraints(genericParam, methodInstance->mIsUnspecialized); ResolveGenericParamConstraints(genericParam, methodInstance->mIsUnspecialized, &deferredResolveTypes);
if (genericParamIdx < (int)methodDef->mGenericParams.size()) if (genericParamIdx < (int)methodDef->mGenericParams.size())
{ {
@ -21654,6 +21665,8 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool
} }
} }
} }
for (auto typeRef : deferredResolveTypes)
auto constraintType = ResolveTypeRef(typeRef, BfPopulateType_Declaration, BfResolveTypeRefFlag_None);
for (auto genericParam : methodInstance->mMethodInfoEx->mGenericParams) for (auto genericParam : methodInstance->mMethodInfoEx->mGenericParams)
{ {

View file

@ -1778,7 +1778,7 @@ public:
bool TypeEquals(BfTypedValue& val, BfType* type); bool TypeEquals(BfTypedValue& val, BfType* type);
BfTypeDef* ResolveGenericInstanceDef(BfGenericInstanceTypeRef* genericTypeRef, BfType** outType = NULL, BfResolveTypeRefFlags resolveFlags = BfResolveTypeRefFlag_None); BfTypeDef* ResolveGenericInstanceDef(BfGenericInstanceTypeRef* genericTypeRef, BfType** outType = NULL, BfResolveTypeRefFlags resolveFlags = BfResolveTypeRefFlag_None);
BfType* ResolveType(BfType* lookupType, BfPopulateType populateType = BfPopulateType_Data, BfResolveTypeRefFlags resolveFlags = BfResolveTypeRefFlag_None); BfType* ResolveType(BfType* lookupType, BfPopulateType populateType = BfPopulateType_Data, BfResolveTypeRefFlags resolveFlags = BfResolveTypeRefFlag_None);
void ResolveGenericParamConstraints(BfGenericParamInstance* genericParamInstance, bool isUnspecialized); void ResolveGenericParamConstraints(BfGenericParamInstance* genericParamInstance, bool isUnspecialized, Array<BfTypeReference*>* deferredResolveTypes = NULL);
String GenericParamSourceToString(const BfGenericParamSource& genericParamSource); String GenericParamSourceToString(const BfGenericParamSource& genericParamSource);
bool CheckGenericConstraints(const BfGenericParamSource& genericParamSource, BfType* checkArgType, BfAstNode* checkArgTypeRef, BfGenericParamInstance* genericParamInst, BfTypeVector* methodGenericArgs = NULL, BfError** errorOut = NULL); bool CheckGenericConstraints(const BfGenericParamSource& genericParamSource, BfType* checkArgType, BfAstNode* checkArgTypeRef, BfGenericParamInstance* genericParamInst, BfTypeVector* methodGenericArgs = NULL, BfError** errorOut = NULL);
BfIRValue AllocLocalVariable(BfType* type, const StringImpl& name, bool doLifetimeEnd = true); BfIRValue AllocLocalVariable(BfType* type, const StringImpl& name, bool doLifetimeEnd = true);

View file

@ -164,6 +164,7 @@ bool BfModule::FinishGenericParams(BfType* resolvedTypeRef)
typeState.mResolveKind = BfTypeState::ResolveKind_BuildingGenericParams; typeState.mResolveKind = BfTypeState::ResolveKind_BuildingGenericParams;
typeState.mTypeInstance = resolvedTypeRef->ToTypeInstance(); typeState.mTypeInstance = resolvedTypeRef->ToTypeInstance();
SetAndRestoreValue<BfTypeState*> prevTypeState(mContext->mCurTypeState, &typeState); SetAndRestoreValue<BfTypeState*> prevTypeState(mContext->mCurTypeState, &typeState);
Array<BfTypeReference*> deferredResolveTypes;
BF_ASSERT(mCurMethodInstance == NULL); BF_ASSERT(mCurMethodInstance == NULL);
@ -210,7 +211,7 @@ bool BfModule::FinishGenericParams(BfType* resolvedTypeRef)
genericParamInstance->mExternType = GetPrimitiveType(BfTypeCode_Var); genericParamInstance->mExternType = GetPrimitiveType(BfTypeCode_Var);
} }
ResolveGenericParamConstraints(genericParamInstance, genericTypeInst->IsUnspecializedType()); ResolveGenericParamConstraints(genericParamInstance, genericTypeInst->IsUnspecializedType(), &deferredResolveTypes);
if (genericParamDef != NULL) if (genericParamDef != NULL)
{ {
@ -283,7 +284,7 @@ bool BfModule::FinishGenericParams(BfType* resolvedTypeRef)
genericParamInstance->mExternType = GetPrimitiveType(BfTypeCode_Var); genericParamInstance->mExternType = GetPrimitiveType(BfTypeCode_Var);
} }
ResolveGenericParamConstraints(genericParamInstance, genericTypeInst->IsUnspecializedType()); ResolveGenericParamConstraints(genericParamInstance, genericTypeInst->IsUnspecializedType(), &deferredResolveTypes);
auto genericParamDef = genericParamInstance->GetGenericParamDef(); auto genericParamDef = genericParamInstance->GetGenericParamDef();
if (genericParamDef != NULL) if (genericParamDef != NULL)
{ {
@ -295,6 +296,9 @@ bool BfModule::FinishGenericParams(BfType* resolvedTypeRef)
} }
} }
for (auto typeRef : deferredResolveTypes)
auto constraintType = ResolveTypeRef(typeRef, BfPopulateType_Declaration, BfResolveTypeRefFlag_None);
for (auto genericParam : genericTypeInst->mGenericTypeInfo->mGenericParams) for (auto genericParam : genericTypeInst->mGenericTypeInfo->mGenericParams)
{ {
for (auto constraintTypeInst : genericParam->mInterfaceConstraints) for (auto constraintTypeInst : genericParam->mInterfaceConstraints)
@ -339,6 +343,13 @@ bool BfModule::ValidateGenericConstraints(BfTypeReference* typeRef, BfTypeInstan
return true; return true;
} }
for (auto typeArg : genericTypeInst->mGenericTypeInfo->mTypeGenericArguments)
{
auto genericArg = typeArg->ToGenericTypeInstance();
if (genericArg != NULL)
genericTypeInst->mGenericTypeInfo->mMaxGenericDepth = BF_MAX(genericTypeInst->mGenericTypeInfo->mMaxGenericDepth, genericArg->mGenericTypeInfo->mMaxGenericDepth + 1);
}
auto typeDef = genericTypeInst->mTypeDef; auto typeDef = genericTypeInst->mTypeDef;
for (int paramIdx = 0; paramIdx < (int)genericTypeInst->mGenericTypeInfo->mGenericParams.size(); paramIdx++) for (int paramIdx = 0; paramIdx < (int)genericTypeInst->mGenericTypeInfo->mGenericParams.size(); paramIdx++)
{ {
@ -4973,7 +4984,7 @@ void BfModule::DoTypeInstanceMethodProcessing(BfTypeInstance* typeInstance)
// //
{ {
if (typeInstance->IsSpecializedType()) if ((typeInstance->IsSpecializedType()) || (typeInstance->IsUnspecializedTypeVariation()))
wantsOnDemandMethods = true; wantsOnDemandMethods = true;
else if ((mCompiler->mOptions.mCompileOnDemandKind != BfCompileOnDemandKind_AlwaysInclude) && else if ((mCompiler->mOptions.mCompileOnDemandKind != BfCompileOnDemandKind_AlwaysInclude) &&
(!typeInstance->IsUnspecializedTypeVariation())) (!typeInstance->IsUnspecializedTypeVariation()))
@ -7939,7 +7950,7 @@ bool BfModule::ResolveTypeResult_Validate(BfTypeReference* typeRef, BfType* reso
if ((curGenericTypeInstance->mDependencyMap.mMinDependDepth > 32) && if ((curGenericTypeInstance->mDependencyMap.mMinDependDepth > 32) &&
(genericTypeInstance->mDependencyMap.mMinDependDepth > 32)) (genericTypeInstance->mDependencyMap.mMinDependDepth > 32))
{ {
Fail(StrFormat("Generic type dependency depth exceeded for type '{}'", TypeToString(genericTypeInstance).c_str()), typeRef); Fail(StrFormat("Generic type dependency depth exceeded for type '%s'", TypeToString(genericTypeInstance).c_str()), typeRef);
return false; return false;
} }
@ -9724,7 +9735,14 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula
CheckUnspecializedGenericType(genericTypeInst, populateType); CheckUnspecializedGenericType(genericTypeInst, populateType);
resolvedEntry->mValue = genericTypeInst; resolvedEntry->mValue = genericTypeInst;
populateModule->InitType(genericTypeInst, populateType); populateModule->InitType(genericTypeInst, populateType);
BF_ASSERT(BfResolvedTypeSet::Hash(genericTypeInst, &lookupCtx) == resolvedEntry->mHash); #ifdef _DEBUG
if (BfResolvedTypeSet::Hash(genericTypeInst, &lookupCtx) != resolvedEntry->mHash)
{
int refHash = BfResolvedTypeSet::Hash(typeRef, &lookupCtx);
int typeHash = BfResolvedTypeSet::Hash(genericTypeInst, &lookupCtx);
BF_ASSERT(refHash == typeHash);
}
#endif
return ResolveTypeResult(typeRef, genericTypeInst, populateType, resolveFlags); return ResolveTypeResult(typeRef, genericTypeInst, populateType, resolveFlags);
} }
} }
@ -9978,15 +9996,16 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula
auto parentTypeInstance = outerTypeInstance; auto parentTypeInstance = outerTypeInstance;
if (parentTypeInstance->IsTypeAlias()) if (parentTypeInstance->IsTypeAlias())
parentTypeInstance = (BfTypeInstance*)GetOuterType(parentTypeInstance)->ToTypeInstance(); parentTypeInstance = (BfTypeInstance*)GetOuterType(parentTypeInstance)->ToTypeInstance();
genericTypeInst->mGenericTypeInfo->mMaxGenericDepth = BF_MAX(genericTypeInst->mGenericTypeInfo->mMaxGenericDepth, parentTypeInstance->mGenericTypeInfo->mMaxGenericDepth);
for (int i = 0; i < startDefGenericParamIdx; i++) for (int i = 0; i < startDefGenericParamIdx; i++)
{ {
genericTypeInst->mGenericTypeInfo->mGenericParams.push_back(parentTypeInstance->mGenericTypeInfo->mGenericParams[i]->AddRef()); genericTypeInst->mGenericTypeInfo->mGenericParams.push_back(parentTypeInstance->mGenericTypeInfo->mGenericParams[i]->AddRef());
genericTypeInst->mGenericTypeInfo->mTypeGenericArguments.push_back(parentTypeInstance->mGenericTypeInfo->mTypeGenericArguments[i]); genericTypeInst->mGenericTypeInfo->mTypeGenericArguments.push_back(parentTypeInstance->mGenericTypeInfo->mTypeGenericArguments[i]);
auto typeGenericArg = genericTypeInst->mGenericTypeInfo->mTypeGenericArguments[i]; auto typeGenericArg = genericTypeInst->mGenericTypeInfo->mTypeGenericArguments[i];
genericTypeInst->mGenericTypeInfo->mIsUnspecialized |= typeGenericArg->IsGenericParam() || typeGenericArg->IsUnspecializedType(); genericTypeInst->mGenericTypeInfo->mIsUnspecialized |= typeGenericArg->IsGenericParam() || typeGenericArg->IsUnspecializedType();
}
}
}
}
int wantedGenericParams = genericParamCount - startDefGenericParamIdx; int wantedGenericParams = genericParamCount - startDefGenericParamIdx;
int genericArgDiffCount = (int)genericArguments.size() - wantedGenericParams; int genericArgDiffCount = (int)genericArguments.size() - wantedGenericParams;
@ -10005,12 +10024,26 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula
for (auto genericArgRef : genericArguments) for (auto genericArgRef : genericArguments)
{ {
auto genericArg = genericArgs[genericParamIdx + startDefGenericParamIdx]; auto genericArg = genericArgs[genericParamIdx + startDefGenericParamIdx];
if (auto genericGenericArg = genericArg->ToGenericTypeInstance())
{
genericTypeInst->mGenericTypeInfo->mMaxGenericDepth = BF_MAX(genericTypeInst->mGenericTypeInfo->mMaxGenericDepth, genericGenericArg->mGenericTypeInfo->mMaxGenericDepth + 1);
}
genericTypeInst->mGenericTypeInfo->mTypeGenericArguments.push_back(genericArg); genericTypeInst->mGenericTypeInfo->mTypeGenericArguments.push_back(genericArg);
genericTypeInst->mGenericTypeInfo->mTypeGenericArgumentRefs.push_back(genericArgRef); genericTypeInst->mGenericTypeInfo->mTypeGenericArgumentRefs.push_back(genericArgRef);
genericParamIdx++; genericParamIdx++;
} }
if (genericTypeInst->mGenericTypeInfo->mMaxGenericDepth > 64)
{
Fail("Maximum generic depth exceeded", typeRef);
delete genericTypeInst;
mContext->mResolvedTypes.RemoveEntry(resolvedEntry);
return ResolveTypeResult(typeRef, NULL, populateType, resolveFlags);
}
resolvedEntry->mValue = genericTypeInst; resolvedEntry->mValue = genericTypeInst;
CheckUnspecializedGenericType(genericTypeInst, populateType); CheckUnspecializedGenericType(genericTypeInst, populateType);
@ -10027,6 +10060,8 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula
{ {
BF_ASSERT(BfResolvedTypeSet::Equals(genericTypeInst, typeRef, &lookupCtx)); BF_ASSERT(BfResolvedTypeSet::Equals(genericTypeInst, typeRef, &lookupCtx));
} }
BfLogSysM("Generic type %p typeHash: %8X\n", genericTypeInst, resolvedEntry->mHash);
#endif #endif
BF_ASSERT(BfResolvedTypeSet::Hash(genericTypeInst, &lookupCtx) == resolvedEntry->mHash); BF_ASSERT(BfResolvedTypeSet::Hash(genericTypeInst, &lookupCtx) == resolvedEntry->mHash);
@ -10161,7 +10196,14 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula
CheckUnspecializedGenericType(genericTypeInst, populateType); CheckUnspecializedGenericType(genericTypeInst, populateType);
resolvedEntry->mValue = genericTypeInst; resolvedEntry->mValue = genericTypeInst;
BF_ASSERT(BfResolvedTypeSet::Hash(genericTypeInst, &lookupCtx) == resolvedEntry->mHash); #ifdef _DEBUG
if (BfResolvedTypeSet::Hash(genericTypeInst, &lookupCtx) != resolvedEntry->mHash)
{
int refHash = BfResolvedTypeSet::Hash(typeRef, &lookupCtx);
int typeHash = BfResolvedTypeSet::Hash(genericTypeInst, &lookupCtx);
BF_ASSERT(refHash == typeHash);
}
#endif
populateModule->InitType(genericTypeInst, populateType); populateModule->InitType(genericTypeInst, populateType);
return ResolveTypeResult(typeRef, genericTypeInst, populateType, resolveFlags); return ResolveTypeResult(typeRef, genericTypeInst, populateType, resolveFlags);
} }

View file

@ -2723,6 +2723,8 @@ BfResolvedTypeSet::~BfResolvedTypeSet()
} }
#define HASH_MIX(origHashVal, newHashVal) ((((origHashVal) << 5) - (origHashVal)) ^ (newHashVal))
#define HASH_VAL_PTR 1 #define HASH_VAL_PTR 1
#define HASH_VAL_BOXED 2 #define HASH_VAL_BOXED 2
#define HASH_VAL_REF 3 #define HASH_VAL_REF 3
@ -2769,7 +2771,7 @@ BfVariant BfResolvedTypeSet::EvaluateToVariant(LookupContext* ctx, BfExpression*
return variant; return variant;
} }
int BfResolvedTypeSet::Hash(BfType* type, LookupContext* ctx, bool allowRef) int BfResolvedTypeSet::DoHash(BfType* type, LookupContext* ctx, bool allowRef, int hashSeed)
{ {
//BP_ZONE("BfResolvedTypeSet::Hash"); //BP_ZONE("BfResolvedTypeSet::Hash");
@ -2876,7 +2878,7 @@ int BfResolvedTypeSet::Hash(BfType* type, LookupContext* ctx, bool allowRef)
{ {
BfTypeInstance* genericType = (BfTypeInstance*)type; BfTypeInstance* genericType = (BfTypeInstance*)type;
for (auto genericArg : genericType->mGenericTypeInfo->mTypeGenericArguments) for (auto genericArg : genericType->mGenericTypeInfo->mTypeGenericArguments)
hashVal = ((hashVal ^ (Hash(genericArg, ctx))) << 5) - hashVal; hashVal = HASH_MIX(hashVal, Hash(genericArg, ctx, BfHashFlag_None, hashSeed + 1));
} }
return hashVal; return hashVal;
} }
@ -2952,21 +2954,29 @@ int BfResolvedTypeSet::Hash(BfType* type, LookupContext* ctx, bool allowRef)
return 0; return 0;
} }
void BfResolvedTypeSet::HashGenericArguments(BfTypeReference* typeRef, LookupContext* ctx, int& hashVal) int BfResolvedTypeSet::Hash(BfType* type, LookupContext* ctx, bool allowRef, int hashSeed)
{
int hashVal = DoHash(type, ctx, allowRef, hashSeed);
if (hashSeed == 0)
return hashVal;
return HASH_MIX(hashVal, hashSeed);
}
void BfResolvedTypeSet::HashGenericArguments(BfTypeReference* typeRef, LookupContext* ctx, int& hashVal, int hashSeed)
{ {
if (auto elementedTypeRef = BfNodeDynCast<BfElementedTypeRef>(typeRef)) if (auto elementedTypeRef = BfNodeDynCast<BfElementedTypeRef>(typeRef))
{ {
HashGenericArguments(elementedTypeRef->mElementType, ctx, hashVal); HashGenericArguments(elementedTypeRef->mElementType, ctx, hashVal, hashSeed);
} }
else if (auto qualifiedTypeRef = BfNodeDynCast<BfQualifiedTypeReference>(typeRef)) else if (auto qualifiedTypeRef = BfNodeDynCast<BfQualifiedTypeReference>(typeRef))
{ {
HashGenericArguments(qualifiedTypeRef->mLeft, ctx, hashVal); HashGenericArguments(qualifiedTypeRef->mLeft, ctx, hashVal, hashSeed);
} }
if (auto genericTypeRef = BfNodeDynCast<BfGenericInstanceTypeRef>(typeRef)) if (auto genericTypeRef = BfNodeDynCast<BfGenericInstanceTypeRef>(typeRef))
{ {
for (auto genericArg : genericTypeRef->mGenericArguments) for (auto genericArg : genericTypeRef->mGenericArguments)
hashVal = ((hashVal ^ (Hash(genericArg, ctx, BfHashFlag_AllowGenericParamConstValue))) << 5) - hashVal; hashVal = HASH_MIX(hashVal, Hash(genericArg, ctx, BfHashFlag_AllowGenericParamConstValue, hashSeed + 1));
} }
} }
@ -2978,7 +2988,7 @@ static int HashNode(BfAstNode* node)
return (int)Hash64(nameStr, node->GetSrcLength()); return (int)Hash64(nameStr, node->GetSrcLength());
} }
int BfResolvedTypeSet::DirectHash(BfTypeReference* typeRef, LookupContext* ctx, BfHashFlags flags) int BfResolvedTypeSet::DirectHash(BfTypeReference* typeRef, LookupContext* ctx, BfHashFlags flags, int hashSeed)
{ {
bool isHeadType = typeRef == ctx->mRootTypeRef; bool isHeadType = typeRef == ctx->mRootTypeRef;
@ -2992,7 +3002,7 @@ int BfResolvedTypeSet::DirectHash(BfTypeReference* typeRef, LookupContext* ctx,
ctx->mFailed = true; ctx->mFailed = true;
return 0; return 0;
} }
return Hash(resolvedType, ctx); return Hash(resolvedType, ctx, BfHashFlag_None, hashSeed);
} }
BfTypeDef* BfResolvedTypeSet::FindRootCommonOuterType(BfTypeDef* outerType, LookupContext* ctx, BfTypeInstance*& outOuterTypeInstance) BfTypeDef* BfResolvedTypeSet::FindRootCommonOuterType(BfTypeDef* outerType, LookupContext* ctx, BfTypeInstance*& outOuterTypeInstance)
@ -3022,7 +3032,7 @@ BfTypeDef* BfResolvedTypeSet::FindRootCommonOuterType(BfTypeDef* outerType, Look
return commonOuterType; return commonOuterType;
} }
int BfResolvedTypeSet::Hash(BfTypeReference* typeRef, LookupContext* ctx, BfHashFlags flags) int BfResolvedTypeSet::DoHash(BfTypeReference* typeRef, LookupContext* ctx, BfHashFlags flags, int& hashSeed)
{ {
if ((typeRef == ctx->mRootTypeRef) && (ctx->mRootTypeDef != NULL) && if ((typeRef == ctx->mRootTypeRef) && (ctx->mRootTypeDef != NULL) &&
((typeRef->IsNamedTypeReference()) || (BfNodeIsA<BfDirectTypeDefReference>(typeRef)))) ((typeRef->IsNamedTypeReference()) || (BfNodeIsA<BfDirectTypeDefReference>(typeRef))))
@ -3075,7 +3085,7 @@ int BfResolvedTypeSet::Hash(BfTypeReference* typeRef, LookupContext* ctx, BfHash
int numParentGenericParams = (int)commonOuterType->mGenericParamDefs.size(); int numParentGenericParams = (int)commonOuterType->mGenericParamDefs.size();
for (int i = 0; i < numParentGenericParams; i++) for (int i = 0; i < numParentGenericParams; i++)
{ {
hashVal = ((hashVal ^ (Hash(curGenericTypeInst->mGenericTypeInfo->mTypeGenericArguments[i], ctx))) << 5) - hashVal; hashVal = HASH_MIX(hashVal, Hash(curGenericTypeInst->mGenericTypeInfo->mTypeGenericArguments[i], ctx, BfHashFlag_None, hashSeed + 1));
} }
} }
@ -3084,7 +3094,9 @@ int BfResolvedTypeSet::Hash(BfTypeReference* typeRef, LookupContext* ctx, BfHash
if (typeRef->IsNamedTypeReference()) if (typeRef->IsNamedTypeReference())
{ {
return DirectHash(typeRef, ctx, flags); int hashVal = DirectHash(typeRef, ctx, flags, hashSeed);
hashSeed = 0;
return hashVal;
} }
if (auto genericInstTypeRef = BfNodeDynCastExact<BfGenericInstanceTypeRef>(typeRef)) if (auto genericInstTypeRef = BfNodeDynCastExact<BfGenericInstanceTypeRef>(typeRef))
{ {
@ -3158,11 +3170,11 @@ int BfResolvedTypeSet::Hash(BfTypeReference* typeRef, LookupContext* ctx, BfHash
auto parentTypeInstance = checkTypeInstance; auto parentTypeInstance = checkTypeInstance;
int numParentGenericParams = (int)commonOuterType->mGenericParamDefs.size(); int numParentGenericParams = (int)commonOuterType->mGenericParamDefs.size();
for (int i = 0; i < numParentGenericParams; i++) for (int i = 0; i < numParentGenericParams; i++)
hashVal = ((hashVal ^ (Hash(parentTypeInstance->mGenericTypeInfo->mTypeGenericArguments[i], ctx))) << 5) - hashVal; hashVal = HASH_MIX(hashVal, Hash(parentTypeInstance->mGenericTypeInfo->mTypeGenericArguments[i], ctx, Beefy::BfResolvedTypeSet::BfHashFlag_None, hashSeed + 1));
} }
} }
HashGenericArguments(genericInstTypeRef, ctx, hashVal); HashGenericArguments(genericInstTypeRef, ctx, hashVal, hashSeed);
return hashVal; return hashVal;
} }
@ -3297,7 +3309,7 @@ int BfResolvedTypeSet::Hash(BfTypeReference* typeRef, LookupContext* ctx, BfHash
ctx->mRootTypeDef = ctx->mModule->mCompiler->mNullableTypeDef; ctx->mRootTypeDef = ctx->mModule->mCompiler->mNullableTypeDef;
int hashVal = ctx->mModule->mCompiler->mNullableTypeDef->mHash; int hashVal = ctx->mModule->mCompiler->mNullableTypeDef->mHash;
hashVal = ((hashVal ^ (Hash(nullableType->mElementType, ctx))) << 5) - hashVal; hashVal = HASH_MIX(hashVal, Hash(nullableType->mElementType, ctx, BfHashFlag_None, hashSeed + 1));
return hashVal; return hashVal;
} }
else if (auto refType = BfNodeDynCastExact<BfRefTypeRef>(typeRef)) else if (auto refType = BfNodeDynCastExact<BfRefTypeRef>(typeRef))
@ -3510,7 +3522,9 @@ int BfResolvedTypeSet::Hash(BfTypeReference* typeRef, LookupContext* ctx, BfHash
return 0; return 0;
} }
return Hash(cachedResolvedType, ctx, flags); int hashVal = Hash(cachedResolvedType, ctx, flags, hashSeed);
hashSeed = 0;
return hashVal;
} }
else if (auto constExprTypeRef = BfNodeDynCastExact<BfConstExprTypeRef>(typeRef)) else if (auto constExprTypeRef = BfNodeDynCastExact<BfConstExprTypeRef>(typeRef))
{ {
@ -3546,6 +3560,14 @@ int BfResolvedTypeSet::Hash(BfTypeReference* typeRef, LookupContext* ctx, BfHash
return 0; return 0;
} }
int BfResolvedTypeSet::Hash(BfTypeReference* typeRef, LookupContext* ctx, BfHashFlags flags, int hashSeed)
{
int hashVal = DoHash(typeRef, ctx, flags, hashSeed);
if (hashSeed == 0)
return hashVal;
return HASH_MIX(hashVal, hashSeed);
}
// These types can be from different contexts ("foreign" types) so we can't just compare ptrs // These types can be from different contexts ("foreign" types) so we can't just compare ptrs
bool BfResolvedTypeSet::Equals(BfType* lhs, BfType* rhs, LookupContext* ctx) bool BfResolvedTypeSet::Equals(BfType* lhs, BfType* rhs, LookupContext* ctx)
{ {

View file

@ -1774,6 +1774,7 @@ public:
bool mInitializedGenericParams; bool mInitializedGenericParams;
bool mFinishedGenericParams; bool mFinishedGenericParams;
Array<BfProject*> mProjectsReferenced; // Generic methods that only refer to these projects don't need a specialized extension Array<BfProject*> mProjectsReferenced; // Generic methods that only refer to these projects don't need a specialized extension
int32 mMaxGenericDepth;
public: public:
BfGenericTypeInfo() BfGenericTypeInfo()
@ -1785,6 +1786,7 @@ public:
mValidatedGenericConstraints = false; mValidatedGenericConstraints = false;
mInitializedGenericParams = false; mInitializedGenericParams = false;
mFinishedGenericParams = false; mFinishedGenericParams = false;
mMaxGenericDepth = -1;
} }
~BfGenericTypeInfo(); ~BfGenericTypeInfo();
@ -2525,10 +2527,12 @@ public:
static BfVariant EvaluateToVariant(LookupContext* ctx, BfExpression* expr, BfType*& outType); static BfVariant EvaluateToVariant(LookupContext* ctx, BfExpression* expr, BfType*& outType);
static bool GenericTypeEquals(BfTypeInstance* lhsGenericType, BfTypeVector* lhsTypeGenericArguments, BfTypeReference* rhs, LookupContext* ctx, int& genericParamOffset); static bool GenericTypeEquals(BfTypeInstance* lhsGenericType, BfTypeVector* lhsTypeGenericArguments, BfTypeReference* rhs, LookupContext* ctx, int& genericParamOffset);
static bool GenericTypeEquals(BfTypeInstance* lhsGenericType, BfTypeVector* typeGenericArguments, BfTypeReference* rhs, BfTypeDef* rhsTypeDef, LookupContext* ctx); static bool GenericTypeEquals(BfTypeInstance* lhsGenericType, BfTypeVector* typeGenericArguments, BfTypeReference* rhs, BfTypeDef* rhsTypeDef, LookupContext* ctx);
static void HashGenericArguments(BfTypeReference* typeRef, LookupContext* ctx, int& hash); static void HashGenericArguments(BfTypeReference* typeRef, LookupContext* ctx, int& hash, int hashSeed);
static int Hash(BfType* type, LookupContext* ctx, bool allowRef = false); static int DoHash(BfType* type, LookupContext* ctx, bool allowRef, int hashSeed);
static int DirectHash(BfTypeReference* typeRef, LookupContext* ctx, BfHashFlags flags = BfHashFlag_None); static int Hash(BfType* type, LookupContext* ctx, bool allowRef = false, int hashSeed = 0);
static int Hash(BfTypeReference* typeRef, LookupContext* ctx, BfHashFlags flags = BfHashFlag_None); static int DirectHash(BfTypeReference* typeRef, LookupContext* ctx, BfHashFlags flags = BfHashFlag_None, int hashSeed = 0);
static int DoHash(BfTypeReference* typeRef, LookupContext* ctx, BfHashFlags flags, int& hashSeed);
static int Hash(BfTypeReference* typeRef, LookupContext* ctx, BfHashFlags flags = BfHashFlag_None, int hashSeed = 0);
static bool Equals(BfType* lhs, BfType* rhs, LookupContext* ctx); static bool Equals(BfType* lhs, BfType* rhs, LookupContext* ctx);
static bool Equals(BfType* lhs, BfTypeReference* rhs, LookupContext* ctx); static bool Equals(BfType* lhs, BfTypeReference* rhs, LookupContext* ctx);
static bool Equals(BfType* lhs, BfTypeReference* rhs, BfTypeDef* rhsTypeDef, LookupContext* ctx); static bool Equals(BfType* lhs, BfTypeReference* rhs, BfTypeDef* rhsTypeDef, LookupContext* ctx);

View file

@ -1,3 +1,4 @@
using System;
namespace Tests namespace Tests
{ {
class Classes class Classes
@ -22,5 +23,22 @@ namespace Tests
{ {
} }
} }
class ClassA<T0, T1>
{
//public ClassA<T0, ClassA<T0, T1>> mVal;
public ClassA<T0, ClassA<T0, T1>> GetRecursive()
{
return null;
}
}
[Test]
static void TestBasics()
{
ClassA<int, float> ca = scope .();
Test.Assert(typeof(decltype(ca.GetRecursive())) == typeof(ClassA<int, ClassA<int, float>>));
}
} }
} }

View file

@ -95,6 +95,16 @@ namespace Tests
} }
} }
class IFaceA<T0, T1> where T0 : Dictionary<T1, int> where T1 : IHashable
{
Dictionary<T1, int> mDict;
}
public static void MethodA<T0, T1>() where T0 : Dictionary<T1, int> where T1 : IHashable
{
}
[Test] [Test]
public static void TestBasics() public static void TestBasics()
{ {