Introduce FirFunctionReturnTypeMismatchChecker
This commit is contained in:
@@ -11,7 +11,7 @@ interface KtLightMethod : PsiElement
|
|||||||
// With covariant array here we do not visit lambda (it.usage is KtLightMethod) below
|
// With covariant array here we do not visit lambda (it.usage is KtLightMethod) below
|
||||||
// Problem disappears if 'out' is removed
|
// Problem disappears if 'out' is removed
|
||||||
fun <T> Array<out T>.filterNot(f: (T) -> Boolean): List<T> {
|
fun <T> Array<out T>.filterNot(f: (T) -> Boolean): List<T> {
|
||||||
return this
|
return <!RETURN_TYPE_MISMATCH!>this<!>
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <T> Array<T>.toList(): List<T>? = null
|
fun <T> Array<T>.toList(): List<T>? = null
|
||||||
|
|||||||
+1
-1
@@ -57,7 +57,7 @@ open class J() : S() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
open class Base<T : X, Z : T> {
|
open class Base<T : X, Z : T> {
|
||||||
open fun kek(): Z = Z()
|
open fun kek(): Z = <!RETURN_TYPE_MISMATCH!>Z()<!>
|
||||||
}
|
}
|
||||||
|
|
||||||
open class GoodDerrived : Base<Y, W>() {
|
open class GoodDerrived : Base<Y, W>() {
|
||||||
|
|||||||
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
|
|
||||||
class Bar {
|
class Bar {
|
||||||
operator fun invoke(): Foo { return this } // (1)
|
operator fun invoke(): Foo { return <!RETURN_TYPE_MISMATCH!>this<!> } // (1)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -11,7 +11,7 @@ fun x() {
|
|||||||
class Foo {
|
class Foo {
|
||||||
|
|
||||||
|
|
||||||
operator fun Bar.invoke(): Foo { return this } // (2)
|
operator fun Bar.invoke(): Foo { return <!RETURN_TYPE_MISMATCH!>this<!> } // (2)
|
||||||
|
|
||||||
val x: Bar = Bar()
|
val x: Bar = Bar()
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
|
|
||||||
|
|
||||||
class Bar {
|
class Bar {
|
||||||
fun FooBar.invoke(): Bar = this
|
fun FooBar.invoke(): Bar = <!RETURN_TYPE_MISMATCH!>this<!>
|
||||||
}
|
}
|
||||||
|
|
||||||
class Buz
|
class Buz
|
||||||
|
|||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
<!CONFLICTING_OVERLOADS!>fun bar(x: String): Int<!> = 1
|
<!CONFLICTING_OVERLOADS!>fun bar(x: String): Int<!> = 1
|
||||||
<!CONFLICTING_OVERLOADS!>fun bar(x: String): Double<!> = 1
|
<!CONFLICTING_OVERLOADS!>fun bar(x: String): Double<!> = <!RETURN_TYPE_MISMATCH!>1<!>
|
||||||
|
|
||||||
fun baz(x: String): Int = 1
|
fun baz(x: String): Int = 1
|
||||||
fun <T, R> foobaz(x: T): R = TODO()
|
fun <T, R> foobaz(x: T): R = TODO()
|
||||||
|
|||||||
+1
-1
@@ -5,7 +5,7 @@ fun checkNotNull(x: Any?) {
|
|||||||
returns(true) implies (x != null)
|
returns(true) implies (x != null)
|
||||||
returns(false) implies (x == null)
|
returns(false) implies (x == null)
|
||||||
}
|
}
|
||||||
return x != null
|
return <!RETURN_TYPE_MISMATCH!>x != null<!>
|
||||||
}
|
}
|
||||||
|
|
||||||
fun trickyRequireNotNull(x: Any?) {
|
fun trickyRequireNotNull(x: Any?) {
|
||||||
|
|||||||
+1
-1
@@ -5,7 +5,7 @@ fun checkIsString(x: Any) {
|
|||||||
returns(true) implies (x is String)
|
returns(true) implies (x is String)
|
||||||
returns(false) implies (x !is String)
|
returns(false) implies (x !is String)
|
||||||
}
|
}
|
||||||
return x is String
|
return <!RETURN_TYPE_MISMATCH!>x is String<!>
|
||||||
}
|
}
|
||||||
|
|
||||||
fun test(x: Any) {
|
fun test(x: Any) {
|
||||||
|
|||||||
+77
@@ -0,0 +1,77 @@
|
|||||||
|
FILE: basic.kt
|
||||||
|
public final fun illegalReturnIf(): R|kotlin/Char| {
|
||||||
|
^illegalReturnIf when () {
|
||||||
|
CMP(<, Int(1).R|kotlin/Int.compareTo|(Int(2))) -> {
|
||||||
|
Char(a)
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
Int(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
public final fun foo(): R|kotlin/String| {
|
||||||
|
^foo Int(1)
|
||||||
|
}
|
||||||
|
public final fun ok(): R|kotlin/Int| {
|
||||||
|
^ok Int(1)
|
||||||
|
}
|
||||||
|
public final fun okOneLineFunction(): R|kotlin/Int| {
|
||||||
|
^okOneLineFunction Int(10).R|kotlin/Int.plus|(Int(1))
|
||||||
|
}
|
||||||
|
public final fun errorOneLineFunction(): R|kotlin/String| {
|
||||||
|
^errorOneLineFunction Int(10).R|kotlin/Int.plus|(Int(1))
|
||||||
|
}
|
||||||
|
public final class A : R|kotlin/Any| {
|
||||||
|
public constructor(): R|A| {
|
||||||
|
super<R|kotlin/Any|>()
|
||||||
|
}
|
||||||
|
|
||||||
|
public final fun bar(): R|kotlin/Unit| {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
public final infix fun R|() -> kotlin/Unit|.foo(x: R|A.() -> kotlin/Unit|): R|kotlin/Unit| {
|
||||||
|
}
|
||||||
|
public final fun okWithLambda(): R|kotlin/String| {
|
||||||
|
foo@fun <anonymous>(): R|kotlin/Unit| <inline=Unknown> {
|
||||||
|
^@foo Unit
|
||||||
|
}
|
||||||
|
.R|/foo|(foo@fun R|A|.<anonymous>(): R|kotlin/Unit| <inline=NoInline> {
|
||||||
|
this@R|special/anonymous|.R|/A.bar|()
|
||||||
|
^@foo Unit
|
||||||
|
}
|
||||||
|
)
|
||||||
|
^okWithLambda String()
|
||||||
|
}
|
||||||
|
public final fun errorWithLambda(): R|kotlin/String| {
|
||||||
|
foo@fun <anonymous>(): R|kotlin/Unit| <inline=Unknown> {
|
||||||
|
^@foo Unit
|
||||||
|
}
|
||||||
|
.R|/foo|(foo@fun R|A|.<anonymous>(): R|kotlin/Unit| <inline=NoInline> {
|
||||||
|
this@R|special/anonymous|.R|/A.bar|()
|
||||||
|
^@foo Int(10)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
^errorWithLambda String()
|
||||||
|
}
|
||||||
|
public final fun blockReturnValueTypeMatch1(): R|kotlin/Int| {
|
||||||
|
when () {
|
||||||
|
CMP(>, Int(1).R|kotlin/Int.compareTo|(Int(2))) -> {
|
||||||
|
^blockReturnValueTypeMatch1 Double(1.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
^blockReturnValueTypeMatch1 Double(2.0)
|
||||||
|
}
|
||||||
|
public final fun blockReturnValueTypeMatch2(): R|kotlin/Int| {
|
||||||
|
when () {
|
||||||
|
CMP(>, Int(1).R|kotlin/Int.compareTo|(Int(2))) -> {
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
^blockReturnValueTypeMatch2 Double(1.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
^blockReturnValueTypeMatch2 Double(2.0)
|
||||||
|
}
|
||||||
+55
@@ -0,0 +1,55 @@
|
|||||||
|
// bug: type of the expression in return statement is Char
|
||||||
|
fun illegalReturnIf(): Char {
|
||||||
|
return if (1 < 2) 'a' else { 1 }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun foo(): String {
|
||||||
|
return <!RETURN_TYPE_MISMATCH!>1<!>
|
||||||
|
}
|
||||||
|
|
||||||
|
fun ok(): Int {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
fun okOneLineFunction(): Int = 10 + 1
|
||||||
|
fun errorOneLineFunction(): String = <!RETURN_TYPE_MISMATCH!>10 + 1<!>
|
||||||
|
|
||||||
|
class A {
|
||||||
|
fun bar() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
infix fun (() -> Unit).foo(x: A.() -> Unit) {}
|
||||||
|
|
||||||
|
fun okWithLambda(): String {
|
||||||
|
{
|
||||||
|
return@foo
|
||||||
|
} foo {
|
||||||
|
bar()
|
||||||
|
return@foo
|
||||||
|
}
|
||||||
|
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// no report due bad returns in lambda
|
||||||
|
fun errorWithLambda(): String {
|
||||||
|
{
|
||||||
|
return@foo
|
||||||
|
} foo {
|
||||||
|
bar()
|
||||||
|
return@foo 10
|
||||||
|
}
|
||||||
|
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
fun blockReturnValueTypeMatch1() : Int {
|
||||||
|
if (1 > 2)
|
||||||
|
return <!RETURN_TYPE_MISMATCH!>1.0<!>
|
||||||
|
return <!RETURN_TYPE_MISMATCH!>2.0<!>
|
||||||
|
}
|
||||||
|
fun blockReturnValueTypeMatch2() : Int {
|
||||||
|
if (1 > 2)
|
||||||
|
else return <!RETURN_TYPE_MISMATCH!>1.0<!>
|
||||||
|
return <!RETURN_TYPE_MISMATCH!>2.0<!>
|
||||||
|
}
|
||||||
+16
@@ -4781,6 +4781,22 @@ public class FirDiagnosticTestGenerated extends AbstractFirDiagnosticTest {
|
|||||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/resolveWithStdlib/diagnostics"), Pattern.compile("^([^.]+)\\.kt$"), null, true);
|
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/resolveWithStdlib/diagnostics"), Pattern.compile("^([^.]+)\\.kt$"), null, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
@TestMetadata("compiler/fir/analysis-tests/testData/resolveWithStdlib/diagnostics/functionReturnTypeMismatchChecker")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
public class FunctionReturnTypeMismatchChecker {
|
||||||
|
@Test
|
||||||
|
public void testAllFilesPresentInFunctionReturnTypeMismatchChecker() throws Exception {
|
||||||
|
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/resolveWithStdlib/diagnostics/functionReturnTypeMismatchChecker"), Pattern.compile("^([^.]+)\\.kt$"), null, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("basic.kt")
|
||||||
|
public void testBasic() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/diagnostics/functionReturnTypeMismatchChecker/basic.kt");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Nested
|
@Nested
|
||||||
@TestMetadata("compiler/fir/analysis-tests/testData/resolveWithStdlib/diagnostics/initializerTypeMismatchChecker")
|
@TestMetadata("compiler/fir/analysis-tests/testData/resolveWithStdlib/diagnostics/initializerTypeMismatchChecker")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
|||||||
+17
@@ -4851,6 +4851,23 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos
|
|||||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/resolveWithStdlib/diagnostics"), Pattern.compile("^([^.]+)\\.kt$"), null, true);
|
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/resolveWithStdlib/diagnostics"), Pattern.compile("^([^.]+)\\.kt$"), null, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
@TestMetadata("compiler/fir/analysis-tests/testData/resolveWithStdlib/diagnostics/functionReturnTypeMismatchChecker")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
@Execution(ExecutionMode.SAME_THREAD)
|
||||||
|
public class FunctionReturnTypeMismatchChecker {
|
||||||
|
@Test
|
||||||
|
public void testAllFilesPresentInFunctionReturnTypeMismatchChecker() throws Exception {
|
||||||
|
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/resolveWithStdlib/diagnostics/functionReturnTypeMismatchChecker"), Pattern.compile("^([^.]+)\\.kt$"), null, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("basic.kt")
|
||||||
|
public void testBasic() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/diagnostics/functionReturnTypeMismatchChecker/basic.kt");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Nested
|
@Nested
|
||||||
@TestMetadata("compiler/fir/analysis-tests/testData/resolveWithStdlib/diagnostics/initializerTypeMismatchChecker")
|
@TestMetadata("compiler/fir/analysis-tests/testData/resolveWithStdlib/diagnostics/initializerTypeMismatchChecker")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
|||||||
+1
@@ -57,6 +57,7 @@ enum class PositioningStrategy(private val strategy: String? = null) {
|
|||||||
SUPERTYPES_LIST,
|
SUPERTYPES_LIST,
|
||||||
RETURN_WITH_LABEL,
|
RETURN_WITH_LABEL,
|
||||||
ASSIGNMENT_VALUE,
|
ASSIGNMENT_VALUE,
|
||||||
|
WHOLE_ELEMENT,
|
||||||
INT_LITERAL_OUT_OF_RANGE,
|
INT_LITERAL_OUT_OF_RANGE,
|
||||||
FLOAT_LITERAL_OUT_OF_RANGE,
|
FLOAT_LITERAL_OUT_OF_RANGE,
|
||||||
LONG_LITERAL_SUFFIX,
|
LONG_LITERAL_SUFFIX,
|
||||||
|
|||||||
+5
@@ -317,6 +317,11 @@ object DIAGNOSTICS_LIST : DiagnosticList() {
|
|||||||
parameter<Name>("typeParameterName")
|
parameter<Name>("typeParameterName")
|
||||||
parameter<FirDeclaration>("typeParametersOwner")
|
parameter<FirDeclaration>("typeParametersOwner")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val RETURN_TYPE_MISMATCH by error<FirSourceElement, KtExpression>(PositioningStrategy.WHOLE_ELEMENT) {
|
||||||
|
parameter<ConeKotlinType>("expected")
|
||||||
|
parameter<ConeKotlinType>("actual")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val REFLECTION by object : DiagnosticGroup("Reflection") {
|
val REFLECTION by object : DiagnosticGroup("Reflection") {
|
||||||
|
|||||||
@@ -235,6 +235,7 @@ object FirErrors {
|
|||||||
val REPEATED_BOUND by error0<FirSourceElement, KtTypeReference>()
|
val REPEATED_BOUND by error0<FirSourceElement, KtTypeReference>()
|
||||||
val CONFLICTING_UPPER_BOUNDS by error1<FirSourceElement, KtNamedDeclaration, FirTypeParameterSymbol>()
|
val CONFLICTING_UPPER_BOUNDS by error1<FirSourceElement, KtNamedDeclaration, FirTypeParameterSymbol>()
|
||||||
val NAME_IN_CONSTRAINT_IS_NOT_A_TYPE_PARAMETER by error2<FirSourceElement, KtSimpleNameExpression, Name, FirDeclaration>()
|
val NAME_IN_CONSTRAINT_IS_NOT_A_TYPE_PARAMETER by error2<FirSourceElement, KtSimpleNameExpression, Name, FirDeclaration>()
|
||||||
|
val RETURN_TYPE_MISMATCH by error2<FirSourceElement, KtExpression, ConeKotlinType, ConeKotlinType>(SourceElementPositioningStrategies.WHOLE_ELEMENT)
|
||||||
|
|
||||||
// Reflection
|
// Reflection
|
||||||
val EXTENSION_IN_CLASS_REFERENCE_NOT_ALLOWED by error1<FirSourceElement, KtExpression, FirCallableDeclaration<*>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
|
val EXTENSION_IN_CLASS_REFERENCE_NOT_ALLOWED by error1<FirSourceElement, KtExpression, FirCallableDeclaration<*>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
|
||||||
|
|||||||
@@ -16,11 +16,14 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.overrideModifier
|
|||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.visibilityModifier
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.visibilityModifier
|
||||||
import org.jetbrains.kotlin.fir.analysis.getChild
|
import org.jetbrains.kotlin.fir.analysis.getChild
|
||||||
import org.jetbrains.kotlin.fir.declarations.*
|
import org.jetbrains.kotlin.fir.declarations.*
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.FirComponentCall
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
|
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
|
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
|
||||||
import org.jetbrains.kotlin.fir.expressions.impl.FirEmptyExpressionBlock
|
import org.jetbrains.kotlin.fir.expressions.impl.FirEmptyExpressionBlock
|
||||||
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
|
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
|
||||||
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.inference.isBuiltinFunctionalType
|
||||||
import org.jetbrains.kotlin.fir.resolve.symbolProvider
|
import org.jetbrains.kotlin.fir.resolve.symbolProvider
|
||||||
import org.jetbrains.kotlin.fir.resolve.toSymbol
|
import org.jetbrains.kotlin.fir.resolve.toSymbol
|
||||||
import org.jetbrains.kotlin.fir.resolve.transformers.firClassLike
|
import org.jetbrains.kotlin.fir.resolve.transformers.firClassLike
|
||||||
@@ -416,3 +419,38 @@ private fun lowerThanBound(context: ConeInferenceContext, argument: ConeKotlinTy
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun FirMemberDeclaration.isInlineOnly(): Boolean = isInline && hasAnnotation(INLINE_ONLY_ANNOTATION_CLASS_ID)
|
fun FirMemberDeclaration.isInlineOnly(): Boolean = isInline && hasAnnotation(INLINE_ONLY_ANNOTATION_CLASS_ID)
|
||||||
|
|
||||||
|
val FirProperty.isDestructuringDeclaration
|
||||||
|
get() = name.asString() == "<destruct>"
|
||||||
|
|
||||||
|
val FirExpression.isComponentCall
|
||||||
|
get() = this is FirComponentCall
|
||||||
|
|
||||||
|
fun isSubtypeForTypeMismatch(context: ConeInferenceContext, subtype: ConeKotlinType, supertype: ConeKotlinType): Boolean {
|
||||||
|
return AbstractTypeChecker.isSubtypeOf(context, subtype, supertype)
|
||||||
|
|| isSubtypeOfForFunctionalTypeReturningUnit(context.session.typeContext, subtype, supertype)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isSubtypeOfForFunctionalTypeReturningUnit(context: ConeInferenceContext, subtype: ConeKotlinType, supertype: ConeKotlinType): Boolean {
|
||||||
|
if (!supertype.isBuiltinFunctionalType(context.session)) return false
|
||||||
|
val functionalTypeReturnType = supertype.typeArguments.lastOrNull()
|
||||||
|
if ((functionalTypeReturnType as? ConeClassLikeType)?.isUnit == true) {
|
||||||
|
// We don't try to match return type for this case
|
||||||
|
// Dropping the return type (getting only the lambda args)
|
||||||
|
val superTypeArgs = supertype.typeArguments.dropLast(1)
|
||||||
|
val subTypeArgs = subtype.typeArguments.dropLast(1)
|
||||||
|
if (superTypeArgs.size != subTypeArgs.size) return false
|
||||||
|
|
||||||
|
for (i in superTypeArgs.indices) {
|
||||||
|
val subTypeArg = subTypeArgs[i].type ?: return false
|
||||||
|
val superTypeArg = superTypeArgs[i].type ?: return false
|
||||||
|
|
||||||
|
if (!AbstractTypeChecker.isSubtypeOf(context.session.typeContext, subTypeArg, superTypeArg)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|||||||
+7
-46
@@ -6,67 +6,28 @@
|
|||||||
package org.jetbrains.kotlin.fir.analysis.checkers.declaration
|
package org.jetbrains.kotlin.fir.analysis.checkers.declaration
|
||||||
|
|
||||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.checkers.isComponentCall
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.checkers.isDestructuringDeclaration
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.checkers.isSubtypeForTypeMismatch
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INITIALIZER_TYPE_MISMATCH
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INITIALIZER_TYPE_MISMATCH
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirProperty
|
import org.jetbrains.kotlin.fir.declarations.FirProperty
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirComponentCall
|
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
|
||||||
import org.jetbrains.kotlin.fir.resolve.inference.isFunctionalType
|
|
||||||
import org.jetbrains.kotlin.fir.typeContext
|
import org.jetbrains.kotlin.fir.typeContext
|
||||||
import org.jetbrains.kotlin.fir.types.*
|
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||||
import org.jetbrains.kotlin.types.AbstractTypeChecker
|
import org.jetbrains.kotlin.fir.types.coneTypeSafe
|
||||||
|
|
||||||
object FirInitializerTypeMismatchChecker : FirPropertyChecker() {
|
object FirInitializerTypeMismatchChecker : FirPropertyChecker() {
|
||||||
override fun check(declaration: FirProperty, context: CheckerContext, reporter: DiagnosticReporter) {
|
override fun check(declaration: FirProperty, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||||
val initializer = declaration.initializer ?: return
|
val initializer = declaration.initializer ?: return
|
||||||
if (declaration.isDestructuringDeclaration) return
|
if (declaration.isDestructuringDeclaration) return
|
||||||
if (initializer.isComponent) return
|
if (initializer.isComponentCall) return
|
||||||
val propertyType = declaration.returnTypeRef.coneTypeSafe<ConeKotlinType>() ?: return
|
val propertyType = declaration.returnTypeRef.coneTypeSafe<ConeKotlinType>() ?: return
|
||||||
val expressionType = initializer.typeRef.coneTypeSafe<ConeKotlinType>() ?: return
|
val expressionType = initializer.typeRef.coneTypeSafe<ConeKotlinType>() ?: return
|
||||||
val typeContext = context.session.typeContext
|
val typeContext = context.session.typeContext
|
||||||
|
|
||||||
// hack: if property's type is (args) -> Unit, and lambda returns non-Unit value, the type of the lambda
|
if (!isSubtypeForTypeMismatch(typeContext, subtype = expressionType, supertype = propertyType)) {
|
||||||
// will be non-unit, but it's OK
|
|
||||||
if (propertyType.isFunctionalType(context.session)) {
|
|
||||||
// getting property's expected return type
|
|
||||||
val expectedType = propertyType.typeArguments.lastOrNull()
|
|
||||||
if ((expectedType as? ConeClassLikeType)?.isUnit == true) {
|
|
||||||
// dropping the return type (getting only the lambda args)
|
|
||||||
val expectedArgs = propertyType.typeArguments.dropLast(1)
|
|
||||||
val actualArgs = expressionType.typeArguments.dropLast(1)
|
|
||||||
if (compareTypesList(actualArgs, expectedArgs, typeContext)) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!AbstractTypeChecker.isSubtypeOf(typeContext, expressionType, propertyType)) {
|
|
||||||
val source = declaration.source ?: return
|
val source = declaration.source ?: return
|
||||||
reporter.report(INITIALIZER_TYPE_MISMATCH.on(source, propertyType, expressionType), context)
|
reporter.report(INITIALIZER_TYPE_MISMATCH.on(source, propertyType, expressionType), context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val FirProperty.isDestructuringDeclaration
|
|
||||||
get() = name.asString() == "<destruct>"
|
|
||||||
private val FirExpression.isComponent
|
|
||||||
get() = this is FirComponentCall
|
|
||||||
|
|
||||||
private fun compareTypesList(
|
|
||||||
expressionTypes: List<ConeTypeProjection>,
|
|
||||||
propertyTypes: List<ConeTypeProjection>,
|
|
||||||
context: ConeInferenceContext
|
|
||||||
): Boolean {
|
|
||||||
if (expressionTypes.size != propertyTypes.size) return false
|
|
||||||
|
|
||||||
for (i in expressionTypes.indices) {
|
|
||||||
val expressionType = expressionTypes[i].type ?: return false
|
|
||||||
val propertyType = propertyTypes[i].type ?: return false
|
|
||||||
|
|
||||||
if (!AbstractTypeChecker.isSubtypeOf(context.session.typeContext, expressionType, propertyType)) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
+37
@@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.fir.analysis.checkers.expression
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.checkers.isSubtypeForTypeMismatch
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.RETURN_TYPE_MISMATCH
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.FirReturnExpression
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.FirWhenExpression
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.isExhaustive
|
||||||
|
import org.jetbrains.kotlin.fir.typeContext
|
||||||
|
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||||
|
import org.jetbrains.kotlin.fir.types.coneTypeSafe
|
||||||
|
|
||||||
|
object FirFunctionReturnTypeMismatchChecker : FirReturnExpressionChecker() {
|
||||||
|
override fun check(expression: FirReturnExpression, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||||
|
if (expression.source == null) return
|
||||||
|
val targetElement = expression.target.labeledElement
|
||||||
|
if (targetElement !is FirSimpleFunction) return
|
||||||
|
val resultExpression = expression.result
|
||||||
|
if (resultExpression is FirWhenExpression && !resultExpression.isExhaustive) return
|
||||||
|
|
||||||
|
val functionReturnType = targetElement.returnTypeRef.coneTypeSafe<ConeKotlinType>() ?: return
|
||||||
|
val typeContext = context.session.typeContext
|
||||||
|
val returnExpressionType = resultExpression.typeRef.coneTypeSafe<ConeKotlinType>() ?: return
|
||||||
|
|
||||||
|
if (!isSubtypeForTypeMismatch(typeContext, subtype = returnExpressionType, supertype = functionReturnType)) {
|
||||||
|
val returnExpressionSource = resultExpression.source ?: return
|
||||||
|
reporter.report(RETURN_TYPE_MISMATCH.on(returnExpressionSource, functionReturnType, returnExpressionType), context)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-1
@@ -102,7 +102,7 @@ class ExpressionCheckersDiagnosticComponent(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun visitReturnExpression(returnExpression: FirReturnExpression, data: CheckerContext) {
|
override fun visitReturnExpression(returnExpression: FirReturnExpression, data: CheckerContext) {
|
||||||
checkers.returnExpressionCheckers.check(returnExpression, data, reporter)
|
checkers.allReturnExpressionCheckers.check(returnExpression, data, reporter)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun <E : FirStatement> Collection<FirExpressionChecker<E>>.check(
|
private fun <E : FirStatement> Collection<FirExpressionChecker<E>>.check(
|
||||||
|
|||||||
+3
@@ -196,6 +196,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.REPEATED_MODIFIER
|
|||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.RESERVED_MEMBER_INSIDE_INLINE_CLASS
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.RESERVED_MEMBER_INSIDE_INLINE_CLASS
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.RETURN_IN_FUNCTION_WITH_EXPRESSION_BODY
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.RETURN_IN_FUNCTION_WITH_EXPRESSION_BODY
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.RETURN_NOT_ALLOWED
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.RETURN_NOT_ALLOWED
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.RETURN_TYPE_MISMATCH
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.RETURN_TYPE_MISMATCH_ON_OVERRIDE
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.RETURN_TYPE_MISMATCH_ON_OVERRIDE
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SEALED_CLASS_CONSTRUCTOR_CALL
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SEALED_CLASS_CONSTRUCTOR_CALL
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SEALED_SUPERTYPE
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SEALED_SUPERTYPE
|
||||||
@@ -488,6 +489,8 @@ class FirDefaultErrorMessages : DefaultErrorMessages.Extension {
|
|||||||
NAME
|
NAME
|
||||||
)
|
)
|
||||||
|
|
||||||
|
map.put(RETURN_TYPE_MISMATCH, "Return type mismatch: expected {0}, actual {1}", RENDER_TYPE, RENDER_TYPE)
|
||||||
|
|
||||||
// Reflection
|
// Reflection
|
||||||
map.put(
|
map.put(
|
||||||
EXTENSION_IN_CLASS_REFERENCE_NOT_ALLOWED,
|
EXTENSION_IN_CLASS_REFERENCE_NOT_ALLOWED,
|
||||||
|
|||||||
+5
-2
@@ -12,6 +12,7 @@ import com.intellij.psi.impl.source.tree.ElementType
|
|||||||
import com.intellij.psi.tree.IElementType
|
import com.intellij.psi.tree.IElementType
|
||||||
import com.intellij.psi.tree.TokenSet
|
import com.intellij.psi.tree.TokenSet
|
||||||
import com.intellij.util.diff.FlyweightCapableTreeStructure
|
import com.intellij.util.diff.FlyweightCapableTreeStructure
|
||||||
|
import org.jetbrains.kotlin.KtNodeType
|
||||||
import org.jetbrains.kotlin.KtNodeTypes
|
import org.jetbrains.kotlin.KtNodeTypes
|
||||||
import org.jetbrains.kotlin.fir.FirSourceElement
|
import org.jetbrains.kotlin.fir.FirSourceElement
|
||||||
import org.jetbrains.kotlin.fir.analysis.checkers.getChildren
|
import org.jetbrains.kotlin.fir.analysis.checkers.getChildren
|
||||||
@@ -242,7 +243,7 @@ object LightTreePositioningStrategies {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val ASSIGNMENT_VALUE: LightTreePositioningStrategy = object : LightTreePositioningStrategy() {
|
val LAST_CHILD: LightTreePositioningStrategy = object : LightTreePositioningStrategy() {
|
||||||
override fun mark(
|
override fun mark(
|
||||||
node: LighterASTNode,
|
node: LighterASTNode,
|
||||||
startOffset: Int,
|
startOffset: Int,
|
||||||
@@ -537,6 +538,8 @@ object LightTreePositioningStrategies {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val WHOLE_ELEMENT = object : LightTreePositioningStrategy() { }
|
||||||
|
|
||||||
val LONG_LITERAL_SUFFIX = object : LightTreePositioningStrategy() {
|
val LONG_LITERAL_SUFFIX = object : LightTreePositioningStrategy() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -739,5 +742,5 @@ private fun FlyweightCapableTreeStructure<LighterASTNode>.firstChild(node: Light
|
|||||||
private fun FlyweightCapableTreeStructure<LighterASTNode>.lastChild(node: LighterASTNode): LighterASTNode? {
|
private fun FlyweightCapableTreeStructure<LighterASTNode>.lastChild(node: LighterASTNode): LighterASTNode? {
|
||||||
val childrenRef = Ref<Array<LighterASTNode>>()
|
val childrenRef = Ref<Array<LighterASTNode>>()
|
||||||
getChildren(node, childrenRef)
|
getChildren(node, childrenRef)
|
||||||
return childrenRef.get()?.lastOrNull()
|
return childrenRef.get().lastOrNull()
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-1
@@ -179,10 +179,15 @@ object SourceElementPositioningStrategies {
|
|||||||
)
|
)
|
||||||
|
|
||||||
val ASSIGNMENT_VALUE = SourceElementPositioningStrategy(
|
val ASSIGNMENT_VALUE = SourceElementPositioningStrategy(
|
||||||
LightTreePositioningStrategies.ASSIGNMENT_VALUE,
|
LightTreePositioningStrategies.LAST_CHILD,
|
||||||
PositioningStrategies.ASSIGNMENT_VALUE
|
PositioningStrategies.ASSIGNMENT_VALUE
|
||||||
)
|
)
|
||||||
|
|
||||||
|
val WHOLE_ELEMENT = SourceElementPositioningStrategy(
|
||||||
|
LightTreePositioningStrategies.WHOLE_ELEMENT,
|
||||||
|
PositioningStrategies.WHOLE_ELEMENT
|
||||||
|
)
|
||||||
|
|
||||||
val LONG_LITERAL_SUFFIX = SourceElementPositioningStrategy(
|
val LONG_LITERAL_SUFFIX = SourceElementPositioningStrategy(
|
||||||
LightTreePositioningStrategies.LONG_LITERAL_SUFFIX,
|
LightTreePositioningStrategies.LONG_LITERAL_SUFFIX,
|
||||||
PositioningStrategies.LONG_LITERAL_SUFFIX
|
PositioningStrategies.LONG_LITERAL_SUFFIX
|
||||||
|
|||||||
+2
-1
@@ -48,6 +48,7 @@ object CommonExpressionCheckers : ExpressionCheckers() {
|
|||||||
)
|
)
|
||||||
|
|
||||||
override val returnExpressionCheckers: Set<FirReturnExpressionChecker> = setOf(
|
override val returnExpressionCheckers: Set<FirReturnExpressionChecker> = setOf(
|
||||||
FirReturnAllowedChecker
|
FirReturnAllowedChecker,
|
||||||
|
FirFunctionReturnTypeMismatchChecker
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -782,23 +782,12 @@ object PositioningStrategies {
|
|||||||
|
|
||||||
val ASSIGNMENT_VALUE: PositioningStrategy<KtProperty> = object : PositioningStrategy<PsiElement>() {
|
val ASSIGNMENT_VALUE: PositioningStrategy<KtProperty> = object : PositioningStrategy<PsiElement>() {
|
||||||
override fun mark(element: PsiElement): List<TextRange> {
|
override fun mark(element: PsiElement): List<TextRange> {
|
||||||
return if (element is KtProperty) {
|
return markElement(if (element is KtProperty) element.initializer ?: element else element)
|
||||||
mark(element.initializer ?: element)
|
|
||||||
} else {
|
|
||||||
super.mark(element)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val RETURN_EXPRESSION: PositioningStrategy<KtReturnExpression> = object : PositioningStrategy<PsiElement>() {
|
val WHOLE_ELEMENT: PositioningStrategy<KtElement> = object : PositioningStrategy<KtElement>() {}
|
||||||
override fun mark(element: PsiElement): List<TextRange> {
|
|
||||||
return if (element is KtReturnExpression) {
|
|
||||||
markElement(element.returnedExpression ?: element)
|
|
||||||
} else {
|
|
||||||
markElement(element)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param locateReferencedName whether to remove any nested parentheses while locating the reference element. This is useful for
|
* @param locateReferencedName whether to remove any nested parentheses while locating the reference element. This is useful for
|
||||||
|
|||||||
+28
-28
@@ -6,7 +6,7 @@ fun none() {}
|
|||||||
fun unitEmptyInfer() {}
|
fun unitEmptyInfer() {}
|
||||||
fun unitEmpty() : Unit {}
|
fun unitEmpty() : Unit {}
|
||||||
fun unitEmptyReturn() : Unit {return}
|
fun unitEmptyReturn() : Unit {return}
|
||||||
fun unitIntReturn() : Unit {return 1}
|
fun unitIntReturn() : Unit {return <!RETURN_TYPE_MISMATCH!>1<!>}
|
||||||
fun unitUnitReturn() : Unit {return Unit}
|
fun unitUnitReturn() : Unit {return Unit}
|
||||||
fun test1() : Any = {<!RETURN_NOT_ALLOWED!>return<!>}
|
fun test1() : Any = {<!RETURN_NOT_ALLOWED!>return<!>}
|
||||||
fun test2() : Any = a@ {return@a 1}
|
fun test2() : Any = a@ {return@a 1}
|
||||||
@@ -16,7 +16,7 @@ fun test5(): Any = l@{ return@l }
|
|||||||
fun test6(): Any = {<!RETURN_NOT_ALLOWED!>return<!> 1}
|
fun test6(): Any = {<!RETURN_NOT_ALLOWED!>return<!> 1}
|
||||||
|
|
||||||
fun bbb() {
|
fun bbb() {
|
||||||
return 1
|
return <!RETURN_TYPE_MISMATCH!>1<!>
|
||||||
}
|
}
|
||||||
|
|
||||||
fun foo(expr: StringBuilder): Int {
|
fun foo(expr: StringBuilder): Int {
|
||||||
@@ -29,8 +29,8 @@ fun foo(expr: StringBuilder): Int {
|
|||||||
|
|
||||||
|
|
||||||
fun unitShort() : Unit = Unit
|
fun unitShort() : Unit = Unit
|
||||||
fun unitShortConv() : Unit = 1
|
fun unitShortConv() : Unit = <!RETURN_TYPE_MISMATCH!>1<!>
|
||||||
fun unitShortNull() : Unit = null
|
fun unitShortNull() : Unit = <!RETURN_TYPE_MISMATCH!>null<!>
|
||||||
|
|
||||||
fun intEmpty() : Int {}
|
fun intEmpty() : Int {}
|
||||||
fun intShortInfer() = 1
|
fun intShortInfer() = 1
|
||||||
@@ -39,56 +39,56 @@ fun intShort() : Int = 1
|
|||||||
fun intBlock() : Int {return 1}
|
fun intBlock() : Int {return 1}
|
||||||
fun intBlock1() : Int {1}
|
fun intBlock1() : Int {1}
|
||||||
|
|
||||||
fun intString(): Int = "s"
|
fun intString(): Int = <!RETURN_TYPE_MISMATCH!>"s"<!>
|
||||||
fun intFunctionLiteral(): Int = { 10 }
|
fun intFunctionLiteral(): Int = <!RETURN_TYPE_MISMATCH!>{ 10 }<!>
|
||||||
|
|
||||||
fun blockReturnUnitMismatch() : Int {return}
|
fun blockReturnUnitMismatch() : Int {<!RETURN_TYPE_MISMATCH!>return<!>}
|
||||||
fun blockReturnValueTypeMismatch() : Int {return 3.4}
|
fun blockReturnValueTypeMismatch() : Int {return <!RETURN_TYPE_MISMATCH!>3.4<!>}
|
||||||
fun blockReturnValueTypeMatch() : Int {return 1}
|
fun blockReturnValueTypeMatch() : Int {return 1}
|
||||||
fun blockReturnValueTypeMismatchUnit() : Int {return Unit}
|
fun blockReturnValueTypeMismatchUnit() : Int {return <!RETURN_TYPE_MISMATCH!>Unit<!>}
|
||||||
|
|
||||||
fun blockAndAndMismatch() : Int {
|
fun blockAndAndMismatch() : Int {
|
||||||
true && false
|
true && false
|
||||||
}
|
}
|
||||||
fun blockAndAndMismatch1() : Int {
|
fun blockAndAndMismatch1() : Int {
|
||||||
return true && false
|
return <!RETURN_TYPE_MISMATCH!>true && false<!>
|
||||||
}
|
}
|
||||||
fun blockAndAndMismatch2() : Int {
|
fun blockAndAndMismatch2() : Int {
|
||||||
(return true) && (return false)
|
(return <!RETURN_TYPE_MISMATCH!>true<!>) && (return <!RETURN_TYPE_MISMATCH!>false<!>)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun blockAndAndMismatch3() : Int {
|
fun blockAndAndMismatch3() : Int {
|
||||||
true || false
|
true || false
|
||||||
}
|
}
|
||||||
fun blockAndAndMismatch4() : Int {
|
fun blockAndAndMismatch4() : Int {
|
||||||
return true || false
|
return <!RETURN_TYPE_MISMATCH!>true || false<!>
|
||||||
}
|
}
|
||||||
fun blockAndAndMismatch5() : Int {
|
fun blockAndAndMismatch5() : Int {
|
||||||
(return true) || (return false)
|
(return <!RETURN_TYPE_MISMATCH!>true<!>) || (return <!RETURN_TYPE_MISMATCH!>false<!>)
|
||||||
}
|
}
|
||||||
fun blockReturnValueTypeMatch1() : Int {
|
fun blockReturnValueTypeMatch1() : Int {
|
||||||
return if (1 > 2) 1.0 else 2.0
|
return <!RETURN_TYPE_MISMATCH!>if (1 > 2) 1.0 else 2.0<!>
|
||||||
}
|
}
|
||||||
fun blockReturnValueTypeMatch2() : Int {
|
fun blockReturnValueTypeMatch2() : Int {
|
||||||
return <!INVALID_IF_AS_EXPRESSION!>if<!> (1 > 2) 1
|
return <!INVALID_IF_AS_EXPRESSION!>if<!> (1 > 2) 1
|
||||||
}
|
}
|
||||||
fun blockReturnValueTypeMatch3() : Int {
|
fun blockReturnValueTypeMatch3() : Int {
|
||||||
return if (1 > 2) else 1
|
return <!RETURN_TYPE_MISMATCH!>if (1 > 2) else 1<!>
|
||||||
}
|
}
|
||||||
fun blockReturnValueTypeMatch4() : Int {
|
fun blockReturnValueTypeMatch4() : Int {
|
||||||
if (1 > 2)
|
if (1 > 2)
|
||||||
return 1.0
|
return <!RETURN_TYPE_MISMATCH!>1.0<!>
|
||||||
else return 2.0
|
else return <!RETURN_TYPE_MISMATCH!>2.0<!>
|
||||||
}
|
}
|
||||||
fun blockReturnValueTypeMatch5() : Int {
|
fun blockReturnValueTypeMatch5() : Int {
|
||||||
if (1 > 2)
|
if (1 > 2)
|
||||||
return 1.0
|
return <!RETURN_TYPE_MISMATCH!>1.0<!>
|
||||||
return 2.0
|
return <!RETURN_TYPE_MISMATCH!>2.0<!>
|
||||||
}
|
}
|
||||||
fun blockReturnValueTypeMatch6() : Int {
|
fun blockReturnValueTypeMatch6() : Int {
|
||||||
if (1 > 2)
|
if (1 > 2)
|
||||||
else return 1.0
|
else return <!RETURN_TYPE_MISMATCH!>1.0<!>
|
||||||
return 2.0
|
return <!RETURN_TYPE_MISMATCH!>2.0<!>
|
||||||
}
|
}
|
||||||
fun blockReturnValueTypeMatch7() : Int {
|
fun blockReturnValueTypeMatch7() : Int {
|
||||||
if (1 > 2)
|
if (1 > 2)
|
||||||
@@ -116,7 +116,7 @@ fun blockReturnValueTypeMatch11() : Int {
|
|||||||
fun blockReturnValueTypeMatch12() : Int {
|
fun blockReturnValueTypeMatch12() : Int {
|
||||||
if (1 > 2)
|
if (1 > 2)
|
||||||
return 1
|
return 1
|
||||||
else return 1.0
|
else return <!RETURN_TYPE_MISMATCH!>1.0<!>
|
||||||
}
|
}
|
||||||
fun blockNoReturnIfValDeclaration(): Int {
|
fun blockNoReturnIfValDeclaration(): Int {
|
||||||
val x = 1
|
val x = 1
|
||||||
@@ -134,23 +134,23 @@ fun blockNoReturnIfUnitInOneBranch(): Int {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fun nonBlockReturnIfEmptyIf(): Int = if (1 < 2) {} else {}
|
fun nonBlockReturnIfEmptyIf(): Int = <!RETURN_TYPE_MISMATCH!>if (1 < 2) {} else {}<!>
|
||||||
fun nonBlockNoReturnIfUnitInOneBranch(): Int = if (1 < 2) {} else 2
|
fun nonBlockNoReturnIfUnitInOneBranch(): Int = <!RETURN_TYPE_MISMATCH!>if (1 < 2) {} else 2<!>
|
||||||
|
|
||||||
val a = <!RETURN_NOT_ALLOWED!>return<!> 1
|
val a = <!RETURN_NOT_ALLOWED!>return<!> 1
|
||||||
|
|
||||||
class A() {
|
class A() {
|
||||||
}
|
}
|
||||||
fun illegalConstantBody(): Int = "s"
|
fun illegalConstantBody(): Int = <!RETURN_TYPE_MISMATCH!>"s"<!>
|
||||||
fun illegalConstantBlock(): String {
|
fun illegalConstantBlock(): String {
|
||||||
return 1
|
return <!RETURN_TYPE_MISMATCH!>1<!>
|
||||||
}
|
}
|
||||||
fun illegalIfBody(): Int =
|
fun illegalIfBody(): Int =
|
||||||
if (1 < 2) 'a' else { 1.0 }
|
<!RETURN_TYPE_MISMATCH!>if (1 < 2) 'a' else { 1.0 }<!>
|
||||||
fun illegalIfBlock(): Boolean {
|
fun illegalIfBlock(): Boolean {
|
||||||
if (1 < 2)
|
if (1 < 2)
|
||||||
return false
|
return false
|
||||||
else { return 1 }
|
else { return <!RETURN_TYPE_MISMATCH!>1<!> }
|
||||||
}
|
}
|
||||||
fun illegalReturnIf(): Char {
|
fun illegalReturnIf(): Char {
|
||||||
return if (1 < 2) 'a' else { 1 }
|
return if (1 < 2) 'a' else { 1 }
|
||||||
|
|||||||
+1
-1
@@ -19,6 +19,6 @@ class A3<T> {
|
|||||||
fun test2(): (T) -> Unit = A3<T>()::a3
|
fun test2(): (T) -> Unit = A3<T>()::a3
|
||||||
fun test3(): (Int) -> String = A3<Int>()::a3
|
fun test3(): (Int) -> String = A3<Int>()::a3
|
||||||
|
|
||||||
fun <R> test4(): (R) -> Unit = this::a3
|
fun <R> test4(): (R) -> Unit = <!RETURN_TYPE_MISMATCH!>this::a3<!>
|
||||||
fun <R> test5(): (T) -> R = this::a3
|
fun <R> test5(): (T) -> R = this::a3
|
||||||
}
|
}
|
||||||
compiler/testData/diagnostics/tests/callableReference/unitAdaptationForReferenceCompatibility.fir.kt
Vendored
+2
-2
@@ -20,6 +20,6 @@ public interface Executor {
|
|||||||
fun f(): String = "test"
|
fun f(): String = "test"
|
||||||
|
|
||||||
class A {
|
class A {
|
||||||
fun schedule1(e: Executor): Future<String> = e.submit(::f)
|
fun schedule1(e: Executor): Future<String> = <!RETURN_TYPE_MISMATCH!>e.submit(::f)<!>
|
||||||
fun schedule2(e: Executor): Future<String> = e.submit { f() }
|
fun schedule2(e: Executor): Future<String> = <!RETURN_TYPE_MISMATCH!>e.submit { f() }<!>
|
||||||
}
|
}
|
||||||
@@ -20,12 +20,12 @@ operator fun Impl2.unaryMinus() = Impl2()
|
|||||||
// See also KT-10384: in non-error functions, as is necessary!
|
// See also KT-10384: in non-error functions, as is necessary!
|
||||||
fun add1(x: Impl2, y: Base): Impl1 = x as Base + y
|
fun add1(x: Impl2, y: Base): Impl1 = x as Base + y
|
||||||
|
|
||||||
fun error1(x: Impl2, y: Base): Impl1 = x + y
|
fun error1(x: Impl2, y: Base): Impl1 = <!RETURN_TYPE_MISMATCH!>x + y<!>
|
||||||
|
|
||||||
fun add2(x: Base, y: Impl2): Impl1 = x + y as Base
|
fun add2(x: Base, y: Impl2): Impl1 = x + y as Base
|
||||||
|
|
||||||
fun error2(x: Base, y: Impl2): Impl1 = x + y
|
fun error2(x: Base, y: Impl2): Impl1 = <!RETURN_TYPE_MISMATCH!>x + y<!>
|
||||||
|
|
||||||
fun minus3(x: Impl2): Impl1 = -(x as Base)
|
fun minus3(x: Impl2): Impl1 = -(x as Base)
|
||||||
|
|
||||||
fun error3(x: Impl2): Impl1 = -x
|
fun error3(x: Impl2): Impl1 = <!RETURN_TYPE_MISMATCH!>-x<!>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ fun <T> f1(): KClass<Array<T>> = <!CLASS_LITERAL_LHS_NOT_A_CLASS!>Array<T>::clas
|
|||||||
fun <T> f2(): KClass<Array<Array<T>>> = <!CLASS_LITERAL_LHS_NOT_A_CLASS!>Array<Array<T>>::class<!>
|
fun <T> f2(): KClass<Array<Array<T>>> = <!CLASS_LITERAL_LHS_NOT_A_CLASS!>Array<Array<T>>::class<!>
|
||||||
inline fun <reified T> f3() = Array<T>::class
|
inline fun <reified T> f3() = Array<T>::class
|
||||||
inline fun <reified T> f4() = Array<Array<T>>::class
|
inline fun <reified T> f4() = Array<Array<T>>::class
|
||||||
fun f5(): KClass<Array<Any>> = <!CLASS_LITERAL_LHS_NOT_A_CLASS!>Array<*>::class<!>
|
fun f5(): KClass<Array<Any>> = <!CLASS_LITERAL_LHS_NOT_A_CLASS, RETURN_TYPE_MISMATCH!>Array<*>::class<!>
|
||||||
fun f6(): KClass<Array<Int?>> = Array<Int?>::class
|
fun f6(): KClass<Array<Int?>> = Array<Int?>::class
|
||||||
fun f7() = <!CLASS_LITERAL_LHS_NOT_A_CLASS!>Array<List<String>>::class<!>
|
fun f7() = <!CLASS_LITERAL_LHS_NOT_A_CLASS!>Array<List<String>>::class<!>
|
||||||
fun f8() = <!CLASS_LITERAL_LHS_NOT_A_CLASS!>Array<List<String>?>::class<!>
|
fun f8() = <!CLASS_LITERAL_LHS_NOT_A_CLASS!>Array<List<String>?>::class<!>
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
// KT-16291 Smart cast doesn't work when getting class of instance
|
||||||
|
|
||||||
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
|
class Foo {
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
if (this === other) return true
|
||||||
|
if (other === null || other::class != this::class) return false
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test(f: Foo?): KClass<out Foo>? = if (f != null) f::class else null
|
||||||
|
|
||||||
|
fun test2(): KClass<out Foo>? {
|
||||||
|
var f: Foo? = null
|
||||||
|
if (f != null) {
|
||||||
|
run { f = null }
|
||||||
|
return <!RETURN_TYPE_MISMATCH!><!EXPRESSION_OF_NULLABLE_TYPE_IN_CLASS_LITERAL_LHS!>f<!>::class<!>
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
// FIR_IDENTICAL
|
|
||||||
// KT-16291 Smart cast doesn't work when getting class of instance
|
// KT-16291 Smart cast doesn't work when getting class of instance
|
||||||
|
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
|
|||||||
Vendored
+2
-2
@@ -6,7 +6,7 @@ fun t1() : Int{
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun t1a() : Int {
|
fun t1a() : Int {
|
||||||
return
|
<!RETURN_TYPE_MISMATCH!>return<!>
|
||||||
return 1
|
return 1
|
||||||
1
|
1
|
||||||
}
|
}
|
||||||
@@ -19,7 +19,7 @@ fun t1b() : Int {
|
|||||||
|
|
||||||
fun t1c() : Int {
|
fun t1c() : Int {
|
||||||
return 1
|
return 1
|
||||||
return
|
<!RETURN_TYPE_MISMATCH!>return<!>
|
||||||
1
|
1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -35,5 +35,5 @@ val bbbb = ( l() ?: null) ?: ( l() ?: null)
|
|||||||
|
|
||||||
fun f(x : Long?): Long {
|
fun f(x : Long?): Long {
|
||||||
var a = x ?: (fun() {} ?: fun() {})
|
var a = x ?: (fun() {} ?: fun() {})
|
||||||
return a
|
return <!RETURN_TYPE_MISMATCH!>a<!>
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-4
@@ -33,15 +33,15 @@ fun testReturnFromAnonFun() =
|
|||||||
|
|
||||||
fun testReturn1() =
|
fun testReturn1() =
|
||||||
run {
|
run {
|
||||||
return if (true) 42
|
return <!RETURN_TYPE_MISMATCH!>if (true) 42
|
||||||
else println()
|
else println()<!>
|
||||||
}
|
}
|
||||||
|
|
||||||
fun testReturn2() =
|
fun testReturn2() =
|
||||||
run {
|
run {
|
||||||
return if (true) 42
|
return <!RETURN_TYPE_MISMATCH!>if (true) 42
|
||||||
else if (true) 42
|
else if (true) 42
|
||||||
else println()
|
else println()<!>
|
||||||
}
|
}
|
||||||
|
|
||||||
fun testUsage1() =
|
fun testUsage1() =
|
||||||
|
|||||||
@@ -1,21 +1,21 @@
|
|||||||
// !DIAGNOSTICS: -UNUSED_EXPRESSION -UNREACHABLE_CODE -UNUSED_PARAMETER -RETURN_NOT_ALLOWED
|
// !DIAGNOSTICS: -UNUSED_EXPRESSION -UNREACHABLE_CODE -UNUSED_PARAMETER -RETURN_NOT_ALLOWED
|
||||||
|
|
||||||
fun test1() = run {
|
fun test1() = run {
|
||||||
return "OK"
|
return <!RETURN_TYPE_MISMATCH!>"OK"<!>
|
||||||
}
|
}
|
||||||
|
|
||||||
fun test2() = run {
|
fun test2() = run {
|
||||||
fun local(): String {
|
fun local(): String {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
return ""
|
return <!RETURN_TYPE_MISMATCH!>""<!>
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fun <T, R> Iterable<T>.map(transform: (T) -> R): List<R> = null!!
|
inline fun <T, R> Iterable<T>.map(transform: (T) -> R): List<R> = null!!
|
||||||
fun test3(a: List<String>, b: List<Int>) = a.map {
|
fun test3(a: List<String>, b: List<Int>) = a.map {
|
||||||
if (it.length == 3) return null
|
if (it.length == 3) return <!RETURN_TYPE_MISMATCH!>null<!>
|
||||||
if (it.length == 4) return ""
|
if (it.length == 4) return <!RETURN_TYPE_MISMATCH!>""<!>
|
||||||
if (it.length == 4) return 5
|
if (it.length == 4) return <!RETURN_TYPE_MISMATCH!>5<!>
|
||||||
if (it.length == 4) return b
|
if (it.length == 4) return b
|
||||||
1
|
1
|
||||||
}
|
}
|
||||||
@@ -24,14 +24,14 @@ fun test4() = run {
|
|||||||
fun test5() {
|
fun test5() {
|
||||||
return
|
return
|
||||||
|
|
||||||
return@test4
|
<!RETURN_TYPE_MISMATCH!>return@test4<!>
|
||||||
|
|
||||||
return return@test4
|
return <!RETURN_TYPE_MISMATCH!>return@test4<!>
|
||||||
|
|
||||||
return fun() { return; return@test4 "" }
|
return <!RETURN_TYPE_MISMATCH!>fun() { return; return@test4 <!RETURN_TYPE_MISMATCH!>""<!> }<!>
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
<!RETURN_TYPE_MISMATCH!>return<!>
|
||||||
3
|
3
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,5 +43,5 @@ val foo: Int
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun test(): Int = run {
|
fun test(): Int = run {
|
||||||
return ""
|
return <!RETURN_TYPE_MISMATCH!>""<!>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,11 +2,11 @@
|
|||||||
package f
|
package f
|
||||||
|
|
||||||
fun test(a: Boolean, b: Boolean): Int {
|
fun test(a: Boolean, b: Boolean): Int {
|
||||||
return if(a) {
|
return <!RETURN_TYPE_MISMATCH!>if(a) {
|
||||||
1
|
1
|
||||||
} else {
|
} else {
|
||||||
if (b) {
|
if (b) {
|
||||||
3
|
3
|
||||||
}
|
}
|
||||||
}
|
}<!>
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
+1
-1
@@ -10,7 +10,7 @@ fun f() = object : ClassData {
|
|||||||
fun g() = object : ClassData {
|
fun g() = object : ClassData {
|
||||||
init {
|
init {
|
||||||
if (true) {
|
if (true) {
|
||||||
<!RETURN_NOT_ALLOWED!>return<!> 0
|
<!RETURN_NOT_ALLOWED!>return<!> <!RETURN_TYPE_MISMATCH!>0<!>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,15 +6,15 @@ fun foo() : Int {
|
|||||||
doSmth()
|
doSmth()
|
||||||
}
|
}
|
||||||
catch (e: Exception) {
|
catch (e: Exception) {
|
||||||
return ""
|
return <!RETURN_TYPE_MISMATCH!>""<!>
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
return ""
|
return <!RETURN_TYPE_MISMATCH!>""<!>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun bar() : Int =
|
fun bar() : Int =
|
||||||
try {
|
<!RETURN_TYPE_MISMATCH!>try {
|
||||||
doSmth()
|
doSmth()
|
||||||
}
|
}
|
||||||
catch (e: Exception) {
|
catch (e: Exception) {
|
||||||
@@ -22,7 +22,7 @@ fun bar() : Int =
|
|||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
""
|
""
|
||||||
}
|
}<!>
|
||||||
|
|
||||||
|
|
||||||
fun doSmth() {}
|
fun doSmth() {}
|
||||||
|
|||||||
+4
-4
@@ -26,22 +26,22 @@ fun testResultOfLambda2() =
|
|||||||
|
|
||||||
fun testReturn1() =
|
fun testReturn1() =
|
||||||
run {
|
run {
|
||||||
return when {
|
return <!RETURN_TYPE_MISMATCH!>when {
|
||||||
true -> 42
|
true -> 42
|
||||||
else -> println()
|
else -> println()
|
||||||
}
|
}<!>
|
||||||
}
|
}
|
||||||
|
|
||||||
fun testReturn2() =
|
fun testReturn2() =
|
||||||
run {
|
run {
|
||||||
return when {
|
return <!RETURN_TYPE_MISMATCH!>when {
|
||||||
true -> 42
|
true -> 42
|
||||||
else ->
|
else ->
|
||||||
when {
|
when {
|
||||||
true -> 42
|
true -> 42
|
||||||
else -> println()
|
else -> println()
|
||||||
}
|
}
|
||||||
}
|
}<!>
|
||||||
}
|
}
|
||||||
|
|
||||||
fun testUsage1() =
|
fun testUsage1() =
|
||||||
|
|||||||
@@ -14,5 +14,5 @@ fun foo(): Int {
|
|||||||
val z: Int? = null
|
val z: Int? = null
|
||||||
if (z != null) return if (z == null) z else z
|
if (z != null) return if (z == null) z else z
|
||||||
|
|
||||||
return z
|
return <!RETURN_TYPE_MISMATCH!>z<!>
|
||||||
}
|
}
|
||||||
|
|||||||
+16
-16
@@ -1,36 +1,36 @@
|
|||||||
// !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_VARIABLE
|
// !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_VARIABLE
|
||||||
// KT-5068 Add special error for scala-like syntax 'fun foo(): Int = { 1 }'
|
// KT-5068 Add special error for scala-like syntax 'fun foo(): Int = { 1 }'
|
||||||
|
|
||||||
fun test1(): Int = { <!RETURN_NOT_ALLOWED!>return<!> 1 }
|
fun test1(): Int = <!RETURN_TYPE_MISMATCH!>{ <!RETURN_NOT_ALLOWED!>return<!> 1 }<!>
|
||||||
fun test2(): Int = { 1 }
|
fun test2(): Int = <!RETURN_TYPE_MISMATCH!>{ 1 }<!>
|
||||||
val test3: () -> Int = <!INITIALIZER_TYPE_MISMATCH!>fun (): Int = { <!RETURN_NOT_ALLOWED!>return<!> 1 }<!>
|
val test3: () -> Int = <!INITIALIZER_TYPE_MISMATCH!>fun (): Int = { <!RETURN_NOT_ALLOWED!>return<!> 1 }<!>
|
||||||
val test4: () -> Int = <!INITIALIZER_TYPE_MISMATCH!>fun (): Int = { 1 }<!>
|
val test4: () -> Int = <!INITIALIZER_TYPE_MISMATCH!>fun (): Int = { 1 }<!>
|
||||||
fun test5(): Int { return { 1 } }
|
fun test5(): Int { return <!RETURN_TYPE_MISMATCH!>{ 1 }<!> }
|
||||||
fun test6(): Int = fun (): Int = 1
|
fun test6(): Int = <!RETURN_TYPE_MISMATCH!>fun (): Int = 1<!>
|
||||||
|
|
||||||
fun outer() {
|
fun outer() {
|
||||||
fun test1(): Int = { <!RETURN_NOT_ALLOWED!>return<!> 1 }
|
fun test1(): Int = <!RETURN_TYPE_MISMATCH!>{ <!RETURN_NOT_ALLOWED!>return<!> 1 }<!>
|
||||||
fun test2(): Int = { 1 }
|
fun test2(): Int = <!RETURN_TYPE_MISMATCH!>{ 1 }<!>
|
||||||
val test3: () -> Int = <!INITIALIZER_TYPE_MISMATCH!>fun (): Int = { <!RETURN_NOT_ALLOWED!>return<!> 1 }<!>
|
val test3: () -> Int = <!INITIALIZER_TYPE_MISMATCH!>fun (): Int = { <!RETURN_NOT_ALLOWED!>return<!> 1 }<!>
|
||||||
val test4: () -> Int = <!INITIALIZER_TYPE_MISMATCH!>fun (): Int = { 1 }<!>
|
val test4: () -> Int = <!INITIALIZER_TYPE_MISMATCH!>fun (): Int = { 1 }<!>
|
||||||
fun test5(): Int { return { 1 } }
|
fun test5(): Int { return <!RETURN_TYPE_MISMATCH!>{ 1 }<!> }
|
||||||
fun test6(): Int = fun (): Int = 1
|
fun test6(): Int = <!RETURN_TYPE_MISMATCH!>fun (): Int = 1<!>
|
||||||
}
|
}
|
||||||
|
|
||||||
class Outer {
|
class Outer {
|
||||||
fun test1(): Int = { <!RETURN_NOT_ALLOWED!>return<!> 1 }
|
fun test1(): Int = <!RETURN_TYPE_MISMATCH!>{ <!RETURN_NOT_ALLOWED!>return<!> 1 }<!>
|
||||||
fun test2(): Int = { 1 }
|
fun test2(): Int = <!RETURN_TYPE_MISMATCH!>{ 1 }<!>
|
||||||
val test3: () -> Int = <!INITIALIZER_TYPE_MISMATCH!>fun (): Int = { <!RETURN_NOT_ALLOWED!>return<!> 1 }<!>
|
val test3: () -> Int = <!INITIALIZER_TYPE_MISMATCH!>fun (): Int = { <!RETURN_NOT_ALLOWED!>return<!> 1 }<!>
|
||||||
val test4: () -> Int = <!INITIALIZER_TYPE_MISMATCH!>fun (): Int = { 1 }<!>
|
val test4: () -> Int = <!INITIALIZER_TYPE_MISMATCH!>fun (): Int = { 1 }<!>
|
||||||
fun test5(): Int { return { 1 } }
|
fun test5(): Int { return <!RETURN_TYPE_MISMATCH!>{ 1 }<!> }
|
||||||
fun test6(): Int = fun (): Int = 1
|
fun test6(): Int = <!RETURN_TYPE_MISMATCH!>fun (): Int = 1<!>
|
||||||
|
|
||||||
class Nested {
|
class Nested {
|
||||||
fun test1(): Int = { <!RETURN_NOT_ALLOWED!>return<!> 1 }
|
fun test1(): Int = <!RETURN_TYPE_MISMATCH!>{ <!RETURN_NOT_ALLOWED!>return<!> 1 }<!>
|
||||||
fun test2(): Int = { 1 }
|
fun test2(): Int = <!RETURN_TYPE_MISMATCH!>{ 1 }<!>
|
||||||
val test3: () -> Int = <!INITIALIZER_TYPE_MISMATCH!>fun (): Int = { <!RETURN_NOT_ALLOWED!>return<!> 1 }<!>
|
val test3: () -> Int = <!INITIALIZER_TYPE_MISMATCH!>fun (): Int = { <!RETURN_NOT_ALLOWED!>return<!> 1 }<!>
|
||||||
val test4: () -> Int = <!INITIALIZER_TYPE_MISMATCH!>fun (): Int = { 1 }<!>
|
val test4: () -> Int = <!INITIALIZER_TYPE_MISMATCH!>fun (): Int = { 1 }<!>
|
||||||
fun test5(): Int { return { 1 } }
|
fun test5(): Int { return <!RETURN_TYPE_MISMATCH!>{ 1 }<!> }
|
||||||
fun test6(): Int = fun (): Int = 1
|
fun test6(): Int = <!RETURN_TYPE_MISMATCH!>fun (): Int = 1<!>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-4
@@ -9,12 +9,12 @@ fun <T> foo(): T {
|
|||||||
bar<T>(<!ARGUMENT_TYPE_MISMATCH!>null<!>)
|
bar<T>(<!ARGUMENT_TYPE_MISMATCH!>null<!>)
|
||||||
bar<T?>(null)
|
bar<T?>(null)
|
||||||
|
|
||||||
return null
|
return <!RETURN_TYPE_MISMATCH!>null<!>
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <T> baz(): T? = null
|
fun <T> baz(): T? = null
|
||||||
|
|
||||||
fun <T> foobar(): T = null
|
fun <T> foobar(): T = <!RETURN_TYPE_MISMATCH!>null<!>
|
||||||
|
|
||||||
class A<F> {
|
class A<F> {
|
||||||
fun xyz(x: F) {}
|
fun xyz(x: F) {}
|
||||||
@@ -26,10 +26,10 @@ class A<F> {
|
|||||||
xyz(<!ARGUMENT_TYPE_MISMATCH!>null<!>)
|
xyz(<!ARGUMENT_TYPE_MISMATCH!>null<!>)
|
||||||
bar<F?>(null)
|
bar<F?>(null)
|
||||||
|
|
||||||
return null
|
return <!RETURN_TYPE_MISMATCH!>null<!>
|
||||||
}
|
}
|
||||||
|
|
||||||
fun baz(): F? = null
|
fun baz(): F? = null
|
||||||
|
|
||||||
fun foobar(): F = null
|
fun foobar(): F = <!RETURN_TYPE_MISMATCH!>null<!>
|
||||||
}
|
}
|
||||||
|
|||||||
+11
@@ -0,0 +1,11 @@
|
|||||||
|
class Foo<out T>(val baz: Baz<T>)
|
||||||
|
|
||||||
|
class Bar {
|
||||||
|
val foo: Foo<*> = TODO()
|
||||||
|
|
||||||
|
fun <T> bar(): Baz<T> {
|
||||||
|
return <!RETURN_TYPE_MISMATCH!>foo.baz<!>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
typealias Baz<T> = (@UnsafeVariance T) -> Unit
|
||||||
-2
@@ -1,5 +1,3 @@
|
|||||||
// FIR_IDENTICAL
|
|
||||||
|
|
||||||
class Foo<out T>(val baz: Baz<T>)
|
class Foo<out T>(val baz: Baz<T>)
|
||||||
|
|
||||||
class Bar {
|
class Bar {
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ fun check() {
|
|||||||
val x = null!!
|
val x = null!!
|
||||||
}
|
}
|
||||||
|
|
||||||
fun nonLocalReturn() = run { return }
|
fun nonLocalReturn() = run { <!RETURN_TYPE_MISMATCH!>return<!> }
|
||||||
|
|
||||||
class Klass {
|
class Klass {
|
||||||
fun bar() = null!!
|
fun bar() = null!!
|
||||||
|
|||||||
+1
-1
@@ -12,7 +12,7 @@ fun foo(): String? {
|
|||||||
run {
|
run {
|
||||||
if (true) return@run
|
if (true) return@run
|
||||||
|
|
||||||
if (true) return Obj() // correct error, type check against return type of function "foo"
|
if (true) return <!RETURN_TYPE_MISMATCH!>Obj()<!> // correct error, type check against return type of function "foo"
|
||||||
}
|
}
|
||||||
|
|
||||||
run {
|
run {
|
||||||
|
|||||||
+1
-1
@@ -23,4 +23,4 @@ fun noCoercionBlockHasExplicitReturn() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun noCoercionInExpressionBody(): Unit = "hello"
|
fun noCoercionInExpressionBody(): Unit = <!RETURN_TYPE_MISMATCH!>"hello"<!>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
// !DIAGNOSTICS: -UNUSED_VARIABLE
|
// !DIAGNOSTICS: -UNUSED_VARIABLE
|
||||||
// Related issue: KT-28654
|
// Related issue: KT-28654
|
||||||
|
|
||||||
fun <K> select(): K = run { }
|
fun <K> select(): K = <!RETURN_TYPE_MISMATCH!>run { }<!>
|
||||||
|
|
||||||
fun test() {
|
fun test() {
|
||||||
val x: Int = select()
|
val x: Int = select()
|
||||||
|
|||||||
@@ -149,7 +149,7 @@ fun illegalWhenBody(a: Any): Int = <!NO_ELSE_IN_WHEN!>when<!>(a) {
|
|||||||
fun illegalWhenBlock(a: Any): Int {
|
fun illegalWhenBlock(a: Any): Int {
|
||||||
when(a) {
|
when(a) {
|
||||||
is Int -> return a
|
is Int -> return a
|
||||||
is String -> return a
|
is String -> return <!RETURN_TYPE_MISMATCH!>a<!>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fun declarations(a: Any?) {
|
fun declarations(a: Any?) {
|
||||||
@@ -222,7 +222,7 @@ fun f(): String {
|
|||||||
fun foo(aa: Any?): Int {
|
fun foo(aa: Any?): Int {
|
||||||
var a = aa
|
var a = aa
|
||||||
if (a is Int?) {
|
if (a is Int?) {
|
||||||
return a
|
return <!RETURN_TYPE_MISMATCH!>a<!>
|
||||||
}
|
}
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -30,5 +30,5 @@ import p2.*
|
|||||||
|
|
||||||
fun test2(): Int {
|
fun test2(): Int {
|
||||||
val r = foo(42)
|
val r = foo(42)
|
||||||
return r
|
return <!RETURN_TYPE_MISMATCH!>r<!>
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-4
@@ -2,8 +2,8 @@ interface A
|
|||||||
|
|
||||||
interface B
|
interface B
|
||||||
|
|
||||||
fun test1(): B = object : A {
|
fun test1(): B = <!RETURN_TYPE_MISMATCH!>object : A {
|
||||||
}
|
}<!>
|
||||||
|
|
||||||
fun test2(): B = object {
|
fun test2(): B = <!RETURN_TYPE_MISMATCH!>object {
|
||||||
}
|
}<!>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ interface A {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface B : A {
|
interface B : A {
|
||||||
override fun test(): <!RETURN_TYPE_MISMATCH_ON_OVERRIDE!>Unit<!> = "B"
|
override fun test(): <!RETURN_TYPE_MISMATCH_ON_OVERRIDE!>Unit<!> = <!RETURN_TYPE_MISMATCH!>"B"<!>
|
||||||
}
|
}
|
||||||
|
|
||||||
open class C : A
|
open class C : A
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ fun <T> f(expression : T) : G<out T> = G<T>()
|
|||||||
|
|
||||||
fun foo() : G<Point> {
|
fun foo() : G<Point> {
|
||||||
val p = Point()
|
val p = Point()
|
||||||
return f<Point>(p)
|
return <!RETURN_TYPE_MISMATCH!>f<Point>(p)<!>
|
||||||
}
|
}
|
||||||
|
|
||||||
class Out<out T>() {}
|
class Out<out T>() {}
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ fun t3() : String {
|
|||||||
<!RETURN_NOT_ALLOWED!>return@t3<!> "1"
|
<!RETURN_NOT_ALLOWED!>return@t3<!> "1"
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
<!RETURN_NOT_ALLOWED!>return<!> 2
|
<!RETURN_NOT_ALLOWED!>return<!> <!RETURN_TYPE_MISMATCH!>2<!>
|
||||||
}
|
}
|
||||||
return@l 0
|
return@l 0
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -111,8 +111,8 @@ fun testTwoLambdas() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun f1(): (() -> Unit) -> (() -> Unit) -> Unit {
|
fun f1(): (() -> Unit) -> (() -> Unit) -> Unit {
|
||||||
return { l1 ->
|
return <!RETURN_TYPE_MISMATCH!>{ l1 ->
|
||||||
l1()
|
l1()
|
||||||
<!TOO_MANY_ARGUMENTS!>{ l2 -> <!UNRESOLVED_REFERENCE!>l2<!>() }<!>
|
<!TOO_MANY_ARGUMENTS!>{ l2 -> <!UNRESOLVED_REFERENCE!>l2<!>() }<!>
|
||||||
}
|
}<!>
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -16,7 +16,7 @@ fun <T> LiveData<T>.observe(a: Any, observer: (T) -> Unit): Observer<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// FILE: test.kt
|
// FILE: test.kt
|
||||||
fun <T> test1(r: Runnable, l: LiveData<T>): Observer<T> = l.observe(r) { } // partial conversion
|
fun <T> test1(r: Runnable, l: LiveData<T>): Observer<T> = <!RETURN_TYPE_MISMATCH!>l.observe(r) { }<!> // partial conversion
|
||||||
|
|
||||||
fun <T> test2(r: Runnable, o: Observer<T>, l: LiveData<T>) {
|
fun <T> test2(r: Runnable, o: Observer<T>, l: LiveData<T>) {
|
||||||
val a = l.observe(r, o) // no conversion
|
val a = l.observe(r, o) // no conversion
|
||||||
|
|||||||
@@ -33,5 +33,5 @@ fun baz(s: String?, r: String?): String {
|
|||||||
fun withNull(s: String?): String {
|
fun withNull(s: String?): String {
|
||||||
val t = s ?: null
|
val t = s ?: null
|
||||||
// Error: nullable
|
// Error: nullable
|
||||||
return t
|
return <!RETURN_TYPE_MISMATCH!>t<!>
|
||||||
}
|
}
|
||||||
@@ -8,7 +8,7 @@ class Immutable(val x: String?) {
|
|||||||
|
|
||||||
class Mutable(var y: String?) {
|
class Mutable(var y: String?) {
|
||||||
fun foo(): String {
|
fun foo(): String {
|
||||||
if (y != null) return y
|
if (y != null) return <!RETURN_TYPE_MISMATCH!>y<!>
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+1
-1
@@ -3,5 +3,5 @@
|
|||||||
fun calc(x: List<String>?, y: Int?): Int {
|
fun calc(x: List<String>?, y: Int?): Int {
|
||||||
x?.subList(y!! - 1, y)
|
x?.subList(y!! - 1, y)
|
||||||
// y!! above should not provide smart cast here
|
// y!! above should not provide smart cast here
|
||||||
return y
|
return <!RETURN_TYPE_MISMATCH!>y<!>
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -6,5 +6,5 @@ fun calc(x: String?, y: Int?): Int {
|
|||||||
// Smart cast because of x!! in receiver
|
// Smart cast because of x!! in receiver
|
||||||
foo(x!!)?.subSequence(y!!, x.length)?.length
|
foo(x!!)?.subSequence(y!!, x.length)?.length
|
||||||
// No smart cast possible
|
// No smart cast possible
|
||||||
return y
|
return <!RETURN_TYPE_MISMATCH!>y<!>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,5 +13,5 @@ fun list(start: SomeObject): SomeObject {
|
|||||||
e = e<!UNSAFE_CALL!>.<!>next()
|
e = e<!UNSAFE_CALL!>.<!>next()
|
||||||
}
|
}
|
||||||
// Smart cast is not possible here due to next()
|
// Smart cast is not possible here due to next()
|
||||||
return e
|
return <!RETURN_TYPE_MISMATCH!>e<!>
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -14,5 +14,5 @@ fun list(start: SomeObject): SomeObject {
|
|||||||
e.doSomething()
|
e.doSomething()
|
||||||
e = e.next()
|
e = e.next()
|
||||||
}
|
}
|
||||||
return e
|
return <!RETURN_TYPE_MISMATCH!>e<!>
|
||||||
}
|
}
|
||||||
+1
-1
@@ -14,5 +14,5 @@ fun list(start: SomeObject): SomeObject {
|
|||||||
e.doSomething()
|
e.doSomething()
|
||||||
e = e.next()
|
e = e.next()
|
||||||
}
|
}
|
||||||
return e
|
return <!RETURN_TYPE_MISMATCH!>e<!>
|
||||||
}
|
}
|
||||||
Vendored
+1
-1
@@ -2,7 +2,7 @@
|
|||||||
// FILE: KotlinFile.kt
|
// FILE: KotlinFile.kt
|
||||||
fun foo(javaClass: JavaClass<Int>): Int {
|
fun foo(javaClass: JavaClass<Int>): Int {
|
||||||
val inner = javaClass.createInner<String>()
|
val inner = javaClass.createInner<String>()
|
||||||
return inner.doSomething(<!ARGUMENT_TYPE_MISMATCH!>1<!>, "") { }
|
return <!RETURN_TYPE_MISMATCH!>inner.doSomething(<!ARGUMENT_TYPE_MISMATCH!>1<!>, "") { }<!>
|
||||||
}
|
}
|
||||||
|
|
||||||
// FILE: JavaClass.java
|
// FILE: JavaClass.java
|
||||||
|
|||||||
+1
-1
@@ -40,7 +40,7 @@ class Context<T>
|
|||||||
fun <T> Any.decodeIn(typeFrom: Context<in T>): T = something()
|
fun <T> Any.decodeIn(typeFrom: Context<in T>): T = something()
|
||||||
|
|
||||||
fun <T> Any?.decodeOut1(typeFrom: Context<out T>): T {
|
fun <T> Any?.decodeOut1(typeFrom: Context<out T>): T {
|
||||||
return this?.decodeIn(typeFrom) ?: kotlin.Unit
|
return <!RETURN_TYPE_MISMATCH!>this?.decodeIn(typeFrom) ?: kotlin.Unit<!>
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <T> Any.decodeOut2(typeFrom: Context<out T>): T {
|
fun <T> Any.decodeOut2(typeFrom: Context<out T>): T {
|
||||||
|
|||||||
+1
-1
@@ -4,4 +4,4 @@ fun ushort(vararg a: UShort): UShortArray = a
|
|||||||
fun uint(vararg a: UInt): UIntArray = a
|
fun uint(vararg a: UInt): UIntArray = a
|
||||||
fun ulong(vararg a: ULong): ULongArray = a
|
fun ulong(vararg a: ULong): ULongArray = a
|
||||||
|
|
||||||
fun rawUInt(vararg a: UInt): IntArray = a
|
fun rawUInt(vararg a: UInt): IntArray = <!RETURN_TYPE_MISMATCH!>a<!>
|
||||||
|
|||||||
@@ -18,5 +18,5 @@ fun test(a: Any): String {
|
|||||||
is A -> q!!
|
is A -> q!!
|
||||||
}
|
}
|
||||||
// When is not exhaustive
|
// When is not exhaustive
|
||||||
return q
|
return <!RETURN_TYPE_MISMATCH!>q<!>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,5 +18,5 @@ fun test(a: Any) {
|
|||||||
is A -> q = "1"
|
is A -> q = "1"
|
||||||
}
|
}
|
||||||
// When is not exhaustive
|
// When is not exhaustive
|
||||||
return q
|
return <!RETURN_TYPE_MISMATCH!>q<!>
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -14,14 +14,14 @@ package test
|
|||||||
|
|
||||||
fun foo(): Int {
|
fun foo(): Int {
|
||||||
val a = "a"
|
val a = "a"
|
||||||
return if (a.length > 0) {
|
return <!RETURN_TYPE_MISMATCH!>if (a.length > 0) {
|
||||||
when (a) {
|
when (a) {
|
||||||
"a" -> 1
|
"a" -> 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
3
|
3
|
||||||
}
|
}<!>
|
||||||
}
|
}
|
||||||
|
|
||||||
fun bar(): Int {
|
fun bar(): Int {
|
||||||
|
|||||||
@@ -15,5 +15,5 @@ public class P {
|
|||||||
|
|
||||||
fun foo(c: P): MutableList<Int> {
|
fun foo(c: P): MutableList<Int> {
|
||||||
// Error should be here: see KT-8168 Typechecker fails for platform collection type
|
// Error should be here: see KT-8168 Typechecker fails for platform collection type
|
||||||
return c.getList() ?: listOf()
|
return <!RETURN_TYPE_MISMATCH!>c.getList() ?: listOf()<!>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,9 +5,9 @@ import kotlin.comparisons.nullsLast
|
|||||||
class Foo(val a: String, val b: Int)
|
class Foo(val a: String, val b: Int)
|
||||||
|
|
||||||
fun getComp(): Comparator<Foo?> =
|
fun getComp(): Comparator<Foo?> =
|
||||||
when {
|
<!RETURN_TYPE_MISMATCH!>when {
|
||||||
else -> nullsLast(compareBy({ it.<!UNRESOLVED_REFERENCE!>a<!> }, { it.<!UNRESOLVED_REFERENCE!>b<!> }))
|
else -> nullsLast(compareBy({ it.<!UNRESOLVED_REFERENCE!>a<!> }, { it.<!UNRESOLVED_REFERENCE!>b<!> }))
|
||||||
}
|
}<!>
|
||||||
|
|
||||||
fun getCompInverted(): Comparator<Foo?> =
|
fun getCompInverted(): Comparator<Foo?> =
|
||||||
nullsLast(
|
nullsLast(
|
||||||
|
|||||||
+1
-1
@@ -5,7 +5,7 @@
|
|||||||
// TESTCASE NUMBER: 1
|
// TESTCASE NUMBER: 1
|
||||||
// UNEXPECTED BEHAVIOUR
|
// UNEXPECTED BEHAVIOUR
|
||||||
// ISSUES : KT-35545
|
// ISSUES : KT-35545
|
||||||
fun case1(a: Boolean) = run { println("d"); return true }
|
fun case1(a: Boolean) = run { println("d"); return <!RETURN_TYPE_MISMATCH!>true<!> }
|
||||||
|
|
||||||
// TESTCASE NUMBER: 2
|
// TESTCASE NUMBER: 2
|
||||||
val case2
|
val case2
|
||||||
|
|||||||
Vendored
+3
-3
@@ -43,13 +43,13 @@ class Case8 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TESTCASE NUMBER: 9
|
// TESTCASE NUMBER: 9
|
||||||
fun case_9(): Any = null
|
fun case_9(): Any = <!RETURN_TYPE_MISMATCH!>null<!>
|
||||||
|
|
||||||
// TESTCASE NUMBER: 10
|
// TESTCASE NUMBER: 10
|
||||||
fun case_10(x: Int, y: Boolean): Any = if (y) x else null
|
fun case_10(x: Int, y: Boolean): Any = <!RETURN_TYPE_MISMATCH!>if (y) x else null<!>
|
||||||
|
|
||||||
// TESTCASE NUMBER: 11
|
// TESTCASE NUMBER: 11
|
||||||
fun case_11(x: Int, y: Boolean): Any = if (y) x else null
|
fun case_11(x: Int, y: Boolean): Any = <!RETURN_TYPE_MISMATCH!>if (y) x else null<!>
|
||||||
|
|
||||||
// TESTCASE NUMBER: 12
|
// TESTCASE NUMBER: 12
|
||||||
class Case12 {
|
class Case12 {
|
||||||
|
|||||||
@@ -17,5 +17,5 @@ fun case_1(x: Number?): Long? {
|
|||||||
* ISSUES: KT-22997
|
* ISSUES: KT-22997
|
||||||
*/
|
*/
|
||||||
fun case_2(x: Number?): Long? {
|
fun case_2(x: Number?): Long? {
|
||||||
if (x == null || x is Long) return x else return 0L
|
if (x == null || x is Long) return <!RETURN_TYPE_MISMATCH!>x<!> else return 0L
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ class Case1<T> {
|
|||||||
x = getT()
|
x = getT()
|
||||||
}
|
}
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T?")!>x<!>
|
<!DEBUG_INFO_EXPRESSION_TYPE("T?")!>x<!>
|
||||||
return x
|
return <!RETURN_TYPE_MISMATCH!>x<!>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+8
@@ -986,6 +986,14 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
|
|||||||
token,
|
token,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
add(FirErrors.RETURN_TYPE_MISMATCH) { firDiagnostic ->
|
||||||
|
ReturnTypeMismatchImpl(
|
||||||
|
firSymbolBuilder.typeBuilder.buildKtType(firDiagnostic.a),
|
||||||
|
firSymbolBuilder.typeBuilder.buildKtType(firDiagnostic.b),
|
||||||
|
firDiagnostic as FirPsiDiagnostic<*>,
|
||||||
|
token,
|
||||||
|
)
|
||||||
|
}
|
||||||
add(FirErrors.EXTENSION_IN_CLASS_REFERENCE_NOT_ALLOWED) { firDiagnostic ->
|
add(FirErrors.EXTENSION_IN_CLASS_REFERENCE_NOT_ALLOWED) { firDiagnostic ->
|
||||||
ExtensionInClassReferenceNotAllowedImpl(
|
ExtensionInClassReferenceNotAllowedImpl(
|
||||||
firSymbolBuilder.callableBuilder.buildCallableSymbol(firDiagnostic.a as FirCallableDeclaration),
|
firSymbolBuilder.callableBuilder.buildCallableSymbol(firDiagnostic.a as FirCallableDeclaration),
|
||||||
|
|||||||
+6
@@ -701,6 +701,12 @@ sealed class KtFirDiagnostic<PSI: PsiElement> : KtDiagnosticWithPsi<PSI> {
|
|||||||
abstract val typeParametersOwner: KtSymbol
|
abstract val typeParametersOwner: KtSymbol
|
||||||
}
|
}
|
||||||
|
|
||||||
|
abstract class ReturnTypeMismatch : KtFirDiagnostic<KtExpression>() {
|
||||||
|
override val diagnosticClass get() = ReturnTypeMismatch::class
|
||||||
|
abstract val expected: KtType
|
||||||
|
abstract val actual: KtType
|
||||||
|
}
|
||||||
|
|
||||||
abstract class ExtensionInClassReferenceNotAllowed : KtFirDiagnostic<KtExpression>() {
|
abstract class ExtensionInClassReferenceNotAllowed : KtFirDiagnostic<KtExpression>() {
|
||||||
override val diagnosticClass get() = ExtensionInClassReferenceNotAllowed::class
|
override val diagnosticClass get() = ExtensionInClassReferenceNotAllowed::class
|
||||||
abstract val referencedDeclaration: KtCallableSymbol
|
abstract val referencedDeclaration: KtCallableSymbol
|
||||||
|
|||||||
+9
@@ -1131,6 +1131,15 @@ internal class NameInConstraintIsNotATypeParameterImpl(
|
|||||||
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
|
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal class ReturnTypeMismatchImpl(
|
||||||
|
override val expected: KtType,
|
||||||
|
override val actual: KtType,
|
||||||
|
firDiagnostic: FirPsiDiagnostic<*>,
|
||||||
|
override val token: ValidityToken,
|
||||||
|
) : KtFirDiagnostic.ReturnTypeMismatch(), KtAbstractFirDiagnostic<KtExpression> {
|
||||||
|
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
|
||||||
|
}
|
||||||
|
|
||||||
internal class ExtensionInClassReferenceNotAllowedImpl(
|
internal class ExtensionInClassReferenceNotAllowedImpl(
|
||||||
override val referencedDeclaration: KtCallableSymbol,
|
override val referencedDeclaration: KtCallableSymbol,
|
||||||
firDiagnostic: FirPsiDiagnostic<*>,
|
firDiagnostic: FirPsiDiagnostic<*>,
|
||||||
|
|||||||
+28
-28
@@ -6,14 +6,14 @@ fun none() {}
|
|||||||
fun unitEmptyInfer() {}
|
fun unitEmptyInfer() {}
|
||||||
fun unitEmpty() : Unit {}
|
fun unitEmpty() : Unit {}
|
||||||
fun unitEmptyReturn() : Unit {return}
|
fun unitEmptyReturn() : Unit {return}
|
||||||
fun unitIntReturn() : Unit {return 1}
|
fun unitIntReturn() : Unit {return <error descr="[RETURN_TYPE_MISMATCH] Return type mismatch: expected kotlin/Unit, actual kotlin/Int">1</error>}
|
||||||
fun unitUnitReturn() : Unit {return Unit}
|
fun unitUnitReturn() : Unit {return Unit}
|
||||||
fun test1() : Any = { <error descr="[RETURN_NOT_ALLOWED] 'return' is not allowed here">return</error> }
|
fun test1() : Any = { <error descr="[RETURN_NOT_ALLOWED] 'return' is not allowed here">return</error> }
|
||||||
fun test2() : Any = a@ {return@a 1}
|
fun test2() : Any = a@ {return@a 1}
|
||||||
fun test3() : Any { return }
|
fun test3() : Any { return }
|
||||||
|
|
||||||
fun bbb() {
|
fun bbb() {
|
||||||
return 1
|
return <error descr="[RETURN_TYPE_MISMATCH] Return type mismatch: expected kotlin/Unit, actual kotlin/Int">1</error>
|
||||||
}
|
}
|
||||||
|
|
||||||
fun foo(expr: StringBuilder): Int {
|
fun foo(expr: StringBuilder): Int {
|
||||||
@@ -26,8 +26,8 @@ fun foo(expr: StringBuilder): Int {
|
|||||||
|
|
||||||
|
|
||||||
fun unitShort() : Unit = Unit
|
fun unitShort() : Unit = Unit
|
||||||
fun unitShortConv() : Unit = 1
|
fun unitShortConv() : Unit = <error descr="[RETURN_TYPE_MISMATCH] Return type mismatch: expected kotlin/Unit, actual kotlin/Int">1</error>
|
||||||
fun unitShortNull() : Unit = null
|
fun unitShortNull() : Unit = <error descr="[RETURN_TYPE_MISMATCH] Return type mismatch: expected kotlin/Unit, actual kotlin/Nothing?">null</error>
|
||||||
|
|
||||||
fun intEmpty() : Int {}
|
fun intEmpty() : Int {}
|
||||||
fun intShortInfer() = 1
|
fun intShortInfer() = 1
|
||||||
@@ -36,56 +36,56 @@ fun intShort() : Int = 1
|
|||||||
fun intBlock() : Int {return 1}
|
fun intBlock() : Int {return 1}
|
||||||
fun intBlock1() : Int {1}
|
fun intBlock1() : Int {1}
|
||||||
|
|
||||||
fun intString(): Int = "s"
|
fun intString(): Int = <error descr="[RETURN_TYPE_MISMATCH] Return type mismatch: expected kotlin/Int, actual kotlin/String">"s"</error>
|
||||||
fun intFunctionLiteral(): Int = { 10 }
|
fun intFunctionLiteral(): Int = <error descr="[RETURN_TYPE_MISMATCH] Return type mismatch: expected kotlin/Int, actual kotlin/Function0<kotlin/Int>">{ 10 }</error>
|
||||||
|
|
||||||
fun blockReturnUnitMismatch() : Int {return}
|
fun blockReturnUnitMismatch() : Int {<error descr="[RETURN_TYPE_MISMATCH] Return type mismatch: expected kotlin/Int, actual kotlin/Unit">return</error>}
|
||||||
fun blockReturnValueTypeMismatch() : Int {return 3.4}
|
fun blockReturnValueTypeMismatch() : Int {return <error descr="[RETURN_TYPE_MISMATCH] Return type mismatch: expected kotlin/Int, actual kotlin/Double">3.4</error>}
|
||||||
fun blockReturnValueTypeMatch() : Int {return 1}
|
fun blockReturnValueTypeMatch() : Int {return 1}
|
||||||
fun blockReturnValueTypeMismatchUnit() : Int {return Unit}
|
fun blockReturnValueTypeMismatchUnit() : Int {return <error descr="[RETURN_TYPE_MISMATCH] Return type mismatch: expected kotlin/Int, actual kotlin/Unit">Unit</error>}
|
||||||
|
|
||||||
fun blockAndAndMismatch() : Int {
|
fun blockAndAndMismatch() : Int {
|
||||||
true && false
|
true && false
|
||||||
}
|
}
|
||||||
fun blockAndAndMismatch1() : Int {
|
fun blockAndAndMismatch1() : Int {
|
||||||
return true && false
|
return <error descr="[RETURN_TYPE_MISMATCH] Return type mismatch: expected kotlin/Int, actual kotlin/Boolean">true && false</error>
|
||||||
}
|
}
|
||||||
fun blockAndAndMismatch2() : Int {
|
fun blockAndAndMismatch2() : Int {
|
||||||
(return true) && (return false)
|
(return <error descr="[RETURN_TYPE_MISMATCH] Return type mismatch: expected kotlin/Int, actual kotlin/Boolean">true</error>) && (return <error descr="[RETURN_TYPE_MISMATCH] Return type mismatch: expected kotlin/Int, actual kotlin/Boolean">false</error>)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun blockAndAndMismatch3() : Int {
|
fun blockAndAndMismatch3() : Int {
|
||||||
true || false
|
true || false
|
||||||
}
|
}
|
||||||
fun blockAndAndMismatch4() : Int {
|
fun blockAndAndMismatch4() : Int {
|
||||||
return true || false
|
return <error descr="[RETURN_TYPE_MISMATCH] Return type mismatch: expected kotlin/Int, actual kotlin/Boolean">true || false</error>
|
||||||
}
|
}
|
||||||
fun blockAndAndMismatch5() : Int {
|
fun blockAndAndMismatch5() : Int {
|
||||||
(return true) || (return false)
|
(return <error descr="[RETURN_TYPE_MISMATCH] Return type mismatch: expected kotlin/Int, actual kotlin/Boolean">true</error>) || (return <error descr="[RETURN_TYPE_MISMATCH] Return type mismatch: expected kotlin/Int, actual kotlin/Boolean">false</error>)
|
||||||
}
|
}
|
||||||
fun blockReturnValueTypeMatch1() : Int {
|
fun blockReturnValueTypeMatch1() : Int {
|
||||||
return if (1 > 2) 1.0 else 2.0
|
return <error descr="[RETURN_TYPE_MISMATCH] Return type mismatch: expected kotlin/Int, actual kotlin/Double">if (1 > 2) 1.0 else 2.0</error>
|
||||||
}
|
}
|
||||||
fun blockReturnValueTypeMatch2() : Int {
|
fun blockReturnValueTypeMatch2() : Int {
|
||||||
return <error descr="[INVALID_IF_AS_EXPRESSION] 'if' must have both main and 'else' branches if used as an expression">if</error> (1 > 2) 1
|
return <error descr="[INVALID_IF_AS_EXPRESSION] 'if' must have both main and 'else' branches if used as an expression">if</error> (1 > 2) 1
|
||||||
}
|
}
|
||||||
fun blockReturnValueTypeMatch3() : Int {
|
fun blockReturnValueTypeMatch3() : Int {
|
||||||
return if (1 > 2) else 1
|
return <error descr="[RETURN_TYPE_MISMATCH] Return type mismatch: expected kotlin/Int, actual kotlin/Any">if (1 > 2) else 1</error>
|
||||||
}
|
}
|
||||||
fun blockReturnValueTypeMatch4() : Int {
|
fun blockReturnValueTypeMatch4() : Int {
|
||||||
if (1 > 2)
|
if (1 > 2)
|
||||||
return 1.0
|
return <error descr="[RETURN_TYPE_MISMATCH] Return type mismatch: expected kotlin/Int, actual kotlin/Double">1.0</error>
|
||||||
else return 2.0
|
else return <error descr="[RETURN_TYPE_MISMATCH] Return type mismatch: expected kotlin/Int, actual kotlin/Double">2.0</error>
|
||||||
}
|
}
|
||||||
fun blockReturnValueTypeMatch5() : Int {
|
fun blockReturnValueTypeMatch5() : Int {
|
||||||
if (1 > 2)
|
if (1 > 2)
|
||||||
return 1.0
|
return <error descr="[RETURN_TYPE_MISMATCH] Return type mismatch: expected kotlin/Int, actual kotlin/Double">1.0</error>
|
||||||
return 2.0
|
return <error descr="[RETURN_TYPE_MISMATCH] Return type mismatch: expected kotlin/Int, actual kotlin/Double">2.0</error>
|
||||||
}
|
}
|
||||||
fun blockReturnValueTypeMatch6() : Int {
|
fun blockReturnValueTypeMatch6() : Int {
|
||||||
if (1 > 2)
|
if (1 > 2)
|
||||||
else return 1.0
|
else return <error descr="[RETURN_TYPE_MISMATCH] Return type mismatch: expected kotlin/Int, actual kotlin/Double">1.0</error>
|
||||||
return 2.0
|
return <error descr="[RETURN_TYPE_MISMATCH] Return type mismatch: expected kotlin/Int, actual kotlin/Double">2.0</error>
|
||||||
}
|
}
|
||||||
fun blockReturnValueTypeMatch7() : Int {
|
fun blockReturnValueTypeMatch7() : Int {
|
||||||
if (1 > 2)
|
if (1 > 2)
|
||||||
@@ -112,7 +112,7 @@ fun blockReturnValueTypeMatch11() : Int {
|
|||||||
fun blockReturnValueTypeMatch12() : Int {
|
fun blockReturnValueTypeMatch12() : Int {
|
||||||
if (1 > 2)
|
if (1 > 2)
|
||||||
return 1
|
return 1
|
||||||
else return 1.0
|
else return <error descr="[RETURN_TYPE_MISMATCH] Return type mismatch: expected kotlin/Int, actual kotlin/Double">1.0</error>
|
||||||
}
|
}
|
||||||
fun blockNoReturnIfValDeclaration(): Int {
|
fun blockNoReturnIfValDeclaration(): Int {
|
||||||
val x = 1
|
val x = 1
|
||||||
@@ -130,23 +130,23 @@ fun blockNoReturnIfUnitInOneBranch(): Int {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fun nonBlockReturnIfEmptyIf(): Int = if (1 < 2) {} else {}
|
fun nonBlockReturnIfEmptyIf(): Int = <error descr="[RETURN_TYPE_MISMATCH] Return type mismatch: expected kotlin/Int, actual kotlin/Unit">if (1 < 2) {} else {}</error>
|
||||||
fun nonBlockNoReturnIfUnitInOneBranch(): Int = if (1 < 2) {} else 2
|
fun nonBlockNoReturnIfUnitInOneBranch(): Int = <error descr="[RETURN_TYPE_MISMATCH] Return type mismatch: expected kotlin/Int, actual kotlin/Any">if (1 < 2) {} else 2</error>
|
||||||
|
|
||||||
val a = <error descr="[RETURN_NOT_ALLOWED] 'return' is not allowed here">return</error> 1
|
val a = <error descr="[RETURN_NOT_ALLOWED] 'return' is not allowed here">return</error> 1
|
||||||
|
|
||||||
class A() {
|
class A() {
|
||||||
}
|
}
|
||||||
fun illegalConstantBody(): Int = "s"
|
fun illegalConstantBody(): Int = <error descr="[RETURN_TYPE_MISMATCH] Return type mismatch: expected kotlin/Int, actual kotlin/String">"s"</error>
|
||||||
fun illegalConstantBlock(): String {
|
fun illegalConstantBlock(): String {
|
||||||
return 1
|
return <error descr="[RETURN_TYPE_MISMATCH] Return type mismatch: expected kotlin/String, actual kotlin/Int">1</error>
|
||||||
}
|
}
|
||||||
fun illegalIfBody(): Int =
|
fun illegalIfBody(): Int =
|
||||||
if (1 < 2) 'a' else { 1.0 }
|
<error descr="[RETURN_TYPE_MISMATCH] Return type mismatch: expected kotlin/Int, actual it(kotlin/Comparable<*> & java/io/Serializable)">if (1 < 2) 'a' else { 1.0 }</error>
|
||||||
fun illegalIfBlock(): Boolean {
|
fun illegalIfBlock(): Boolean {
|
||||||
if (1 < 2)
|
if (1 < 2)
|
||||||
return false
|
return false
|
||||||
else { return 1 }
|
else { return <error descr="[RETURN_TYPE_MISMATCH] Return type mismatch: expected kotlin/Boolean, actual kotlin/Int">1</error> }
|
||||||
}
|
}
|
||||||
fun illegalReturnIf(): Char {
|
fun illegalReturnIf(): Char {
|
||||||
return if (1 < 2) 'a' else { 1 }
|
return if (1 < 2) 'a' else { 1 }
|
||||||
|
|||||||
+8
-8
@@ -161,7 +161,7 @@ fun illegalWhenBody(a: Any): Int = when(a) {
|
|||||||
fun illegalWhenBlock(a: Any): Int {
|
fun illegalWhenBlock(a: Any): Int {
|
||||||
when(a) {
|
when(a) {
|
||||||
is Int -> return a
|
is Int -> return a
|
||||||
is String -> return a
|
is String -> return <error descr="[RETURN_TYPE_MISMATCH] Return type mismatch: expected kotlin/Int, actual kotlin/String">a</error>
|
||||||
else -> return 1
|
else -> return 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -218,11 +218,11 @@ fun f(): String {
|
|||||||
if (a is String) {
|
if (a is String) {
|
||||||
val i: String = a
|
val i: String = a
|
||||||
a.compareTo("f")
|
a.compareTo("f")
|
||||||
val f: Function0<String> = {
|
val f: Function0<String> = <error descr="[INITIALIZER_TYPE_MISMATCH] Initializer type mismatch: expected kotlin/Function0<kotlin/String>, actual kotlin/Function0<kotlin/Int>">{
|
||||||
a = 42
|
a = 42
|
||||||
a
|
a
|
||||||
}
|
}</error>
|
||||||
return a
|
return <error descr="[RETURN_TYPE_MISMATCH] Return type mismatch: expected kotlin/String, actual kotlin/Int">a</error>
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
@@ -234,13 +234,13 @@ class Mutable(var x: String?) {
|
|||||||
|
|
||||||
fun foo(): String {
|
fun foo(): String {
|
||||||
if (x is String) {
|
if (x is String) {
|
||||||
return x
|
return <error descr="[RETURN_TYPE_MISMATCH] Return type mismatch: expected kotlin/String, actual kotlin/String?">x</error>
|
||||||
}
|
}
|
||||||
if (x != null) {
|
if (x != null) {
|
||||||
return x
|
return <error descr="[RETURN_TYPE_MISMATCH] Return type mismatch: expected kotlin/String, actual kotlin/String?">x</error>
|
||||||
}
|
}
|
||||||
if (xx is String) {
|
if (xx is String) {
|
||||||
return xx
|
return <error descr="[RETURN_TYPE_MISMATCH] Return type mismatch: expected kotlin/String, actual kotlin/String?">xx</error>
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
@@ -248,7 +248,7 @@ class Mutable(var x: String?) {
|
|||||||
fun bar(other: Mutable): String {
|
fun bar(other: Mutable): String {
|
||||||
var y = other
|
var y = other
|
||||||
if (y.x is String) {
|
if (y.x is String) {
|
||||||
return y.x
|
return <error descr="[RETURN_TYPE_MISMATCH] Return type mismatch: expected kotlin/String, actual kotlin/String?">y.x</error>
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user