From 3e8d18bb5754d1eb5fd0f86a0db27666247a0872 Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Fri, 23 Jan 2026 11:57:16 -0800 Subject: [PATCH 01/11] Start trying to separate phases of POI search Signed-off-by: Danila Fedorin --- compiler/include/resolution.h | 2 +- compiler/resolution/functionResolution.cpp | 101 +++++++++++++++------ 2 files changed, 72 insertions(+), 31 deletions(-) diff --git a/compiler/include/resolution.h b/compiler/include/resolution.h index b9c5cd677582..2867970c0807 100644 --- a/compiler/include/resolution.h +++ b/compiler/include/resolution.h @@ -257,7 +257,7 @@ void resolveCallAndCallee(CallExpr* call, bool allowUnresolved = false); Type* resolveDefaultGenericTypeSymExpr(SymExpr* se); Type* resolveTypeAlias(SymExpr* se); -FnSymbol* tryResolveCall(CallExpr* call, bool checkWithin=false); +FnSymbol* tryResolveCall(CallExpr* call, bool checkWithin=false, bool considerPoi=true); void makeRefType(Type* type); // FnSymbol changes diff --git a/compiler/resolution/functionResolution.cpp b/compiler/resolution/functionResolution.cpp index 066e7f1eccee..c21c1c64d613 100644 --- a/compiler/resolution/functionResolution.cpp +++ b/compiler/resolution/functionResolution.cpp @@ -2992,13 +2992,13 @@ static void resolveRefDeserialization(CallExpr* call) { lhsSE->symbol()->type = typeSE->symbol()->getRefType(); } -static FnSymbol* resolveNormalCall(CallExpr* call, check_state_t checkState); +static FnSymbol* resolveNormalCall(CallExpr* call, check_state_t checkState, bool considerPoi=true); FnSymbol* resolveNormalCall(CallExpr* call) { return resolveNormalCall(call, CHECK_NORMAL_CALL); } -FnSymbol* tryResolveCall(CallExpr* call, bool checkWithin) { +FnSymbol* tryResolveCall(CallExpr* call, bool checkWithin, bool considerPoi) { check_state_t checkState = CHECK_CALLABLE_ONLY; if (checkWithin) checkState = CHECK_BODY_RESOLVES; @@ -3528,9 +3528,13 @@ static void resolveCoerceCopyMove(CallExpr* call) { static bool isGenericRecordInit(CallExpr* call); -static FnSymbol* resolveNormalCall(CallInfo& info, check_state_t checkState); -static FnSymbol* resolveNormalCall(CallExpr* call, check_state_t checkState); +static FnSymbol* resolveNormalCall(CallInfo& info, check_state_t checkState, bool considerPoi = true); +static FnSymbol* resolveNormalCall(CallExpr* call, check_state_t checkState, bool considerPoi); +static BlockStmt* tryFindVisibileCandidatesForExplicitFn(CallInfo& info, + VisibilityInfo& visInfo, + Vec& mostApplicable, + Vec& candidates); static BlockStmt* findVisibleFunctionsAndCandidates( CallInfo& info, VisibilityInfo& visInfo, @@ -3991,7 +3995,7 @@ static void maybeWarnGenericActuals(CallExpr* call) { } static -FnSymbol* resolveNormalCall(CallExpr* call, check_state_t checkState) { +FnSymbol* resolveNormalCall(CallExpr* call, check_state_t checkState, bool considerPoi) { CallInfo info; FnSymbol* retval = NULL; @@ -4017,7 +4021,7 @@ FnSymbol* resolveNormalCall(CallExpr* call, check_state_t checkState) { if (isTypeConstructionCall(call)) { resolveTypeSpecifier(info); } else { - retval = resolveNormalCall(info, checkState); + retval = resolveNormalCall(info, checkState, considerPoi); } } else if (checkState != CHECK_NORMAL_CALL) { @@ -4255,10 +4259,10 @@ static bool overloadSetsOK(CallExpr* call, } -static FnSymbol* resolveForwardedCall(CallInfo& info, check_state_t checkState); +static FnSymbol* resolveForwardedCall(CallInfo& info, check_state_t checkState, bool considerPoi = true); static bool typeUsesForwarding(Type* t); -static FnSymbol* resolveNormalCall(CallInfo& info, check_state_t checkState) { +static FnSymbol* resolveNormalCall(CallInfo& info, check_state_t checkState, bool considerPoi) { Vec mostApplicable; Vec candidates; @@ -4273,8 +4277,14 @@ static FnSymbol* resolveNormalCall(CallInfo& info, check_state_t checkState) { BlockStmt* scopeUsed = nullptr; - scopeUsed = findVisibleFunctionsAndCandidates(info, visInfo, - mostApplicable, candidates); + if ((scopeUsed = tryFindVisibileCandidatesForExplicitFn(info, visInfo, mostApplicable, candidates))) { + /* the function was explicitly specified via FnSymbol*. Don't search + for others and don't consider POI */ + considerPoi = false; + } else { + scopeUsed = findVisibleFunctionsAndCandidates(info, visInfo, + mostApplicable, candidates); + } numMatches = disambiguateByMatch(info, scopeUsed, candidates, bestRef, bestCref, bestVal); @@ -4284,13 +4294,23 @@ static FnSymbol* resolveNormalCall(CallInfo& info, check_state_t checkState) { bestRef, bestCref, bestVal); // If no candidates were found and it's a method, try forwarding - if (candidates.n == 0 && - info.call->numActuals() >= 1 && - info.call->get(1)->typeInfo() == dtMethodToken && - isUnresolvedSymExpr(info.call->baseExpr)) { - Type* receiverType = canonicalDecoratedClassType(info.call->get(2)->getValType()); - if (typeUsesForwarding(receiverType)) { - FnSymbol* fn = resolveForwardedCall(info, checkState); + bool forwardingEligible = + candidates.n == 0 && + info.call->numActuals() >= 1 && + info.call->get(1)->typeInfo() == dtMethodToken && + isUnresolvedSymExpr(info.call->baseExpr); + Type* receiverType; + bool usesForwarding = false; + + // For now, do not consider POI. This way, if/when we recurse, we first + // check all forwarding statements without POI, and only then go back + // to POI. This is crucial for correctness. See + // + // https://github.com/chapel-lang/chapel/issues/28246 + if (forwardingEligible) { + receiverType = canonicalDecoratedClassType(info.call->get(2)->getValType()); + if ((usesForwarding = typeUsesForwarding(receiverType))) { + FnSymbol* fn = resolveForwardedCall(info, checkState, /* conisiderPoi */ false); if (fn) { return fn; } @@ -4298,6 +4318,19 @@ static FnSymbol* resolveNormalCall(CallInfo& info, check_state_t checkState) { } } + if (considerPoi) { + // TODO: consider POI + } + + // Now, try forwarding again, this time considering POI + if (candidates.n == 0 && forwardingEligible && usesForwarding && considerPoi) { + FnSymbol* fn = resolveForwardedCall(info, checkState, /* conisiderPoi */ true); + if (fn) { + return fn; + } + // otherwise error is printed below + } + if (numMatches > 0) { if (! overloadSetsOK(info.call, scopeUsed, checkState, candidates, bestRef, bestCref, bestVal)) @@ -5513,17 +5546,14 @@ void advanceCurrStart(VisibilityInfo& visInfo) { visInfo.nextPOI = NULL; } -// Returns the POI scope used to find the candidates -static BlockStmt* findVisibleFunctionsAndCandidates( - CallInfo& info, - VisibilityInfo& visInfo, - Vec& mostApplicable, - Vec& candidates) { +static BlockStmt* tryFindVisibileCandidatesForExplicitFn(CallInfo& info, + VisibilityInfo& visInfo, + Vec& mostApplicable, + Vec& candidates) { CallExpr* call = info.call; FnSymbol* fn = call->resolvedFunction(); Vec visibleFns; - - if (fn != NULL) { + if (fn != nullptr) { visibleFns.add(fn); mostApplicable.add(fn); // for better error reporting @@ -5536,6 +5566,17 @@ static BlockStmt* findVisibleFunctionsAndCandidates( return getVisibilityScope(call); } + return nullptr; +} + +// Returns the POI scope used to find the candidates +static BlockStmt* findVisibleFunctionsAndCandidates( + CallInfo& info, + VisibilityInfo& visInfo, + Vec& mostApplicable, + Vec& candidates) { + CallExpr* call = info.call; + Vec visibleFns; // CG TODO: pull all visible interface functions, if within a CG context @@ -5738,7 +5779,7 @@ static const char* getForwardedMethodName(const char* calledName, return methodName; } -static FnSymbol* adjustAndResolveForwardedCall(CallExpr* call, ForwardingStmt* delegate, const char* methodName) { +static FnSymbol* adjustAndResolveForwardedCall(CallExpr* call, ForwardingStmt* delegate, const char* methodName, bool considerPoi) { FnSymbol* ret = NULL; const char* fnGetTgt = delegate->fnReturningForwarding; @@ -5780,7 +5821,7 @@ static FnSymbol* adjustAndResolveForwardedCall(CallExpr* call, ForwardingStmt* d } resolveCall(setTgt); - ret = tryResolveCall(call); + ret = tryResolveCall(call, /* checkWithin */ false, considerPoi); } return ret; @@ -5789,7 +5830,7 @@ static FnSymbol* adjustAndResolveForwardedCall(CallExpr* call, ForwardingStmt* d llvm::SmallVector, 4> forwardCallCycleSet; // Returns a relevant FnSymbol if it worked -static FnSymbol* resolveForwardedCall(CallInfo& info, check_state_t checkState) { +static FnSymbol* resolveForwardedCall(CallInfo& info, check_state_t checkState, bool considerPoi) { CallExpr* call = info.call; const char* calledName = astr(info.name); const char* inFnName = astr(call->getFunction()->name); @@ -5871,7 +5912,7 @@ static FnSymbol* resolveForwardedCall(CallInfo& info, check_state_t checkState) BlockStmt* block = new BlockStmt(forwardedCall, BLOCK_SCOPELESS); call->getStmtExpr()->insertBefore(block); - auto fn = adjustAndResolveForwardedCall(forwardedCall, delegate, methodName); + auto fn = adjustAndResolveForwardedCall(forwardedCall, delegate, methodName, considerPoi); if (fn) { if (bestFn == NULL) { bestFn = fn; @@ -5903,7 +5944,7 @@ static FnSymbol* resolveForwardedCall(CallInfo& info, check_state_t checkState) const char* methodName = getForwardedMethodName(calledName, bestDelegate); INT_ASSERT(methodName); - bestFn = adjustAndResolveForwardedCall(call, bestDelegate, methodName); + bestFn = adjustAndResolveForwardedCall(call, bestDelegate, methodName, considerPoi); } else { // Replace actuals in call with those from bestCall // Note that the above path could be used instead, but From 5529fb972e59b25bcb4e2bd6a0b9a0b10a2e571c Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Fri, 23 Jan 2026 17:40:39 -0800 Subject: [PATCH 02/11] Move candidate search state into a class. This helps make the data flow more explicit and bundle repeated arguments. Signed-off-by: Danila Fedorin --- compiler/resolution/functionResolution.cpp | 147 ++++++++++++--------- 1 file changed, 84 insertions(+), 63 deletions(-) diff --git a/compiler/resolution/functionResolution.cpp b/compiler/resolution/functionResolution.cpp index c21c1c64d613..622f52ae32af 100644 --- a/compiler/resolution/functionResolution.cpp +++ b/compiler/resolution/functionResolution.cpp @@ -3526,20 +3526,57 @@ static void resolveCoerceCopyMove(CallExpr* call) { * * ************************************** | *************************************/ +// +// We gather a list of last-resort candidates as we go. +// The last-resort candidates visible from the call are followed by a NULL +// to separate them from those visible from the point of instantiation. +// +using LastResortCandidates = std::vector; + static bool isGenericRecordInit(CallExpr* call); static FnSymbol* resolveNormalCall(CallInfo& info, check_state_t checkState, bool considerPoi = true); static FnSymbol* resolveNormalCall(CallExpr* call, check_state_t checkState, bool considerPoi); -static BlockStmt* tryFindVisibileCandidatesForExplicitFn(CallInfo& info, - VisibilityInfo& visInfo, - Vec& mostApplicable, - Vec& candidates); -static BlockStmt* findVisibleFunctionsAndCandidates( - CallInfo& info, - VisibilityInfo& visInfo, - Vec& visibleFns, - Vec& candidates); +// State for candidate search. Tracks seen, most applicable, etc. candidates, +// and other information like the current POI scope. +struct CandidateSearchState { + CallInfo& info; + VisibilityInfo visInfo; // note: contains state as to the current POI scope. + PtrSet visited; + BlockStmt* scopeUsed = nullptr; // scope last searched for candidates + + // Keep *all* discovered functions in 'visibleFns' and 'mostApplicable' + // so that we can revisit them for error reporting. The lists ( + // visible -> most applicable -> candidates) trickle down into the next. + // All of them only every grow, with numVisitedVis and numVisitedMA tracking + // the point up all candiddates have been moved to the successive list if + // they needed to be. The flow is as follows: + // 1. In each potential scope (call and POI(s)), visible functions get + // placed into `visibleFns`. + // 2. From those, we find the most applicable functions (coarse, early + // filtering, which removes functions on unrelated objects as best as + // I can tell) and move them into `mostApplicable`. + // 3. From those, we either move candidates into the last resort group + // (if they are last resort candidates) or into `candidates`. + // In this way, 'numVisited*' keeps track of where we left off with the + // previous POI / scope to avoid revisiting those functions for the next POI. + int numVisitedVis = 0, numVisitedMA = 0; + Vec visibleFns; + Vec mostApplicable; + Vec candidates; + LastResortCandidates lrc; + + CandidateSearchState(CallInfo& info) + : info(info), visInfo(info) { + visInfo.currStart = getVisibilityScope(info.call); + INT_ASSERT(visInfo.poiDepth == -1); // we have not used it + } + + bool tryFindVisibileCandidatesForExplicitFn(); + void searchOnePoiLevel(); + void findVisibleFunctionsAndCandidates(); +}; static int disambiguateByMatch(CallInfo& info, BlockStmt* searchScope, @@ -4263,27 +4300,26 @@ static FnSymbol* resolveForwardedCall(CallInfo& info, check_state_t checkState, static bool typeUsesForwarding(Type* t); static FnSymbol* resolveNormalCall(CallInfo& info, check_state_t checkState, bool considerPoi) { - Vec mostApplicable; - Vec candidates; - ResolutionCandidate* bestRef = NULL; ResolutionCandidate* bestCref = NULL; ResolutionCandidate* bestVal = NULL; - VisibilityInfo visInfo(info); int numMatches = 0; FnSymbol* retval = NULL; - BlockStmt* scopeUsed = nullptr; + CandidateSearchState searchState(info); + auto& visInfo = searchState.visInfo; + auto& mostApplicable = searchState.mostApplicable; + auto& candidates = searchState.candidates; + auto& scopeUsed = searchState.scopeUsed; - if ((scopeUsed = tryFindVisibileCandidatesForExplicitFn(info, visInfo, mostApplicable, candidates))) { + if (searchState.tryFindVisibileCandidatesForExplicitFn()) { /* the function was explicitly specified via FnSymbol*. Don't search for others and don't consider POI */ considerPoi = false; } else { - scopeUsed = findVisibleFunctionsAndCandidates(info, visInfo, - mostApplicable, candidates); + searchState.findVisibleFunctionsAndCandidates(); } numMatches = disambiguateByMatch(info, scopeUsed, candidates, @@ -5400,13 +5436,6 @@ static void generateUnresolvedMsg(CallInfo& info, Vec& visibleFns) { * * ************************************** | *************************************/ -// -// We gather a list of last-resort candidates as we go. -// The last-resort candidates visible from the call are followed by a NULL -// to separate them from those visible from the point of instantiation. -// -typedef std::vector LastResortCandidates; - // add a null separator static void markEndOfPOI(LastResortCandidates& lrc) { lrc.push_back(NULL); @@ -5546,10 +5575,7 @@ void advanceCurrStart(VisibilityInfo& visInfo) { visInfo.nextPOI = NULL; } -static BlockStmt* tryFindVisibileCandidatesForExplicitFn(CallInfo& info, - VisibilityInfo& visInfo, - Vec& mostApplicable, - Vec& candidates) { +bool CandidateSearchState::tryFindVisibileCandidatesForExplicitFn() { CallExpr* call = info.call; FnSymbol* fn = call->resolvedFunction(); Vec visibleFns; @@ -5564,50 +5590,47 @@ static BlockStmt* tryFindVisibileCandidatesForExplicitFn(CallInfo& info, explainGatherCandidate(info, candidates); - return getVisibilityScope(call); + scopeUsed = getVisibilityScope(call); + return true; } - return nullptr; + return false; } -// Returns the POI scope used to find the candidates -static BlockStmt* findVisibleFunctionsAndCandidates( - CallInfo& info, - VisibilityInfo& visInfo, - Vec& mostApplicable, - Vec& candidates) { - CallExpr* call = info.call; - Vec visibleFns; +// when looking for function candidates, we first check the current scope, +// then walk through the POI scopes. For each scope, we execute searchOnePoiLevel(), +// which checks for visible functions and gathers candidates. We stop if +// we find any candidates. +void CandidateSearchState::searchOnePoiLevel() { + // CG TODO: no POI for CG functions + visInfo.poiDepth++; - // CG TODO: pull all visible interface functions, if within a CG context + findVisibleFunctions(info, &visInfo, &visited, + &numVisitedVis, visibleFns); - // Keep *all* discovered functions in 'visibleFns' and 'mostApplicable' - // so that we can revisit them for error reporting. - // Keep track in 'numVisited*' of where we left off with the previous POI - // to avoid revisiting those functions for the next POI. - int numVisitedVis = 0, numVisitedMA = 0; - LastResortCandidates lrc; - PtrSet visited; - visInfo.currStart = getVisibilityScope(call); - INT_ASSERT(visInfo.poiDepth == -1); // we have not used it - BlockStmt* scopeUsed = nullptr; + trimVisibleCandidates(info, mostApplicable, + numVisitedVis, visibleFns); - do { - // CG TODO: no POI for CG functions - visInfo.poiDepth++; + gatherCandidatesAndLastResort(info, visInfo, mostApplicable, numVisitedMA, + lrc, candidates); + + // save the scope used for disambiguation + scopeUsed = visInfo.currStart; - findVisibleFunctions(info, &visInfo, &visited, - &numVisitedVis, visibleFns); + advanceCurrStart(visInfo); +} +// static BlockStmt* findVisibleFunctionsAndCandidatesWithoutPoi(); +// static BlockStmt* findVisibleFunctionsAndCandidatesPoi(); - trimVisibleCandidates(info, mostApplicable, - numVisitedVis, visibleFns); +// Returns the POI scope used to find the candidates +void CandidateSearchState::findVisibleFunctionsAndCandidates() { + // CG TODO: pull all visible interface functions, if within a CG context - gatherCandidatesAndLastResort(info, visInfo, mostApplicable, numVisitedMA, - lrc, candidates); + BlockStmt* scopeUsed = nullptr; - // save the scope used for disambiguation - scopeUsed = visInfo.currStart; + do { + // CG TODO: no POI for CG functions - advanceCurrStart(visInfo); + searchOnePoiLevel(); // prevent infinite loop if (scopeUsed == visInfo.currStart) { @@ -5631,8 +5654,6 @@ static BlockStmt* findVisibleFunctionsAndCandidates( } explainGatherCandidate(info, candidates); - - return scopeUsed; } // run filterCandidate() on 'fn' if appropriate From a546b04c085ced2fd70127f682749a913c0e3e86 Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Fri, 23 Jan 2026 18:41:48 -0800 Subject: [PATCH 03/11] Reorder search such that POI follows forwarding Signed-off-by: Danila Fedorin --- compiler/resolution/functionResolution.cpp | 60 ++++++++++++++-------- 1 file changed, 38 insertions(+), 22 deletions(-) diff --git a/compiler/resolution/functionResolution.cpp b/compiler/resolution/functionResolution.cpp index 622f52ae32af..5f4f73fb62fb 100644 --- a/compiler/resolution/functionResolution.cpp +++ b/compiler/resolution/functionResolution.cpp @@ -3576,6 +3576,7 @@ struct CandidateSearchState { bool tryFindVisibileCandidatesForExplicitFn(); void searchOnePoiLevel(); void findVisibleFunctionsAndCandidates(); + void considerLastResortCandidates(); }; static int disambiguateByMatch(CallInfo& info, @@ -4319,17 +4320,18 @@ static FnSymbol* resolveNormalCall(CallInfo& info, check_state_t checkState, boo for others and don't consider POI */ considerPoi = false; } else { - searchState.findVisibleFunctionsAndCandidates(); + /* At this point, the top-level POI level is the regular scope of the call + (so it's not really POI). This was configured as part of searchState's + constructor. So, this brach is the non-POI candidate search, which + always happens. */ + searchState.searchOnePoiLevel(); } - numMatches = disambiguateByMatch(info, scopeUsed, candidates, - bestRef, bestCref, bestVal); - - if (checkState == CHECK_NORMAL_CALL && numMatches > 0 && visInfo.inPOI()) - updateCacheInfosForACall(visInfo, - bestRef, bestCref, bestVal); - - // If no candidates were found and it's a method, try forwarding + // If no non-POI candidates were found and it's a method, try forwarding. + // Forwarded methods are treated as if they were defined directly on the type, + // so they take precedence over POI candidates. This is crucial for correctness. + // + // See https://github.com/chapel-lang/chapel/issues/28246 bool forwardingEligible = candidates.n == 0 && info.call->numActuals() >= 1 && @@ -4338,30 +4340,44 @@ static FnSymbol* resolveNormalCall(CallInfo& info, check_state_t checkState, boo Type* receiverType; bool usesForwarding = false; - // For now, do not consider POI. This way, if/when we recurse, we first - // check all forwarding statements without POI, and only then go back - // to POI. This is crucial for correctness. See - // - // https://github.com/chapel-lang/chapel/issues/28246 + // While searching for forwarding candidates, do not consider _their_ POI. + // That's because we haven't looked at the POI candidates for the original type, + // and returning the impl type's POI candidates here would be strange. if (forwardingEligible) { receiverType = canonicalDecoratedClassType(info.call->get(2)->getValType()); if ((usesForwarding = typeUsesForwarding(receiverType))) { - FnSymbol* fn = resolveForwardedCall(info, checkState, /* conisiderPoi */ false); - if (fn) { + if (auto fn = resolveForwardedCall(info, checkState, /* conisiderPoi */ false)) { return fn; } - // otherwise error is printed below } } + // At this point, we have found no non-POI candidates, neither in the + // original type nor in any fields it forwards. Time to move on to POI. if (considerPoi) { - // TODO: consider POI + // Ok, no forwaring candidates found without POI. Now move on to + // our POI candidates. + if (candidates.n == 0 && visInfo.currStart != nullptr && scopeUsed != visInfo.currStart) { + searchState.findVisibleFunctionsAndCandidates(); + } + + // If we have not found any candidates after traversing all POIs, + // look at "last resort" candidates, if any. + if (candidates.n == 0) { + searchState.considerLastResortCandidates(); + } } + numMatches = disambiguateByMatch(info, scopeUsed, candidates, + bestRef, bestCref, bestVal); + + if (checkState == CHECK_NORMAL_CALL && numMatches > 0 && visInfo.inPOI()) + updateCacheInfosForACall(visInfo, + bestRef, bestCref, bestVal); + // Now, try forwarding again, this time considering POI if (candidates.n == 0 && forwardingEligible && usesForwarding && considerPoi) { - FnSymbol* fn = resolveForwardedCall(info, checkState, /* conisiderPoi */ true); - if (fn) { + if (auto fn = resolveForwardedCall(info, checkState, /* conisiderPoi */ true)) { return fn; } // otherwise error is printed below @@ -5639,9 +5655,9 @@ void CandidateSearchState::findVisibleFunctionsAndCandidates() { } while (candidates.n == 0 && visInfo.currStart != NULL); +} - // If we have not found any candidates after traversing all POIs, - // look at "last resort" candidates, if any. +void CandidateSearchState::considerLastResortCandidates() { if (candidates.n == 0 && haveAnyLRCs(lrc, visInfo.poiDepth)) { visInfo.poiDepth = -1; int numVisitedLRC = 0; From 102ec26167f76e20db6e207ff0fa418f811959d7 Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Wed, 28 Jan 2026 12:43:33 -0800 Subject: [PATCH 04/11] Fix bug in which POI consideration is not passed through Signed-off-by: Danila Fedorin --- compiler/resolution/functionResolution.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/resolution/functionResolution.cpp b/compiler/resolution/functionResolution.cpp index 5f4f73fb62fb..000f2b3d1d49 100644 --- a/compiler/resolution/functionResolution.cpp +++ b/compiler/resolution/functionResolution.cpp @@ -3003,7 +3003,7 @@ FnSymbol* tryResolveCall(CallExpr* call, bool checkWithin, bool considerPoi) { if (checkWithin) checkState = CHECK_BODY_RESOLVES; - return resolveNormalCall(call, checkState); + return resolveNormalCall(call, checkState, considerPoi); } static Type* resolveGenericActual(SymExpr* se, CallExpr* inCall, From ff1b9c4e406ccd8564ce9ec981a2602d56cd8eab Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Wed, 28 Jan 2026 12:54:56 -0800 Subject: [PATCH 05/11] Ensure candidates are explained always Signed-off-by: Danila Fedorin --- compiler/resolution/functionResolution.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/compiler/resolution/functionResolution.cpp b/compiler/resolution/functionResolution.cpp index 000f2b3d1d49..d49757da2ced 100644 --- a/compiler/resolution/functionResolution.cpp +++ b/compiler/resolution/functionResolution.cpp @@ -3577,6 +3577,7 @@ struct CandidateSearchState { void searchOnePoiLevel(); void findVisibleFunctionsAndCandidates(); void considerLastResortCandidates(); + void explainGatherCandidate(); }; static int disambiguateByMatch(CallInfo& info, @@ -4367,6 +4368,7 @@ static FnSymbol* resolveNormalCall(CallInfo& info, check_state_t checkState, boo searchState.considerLastResortCandidates(); } } + searchState.explainGatherCandidate(); numMatches = disambiguateByMatch(info, scopeUsed, candidates, bestRef, bestCref, bestVal); @@ -5604,8 +5606,6 @@ bool CandidateSearchState::tryFindVisibileCandidatesForExplicitFn() { // no need for trimVisibleCandidates() and findVisibleCandidates() gatherCandidates(info, visInfo, fn, candidates); - explainGatherCandidate(info, candidates); - scopeUsed = getVisibilityScope(call); return true; } @@ -5668,8 +5668,10 @@ void CandidateSearchState::considerLastResortCandidates() { while (candidates.n == 0 && haveMoreLRCs(lrc, numVisitedLRC)); } +} - explainGatherCandidate(info, candidates); +void CandidateSearchState::explainGatherCandidate() { + ::explainGatherCandidate(info, candidates); } // run filterCandidate() on 'fn' if appropriate From 29069a5a09be6b1bb49396d16a1a72a3966faab5 Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Wed, 28 Jan 2026 12:55:35 -0800 Subject: [PATCH 06/11] Remove "last resort" from (de)serializers Signed-off-by: Danila Fedorin --- compiler/passes/buildDefaultFunctions.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/compiler/passes/buildDefaultFunctions.cpp b/compiler/passes/buildDefaultFunctions.cpp index 508d2ba15f2c..a07352df7f6f 100644 --- a/compiler/passes/buildDefaultFunctions.cpp +++ b/compiler/passes/buildDefaultFunctions.cpp @@ -1743,7 +1743,6 @@ FnSymbol* buildSerializeFnSymbol(AggregateType* ct, ArgSymbol** filearg) { FnSymbol* fn = new FnSymbol("serialize"); fn->addFlag(FLAG_COMPILER_GENERATED); - fn->addFlag(FLAG_LAST_RESORT); if (ct->isClass() && ct != dtObject) { fn->addFlag(FLAG_OVERRIDE); } else { @@ -1788,7 +1787,6 @@ static FnSymbol* buildDeserializeFnSymbol(AggregateType* ct, ArgSymbol** filearg FnSymbol* fn = new FnSymbol("deserialize"); fn->addFlag(FLAG_COMPILER_GENERATED); - fn->addFlag(FLAG_LAST_RESORT); if (ct->isClass() && ct != dtObject) fn->addFlag(FLAG_OVERRIDE); else From 7b2037ba534cba77cf3237225b713923b47e1f68 Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Wed, 28 Jan 2026 13:45:20 -0800 Subject: [PATCH 07/11] Add current tests for POI + forwarding order Signed-off-by: Danila Fedorin --- .../forwarding/forwarding-poi-order.1-0.good | 3 + .../forwarding/forwarding-poi-order.2-0.good | 2 + .../forwarding/forwarding-poi-order.3-0.good | 1 + .../forwarding/forwarding-poi-order.4.good | 4 ++ .../forwarding/forwarding-poi-order.5-0.good | 2 + .../forwarding/forwarding-poi-order.6.good | 4 ++ .../forwarding/forwarding-poi-order.chpl | 62 +++++++++++++++++++ .../forwarding/forwarding-poi-order.compopts | 6 ++ 8 files changed, 84 insertions(+) create mode 100644 test/classes/forwarding/forwarding-poi-order.1-0.good create mode 100644 test/classes/forwarding/forwarding-poi-order.2-0.good create mode 100644 test/classes/forwarding/forwarding-poi-order.3-0.good create mode 100644 test/classes/forwarding/forwarding-poi-order.4.good create mode 100644 test/classes/forwarding/forwarding-poi-order.5-0.good create mode 100644 test/classes/forwarding/forwarding-poi-order.6.good create mode 100644 test/classes/forwarding/forwarding-poi-order.chpl create mode 100644 test/classes/forwarding/forwarding-poi-order.compopts diff --git a/test/classes/forwarding/forwarding-poi-order.1-0.good b/test/classes/forwarding/forwarding-poi-order.1-0.good new file mode 100644 index 000000000000..bda709ecfb47 --- /dev/null +++ b/test/classes/forwarding/forwarding-poi-order.1-0.good @@ -0,0 +1,3 @@ +42 +42 +42 diff --git a/test/classes/forwarding/forwarding-poi-order.2-0.good b/test/classes/forwarding/forwarding-poi-order.2-0.good new file mode 100644 index 000000000000..daaac9e30302 --- /dev/null +++ b/test/classes/forwarding/forwarding-poi-order.2-0.good @@ -0,0 +1,2 @@ +42 +42 diff --git a/test/classes/forwarding/forwarding-poi-order.3-0.good b/test/classes/forwarding/forwarding-poi-order.3-0.good new file mode 100644 index 000000000000..d81cc0710eb6 --- /dev/null +++ b/test/classes/forwarding/forwarding-poi-order.3-0.good @@ -0,0 +1 @@ +42 diff --git a/test/classes/forwarding/forwarding-poi-order.4.good b/test/classes/forwarding/forwarding-poi-order.4.good new file mode 100644 index 000000000000..29b4e22ea105 --- /dev/null +++ b/test/classes/forwarding/forwarding-poi-order.4.good @@ -0,0 +1,4 @@ +forwarding-poi-order.chpl:34: In function 'generic': +forwarding-poi-order.chpl:35: error: unresolved call 'Outermost.foo()' +forwarding-poi-order.chpl:35: note: because no functions named foo found in scope + forwarding-poi-order.chpl:40: called as generic(x: Outermost) diff --git a/test/classes/forwarding/forwarding-poi-order.5-0.good b/test/classes/forwarding/forwarding-poi-order.5-0.good new file mode 100644 index 000000000000..d8927df73390 --- /dev/null +++ b/test/classes/forwarding/forwarding-poi-order.5-0.good @@ -0,0 +1,2 @@ +Outer foo +Outer foo diff --git a/test/classes/forwarding/forwarding-poi-order.6.good b/test/classes/forwarding/forwarding-poi-order.6.good new file mode 100644 index 000000000000..30cc8d66d57b --- /dev/null +++ b/test/classes/forwarding/forwarding-poi-order.6.good @@ -0,0 +1,4 @@ +forwarding-poi-order.chpl:34: In function 'generic': +forwarding-poi-order.chpl:35: error: unresolved call 'Outermost.foo()' +forwarding-poi-order.chpl:35: note: because no functions named foo found in scope + forwarding-poi-order.chpl:53: called as generic(x: Outermost) diff --git a/test/classes/forwarding/forwarding-poi-order.chpl b/test/classes/forwarding/forwarding-poi-order.chpl new file mode 100644 index 000000000000..cb37674ecff3 --- /dev/null +++ b/test/classes/forwarding/forwarding-poi-order.chpl @@ -0,0 +1,62 @@ +module A { + config param enableInnerFoo = true; + + record Inner { + proc foo() where enableInnerFoo { + return 42; + } + } +} + +module B { + import A.Inner; + + record Outer { + forwarding var inner: Inner; + } +} + +module C { + import B.Outer; + + record Outermost { + forwarding var outer: Outer; + } +} + +module D { + import A.Inner; + import B.Outer; + import C.Outermost; + + config param startAtCase = 1; + + proc generic(x) { + writeln(x.foo()); + } + + proc case1() { + if startAtCase <= 1 { + generic(new Outermost()); + } + } + + proc case2() { + if startAtCase <= 2 { + proc Outer.foo() do return "Outer foo"; + generic(new Outermost()); + } + } + + proc case3() { + if startAtCase <= 3 { + generic(new Outermost()); + } + } + + proc main() { + case1(); + case2(); + case3(); + } +} diff --git a/test/classes/forwarding/forwarding-poi-order.compopts b/test/classes/forwarding/forwarding-poi-order.compopts new file mode 100644 index 000000000000..04cc48ed74c9 --- /dev/null +++ b/test/classes/forwarding/forwarding-poi-order.compopts @@ -0,0 +1,6 @@ +-sstartAtCase=1 +-sstartAtCase=2 +-sstartAtCase=3 +-sstartAtCase=1 -senableInnerFoo=false +-sstartAtCase=2 -senableInnerFoo=false +-sstartAtCase=3 -senableInnerFoo=false From 3d066273de286ec6e9279fe7f7c7ad69d3a9acaa Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Wed, 28 Jan 2026 15:54:40 -0800 Subject: [PATCH 08/11] Update generic cache even for speculative resolution Signed-off-by: Danila Fedorin --- compiler/resolution/functionResolution.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/resolution/functionResolution.cpp b/compiler/resolution/functionResolution.cpp index d49757da2ced..8f044e5faeb0 100644 --- a/compiler/resolution/functionResolution.cpp +++ b/compiler/resolution/functionResolution.cpp @@ -4373,7 +4373,7 @@ static FnSymbol* resolveNormalCall(CallInfo& info, check_state_t checkState, boo numMatches = disambiguateByMatch(info, scopeUsed, candidates, bestRef, bestCref, bestVal); - if (checkState == CHECK_NORMAL_CALL && numMatches > 0 && visInfo.inPOI()) + if (numMatches > 0 && visInfo.inPOI()) updateCacheInfosForACall(visInfo, bestRef, bestCref, bestVal); From 2b05947aa3c7452c21c50ea694a6a484f3733465 Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Wed, 28 Jan 2026 15:58:19 -0800 Subject: [PATCH 09/11] Update test with newly proper behavior Signed-off-by: Danila Fedorin --- test/classes/forwarding/forwarding-poi-order.5-0.good | 2 -- test/classes/forwarding/forwarding-poi-order.5.good | 4 ++++ 2 files changed, 4 insertions(+), 2 deletions(-) delete mode 100644 test/classes/forwarding/forwarding-poi-order.5-0.good create mode 100644 test/classes/forwarding/forwarding-poi-order.5.good diff --git a/test/classes/forwarding/forwarding-poi-order.5-0.good b/test/classes/forwarding/forwarding-poi-order.5-0.good deleted file mode 100644 index d8927df73390..000000000000 --- a/test/classes/forwarding/forwarding-poi-order.5-0.good +++ /dev/null @@ -1,2 +0,0 @@ -Outer foo -Outer foo diff --git a/test/classes/forwarding/forwarding-poi-order.5.good b/test/classes/forwarding/forwarding-poi-order.5.good new file mode 100644 index 000000000000..30cc8d66d57b --- /dev/null +++ b/test/classes/forwarding/forwarding-poi-order.5.good @@ -0,0 +1,4 @@ +forwarding-poi-order.chpl:34: In function 'generic': +forwarding-poi-order.chpl:35: error: unresolved call 'Outermost.foo()' +forwarding-poi-order.chpl:35: note: because no functions named foo found in scope + forwarding-poi-order.chpl:53: called as generic(x: Outermost) From c799d9bfbbf143b873bc9aa37358c9b9995044a8 Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Wed, 28 Jan 2026 16:01:39 -0800 Subject: [PATCH 10/11] Add test for non-forwarding case that was similarly broken Signed-off-by: Danila Fedorin --- .../Reflection/speculative-poi-cache.chpl | 20 +++++++++++++++++++ .../Reflection/speculative-poi-cache.good | 2 ++ 2 files changed, 22 insertions(+) create mode 100644 test/library/standard/Reflection/speculative-poi-cache.chpl create mode 100644 test/library/standard/Reflection/speculative-poi-cache.good diff --git a/test/library/standard/Reflection/speculative-poi-cache.chpl b/test/library/standard/Reflection/speculative-poi-cache.chpl new file mode 100644 index 000000000000..d25323ce6b83 --- /dev/null +++ b/test/library/standard/Reflection/speculative-poi-cache.chpl @@ -0,0 +1,20 @@ +record Outermost {} + +proc generic(x) { + use Reflection; + return canResolveMethod(x, "foo"); +} + +proc case1() { + proc Outermost.foo() do return "Outer foo"; + return generic(new Outermost()); +} + +proc case2() { + return generic(new Outermost()); +} + +proc main() { + writeln(case1()); + writeln(case2()); +} diff --git a/test/library/standard/Reflection/speculative-poi-cache.good b/test/library/standard/Reflection/speculative-poi-cache.good new file mode 100644 index 000000000000..da29283aaa47 --- /dev/null +++ b/test/library/standard/Reflection/speculative-poi-cache.good @@ -0,0 +1,2 @@ +true +false From 38499362d764fe6f75e1af129e471d1773be69e4 Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Wed, 28 Jan 2026 17:18:29 -0800 Subject: [PATCH 11/11] Avoid redundant re-computation while searching for forwards. Suppose there's a forwarding chain A -> B -> C. Previously, because only a 'considerPoi' flag was used, the search pattern was roughly like this: * Search for type A candidates (non-POI) * Search for type B candidates (non-POI) * Search tor type C candidates (non-POI) * Search for type A POI candidates * Search for type B candidates (non-POI, because POI search entails non-POI search) * Search for type A candidates (non-POI) * Search for type B POI candidates * Search for type A candidates (non-POI, because POI search entails non-POI search) * Search for Type A POI candidates Basically, because 'considerPoi' entailed a superset of work that '!considerPoi' did, we often duplicated effort. I suspect that this duplication is exponential in the length of the forwarding chain. To fix this, adjust 'considerPoi' to instead be tri-state: default (poi and non-poi), non-poi-only, and poi-only. This way, we can proceed as: * Search for type A candidates (non-POI) * Search for type B candidates (non-POI) * Search tor type C candidates (non-POI) * Search for type A POI candidates * Search for type B POI candidates (because POI-only is set) * Search for Type C POI candidates (because POI-only is set) This is exactly the search set we desire, without repetition. Signed-off-by: Danila Fedorin --- compiler/include/resolution.h | 8 ++- compiler/include/visibleFunctions.h | 1 + compiler/resolution/functionResolution.cpp | 61 +++++++++++++++------- compiler/resolution/visibleFunctions.cpp | 4 +- 4 files changed, 50 insertions(+), 24 deletions(-) diff --git a/compiler/include/resolution.h b/compiler/include/resolution.h index 2867970c0807..1c6af63fb5f0 100644 --- a/compiler/include/resolution.h +++ b/compiler/include/resolution.h @@ -257,7 +257,13 @@ void resolveCallAndCallee(CallExpr* call, bool allowUnresolved = false); Type* resolveDefaultGenericTypeSymExpr(SymExpr* se); Type* resolveTypeAlias(SymExpr* se); -FnSymbol* tryResolveCall(CallExpr* call, bool checkWithin=false, bool considerPoi=true); +enum class PoiSearchMode { + NORMAL, + NON_POI_ONLY, + POI_ONLY, +}; + +FnSymbol* tryResolveCall(CallExpr* call, bool checkWithin=false, PoiSearchMode poiMode = PoiSearchMode::NORMAL); void makeRefType(Type* type); // FnSymbol changes diff --git a/compiler/include/visibleFunctions.h b/compiler/include/visibleFunctions.h index 34fff95605f8..bb4d8f14f598 100644 --- a/compiler/include/visibleFunctions.h +++ b/compiler/include/visibleFunctions.h @@ -76,6 +76,7 @@ void getMoreVisibleFunctionsOrMethods(const char* name, void getVisibleFunctions(const char* name, CallExpr* call, Vec& visibleFns); +BlockStmt* getVisibleFnsInstantiationPt(BlockStmt* block); BlockStmt* getVisibilityScope(Expr* expr); BlockStmt* getInstantiationPoint(Expr* expr); diff --git a/compiler/resolution/functionResolution.cpp b/compiler/resolution/functionResolution.cpp index 8f044e5faeb0..d898b5c3306c 100644 --- a/compiler/resolution/functionResolution.cpp +++ b/compiler/resolution/functionResolution.cpp @@ -2992,18 +2992,18 @@ static void resolveRefDeserialization(CallExpr* call) { lhsSE->symbol()->type = typeSE->symbol()->getRefType(); } -static FnSymbol* resolveNormalCall(CallExpr* call, check_state_t checkState, bool considerPoi=true); +static FnSymbol* resolveNormalCall(CallExpr* call, check_state_t checkState, PoiSearchMode poiMode=PoiSearchMode::NORMAL); FnSymbol* resolveNormalCall(CallExpr* call) { return resolveNormalCall(call, CHECK_NORMAL_CALL); } -FnSymbol* tryResolveCall(CallExpr* call, bool checkWithin, bool considerPoi) { +FnSymbol* tryResolveCall(CallExpr* call, bool checkWithin, PoiSearchMode poiMode) { check_state_t checkState = CHECK_CALLABLE_ONLY; if (checkWithin) checkState = CHECK_BODY_RESOLVES; - return resolveNormalCall(call, checkState, considerPoi); + return resolveNormalCall(call, checkState, poiMode); } static Type* resolveGenericActual(SymExpr* se, CallExpr* inCall, @@ -3535,8 +3535,8 @@ using LastResortCandidates = std::vector; static bool isGenericRecordInit(CallExpr* call); -static FnSymbol* resolveNormalCall(CallInfo& info, check_state_t checkState, bool considerPoi = true); -static FnSymbol* resolveNormalCall(CallExpr* call, check_state_t checkState, bool considerPoi); +static FnSymbol* resolveNormalCall(CallInfo& info, check_state_t checkState, PoiSearchMode poiMode = PoiSearchMode::NORMAL); +static FnSymbol* resolveNormalCall(CallExpr* call, check_state_t checkState, PoiSearchMode poiMode); // State for candidate search. Tracks seen, most applicable, etc. candidates, // and other information like the current POI scope. @@ -3575,6 +3575,7 @@ struct CandidateSearchState { bool tryFindVisibileCandidatesForExplicitFn(); void searchOnePoiLevel(); + void skipOnePoiLevel(); void findVisibleFunctionsAndCandidates(); void considerLastResortCandidates(); void explainGatherCandidate(); @@ -4034,7 +4035,7 @@ static void maybeWarnGenericActuals(CallExpr* call) { } static -FnSymbol* resolveNormalCall(CallExpr* call, check_state_t checkState, bool considerPoi) { +FnSymbol* resolveNormalCall(CallExpr* call, check_state_t checkState, PoiSearchMode poiMode) { CallInfo info; FnSymbol* retval = NULL; @@ -4060,7 +4061,7 @@ FnSymbol* resolveNormalCall(CallExpr* call, check_state_t checkState, bool consi if (isTypeConstructionCall(call)) { resolveTypeSpecifier(info); } else { - retval = resolveNormalCall(info, checkState, considerPoi); + retval = resolveNormalCall(info, checkState, poiMode); } } else if (checkState != CHECK_NORMAL_CALL) { @@ -4298,10 +4299,10 @@ static bool overloadSetsOK(CallExpr* call, } -static FnSymbol* resolveForwardedCall(CallInfo& info, check_state_t checkState, bool considerPoi = true); +static FnSymbol* resolveForwardedCall(CallInfo& info, check_state_t checkState, PoiSearchMode poiMode = PoiSearchMode::NORMAL); static bool typeUsesForwarding(Type* t); -static FnSymbol* resolveNormalCall(CallInfo& info, check_state_t checkState, bool considerPoi) { +static FnSymbol* resolveNormalCall(CallInfo& info, check_state_t checkState, PoiSearchMode poiMode) { ResolutionCandidate* bestRef = NULL; ResolutionCandidate* bestCref = NULL; ResolutionCandidate* bestVal = NULL; @@ -4316,10 +4317,21 @@ static FnSymbol* resolveNormalCall(CallInfo& info, check_state_t checkState, boo auto& candidates = searchState.candidates; auto& scopeUsed = searchState.scopeUsed; + bool considerNonPoi = (poiMode != PoiSearchMode::POI_ONLY); + bool considerPoi = (poiMode != PoiSearchMode::NON_POI_ONLY); + + if (auto use = toUnresolvedSymExpr(info.call->baseExpr)) { + if (strcmp(use->unresolved, "foo") == 0) debuggerBreakHere(); + } + if (searchState.tryFindVisibileCandidatesForExplicitFn()) { /* the function was explicitly specified via FnSymbol*. Don't search for others and don't consider POI */ - considerPoi = false; + poiMode = PoiSearchMode::NON_POI_ONLY; + } else if (!considerNonPoi) { + /* This function was previously used to search for non-POI, and now, it's + being used to search for only POI. Skip past the non-POI scope. */ + searchState.skipOnePoiLevel(); } else { /* At this point, the top-level POI level is the regular scope of the call (so it's not really POI). This was configured as part of searchState's @@ -4347,8 +4359,10 @@ static FnSymbol* resolveNormalCall(CallInfo& info, check_state_t checkState, boo if (forwardingEligible) { receiverType = canonicalDecoratedClassType(info.call->get(2)->getValType()); if ((usesForwarding = typeUsesForwarding(receiverType))) { - if (auto fn = resolveForwardedCall(info, checkState, /* conisiderPoi */ false)) { - return fn; + if (considerNonPoi) { + if (auto fn = resolveForwardedCall(info, checkState, PoiSearchMode::NON_POI_ONLY)) { + return fn; + } } } } @@ -4379,7 +4393,7 @@ static FnSymbol* resolveNormalCall(CallInfo& info, check_state_t checkState, boo // Now, try forwarding again, this time considering POI if (candidates.n == 0 && forwardingEligible && usesForwarding && considerPoi) { - if (auto fn = resolveForwardedCall(info, checkState, /* conisiderPoi */ true)) { + if (auto fn = resolveForwardedCall(info, checkState, PoiSearchMode::POI_ONLY)) { return fn; } // otherwise error is printed below @@ -5634,8 +5648,15 @@ void CandidateSearchState::searchOnePoiLevel() { advanceCurrStart(visInfo); } -// static BlockStmt* findVisibleFunctionsAndCandidatesWithoutPoi(); -// static BlockStmt* findVisibleFunctionsAndCandidatesPoi(); + +void CandidateSearchState::skipOnePoiLevel() { + visInfo.poiDepth++; + scopeUsed = visInfo.currStart; + visInfo.nextPOI = getVisibleFnsInstantiationPt(scopeUsed); + visInfo.visitedScopes.push_back(scopeUsed); + visited.insert(scopeUsed); + advanceCurrStart(visInfo); +} // Returns the POI scope used to find the candidates void CandidateSearchState::findVisibleFunctionsAndCandidates() { @@ -5818,7 +5839,7 @@ static const char* getForwardedMethodName(const char* calledName, return methodName; } -static FnSymbol* adjustAndResolveForwardedCall(CallExpr* call, ForwardingStmt* delegate, const char* methodName, bool considerPoi) { +static FnSymbol* adjustAndResolveForwardedCall(CallExpr* call, ForwardingStmt* delegate, const char* methodName, PoiSearchMode poiMode) { FnSymbol* ret = NULL; const char* fnGetTgt = delegate->fnReturningForwarding; @@ -5860,7 +5881,7 @@ static FnSymbol* adjustAndResolveForwardedCall(CallExpr* call, ForwardingStmt* d } resolveCall(setTgt); - ret = tryResolveCall(call, /* checkWithin */ false, considerPoi); + ret = tryResolveCall(call, /* checkWithin */ false, poiMode); } return ret; @@ -5869,7 +5890,7 @@ static FnSymbol* adjustAndResolveForwardedCall(CallExpr* call, ForwardingStmt* d llvm::SmallVector, 4> forwardCallCycleSet; // Returns a relevant FnSymbol if it worked -static FnSymbol* resolveForwardedCall(CallInfo& info, check_state_t checkState, bool considerPoi) { +static FnSymbol* resolveForwardedCall(CallInfo& info, check_state_t checkState, PoiSearchMode poiMode) { CallExpr* call = info.call; const char* calledName = astr(info.name); const char* inFnName = astr(call->getFunction()->name); @@ -5951,7 +5972,7 @@ static FnSymbol* resolveForwardedCall(CallInfo& info, check_state_t checkState, BlockStmt* block = new BlockStmt(forwardedCall, BLOCK_SCOPELESS); call->getStmtExpr()->insertBefore(block); - auto fn = adjustAndResolveForwardedCall(forwardedCall, delegate, methodName, considerPoi); + auto fn = adjustAndResolveForwardedCall(forwardedCall, delegate, methodName, poiMode); if (fn) { if (bestFn == NULL) { bestFn = fn; @@ -5983,7 +6004,7 @@ static FnSymbol* resolveForwardedCall(CallInfo& info, check_state_t checkState, const char* methodName = getForwardedMethodName(calledName, bestDelegate); INT_ASSERT(methodName); - bestFn = adjustAndResolveForwardedCall(call, bestDelegate, methodName, considerPoi); + bestFn = adjustAndResolveForwardedCall(call, bestDelegate, methodName, poiMode); } else { // Replace actuals in call with those from bestCall // Note that the above path could be used instead, but diff --git a/compiler/resolution/visibleFunctions.cpp b/compiler/resolution/visibleFunctions.cpp index e4c22fd9567b..2da24ffb6511 100644 --- a/compiler/resolution/visibleFunctions.cpp +++ b/compiler/resolution/visibleFunctions.cpp @@ -411,8 +411,6 @@ static void lookAtTypeFirst(const char* name, CallExpr* call, BlockStmt* block, PtrSet& visited, Vec& visibleFns); -static BlockStmt* getVisibleFnsInstantiationPt(BlockStmt* block); - static void getVisibleFnsShowBlock(const char* context, BlockStmt* block, BlockStmt* instantiationPt); @@ -1039,7 +1037,7 @@ void getVisibleFunctions(const char* name, visited, visibleFns, false); } -static BlockStmt* getVisibleFnsInstantiationPt(BlockStmt* block) { +BlockStmt* getVisibleFnsInstantiationPt(BlockStmt* block) { BlockStmt* instantiationPt = NULL; // We check for an instantiation point only at FnSymbols'