[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
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.*
|
||||
import org.jetbrains.kotlin.resolve.calls.model.KotlinCallDiagnostic
|
||||
import org.jetbrains.kotlin.types.FlexibleType
|
||||
import org.jetbrains.kotlin.types.SimpleType
|
||||
import org.jetbrains.kotlin.types.TypeConstructor
|
||||
import org.jetbrains.kotlin.types.UnwrappedType
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.checker.CaptureStatus
|
||||
import org.jetbrains.kotlin.types.checker.NewCapturedType
|
||||
import org.jetbrains.kotlin.types.checker.NewKotlinTypeChecker
|
||||
import org.jetbrains.kotlin.types.typeUtil.contains
|
||||
import java.util.*
|
||||
|
||||
class ConstraintInjector(val constraintIncorporator: ConstraintIncorporator) {
|
||||
class ConstraintInjector(val constraintIncorporator: ConstraintIncorporator, val typeApproximator: TypeApproximator) {
|
||||
private val ALLOWED_DEPTH_DELTA_FOR_INCORPORATION = 3
|
||||
|
||||
interface Context {
|
||||
@@ -119,24 +117,44 @@ class ConstraintInjector(val constraintIncorporator: ConstraintIncorporator) {
|
||||
override fun addLowerConstraint(typeVariable: TypeConstructor, subType: UnwrappedType) =
|
||||
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) {
|
||||
val typeVariable = c.allTypeVariables[typeVariableConstructor]
|
||||
?: error("Should by type variableConstructor: $typeVariableConstructor. ${c.allTypeVariables.values}")
|
||||
|
||||
if (type.contains {
|
||||
val captureStatus = (it as? NewCapturedType)?.captureStatus
|
||||
assert(captureStatus != CaptureStatus.FOR_INCORPORATION) {
|
||||
"Captured type for incorporation shouldn't escape from incorporation: $type\n" + renderBaseConstraint()
|
||||
var targetType = type
|
||||
if (type.contains(this::isCapturedTypeFromSubtyping)) {
|
||||
// TypeVariable <: type -> if TypeVariable <: subType => TypeVariable <: type
|
||||
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)
|
||||
}
|
||||
|
||||
|
||||
@@ -19,12 +19,8 @@ package org.jetbrains.kotlin.types
|
||||
import org.jetbrains.kotlin.resolve.calls.components.CommonSupertypeCalculator
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.TypeVariableTypeConstructor
|
||||
import org.jetbrains.kotlin.types.TypeApproximatorConfiguration.IntersectionStrategy.*
|
||||
import org.jetbrains.kotlin.types.checker.CaptureStatus.FOR_INCORPORATION
|
||||
import org.jetbrains.kotlin.types.checker.CaptureStatus.FROM_EXPRESSION
|
||||
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.checker.*
|
||||
import org.jetbrains.kotlin.types.checker.CaptureStatus.*
|
||||
import org.jetbrains.kotlin.types.typeUtil.asTypeProjection
|
||||
import org.jetbrains.kotlin.types.typeUtil.builtIns
|
||||
import org.jetbrains.kotlin.types.typeUtil.isNothing
|
||||
@@ -64,24 +60,18 @@ open class TypeApproximatorConfiguration {
|
||||
override val allFlexible get() = true
|
||||
}
|
||||
|
||||
object IncorporationConfiguration : TypeApproximatorConfiguration.AllFlexibleSameValue() {
|
||||
abstract class AbstractCapturedTypesApproximation(val approximatedCapturedStatus: CaptureStatus): TypeApproximatorConfiguration.AllFlexibleSameValue() {
|
||||
override val allFlexible get() = true
|
||||
|
||||
// i.e. will be approximated only FOR_INCORPORATION captured types
|
||||
override val capturedType get() = { it: NewCapturedType -> it.captureStatus != FOR_INCORPORATION }
|
||||
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 }
|
||||
// i.e. will be approximated only approximatedCapturedStatus captured types
|
||||
override val capturedType get() = { it: NewCapturedType -> it.captureStatus != approximatedCapturedStatus }
|
||||
override val intersection get() = IntersectionStrategy.ALLOWED
|
||||
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) {
|
||||
|
||||
+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);
|
||||
}
|
||||
|
||||
@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")
|
||||
public void testCaptureFromTypeParameterUpperBound() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/inference/capturedTypes/captureFromTypeParameterUpperBound.kt");
|
||||
|
||||
@@ -122,7 +122,7 @@ enum class CaptureStatus {
|
||||
class NewCapturedType(
|
||||
val captureStatus: CaptureStatus,
|
||||
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 isMarkedNullable: Boolean = false
|
||||
): SimpleType() {
|
||||
|
||||
Reference in New Issue
Block a user