From e626620e48cef23a26dc48d80bd0e3a7dcd78901 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Wed, 17 Feb 2021 07:08:09 -0800 Subject: [PATCH] Fix typeof(T).MinValue/MaxValue with generic params --- IDEHelper/Compiler/BfExprEvaluator.cpp | 62 +++++++++++++++++++------- 1 file changed, 47 insertions(+), 15 deletions(-) diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index 4451676b..3d1dfd8c 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/IDEHelper/Compiler/BfExprEvaluator.cpp @@ -10107,19 +10107,22 @@ void BfExprEvaluator::Visit(BfTypeOfExpression* typeOfExpr) bool BfExprEvaluator::LookupTypeProp(BfTypeOfExpression* typeOfExpr, BfIdentifierNode* propName) { - // We ignore errors because we go through the normal Visit(BfTypeOfExpression) if this fails, which will throw the error again - SetAndRestoreValue prevIgnoreErrors(mModule->mIgnoreErrors, true); - auto typeType = mModule->ResolveTypeDef(mModule->mCompiler->mTypeTypeDef); BfType* type; - if (auto genericTypeRef = BfNodeDynCast(typeOfExpr->mTypeRef)) + // { - type = mModule->ResolveTypeRefAllowUnboundGenerics(typeOfExpr->mTypeRef, BfPopulateType_Identity); - } - else - { - type = ResolveTypeRef(typeOfExpr->mTypeRef, BfPopulateType_Identity); + // We ignore errors because we go through the normal Visit(BfTypeOfExpression) if this fails, which will throw the error again + SetAndRestoreValue prevIgnoreErrors(mModule->mIgnoreErrors, true); + if (auto genericTypeRef = BfNodeDynCast(typeOfExpr->mTypeRef)) + { + SetAndRestoreValue prevIgnoreErrors(mModule->mIgnoreErrors, true); + type = mModule->ResolveTypeRefAllowUnboundGenerics(typeOfExpr->mTypeRef, BfPopulateType_Identity); + } + else + { + type = ResolveTypeRef(typeOfExpr->mTypeRef, BfPopulateType_Identity, BfResolveTypeRefFlag_IgnoreLookupError); + } } if (type == NULL) @@ -10209,11 +10212,40 @@ bool BfExprEvaluator::LookupTypeProp(BfTypeOfExpression* typeOfExpr, BfIdentifie else if ((memberName == "MinValue") || (memberName == "MaxValue")) { bool isMin = memberName == "MinValue"; - - BfType* checkType = typeInstance; + + BfType* checkType = type; if (checkType->IsTypedPrimitive()) checkType = checkType->GetUnderlyingType(); + if (checkType->IsGenericParam()) + { + bool foundMatch = false; + + auto genericParamInstance = mModule->GetGenericParamInstance((BfGenericParamType*)checkType); + if ((genericParamInstance->mTypeConstraint != NULL) && (genericParamInstance->mTypeConstraint->IsInstanceOf(mModule->mCompiler->mEnumTypeDef))) + foundMatch = true; + + if ((mModule->mCurMethodInstance != NULL) && (mModule->mCurMethodInstance->mIsUnspecialized) && (mModule->mCurMethodInstance->mMethodInfoEx != NULL)) + { + for (int genericParamIdx = (int)mModule->mCurMethodInstance->mMethodInfoEx->mMethodGenericArguments.size(); + genericParamIdx < mModule->mCurMethodInstance->mMethodInfoEx->mGenericParams.size(); genericParamIdx++) + { + genericParamInstance = mModule->mCurMethodInstance->mMethodInfoEx->mGenericParams[genericParamIdx]; + if (genericParamInstance->mExternType == type) + { + if ((genericParamInstance->mTypeConstraint != NULL) && (genericParamInstance->mTypeConstraint->IsInstanceOf(mModule->mCompiler->mEnumTypeDef))) + foundMatch = true; + } + } + } + + if (foundMatch) + { + mResult = mModule->GetDefaultTypedValue(type, false, Beefy::BfDefaultValueKind_Undef); + return true; + } + } + if (checkType->IsPrimitiveType()) { auto primType = (BfPrimitiveType*)checkType; @@ -10260,15 +10292,15 @@ bool BfExprEvaluator::LookupTypeProp(BfTypeOfExpression* typeOfExpr, BfIdentifie default: break; } } - } + } - if (typeInstance->IsEnum()) + if (type->IsEnum()) { - mModule->Fail("'MinValue' cannot be used on enums with payloads", propName); + mModule->Fail(StrFormat("'MinValue' cannot be used on enum with payload '%s'", mModule->TypeToString(type).c_str()), propName); } else { - mModule->Fail(StrFormat("'%s' cannot be used on type '%s'", memberName.c_str(), mModule->TypeToString(typeInstance).c_str()), propName); + mModule->Fail(StrFormat("'%s' cannot be used on type '%s'", memberName.c_str(), mModule->TypeToString(type).c_str()), propName); } } else