diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index ab58f13a..c47e4f69 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/IDEHelper/Compiler/BfExprEvaluator.cpp @@ -156,6 +156,7 @@ void BfMethodMatcher::Init(/*SizedArrayImpl& arguments, */BfSized mActiveTypeDef = NULL; mBestMethodDef = NULL; mBackupMethodDef = NULL; + mBestRawMethodInstance = NULL; mBestMethodTypeInstance = NULL; mExplicitInterfaceCheck = NULL; mSelfType = NULL; @@ -169,6 +170,7 @@ void BfMethodMatcher::Init(/*SizedArrayImpl& arguments, */BfSized mAllowNonStatic = true; mSkipImplicitParams = false; mAllowImplicitThis = false; + mHadVarConflictingReturnType = false; mMethodCheckCount = 0; mInferGenericProgressIdx = 0; mCheckedKind = BfCheckedKind_NotSet; @@ -178,7 +180,15 @@ void BfMethodMatcher::Init(/*SizedArrayImpl& arguments, */BfSized { auto bfType = arg.mTypedValue.mType; if (bfType != NULL) + { mHasVarArguments |= bfType->IsVar(); + if (bfType->IsGenericParam()) + { + auto genericParamInstance = mModule->GetGenericParamInstance((BfGenericParamType*)bfType); + if ((genericParamInstance->mGenericParamFlags & BfGenericParamFlag_Var) != 0) + mHasVarArguments = true; + } + } } if (methodGenericArguments != NULL) @@ -186,8 +196,6 @@ void BfMethodMatcher::Init(/*SizedArrayImpl& arguments, */BfSized for (BfTypeReference* genericArg : *methodGenericArguments) { auto genericArgType = mModule->ResolveTypeRef(genericArg); -// if (genericArgType == NULL) -// return; mExplicitMethodGenericArguments.push_back(genericArgType); } mHadExplicitGenericArguments = true; @@ -213,9 +221,7 @@ bool BfMethodMatcher::IsMemberAccessible(BfTypeInstance* typeInst, BfTypeDef* de bool BfMethodMatcher::InferGenericArgument(BfMethodInstance* methodInstance, BfType* argType, BfType* wantType, BfIRValue argValue, HashSet& checkedTypeSet) { if (argType == NULL) - return false; - if (argType->IsVar()) - return false; + return false; if (!wantType->IsUnspecializedType()) return true; @@ -235,9 +241,7 @@ bool BfMethodMatcher::InferGenericArgument(BfMethodInstance* methodInstance, BfT BfType* methodGenericTypeConstraint = NULL; auto _SetGeneric = [&]() - { - BF_ASSERT((argType == NULL) || (!argType->IsVar())); - + { if (argType != NULL) { // Disallow illegal types @@ -300,6 +304,12 @@ bool BfMethodMatcher::InferGenericArgument(BfMethodInstance* methodInstance, BfT mPrevArgValues[wantGenericParam->mGenericParamIdx] = argValue; }; + if (argType->IsVar()) + { + _SetGeneric(); + return true; + } + if (wantGenericParam->mGenericParamKind == BfGenericParamKind_Method) { auto genericParamInst = methodInstance->mMethodInfoEx->mGenericParams[wantGenericParam->mGenericParamIdx]; @@ -381,8 +391,33 @@ bool BfMethodMatcher::InferGenericArgument(BfMethodInstance* methodInstance, BfT if ((wantType->IsGenericTypeInstance()) && (wantType->IsUnspecializedTypeVariation())) { auto wantGenericType = (BfGenericTypeInstance*)wantType; + if (argType->IsGenericParam()) + { + auto genericParam = mModule->GetGenericParamInstance((BfGenericParamType*)argType); + if ((genericParam->mGenericParamFlags & BfGenericParamFlag_Var) != 0) + { + InferGenericArgument(methodInstance, mModule->GetPrimitiveType(BfTypeCode_Var), wantType, BfIRValue(), checkedTypeSet); + return true; + } + + if ((genericParam->mTypeConstraint != NULL) && (genericParam->mTypeConstraint->IsGenericTypeInstance())) + InferGenericArgument(methodInstance, genericParam->mTypeConstraint, wantType, BfIRValue(), checkedTypeSet); + } + + if (argType->IsVar()) + { + for (int genericArgIdx = 0; genericArgIdx < (int)wantGenericType->mTypeGenericArguments.size(); genericArgIdx++) + { + BfType* wantGenericArgument = wantGenericType->mTypeGenericArguments[genericArgIdx]; + if (!wantGenericArgument->IsUnspecializedType()) + continue; + InferGenericArgument(methodInstance, mModule->GetPrimitiveType(BfTypeCode_Var), wantGenericArgument, BfIRValue(), checkedTypeSet); + } + return true; + } + if (!argType->IsGenericTypeInstance()) - return true; + return true; auto argGenericType = (BfGenericTypeInstance*)argType; if (argGenericType->mTypeDef != wantGenericType->mTypeDef) return true; @@ -1555,7 +1590,12 @@ bool BfMethodMatcher::CheckMethod(BfTypeInstance* targetTypeInstance, BfTypeInst // And if neither better nor worse then they are equally good, which is not allowed either if (((!isBetter) && (!isWorse)) || ((isBetter) && (isWorse))) { - if (!mHasVarArguments) + if (mHasVarArguments) + { + if (prevMethodInstance->mReturnType != prevMethodInstance->mReturnType) + mHadVarConflictingReturnType = true; + } + else { BfAmbiguousEntry ambiguousEntry; ambiguousEntry.mMethodInstance = methodInstance; @@ -1588,6 +1628,7 @@ bool BfMethodMatcher::CheckMethod(BfTypeInstance* targetTypeInstance, BfTypeInst mAmbiguousEntries.Clear(); hadMatch = true; mBestMethodDef = checkMethod; + mBestRawMethodInstance = methodInstance; for (auto& arg : mArguments) arg.mBestBoundType = arg.mTypedValue.mType; @@ -1646,10 +1687,10 @@ NoMatch: if (genericArgumentsSubstitute != NULL) { mBestMethodGenericArguments = *genericArgumentsSubstitute; -#ifdef _DEBUG - for (auto arg : mBestMethodGenericArguments) - BF_ASSERT((arg == NULL) || (!arg->IsVar())); -#endif +// #ifdef _DEBUG +// for (auto arg : mBestMethodGenericArguments) +// BF_ASSERT((arg == NULL) || (!arg->IsVar())); +// #endif } else mBestMethodGenericArguments.clear(); @@ -2087,6 +2128,17 @@ void BfMethodMatcher::TryDevirtualizeCall(BfTypedValue target, BfTypedValue* ori } } +bool BfMethodMatcher::HasVarGenerics() +{ + for (auto genericArg : mBestMethodGenericArguments) + if (genericArg->IsVar()) + return true; + for (auto genericArg : mExplicitMethodGenericArguments) + if (genericArg->IsVar()) + return true; + return false; +} + void BfMethodMatcher::CheckOuterTypeStaticMethods(BfTypeInstance* typeInstance, bool isFailurePass) { bool allowPrivate = true; @@ -7050,20 +7102,29 @@ BfTypedValue BfExprEvaluator::MatchMethod(BfAstNode* targetSrc, BfMethodBoundExp mModule->Fail(StrFormat("Method '%s' does not exist", methodName.c_str()), targetSrc); return BfTypedValue(); } - - if ((mModule->mCurMethodInstance != NULL) && (mModule->mCurMethodInstance->mIsUnspecialized)) - { - for (auto& arg : methodMatcher.mBestMethodGenericArguments) - { - if ((arg != NULL) && (arg->IsVar())) - return mModule->GetDefaultTypedValue(mModule->GetPrimitiveType(BfTypeCode_Var)); - } - } - + if ((prevBindResult.mPrevVal != NULL) && (methodMatcher.mMethodCheckCount > 1)) prevBindResult.mPrevVal->mCheckedMultipleMethods = true; BfModuleMethodInstance moduleMethodInstance = GetSelectedMethod(targetSrc, curTypeInst, methodDef, methodMatcher); + + if ((mModule->mCurMethodInstance != NULL) && (mModule->mCurMethodInstance->mIsUnspecialized)) + { + if (methodMatcher.mHasVarArguments) + { + BfType* retType = mModule->GetPrimitiveType(BfTypeCode_Var); + + if ((!methodMatcher.mHadVarConflictingReturnType) && (methodMatcher.mBestRawMethodInstance != NULL) && (!methodMatcher.mBestRawMethodInstance->mReturnType->IsUnspecializedTypeVariation())) + { + if ((!methodMatcher.mBestRawMethodInstance->mReturnType->IsGenericParam()) || + (((BfGenericParamType*)methodMatcher.mBestRawMethodInstance->mReturnType)->mGenericParamKind != BfGenericParamKind_Method)) + retType = methodMatcher.mBestRawMethodInstance->mReturnType; + } + + return mModule->GetDefaultTypedValue(retType); + } + } + if ((bypassVirtual) && (!target.mValue) && (target.mType->IsInterface())) { target = mModule->GetThis(); @@ -12361,6 +12422,8 @@ BfModuleMethodInstance BfExprEvaluator::GetSelectedMethod(BfAstNode* targetSrc, BfMethodInstance* unspecializedMethod = NULL; + bool hasVarGenerics = false; + for (int checkGenericIdx = 0; checkGenericIdx < (int)methodMatcher.mBestMethodGenericArguments.size(); checkGenericIdx++) { BfMethodInstance* outerMethodInstance = NULL; @@ -12440,6 +12503,12 @@ BfModuleMethodInstance BfExprEvaluator::GetSelectedMethod(BfAstNode* targetSrc, } else { + if (genericArg->IsVar()) + { + BF_ASSERT(methodMatcher.mHasVarArguments); + hasVarGenerics = true; + } + if (genericArg->IsIntUnknown()) genericArg = mModule->GetPrimitiveType(BfTypeCode_IntPtr); @@ -12448,7 +12517,7 @@ BfModuleMethodInstance BfExprEvaluator::GetSelectedMethod(BfAstNode* targetSrc, hasDifferentResolvedTypes = true; resolvedGenericArguments.push_back(resolvedGenericArg); } - } + } BfTypeInstance* foreignType = NULL; BfGetMethodInstanceFlags flags = BfGetMethodInstanceFlag_None; @@ -12479,6 +12548,9 @@ BfModuleMethodInstance BfExprEvaluator::GetSelectedMethod(BfAstNode* targetSrc, } } + if (hasVarGenerics) + return BfModuleMethodInstance(); + BfModuleMethodInstance methodInstance; if (methodMatcher.mBestMethodInstance) { @@ -12598,21 +12670,24 @@ void BfExprEvaluator::CheckLocalMethods(BfAstNode* targetSrc, BfTypeInstance* ty if ((mModule->mCurMethodState != NULL) && (mModule->mCurMethodState->mClosureState != NULL) && (mModule->mCurMethodState->mClosureState->mCapturing)) { BfModuleMethodInstance moduleMethodInstance = GetSelectedMethod(targetSrc, typeInstance, matchedLocalMethod->mMethodDef, methodMatcher); - auto methodInstance = moduleMethodInstance.mMethodInstance; - - if ((methodInstance->mMethodInfoEx != NULL) && (methodInstance->mMethodInfoEx->mClosureInstanceInfo->mCaptureClosureState != NULL)) + if (moduleMethodInstance) { - // The called method is calling us from its mLocalMethodRefs set. Stretch our mCaptureStartAccessId back to incorporate its - // captures as well - if (methodInstance->mMethodInfoEx->mClosureInstanceInfo->mCaptureClosureState->mCaptureStartAccessId < mModule->mCurMethodState->mClosureState->mCaptureStartAccessId) - mModule->mCurMethodState->mClosureState->mCaptureStartAccessId = methodInstance->mMethodInfoEx->mClosureInstanceInfo->mCaptureClosureState->mCaptureStartAccessId; - } - else - { - if (methodInstance->mDisallowCalling) // We need to process the captures from this guy + auto methodInstance = moduleMethodInstance.mMethodInstance; + + if ((methodInstance->mMethodInfoEx != NULL) && (methodInstance->mMethodInfoEx->mClosureInstanceInfo->mCaptureClosureState != NULL)) { - if (mModule->mCurMethodState->mClosureState->mLocalMethodRefSet.Add(methodInstance)) - mModule->mCurMethodState->mClosureState->mLocalMethodRefs.Add(methodInstance); + // The called method is calling us from its mLocalMethodRefs set. Stretch our mCaptureStartAccessId back to incorporate its + // captures as well + if (methodInstance->mMethodInfoEx->mClosureInstanceInfo->mCaptureClosureState->mCaptureStartAccessId < mModule->mCurMethodState->mClosureState->mCaptureStartAccessId) + mModule->mCurMethodState->mClosureState->mCaptureStartAccessId = methodInstance->mMethodInfoEx->mClosureInstanceInfo->mCaptureClosureState->mCaptureStartAccessId; + } + else + { + if (methodInstance->mDisallowCalling) // We need to process the captures from this guy + { + if (mModule->mCurMethodState->mClosureState->mLocalMethodRefSet.Add(methodInstance)) + mModule->mCurMethodState->mClosureState->mLocalMethodRefs.Add(methodInstance); + } } } } diff --git a/IDEHelper/Compiler/BfExprEvaluator.h b/IDEHelper/Compiler/BfExprEvaluator.h index 13e3fbe4..7b64d4a3 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.h +++ b/IDEHelper/Compiler/BfExprEvaluator.h @@ -127,12 +127,13 @@ public: BfMethodType mMethodType; BfCheckedKind mCheckedKind; bool mHadExplicitGenericArguments; - bool mHasVarArguments; + bool mHasVarArguments; + bool mHadVarConflictingReturnType; bool mBypassVirtual; bool mAllowImplicitThis; bool mAllowStatic; bool mAllowNonStatic; - bool mSkipImplicitParams; + bool mSkipImplicitParams; int mMethodCheckCount; int mInferGenericProgressIdx; BfType* mExplicitInterfaceCheck; @@ -146,6 +147,7 @@ public: int mBackupArgMatchCount; BfMethodDef* mBestMethodDef; BfTypeInstance* mBestMethodTypeInstance; + BfMethodInstance* mBestRawMethodInstance; BfModuleMethodInstance mBestMethodInstance; SizedArray mBestMethodGenericArgumentSrcs; BfTypeVector mBestMethodGenericArguments; @@ -173,6 +175,8 @@ public: bool WantsCheckMethod(BfProtectionCheckFlags& flags, BfTypeInstance* startTypeInstance, BfTypeInstance* checkTypeInstance, BfMethodDef* methodDef); bool CheckMethod(BfTypeInstance* targetTypeInstance, BfTypeInstance* typeInstance, BfMethodDef* checkMethod, bool isFailurePass); void TryDevirtualizeCall(BfTypedValue target, BfTypedValue* origTarget = NULL, BfTypedValue* staticResult = NULL); + bool HasVarGenerics(); + bool IsVarCall(BfType*& outReturnType); }; diff --git a/IDEHelper/Compiler/BfModuleTypeUtils.cpp b/IDEHelper/Compiler/BfModuleTypeUtils.cpp index 0db2c0b0..854a717e 100644 --- a/IDEHelper/Compiler/BfModuleTypeUtils.cpp +++ b/IDEHelper/Compiler/BfModuleTypeUtils.cpp @@ -472,6 +472,11 @@ bool BfModule::InitType(BfType* resolvedTypeRef, BfPopulateType populateType) { auto genericTypeInstance = (BfGenericTypeInstance*)resolvedTypeRef; +#ifdef _DEBUG + for (auto genericArg : genericTypeInstance->mTypeGenericArguments) + BF_ASSERT(!genericArg->IsVar()); +#endif + // Do it here so the location we attempted to specialize this type will throw the failure if there is one if (!BuildGenericParams(resolvedTypeRef)) return false; @@ -5680,6 +5685,8 @@ BfType* BfModule::ResolveGenericType(BfType* unspecializedType, BfTypeVector* ty auto elementType = ResolveGenericType(arrayType->mElementType, typeGenericArguments, methodGenericArguments, allowFail); if (elementType == NULL) return NULL; + if (elementType->IsVar()) + return elementType; auto sizeType = ResolveGenericType(arrayType->mElementCountSource, typeGenericArguments, methodGenericArguments, allowFail); if (sizeType == NULL) return NULL; @@ -5696,6 +5703,8 @@ BfType* BfModule::ResolveGenericType(BfType* unspecializedType, BfTypeVector* ty auto elementType = ResolveGenericType(arrayType->mElementType, typeGenericArguments, methodGenericArguments, allowFail); if (elementType == NULL) return NULL; + if (elementType->IsVar()) + return elementType; return CreateSizedArrayType(elementType, (int)arrayType->mElementCount); } @@ -5705,6 +5714,8 @@ BfType* BfModule::ResolveGenericType(BfType* unspecializedType, BfTypeVector* ty auto elementType = ResolveGenericType(refType->GetUnderlyingType(), typeGenericArguments, methodGenericArguments, allowFail); if (elementType == NULL) return NULL; + if (elementType->IsVar()) + return elementType; return CreateRefType(elementType, refType->mRefKind); } @@ -5714,6 +5725,8 @@ BfType* BfModule::ResolveGenericType(BfType* unspecializedType, BfTypeVector* ty auto elementType = ResolveGenericType(ptrType->GetUnderlyingType(), typeGenericArguments, methodGenericArguments, allowFail); if (elementType == NULL) return NULL; + if (elementType->IsVar()) + return elementType; return CreatePointerType(elementType); } @@ -5723,6 +5736,8 @@ BfType* BfModule::ResolveGenericType(BfType* unspecializedType, BfTypeVector* ty auto elementType = ResolveGenericType(arrayType->GetUnderlyingType(), typeGenericArguments, methodGenericArguments, allowFail); if (elementType == NULL) return NULL; + if (elementType->IsVar()) + return elementType; return CreateArrayType(elementType, arrayType->mDimensions); } @@ -5741,6 +5756,8 @@ BfType* BfModule::ResolveGenericType(BfType* unspecializedType, BfTypeVector* ty auto newGenericArg = ResolveGenericType(origGenericArg, typeGenericArguments, methodGenericArguments, allowFail); if (newGenericArg == NULL) return NULL; + if (newGenericArg->IsVar()) + return newGenericArg; if (newGenericArg != origGenericArg) hadChange = true; genericArgs.push_back(newGenericArg); @@ -5773,6 +5790,8 @@ BfType* BfModule::ResolveGenericType(BfType* unspecializedType, BfTypeVector* ty auto returnType = ResolveGenericType(unspecializedDelegateInfo->mReturnType, typeGenericArguments, methodGenericArguments, allowFail); if (returnType == NULL) return NULL; + if (returnType->IsVar()) + return returnType; _CheckType(returnType); if (returnType->IsGenericParam()) hasTypeGenerics |= ((BfGenericParamType*)returnType)->mGenericParamKind == BfGenericParamKind_Type; @@ -5782,6 +5801,8 @@ BfType* BfModule::ResolveGenericType(BfType* unspecializedType, BfTypeVector* ty auto paramType = ResolveGenericType(param, typeGenericArguments, methodGenericArguments, allowFail); if (paramType == NULL) return NULL; + if (paramType->IsVar()) + return paramType; paramTypes.Add(paramType); _CheckType(paramType); } @@ -5803,6 +5824,8 @@ BfType* BfModule::ResolveGenericType(BfType* unspecializedType, BfTypeVector* ty resolvedArg = ResolveGenericType(resolvedArg, typeGenericArguments, methodGenericArguments, allowFail); if (resolvedArg == NULL) return NULL; + if (resolvedArg->IsVar()) + return resolvedArg; } genericArgs.push_back(resolvedArg); } @@ -5938,6 +5961,8 @@ BfType* BfModule::ResolveGenericType(BfType* unspecializedType, BfTypeVector* ty auto resolvedArg = ResolveGenericType(genericArg, typeGenericArguments, methodGenericArguments, allowFail); if (resolvedArg == NULL) return NULL; + if (resolvedArg->IsVar()) + return resolvedArg; genericArgs.push_back(resolvedArg); } else