java overload resolution: reuse computed getSubstitutor(false); use cache for method references

GitOrigin-RevId: abd73c52013d4924fa66fabdfa67bcba597279f5
This commit is contained in:
Anna Kozlova
2020-10-06 06:44:41 +00:00
committed by intellij-monorepo-bot
parent b6d5ec0315
commit 308e4f7daf
3 changed files with 41 additions and 17 deletions
@@ -20,8 +20,10 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.Supplier;
import java.util.stream.Collectors;
/**
@@ -107,9 +109,17 @@ public class MethodCandidateInfo extends CandidateInfo{
@ApplicabilityLevelConstant
public int getPertinentApplicabilityLevel() {
return getPertinentApplicabilityLevel(null);
}
/**
* @param map reuse substitutor from conflict resolver cache when available
*/
@ApplicabilityLevelConstant
public int getPertinentApplicabilityLevel(@Nullable Map<MethodCandidateInfo, PsiSubstitutor> map) {
int result = myPertinentApplicabilityLevel;
if (result == 0) {
myPertinentApplicabilityLevel = result = getPertinentApplicabilityLevelInner();
myPertinentApplicabilityLevel = result = getPertinentApplicabilityLevelInner(() -> map != null ? map.get(this) : getSubstitutor(false));
}
return result;
}
@@ -118,7 +128,7 @@ public class MethodCandidateInfo extends CandidateInfo{
* 15.12.2.2 Identify Matching Arity Methods Applicable by Strict Invocation
*/
@ApplicabilityLevelConstant
private int getPertinentApplicabilityLevelInner() {
private int getPertinentApplicabilityLevelInner(Supplier<PsiSubstitutor> substitutorSupplier) {
if (myArgumentList == null || !myLanguageLevel.isAtLeast(LanguageLevel.JDK_1_8)) {
return getApplicabilityLevel();
}
@@ -127,7 +137,7 @@ public class MethodCandidateInfo extends CandidateInfo{
if (isToInferApplicability()) {
//ensure applicability check is performed
getSubstitutor(false);
substitutorSupplier.get();
//already performed checks, so if inference failed, error message should be saved
if (myApplicabilityError || isPotentiallyCompatible() != ThreeState.YES) {
@@ -136,7 +146,7 @@ public class MethodCandidateInfo extends CandidateInfo{
return isVarargs() ? ApplicabilityLevel.VARARGS : ApplicabilityLevel.FIXED_ARITY;
}
final PsiSubstitutor substitutor = getSubstitutor(false);
final PsiSubstitutor substitutor = substitutorSupplier.get();
final Computable<Integer> computable = () -> computeWithKnownTargetType(() -> {
//arg types are calculated here without additional constraints:
//non-pertinent to applicability arguments of arguments would be skipped
@@ -19,11 +19,13 @@ import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.psi.util.TypeConversionUtil;
import com.intellij.util.SmartList;
import com.intellij.util.containers.FactoryMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
public class MethodReferenceResolver implements ResolveCache.PolyVariantContextResolver<PsiMethodReferenceExpressionImpl> {
@@ -208,7 +210,8 @@ public class MethodReferenceResolver implements ResolveCache.PolyVariantContextR
}
@Override
protected int getPertinentApplicabilityLevel(@NotNull MethodCandidateInfo conflict) {
protected int getPertinentApplicabilityLevel(@NotNull MethodCandidateInfo conflict,
Map<MethodCandidateInfo, PsiSubstitutor> map) {
return conflict.isVarargs() ? MethodCandidateInfo.ApplicabilityLevel.VARARGS : MethodCandidateInfo.ApplicabilityLevel.FIXED_ARITY;
}
@@ -219,8 +222,9 @@ public class MethodReferenceResolver implements ResolveCache.PolyVariantContextR
if (conflicts.isEmpty()) return null;
if (conflicts.size() == 1) return conflicts.get(0);
final Map<MethodCandidateInfo, PsiSubstitutor> map = FactoryMap.create(key -> key.getSubstitutor(false));
checkSameSignatures(conflicts);
checkSameSignatures(conflicts, map);
if (conflicts.size() == 1) return conflicts.get(0);
checkAccessStaticLevels(conflicts, true);
@@ -254,12 +258,12 @@ public class MethodReferenceResolver implements ResolveCache.PolyVariantContextR
}
}
CandidateInfo candidateInfo = resolveConflicts(firstCandidates, secondCandidates, MethodCandidateInfo.ApplicabilityLevel.FIXED_ARITY);
CandidateInfo candidateInfo = resolveConflicts(firstCandidates, secondCandidates, map, MethodCandidateInfo.ApplicabilityLevel.FIXED_ARITY);
if (candidateInfo != null) {
return candidateInfo;
}
candidateInfo = resolveConflicts(firstCandidates, secondCandidates, MethodCandidateInfo.ApplicabilityLevel.VARARGS);
candidateInfo = resolveConflicts(firstCandidates, secondCandidates, map, MethodCandidateInfo.ApplicabilityLevel.VARARGS);
if (candidateInfo != null) {
return candidateInfo;
}
@@ -346,12 +350,15 @@ public class MethodReferenceResolver implements ResolveCache.PolyVariantContextR
}
}
private CandidateInfo resolveConflicts(@NotNull List<CandidateInfo> firstCandidates, @NotNull List<CandidateInfo> secondCandidates, int applicabilityLevel) {
private CandidateInfo resolveConflicts(@NotNull List<CandidateInfo> firstCandidates,
@NotNull List<CandidateInfo> secondCandidates,
Map<MethodCandidateInfo, PsiSubstitutor> map,
int applicabilityLevel) {
int firstApplicability = checkApplicability(firstCandidates);
checkSpecifics(firstCandidates, applicabilityLevel);
checkSpecifics(firstCandidates, applicabilityLevel, map, 0);
int secondApplicability = checkApplicability(secondCandidates);
checkSpecifics(secondCandidates, applicabilityLevel, null, 1);
checkSpecifics(secondCandidates, applicabilityLevel, map, 1);
if (firstApplicability < secondApplicability) {
return secondCandidates.size() == 1 ? secondCandidates.get(0) : null;
@@ -81,7 +81,7 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{
if (conflicts.size() == 1) return conflicts.get(0);
}
final int applicabilityLevel = checkApplicability(conflicts);
final int applicabilityLevel = checkApplicability(conflicts, map);
if (conflicts.size() == 1) return conflicts.get(0);
// makes no sense to do further checks, because if no one candidate matches by parameters count
@@ -186,7 +186,7 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{
checkSameSignatures(conflicts, null);
}
private void checkSameSignatures(@NotNull List<? extends CandidateInfo> conflicts, Map<MethodCandidateInfo, PsiSubstitutor> map) {
protected void checkSameSignatures(@NotNull List<? extends CandidateInfo> conflicts, Map<MethodCandidateInfo, PsiSubstitutor> map) {
// candidates should go in order of class hierarchy traversal
// in order for this to work
Map<MethodSignature, CandidateInfo> signatures = new THashMap<>(conflicts.size());
@@ -364,11 +364,17 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{
@MethodCandidateInfo.ApplicabilityLevelConstant
public int checkApplicability(@NotNull List<CandidateInfo> conflicts) {
return checkApplicability(conflicts, null);
}
@MethodCandidateInfo.ApplicabilityLevelConstant
public int checkApplicability(@NotNull List<CandidateInfo> conflicts,
Map<MethodCandidateInfo, PsiSubstitutor> map) {
@MethodCandidateInfo.ApplicabilityLevelConstant int maxApplicabilityLevel = 0;
boolean toFilter = false;
for (CandidateInfo conflict : conflicts) {
ProgressManager.checkCanceled();
@MethodCandidateInfo.ApplicabilityLevelConstant final int level = getPertinentApplicabilityLevel((MethodCandidateInfo)conflict);
@MethodCandidateInfo.ApplicabilityLevelConstant final int level = getPertinentApplicabilityLevel((MethodCandidateInfo)conflict, map);
if (maxApplicabilityLevel > 0 && maxApplicabilityLevel != level) {
toFilter = true;
}
@@ -381,7 +387,7 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{
for (Iterator<CandidateInfo> iterator = conflicts.iterator(); iterator.hasNext();) {
ProgressManager.checkCanceled();
CandidateInfo info = iterator.next();
final int level = getPertinentApplicabilityLevel((MethodCandidateInfo)info);
final int level = getPertinentApplicabilityLevel((MethodCandidateInfo)info, map);
if (level < maxApplicabilityLevel) {
iterator.remove();
}
@@ -391,8 +397,9 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{
return maxApplicabilityLevel;
}
protected int getPertinentApplicabilityLevel(@NotNull MethodCandidateInfo conflict) {
return conflict.getPertinentApplicabilityLevel();
protected int getPertinentApplicabilityLevel(@NotNull MethodCandidateInfo conflict,
Map<MethodCandidateInfo, PsiSubstitutor> map) {
return conflict.getPertinentApplicabilityLevel(map);
}
private static int getCheckAccessLevel(@NotNull MethodCandidateInfo method){