[FIR] Capture type from type parameter upper bound when needed
This commit is contained in:
@@ -0,0 +1,12 @@
|
||||
// ISSUE: KT-40131
|
||||
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
val <U> KClass<U>.javaImpl: Class<U>
|
||||
get() = null!!
|
||||
|
||||
val <T : KClass<*>> T.myJava1: Class<*>
|
||||
get() = <!DEBUG_INFO_EXPRESSION_TYPE("java.lang.Class<out kotlin.Any?>")!>javaImpl<!>
|
||||
|
||||
val <E : Any, T : KClass<E>> T.myJava2: Class<E>
|
||||
get() = <!DEBUG_INFO_EXPRESSION_TYPE("java.lang.Class<E>")!>javaImpl<!>
|
||||
@@ -0,0 +1,13 @@
|
||||
FILE: kt40131.kt
|
||||
public final val <U> R|kotlin/reflect/KClass<U>|.javaImpl: R|java/lang/Class<U>|
|
||||
public get(): R|java/lang/Class<U>| {
|
||||
^ Null(null)!!
|
||||
}
|
||||
public final val <T : R|kotlin/reflect/KClass<*>|> R|T|.myJava1: R|java/lang/Class<*>|
|
||||
public get(): R|java/lang/Class<*>| {
|
||||
^ this@R|/myJava1|.R|/javaImpl|<R|kotlin/Any?|>
|
||||
}
|
||||
public final val <E : R|kotlin/Any|, T : R|kotlin/reflect/KClass<E>|> R|T|.myJava2: R|java/lang/Class<E>|
|
||||
public get(): R|java/lang/Class<E>| {
|
||||
^ this@R|/myJava2|.R|/javaImpl|<R|E|>
|
||||
}
|
||||
Generated
+5
@@ -1744,6 +1744,11 @@ public class FirDiagnosticsTestGenerated extends AbstractFirDiagnosticsTest {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/inference/intersectionTypesInConstraints.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt40131.kt")
|
||||
public void testKt40131() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/inference/kt40131.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt41989.kt")
|
||||
public void testKt41989() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/inference/kt41989.kt");
|
||||
|
||||
+5
@@ -1744,6 +1744,11 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/inference/intersectionTypesInConstraints.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt40131.kt")
|
||||
public void testKt40131() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/inference/kt40131.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt41989.kt")
|
||||
public void testKt41989() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/inference/kt41989.kt");
|
||||
|
||||
@@ -15,9 +15,12 @@ import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.firUnsafe
|
||||
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.resultType
|
||||
import org.jetbrains.kotlin.fir.resolve.transformers.ensureResolvedTypeDeclaration
|
||||
import org.jetbrains.kotlin.fir.returnExpressions
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
|
||||
import org.jetbrains.kotlin.fir.symbols.StandardClassIds
|
||||
import org.jetbrains.kotlin.fir.typeCheckerContext
|
||||
import org.jetbrains.kotlin.fir.typeContext
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.addSubtypeConstraintIfCompatible
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.SimpleConstraintSystemConstraintPosition
|
||||
@@ -408,3 +411,49 @@ internal fun FirExpression.getExpectedType(
|
||||
fun ConeKotlinType.varargElementType(): ConeKotlinType {
|
||||
return this.arrayElementType() ?: this
|
||||
}
|
||||
|
||||
/**
|
||||
* interface Inv<T>
|
||||
* fun <Y> bar(l: Inv<Y>): Y = ...
|
||||
*
|
||||
* fun <X : Inv<out Int>> foo(x: X) {
|
||||
* val xr = bar(x)
|
||||
* }
|
||||
* Here we try to capture from upper bound from type parameter.
|
||||
* We replace type of `x` to `Inv<out Int>`(we chose supertype which contains supertype with expectedTypeConstructor) and capture from this type.
|
||||
* It is correct, because it is like this code:
|
||||
* fun <X : Inv<out Int>> foo(x: X) {
|
||||
* val inv: Inv<out Int> = x
|
||||
* val xr = bar(inv)
|
||||
* }
|
||||
*
|
||||
*/
|
||||
internal fun captureFromTypeParameterUpperBoundIfNeeded(
|
||||
argumentType: ConeKotlinType,
|
||||
expectedType: ConeKotlinType,
|
||||
session: FirSession
|
||||
): ConeKotlinType {
|
||||
val expectedTypeClassId = expectedType.upperBoundIfFlexible().classId ?: return argumentType
|
||||
val simplifiedArgumentType = argumentType.lowerBoundIfFlexible() as? ConeTypeParameterType ?: return argumentType
|
||||
val typeParameter = simplifiedArgumentType.lookupTag.typeParameterSymbol.fir
|
||||
|
||||
val context = session.typeCheckerContext
|
||||
|
||||
val chosenSupertype = typeParameter.bounds.map { it.coneType }
|
||||
.singleOrNull { it.hasSupertypeWithGivenClassId(expectedTypeClassId, context) } ?: return argumentType
|
||||
|
||||
val capturedType = context.captureFromExpression(chosenSupertype) as ConeKotlinType? ?: return argumentType
|
||||
return if (argumentType is ConeDefinitelyNotNullType) {
|
||||
ConeDefinitelyNotNullType.create(capturedType) ?: capturedType
|
||||
} else {
|
||||
capturedType
|
||||
}
|
||||
}
|
||||
|
||||
private fun ConeKotlinType.hasSupertypeWithGivenClassId(classId: ClassId, context: ConeTypeCheckerContext): Boolean {
|
||||
return with(context) {
|
||||
anySuperTypeConstructor {
|
||||
it is ConeClassLikeLookupTag && it.classId == classId
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,10 +130,16 @@ internal sealed class CheckReceivers : ResolutionStage() {
|
||||
} else {
|
||||
val argumentExtensionReceiverValue = candidate.implicitExtensionReceiverValue
|
||||
if (argumentExtensionReceiverValue != null && explicitReceiverKind.shouldBeCheckedAgainstImplicit()) {
|
||||
val expectedType = candidate.substitutor.substituteOrSelf(expectedReceiverType.type)
|
||||
val argumentType = captureFromTypeParameterUpperBoundIfNeeded(
|
||||
argumentType = argumentExtensionReceiverValue.type,
|
||||
expectedType = expectedType,
|
||||
session = context.session
|
||||
)
|
||||
candidate.resolvePlainArgumentType(
|
||||
candidate.csBuilder,
|
||||
argumentType = argumentExtensionReceiverValue.type,
|
||||
expectedType = candidate.substitutor.substituteOrSelf(expectedReceiverType.type),
|
||||
argumentType = argumentType,
|
||||
expectedType = expectedType,
|
||||
sink = sink,
|
||||
context = context,
|
||||
isReceiver = true,
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
// IGNORE_BACKEND: JS_IR_ES6
|
||||
// TODO: muted automatically, investigate should it be ran for JS or not
|
||||
|
||||
Reference in New Issue
Block a user