[NI] Add constrains even we try add constraint like TypeVariable <: CapturedType from subtyping.
If such captured type has lower type, then from TypeVariable <: lowerType => TypeVariable <: CapturedType.
This commit is contained in:
+33
-15
@@ -16,19 +16,17 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.resolve.calls.inference.components
|
package org.jetbrains.kotlin.resolve.calls.inference.components
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.model.*
|
import org.jetbrains.kotlin.resolve.calls.inference.model.*
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.KotlinCallDiagnostic
|
import org.jetbrains.kotlin.resolve.calls.model.KotlinCallDiagnostic
|
||||||
import org.jetbrains.kotlin.types.FlexibleType
|
import org.jetbrains.kotlin.types.*
|
||||||
import org.jetbrains.kotlin.types.SimpleType
|
|
||||||
import org.jetbrains.kotlin.types.TypeConstructor
|
|
||||||
import org.jetbrains.kotlin.types.UnwrappedType
|
|
||||||
import org.jetbrains.kotlin.types.checker.CaptureStatus
|
import org.jetbrains.kotlin.types.checker.CaptureStatus
|
||||||
import org.jetbrains.kotlin.types.checker.NewCapturedType
|
import org.jetbrains.kotlin.types.checker.NewCapturedType
|
||||||
import org.jetbrains.kotlin.types.checker.NewKotlinTypeChecker
|
import org.jetbrains.kotlin.types.checker.NewKotlinTypeChecker
|
||||||
import org.jetbrains.kotlin.types.typeUtil.contains
|
import org.jetbrains.kotlin.types.typeUtil.contains
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class ConstraintInjector(val constraintIncorporator: ConstraintIncorporator) {
|
class ConstraintInjector(val constraintIncorporator: ConstraintIncorporator, val typeApproximator: TypeApproximator) {
|
||||||
private val ALLOWED_DEPTH_DELTA_FOR_INCORPORATION = 3
|
private val ALLOWED_DEPTH_DELTA_FOR_INCORPORATION = 3
|
||||||
|
|
||||||
interface Context {
|
interface Context {
|
||||||
@@ -119,24 +117,44 @@ class ConstraintInjector(val constraintIncorporator: ConstraintIncorporator) {
|
|||||||
override fun addLowerConstraint(typeVariable: TypeConstructor, subType: UnwrappedType) =
|
override fun addLowerConstraint(typeVariable: TypeConstructor, subType: UnwrappedType) =
|
||||||
addConstraint(typeVariable, subType, ConstraintKind.LOWER)
|
addConstraint(typeVariable, subType, ConstraintKind.LOWER)
|
||||||
|
|
||||||
|
private fun isCapturedTypeFromSubtyping(type: UnwrappedType) =
|
||||||
|
when ((type as? NewCapturedType)?.captureStatus) {
|
||||||
|
null, CaptureStatus.FROM_EXPRESSION -> false
|
||||||
|
CaptureStatus.FOR_SUBTYPING -> true
|
||||||
|
CaptureStatus.FOR_INCORPORATION ->
|
||||||
|
error("Captured type for incorporation shouldn't escape from incorporation: $type\n" + renderBaseConstraint())
|
||||||
|
}
|
||||||
|
|
||||||
private fun addConstraint(typeVariableConstructor: TypeConstructor, type: UnwrappedType, kind: ConstraintKind) {
|
private fun addConstraint(typeVariableConstructor: TypeConstructor, type: UnwrappedType, kind: ConstraintKind) {
|
||||||
val typeVariable = c.allTypeVariables[typeVariableConstructor]
|
val typeVariable = c.allTypeVariables[typeVariableConstructor]
|
||||||
?: error("Should by type variableConstructor: $typeVariableConstructor. ${c.allTypeVariables.values}")
|
?: error("Should by type variableConstructor: $typeVariableConstructor. ${c.allTypeVariables.values}")
|
||||||
|
|
||||||
if (type.contains {
|
var targetType = type
|
||||||
val captureStatus = (it as? NewCapturedType)?.captureStatus
|
if (type.contains(this::isCapturedTypeFromSubtyping)) {
|
||||||
assert(captureStatus != CaptureStatus.FOR_INCORPORATION) {
|
// TypeVariable <: type -> if TypeVariable <: subType => TypeVariable <: type
|
||||||
"Captured type for incorporation shouldn't escape from incorporation: $type\n" + renderBaseConstraint()
|
if (kind == ConstraintKind.UPPER) {
|
||||||
|
val subType = typeApproximator.approximateToSubType(type, TypeApproximatorConfiguration.SubtypeCapturedTypesApproximation)
|
||||||
|
if (subType != null && !KotlinBuiltIns.isNothingOrNullableNothing(subType)) {
|
||||||
|
targetType = subType
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (kind == ConstraintKind.LOWER) {
|
||||||
|
val superType = typeApproximator.approximateToSuperType(type, TypeApproximatorConfiguration.SubtypeCapturedTypesApproximation)
|
||||||
|
if (superType != null && !KotlinBuiltIns.isAnyOrNullableAny(superType)) { // todo rethink error reporting for Any cases
|
||||||
|
targetType = superType
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (targetType === type) {
|
||||||
|
c.addError(CapturedTypeFromSubtyping(typeVariable, type, position))
|
||||||
|
return
|
||||||
}
|
}
|
||||||
captureStatus != null && captureStatus != CaptureStatus.FROM_EXPRESSION
|
|
||||||
}) {
|
|
||||||
c.addError(CapturedTypeFromSubtyping(typeVariable, type, position))
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!c.isAllowedType(type)) return
|
if (!c.isAllowedType(targetType)) return
|
||||||
|
|
||||||
val newConstraint = Constraint(kind, type, position)
|
val newConstraint = Constraint(kind, targetType, position)
|
||||||
possibleNewConstraints.add(typeVariable to newConstraint)
|
possibleNewConstraints.add(typeVariable to newConstraint)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,12 +19,8 @@ package org.jetbrains.kotlin.types
|
|||||||
import org.jetbrains.kotlin.resolve.calls.components.CommonSupertypeCalculator
|
import org.jetbrains.kotlin.resolve.calls.components.CommonSupertypeCalculator
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.model.TypeVariableTypeConstructor
|
import org.jetbrains.kotlin.resolve.calls.inference.model.TypeVariableTypeConstructor
|
||||||
import org.jetbrains.kotlin.types.TypeApproximatorConfiguration.IntersectionStrategy.*
|
import org.jetbrains.kotlin.types.TypeApproximatorConfiguration.IntersectionStrategy.*
|
||||||
import org.jetbrains.kotlin.types.checker.CaptureStatus.FOR_INCORPORATION
|
import org.jetbrains.kotlin.types.checker.*
|
||||||
import org.jetbrains.kotlin.types.checker.CaptureStatus.FROM_EXPRESSION
|
import org.jetbrains.kotlin.types.checker.CaptureStatus.*
|
||||||
import org.jetbrains.kotlin.types.checker.NewCapturedType
|
|
||||||
import org.jetbrains.kotlin.types.checker.NewCapturedTypeConstructor
|
|
||||||
import org.jetbrains.kotlin.types.checker.NewKotlinTypeChecker
|
|
||||||
import org.jetbrains.kotlin.types.checker.intersectTypes
|
|
||||||
import org.jetbrains.kotlin.types.typeUtil.asTypeProjection
|
import org.jetbrains.kotlin.types.typeUtil.asTypeProjection
|
||||||
import org.jetbrains.kotlin.types.typeUtil.builtIns
|
import org.jetbrains.kotlin.types.typeUtil.builtIns
|
||||||
import org.jetbrains.kotlin.types.typeUtil.isNothing
|
import org.jetbrains.kotlin.types.typeUtil.isNothing
|
||||||
@@ -64,24 +60,18 @@ open class TypeApproximatorConfiguration {
|
|||||||
override val allFlexible get() = true
|
override val allFlexible get() = true
|
||||||
}
|
}
|
||||||
|
|
||||||
object IncorporationConfiguration : TypeApproximatorConfiguration.AllFlexibleSameValue() {
|
abstract class AbstractCapturedTypesApproximation(val approximatedCapturedStatus: CaptureStatus): TypeApproximatorConfiguration.AllFlexibleSameValue() {
|
||||||
override val allFlexible get() = true
|
override val allFlexible get() = true
|
||||||
|
|
||||||
// i.e. will be approximated only FOR_INCORPORATION captured types
|
// i.e. will be approximated only approximatedCapturedStatus captured types
|
||||||
override val capturedType get() = { it: NewCapturedType -> it.captureStatus != FOR_INCORPORATION }
|
override val capturedType get() = { it: NewCapturedType -> it.captureStatus != approximatedCapturedStatus }
|
||||||
override val intersection get() = IntersectionStrategy.ALLOWED
|
|
||||||
override val typeVariable: (TypeVariableTypeConstructor) -> Boolean get() = { true }
|
|
||||||
}
|
|
||||||
|
|
||||||
object CapturedTypesApproximation : TypeApproximatorConfiguration.AllFlexibleSameValue() {
|
|
||||||
override val allFlexible get() = true
|
|
||||||
|
|
||||||
// i.e. will be approximated only FROM_EXPRESSION captured types
|
|
||||||
override val capturedType get() = { it: NewCapturedType -> it.captureStatus != FROM_EXPRESSION }
|
|
||||||
override val intersection get() = IntersectionStrategy.ALLOWED
|
override val intersection get() = IntersectionStrategy.ALLOWED
|
||||||
override val typeVariable: (TypeVariableTypeConstructor) -> Boolean get() = { true }
|
override val typeVariable: (TypeVariableTypeConstructor) -> Boolean get() = { true }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
object IncorporationConfiguration : TypeApproximatorConfiguration.AbstractCapturedTypesApproximation(FOR_INCORPORATION)
|
||||||
|
object SubtypeCapturedTypesApproximation : TypeApproximatorConfiguration.AbstractCapturedTypesApproximation(FOR_SUBTYPING)
|
||||||
|
object CapturedTypesApproximation : TypeApproximatorConfiguration.AbstractCapturedTypesApproximation(FROM_EXPRESSION)
|
||||||
}
|
}
|
||||||
|
|
||||||
class TypeApproximator(private val commonSupertypeCalculator: CommonSupertypeCalculator) {
|
class TypeApproximator(private val commonSupertypeCalculator: CommonSupertypeCalculator) {
|
||||||
|
|||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
fun <V, R, M : MutableMap<in R, out V>> mapKeysTo(destination: M): Inv3<R, V, M> {
|
||||||
|
val foo = associateByTo(destination)
|
||||||
|
|
||||||
|
return foo
|
||||||
|
}
|
||||||
|
|
||||||
|
fun < Y, Z, T : MutableMap<in Y, out Z>> associateByTo(<!UNUSED_PARAMETER!>destination<!>: T): Inv3<Y, Z, T> = TODO()
|
||||||
|
|
||||||
|
interface Inv3<A, B, C>
|
||||||
+10
@@ -0,0 +1,10 @@
|
|||||||
|
package
|
||||||
|
|
||||||
|
public fun </*0*/ Y, /*1*/ Z, /*2*/ T : kotlin.collections.MutableMap<in Y, out Z>> associateByTo(/*0*/ destination: T): Inv3<Y, Z, T>
|
||||||
|
public fun </*0*/ V, /*1*/ R, /*2*/ M : kotlin.collections.MutableMap<in R, out V>> mapKeysTo(/*0*/ destination: M): Inv3<R, V, M>
|
||||||
|
|
||||||
|
public interface Inv3</*0*/ A, /*1*/ B, /*2*/ C> {
|
||||||
|
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
|
||||||
|
}
|
||||||
@@ -10242,6 +10242,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("captureFromSubtyping.kt")
|
||||||
|
public void testCaptureFromSubtyping() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/inference/capturedTypes/captureFromSubtyping.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("captureFromTypeParameterUpperBound.kt")
|
@TestMetadata("captureFromTypeParameterUpperBound.kt")
|
||||||
public void testCaptureFromTypeParameterUpperBound() throws Exception {
|
public void testCaptureFromTypeParameterUpperBound() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/inference/capturedTypes/captureFromTypeParameterUpperBound.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/inference/capturedTypes/captureFromTypeParameterUpperBound.kt");
|
||||||
|
|||||||
@@ -122,7 +122,7 @@ enum class CaptureStatus {
|
|||||||
class NewCapturedType(
|
class NewCapturedType(
|
||||||
val captureStatus: CaptureStatus,
|
val captureStatus: CaptureStatus,
|
||||||
override val constructor: NewCapturedTypeConstructor,
|
override val constructor: NewCapturedTypeConstructor,
|
||||||
val lowerType: UnwrappedType?,
|
val lowerType: UnwrappedType?, // todo check lower type for nullable captured types
|
||||||
override val annotations: Annotations = Annotations.EMPTY,
|
override val annotations: Annotations = Annotations.EMPTY,
|
||||||
override val isMarkedNullable: Boolean = false
|
override val isMarkedNullable: Boolean = false
|
||||||
): SimpleType() {
|
): SimpleType() {
|
||||||
|
|||||||
Reference in New Issue
Block a user