Merge pull request #16261 from vasslitvinov/poi-generic-caching
Make caching of generic instantiations POI-aware
Implements #15923 for non-method functions.
Resolves the .future test from #6252:
The compiler now performs a test whether a cached generic instantiation
created for one call is applicable for another call that resolves to
the same generic function. Semantically, the guiding principle is
that it should work the same as if no instantiations are cached.
WHAT IS BEING TESTED - details
Let F be the generic function and FI be its instantiation at hand.
While resolving FI body for the first call, we gather
The applicability test for another call to F checks the scopes visible
from that call and its POI(s) against that GenericsCacheInfo.
Intuitively, the test imitates resolution of FI body for the other call. If
the test passes, the resolution outcomes for the other call would be the
same as they were for the first call. Therefore reusing FI for the other
call is appropriate.
Since #16158, the resolution outcomes will be the same when the target
function is visible from the scope where F is defined. Therefore
GenericsCacheInfo records information only for resolution targets visible
from FI’s point(s) of instantiation (POIs) and not from F’s scope.
This test is performed only when the values of the generic arguments are the
same for both calls. This precondition has already been in place and is
unaffected by this PR.
(A) GATHERING GenericsCacheInfo
A GenericsCacheInfo is a set of
Each call in FI body contributes a CalledFunInfo entry that describes its
resolution target, provided the target is not visible from the call’s
lexical scope. The entry contains:
- the name of the target function
- the scope where it is declared
- the set of scopes visited when gathering visible functions for the call
GenericsCacheInfo for FI also includes CalledFunInfo entries for the
functions called from FI body for which FI serves as POI. The entries where
the target function is visible from the FI’s definition scope are excluded.
(B) CHECKING AGAINST GenericsCacheInfo
Upon another call to F, where FI is considered for reuse, we check each of
its CalledFunInfo entries:
- Traverse the scopes visible from the call and its POI, in the order they
are traversed while gathering visible candidates. For each scope:
If the scope matches the declaration scope from the CalledFunInfo,
checking is complete, the test passes.
If the scope is not in CalledFunInfo’s set of visited scopes, it means
that it was not considered while resolving the corresponding call in
FI. So we do not know if it contains function(s) that would be better
candidate(s) and lead to a different resolution outcome. As a
conservative approximation, check that scope for definitions of any
functions with CalledFunInfo’s name. If any are present, checking is
complete, the test fails.
- If all scopes have been visited and CalledFunInfo’s declaration scope has
not been encountered, it means that the resolution target used in FI is
not available this time. So the resolution outcome of the corresponding
call in FI will be different this time. The test fails.
On chapcs7, seconds, before/after this PR
hello 5.16 / 5.18
SSCA2 33.66 / 33.70
- resolve 148 / 152
- make binary 433 / 433
- total 685 / 690
Rename an overload of findVisibleFunctions to findVisibleFunctionsAllPOIs
and instantiate -> instantiateWithoutCall, for better grepping.
Remove parts of the comment for filterInitCandidate that are
either incorrect or obvious.
Additional instrumentation was present earlier in e41d4a56d5…ff67f3a58d
The previous implementation of this strategy was in 6e813eac1b…dffe8da574