1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-06-08 19:48:20 +02:00

Improvements and safety for const exprs

This commit is contained in:
Brian Fiete 2020-09-28 12:41:42 -07:00
parent da508156c1
commit 0a78b5cc35
8 changed files with 290 additions and 85 deletions

View file

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

View file

@ -423,13 +423,7 @@ void BfGNUMangler::Mangle(MangleContext& mangleContext, StringImpl& name, BfType
name += "v"; name += "v";
else else
name += "U4void"; name += "U4void";
return; return;
case BfTypeCode_Var:
if ((mangleContext.mCCompat) || (mangleContext.mInArgs))
name += "v";
else
name += "U3var";
return;
case BfTypeCode_Self: case BfTypeCode_Self:
if ((mangleContext.mCCompat) || (mangleContext.mInArgs)) if ((mangleContext.mCCompat) || (mangleContext.mInArgs))
name += "U8concrete"; name += "U8concrete";
@ -494,6 +488,19 @@ void BfGNUMangler::Mangle(MangleContext& mangleContext, StringImpl& name, BfType
name += "f"; return; name += "f"; return;
case BfTypeCode_Double: case BfTypeCode_Double:
name += "d"; return; 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; default: break;
} }
@ -1455,21 +1462,7 @@ void BfMSMangler::Mangle(MangleContext& mangleContext, StringImpl& name, BfType*
} }
return; return;
case BfTypeCode_None: case BfTypeCode_None:
name += "X"; return; 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;
case BfTypeCode_Int8: case BfTypeCode_Int8:
name += "C"; return; name += "C"; return;
case BfTypeCode_UInt8: case BfTypeCode_UInt8:
@ -1512,6 +1505,28 @@ void BfMSMangler::Mangle(MangleContext& mangleContext, StringImpl& name, BfType*
} }
isLongPrim = true; isLongPrim = true;
break; 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: default:
name += "?"; return; name += "?"; return;
} }

View file

