mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-05-06 05:10:22 +07:00
new inference: proceed nested calls of the same method with dependencies between inference variables from different calls (IDEA-136716; IDEA-135286)
This commit is contained in:
@@ -284,7 +284,7 @@ public class InferenceSession {
|
||||
variable.setInstantiation(substitutor.substitute(variable.getParameter()));
|
||||
}
|
||||
} else {
|
||||
return resolveSubset(myInferenceVariables, mySiteSubstitutor);
|
||||
return prepareSubstitution();
|
||||
}
|
||||
|
||||
return prepareSubstitution();
|
||||
@@ -774,7 +774,17 @@ public class InferenceSession {
|
||||
}
|
||||
|
||||
private PsiType substituteNonProperBound(PsiType bound, PsiSubstitutor substitutor) {
|
||||
return isProperType(bound) ? bound : substitutor.substitute(bound);
|
||||
final HashSet<InferenceVariable> dependencies = new LinkedHashSet<InferenceVariable>();
|
||||
if (!collectDependencies(bound, dependencies)) {
|
||||
return bound;
|
||||
}
|
||||
for (InferenceVariable dependency : dependencies) {
|
||||
PsiType instantiation = dependency.getInstantiation();
|
||||
if (instantiation != PsiType.NULL) {
|
||||
substitutor = substitutor.put(dependency.getParameter(), instantiation);
|
||||
}
|
||||
}
|
||||
return substitutor.substitute(bound);
|
||||
}
|
||||
|
||||
private static boolean hasBoundProblems(final List<InferenceVariable> typeParams,
|
||||
@@ -796,10 +806,11 @@ public class InferenceSession {
|
||||
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);
|
||||
PsiSubstitutor firstSubstitutor = resolveSubset(vars, substitutor, foreignMap);
|
||||
if (firstSubstitutor != null) {
|
||||
if (hasBoundProblems(vars, firstSubstitutor, myContext)) {
|
||||
firstSubstitutor = null;
|
||||
@@ -808,6 +819,14 @@ public class InferenceSession {
|
||||
if (firstSubstitutor != null) {
|
||||
substitutor = firstSubstitutor;
|
||||
allVars.removeAll(vars);
|
||||
|
||||
for (InferenceVariable var : vars) {
|
||||
PsiType type = foreignMap.get(var);
|
||||
if (type != null) {
|
||||
var.setInstantiation(type);
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -875,15 +894,28 @@ 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();
|
||||
if (substitutor.putAll(mySiteSubstitutor).getSubstitutionMap().containsKey(typeParameter) && var.getCallContext() != myContext) {
|
||||
continue;//todo
|
||||
}
|
||||
|
||||
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 (substitutor.putAll(mySiteSubstitutor).getSubstitutionMap().containsKey(typeParameter) && var.getCallContext() != myContext) {
|
||||
continue;
|
||||
}
|
||||
|
||||
substitutor = substitutor.put(typeParameter, type);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ class SortTest<R extends Comparable<R>> implements Comparable<SortTest<R>> {
|
||||
list.add(t1);
|
||||
SortTest<?> t2 = new SortTest<Integer>(0);
|
||||
list.add(t2);
|
||||
<error descr="Inferred type 'java.lang.Object' for type parameter 'T' is not within its bound; should implement 'java.lang.Comparable<? super java.lang.Object>'">Collections.sort(list)</error>;
|
||||
Collections.sort<error descr="'sort(java.util.List<T>)' in 'java.util.Collections' cannot be applied to '(java.util.ArrayList<SortTest<?>>)'">(list)</error>;
|
||||
t1.compareTo<error descr="'compareTo(SortTest<capture<? extends java.lang.Comparable<capture<?>>>>)' in 'SortTest' cannot be applied to '(SortTest<capture<?>>)'">(t2)</error>;
|
||||
|
||||
//this should be OK
|
||||
|
||||
@@ -47,7 +47,7 @@ class Test {
|
||||
}
|
||||
|
||||
void bug1(Parametrized<? super T> param) {
|
||||
foo<error descr="'foo(Test.Parametrized<java.lang.Number>)' in 'Test.Bug2' cannot be applied to '(Test.Parametrized<capture<? super T>>)'">(param)</error>;
|
||||
foo<error descr="'foo(Test.Parametrized<I>)' in 'Test.Bug2' cannot be applied to '(Test.Parametrized<capture<? super T>>)'">(param)</error>;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -22,8 +22,8 @@ class TestIDEA128101 {
|
||||
construct(String.class, createPath(integerAttribute), createPath(stringAttribute));
|
||||
construct1<error descr="Cannot resolve method 'construct1(java.lang.Class<java.lang.String>, TestIDEA128101.Path<java.lang.Integer>, TestIDEA128101.Path<java.lang.String>)'">(String.class, createPath(integerAttribute), createPath(stringAttribute))</error>;
|
||||
construct2(String.class, createPath(integerAttribute), createPath(stringAttribute));
|
||||
construct3<error descr="Cannot resolve method 'construct3(java.lang.Class<java.lang.String>, TestIDEA128101.Path<java.lang.Integer>, TestIDEA128101.Path<java.lang.String>)'">(String.class, createPath(integerAttribute), createPath(stringAttribute))</error>;
|
||||
construct4(String.class, createPath(integerAttribute), createPath<error descr="'createPath(TestIDEA128101.Attribute<Y>)' in 'TestIDEA128101' cannot be applied to '(TestIDEA128101.Attribute<java.lang.String>)'">(stringAttribute)</error>);
|
||||
<error descr="Type parameter K has incompatible upper bounds: Integer and String">construct3(String.class, createPath(integerAttribute), createPath(stringAttribute));</error>
|
||||
<error descr="Type parameter K has incompatible upper bounds: Integer and String">construct4(String.class, createPath(integerAttribute), createPath(stringAttribute));</error>
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
class Test {
|
||||
static {
|
||||
map("Account", map(
|
||||
"Email", map("email", "myemail@domain.com"),
|
||||
"firstname", "momo",
|
||||
"lastname", "this argument makes no difference"
|
||||
),
|
||||
"akey", "makes no difference");
|
||||
|
||||
map("Account", map(
|
||||
"Email", map("email", "myemail@domain.com", "aKey", "commenting out does not help"),
|
||||
"firstname", "momo",
|
||||
"lastname", "this argument makes no difference"
|
||||
),
|
||||
"akey", "makes no difference"
|
||||
);
|
||||
}
|
||||
|
||||
public static <K, V> Map<K, V> map(K key, V value, Object... args) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static <K, V> Map<K, V> map(K key, V value) {
|
||||
return map(key, value, new Object[]{});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
class P<A, B> {
|
||||
static <C, D> P<C, D> create(C c, D d) {
|
||||
return null;
|
||||
}
|
||||
|
||||
P<String, P<Integer, String>> fooBar(String s, String s1) {
|
||||
return create(s, create(1, s1));
|
||||
}
|
||||
}
|
||||
@@ -267,6 +267,14 @@ public class GraphInferenceHighlightingTest extends LightDaemonAnalyzerTestCase
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testSameMethodCalledWithDifferentArgsResultingInDependenciesBetweenSameTypeParams() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testNestedMethodCallsWithVarargs() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
private void doTest() throws Exception {
|
||||
doTest(false);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user