[NI] Capture from supertypes of type parameter.
This works by accident in OI, so this should be supported by new inference.
This commit is contained in:
+39
-4
@@ -19,18 +19,21 @@ package org.jetbrains.kotlin.resolve.calls.components
|
||||
import org.jetbrains.kotlin.builtins.getValueParameterTypesFromFunctionType
|
||||
import org.jetbrains.kotlin.builtins.isExtensionFunctionType
|
||||
import org.jetbrains.kotlin.builtins.isFunctionType
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.ArgumentConstraintPosition
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.LambdaTypeVariable
|
||||
import org.jetbrains.kotlin.resolve.calls.model.*
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.isSuccess
|
||||
import org.jetbrains.kotlin.types.UnwrappedType
|
||||
import org.jetbrains.kotlin.types.checker.captureFromExpression
|
||||
import org.jetbrains.kotlin.types.checker.hasSupertypeWithGivenTypeConstructor
|
||||
import org.jetbrains.kotlin.types.checker.intersectWrappedTypes
|
||||
import org.jetbrains.kotlin.types.lowerIfFlexible
|
||||
import org.jetbrains.kotlin.types.typeUtil.builtIns
|
||||
import org.jetbrains.kotlin.types.typeUtil.immediateSupertypes
|
||||
import org.jetbrains.kotlin.types.typeUtil.supertypes
|
||||
import org.jetbrains.kotlin.types.upperIfFlexible
|
||||
import org.jetbrains.kotlin.utils.SmartList
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
import java.lang.UnsupportedOperationException
|
||||
@@ -202,7 +205,7 @@ internal fun checkExpressionArgument(
|
||||
isReceiver: Boolean
|
||||
): KotlinCallDiagnostic? {
|
||||
// todo run this approximation only once for call
|
||||
val argumentType = expressionArgument.stableType
|
||||
val argumentType = captureFromTypeParameterUpperBoundIfNeeded(expressionArgument.stableType, expectedType)
|
||||
|
||||
fun unstableSmartCastOrSubtypeError(
|
||||
unstableType: UnwrappedType?, expectedType: UnwrappedType, position: ArgumentConstraintPosition
|
||||
@@ -246,6 +249,38 @@ internal fun checkExpressionArgument(
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
* }
|
||||
*
|
||||
*/
|
||||
private fun captureFromTypeParameterUpperBoundIfNeeded(argumentType: UnwrappedType, expectedType: UnwrappedType): UnwrappedType {
|
||||
val expectedTypeConstructor = expectedType.upperIfFlexible().constructor
|
||||
|
||||
if (argumentType.lowerIfFlexible().constructor.declarationDescriptor is TypeParameterDescriptor) {
|
||||
val chosenSupertype = argumentType.lowerIfFlexible().supertypes().singleOrNull {
|
||||
it.constructor.declarationDescriptor is ClassifierDescriptorWithTypeParameters &&
|
||||
it.unwrap().hasSupertypeWithGivenTypeConstructor(expectedTypeConstructor)
|
||||
}
|
||||
if (chosenSupertype != null) {
|
||||
return captureFromExpression(chosenSupertype.unwrap()) ?: argumentType
|
||||
}
|
||||
}
|
||||
|
||||
return argumentType
|
||||
}
|
||||
|
||||
// if expression is not stable and has smart casts, then we create this type
|
||||
private val ExpressionKotlinCallArgument.unstableType: UnwrappedType?
|
||||
get() {
|
||||
|
||||
Vendored
+11
@@ -0,0 +1,11 @@
|
||||
interface Inv<T>
|
||||
|
||||
fun <Y: X, X : Inv<out String>> foo(x: X, y: Y) {
|
||||
val rX = bar(x)
|
||||
rX.length
|
||||
|
||||
val rY = bar(y)
|
||||
rY.length
|
||||
}
|
||||
|
||||
fun <Y> bar(<!UNUSED_PARAMETER!>l<!>: Inv<Y>): Y = TODO()
|
||||
Vendored
+10
@@ -0,0 +1,10 @@
|
||||
package
|
||||
|
||||
public fun </*0*/ Y> bar(/*0*/ l: Inv<Y>): Y
|
||||
public fun </*0*/ Y : X, /*1*/ X : Inv<out kotlin.String>> foo(/*0*/ x: X, /*1*/ y: Y): kotlin.Unit
|
||||
|
||||
public interface Inv</*0*/ T> {
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
@@ -10236,6 +10236,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("captureFromTypeParameterUpperBound.kt")
|
||||
public void testCaptureFromTypeParameterUpperBound() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/inference/capturedTypes/captureFromTypeParameterUpperBound.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("captureTypeOnlyOnTopLevel.kt")
|
||||
public void testCaptureTypeOnlyOnTopLevel() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/inference/capturedTypes/captureTypeOnlyOnTopLevel.kt");
|
||||
|
||||
@@ -391,6 +391,9 @@ object NullabilityChecker {
|
||||
|
||||
}
|
||||
|
||||
fun UnwrappedType.hasSupertypeWithGivenTypeConstructor(typeConstructor: TypeConstructor) =
|
||||
TypeCheckerContext(false).anySupertype(lowerIfFlexible(), { it.constructor == typeConstructor }, { SupertypesPolicy.LowerIfFlexible })
|
||||
|
||||
/**
|
||||
* ClassType means that type constructor for this type is type for real class or interface
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user