Pārlūkot izejas kodu

Improvements and safety for const exprs

Brian Fiete 5 gadi atpakaļ
vecāks
revīzija
0a78b5cc35

+ 3 - 3
IDEHelper/Compiler/BfCompiler.h

@@ -67,7 +67,7 @@ public:
 		int mMethodDeclarations;
 		int mTypesPopulated;
 		int mMethodsProcessed;
-		int mUnreifiedMethodsProcessed;
+		int mUnreifiedMethodsProcessed;		
 
 		int mQueuedTypesProcessed;
 		int mTypesQueued;
@@ -82,7 +82,7 @@ public:
 
 		int mReifiedModuleCount;
 		int mIRBytes;
-		int mConstBytes;
+		int mConstBytes;		
 	};
 	Stats mStats;
 
@@ -122,7 +122,7 @@ public:
 		bool mDebugAlloc;
 		bool mOmitDebugHelpers;
 
-		bool mUseDebugBackingParams;		
+		bool mUseDebugBackingParams;
 
 		bool mWriteIR;
 		bool mGenerateObj;

+ 37 - 22
IDEHelper/Compiler/BfMangler.cpp

@@ -423,13 +423,7 @@ void BfGNUMangler::Mangle(MangleContext& mangleContext, StringImpl& name, BfType
 				name += "v";
 			else
 				name += "U4void";
-			return;
-		case BfTypeCode_Var:
-			if ((mangleContext.mCCompat) || (mangleContext.mInArgs))
-				name += "v";
-			else
-				name += "U3var";
-			return;
+			return;		
 		case BfTypeCode_Self:
 			if ((mangleContext.mCCompat) || (mangleContext.mInArgs))
 				name += "U8concrete";
@@ -494,6 +488,19 @@ void BfGNUMangler::Mangle(MangleContext& mangleContext, StringImpl& name, BfType
 			name += "f"; return;
 		case BfTypeCode_Double:
 			name += "d"; return;
+
+		case BfTypeCode_Var:
+			if ((mangleContext.mCCompat) || (mangleContext.mInArgs))
+				name += "v";
+			else
+				name += "U3var";
+			return;
+		case BfTypeCode_Let:
+			name += "U3let"; return;
+		case BfTypeCode_IntUnknown:
+			name += "U4iunk"; return;
+		case BfTypeCode_UIntUnknown:
+			name += "U4uunk"; return;
 		default: break;
 		}
 
@@ -1455,21 +1462,7 @@ void BfMSMangler::Mangle(MangleContext& mangleContext, StringImpl& name, BfType*
 			}
 			return;
 		case BfTypeCode_None:
-			name += "X"; return;
-		case BfTypeCode_Dot:
-			name += "Tdot@@"; return;
-		case BfTypeCode_Var:
-			if ((mangleContext.mCCompat) || (mangleContext.mInArgs))
-				name += "X";
-			else
-				name += "Tvar@@";
-			return;
-		case BfTypeCode_Self:
-			if ((mangleContext.mCCompat) || (mangleContext.mInArgs))
-				name += "X";
-			else
-				name += "Tself@@";
-			return;
+			name += "X"; return;		
 		case BfTypeCode_Int8:
 			name += "C"; return;
 		case BfTypeCode_UInt8:
@@ -1512,6 +1505,28 @@ void BfMSMangler::Mangle(MangleContext& mangleContext, StringImpl& name, BfType*
 			}
 			isLongPrim = true;
 			break;
+
+		case BfTypeCode_Dot:
+			name += "Tdot@@"; return;
+		case BfTypeCode_Var:
+			if ((mangleContext.mCCompat) || (mangleContext.mInArgs))
+				name += "X";
+			else
+				name += "Tvar@@";
+			return;
+		case BfTypeCode_Self:
+			if ((mangleContext.mCCompat) || (mangleContext.mInArgs))
+				name += "X";
+			else
+				name += "Tself@@";
+			return;
+		case BfTypeCode_Let:
+			name += "Tlet@@"; return;
+		case BfTypeCode_IntUnknown:
+			name += "Tiunk@@"; return;
+		case BfTypeCode_UIntUnknown:
+			name += "Tuunk@@"; return;
+
 		default:
 			name += "?"; return;
 		}		

+ 64 - 10
IDEHelper/Compiler/BfModule.cpp

@@ -4766,7 +4766,7 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary<int, int>& usedStrin
 		return *irValuePtr;
 	}
 	
