mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-04-21 22:11:40 +07:00
new inference: collect during inference substitutor from inference variables and replace them with type parameters at the very end, excluding foreign variables so e.g. no essential dependency would get overridden by type parameter from sibling call (IDEA-140387)
This commit is contained in:
@@ -264,7 +264,7 @@ public class InferenceSession {
|
||||
if (parameters != null && args != null) {
|
||||
final Set<ConstraintFormula> additionalConstraints = new LinkedHashSet<ConstraintFormula>();
|
||||
if (parameters.length > 0) {
|
||||
collectAdditionalConstraints(parameters, args, properties.getMethod(), PsiSubstitutor.EMPTY, additionalConstraints, properties.isVarargs());
|
||||
collectAdditionalConstraints(parameters, args, properties.getMethod(), mySiteSubstitutor, additionalConstraints, properties.isVarargs());
|
||||
}
|
||||
|
||||
if (!additionalConstraints.isEmpty() && !proceedWithAdditionalConstraints(additionalConstraints)) {
|
||||
@@ -278,9 +278,22 @@ public class InferenceSession {
|
||||
if (myContext != null) {
|
||||
myContext.putUserData(ERASED, myErased);
|
||||
}
|
||||
mySiteSubstitutor = mySiteSubstitutor.putAll(substitutor);
|
||||
for (InferenceVariable variable : myInferenceVariables) {
|
||||
variable.setInstantiation(substitutor.substitute(variable.getParameter()));
|
||||
final Map<PsiTypeParameter, PsiType> map = substitutor.getSubstitutionMap();
|
||||
for (PsiTypeParameter parameter : map.keySet()) {
|
||||
final PsiType mapping = map.get(parameter);
|
||||
PsiTypeParameter param;
|
||||
if (parameter instanceof InferenceVariable) {
|
||||
((InferenceVariable)parameter).setInstantiation(mapping);
|
||||
if (((InferenceVariable)parameter).getCallContext() != myContext) {
|
||||
//don't include in result substitutor foreign inference variables
|
||||
continue;
|
||||
}
|
||||
param = ((InferenceVariable)parameter).getParameter();
|
||||
}
|
||||
else {
|
||||
param = parameter;
|
||||
}
|
||||
mySiteSubstitutor = mySiteSubstitutor.put(param, mapping);
|
||||
}
|
||||
} else {
|
||||
return prepareSubstitution();
|
||||
@@ -805,19 +818,15 @@ public class InferenceSession {
|
||||
for (InferenceVariable dependency : dependencies) {
|
||||
PsiType instantiation = dependency.getInstantiation();
|
||||
if (instantiation != PsiType.NULL) {
|
||||
substitutor = substitutor.put(dependency.getParameter(), instantiation);
|
||||
substitutor = substitutor.put(dependency, instantiation);
|
||||
}
|
||||
}
|
||||
return substitutor.substitute(bound);
|
||||
}
|
||||
|
||||
private boolean hasBoundProblems(final List<InferenceVariable> typeParams,
|
||||
final PsiSubstitutor psiSubstitutor,
|
||||
final PsiSubstitutor substitutor) {
|
||||
for (InferenceVariable typeParameter : typeParams) {
|
||||
if (isForeignVariable(psiSubstitutor, typeParameter)) {
|
||||
continue;
|
||||
}
|
||||
final List<PsiType> extendsTypes = typeParameter.getBounds(InferenceBound.UPPER);
|
||||
final PsiType[] bounds = extendsTypes.toArray(new PsiType[extendsTypes.size()]);
|
||||
if (GenericsUtil.findTypeParameterBoundError(typeParameter, bounds, substitutor, myContext, true) != null) {
|
||||
@@ -827,36 +836,19 @@ public class InferenceSession {
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isForeignVariable(PsiSubstitutor fullSubstitutor,
|
||||
InferenceVariable typeParameter) {
|
||||
return fullSubstitutor.putAll(mySiteSubstitutor).getSubstitutionMap().containsKey(typeParameter.getParameter()) &&
|
||||
typeParameter.getCallContext() != myContext;
|
||||
}
|
||||
|
||||
private PsiSubstitutor resolveBounds(final Collection<InferenceVariable> inferenceVariables,
|
||||
PsiSubstitutor substitutor) {
|
||||
final Collection<InferenceVariable> allVars = new ArrayList<InferenceVariable>(inferenceVariables);
|
||||
final Map<InferenceVariable, PsiType> foreignMap = new LinkedHashMap<InferenceVariable, PsiType>();
|
||||
while (!allVars.isEmpty()) {
|
||||
final List<InferenceVariable> vars = InferenceVariablesOrder.resolveOrder(allVars, this);
|
||||
if (!myIncorporationPhase.hasCaptureConstraints(vars)) {
|
||||
PsiSubstitutor firstSubstitutor = resolveSubset(vars, substitutor, foreignMap);
|
||||
if (firstSubstitutor != null) {
|
||||
if (hasBoundProblems(vars, substitutor, firstSubstitutor)) {
|
||||
firstSubstitutor = null;
|
||||
}
|
||||
PsiSubstitutor firstSubstitutor = resolveSubset(vars, substitutor);
|
||||
if (firstSubstitutor != null && hasBoundProblems(vars, firstSubstitutor)) {
|
||||
firstSubstitutor = null;
|
||||
}
|
||||
if (firstSubstitutor != null) {
|
||||
substitutor = firstSubstitutor;
|
||||
allVars.removeAll(vars);
|
||||
|
||||
for (InferenceVariable var : vars) {
|
||||
PsiType type = foreignMap.get(var);
|
||||
if (type != null) {
|
||||
var.setInstantiation(type);
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -924,29 +916,11 @@ public class InferenceSession {
|
||||
}
|
||||
|
||||
private PsiSubstitutor resolveSubset(Collection<InferenceVariable> vars, PsiSubstitutor substitutor) {
|
||||
return resolveSubset(vars, substitutor, null);
|
||||
}
|
||||
|
||||
private PsiSubstitutor resolveSubset(Collection<InferenceVariable> vars,
|
||||
PsiSubstitutor substitutor,
|
||||
Map<InferenceVariable, PsiType> foreignMap) {
|
||||
for (InferenceVariable var : vars) {
|
||||
LOG.assertTrue(var.getInstantiation() == PsiType.NULL);
|
||||
final PsiTypeParameter typeParameter = var.getParameter();
|
||||
|
||||
final PsiType type = checkBoundsConsistency(substitutor, var);
|
||||
if (type != PsiType.NULL) {
|
||||
if (foreignMap != null) {
|
||||
//save all instantiations in a map where inference variables are not merged by type parameters
|
||||
//for same method called with different args resulting in different inferred types
|
||||
foreignMap.put(var, type);
|
||||
}
|
||||
|
||||
if (isForeignVariable(substitutor, var)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
substitutor = substitutor.put(typeParameter, type);
|
||||
substitutor = substitutor.put(var, type);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -978,7 +952,6 @@ public class InferenceSession {
|
||||
type = PsiType.getJavaLangRuntimeException(myManager, GlobalSearchScope.allScope(myManager.getProject()));
|
||||
}
|
||||
else {
|
||||
if (substitutor.putAll(mySiteSubstitutor).getSubstitutionMap().get(var.getParameter()) != null) return PsiType.NULL;
|
||||
type = myErased ? null : upperBound;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,10 +126,6 @@ public class MethodReferenceResolver implements ResolveCache.PolyVariantContextR
|
||||
}
|
||||
|
||||
if (includeReturnConstraint && interfaceMethodReturnType != PsiType.VOID && interfaceMethodReturnType != null) {
|
||||
if (method.isConstructor()) {
|
||||
//todo
|
||||
session.initBounds(reference, method.getContainingClass().getTypeParameters());
|
||||
}
|
||||
final PsiType returnType = method.isConstructor() ? composeReturnType(containingClass, substitutor) : method.getReturnType();
|
||||
if (returnType != null) {
|
||||
session.registerReturnTypeConstraints(returnType, interfaceMethodReturnType);
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
import java.util.*;
|
||||
|
||||
abstract class Test {
|
||||
{
|
||||
hasEntry(equalTo("parentId"), equalTo(1));
|
||||
}
|
||||
|
||||
public abstract <T> List<T> equalTo(T operand);
|
||||
public abstract <K, V> void hasEntry(List<? super K> keyMatcher, List<? super V> valueMatcher);
|
||||
}
|
||||
@@ -49,7 +49,7 @@ class MyTestConstructor {
|
||||
private static void <warning descr="Private method 'foo(MyTestConstructor.I3)' is never used">foo</warning>(I3 i) {System.out.println(i);}
|
||||
|
||||
static {
|
||||
foo<error descr="Cannot resolve method 'foo(<method reference>)'">(Foo::new)</error>;
|
||||
foo<error descr="Ambiguous method call: both 'MyTestConstructor.foo(I1)' and 'MyTestConstructor.foo(I2)' match">(Foo::new)</error>;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -39,6 +39,10 @@ public class Java8ExpressionsCheckTest extends LightDaemonAnalyzerTestCase {
|
||||
doTestAllMethodCallExpressions();
|
||||
}
|
||||
|
||||
public void testInfinitiveParameterBoundsCheck() throws Exception {
|
||||
doTestAllMethodCallExpressions();
|
||||
}
|
||||
|
||||
private void doTestAllMethodCallExpressions() {
|
||||
configureByFile(BASE_PATH + "/" + getTestName(false) + ".java");
|
||||
final Collection<PsiCallExpression> methodCallExpressions = PsiTreeUtil.findChildrenOfType(getFile(), PsiCallExpression.class);
|
||||
|
||||
Reference in New Issue
Block a user