[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:
Stanislav Erokhin
2017-04-07 13:24:34 +03:00
parent 657c332a1f
commit 53caa84db9
6 changed files with 67 additions and 34 deletions
@@ -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) {
@@ -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>
@@ -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() {