mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-01-06 20:39:40 +07:00
method references: don't swallow errors during method ref inference (IDEA-179706)
This commit is contained in:
@@ -15,6 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
package com.intellij.psi.impl.source.resolve.graphInference;
|
package com.intellij.psi.impl.source.resolve.graphInference;
|
||||||
|
|
||||||
|
import com.intellij.codeInsight.PsiEquivalenceUtil;
|
||||||
import com.intellij.openapi.diagnostic.Logger;
|
import com.intellij.openapi.diagnostic.Logger;
|
||||||
import com.intellij.openapi.util.Comparing;
|
import com.intellij.openapi.util.Comparing;
|
||||||
import com.intellij.openapi.util.Key;
|
import com.intellij.openapi.util.Key;
|
||||||
@@ -1640,6 +1641,11 @@ public class InferenceSession {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//no additional constraints for array creation
|
||||||
|
if (PsiEquivalenceUtil.areElementsEquivalent(containingClass, JavaPsiFacade.getElementFactory(reference.getProject()).getArrayClass(PsiUtil.getLanguageLevel(reference)))) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
final PsiType qType = JavaPsiFacade.getElementFactory(method.getProject()).createType(containingClass, psiSubstitutor);
|
final PsiType qType = JavaPsiFacade.getElementFactory(method.getProject()).createType(containingClass, psiSubstitutor);
|
||||||
|
|
||||||
addConstraint(new TypeCompatibilityConstraint(substituteWithInferenceVariables(qType), pType));
|
addConstraint(new TypeCompatibilityConstraint(substituteWithInferenceVariables(qType), pType));
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ package com.intellij.psi.impl.source.tree.java;
|
|||||||
|
|
||||||
import com.intellij.codeInsight.PsiEquivalenceUtil;
|
import com.intellij.codeInsight.PsiEquivalenceUtil;
|
||||||
import com.intellij.openapi.diagnostic.Logger;
|
import com.intellij.openapi.diagnostic.Logger;
|
||||||
|
import com.intellij.openapi.util.text.StringUtil;
|
||||||
import com.intellij.psi.*;
|
import com.intellij.psi.*;
|
||||||
import com.intellij.psi.impl.source.resolve.ParameterTypeInferencePolicy;
|
import com.intellij.psi.impl.source.resolve.ParameterTypeInferencePolicy;
|
||||||
import com.intellij.psi.impl.source.resolve.ResolveCache;
|
import com.intellij.psi.impl.source.resolve.ResolveCache;
|
||||||
@@ -124,6 +125,10 @@ public class MethodReferenceResolver implements ResolveCache.PolyVariantContextR
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!session.repeatInferencePhases()) {
|
if (!session.repeatInferencePhases()) {
|
||||||
|
List<String> errorMessages = session.getIncompatibleErrorMessages();
|
||||||
|
if (errorMessages != null) {
|
||||||
|
setApplicabilityError(StringUtil.join(errorMessages, "\n"));
|
||||||
|
}
|
||||||
return substitutor;
|
return substitutor;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -140,6 +145,7 @@ public class MethodReferenceResolver implements ResolveCache.PolyVariantContextR
|
|||||||
@Override
|
@Override
|
||||||
public boolean isApplicable() {
|
public boolean isApplicable() {
|
||||||
if (signature == null) return false;
|
if (signature == null) return false;
|
||||||
|
if (getInferenceErrorMessageAssumeAlreadyComputed() != null) return false;
|
||||||
final PsiType[] argTypes = signature.getParameterTypes();
|
final PsiType[] argTypes = signature.getParameterTypes();
|
||||||
boolean hasReceiver = PsiMethodReferenceUtil.isSecondSearchPossible(argTypes, qualifierResolveResult, reference);
|
boolean hasReceiver = PsiMethodReferenceUtil.isSecondSearchPossible(argTypes, qualifierResolveResult, reference);
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ class AlienTest {
|
|||||||
|
|
||||||
static {
|
static {
|
||||||
IInt i1 = MyTest::<error descr="Cannot resolve method 'abracadabra'">abracadabra</error>;
|
IInt i1 = MyTest::<error descr="Cannot resolve method 'abracadabra'">abracadabra</error>;
|
||||||
IInt i2 = MyTest::<error descr="Cannot resolve method 'foo'">foo</error>;
|
IInt i2 = MyTest::<error descr="Incompatible types: int is not convertible to String">foo</error>;
|
||||||
IInt i3 = MyTest::<error descr="Cannot resolve method 'bar'">bar</error>;
|
IInt i3 = MyTest::<error descr="Cannot resolve method 'bar'">bar</error>;
|
||||||
<error descr="Incompatible types. Found: '<method reference>', required: 'AlienTest.IIntInt'">IIntInt i4 = MyTest::bar;</error>
|
<error descr="Incompatible types. Found: '<method reference>', required: 'AlienTest.IIntInt'">IIntInt i4 = MyTest::bar;</error>
|
||||||
IInt i5 = <error descr="Non-static method cannot be referenced from a static context">MyTest::baz</error>;
|
IInt i5 = <error descr="Non-static method cannot be referenced from a static context">MyTest::baz</error>;
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ class MyTest1 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
Bar1 b1 = MyTest2 :: <error descr="Cannot resolve method 'foo'">foo</error>;
|
Bar1 b1 = MyTest2 :: <error descr="Incompatible types: String is not convertible to int">foo</error>;
|
||||||
bar(MyTest1 :: foo);
|
bar(MyTest1 :: foo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -73,7 +73,7 @@ class MyTest2 {
|
|||||||
}*/
|
}*/
|
||||||
|
|
||||||
{
|
{
|
||||||
Bar1 b1 = MyTest2 :: <error descr="Cannot resolve method 'foo'">foo</error>;
|
Bar1 b1 = MyTest2 :: <error descr="Incompatible types: String is not convertible to int">foo</error>;
|
||||||
bar(MyTest2 :: foo);
|
bar(MyTest2 :: foo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -99,8 +99,8 @@ class MyTest3 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
Bar1 b1 = MyTest2 :: <error descr="Cannot resolve method 'foo'">foo</error>;
|
Bar1 b1 = MyTest2 :: <error descr="Incompatible types: String is not convertible to int">foo</error>;
|
||||||
bar(MyTest3 :: <error descr="Cannot resolve method 'foo'">foo</error>);
|
bar(MyTest3 :: <error descr="Incompatible types: int is not convertible to String">foo</error>);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ class Test {
|
|||||||
{
|
{
|
||||||
Runnable b = Test :: <error descr="Cannot resolve method 'length'">length</error>;
|
Runnable b = Test :: <error descr="Cannot resolve method 'length'">length</error>;
|
||||||
Comparable<String> c = Test :: length;
|
Comparable<String> c = Test :: length;
|
||||||
Comparable<Integer> c1 = Test :: <error descr="Cannot resolve method 'length'">length</error>;
|
Comparable<Integer> c1 = Test :: <error descr="Incompatible types: Integer is not convertible to String">length</error>;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Integer length(String s) {
|
public static Integer length(String s) {
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ class MyTest {
|
|||||||
static {
|
static {
|
||||||
I1 i1 = MyTest::static_1;
|
I1 i1 = MyTest::static_1;
|
||||||
I1 i2 = MyTest::<error descr="Cannot resolve method 'static_2'">static_2</error>;
|
I1 i2 = MyTest::<error descr="Cannot resolve method 'static_2'">static_2</error>;
|
||||||
I1 i3 = MyTest::<error descr="Cannot resolve method 'static_3'">static_3</error>;
|
I1 i3 = MyTest::<error descr="Incompatible types: int is not convertible to String">static_3</error>;
|
||||||
I1 i4 = MyTest::<error descr="Cannot resolve method 'static_4'">static_4</error>;
|
I1 i4 = MyTest::<error descr="Cannot resolve method 'static_4'">static_4</error>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,7 +62,7 @@ class MyTest {
|
|||||||
|
|
||||||
I1 i1 = this::_1;
|
I1 i1 = this::_1;
|
||||||
I1 i2 = this::<error descr="Cannot resolve method '_2'">_2</error>;
|
I1 i2 = this::<error descr="Cannot resolve method '_2'">_2</error>;
|
||||||
I1 i3 = this::<error descr="Cannot resolve method '_3'">_3</error>;
|
I1 i3 = this::<error descr="Incompatible types: int is not convertible to String">_3</error>;
|
||||||
I1 i4 = this::<error descr="Cannot resolve method '_4'">_4</error>;
|
I1 i4 = this::<error descr="Cannot resolve method '_4'">_4</error>;
|
||||||
|
|
||||||
I2 i21 = MyTest::<error descr="Cannot resolve method 'm1'">m1</error>;
|
I2 i21 = MyTest::<error descr="Cannot resolve method 'm1'">m1</error>;
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ class A {
|
|||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
B<? extends CharSequence> q = new B<>();
|
B<? extends CharSequence> q = new B<>();
|
||||||
|
|
||||||
Func x = q::<error descr="Cannot resolve method 'foo'">foo</error>;
|
Func x = q::<error descr="Incompatible types: CharSequence is not convertible to capture of ? extends CharSequence">foo</error>;
|
||||||
x.invoke("");
|
x.invoke("");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ interface B<BT> {
|
|||||||
|
|
||||||
class Test {
|
class Test {
|
||||||
public static void test() {
|
public static void test() {
|
||||||
method1(Test::<error descr="Cannot resolve method 'method2'">method2</error>);
|
method1(Test::<error descr="Incompatible types: A<capture of ? super M> is not convertible to A<? super String>">method2</error>);
|
||||||
}
|
}
|
||||||
|
|
||||||
static <M> void method1(B<A<? super M>> arg) { }
|
static <M> void method1(B<A<? super M>> arg) { }
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import java.util.function.Predicate;
|
|||||||
|
|
||||||
class MyTest {
|
class MyTest {
|
||||||
{
|
{
|
||||||
BiConsumer<Predicate<? extends Runnable>, Predicate<? extends Runnable>> or = MyTest::<error descr="Cannot resolve method 'or'">or</error>;
|
BiConsumer<Predicate<? extends Runnable>, Predicate<? extends Runnable>> or = MyTest::<error descr="Incompatible equality constraint: capture of ? extends Runnable and capture of ? extends Runnable">or</error>;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static <E extends Runnable> void or(Predicate<E> left, Predicate<E> right) {}
|
private static <E extends Runnable> void or(Predicate<E> left, Predicate<E> right) {}
|
||||||
|
|||||||
@@ -29,14 +29,14 @@ class Test {
|
|||||||
static void meth4(I3 s) { }
|
static void meth4(I3 s) { }
|
||||||
|
|
||||||
static {
|
static {
|
||||||
meth1(Foo::<error descr="Cannot resolve constructor 'Foo'">new</error>);
|
meth1(Foo::<error descr="no instance(s) of type variable(s) exist so that String conforms to Number">new</error>);
|
||||||
meth2(Foo::new);
|
meth2(Foo::new);
|
||||||
meth3(Foo::<error descr="Cannot resolve constructor 'Foo'">new</error>);
|
meth3(Foo::<error descr="no instance(s) of type variable(s) exist so that Object conforms to Number">new</error>);
|
||||||
meth4<error descr="Ambiguous method call: both 'Test.meth4(I1)' and 'Test.meth4(I2)' match">(Foo::new)</error>;
|
meth4<error descr="Ambiguous method call: both 'Test.meth4(I1)' and 'Test.meth4(I2)' match">(Foo::new)</error>;
|
||||||
|
|
||||||
meth1(Test::<error descr="Cannot resolve method 'foo'">foo</error>);
|
meth1(Test::<error descr="no instance(s) of type variable(s) exist so that String conforms to Number">foo</error>);
|
||||||
meth2(Test::foo);
|
meth2(Test::foo);
|
||||||
meth3(Test::<error descr="Cannot resolve method 'foo'">foo</error>);
|
meth3(Test::<error descr="no instance(s) of type variable(s) exist so that Object conforms to Number">foo</error>);
|
||||||
meth4<error descr="Ambiguous method call: both 'Test.meth4(I1)' and 'Test.meth4(I2)' match">(Test::foo)</error>;
|
meth4<error descr="Ambiguous method call: both 'Test.meth4(I1)' and 'Test.meth4(I2)' match">(Test::foo)</error>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,8 +55,8 @@ class Test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void test() {
|
void test() {
|
||||||
II1 i1 = this::<error descr="Cannot resolve method 'fooInstance'">fooInstance</error>;
|
II1 i1 = this::<error descr="no instance(s) of type variable(s) exist so that X conforms to Number">fooInstance</error>;
|
||||||
II2 i2 = this::fooInstance;
|
II2 i2 = this::fooInstance;
|
||||||
II3 i3 = this::<error descr="Cannot resolve method 'fooInstance'">fooInstance</error>;
|
II3 i3 = this::<error descr="no instance(s) of type variable(s) exist so that X conforms to Number">fooInstance</error>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,45 @@
|
|||||||
|
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
import java.util.function.BiFunction;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
interface Regression<S, T, A, B> {
|
||||||
|
<F extends Functor, FT extends Functor<T, F>, FB extends Functor<B, F>> FT apply(
|
||||||
|
Function<? super A, ? extends FB> fn, S s);
|
||||||
|
|
||||||
|
static <S, T, A, B> Regression<S, T, A, B> regression(Function<? super S, ? extends A> getter,
|
||||||
|
BiFunction<? super S, ? super B, ? extends T> setter) {
|
||||||
|
return new Regression<S, T, A, B>() {
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public <F extends Functor, FT extends Functor<T, F>, FB extends Functor<B, F>> FT apply(
|
||||||
|
Function<? super A, ? extends FB> fn,
|
||||||
|
S s) {
|
||||||
|
return null; //doesn't matter
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
static <S, A> Simple<S, A> simple(Function<? super S, ? extends A> getter,
|
||||||
|
BiFunction<? super S, ? super A, ? extends S> setter) {
|
||||||
|
return regression(getter, setter)::<error descr="Incompatible equality constraint: capture of ? super A and B">apply</error>; // java9 fails to compile this line
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Functor<X, F extends Functor> {
|
||||||
|
}
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
interface Simple<S, A> extends Regression<S, S, A, A> {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SimplifiedTest<B> {
|
||||||
|
<FB extends Functor<B>> FB apply(Supplier<? extends FB> fn);
|
||||||
|
|
||||||
|
static <A> SimplifiedTest<A> simple(final SimplifiedTest<? super A> regression) {
|
||||||
|
return regression::<error descr="no instance(s) of type variable(s) exist so that capture of ? extends FB conforms to Functor<capture of ? super A>">apply</error>;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Functor<X> { }
|
||||||
|
}
|
||||||
@@ -4,7 +4,7 @@ class InlineRef {
|
|||||||
<K> void foo(Consumer<K> f) {}
|
<K> void foo(Consumer<K> f) {}
|
||||||
|
|
||||||
void bar(){
|
void bar(){
|
||||||
foo(Descriptor::<error descr="Cannot resolve method 'getName'">getName</error>);
|
foo(Descriptor::<error descr="Incompatible types: Object is not convertible to Descriptor">getName</error>);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -177,6 +177,7 @@ public class NewMethodRefHighlightingTest extends LightDaemonAnalyzerTestCase {
|
|||||||
public void testConstructorRefOnClassWithRecursiveTypeParameter() { doTest(); }
|
public void testConstructorRefOnClassWithRecursiveTypeParameter() { doTest(); }
|
||||||
public void testWildcardInCheckedCompatibilityConstraints() { doTest(); }
|
public void testWildcardInCheckedCompatibilityConstraints() { doTest(); }
|
||||||
public void testConstructorReferenceWithVarargsParameters() { doTest(); }
|
public void testConstructorReferenceWithVarargsParameters() { doTest(); }
|
||||||
|
public void testMethodReferenceSwallowedErrors() { doTest(); }
|
||||||
|
|
||||||
public void testPreferErrorOnTopLevelToFailedSubstitutorOnNestedLevel() { doTest(); }
|
public void testPreferErrorOnTopLevelToFailedSubstitutorOnNestedLevel() { doTest(); }
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user