diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java index 5686c1e0f91..ac35425c555 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java @@ -735,6 +735,7 @@ public interface Errors { // Type mismatch DiagnosticFactory2 TYPE_MISMATCH = DiagnosticFactory2.create(ERROR); + DiagnosticFactory1 TYPE_MISMATCH_DUE_TO_EQUALS_LAMBDA_IN_FUN = DiagnosticFactory1.create(ERROR); DiagnosticFactory1 TYPE_MISMATCH_DUE_TO_TYPE_PROJECTIONS = DiagnosticFactory1.create(ERROR); DiagnosticFactory2 MEMBER_PROJECTED_OUT = DiagnosticFactory2.create(ERROR); DiagnosticFactory1 RETURN_TYPE_MISMATCH = DiagnosticFactory1.create(ERROR); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/diagnosticUtils.kt b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/diagnosticUtils.kt index 8a8ea25d0eb..cc9601e137d 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/diagnosticUtils.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/diagnosticUtils.kt @@ -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 } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java index dd01cec7677..70c2cff57c0 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java @@ -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() { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DataFlowAnalyzer.java b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DataFlowAnalyzer.java index d295c994976..589a62ef598 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DataFlowAnalyzer.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DataFlowAnalyzer.java @@ -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); diff --git a/compiler/testData/diagnostics/tests/FunctionReturnTypes.kt b/compiler/testData/diagnostics/tests/FunctionReturnTypes.kt index 4743893d877..0b65ed2b5d1 100644 --- a/compiler/testData/diagnostics/tests/FunctionReturnTypes.kt +++ b/compiler/testData/diagnostics/tests/FunctionReturnTypes.kt @@ -39,7 +39,7 @@ fun intBlock() : Int {return 1} fun intBlock1() : Int {1} fun intString(): Int = "s" -fun intFunctionLiteral(): Int = { 10 } +fun intFunctionLiteral(): Int = { 10 } fun blockReturnUnitMismatch() : Int {return} fun blockReturnValueTypeMismatch() : Int {return 3.4} diff --git a/compiler/testData/diagnostics/tests/declarationChecks/ScalaLikeNamedFun.kt b/compiler/testData/diagnostics/tests/declarationChecks/ScalaLikeNamedFun.kt new file mode 100644 index 00000000000..9c8812cb13b --- /dev/null +++ b/compiler/testData/diagnostics/tests/declarationChecks/ScalaLikeNamedFun.kt @@ -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 = { return 1 } +fun test2(): Int = { 1 } +val test3: () -> Int = fun (): Int = { return 1 } +val test4: () -> Int = fun (): Int = { 1 } +fun test5(): Int { return { 1 } } +fun test6(): Int = fun (): Int = 1 + +fun outer() { + fun test1(): Int = { return 1 } + fun test2(): Int = { 1 } + val test3: () -> Int = fun (): Int = { return 1 } + val test4: () -> Int = fun (): Int = { 1 } + fun test5(): Int { return { 1 } } + fun test6(): Int = fun (): Int = 1 +} + +class Outer { + fun test1(): Int = { return 1 } + fun test2(): Int = { 1 } + val test3: () -> Int = fun (): Int = { return 1 } + val test4: () -> Int = fun (): Int = { 1 } + fun test5(): Int { return { 1 } } + fun test6(): Int = fun (): Int = 1 + + class Nested { + fun test1(): Int = { return 1 } + fun test2(): Int = { 1 } + val test3: () -> Int = fun (): Int = { return 1 } + val test4: () -> Int = fun (): Int = { 1 } + fun test5(): Int { return { 1 } } + fun test6(): Int = fun (): Int = 1 + } +} diff --git a/compiler/testData/diagnostics/tests/declarationChecks/ScalaLikeNamedFun.txt b/compiler/testData/diagnostics/tests/declarationChecks/ScalaLikeNamedFun.txt new file mode 100644 index 00000000000..750d99f8e96 --- /dev/null +++ b/compiler/testData/diagnostics/tests/declarationChecks/ScalaLikeNamedFun.txt @@ -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 + } +} diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index 30e65cd4418..e675f092499 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -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");