mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
calc types by applicability constraints if inference fails
include all inference variables for resolve and ignore additional constraints checks if the inference is going to failure; this way if (expr()) would get type of the 'standalone' expression instead of expression with boolean as expected type
This commit is contained in:
+1
-1
@@ -523,7 +523,7 @@ public class HighlightMethodUtil {
|
||||
PsiType rType = methodCall.getType();
|
||||
if (rType != null && !variable.getType().isAssignableFrom(rType)) {
|
||||
PsiType expectedTypeByApplicabilityConstraints = resolveResult.getSubstitutor(false).substitute(resolved.getReturnType());
|
||||
if (expectedTypeByApplicabilityConstraints != null && !expectedTypeByApplicabilityConstraints.equals(rType)) {
|
||||
if (expectedTypeByApplicabilityConstraints != null && !variable.getType().isAssignableFrom(expectedTypeByApplicabilityConstraints)) {
|
||||
HighlightFixUtil.registerChangeVariableTypeFixes(variable, expectedTypeByApplicabilityConstraints, methodCall, highlightInfo);
|
||||
}
|
||||
}
|
||||
|
||||
+6
-36
@@ -378,11 +378,9 @@ public class InferenceSession {
|
||||
if (expectedActualErrorMessage != null && myErrorMessages != null) {
|
||||
myErrorMessages.add(0, expectedActualErrorMessage);
|
||||
}
|
||||
resolveBounds(getInputInferenceVariablesFromTopLevelFunctionalExpressions(args, properties), initialSubstitutor);
|
||||
return;
|
||||
}
|
||||
|
||||
if (parameters != null && args != null && !isOverloadCheck()) {
|
||||
//proceed to B3 constraints
|
||||
else if (parameters != null && args != null && !isOverloadCheck()) {
|
||||
final Set<ConstraintFormula> additionalConstraints = new LinkedHashSet<>();
|
||||
final HashSet<ConstraintFormula> ignoredConstraints = new HashSet<>();
|
||||
if (parameters.length > 0) {
|
||||
@@ -390,41 +388,13 @@ public class InferenceSession {
|
||||
ignoredConstraints, properties.isVarargs(), initialSubstitutor);
|
||||
}
|
||||
|
||||
if (!additionalConstraints.isEmpty() && !proceedWithAdditionalConstraints(additionalConstraints, ignoredConstraints)) {
|
||||
resolveBounds(getInputInferenceVariablesFromTopLevelFunctionalExpressions(args, properties), initialSubstitutor);
|
||||
return;
|
||||
}
|
||||
proceedWithAdditionalConstraints(additionalConstraints, ignoredConstraints);
|
||||
}
|
||||
}
|
||||
|
||||
resolveBounds(myInferenceVariables, initialSubstitutor);
|
||||
}
|
||||
|
||||
private Collection<InferenceVariable> getInputInferenceVariablesFromTopLevelFunctionalExpressions(PsiExpression[] args, MethodCandidateInfo.CurrentCandidateProperties properties) {
|
||||
if (args == null) return Collections.emptyList();
|
||||
final PsiMethod method = properties.getMethod();
|
||||
final PsiParameter[] parameters = method.getParameterList().getParameters();
|
||||
if (parameters.length == 0) return Collections.emptyList();
|
||||
final HashSet<InferenceVariable> dependencies = new HashSet<>();
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
PsiExpression arg = args[i];
|
||||
if (arg instanceof PsiLambdaExpression && !((PsiLambdaExpression)arg).hasFormalParameterTypes() ||
|
||||
arg instanceof PsiMethodReferenceExpression && !((PsiMethodReferenceExpression)arg).isExact()) {
|
||||
final PsiSubstitutor nestedSubstitutor = myInferenceSessionContainer.findNestedSubstitutor(arg, myInferenceSubstitution);
|
||||
final PsiType parameterType = nestedSubstitutor.substitute(getParameterType(parameters, i, mySiteSubstitutor, properties.isVarargs()));
|
||||
final PsiClassType.ClassResolveResult result = PsiUtil.resolveGenericsClassInType(parameterType);
|
||||
final PsiMethod interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(result);
|
||||
if (interfaceMethod != null) {
|
||||
final PsiSubstitutor substitutor = LambdaUtil.getSubstitutor(interfaceMethod, result);
|
||||
for (PsiParameter parameter : interfaceMethod.getParameterList().getParameters()) {
|
||||
collectDependencies(substitutor.substitute(parameter.getType()), dependencies);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return dependencies;
|
||||
}
|
||||
|
||||
private boolean isOverloadCheck() {
|
||||
if (myContext != null) {
|
||||
for (Object o : MethodCandidateInfo.ourOverloadGuard.currentStack()) {
|
||||
@@ -1089,7 +1059,7 @@ public class InferenceSession {
|
||||
}
|
||||
if (!myIncorporationPhase.hasCaptureConstraints(unresolved)) {
|
||||
PsiSubstitutor firstSubstitutor = resolveSubset(vars, substitutor);
|
||||
if (hasBoundProblems(vars, firstSubstitutor)) {
|
||||
if (myErrorMessages == null && hasBoundProblems(vars, firstSubstitutor)) {
|
||||
firstSubstitutor = null;
|
||||
unresolved = vars;
|
||||
}
|
||||
@@ -1243,7 +1213,7 @@ public class InferenceSession {
|
||||
type = var.getBounds(InferenceBound.UPPER).size() == 1 ? myPolicy.getInferredTypeWithNoConstraint(myManager, upperBound).first : upperBound;
|
||||
}
|
||||
|
||||
if (type instanceof PsiIntersectionType) {
|
||||
if (myErrorMessages == null && type instanceof PsiIntersectionType) {
|
||||
String conflictingConjunctsMessage = ((PsiIntersectionType)type).getConflictingConjunctsMessage();
|
||||
if (conflictingConjunctsMessage == null) {
|
||||
if (findParameterizationOfTheSameGenericClass(var.getBounds(InferenceBound.UPPER),
|
||||
@@ -1265,7 +1235,7 @@ public class InferenceSession {
|
||||
}
|
||||
else {
|
||||
for (PsiType upperType : var.getBounds(InferenceBound.UPPER)) {
|
||||
if (isProperType(upperType) ) {
|
||||
if (myErrorMessages == null && isProperType(upperType)) {
|
||||
String incompatibleBoundsMessage = null;
|
||||
if (type != lowerBound && !TypeConversionUtil.isAssignable(upperType, type)) {
|
||||
incompatibleBoundsMessage = incompatibleBoundsMessage(var, substitutor, InferenceBound.EQ, EQUALITY_CONSTRAINTS_PRESENTATION, InferenceBound.UPPER, UPPER_BOUNDS_PRESENTATION);
|
||||
|
||||
@@ -20,7 +20,6 @@ import com.intellij.psi.*;
|
||||
import com.intellij.psi.codeStyle.CodeStyleManager;
|
||||
import com.intellij.psi.util.InheritanceUtil;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.PsiTypesUtil;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -67,9 +66,6 @@ public class RefactoringChangeUtil {
|
||||
if (refClass instanceof PsiAnonymousClass) {
|
||||
type = ((PsiAnonymousClass)refClass).getBaseClassType();
|
||||
}
|
||||
if (refClass instanceof PsiTypeParameter && !PsiTypesUtil.isAccessibleAt((PsiTypeParameter)refClass, expr)) {
|
||||
type = ((PsiExpression)expr.copy()).getType();
|
||||
}
|
||||
|
||||
return GenericsUtil.getVariableTypeByExpressionType(type);
|
||||
}
|
||||
|
||||
+1
-4
@@ -8,9 +8,6 @@ abstract class Test {
|
||||
|
||||
private void call(){
|
||||
String s = <error descr="Incompatible types. Required String but 'test' was inferred to T:
|
||||
no instance(s) of type variable(s) exist so that String[] conforms to String
|
||||
inference variable T has incompatible bounds:
|
||||
equality constraints: String[]
|
||||
upper bounds: Object, String">test(String[].class);</error>
|
||||
no instance(s) of type variable(s) exist so that String[] conforms to String">test(String[].class);</error>
|
||||
}
|
||||
}
|
||||
|
||||
+1
-4
@@ -7,10 +7,7 @@ class Test {
|
||||
final Class<? extends ClassB> bClass = null;
|
||||
ClassB b = factory.create(bClass);
|
||||
String str = <error descr="Incompatible types. Required String but 'create' was inferred to T:
|
||||
no instance(s) of type variable(s) exist so that capture of ? extends ClassB conforms to String
|
||||
inference variable T has incompatible bounds:
|
||||
equality constraints: capture of ? extends ClassB
|
||||
upper bounds: ClassA<I>, Object, String">factory.create(bClass);</error>
|
||||
no instance(s) of type variable(s) exist so that capture of ? extends ClassB conforms to String">factory.create(bClass);</error>
|
||||
}
|
||||
|
||||
public static class Factory {
|
||||
|
||||
+3
-3
@@ -15,13 +15,13 @@ class NoInferenceResult {
|
||||
<T> void m1(T t) { }
|
||||
|
||||
void test() {
|
||||
m(<error descr="Object is not a functional interface">(String s1) -> (String s2) -> s1 + s2</error>);
|
||||
m(<error descr="Object is not a functional interface">(String s1) -> {return (String s2) -> s1 + s2;}</error>);
|
||||
m((String s1) -> <error descr="Target type of a lambda conversion must be an interface">(String s2) -> s1 + s2</error>);
|
||||
m((String s1) -> {return <error descr="Target type of a lambda conversion must be an interface">(String s2) -> s1 + s2</error>;});
|
||||
|
||||
m((String s1) -> s1.length());
|
||||
m((String s1) -> s1);
|
||||
|
||||
m1(<error descr="Object is not a functional interface">() -> { }</error>);
|
||||
m1(<error descr="Target type of a lambda conversion must be an interface">() -> { }</error>);
|
||||
|
||||
Foo<String> foo = new Foo<String>();
|
||||
foo.map(v -> null);
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@ class NoLambda {
|
||||
static <T> T id(T i2) {return i2;}
|
||||
|
||||
{
|
||||
id(<error descr="Object is not a functional interface">() -> {System.out.println("hi");}</error>);
|
||||
id(<error descr="Target type of a lambda conversion must be an interface">() -> {System.out.println("hi");}</error>);
|
||||
NoLambda.<Runnable>id(() -> {System.out.println("hi");});
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -5,7 +5,7 @@ import java.util.function.Consumer;
|
||||
class Test {
|
||||
|
||||
public static void main(String[] args) {
|
||||
Iterable<Consumer<Reader>> i = Arrays.asList(<error descr="Unhandled exception: IOException">(r) -> r.read()</error>);
|
||||
Iterable<Consumer<Reader>> i = Arrays.asList((r) -> r.<error descr="Unhandled exception: java.io.IOException">read()</error>);
|
||||
Iterable<Consumer<Reader>> i1 = Arrays.<Consumer<Reader>>asList((r) -> r.<error descr="Unhandled exception: java.io.IOException">read()</error>);
|
||||
}
|
||||
}
|
||||
+1
-4
@@ -10,10 +10,7 @@ class Test {
|
||||
<R> SuperFoo<R> foo(I<R> ax) { return null; }
|
||||
|
||||
SuperFoo<String> ls = foo(<error descr="Incompatible types. Required SuperFoo<String> but 'foo' was inferred to SuperFoo<R>:
|
||||
no instance(s) of type variable(s) exist so that String conforms to Number
|
||||
inference variable R has incompatible bounds:
|
||||
equality constraints: String
|
||||
upper bounds: Object, Number">() -> new Foo<>()</error>);
|
||||
no instance(s) of type variable(s) exist so that String conforms to Number">() -> new Foo<>()</error>);
|
||||
SuperFoo<Integer> li = foo(() -> new Foo<>());
|
||||
SuperFoo<?> lw = foo(() -> new Foo<>());
|
||||
}
|
||||
+1
-4
@@ -26,10 +26,7 @@ abstract class NoFormalParamTypeInferenceNeeded {
|
||||
{
|
||||
map(a -> zip(text -> text));
|
||||
zip(a -> zip(text -> text));
|
||||
Integer zip = zip(<error descr="no instance(s) of type variable(s) exist so that Object conforms to Integer
|
||||
inference variable R has incompatible bounds:
|
||||
lower bounds: Object
|
||||
upper bounds: Object, Integer">a -> zip(text -> text)</error>);
|
||||
Integer zip = zip(<error descr="no instance(s) of type variable(s) exist so that Object conforms to Integer">a -> zip(text -> text)</error>);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ class Test {
|
||||
<T extends Runnable> void call1(T t) {}
|
||||
|
||||
{
|
||||
call(<error descr="Object is not a functional interface">() -> {}</error>);
|
||||
call(<error descr="Target type of a lambda conversion must be an interface">() -> {}</error>);
|
||||
call1(() -> {});
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
class Test {
|
||||
{
|
||||
asList(<error descr="Integer is not a functional interface">o -> {}</error>, 1, 2, 3);
|
||||
asList(<error descr="T is not a functional interface">Test::foo</error>, 1, 2, 3);
|
||||
asList(<error descr="Target type of a lambda conversion must be an interface">o -> {}</error>, 1, 2, 3);
|
||||
asList(<error descr="Integer is not a functional interface">Test::foo</error>, 1, 2, 3);
|
||||
}
|
||||
|
||||
void foo() {}
|
||||
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
// "Replace with 'java.util.TreeSet' constructor" "true"
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.*;
|
||||
|
||||
class Test {
|
||||
public static void test(List<String> s) {
|
||||
new TreeSet<? extends String>(s).contains("abc");
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
// "Replace with 'java.util.TreeSet' constructor" "false"
|
||||
// "Replace with 'java.util.TreeSet' constructor" "true"
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.*;
|
||||
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
import java.util.List;
|
||||
|
||||
class GenericTypeMismatch {
|
||||
interface Key<T> {}
|
||||
|
||||
static final Key<String> KEY = new Key<String>() {};
|
||||
|
||||
<T> java.util.List<T> getByKey(Key<T> key) {
|
||||
return null;
|
||||
}
|
||||
|
||||
void test() {
|
||||
final List<String> i = getByKey(KEY);
|
||||
if(i)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
class GenericTypeMismatch {
|
||||
interface Key<T> {}
|
||||
|
||||
static final Key<String> KEY = new Key<String>() {};
|
||||
|
||||
<T> java.util.List<T> getByKey(Key<T> key) {
|
||||
return null;
|
||||
}
|
||||
|
||||
void test() {
|
||||
if(ge<caret>tByKey(KEY))
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -238,6 +238,10 @@ public class IntroduceVariableTest extends LightCodeInsightTestCase {
|
||||
doTest(new MockIntroduceVariableHandler("i", true, true, false, "java.lang.String"));
|
||||
}
|
||||
|
||||
public void testGenericTypeMismatch1() {
|
||||
doTest(new MockIntroduceVariableHandler("i", true, true, false, "java.util.List<java.lang.String>"));
|
||||
}
|
||||
|
||||
public void testThisQualifier() {
|
||||
doTest(new MockIntroduceVariableHandler("count", true, true, false, "int"));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user