KT-5068: Introduce a special diagnostic message for TYPE_MISMATCH cases such as 'fun f(): Int = { 1 }'.

This commit is contained in:
Dmitry Petrov
2016-05-20 16:27:03 +03:00
parent 8b06d919b4
commit 968ed3f091
8 changed files with 108 additions and 2 deletions
@@ -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 }
@@ -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);
+1 -1
View File
@@ -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");