[FIR] Fix incorrect inference of return type of anonymous functions
Also remove incorrect subtype check checkers Test unsafeVarianceInAliasedFunctionalType.kt started to fail because of KT-54894. This bug existed before, changes from this commit just unhided it (previously it was hidden because incorrect subtype check in `isSubtypeForTypeMismatch` which is used by FirFunctionReturnTypeMismatchChecker
This commit is contained in:
committed by
Space Team
parent
1b42298025
commit
991d8c18aa
@@ -272,35 +272,6 @@ fun isSubtypeForTypeMismatch(context: ConeInferenceContext, subtype: ConeKotlinT
|
||||
val subtypeFullyExpanded = subtype.fullyExpandedType(context.session)
|
||||
val supertypeFullyExpanded = supertype.fullyExpandedType(context.session)
|
||||
return AbstractTypeChecker.isSubtypeOf(context, subtypeFullyExpanded, supertypeFullyExpanded)
|
||||
|| isSubtypeOfForFunctionalTypeReturningUnit(context.session.typeContext, subtypeFullyExpanded, supertypeFullyExpanded)
|
||||
}
|
||||
|
||||
private 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
|
||||
}
|
||||
|
||||
fun FirCallableDeclaration.isVisibleInClass(parentClass: FirClass): Boolean {
|
||||
|
||||
@@ -54,6 +54,11 @@ fun FirTypeRef.resolvedTypeFromPrototype(
|
||||
buildResolvedTypeRef {
|
||||
source = this@resolvedTypeFromPrototype.source
|
||||
this.type = type
|
||||
delegatedTypeRef = when (val original = this@resolvedTypeFromPrototype) {
|
||||
is FirResolvedTypeRef -> original.delegatedTypeRef
|
||||
is FirUserTypeRef -> original
|
||||
else -> null
|
||||
}
|
||||
annotations += this@resolvedTypeFromPrototype.annotations
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,6 +79,11 @@ fun ConeKotlinType.isFunctionalType(session: FirSession): Boolean {
|
||||
return isFunctionalType(session) { it == FunctionClassKind.Function }
|
||||
}
|
||||
|
||||
// Function, SuspendFunction
|
||||
fun ConeKotlinType.isFunctionalOrSuspendFunctionalType(session: FirSession): Boolean {
|
||||
return isFunctionalType(session) { it == FunctionClassKind.Function || it == FunctionClassKind.SuspendFunction }
|
||||
}
|
||||
|
||||
// SuspendFunction, KSuspendFunction
|
||||
fun ConeKotlinType.isSuspendFunctionType(session: FirSession): Boolean {
|
||||
return isFunctionalType(session) { it.isSuspendType }
|
||||
|
||||
@@ -25,8 +25,7 @@ import org.jetbrains.kotlin.fir.resolve.toSymbol
|
||||
import org.jetbrains.kotlin.fir.resolvedTypeFromPrototype
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterLookupTag
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.*
|
||||
import org.jetbrains.kotlin.fir.types.builder.buildErrorTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.builder.*
|
||||
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
|
||||
import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl
|
||||
import org.jetbrains.kotlin.fir.types.lowerBoundIfFlexible
|
||||
@@ -426,15 +425,15 @@ private fun ConeKotlinType.approximateToOnlySupertype(session: FirSession): Cone
|
||||
}
|
||||
|
||||
fun shouldApproximateLocalTypesOfNonLocalDeclaration(containingCallableVisibility: Visibility?, isInlineFunction: Boolean): Boolean {
|
||||
if (containingCallableVisibility == null) {
|
||||
return false
|
||||
}
|
||||
// Approximate types for non-private (all but package private or private) members.
|
||||
// Also private inline functions, as per KT-33917.
|
||||
return containingCallableVisibility == Visibilities.Public ||
|
||||
containingCallableVisibility == Visibilities.Protected ||
|
||||
containingCallableVisibility == Visibilities.Internal ||
|
||||
containingCallableVisibility == Visibilities.Private && isInlineFunction
|
||||
return when (containingCallableVisibility) {
|
||||
Visibilities.Public,
|
||||
Visibilities.Protected,
|
||||
Visibilities.Internal -> true
|
||||
Visibilities.Private -> isInlineFunction
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
fun FirDeclaration.visibilityForApproximation(container: FirDeclaration?): Visibility {
|
||||
|
||||
+5
-2
@@ -46,6 +46,7 @@ import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.builder.buildStarProjection
|
||||
import org.jetbrains.kotlin.fir.types.builder.buildTypeProjectionWithVariance
|
||||
import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl
|
||||
import org.jetbrains.kotlin.fir.types.impl.FirImplicitUnitTypeRef
|
||||
import org.jetbrains.kotlin.fir.visitors.FirDefaultTransformer
|
||||
import org.jetbrains.kotlin.fir.visitors.FirTransformer
|
||||
import org.jetbrains.kotlin.fir.visitors.transformSingle
|
||||
@@ -635,8 +636,10 @@ class FirCallCompletionResultsWriterTransformer(
|
||||
}
|
||||
|
||||
if (finalType != null) {
|
||||
val resultType = anonymousFunction.returnTypeRef.withReplacedConeType(finalType)
|
||||
anonymousFunction.transformReturnTypeRef(StoreType, resultType)
|
||||
if (anonymousFunction.returnTypeRef !is FirImplicitUnitTypeRef) {
|
||||
val resultType = anonymousFunction.returnTypeRef.withReplacedConeType(finalType)
|
||||
anonymousFunction.transformReturnTypeRef(StoreType, resultType)
|
||||
}
|
||||
needUpdateLambdaType = true
|
||||
}
|
||||
|
||||
|
||||
+9
-6
@@ -876,9 +876,10 @@ open class FirDeclarationsResolveTransformer(transformer: FirAbstractBodyResolve
|
||||
initialReturnTypeRef is FirResolvedTypeRef -> {
|
||||
initialReturnTypeRef.coneType
|
||||
}
|
||||
implicitReturns.isNotEmpty() || lambda.returnType?.isUnit == true -> {
|
||||
implicitReturns.isNotEmpty() || (lambda.returnType?.isUnit == true && lambda.isLambda) -> {
|
||||
// i.e., early return, e.g., l@{ ... return@l ... }
|
||||
// Note that the last statement will be coerced to Unit if needed.
|
||||
// also we don't coerce to Unit anonymous functions, only lambdas
|
||||
session.builtinTypes.unitType.type
|
||||
}
|
||||
else -> {
|
||||
@@ -888,11 +889,13 @@ open class FirDeclarationsResolveTransformer(transformer: FirAbstractBodyResolve
|
||||
) ?: session.builtinTypes.unitType.type
|
||||
}
|
||||
}
|
||||
lambda.replaceReturnTypeRef(
|
||||
lambda.returnTypeRef.resolvedTypeFromPrototype(returnType).also {
|
||||
session.lookupTracker?.recordTypeResolveAsLookup(it, lambda.source, components.file.source)
|
||||
}
|
||||
)
|
||||
if (lambda.returnTypeRef !is FirImplicitUnitTypeRef) {
|
||||
lambda.replaceReturnTypeRef(
|
||||
initialReturnTypeRef.resolvedTypeFromPrototype(returnType).also {
|
||||
session.lookupTracker?.recordTypeResolveAsLookup(it, lambda.source, components.file.source)
|
||||
}
|
||||
)
|
||||
}
|
||||
lambda.replaceTypeRef(
|
||||
lambda.constructFunctionalTypeRef(
|
||||
isSuspend = expectedTypeRef.coneTypeSafe<ConeKotlinType>()?.isSuspendFunctionType(session) == true
|
||||
|
||||
@@ -10,7 +10,7 @@ fun unitUnitReturn() : Unit {return Unit}
|
||||
fun test1() : Any = {<!RETURN_NOT_ALLOWED!>return<!>}
|
||||
fun test2() : Any = a@ {return@a 1}
|
||||
fun test3() : Any { return }
|
||||
fun test4(): ()-> Unit = { <!RETURN_NOT_ALLOWED!>return@test4<!> }
|
||||
fun test4(): ()-> Unit = { <!RETURN_NOT_ALLOWED, RETURN_TYPE_MISMATCH!>return@test4<!> }
|
||||
fun test5(): Any = l@{ return@l }
|
||||
fun test6(): Any = {<!RETURN_NOT_ALLOWED!>return<!> 1}
|
||||
|
||||
|
||||
+3
-3
@@ -11,8 +11,8 @@ fun main() {
|
||||
|
||||
val a0: () -> Int = <!INITIALIZER_TYPE_MISMATCH!>fun(): String = "1"<!>
|
||||
val a1: () -> Int = <!INITIALIZER_TYPE_MISMATCH!>(fun() = "1")<!>
|
||||
val a2: () -> Unit = (fun() = <!RETURN_TYPE_MISMATCH!>"1"<!>)
|
||||
val a3: Unit = <!INITIALIZER_TYPE_MISMATCH!>(fun() = <!RETURN_TYPE_MISMATCH!>"1"<!>)<!>
|
||||
val a2: () -> Unit = <!INITIALIZER_TYPE_MISMATCH!>(fun() = "1")<!>
|
||||
val a3: Unit = <!INITIALIZER_TYPE_MISMATCH!>(fun() = "1")<!>
|
||||
val a4 = (fun() = "1")
|
||||
val a5 = (fun(): String = "1")
|
||||
val a6: () -> Int = (fun() = 1)
|
||||
@@ -36,5 +36,5 @@ fun main() {
|
||||
val a18: () -> Int = <!INITIALIZER_TYPE_MISMATCH!>fun() {}<!>
|
||||
val a19: () -> () -> Int = <!INITIALIZER_TYPE_MISMATCH!>fun() = fun() {}<!>
|
||||
val a20: () -> () -> () -> Unit = fun() = fun() = {}
|
||||
val a21: () -> () -> () -> Int = fun() = fun() = {}
|
||||
val a21: () -> () -> () -> Int = <!INITIALIZER_TYPE_MISMATCH!>fun() = fun() = {}<!>
|
||||
}
|
||||
|
||||
+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
|
||||
-1
@@ -1,4 +1,3 @@
|
||||
// FIR_IDENTICAL
|
||||
class Foo<out T>(val baz: Baz<T>)
|
||||
|
||||
class Bar {
|
||||
|
||||
@@ -14,7 +14,7 @@ class A() {
|
||||
|
||||
//more tests
|
||||
val g : () -> Unit = { 42 }
|
||||
val gFunction : () -> Unit = fun(): Int = 1
|
||||
val gFunction : () -> Unit = <!INITIALIZER_TYPE_MISMATCH!>fun(): Int = 1<!>
|
||||
|
||||
val h : () -> Unit = { doSmth() }
|
||||
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@ fun main() {
|
||||
val x1: suspend (Int) -> Unit = takeSuspend(<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.coroutines.SuspendFunction1<kotlin.Int, kotlin.Unit>")!>id { it }<!>, <!DEBUG_INFO_EXPRESSION_TYPE("kotlin.coroutines.SuspendFunction1<kotlin.Int, kotlin.Unit>")!>{ x -> x }<!>)
|
||||
|
||||
// Here, the error should be
|
||||
val x2: (Int) -> Unit = takeSuspend(<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.coroutines.SuspendFunction1<kotlin.Int, kotlin.Unit>")!>id <!ARGUMENT_TYPE_MISMATCH, ARGUMENT_TYPE_MISMATCH!>{ it }<!><!>, <!ARGUMENT_TYPE_MISMATCH, ARGUMENT_TYPE_MISMATCH, DEBUG_INFO_EXPRESSION_TYPE("kotlin.coroutines.SuspendFunction1<kotlin.Int, kotlin.Unit>")!>{ x -> x }<!>)
|
||||
val x2: (Int) -> Unit = <!INITIALIZER_TYPE_MISMATCH!>takeSuspend(<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.coroutines.SuspendFunction1<kotlin.Int, kotlin.Unit>")!>id <!ARGUMENT_TYPE_MISMATCH, ARGUMENT_TYPE_MISMATCH!>{ it }<!><!>, <!ARGUMENT_TYPE_MISMATCH, ARGUMENT_TYPE_MISMATCH, DEBUG_INFO_EXPRESSION_TYPE("kotlin.coroutines.SuspendFunction1<kotlin.Int, kotlin.Unit>")!>{ x -> x }<!>)<!>
|
||||
val x3: suspend (Int) -> Unit = takeSimpleFunction(<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.coroutines.SuspendFunction1<kotlin.Int, kotlin.Unit>")!>id <!ARGUMENT_TYPE_MISMATCH, ARGUMENT_TYPE_MISMATCH!>{ it }<!><!>, <!ARGUMENT_TYPE_MISMATCH, ARGUMENT_TYPE_MISMATCH, DEBUG_INFO_EXPRESSION_TYPE("kotlin.coroutines.SuspendFunction1<kotlin.Int, kotlin.Unit>")!>{ x -> x }<!>)
|
||||
val x4: (Int) -> Unit = takeSimpleFunction(<!ARGUMENT_TYPE_MISMATCH!>id<suspend (Int) -> Unit> {}<!>, <!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Function1<kotlin.Int, kotlin.Unit>")!>{}<!>)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user