@ -4766,7 +4766,7 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary<int, int>& usedStrin
return *irValuePtr; return *irValuePtr;
} }
BfTypeInstance* typeInstance = type->ToTypeInstance(); BfTypeInstance* typeInstance = type->ToTypeInstance();
BfType* typeInstanceType = ResolveTypeDef(mCompiler->mReflectTypeInstanceTypeDef); BfType* typeInstanceType = ResolveTypeDef(mCompiler->mReflectTypeInstanceTypeDef);
mBfIRBuilder->PopulateType(typeInstanceType, BfIRPopulateType_Full_ForceDefinition); 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); BfMangler::Mangle(typeDataName, mCompiler->GetMangleKind(), type, mContext->mScratchModule);
} }
if (typeDataName == "sBfTypeData.?")
{
NOP;
}
int typeCode = BfTypeCode_None; int typeCode = BfTypeCode_None;
if (typeInstance != NULL) if (typeInstance != NULL)
@ -12042,13 +12047,20 @@ BfModuleMethodInstance BfModule::GetMethodInstance(BfTypeInstance* typeInst, BfM
BF_ASSERT(instModule == mParentModule); BF_ASSERT(instModule == mParentModule);
} }
else if (instModule != this) else if (instModule != this)
{ {
if ((mCurMethodInstance != NULL) && (mCurMethodInstance->mMethodInfoEx != NULL) && (mCurMethodInstance->mMethodInfoEx->mMinDependDepth >= 32))
flags = (BfGetMethodInstanceFlags)(flags | BfGetMethodInstanceFlag_DepthExceeded);
if ((!mIsReified) && (instModule->mIsReified)) if ((!mIsReified) && (instModule->mIsReified))
{ {
BF_ASSERT(!mCompiler->mIsResolveOnly); BF_ASSERT(!mCompiler->mIsResolveOnly);
// A resolve-only module is specializing a method from a type in a reified module, // 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 // 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 else
{ {
@ -12081,6 +12093,8 @@ BfModuleMethodInstance BfModule::GetMethodInstance(BfTypeInstance* typeInst, BfM
// Not extern // Not extern
// Create the instance in the proper module and then create a reference in this one // Create the instance in the proper module and then create a reference in this one
moduleMethodInst = instModule->GetMethodInstance(typeInst, methodDef, methodGenericArguments, defFlags, foreignType); moduleMethodInst = instModule->GetMethodInstance(typeInst, methodDef, methodGenericArguments, defFlags, foreignType);
if (!moduleMethodInst)
return moduleMethodInst;
tryModuleMethodLookup = true; tryModuleMethodLookup = true;
if ((mIsReified) && (!moduleMethodInst.mMethodInstance->mIsReified)) if ((mIsReified) && (!moduleMethodInst.mMethodInstance->mIsReified))
@ -12091,7 +12105,10 @@ BfModuleMethodInstance BfModule::GetMethodInstance(BfTypeInstance* typeInst, BfM
} }
if (tryModuleMethodLookup) if (tryModuleMethodLookup)
{
SetMethodDependency(moduleMethodInst.mMethodInstance);
return ReferenceExternalMethodInstance(moduleMethodInst.mMethodInstance, flags); return ReferenceExternalMethodInstance(moduleMethodInst.mMethodInstance, flags);
}
if (((flags & BfGetMethodInstanceFlag_ForceInline) != 0) && (!methodDef->mAlwaysInline)) if (((flags & BfGetMethodInstanceFlag_ForceInline) != 0) && (!methodDef->mAlwaysInline))
{ {
@ -12422,6 +12439,8 @@ BfModuleMethodInstance BfModule::GetMethodInstance(BfTypeInstance* typeInst, BfM
if ((methodInstance != NULL) && (!doingRedeclare)) if ((methodInstance != NULL) && (!doingRedeclare))
{ {
SetMethodDependency(methodInstance);
if (methodInstance->mMethodInstanceGroup->mOnDemandKind == BfMethodOnDemandKind_Decl_AwaitingReference) if (methodInstance->mMethodInstanceGroup->mOnDemandKind == BfMethodOnDemandKind_Decl_AwaitingReference)
{ {
/*if ((!mCompiler->mIsResolveOnly) && (!isReified)) /*if ((!mCompiler->mIsResolveOnly) && (!isReified))
@ -12535,7 +12554,7 @@ BfModuleMethodInstance BfModule::GetMethodInstance(BfTypeInstance* typeInst, BfM
GetMethodInstance(typeInst, methodDef, BfTypeVector(), BfGetMethodInstanceFlag_UnspecializedPass); GetMethodInstance(typeInst, methodDef, BfTypeVector(), BfGetMethodInstanceFlag_UnspecializedPass);
} }
} }
if (methodInstance == NULL) if (methodInstance == NULL)
{ {
if (lookupMethodGenericArguments.size() == 0) 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); BfLogSysM("Created Default MethodInst: %p TypeInst: %p Group: %p\n", methodInstance, typeInst, methodInstGroup);
} }
else 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; BfMethodInstance** methodInstancePtr = NULL;
bool added = methodInstGroup->mMethodSpecializationMap->TryAdd(lookupMethodGenericArguments, NULL, &methodInstancePtr); bool added = methodInstGroup->mMethodSpecializationMap->TryAdd(lookupMethodGenericArguments, NULL, &methodInstancePtr);
BF_ASSERT(added); BF_ASSERT(added);
@ -12561,7 +12591,7 @@ BfModuleMethodInstance BfModule::GetMethodInstance(BfTypeInstance* typeInst, BfM
} }
if ((prevIRFunc) && (!prevIRFunc.IsFake())) 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 /*// 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); BF_ASSERT(!methodInstance->mIsReified);
declareModule = mContext->mUnreifiedModule; declareModule = mContext->mUnreifiedModule;
} }
SetMethodDependency(methodInstance);
SetAndRestoreValue<BfMethodInstance*> prevMethodInstance(declareModule->mCurMethodInstance, methodInstance); SetAndRestoreValue<BfMethodInstance*> prevMethodInstance(declareModule->mCurMethodInstance, methodInstance);
SetAndRestoreValue<BfTypeInstance*> prevTypeInstance(declareModule->mCurTypeInstance, typeInst); SetAndRestoreValue<BfTypeInstance*> prevTypeInstance(declareModule->mCurTypeInstance, typeInst);
@ -20214,9 +20246,6 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool
{ {
BP_ZONE("BfModule::BfMethodDeclaration"); 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 // We could trigger a DoMethodDeclaration from a const resolver or other location, so we reset it here
// to effectively make mIgnoreWrites method-scoped // to effectively make mIgnoreWrites method-scoped
SetAndRestoreValue<bool> prevIgnoreWrites(mBfIRBuilder->mIgnoreWrites, mWantsIRIgnoreWrites || mCurMethodInstance->mIsUnspecialized); 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) if (mCurMethodInstance->mMethodInstanceGroup->mOnDemandKind == BfMethodOnDemandKind_NoDecl_AwaitingReference)
mCurMethodInstance->mMethodInstanceGroup->mOnDemandKind = BfMethodOnDemandKind_Decl_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; bool ignoreWrites = mBfIRBuilder->mIgnoreWrites;
if ((!isTemporaryFunc) && (mCurTypeInstance->mDefineState < BfTypeDefineState_Defined)) if ((!isTemporaryFunc) && (mCurTypeInstance->mDefineState < BfTypeDefineState_Defined))
@ -22256,6 +22289,27 @@ bool BfModule::SlotInterfaceMethod(BfMethodInstance* methodInstance)
return true; 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() void BfModule::DbgFinish()
{ {
if ((mBfIRBuilder == NULL) || (mExtensionCount != 0)) if ((mBfIRBuilder == NULL) || (mExtensionCount != 0))

View file

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

View file

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

View file

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

View file

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

View file

@ -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);
}
}
}