[java-highlighting] Do not report incompatible type problems when operand is lambda parameter having unknown type

Such kind of error is induced by lambda resolution error, and in most of the cases the resolution error should be fixed first
Fixes IDEA-361893 "Introduce local variable" should suggest for Function expression

GitOrigin-RevId: 352d0f9040dd3e153e7d5b15ae61699b8c890194
This commit is contained in:
Tagir Valeev
2024-12-10 16:14:02 +00:00
committed by intellij-monorepo-bot
parent 5378001c87
commit f592c31876
6 changed files with 31 additions and 6 deletions
@@ -409,6 +409,10 @@ public final class HighlightUtil {
PsiType rType = rExpression.getType();
HighlightInfo.Builder errorResult = null;
if (!TypeConversionUtil.isBinaryOperatorApplicable(opSign, lType, rType, true)) {
if (lType instanceof PsiLambdaParameterType || rType instanceof PsiLambdaParameterType) {
// Unresolved lambda parameter type is used: an error for parameter should be more descriptive, so let's avoid reporting type error
return null;
}
String operatorText = operationSign.getText().substring(0, operationSign.getText().length() - 1);
String message = JavaErrorBundle.message("binary.operator.not.applicable", operatorText,
JavaHighlightUtil.formatType(lType),
@@ -437,7 +441,8 @@ public final class HighlightUtil {
// 15.26.2. Compound Assignment Operators
IElementType opSign = TypeConversionUtil.convertEQtoOperation(sign);
PsiType type = TypeConversionUtil.calcTypeForBinaryExpression(lType, rType, opSign, true);
if (type == null || lType == null || TypeConversionUtil.areTypesConvertible(type, lType)) {
if (type == null || lType == null || lType instanceof PsiLambdaParameterType || type instanceof PsiLambdaParameterType ||
TypeConversionUtil.areTypesConvertible(type, lType)) {
return null;
}
if (IncompleteModelUtil.isIncompleteModel(assignment) && IncompleteModelUtil.isPotentiallyConvertible(lType, rExpr)) {
@@ -2026,6 +2031,9 @@ public final class HighlightUtil {
for (int i = 1; i < operands.length; i++) {
PsiExpression operand = operands[i];
PsiType rType = operand.getType();
if (lType instanceof PsiLambdaParameterType || rType instanceof PsiLambdaParameterType) {
return null;
}
if (!TypeConversionUtil.isBinaryOperatorApplicable(operationSign, lType, rType, false) &&
!(IncompleteModelUtil.isIncompleteModel(expression) &&
IncompleteModelUtil.isPotentiallyConvertible(lType, rType, expression))) {
@@ -2046,7 +2054,7 @@ public final class HighlightUtil {
static HighlightInfo.Builder checkUnaryOperatorApplicable(@NotNull PsiJavaToken token, @Nullable PsiExpression expression) {
if (expression != null && !TypeConversionUtil.isUnaryOperatorApplicable(token, expression)) {
PsiType type = expression.getType();
if (type == null) return null;
if (type == null || type instanceof PsiLambdaParameterType) return null;
String message = JavaErrorBundle.message("unary.operator.not.applicable", token.getText(), JavaHighlightUtil.formatType(type));
PsiElement parentExpr = token.getParent();
@@ -1,6 +1,6 @@
class IntStream {
private void foo(IntStream s) {
s.<error descr="Ambiguous method call: both 'IntStream.map(IntUnaryOperator)' and 'IntStream.map(ObjIntFunction<Object>)' match">map</error>(i -> <error descr="Operator '<<' cannot be applied to 'int', '<lambda parameter>'">1 << i</error>);
s.<error descr="Ambiguous method call: both 'IntStream.map(IntUnaryOperator)' and 'IntStream.map(ObjIntFunction<Object>)' match">map</error>(i -> 1 << i);
s.<error descr="Ambiguous method call: both 'IntStream.map(IntUnaryOperator)' and 'IntStream.map(ObjIntFunction<Object>)' match">map</error>(<warning descr="Parameter 'i' is never used">i</warning> -> 1);
s.<error descr="Ambiguous method call: both 'IntStream.map(IntUnaryOperator)' and 'IntStream.map(ObjIntFunction<Object>)' match">map</error>(i -> i);
}
@@ -0,0 +1,16 @@
class Test {
int field;
void foo() {
<error descr="Not a statement">i -> i + 1;</error>
<error descr="Not a statement">i -> 1 + i;</error>
<error descr="Not a statement">i -> 1 + 2 + i;</error>
<error descr="Not a statement">i -> 1 + i + 2;</error>
i -> <error descr="Operator '-' cannot be applied to 'int', 'java.lang.String'">1 - "xyz" - i</error>;
foo<error descr="Expected no arguments but found 1">(i -> ++i)</error>;
<error descr="Cannot resolve method 'bar' in 'Test'">bar</error>(i -> i += 2);
<error descr="Cannot resolve method 'bar' in 'Test'">bar</error>(i -> field += i);
}
}
@@ -14,7 +14,7 @@ class Test {
}
void fooBar(IntStream1 instr){
Supplier<Stream<Integer>> si = () -> instr.<error descr="Ambiguous method call: both 'IntStream1.map(IntFunction<Integer>)' and 'IntStream1.map(IntUnaryOperator)' match">map</error> ((i) -> (( <error descr="Operator '%' cannot be applied to '<lambda parameter>', 'int'">i % 2</error>) == 0) ? i : <error descr="Operator '-' cannot be applied to '<lambda parameter>'">-i</error>).boxed();
Supplier<Stream<Integer>> si = () -> instr.<error descr="Ambiguous method call: both 'IntStream1.map(IntFunction<Integer>)' and 'IntStream1.map(IntUnaryOperator)' match">map</error> ((i) -> (( i % 2) == 0) ? i : -i).boxed();
System.out.println(si);
Supplier<Stream<Integer>> si1 = () -> instr.map <error descr="Ambiguous method call: both 'IntStream1.map(IntFunction<Integer>)' and 'IntStream1.map(IntUnaryOperator)' match">(null)</error>.boxed();
System.out.println(si1);
@@ -14,10 +14,10 @@ abstract class Test {
foo(x -> {
return x += 1;
});
<error descr="Ambiguous method call: both 'Test.foo(A)' and 'Test.foo(B)' match">foo</error>(x -> <error descr="Incompatible types. Found: 'int', required: '<lambda parameter>'">x += 1</error>);
<error descr="Ambiguous method call: both 'Test.foo(A)' and 'Test.foo(B)' match">foo</error>(x -> x += 1);
foo(<warning descr="Parameter 'x' is never used">x</warning> -> 1);
foo(x -> <error descr="Operator '!' cannot be applied to 'int'">!x</error>);
<error descr="Ambiguous method call: both 'Test.foo(A)' and 'Test.foo(B)' match">foo</error>(x -> <error descr="Operator '++' cannot be applied to '<lambda parameter>'">++x</error>);
<error descr="Ambiguous method call: both 'Test.foo(A)' and 'Test.foo(B)' match">foo</error>(x -> ++x);
foo(<warning descr="Parameter 'x' is never used">x</warning> -> o instanceof String ? 1 : 0);
}
}
@@ -49,6 +49,7 @@ class NewLambdaHighlightingTest extends LightJavaCodeInsightFixtureTestCase5 {
@Test void testIDEA123869() { doTest(); }
@Test void testIDEA123848() { doTest(); }
@Test void testOnlyLambdaAtTypeParameterPlace() { doTest(); }
@Test void testOperatorApplicabilityInUnresolvedLambdas() { doTest(); }
@Test void testLiftedIntersectionType() { doTest(); }
@Test void testInferenceFromReturnStatements() { doTest(); }
@Test void testDownUpThroughLambdaReturnStatements() { doTest(); }