[java-highlighting] Do not report incompatible type when found type is lambda

GitOrigin-RevId: 511c42c0fbbb713ec34b6a25d1ceddb0d5612b2f
This commit is contained in:
Tagir Valeev
2025-03-21 14:59:41 +00:00
committed by intellij-monorepo-bot
parent c05cf16cf5
commit c855231a3b
12 changed files with 41 additions and 32 deletions
@@ -141,8 +141,7 @@ final class ExpressionChecker {
if (expression != null && myVisitor.isIncompleteModel() && IncompleteModelUtil.isPotentiallyConvertible(lType, expression)) {
return true;
}
myVisitor.report(JavaErrorKinds.TYPE_INCOMPATIBLE.create(elementToHighlight, new JavaIncompatibleTypeErrorContext(lType, rType)));
return false;
return myVisitor.reportIncompatibleType(lType, rType, elementToHighlight);
}
void checkMustBeBoolean(@NotNull PsiExpression expr) {
@@ -157,7 +156,7 @@ final class ExpressionChecker {
if (type == null && myVisitor.isIncompleteModel() && IncompleteModelUtil.mayHaveUnknownTypeDueToPendingReference(expr)) {
return;
}
myVisitor.report(JavaErrorKinds.TYPE_INCOMPATIBLE.create(expr, new JavaIncompatibleTypeErrorContext(PsiTypes.booleanType(), type)));
myVisitor.reportIncompatibleType(PsiTypes.booleanType(), type, expr);
}
}
}
@@ -366,7 +365,7 @@ final class ExpressionChecker {
PsiClassType processorType = factory.createTypeByFQClassName(CommonClassNames.JAVA_LANG_STRING_TEMPLATE_PROCESSOR, processor.getResolveScope());
if (!TypeConversionUtil.isAssignable(processorType, type)) {
if (myVisitor.isIncompleteModel() && IncompleteModelUtil.isPotentiallyConvertible(processorType, processor)) return;
myVisitor.report(JavaErrorKinds.TYPE_INCOMPATIBLE.create(processor, new JavaIncompatibleTypeErrorContext(processorType, type)));
myVisitor.reportIncompatibleType(processorType, type, processor);
return;
}
@@ -566,7 +565,7 @@ final class ExpressionChecker {
return;
}
if (myVisitor.isIncompleteModel() && IncompleteModelUtil.isPotentiallyConvertible(lType, rExpr)) return;
myVisitor.report(JavaErrorKinds.TYPE_INCOMPATIBLE.create(rExpr, new JavaIncompatibleTypeErrorContext(lType, type)));
myVisitor.reportIncompatibleType(lType, type, rExpr);
}
}
@@ -1381,7 +1380,7 @@ final class ExpressionChecker {
}
// cannot derive type of conditional expression
// elseType will never be cast-able to thenType, so no quick fix here
myVisitor.report(JavaErrorKinds.TYPE_INCOMPATIBLE.create(expression, new JavaIncompatibleTypeErrorContext(thenType, type)));
myVisitor.reportIncompatibleType(thenType, type, expression);
}
}
@@ -99,7 +99,7 @@ final class GenericsChecker {
if (myVisitor.isIncompleteModel() && IncompleteModelUtil.isPotentiallyConvertible(parameterType, itemType, expression)) {
return;
}
myVisitor.report(JavaErrorKinds.TYPE_INCOMPATIBLE.create(parameter, new JavaIncompatibleTypeErrorContext(itemType, parameterType)));
myVisitor.reportIncompatibleType(itemType, parameterType, parameter);
}
void checkDiamondTypeNotAllowed(@NotNull PsiNewExpression expression) {
@@ -6,6 +6,7 @@ import com.intellij.java.codeserver.core.JavaPreviewFeatureUtil;
import com.intellij.java.codeserver.core.JavaPsiModuleUtil;
import com.intellij.java.codeserver.highlighting.errors.JavaCompilationError;
import com.intellij.java.codeserver.highlighting.errors.JavaErrorKinds;
import com.intellij.java.codeserver.highlighting.errors.JavaIncompatibleTypeErrorContext;
import com.intellij.lang.ASTNode;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.IndexNotReadyException;
@@ -1348,6 +1349,16 @@ final class JavaErrorVisitor extends JavaElementVisitor {
}
}
boolean reportIncompatibleType(@NotNull PsiType lType, @Nullable PsiType rType, @NotNull PsiElement elementToHighlight) {
if (rType instanceof PsiLambdaParameterType || lType instanceof PsiLambdaParameterType) {
// Do not report an incompatible type if the lambda parameter type is not known;
// this problem is induced by another problem, which is more useful to report
return true;
}
report(JavaErrorKinds.TYPE_INCOMPATIBLE.create(elementToHighlight, new JavaIncompatibleTypeErrorContext(lType, rType)));
return false;
}
private void checkPreviewFeature(@NotNull PsiElement element) {
if (myLanguageLevel.isPreview()) return;
JavaPreviewFeatureUtil.PreviewFeatureUsage usage = JavaPreviewFeatureUtil.getPreviewFeatureUsage(element);
@@ -7,7 +7,6 @@ import com.intellij.codeInsight.daemon.impl.analysis.JavaGenericsUtil;
import com.intellij.java.codeserver.core.JavaPsiMethodUtil;
import com.intellij.java.codeserver.highlighting.errors.JavaCompilationError;
import com.intellij.java.codeserver.highlighting.errors.JavaErrorKinds;
import com.intellij.java.codeserver.highlighting.errors.JavaIncompatibleTypeErrorContext;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Couple;
@@ -59,7 +58,7 @@ final class MethodChecker {
PsiClassType type = factory.createType(aClass);
PsiClassType throwable = factory.createTypeByFQClassName(CommonClassNames.JAVA_LANG_THROWABLE, context.getResolveScope());
if (myVisitor.isIncompleteModel() && IncompleteModelUtil.isPotentiallyConvertible(throwable, type, context)) return;
myVisitor.report(JavaErrorKinds.TYPE_INCOMPATIBLE.create(context, new JavaIncompatibleTypeErrorContext(throwable, type)));
myVisitor.reportIncompatibleType(throwable, type, context);
}
}
@@ -100,7 +100,7 @@ final class PatternChecker {
@NotNull PsiType itemType) {
if (!TypeConversionUtil.areTypesConvertible(itemType, patternType) &&
(!myVisitor.isIncompleteModel() || !IncompleteModelUtil.isPotentiallyConvertible(patternType, itemType, pattern))) {
myVisitor.report(JavaErrorKinds.TYPE_INCOMPATIBLE.create(pattern, new JavaIncompatibleTypeErrorContext(itemType, patternType)));
myVisitor.reportIncompatibleType(itemType, patternType, pattern);
return;
}
checkUncheckedPatternConversion(pattern);
@@ -154,8 +154,7 @@ final class PatternChecker {
IncompleteModelUtil.hasUnresolvedComponent(deconstructionComponentType))) {
continue;
}
myVisitor.report(JavaErrorKinds.TYPE_INCOMPATIBLE.create(
deconstructionComponent, new JavaIncompatibleTypeErrorContext(substitutedRecordComponentType, deconstructionComponentType)));
myVisitor.reportIncompatibleType(substitutedRecordComponentType, deconstructionComponentType, deconstructionComponent);
}
}
else {
@@ -6,7 +6,6 @@ import com.intellij.codeInsight.daemon.impl.analysis.JavaGenericsUtil;
import com.intellij.core.JavaPsiBundle;
import com.intellij.java.codeserver.core.JavaPsiVariableUtil;
import com.intellij.java.codeserver.highlighting.errors.JavaErrorKinds;
import com.intellij.java.codeserver.highlighting.errors.JavaIncompatibleTypeErrorContext;
import com.intellij.pom.java.JavaFeature;
import com.intellij.psi.*;
import com.intellij.psi.impl.IncompleteModelUtil;
@@ -191,8 +190,7 @@ final class StatementChecker {
if (TypeConversionUtil.isAssignable(autoCloseable, type)) return;
if (myVisitor.isIncompleteModel() && IncompleteModelUtil.isPotentiallyConvertible(autoCloseable, type, resource)) return;
myVisitor.report(JavaErrorKinds.TYPE_INCOMPATIBLE.create(
resource, new JavaIncompatibleTypeErrorContext(autoCloseable, type)));
myVisitor.reportIncompatibleType(autoCloseable, type, resource);
}
void checkBreakTarget(@NotNull PsiBreakStatement statement) {
@@ -335,8 +333,7 @@ final class StatementChecker {
PsiType type = expression.getType();
if (type == null) return;
if (expression == assertStatement.getAssertCondition() && !TypeConversionUtil.isBooleanType(type)) {
myVisitor.report(JavaErrorKinds.TYPE_INCOMPATIBLE.create(
expression, new JavaIncompatibleTypeErrorContext(PsiTypes.booleanType(), type)));
myVisitor.reportIncompatibleType(PsiTypes.booleanType(), type, expression);
}
else if (expression == assertStatement.getAssertDescription() && TypeConversionUtil.isVoidType(type)) {
myVisitor.report(JavaErrorKinds.TYPE_VOID_NOT_ALLOWED.create(expression));
@@ -350,7 +347,7 @@ final class StatementChecker {
if (type == null) return;
if (type instanceof PsiPrimitiveType || TypeConversionUtil.isNullType(type)) {
PsiClassType objectType = PsiType.getJavaLangObject(myVisitor.file().getManager(), expression.getResolveScope());
myVisitor.report(JavaErrorKinds.TYPE_INCOMPATIBLE.create(expression, new JavaIncompatibleTypeErrorContext(objectType, type)));
myVisitor.reportIncompatibleType(objectType, type, expression);
}
}
}
@@ -263,8 +263,7 @@ final class SwitchChecker {
}
}
if (!TypeConversionUtil.isBooleanType(guardingExpr.getType())) {
myVisitor.report(JavaErrorKinds.TYPE_INCOMPATIBLE.create(
guardingExpr, new JavaIncompatibleTypeErrorContext(PsiTypes.booleanType(), guardingExpr.getType())));
myVisitor.reportIncompatibleType(PsiTypes.booleanType(), guardingExpr.getType(), guardingExpr);
return;
}
Object constVal = JavaPsiFacade.getInstance(myVisitor.project()).getConstantEvaluationHelper().computeConstantExpression(guardingExpr);
@@ -305,8 +304,7 @@ final class SwitchChecker {
}
if (label instanceof PsiExpression expr) {
if (selectorType.equals(PsiTypes.nullType())) {
myVisitor.report(
JavaErrorKinds.TYPE_INCOMPATIBLE.create(expr, new JavaIncompatibleTypeErrorContext(selectorType, expr.getType())));
myVisitor.reportIncompatibleType(selectorType, expr.getType(), expr);
continue;
}
if (label instanceof PsiReferenceExpression ref) {
@@ -382,14 +380,13 @@ final class SwitchChecker {
(kind == JavaPsiSwitchUtil.SelectorKind.BOOLEAN && !(constValue instanceof Boolean))) {
PsiType unboxedType = PsiPrimitiveType.getOptionallyUnboxedType(selectorType);
if (unboxedType != null) {
myVisitor.report(JavaErrorKinds.TYPE_INCOMPATIBLE.create(
expr, new JavaIncompatibleTypeErrorContext(unboxedType, expr.getType())));
myVisitor.reportIncompatibleType(unboxedType, expr.getType(), expr);
}
}
return;
}
if (ConstantExpressionUtil.computeCastTo(constValue, selectorType) == null) {
myVisitor.report(JavaErrorKinds.TYPE_INCOMPATIBLE.create(expr, new JavaIncompatibleTypeErrorContext(selectorType, expr.getType())));
myVisitor.reportIncompatibleType(selectorType, expr.getType(), expr);
return;
}
if (kind == JavaPsiSwitchUtil.SelectorKind.INT || kind == JavaPsiSwitchUtil.SelectorKind.STRING) {
@@ -429,8 +426,7 @@ final class SwitchChecker {
myVisitor.report(JavaErrorKinds.UNSUPPORTED_FEATURE.create(elementToReport, JavaFeature.PRIMITIVE_TYPES_IN_PATTERNS));
}
else {
myVisitor.report(JavaErrorKinds.TYPE_INCOMPATIBLE.create(
elementToReport, new JavaIncompatibleTypeErrorContext(selectorType, patternType)));
myVisitor.reportIncompatibleType(selectorType, patternType, elementToReport);
}
return;
}
@@ -2,7 +2,6 @@
package com.intellij.java.codeserver.highlighting;
import com.intellij.java.codeserver.highlighting.errors.JavaErrorKinds;
import com.intellij.java.codeserver.highlighting.errors.JavaIncompatibleTypeErrorContext;
import com.intellij.psi.*;
import com.intellij.psi.impl.IncompleteModelUtil;
import com.intellij.psi.util.PsiTreeUtil;
@@ -186,7 +185,7 @@ final class TypeChecker {
PsiClassType throwable = factory.createTypeByFQClassName(CommonClassNames.JAVA_LANG_THROWABLE, context.getResolveScope());
if (type != null && !TypeConversionUtil.isAssignable(throwable, type) &&
!(myVisitor.isIncompleteModel() && IncompleteModelUtil.isPotentiallyConvertible(throwable, type, context))) {
myVisitor.report(JavaErrorKinds.TYPE_INCOMPATIBLE.create(context, new JavaIncompatibleTypeErrorContext(throwable, type)));
myVisitor.reportIncompatibleType(throwable, type, context);
}
}
}
@@ -1658,7 +1658,7 @@ public final class JavaErrorKinds {
}
/**
* Context for errors related to annotation value
* Context for errors related to the annotation value
* @param method corresponding annotation method
* @param expectedType expected value type
* @param fromDefaultValue if true, the error is reported for the method default value, rather than for use site
@@ -1689,7 +1689,7 @@ public final class JavaErrorKinds {
/**
* A context for {@link #CONSTRUCTOR_AMBIGUOUS_IMPLICIT_CALL} error kind
* @param psiClass a class where ambiguous call is performed
* @param psiClass a class where an ambiguous call is performed
* @param candidate1 first constructor candidate in super class
* @param candidate2 second constructor candidate in super class
*/
@@ -0,0 +1,8 @@
class Test {
void test() {
Object obj = <error descr="Target type of a lambda conversion must be an interface">x -> {
String s = x;
x = "hello";
}</error>;
}
}
@@ -13,7 +13,7 @@ class AssignmentToLambdaParameter {
}
void x() {
Runnable r = a -> <error descr="Incompatible types. Found: 'java.lang.String', required: '<lambda parameter>'">a = ""</error>;
Runnable r = <error descr="Wrong number of parameters in lambda expression: expected 0 but found 1">a</error> -> a = "";
}
}
@@ -151,6 +151,7 @@ class NewLambdaHighlightingTest extends LightJavaCodeInsightFixtureTestCase5 {
@Test void testLambdaWithExplicitTypeAndTargetTypeParameter() { doTest(); }
@Test void testAmbiguousConstructorCallWithLambdaInside() { doTest(); }
@Test void testMultiResolveSameFunction() {doTest();}
@Test void testWrongTargetTypeDoNotReportIncompatibleTypeInside() {doTest();}
@Override
protected @NotNull String getRelativePath() {