KT-5068: Introduce a special diagnostic message for TYPE_MISMATCH cases such as 'fun f(): Int = { 1 }'.
This commit is contained in:
@@ -735,6 +735,7 @@ public interface Errors {
|
||||
// Type mismatch
|
||||
|
||||
DiagnosticFactory2<KtExpression, KotlinType, KotlinType> TYPE_MISMATCH = DiagnosticFactory2.create(ERROR);
|
||||
DiagnosticFactory1<KtElement, KotlinType> TYPE_MISMATCH_DUE_TO_EQUALS_LAMBDA_IN_FUN = DiagnosticFactory1.create(ERROR);
|
||||
DiagnosticFactory1<KtElement, TypeMismatchDueToTypeProjectionsData> TYPE_MISMATCH_DUE_TO_TYPE_PROJECTIONS = DiagnosticFactory1.create(ERROR);
|
||||
DiagnosticFactory2<KtElement, CallableDescriptor, KotlinType> MEMBER_PROJECTED_OUT = DiagnosticFactory2.create(ERROR);
|
||||
DiagnosticFactory1<KtExpression, KotlinType> RETURN_TYPE_MISMATCH = DiagnosticFactory1.create(ERROR);
|
||||
|
||||
@@ -16,9 +16,14 @@
|
||||
|
||||
package org.jetbrains.kotlin.diagnostics
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiWhiteSpace
|
||||
import org.jetbrains.kotlin.builtins.isFunctionType
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.psi.KtElement
|
||||
import org.jetbrains.kotlin.psi.KtLambdaExpression
|
||||
import org.jetbrains.kotlin.psi.KtNamedFunction
|
||||
import org.jetbrains.kotlin.resolve.BindingTrace
|
||||
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.getEffectiveExpectedType
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||
@@ -115,3 +120,22 @@ class TypeMismatchDueToTypeProjectionsData(
|
||||
val receiverType: KotlinType,
|
||||
val callableDescriptor: CallableDescriptor
|
||||
)
|
||||
|
||||
fun ResolutionContext<*>.reportTypeMismatchDueToScalaLikeNamedFunctionSyntax(
|
||||
expression: KtElement,
|
||||
expectedType: KotlinType,
|
||||
expressionType: KotlinType?
|
||||
): Boolean {
|
||||
if (expressionType == null) return false
|
||||
|
||||
if (expressionType.isFunctionType && !expectedType.isFunctionType && isScalaLikeEqualsBlock(expression)) {
|
||||
trace.report(Errors.TYPE_MISMATCH_DUE_TO_EQUALS_LAMBDA_IN_FUN.on(expression, expectedType))
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
private fun isScalaLikeEqualsBlock(expression: KtElement): Boolean =
|
||||
expression is KtLambdaExpression &&
|
||||
expression.parent.let { it is KtNamedFunction && it.equalsToken != null }
|
||||
|
||||
+3
@@ -114,6 +114,9 @@ public class DefaultErrorMessages {
|
||||
MAP.put(ACCESSOR_PARAMETER_NAME_SHADOWING, "Accessor parameter name 'field' is shadowed by backing field variable");
|
||||
|
||||
MAP.put(TYPE_MISMATCH, "Type mismatch: inferred type is {1} but {0} was expected", RENDER_TYPE, RENDER_TYPE);
|
||||
MAP.put(TYPE_MISMATCH_DUE_TO_EQUALS_LAMBDA_IN_FUN,
|
||||
"Inferred type is a function type, but a non-function type {0} was expected. Use either '= ...' or '{ ... }', but not both.",
|
||||
RENDER_TYPE);
|
||||
MAP.put(TYPE_MISMATCH_DUE_TO_TYPE_PROJECTIONS,
|
||||
"Type mismatch: inferred type is {1} but {0} was expected. Projected type {2} restricts use of {3}",
|
||||
new MultiRenderer<TypeMismatchDueToTypeProjectionsData>() {
|
||||
|
||||
@@ -260,7 +260,8 @@ public class DataFlowAnalyzer {
|
||||
SmartCastResult castResult = checkPossibleCast(expressionType, expression, c);
|
||||
if (castResult != null) return castResult.getResultType();
|
||||
|
||||
if (!DiagnosticUtilsKt.reportTypeMismatchDueToTypeProjection(c, expression, c.expectedType, expressionType)) {
|
||||
if (!DiagnosticUtilsKt.reportTypeMismatchDueToTypeProjection(c, expression, c.expectedType, expressionType) &&
|
||||
!DiagnosticUtilsKt.reportTypeMismatchDueToScalaLikeNamedFunctionSyntax(c, expression, c.expectedType, expressionType)) {
|
||||
c.trace.report(TYPE_MISMATCH.on(expression, c.expectedType, expressionType));
|
||||
}
|
||||
hasError.set(true);
|
||||
|
||||
@@ -39,7 +39,7 @@ fun intBlock() : Int {return 1}
|
||||
fun intBlock1() : Int {<!UNUSED_EXPRESSION!>1<!><!NO_RETURN_IN_FUNCTION_WITH_BLOCK_BODY!>}<!>
|
||||
|
||||
fun intString(): Int = <!TYPE_MISMATCH!>"s"<!>
|
||||
fun intFunctionLiteral(): Int = <!TYPE_MISMATCH!>{ 10 }<!>
|
||||
fun intFunctionLiteral(): Int = <!TYPE_MISMATCH_DUE_TO_EQUALS_LAMBDA_IN_FUN!>{ 10 }<!>
|
||||
|
||||
fun blockReturnUnitMismatch() : Int {<!RETURN_TYPE_MISMATCH!>return<!>}
|
||||
fun blockReturnValueTypeMismatch() : Int {return <!CONSTANT_EXPECTED_TYPE_MISMATCH!>3.4<!>}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_VARIABLE
|
||||
// KT-5068 Add special error for scala-like syntax 'fun foo(): Int = { 1 }'
|
||||
|
||||
fun test1(): Int = <!TYPE_MISMATCH_DUE_TO_EQUALS_LAMBDA_IN_FUN!>{ <!RETURN_NOT_ALLOWED!>return 1<!> }<!>
|
||||
fun test2(): Int = <!TYPE_MISMATCH_DUE_TO_EQUALS_LAMBDA_IN_FUN!>{ 1 }<!>
|
||||
val test3: () -> Int = fun (): Int = <!TYPE_MISMATCH_DUE_TO_EQUALS_LAMBDA_IN_FUN!>{ <!RETURN_NOT_ALLOWED!>return 1<!> }<!>
|
||||
val test4: () -> Int = fun (): Int = <!TYPE_MISMATCH_DUE_TO_EQUALS_LAMBDA_IN_FUN!>{ 1 }<!>
|
||||
fun test5(): Int { return <!TYPE_MISMATCH!>{ 1 }<!> }
|
||||
fun test6(): Int = <!TYPE_MISMATCH!>fun (): Int = 1<!>
|
||||
|
||||
fun outer() {
|
||||
fun test1(): Int = <!TYPE_MISMATCH_DUE_TO_EQUALS_LAMBDA_IN_FUN!>{ <!RETURN_NOT_ALLOWED!>return 1<!> }<!>
|
||||
fun test2(): Int = <!TYPE_MISMATCH_DUE_TO_EQUALS_LAMBDA_IN_FUN!>{ 1 }<!>
|
||||
val test3: () -> Int = fun (): Int = <!TYPE_MISMATCH_DUE_TO_EQUALS_LAMBDA_IN_FUN!>{ <!RETURN_NOT_ALLOWED!>return 1<!> }<!>
|
||||
val test4: () -> Int = fun (): Int = <!TYPE_MISMATCH_DUE_TO_EQUALS_LAMBDA_IN_FUN!>{ 1 }<!>
|
||||
fun test5(): Int { return <!TYPE_MISMATCH!>{ 1 }<!> }
|
||||
fun test6(): Int = <!TYPE_MISMATCH!>fun (): Int = 1<!>
|
||||
}
|
||||
|
||||
class Outer {
|
||||
fun test1(): Int = <!TYPE_MISMATCH_DUE_TO_EQUALS_LAMBDA_IN_FUN!>{ <!RETURN_NOT_ALLOWED!>return 1<!> }<!>
|
||||
fun test2(): Int = <!TYPE_MISMATCH_DUE_TO_EQUALS_LAMBDA_IN_FUN!>{ 1 }<!>
|
||||
val test3: () -> Int = fun (): Int = <!TYPE_MISMATCH_DUE_TO_EQUALS_LAMBDA_IN_FUN!>{ <!RETURN_NOT_ALLOWED!>return 1<!> }<!>
|
||||
val test4: () -> Int = fun (): Int = <!TYPE_MISMATCH_DUE_TO_EQUALS_LAMBDA_IN_FUN!>{ 1 }<!>
|
||||
fun test5(): Int { return <!TYPE_MISMATCH!>{ 1 }<!> }
|
||||
fun test6(): Int = <!TYPE_MISMATCH!>fun (): Int = 1<!>
|
||||
|
||||
class Nested {
|
||||
fun test1(): Int = <!TYPE_MISMATCH_DUE_TO_EQUALS_LAMBDA_IN_FUN!>{ <!RETURN_NOT_ALLOWED!>return 1<!> }<!>
|
||||
fun test2(): Int = <!TYPE_MISMATCH_DUE_TO_EQUALS_LAMBDA_IN_FUN!>{ 1 }<!>
|
||||
val test3: () -> Int = fun (): Int = <!TYPE_MISMATCH_DUE_TO_EQUALS_LAMBDA_IN_FUN!>{ <!RETURN_NOT_ALLOWED!>return 1<!> }<!>
|
||||
val test4: () -> Int = fun (): Int = <!TYPE_MISMATCH_DUE_TO_EQUALS_LAMBDA_IN_FUN!>{ 1 }<!>
|
||||
fun test5(): Int { return <!TYPE_MISMATCH!>{ 1 }<!> }
|
||||
fun test6(): Int = <!TYPE_MISMATCH!>fun (): Int = 1<!>
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package
|
||||
|
||||
public val test3: () -> kotlin.Int
|
||||
public val test4: () -> kotlin.Int
|
||||
public fun outer(): kotlin.Unit
|
||||
public fun test1(): kotlin.Int
|
||||
public fun test2(): kotlin.Int
|
||||
public fun test5(): kotlin.Int
|
||||
public fun test6(): kotlin.Int
|
||||
|
||||
public final class Outer {
|
||||
public constructor Outer()
|
||||
public final val test3: () -> kotlin.Int
|
||||
public final val test4: () -> kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public final fun test1(): kotlin.Int
|
||||
public final fun test2(): kotlin.Int
|
||||
public final fun test5(): kotlin.Int
|
||||
public final fun test6(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
|
||||
public final class Nested {
|
||||
public constructor Nested()
|
||||
public final val test3: () -> kotlin.Int
|
||||
public final val test4: () -> kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public final fun test1(): kotlin.Int
|
||||
public final fun test2(): kotlin.Int
|
||||
public final fun test5(): kotlin.Int
|
||||
public final fun test6(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
}
|
||||
@@ -4512,6 +4512,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("ScalaLikeNamedFun.kt")
|
||||
public void testScalaLikeNamedFun() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/declarationChecks/ScalaLikeNamedFun.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("unambiguousObjectExpressionType.kt")
|
||||
public void testUnambiguousObjectExpressionType() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/declarationChecks/unambiguousObjectExpressionType.kt");
|
||||
|
||||
Reference in New Issue
Block a user