[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");
|
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")
|
@TestMetadata("kt41989.kt")
|
||||||
public void testKt41989() throws Exception {
|
public void testKt41989() throws Exception {
|
||||||
runTest("compiler/fir/analysis-tests/testData/resolve/inference/kt41989.kt");
|
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");
|
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")
|
@TestMetadata("kt41989.kt")
|
||||||
public void testKt41989() throws Exception {
|
public void testKt41989() throws Exception {
|
||||||
runTest("compiler/fir/analysis-tests/testData/resolve/inference/kt41989.kt");
|
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.body.resolve.resultType
|
||||||
import org.jetbrains.kotlin.fir.resolve.transformers.ensureResolvedTypeDeclaration
|
import org.jetbrains.kotlin.fir.resolve.transformers.ensureResolvedTypeDeclaration
|
||||||
import org.jetbrains.kotlin.fir.returnExpressions
|
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.symbols.StandardClassIds
|
||||||
|
import org.jetbrains.kotlin.fir.typeCheckerContext
|
||||||
import org.jetbrains.kotlin.fir.typeContext
|
import org.jetbrains.kotlin.fir.typeContext
|
||||||
import org.jetbrains.kotlin.fir.types.*
|
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.ConstraintSystemBuilder
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.addSubtypeConstraintIfCompatible
|
import org.jetbrains.kotlin.resolve.calls.inference.addSubtypeConstraintIfCompatible
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.model.SimpleConstraintSystemConstraintPosition
|
import org.jetbrains.kotlin.resolve.calls.inference.model.SimpleConstraintSystemConstraintPosition
|
||||||
@@ -408,3 +411,49 @@ internal fun FirExpression.getExpectedType(
|
|||||||
fun ConeKotlinType.varargElementType(): ConeKotlinType {
|
fun ConeKotlinType.varargElementType(): ConeKotlinType {
|
||||||
return this.arrayElementType() ?: this
|
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 {
|
} else {
|
||||||
val argumentExtensionReceiverValue = candidate.implicitExtensionReceiverValue
|
val argumentExtensionReceiverValue = candidate.implicitExtensionReceiverValue
|
||||||
if (argumentExtensionReceiverValue != null && explicitReceiverKind.shouldBeCheckedAgainstImplicit()) {
|
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.resolvePlainArgumentType(
|
||||||
candidate.csBuilder,
|
candidate.csBuilder,
|
||||||
argumentType = argumentExtensionReceiverValue.type,
|
argumentType = argumentType,
|
||||||
expectedType = candidate.substitutor.substituteOrSelf(expectedReceiverType.type),
|
expectedType = expectedType,
|
||||||
sink = sink,
|
sink = sink,
|
||||||
context = context,
|
context = context,
|
||||||
isReceiver = true,
|
isReceiver = true,
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND_FIR: JVM_IR
|
|
||||||
// IGNORE_BACKEND: JS_IR
|
// IGNORE_BACKEND: JS_IR
|
||||||
// IGNORE_BACKEND: JS_IR_ES6
|
// IGNORE_BACKEND: JS_IR_ES6
|
||||||
// TODO: muted automatically, investigate should it be ran for JS or not
|
// TODO: muted automatically, investigate should it be ran for JS or not
|
||||||
|
|||||||
Reference in New Issue
Block a user