From eb86c717f038c90318b3e85eb5376fca06d87763 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Tue, 16 Feb 2021 14:53:48 -0800 Subject: [PATCH] Partial recursive generic fixes, deferred constraint type validation --- IDEHelper/Compiler/BfCompiler.cpp | 8 +-- IDEHelper/Compiler/BfCompiler.h | 4 +- IDEHelper/Compiler/BfModule.cpp | 39 +++++++++----- IDEHelper/Compiler/BfModule.h | 2 +- IDEHelper/Compiler/BfModuleTypeUtils.cpp | 62 ++++++++++++++++++---- IDEHelper/Compiler/BfResolvedTypeUtils.cpp | 60 ++++++++++++++------- IDEHelper/Compiler/BfResolvedTypeUtils.h | 12 +++-- IDEHelper/Tests/src/Classes.bf | 18 +++++++ IDEHelper/Tests/src/Generics2.bf | 10 ++++ 9 files changed, 162 insertions(+), 53 deletions(-) diff --git a/IDEHelper/Compiler/BfCompiler.cpp b/IDEHelper/Compiler/BfCompiler.cpp index 0b7fcaf4..fe46736d 100644 --- a/IDEHelper/Compiler/BfCompiler.cpp +++ b/IDEHelper/Compiler/BfCompiler.cpp @@ -398,6 +398,7 @@ BfCompiler::BfCompiler(BfSystem* bfSystem, bool isResolveOnly) mDbgRawAllocDataTypeDef = NULL; mDeferredCallTypeDef = NULL; mDelegateTypeDef = NULL; + mFunctionTypeDef = NULL; mActionTypeDef = NULL; mEnumTypeDef = NULL; mFriendAttributeTypeDef = NULL; @@ -405,8 +406,7 @@ BfCompiler::BfCompiler(BfSystem* bfSystem, bool isResolveOnly) mConstEvalAttributeTypeDef = NULL; mNoExtensionAttributeTypeDef = NULL; mCheckedAttributeTypeDef = NULL; - mUncheckedAttributeTypeDef = NULL; - mFunctionTypeDef = NULL; + mUncheckedAttributeTypeDef = NULL; mGCTypeDef = NULL; mGenericIEnumerableTypeDef = NULL; mGenericIEnumeratorTypeDef = NULL; @@ -6665,6 +6665,7 @@ bool BfCompiler::DoCompile(const StringImpl& outputDirectory) mDbgRawAllocDataTypeDef = _GetRequiredType("System.DbgRawAllocData"); mDeferredCallTypeDef = _GetRequiredType("System.DeferredCall"); mDelegateTypeDef = _GetRequiredType("System.Delegate"); + mFunctionTypeDef = _GetRequiredType("System.Function"); mActionTypeDef = _GetRequiredType("System.Action"); mEnumTypeDef = _GetRequiredType("System.Enum"); mFriendAttributeTypeDef = _GetRequiredType("System.FriendAttribute"); @@ -6673,8 +6674,7 @@ bool BfCompiler::DoCompile(const StringImpl& outputDirectory) mNoExtensionAttributeTypeDef = _GetRequiredType("System.NoExtensionAttribute"); mCheckedAttributeTypeDef = _GetRequiredType("System.CheckedAttribute"); mUncheckedAttributeTypeDef = _GetRequiredType("System.UncheckedAttribute"); - mResultTypeDef = _GetRequiredType("System.Result", 1); - mFunctionTypeDef = _GetRequiredType("System.Function"); + mResultTypeDef = _GetRequiredType("System.Result", 1); mGCTypeDef = _GetRequiredType("System.GC"); mGenericIEnumerableTypeDef = _GetRequiredType("System.Collections.IEnumerable", 1); mGenericIEnumeratorTypeDef = _GetRequiredType("System.Collections.IEnumerator", 1); diff --git a/IDEHelper/Compiler/BfCompiler.h b/IDEHelper/Compiler/BfCompiler.h index 65c8eb83..03bcaec0 100644 --- a/IDEHelper/Compiler/BfCompiler.h +++ b/IDEHelper/Compiler/BfCompiler.h @@ -353,14 +353,14 @@ public: BfTypeDef* mDbgRawAllocDataTypeDef; BfTypeDef* mDeferredCallTypeDef; BfTypeDef* mDelegateTypeDef; + BfTypeDef* mFunctionTypeDef; BfTypeDef* mActionTypeDef; BfTypeDef* mEnumTypeDef; BfTypeDef* mStringTypeDef; BfTypeDef* mStringViewTypeDef; BfTypeDef* mTypeTypeDef; BfTypeDef* mValueTypeTypeDef; - BfTypeDef* mResultTypeDef; - BfTypeDef* mFunctionTypeDef; + BfTypeDef* mResultTypeDef; BfTypeDef* mGCTypeDef; BfTypeDef* mGenericIEnumerableTypeDef; BfTypeDef* mGenericIEnumeratorTypeDef; diff --git a/IDEHelper/Compiler/BfModule.cpp b/IDEHelper/Compiler/BfModule.cpp index 37d9eec9..351dbdd4 100644 --- a/IDEHelper/Compiler/BfModule.cpp +++ b/IDEHelper/Compiler/BfModule.cpp @@ -3425,10 +3425,11 @@ void BfModule::AddDependency(BfType* usedType, BfType* userType, BfDependencyMap BfModule* usedModule; if (usedType->IsFunction()) { - auto typeInst = usedType->ToTypeInstance(); - if (typeInst->mBaseType == NULL) - PopulateType(typeInst); - usedModule = typeInst->mBaseType->GetModule(); + if (mCompiler->mFunctionTypeDef != NULL) + { + auto functionType = ResolveTypeDef(mCompiler->mFunctionTypeDef)->ToTypeInstance(); + usedModule = functionType->GetModule(); + } } else usedModule = usedType->GetModule(); @@ -7217,7 +7218,7 @@ BfIRFunction BfModule::GetBuiltInFunc(BfBuiltInFuncType funcTypeId) return mBuiltInFuncs[(int)funcTypeId]; } -void BfModule::ResolveGenericParamConstraints(BfGenericParamInstance* genericParamInstance, bool isUnspecialized) +void BfModule::ResolveGenericParamConstraints(BfGenericParamInstance* genericParamInstance, bool isUnspecialized, Array* deferredResolveTypes) { BfGenericParamDef* genericParamDef = genericParamInstance->GetGenericParamDef(); BfExternalConstraintDef* externConstraintDef = genericParamInstance->GetExternConstraintDef(); @@ -7323,14 +7324,23 @@ void BfModule::ResolveGenericParamConstraints(BfGenericParamInstance* genericPar if (bfAutocomplete != NULL) bfAutocomplete->CheckTypeRef(constraintTypeRef, true); //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; if (isUnspecialized) 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 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 (deferredResolveTypes != NULL) + { + PopulateType(constraintType, BfPopulateType_Declaration); + if (constraintType->IsUnspecializedTypeVariation()) + deferredResolveTypes->Add(constraintTypeRef); + } + if ((constraintDef->mGenericParamFlags & BfGenericParamFlag_Const) != 0) { bool isValidTypeCode = false; @@ -7511,11 +7521,11 @@ bool BfModule::CheckGenericConstraints(const BfGenericParamSource& genericParamS origCheckArgType = origCheckArgType->GetUnderlyingType(); bool argMayBeReferenceType = false; - + int checkGenericParamFlags = 0; if (checkArgType->IsGenericParam()) { - auto checkGenericParamInst = GetGenericParamInstance((BfGenericParamType*)checkArgType); + BfGenericParamInstance* checkGenericParamInst = GetGenericParamInstance((BfGenericParamType*)checkArgType); checkGenericParamFlags = checkGenericParamInst->mGenericParamFlags; if (checkGenericParamInst->mTypeConstraint != NULL) checkArgType = checkGenericParamInst->mTypeConstraint; @@ -7849,7 +7859,7 @@ bool BfModule::CheckGenericConstraints(const BfGenericParamSource& genericParamS if (TypeIsSubTypeOf(wrappedStructType, typeConstraintInst)) implementsInterface = true; } - + if (!implementsInterface) { if ((!ignoreErrors) && (PreFail())) @@ -21616,6 +21626,7 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool { BfTypeInstance* unspecializedTypeInstance = NULL; + Array deferredResolveTypes; for (int genericParamIdx = 0; genericParamIdx < (int)methodInstance->mMethodInfoEx->mGenericParams.size(); genericParamIdx++) { auto genericParam = methodInstance->mMethodInfoEx->mGenericParams[genericParamIdx]; @@ -21639,8 +21650,8 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool else genericParam->mExternType = GetPrimitiveType(BfTypeCode_Var); } - - ResolveGenericParamConstraints(genericParam, methodInstance->mIsUnspecialized); + + ResolveGenericParamConstraints(genericParam, methodInstance->mIsUnspecialized, &deferredResolveTypes); 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) { diff --git a/IDEHelper/Compiler/BfModule.h b/IDEHelper/Compiler/BfModule.h index 5ae6babe..ed3dcf89 100644 --- a/IDEHelper/Compiler/BfModule.h +++ b/IDEHelper/Compiler/BfModule.h @@ -1778,7 +1778,7 @@ public: bool TypeEquals(BfTypedValue& val, BfType* type); BfTypeDef* ResolveGenericInstanceDef(BfGenericInstanceTypeRef* genericTypeRef, BfType** outType = NULL, 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* deferredResolveTypes = NULL); String GenericParamSourceToString(const BfGenericParamSource& genericParamSource); 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); diff --git a/IDEHelper/Compiler/BfModuleTypeUtils.cpp b/IDEHelper/Compiler/BfModuleTypeUtils.cpp index 9f2df9a8..300df1aa 100644 --- a/IDEHelper/Compiler/BfModuleTypeUtils.cpp +++ b/IDEHelper/Compiler/BfModuleTypeUtils.cpp @@ -164,7 +164,8 @@ bool BfModule::FinishGenericParams(BfType* resolvedTypeRef) typeState.mResolveKind = BfTypeState::ResolveKind_BuildingGenericParams; typeState.mTypeInstance = resolvedTypeRef->ToTypeInstance(); SetAndRestoreValue prevTypeState(mContext->mCurTypeState, &typeState); - + Array deferredResolveTypes; + BF_ASSERT(mCurMethodInstance == NULL); auto genericTypeInst = resolvedTypeRef->ToGenericTypeInstance(); @@ -210,7 +211,7 @@ bool BfModule::FinishGenericParams(BfType* resolvedTypeRef) genericParamInstance->mExternType = GetPrimitiveType(BfTypeCode_Var); } - ResolveGenericParamConstraints(genericParamInstance, genericTypeInst->IsUnspecializedType()); + ResolveGenericParamConstraints(genericParamInstance, genericTypeInst->IsUnspecializedType(), &deferredResolveTypes); if (genericParamDef != NULL) { @@ -283,7 +284,7 @@ bool BfModule::FinishGenericParams(BfType* resolvedTypeRef) genericParamInstance->mExternType = GetPrimitiveType(BfTypeCode_Var); } - ResolveGenericParamConstraints(genericParamInstance, genericTypeInst->IsUnspecializedType()); + ResolveGenericParamConstraints(genericParamInstance, genericTypeInst->IsUnspecializedType(), &deferredResolveTypes); auto genericParamDef = genericParamInstance->GetGenericParamDef(); 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 constraintTypeInst : genericParam->mInterfaceConstraints) @@ -339,6 +343,13 @@ bool BfModule::ValidateGenericConstraints(BfTypeReference* typeRef, BfTypeInstan 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; 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; else if ((mCompiler->mOptions.mCompileOnDemandKind != BfCompileOnDemandKind_AlwaysInclude) && (!typeInstance->IsUnspecializedTypeVariation())) @@ -7939,7 +7950,7 @@ bool BfModule::ResolveTypeResult_Validate(BfTypeReference* typeRef, BfType* reso if ((curGenericTypeInstance->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; } @@ -9724,7 +9735,14 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula CheckUnspecializedGenericType(genericTypeInst, populateType); resolvedEntry->mValue = genericTypeInst; 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); } } @@ -9978,15 +9996,16 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula auto parentTypeInstance = outerTypeInstance; if (parentTypeInstance->IsTypeAlias()) parentTypeInstance = (BfTypeInstance*)GetOuterType(parentTypeInstance)->ToTypeInstance(); + genericTypeInst->mGenericTypeInfo->mMaxGenericDepth = BF_MAX(genericTypeInst->mGenericTypeInfo->mMaxGenericDepth, parentTypeInstance->mGenericTypeInfo->mMaxGenericDepth); for (int i = 0; i < startDefGenericParamIdx; i++) { genericTypeInst->mGenericTypeInfo->mGenericParams.push_back(parentTypeInstance->mGenericTypeInfo->mGenericParams[i]->AddRef()); genericTypeInst->mGenericTypeInfo->mTypeGenericArguments.push_back(parentTypeInstance->mGenericTypeInfo->mTypeGenericArguments[i]); auto typeGenericArg = genericTypeInst->mGenericTypeInfo->mTypeGenericArguments[i]; genericTypeInst->mGenericTypeInfo->mIsUnspecialized |= typeGenericArg->IsGenericParam() || typeGenericArg->IsUnspecializedType(); + } - } - + } int wantedGenericParams = genericParamCount - startDefGenericParamIdx; int genericArgDiffCount = (int)genericArguments.size() - wantedGenericParams; @@ -10005,14 +10024,28 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula for (auto genericArgRef : genericArguments) { 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->mTypeGenericArgumentRefs.push_back(genericArgRef); genericParamIdx++; } - resolvedEntry->mValue = genericTypeInst; + 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; + CheckUnspecializedGenericType(genericTypeInst, populateType); populateModule->InitType(genericTypeInst, populateType); @@ -10027,6 +10060,8 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula { BF_ASSERT(BfResolvedTypeSet::Equals(genericTypeInst, typeRef, &lookupCtx)); } + + BfLogSysM("Generic type %p typeHash: %8X\n", genericTypeInst, resolvedEntry->mHash); #endif BF_ASSERT(BfResolvedTypeSet::Hash(genericTypeInst, &lookupCtx) == resolvedEntry->mHash); @@ -10161,7 +10196,14 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula CheckUnspecializedGenericType(genericTypeInst, populateType); 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); return ResolveTypeResult(typeRef, genericTypeInst, populateType, resolveFlags); } diff --git a/IDEHelper/Compiler/BfResolvedTypeUtils.cpp b/IDEHelper/Compiler/BfResolvedTypeUtils.cpp index a3335f72..2d71d37a 100644 --- a/IDEHelper/Compiler/BfResolvedTypeUtils.cpp +++ b/IDEHelper/Compiler/BfResolvedTypeUtils.cpp @@ -2723,6 +2723,8 @@ BfResolvedTypeSet::~BfResolvedTypeSet() } +#define HASH_MIX(origHashVal, newHashVal) ((((origHashVal) << 5) - (origHashVal)) ^ (newHashVal)) + #define HASH_VAL_PTR 1 #define HASH_VAL_BOXED 2 #define HASH_VAL_REF 3 @@ -2769,7 +2771,7 @@ BfVariant BfResolvedTypeSet::EvaluateToVariant(LookupContext* ctx, BfExpression* 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"); @@ -2875,8 +2877,8 @@ int BfResolvedTypeSet::Hash(BfType* type, LookupContext* ctx, bool allowRef) else if (type->IsGenericTypeInstance()) { BfTypeInstance* genericType = (BfTypeInstance*)type; - for (auto genericArg : genericType->mGenericTypeInfo->mTypeGenericArguments) - hashVal = ((hashVal ^ (Hash(genericArg, ctx))) << 5) - hashVal; + for (auto genericArg : genericType->mGenericTypeInfo->mTypeGenericArguments) + hashVal = HASH_MIX(hashVal, Hash(genericArg, ctx, BfHashFlag_None, hashSeed + 1)); } return hashVal; } @@ -2952,21 +2954,29 @@ int BfResolvedTypeSet::Hash(BfType* type, LookupContext* ctx, bool allowRef) 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(typeRef)) { - HashGenericArguments(elementedTypeRef->mElementType, ctx, hashVal); + HashGenericArguments(elementedTypeRef->mElementType, ctx, hashVal, hashSeed); } else if (auto qualifiedTypeRef = BfNodeDynCast(typeRef)) { - HashGenericArguments(qualifiedTypeRef->mLeft, ctx, hashVal); + HashGenericArguments(qualifiedTypeRef->mLeft, ctx, hashVal, hashSeed); } if (auto genericTypeRef = BfNodeDynCast(typeRef)) { 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()); } -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; @@ -2992,7 +3002,7 @@ int BfResolvedTypeSet::DirectHash(BfTypeReference* typeRef, LookupContext* ctx, ctx->mFailed = true; return 0; } - return Hash(resolvedType, ctx); + return Hash(resolvedType, ctx, BfHashFlag_None, hashSeed); } BfTypeDef* BfResolvedTypeSet::FindRootCommonOuterType(BfTypeDef* outerType, LookupContext* ctx, BfTypeInstance*& outOuterTypeInstance) @@ -3022,7 +3032,7 @@ BfTypeDef* BfResolvedTypeSet::FindRootCommonOuterType(BfTypeDef* outerType, Look 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) && ((typeRef->IsNamedTypeReference()) || (BfNodeIsA(typeRef)))) @@ -3074,8 +3084,8 @@ int BfResolvedTypeSet::Hash(BfTypeReference* typeRef, LookupContext* ctx, BfHash auto curGenericTypeInst = (BfTypeInstance*)checkTypeInstance; int numParentGenericParams = (int)commonOuterType->mGenericParamDefs.size(); 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()) { - return DirectHash(typeRef, ctx, flags); + int hashVal = DirectHash(typeRef, ctx, flags, hashSeed); + hashSeed = 0; + return hashVal; } if (auto genericInstTypeRef = BfNodeDynCastExact(typeRef)) { @@ -3157,12 +3169,12 @@ int BfResolvedTypeSet::Hash(BfTypeReference* typeRef, LookupContext* ctx, BfHash { auto parentTypeInstance = checkTypeInstance; int numParentGenericParams = (int)commonOuterType->mGenericParamDefs.size(); - for (int i = 0; i < numParentGenericParams; i++) - hashVal = ((hashVal ^ (Hash(parentTypeInstance->mGenericTypeInfo->mTypeGenericArguments[i], ctx))) << 5) - hashVal; + for (int i = 0; i < numParentGenericParams; i++) + 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; } @@ -3296,8 +3308,8 @@ int BfResolvedTypeSet::Hash(BfTypeReference* typeRef, LookupContext* ctx, BfHash if (ctx->mRootTypeRef == typeRef) ctx->mRootTypeDef = ctx->mModule->mCompiler->mNullableTypeDef; - int hashVal = ctx->mModule->mCompiler->mNullableTypeDef->mHash; - hashVal = ((hashVal ^ (Hash(nullableType->mElementType, ctx))) << 5) - hashVal; + int hashVal = ctx->mModule->mCompiler->mNullableTypeDef->mHash; + hashVal = HASH_MIX(hashVal, Hash(nullableType->mElementType, ctx, BfHashFlag_None, hashSeed + 1)); return hashVal; } else if (auto refType = BfNodeDynCastExact(typeRef)) @@ -3510,7 +3522,9 @@ int BfResolvedTypeSet::Hash(BfTypeReference* typeRef, LookupContext* ctx, BfHash return 0; } - return Hash(cachedResolvedType, ctx, flags); + int hashVal = Hash(cachedResolvedType, ctx, flags, hashSeed); + hashSeed = 0; + return hashVal; } else if (auto constExprTypeRef = BfNodeDynCastExact(typeRef)) { @@ -3546,6 +3560,14 @@ int BfResolvedTypeSet::Hash(BfTypeReference* typeRef, LookupContext* ctx, BfHash 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 bool BfResolvedTypeSet::Equals(BfType* lhs, BfType* rhs, LookupContext* ctx) { diff --git a/IDEHelper/Compiler/BfResolvedTypeUtils.h b/IDEHelper/Compiler/BfResolvedTypeUtils.h index 097a3ea6..bfea6ed0 100644 --- a/IDEHelper/Compiler/BfResolvedTypeUtils.h +++ b/IDEHelper/Compiler/BfResolvedTypeUtils.h @@ -1774,6 +1774,7 @@ public: bool mInitializedGenericParams; bool mFinishedGenericParams; Array mProjectsReferenced; // Generic methods that only refer to these projects don't need a specialized extension + int32 mMaxGenericDepth; public: BfGenericTypeInfo() @@ -1785,6 +1786,7 @@ public: mValidatedGenericConstraints = false; mInitializedGenericParams = false; mFinishedGenericParams = false; + mMaxGenericDepth = -1; } ~BfGenericTypeInfo(); @@ -2525,10 +2527,12 @@ public: 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* typeGenericArguments, BfTypeReference* rhs, BfTypeDef* rhsTypeDef, LookupContext* ctx); - static void HashGenericArguments(BfTypeReference* typeRef, LookupContext* ctx, int& hash); - static int Hash(BfType* type, LookupContext* ctx, bool allowRef = false); - static int DirectHash(BfTypeReference* typeRef, LookupContext* ctx, BfHashFlags flags = BfHashFlag_None); - static int Hash(BfTypeReference* typeRef, LookupContext* ctx, BfHashFlags flags = BfHashFlag_None); + static void HashGenericArguments(BfTypeReference* typeRef, LookupContext* ctx, int& hash, int hashSeed); + static int DoHash(BfType* type, LookupContext* ctx, bool allowRef, int hashSeed); + static int Hash(BfType* type, LookupContext* ctx, bool allowRef = false, int hashSeed = 0); + 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, BfTypeReference* rhs, LookupContext* ctx); static bool Equals(BfType* lhs, BfTypeReference* rhs, BfTypeDef* rhsTypeDef, LookupContext* ctx); diff --git a/IDEHelper/Tests/src/Classes.bf b/IDEHelper/Tests/src/Classes.bf index b4d4c0f0..03e1fdee 100644 --- a/IDEHelper/Tests/src/Classes.bf +++ b/IDEHelper/Tests/src/Classes.bf @@ -1,3 +1,4 @@ +using System; namespace Tests { class Classes @@ -22,5 +23,22 @@ namespace Tests { } } + + class ClassA + { + //public ClassA> mVal; + + public ClassA> GetRecursive() + { + return null; + } + } + + [Test] + static void TestBasics() + { + ClassA ca = scope .(); + Test.Assert(typeof(decltype(ca.GetRecursive())) == typeof(ClassA>)); + } } } diff --git a/IDEHelper/Tests/src/Generics2.bf b/IDEHelper/Tests/src/Generics2.bf index 390b6892..98ef35d3 100644 --- a/IDEHelper/Tests/src/Generics2.bf +++ b/IDEHelper/Tests/src/Generics2.bf @@ -95,6 +95,16 @@ namespace Tests } } + class IFaceA where T0 : Dictionary where T1 : IHashable + { + Dictionary mDict; + } + + public static void MethodA() where T0 : Dictionary where T1 : IHashable + { + + } + [Test] public static void TestBasics() {