-	BfTypeInstance* typeInstance = type->ToTypeInstance();		
+	BfTypeInstance* typeInstance = type->ToTypeInstance();
 
 	BfType* typeInstanceType = ResolveTypeDef(mCompiler->mReflectTypeInstanceTypeDef);
 	mBfIRBuilder->PopulateType(typeInstanceType, BfIRPopulateType_Full_ForceDefinition);
@@ -4855,6 +4855,11 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary<int, int>& usedStrin
 		BfMangler::Mangle(typeDataName, mCompiler->GetMangleKind(), type, mContext->mScratchModule);
 	}
 
+	if (typeDataName == "sBfTypeData.?")
+	{
+		NOP;
+	}
+
 	int typeCode = BfTypeCode_None;		
 
 	if (typeInstance != NULL)
@@ -12042,13 +12047,20 @@ BfModuleMethodInstance BfModule::GetMethodInstance(BfTypeInstance* typeInst, BfM
 		BF_ASSERT(instModule == mParentModule);
 	}
 	else if (instModule != this)
-	{		
+	{	
+		if ((mCurMethodInstance != NULL) && (mCurMethodInstance->mMethodInfoEx != NULL) && (mCurMethodInstance->mMethodInfoEx->mMinDependDepth >= 32))
+			flags = (BfGetMethodInstanceFlags)(flags | BfGetMethodInstanceFlag_DepthExceeded);
+
 		if ((!mIsReified) && (instModule->mIsReified))
 		{
 			BF_ASSERT(!mCompiler->mIsResolveOnly);
 			// A resolve-only module is specializing a method from a type in a reified module, 
 			//  we need to take care that this doesn't cause anything new to become reified
-			return mContext->mUnreifiedModule->GetMethodInstance(typeInst, methodDef, methodGenericArguments, (BfGetMethodInstanceFlags)(flags | BfGetMethodInstanceFlag_ExplicitResolveOnlyPass), foreignType);			
+			BfModuleMethodInstance moduleMethodInstance = mContext->mUnreifiedModule->GetMethodInstance(typeInst, methodDef, methodGenericArguments, (BfGetMethodInstanceFlags)(flags | BfGetMethodInstanceFlag_ExplicitResolveOnlyPass), foreignType);
+			if (!moduleMethodInstance)
+				return moduleMethodInstance;
+			SetMethodDependency(moduleMethodInstance.mMethodInstance);
+			return moduleMethodInstance;
 		}
 		else
 		{
@@ -12081,6 +12093,8 @@ BfModuleMethodInstance BfModule::GetMethodInstance(BfTypeInstance* typeInst, BfM
 			// Not extern
 			// Create the instance in the proper module and then create a reference in this one
 			moduleMethodInst = instModule->GetMethodInstance(typeInst, methodDef, methodGenericArguments, defFlags, foreignType);
+			if (!moduleMethodInst)
+				return moduleMethodInst;
 			tryModuleMethodLookup = true;
 
 			if ((mIsReified) && (!moduleMethodInst.mMethodInstance->mIsReified))
@@ -12091,7 +12105,10 @@ BfModuleMethodInstance BfModule::GetMethodInstance(BfTypeInstance* typeInst, BfM
 	}		
 
 	if (tryModuleMethodLookup)
+	{
+		SetMethodDependency(moduleMethodInst.mMethodInstance);
 		return ReferenceExternalMethodInstance(moduleMethodInst.mMethodInstance, flags);
+	}
 
 	if (((flags & BfGetMethodInstanceFlag_ForceInline) != 0) && (!methodDef->mAlwaysInline))
 	{
@@ -12422,6 +12439,8 @@ BfModuleMethodInstance BfModule::GetMethodInstance(BfTypeInstance* typeInst, BfM
 	
 	if ((methodInstance != NULL) && (!doingRedeclare))
 	{					
+		SetMethodDependency(methodInstance);
+
 		if (methodInstance->mMethodInstanceGroup->mOnDemandKind == BfMethodOnDemandKind_Decl_AwaitingReference)
 		{
 			/*if ((!mCompiler->mIsResolveOnly) && (!isReified))
@@ -12535,7 +12554,7 @@ BfModuleMethodInstance BfModule::GetMethodInstance(BfTypeInstance* typeInst, BfM
 			GetMethodInstance(typeInst, methodDef, BfTypeVector(), BfGetMethodInstanceFlag_UnspecializedPass);
 		}
 	}
-	
+		
 	if (methodInstance == NULL)
 	{
 		if (lookupMethodGenericArguments.size() == 0)
@@ -12547,7 +12566,18 @@ BfModuleMethodInstance BfModule::GetMethodInstance(BfTypeInstance* typeInst, BfM
 			BfLogSysM("Created Default MethodInst: %p TypeInst: %p Group: %p\n", methodInstance, typeInst, methodInstGroup);
 		}
 		else
-		{			
+		{	
+			bool depthExceeded = ((flags & BfGetMethodInstanceFlag_DepthExceeded) != 0);
+
+			if ((mCurMethodInstance != NULL) && (mCurMethodInstance->mMethodInfoEx != NULL) && (mCurMethodInstance->mMethodInfoEx->mMinDependDepth >= 32))
+				depthExceeded = true;
+
+			if (depthExceeded)
+			{
+				Fail("Generic method dependency depth exceeded", methodDef->GetRefNode());
+				return BfModuleMethodInstance();
+			}
+
 			BfMethodInstance** methodInstancePtr = NULL;
 			bool added = methodInstGroup->mMethodSpecializationMap->TryAdd(lookupMethodGenericArguments, NULL, &methodInstancePtr);
 			BF_ASSERT(added);
@@ -12561,7 +12591,7 @@ BfModuleMethodInstance BfModule::GetMethodInstance(BfTypeInstance* typeInst, BfM
 		}
 
 		if ((prevIRFunc) && (!prevIRFunc.IsFake()))
-			methodInstance->mIRFunction = prevIRFunc; // Take it over
+			methodInstance->mIRFunction = prevIRFunc; // Take it over		
 	}
 		
 	/*// 24 bits for typeid, 20 for method id, 20 for specialization index
@@ -12679,7 +12709,9 @@ BfModuleMethodInstance BfModule::GetMethodInstance(BfTypeInstance* typeInst, BfM
 	{
 		BF_ASSERT(!methodInstance->mIsReified);
 		declareModule = mContext->mUnreifiedModule;
-	}
+	}	
+
+	SetMethodDependency(methodInstance);
 
 	SetAndRestoreValue<BfMethodInstance*> prevMethodInstance(declareModule->mCurMethodInstance, methodInstance);
 	SetAndRestoreValue<BfTypeInstance*> prevTypeInstance(declareModule->mCurTypeInstance, typeInst);
@@ -20214,9 +20246,6 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool
 {
 	BP_ZONE("BfModule::BfMethodDeclaration");	
 
-	// If we are doing this then we may end up creating methods when var types are unknown still, failing on splat/zero-sized info
-	BF_ASSERT((!mContext->mResolvingVarField) || (mBfIRBuilder->mIgnoreWrites));
-
 	// We could trigger a DoMethodDeclaration from a const resolver or other location, so we reset it here
 	//  to effectively make mIgnoreWrites method-scoped
 	SetAndRestoreValue<bool> prevIgnoreWrites(mBfIRBuilder->mIgnoreWrites, mWantsIRIgnoreWrites || mCurMethodInstance->mIsUnspecialized);
@@ -20228,6 +20257,10 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool
 	if (mCurMethodInstance->mMethodInstanceGroup->mOnDemandKind == BfMethodOnDemandKind_NoDecl_AwaitingReference)
 		mCurMethodInstance->mMethodInstanceGroup->mOnDemandKind = BfMethodOnDemandKind_Decl_AwaitingReference;
 
+
+	// If we are doing this then we may end up creating methods when var types are unknown still, failing on splat/zero-sized info
+	BF_ASSERT((!mCurTypeInstance->mResolvingVarField) || (mBfIRBuilder->mIgnoreWrites));
+
 	bool ignoreWrites = mBfIRBuilder->mIgnoreWrites;
 	
  	if ((!isTemporaryFunc) && (mCurTypeInstance->mDefineState < BfTypeDefineState_Defined))
@@ -22256,6 +22289,27 @@ bool BfModule::SlotInterfaceMethod(BfMethodInstance* methodInstance)
 	return true;
 }
 
+void BfModule::SetMethodDependency(BfMethodInstance* methodInstance)
+{
+	if (methodInstance->mMethodInfoEx == NULL)
+		return;
+
+	int wantMinDepth = -1;
+
+	if (mCurTypeInstance != NULL)
+		wantMinDepth = mCurTypeInstance->mDependencyMap.mMinDependDepth + 1;
+
+	if ((mCurMethodInstance != NULL) && (mCurMethodInstance->mMethodInfoEx != NULL) && (mCurMethodInstance->mMethodInfoEx->mMinDependDepth != -1))
+	{		
+		int wantTypeMinDepth = mCurMethodInstance->mMethodInfoEx->mMinDependDepth + 1;
+		if ((wantMinDepth == -1) || (wantTypeMinDepth < wantMinDepth))
+			wantMinDepth = wantTypeMinDepth;
+	}	
+
+	if ((methodInstance->mMethodInfoEx->mMinDependDepth == -1) || (wantMinDepth < methodInstance->mMethodInfoEx->mMinDependDepth))
+		methodInstance->mMethodInfoEx->mMinDependDepth = wantMinDepth;
+}
+
 void BfModule::DbgFinish()
 {
 	if ((mBfIRBuilder == NULL) || (mExtensionCount != 0))

+ 1 - 0
IDEHelper/Compiler/BfModule.h

@@ -1844,6 +1844,7 @@ public:
 	void CompareDeclTypes(BfTypeDef* newDeclType, BfTypeDef* prevDeclType, bool& isBetter, bool& isWorse);
 	bool SlotVirtualMethod(BfMethodInstance* methodInstance, BfAmbiguityContext* ambiguityContext = NULL);	
 	bool SlotInterfaceMethod(BfMethodInstance* methodInstance);	
+	void SetMethodDependency(BfMethodInstance* methodInstance);
 	BfModuleMethodInstance ReferenceExternalMethodInstance(BfMethodInstance* methodInstance, BfGetMethodInstanceFlags flags = BfGetMethodInstanceFlag_None);
 	BfModule* GetOrCreateMethodModule(BfMethodInstance* methodInstance);
 	BfModuleMethodInstance GetMethodInstance(BfTypeInstance* typeInst, BfMethodDef* methodDef, const BfTypeVector& methodGenericArguments, BfGetMethodInstanceFlags flags = BfGetMethodInstanceFlag_None, BfTypeInstance* foreignType = NULL);	

+ 62 - 22
IDEHelper/Compiler/BfModuleTypeUtils.cpp

@@ -330,9 +330,7 @@ bool BfModule::ValidateGenericConstraints(BfTypeReference* typeRef, BfTypeInstan
 		return true;
 	}
 
-	auto typeDef = genericTypeInst->mTypeDef;
-	//for (int paramIdx = 0; paramIdx < (int)genericTypeInst->mGenericTypeInfo->mTypeGenericArguments.size(); paramIdx++)
-
+	auto typeDef = genericTypeInst->mTypeDef;		
 	for (int paramIdx = 0; paramIdx < (int)genericTypeInst->mGenericTypeInfo->mGenericParams.size(); paramIdx++)
 	{
 		auto genericParamInstance = genericTypeInst->mGenericTypeInfo->mGenericParams[paramIdx];
@@ -501,6 +499,18 @@ void BfModule::CheckInjectNewRevision(BfTypeInstance* typeInstance)
 void BfModule::InitType(BfType* resolvedTypeRef, BfPopulateType populateType)
 {
 	BP_ZONE("BfModule::InitType");
+	
+	if (auto depType = resolvedTypeRef->ToDependedType())
+	{
+		if ((mCurMethodInstance != NULL) && (mCurMethodInstance->mMethodInfoEx != NULL))
+		{
+			depType->mDependencyMap.mMinDependDepth = mCurMethodInstance->mMethodInfoEx->mMinDependDepth + 1;
+		}
+		else if (mCurTypeInstance != NULL)
+		{
+			depType->mDependencyMap.mMinDependDepth = mCurTypeInstance->mDependencyMap.mMinDependDepth + 1;
+		}
+	}
 
 	SetAndRestoreValue<BfTypeInstance*> prevTypeInstance(mCurTypeInstance, resolvedTypeRef->ToTypeInstance());
 	SetAndRestoreValue<BfMethodInstance*> prevMethodInstance(mCurMethodInstance, NULL);
@@ -2143,7 +2153,7 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy
 		auto _AddStaticSearch = [&](BfTypeDef* typeDef)
 		{
 			if (typeDef->mStaticSearch.IsEmpty())
-				return;			
+				return;
 			BfStaticSearch* staticSearch;
 			if (typeInstance->mStaticSearchMap.TryAdd(typeDef, NULL, &staticSearch))
 			{
@@ -2162,9 +2172,9 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy
 							staticSearch->mStaticTypes.Add(staticTypeInst);
 							AddDependency(staticTypeInst, typeInstance, BfDependencyMap::DependencyFlag_StaticValue);
 						}
-					}										
+					}
 				}
-			}			
+			}
 		};
 
 		if (typeDef->mIsCombinedPartial)
@@ -7090,7 +7100,7 @@ BfType* BfModule::ResolveTypeResult(BfTypeReference* typeRef, BfType* resolvedTy
 	populateModule->PopulateType(resolvedTypeRef, populateType);
 	
 	if ((genericTypeInstance != NULL) && (genericTypeInstance != mCurTypeInstance) && (populateType > BfPopulateType_Identity))
-	{	
+	{
 		bool doValidate = (genericTypeInstance->mGenericTypeInfo->mHadValidateErrors) || 
 			(!genericTypeInstance->mGenericTypeInfo->mValidatedGenericConstraints) || 
 			(genericTypeInstance->mGenericTypeInfo->mIsUnspecializedVariation);
@@ -7102,6 +7112,13 @@ BfType* BfModule::ResolveTypeResult(BfTypeReference* typeRef, BfType* resolvedTy
 				doValidate = false;
 			if (auto curGenericTypeInstance = mCurTypeInstance->ToGenericTypeInstance())
 			{
+				if ((curGenericTypeInstance->mDependencyMap.mMinDependDepth > 32) &&
+					(genericTypeInstance->mDependencyMap.mMinDependDepth > 32))
+				{
+					Fail(StrFormat("Generic type dependency depth exceeded for type '{}'", TypeToString(genericTypeInstance).c_str()), typeRef);
+					return NULL;
+				}
+
 				if (curGenericTypeInstance->mGenericTypeInfo->mHadValidateErrors)
 					doValidate = false;
 			}
@@ -7731,9 +7748,15 @@ BfTypedValue BfModule::TryLookupGenericConstVaue(BfIdentifierNode* identifierNod
 
 				BfExprEvaluator exprEvaluator(this);
 				exprEvaluator.mExpectingType = genericTypeConstraint;
-				exprEvaluator.GetLiteral(identifierNode, constExprValueType->mValue);
+				exprEvaluator.GetLiteral(identifierNode, constExprValueType->mValue);								
+
+				if (exprEvaluator.mResult)
+				{
+					auto castedVal = CastToValue(identifierNode, exprEvaluator.mResult, genericTypeConstraint, (BfCastFlags)(BfCastFlags_Explicit | BfCastFlags_SilentFail));
+					if (castedVal)
+						return BfTypedValue(castedVal, genericTypeConstraint);
+				}
 				
-				// We don't want to validate type here				
 				return exprEvaluator.mResult;
 			}
 			else if (genericParamResult->IsGenericParam())
@@ -8732,7 +8755,7 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula
 
 		for (auto genericArgRef : genericArguments)
 		{
-			auto genericArg = ResolveTypeRef(genericArgRef, BfPopulateType_Identity, BfResolveTypeRefFlag_AllowGenericMethodParamConstValue);
+			auto genericArg = ResolveTypeRef(genericArgRef, BfPopulateType_Identity, (BfResolveTypeRefFlags)(BfResolveTypeRefFlag_AllowGenericTypeParamConstValue | BfResolveTypeRefFlag_AllowGenericMethodParamConstValue));
 			if (genericArg == NULL)
 			{
 				mContext->mResolvedTypes.RemoveEntry(resolvedEntry);
@@ -8816,10 +8839,16 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula
 			auto genericArg = genericArgs[genericParamIdx + startDefGenericParamIdx];
 			genericTypeInst->mGenericTypeInfo->mTypeGenericArguments.push_back(genericArg);
 			genericTypeInst->mGenericTypeInfo->mTypeGenericArgumentRefs.push_back(genericArgRef);
+
+			if (genericArg->IsConstExprValue())
+			{
+				NOP;
+			}
+
 			genericParamIdx++;
 		}
 
-		resolvedEntry->mValue = genericTypeInst;
+		resolvedEntry->mValue = genericTypeInst;		
 
 		CheckUnspecializedGenericType(genericTypeInst, populateType);
 		populateModule->InitType(genericTypeInst, populateType);
@@ -9290,22 +9319,29 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula
 		return ResolveTypeRef(constTypeRef->mElementType, populateType, (BfResolveTypeRefFlags)(resolveFlags & BfResolveTypeRefFlag_NoResolveGenericParam));
 	}
 	else if (auto constExprTypeRef = BfNodeDynCastExact<BfConstExprTypeRef>(typeRef))
-	{
-		auto constExprType = new BfConstExprValueType();
-		constExprType->mContext = mContext;
+	{				
+		if ((mCurTypeInstance != NULL) && (mCurTypeInstance->mDependencyMap.mMinDependDepth > 32))
+		{
+			Fail("Generic type dependency depth exceeded", typeRef);			
+			mContext->mResolvedTypes.RemoveEntry(resolvedEntry);
+			return ResolveTypeResult(typeRef, NULL, populateType, resolveFlags);
+		}
 
 		BfVariant result;
+		BfType* resultType = NULL;
 		if (constExprTypeRef->mConstExpr != NULL)
-		{
-			BfType* constGenericParam = NULL;
-			result = mContext->mResolvedTypes.EvaluateToVariant(&lookupCtx, constExprTypeRef->mConstExpr, constGenericParam);
-			BF_ASSERT(constGenericParam == NULL);			
+		{			
+			result = mContext->mResolvedTypes.EvaluateToVariant(&lookupCtx, constExprTypeRef->mConstExpr, resultType);
+			BF_ASSERT(resultType != NULL);			
 		}
+		
+		auto constExprType = new BfConstExprValueType();
+		constExprType->mContext = mContext;
 
-		constExprType->mType = GetPrimitiveType(result.mTypeCode);
+		constExprType->mType = resultType;
 		BF_ASSERT(constExprType->mType != NULL);
 		if (constExprType->mType == NULL)
-			constExprType->mType = GetPrimitiveType(BfTypeCode_IntPtr);
+			constExprType->mType = GetPrimitiveType(BfTypeCode_Let);
 		constExprType->mValue = result;
 
 		resolvedEntry->mValue = constExprType;
@@ -9318,8 +9354,9 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula
 		}
 		BF_ASSERT(BfResolvedTypeSet::Equals(constExprType, typeRef, &lookupCtx));
 #endif
+		
+		populateModule->InitType(constExprType, populateType);				
 
-		populateModule->InitType(constExprType, populateType);
 		return constExprType;
 	}
 	else
@@ -11689,6 +11726,9 @@ void BfModule::VariantToString(StringImpl& str, const BfVariant& variant)
 				str += ".0";
 		}
 		break;
+	case BfTypeCode_Let:
+		str += "?";
+		break;
 	default: break;
 	}
 }
@@ -12165,7 +12205,7 @@ void BfModule::DoTypeToString(StringImpl& str, BfType* resolvedType, BfTypeNameF
 	{
 		auto constExprValueType = (BfConstExprValueType*)resolvedType;
 		str += "const ";
-		 
+		 		
 		DoTypeToString(str, constExprValueType->mType, typeNameFlags, genericMethodNameOverrides);
 		str += " ";
 

+ 43 - 21
IDEHelper/Compiler/BfResolvedTypeUtils.cpp

@@ -74,6 +74,16 @@ bool BfDependencyMap::AddUsedBy(BfType* dependentType, BfDependencyMap::Dependen
 	DependencyEntry* dependencyEntry = NULL;
 	if (mTypeSet.TryAddRaw(dependentType, NULL, &dependencyEntry))
 	{
+		if ((flags & ~DependencyFlag_UnspecializedType) != 0)
+		{
+			if (auto dependentDepType = dependentType->ToDependedType())
+			{
+				int tryDepth = dependentDepType->mDependencyMap.mMinDependDepth + 1;
+				if (tryDepth < mMinDependDepth)
+					mMinDependDepth = tryDepth;
+			}
+		}
+		
 		dependencyEntry->mRevision = dependentType->mRevision;
 		dependencyEntry->mFlags = flags;
 		return true;
@@ -1344,7 +1354,10 @@ void BfCustomAttributes::ReportMemory(MemReporter* memReporter)
 BfModuleMethodInstance::BfModuleMethodInstance(BfMethodInstance* methodInstance)
 {
 	mMethodInstance = methodInstance;
-	mFunc = mMethodInstance->mIRFunction;	
+	if (methodInstance != NULL)
+		mFunc = mMethodInstance->mIRFunction;
+	else
+		mFunc = BfIRValue();
 // 	if (methodInstance->GetImportCallKind() == BfImportCallKind_Thunk)
 // 	{
 // 		auto declModule = methodInstance->mDeclModule;		
@@ -2515,18 +2528,19 @@ BfResolvedTypeSet::~BfResolvedTypeSet()
 #define HASH_CONSTEXPR 12
 #define HASH_GLOBAL 13
 
-BfVariant BfResolvedTypeSet::EvaluateToVariant(LookupContext* ctx, BfExpression* expr, BfType*& constGenericParam)
+BfVariant BfResolvedTypeSet::EvaluateToVariant(LookupContext* ctx, BfExpression* expr, BfType*& outType)
 {
 	BfConstResolver constResolver(ctx->mModule);
 	BfVariant variant = { BfTypeCode_None };	
+	constResolver.mAllowGenericConstValue = true;
 	auto result = constResolver.Resolve(expr);
-	if (result)
-	{
+	outType = result.mType;
+	if (result)	
+	{		
 		if (result.mKind == BfTypedValueKind_GenericConstValue)
-		{				
-			constGenericParam = result.mType;
+		{							
 			return variant;
-		}
+		}		
 		else
 		{
 			variant = ctx->mModule->TypedValueToVariant(expr, result, true);
@@ -2709,7 +2723,9 @@ int BfResolvedTypeSet::Hash(BfType* type, LookupContext* ctx, bool allowRef)
 	else if (type->IsConstExprValue())
 	{
 		BfConstExprValueType* constExprValueType = (BfConstExprValueType*)type;
-		return ((int)constExprValueType->mValue.mTypeCode << 17) ^ (constExprValueType->mValue.mInt32 << 3) ^ HASH_CONSTTYPE;
+		int hashVal = ((int)constExprValueType->mValue.mTypeCode << 17) ^ (constExprValueType->mValue.mInt32 << 3) ^ HASH_CONSTTYPE;
+		hashVal = ((hashVal ^ (Hash(constExprValueType->mType, ctx, BfHashFlag_AllowRef))) << 5) - hashVal;
+		return hashVal;
 	}
 	else
 	{
@@ -3216,21 +3232,23 @@ int BfResolvedTypeSet::Hash(BfTypeReference* typeRef, LookupContext* ctx, BfHash
 	else if (auto constExprTypeRef = BfNodeDynCastExact<BfConstExprTypeRef>(typeRef))
 	{
 		BfVariant result;					
+		BfType* resultType = NULL;
 		if (constExprTypeRef->mConstExpr != NULL)
 		{
-			BfType* constGenericParam = NULL;
-			result = EvaluateToVariant(ctx, constExprTypeRef->mConstExpr, constGenericParam);
-			if (constGenericParam != NULL)
-				return Hash(constGenericParam, ctx);
+			result = EvaluateToVariant(ctx, constExprTypeRef->mConstExpr, resultType);			
+			if ((resultType != NULL) && (resultType->IsGenericParam()))
+				return Hash(resultType, ctx);
 		}
 
-		if (result.mTypeCode == BfTypeCode_None)
+		if (resultType == NULL)
 		{
 			ctx->mFailed = true;
 			return 0;
 		}
 
-		return ((int)result.mTypeCode << 17) ^ (result.mInt32 << 3) ^ HASH_CONSTTYPE;
+		auto hashVal = ((int)result.mTypeCode << 17) ^ (result.mInt32 << 3) ^ HASH_CONSTTYPE;		
+		hashVal = ((hashVal ^ (Hash(resultType, ctx, BfHashFlag_AllowRef))) << 5) - hashVal;
+		return hashVal;
 	}
 	else if (auto dotTypeRef = BfNodeDynCastExact<BfDotTypeReference>(typeRef))
 	{
@@ -3884,9 +3902,9 @@ bool BfResolvedTypeSet::Equals(BfType* lhs, BfTypeReference* rhs, LookupContext*
 				if (constExprTypeRef->mConstExpr == NULL)
 					return false;
 
-				BfType* constGenericParam = NULL;
-				result = EvaluateToVariant(ctx, constExprTypeRef->mConstExpr, constGenericParam);
-				return constGenericParam == lhs;
+				BfType* resultType = NULL;
+				result = EvaluateToVariant(ctx, constExprTypeRef->mConstExpr, resultType);				
+				return resultType == lhs;
 			}
 
 			return false;
@@ -3999,9 +4017,9 @@ bool BfResolvedTypeSet::Equals(BfType* lhs, BfTypeReference* rhs, LookupContext*
 		BfVariant result;
 		if (constExprTypeRef->mConstExpr != NULL)
 		{
-			BfType* constGenericParam = NULL;
-			result = EvaluateToVariant(ctx, constExprTypeRef->mConstExpr, constGenericParam);
-			if (constGenericParam != NULL)
+			BfType* resultType = NULL;
+			result = EvaluateToVariant(ctx, constExprTypeRef->mConstExpr, resultType);			
+			if (resultType != lhsConstExprType->mType)
 				return false;
 		}
 
@@ -4455,4 +4473,8 @@ int BfTypeUtils::GetSplatCount(BfType* type)
 	return splatCount;
 }
 
-
+BfConstExprValueType::~BfConstExprValueType()
+{
+// 	mContext->mTypeConstExprCount--;
+// 	BF_ASSERT(mContext->mTypeConstExprCount == 0);
+}

+ 16 - 5
IDEHelper/Compiler/BfResolvedTypeUtils.h

@@ -69,7 +69,8 @@ enum BfGetMethodInstanceFlags : uint16
 	BfGetMethodInstanceFlag_ForceInline = 0x80,
 	BfGetMethodInstanceFlag_Friend = 0x100,
 	BfGetMethodInstanceFlag_DisableObjectAccessChecks = 0x200,
-	BfGetMethodInstanceFlag_NoInline = 0x400
+	BfGetMethodInstanceFlag_NoInline = 0x400,
+	BfGetMethodInstanceFlag_DepthExceeded = 0x800
 };
 
 class BfDependencyMap
@@ -109,12 +110,12 @@ public:
 
 	struct DependencyEntry
 	{
-		int mRevision;
+		int mRevision;		
 		DependencyFlags mFlags;
 
 		DependencyEntry(int revision, DependencyFlags flags)
 		{
-			mRevision = revision;
+			mRevision = revision;			
 			mFlags = flags;			
 		}
 	};
@@ -122,8 +123,14 @@ public:
 public:
 	typedef Dictionary<BfType*, DependencyEntry> TypeMap;	
 	TypeMap mTypeSet;
+	int mMinDependDepth;
 
 public:
+	BfDependencyMap()
+	{
+		mMinDependDepth = 0;
+	}
+
 	bool AddUsedBy(BfType* dependentType, DependencyFlags flags);	
 	bool IsEmpty();
 	TypeMap::iterator begin();
@@ -761,6 +768,7 @@ public:
 	BfTypeVector mMethodGenericArguments;
 	Dictionary<int64, BfType*> mGenericTypeBindings;
 	BfMethodCustomAttributes* mMethodCustomAttributes;
+	int mMinDependDepth;
 
 	BfMethodInfoEx()
 	{
@@ -768,6 +776,7 @@ public:
 		mForeignType = NULL;
 		mClosureInstanceInfo = NULL;
 		mMethodCustomAttributes = NULL;
+		mMinDependDepth = -1;
 	}
 
 	~BfMethodInfoEx();
@@ -1701,7 +1710,7 @@ public:
 	bool mValidatedGenericConstraints;
 	bool mHadValidateErrors;
 	bool mInitializedGenericParams;
-	bool mFinishedGenericParams;
+	bool mFinishedGenericParams;	
 	Array<BfProject*> mProjectsReferenced; // Generic methods that only refer to these projects don't need a specialized extension
 
 public:
@@ -2300,6 +2309,8 @@ public:
 	BfVariant mValue;
 
 public:	
+	~BfConstExprValueType();
+
 	virtual bool IsConstExprValue() override { return true; }
 	virtual BfType* GetUnderlyingType() override { return mType; }
 };
@@ -2397,7 +2408,7 @@ public:
 
 public:
 	static BfTypeDef* FindRootCommonOuterType(BfTypeDef* outerType, LookupContext* ctx, BfTypeInstance*& outCheckTypeInstance);
-	static BfVariant EvaluateToVariant(LookupContext* ctx, BfExpression* expr, BfType*& constGenericParam);
+	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);

+ 62 - 0
IDEHelper/Tests/src/ConstExprs.bf

@@ -0,0 +1,62 @@
+#pragma warning disable 168
+using System;
+namespace Tests
+{
+	class ConstExprs
+	{
+		enum EnumA
+		{
+			A,
+			B,
+			C
+		}
+
+		class ClassA<T, TSize> where TSize : const int
+		{
+			public int GetVal()
+			{
+				return TSize;
+			}
+		}
+
+		class ClassB<T, TSize> where TSize : const int
+		{
+			ClassA<T, TSize> mVal = new ClassA<T, const TSize>();
+			var mVal2 = new ClassA<T, const TSize + 100>();
+
+			public int GetVal()
+			{
+				return mVal.GetVal();
+			}
+
+			public int GetVal2()
+			{
+				return mVal2.GetVal();
+			}
+		}
+
+		class ClassC<TEnum> where TEnum : const EnumA
+		{
+			public int Test()
+			{
+				EnumA ea = TEnum;
+				if (TEnum == .A)
+				{
+					return 1;
+				}
+				return 0;
+			}
+		}
+
+		[Test]
+		public static void TestBasics()
+		{
+			ClassB<float, const 123> cb = scope .();
+			Test.Assert(cb.GetVal() == 123);
+			Test.Assert(cb.GetVal2() == 223);
+
+			ClassC<const EnumA.A> cc = scope .();
+			Test.Assert(cc.Test() == 1);
+		}
+	}
+}