NI: Fix regression for star-projections approximation

See the test added

^KT-35703 Fixed
This commit is contained in:
Denis Zharkov
2020-01-10 16:06:15 +03:00
parent 7255ee0a5b
commit 4202c9c1a4
13 changed files with 92 additions and 13 deletions
@@ -144,7 +144,8 @@ fun ConeKotlinType.lowerBoundIfFlexible() = (this as? ConeFlexibleType)?.lowerBo
class ConeCapturedTypeConstructor(
val projection: ConeKotlinTypeProjection,
var supertypes: List<ConeKotlinType>? = null
var supertypes: List<ConeKotlinType>? = null,
val typeParameterMarker: TypeParameterMarker? = null
) : CapturedTypeConstructorMarker
class ConeCapturedType(
@@ -153,11 +154,15 @@ class ConeCapturedType(
override val nullability: ConeNullability = ConeNullability.NOT_NULL,
val constructor: ConeCapturedTypeConstructor
) : ConeSimpleKotlinType(), CapturedTypeMarker {
constructor(captureStatus: CaptureStatus, lowerType: ConeKotlinType?, projection: ConeKotlinTypeProjection) : this(
constructor(
captureStatus: CaptureStatus, lowerType: ConeKotlinType?, projection: ConeKotlinTypeProjection,
typeParameterMarker: TypeParameterMarker
) : this(
captureStatus,
lowerType,
constructor = ConeCapturedTypeConstructor(
projection
projection,
typeParameterMarker = typeParameterMarker
)
)
@@ -257,6 +257,11 @@ interface ConeInferenceContext : TypeSystemInferenceExtensionContext, ConeTypeCo
return this.constructor.projection
}
override fun CapturedTypeMarker.typeParameter(): TypeParameterMarker? {
require(this is ConeCapturedType)
return this.constructor.typeParameterMarker
}
override fun DefinitelyNotNullTypeMarker.original(): SimpleTypeMarker {
require(this is ConeDefinitelyNotNullType)
return this.original as SimpleTypeMarker
@@ -319,7 +319,7 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext, Ty
null
}
ConeCapturedType(status, lowerType, argument as ConeKotlinTypeProjection)
ConeCapturedType(status, lowerType, argument, typeConstructor.getParameter(index))
}
for (index in 0 until argumentsCount) {
@@ -10058,6 +10058,11 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirOldFronte
runTest("compiler/testData/diagnostics/tests/inference/starApproximationFlexible.kt");
}
@TestMetadata("starApproximationFromDifferentTypeParameter.kt")
public void testStarApproximationFromDifferentTypeParameter() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/starApproximationFromDifferentTypeParameter.kt");
}
@TestMetadata("tooEagerSmartcast.kt")
public void testTooEagerSmartcast() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/tooEagerSmartcast.kt");
@@ -83,7 +83,10 @@ interface NewTypeSubstitutor: TypeSubstitutorMarker {
if (innerType is StubType || substitutedInnerType is StubType) {
return NewCapturedType(
capturedType.captureStatus,
NewCapturedTypeConstructor(TypeProjectionImpl(typeConstructor.projection.projectionKind, substitutedInnerType)),
NewCapturedTypeConstructor(
TypeProjectionImpl(typeConstructor.projection.projectionKind, substitutedInnerType),
typeParameter = typeConstructor.typeParameter
),
lowerType = if (capturedType.lowerType != null) substitutedInnerType else null
)
} else {
@@ -485,12 +485,14 @@ abstract class AbstractTypeApproximator(val ctx: TypeSystemInferenceExtensionCon
val argumentType = newArguments[index]?.getType() ?: argument.getType()
val capturedType = argumentType.lowerBoundIfFlexible().asCapturedType()
val capturedStarProjectionOrNull =
argumentType.lowerBoundIfFlexible().asCapturedType()?.typeConstructorProjection()?.takeIf { it.isStarProjection() }
capturedType?.typeConstructorProjection()?.takeIf { it.isStarProjection() }
if (capturedStarProjectionOrNull != null &&
(effectiveVariance == TypeVariance.OUT || effectiveVariance == TypeVariance.INV) &&
toSuper
toSuper &&
capturedType.typeParameter() == parameter
) {
newArguments[index] = capturedStarProjectionOrNull
continue@loop
@@ -0,0 +1,20 @@
// SKIP_TXT
// !LANGUAGE: +NewInference
// See KT-14453 and KT-35703
val <T : Any> KClass1<T>.primaryConstructor: KFunction1<T>? get() = null!!
interface KClass1<F : Any>
interface KFunction1<out R>
fun f(type: KClass1<*>): KFunction1<Any>? =
// What happens here:
// 1. Create captured type for type argument T (it's built upon star-projection from `KClass<*>` that's argument is <: Any)
// 2. Approximate resulting descriptor, now it 'KClass1<*>.primaryConstructor: KFunction1<*>'
// Note that star-projection in 'KFunction1<*>' is obtained from KClass and its `projectionType` is Any (not-nullable).
// Of course that situation is already strange
// 3. When checking subtyping after call completion we get that 'KFunction1<*>' is not a subtype of 'KFunction1<Any>' in new type checker.
// The answer is correct, but this old type checker used `projectionType` for this and it was resulting in KFunction1<*> <: KFunction1<Any>
//
// So to fix the issue we use 'out starProjectionType' instead of star-projection itself in approximation
// Note that in new inference there should be no approximation for IN-position types (they must remain captured)
type.primaryConstructor
@@ -0,0 +1,20 @@
// SKIP_TXT
// !LANGUAGE: +NewInference
// See KT-14453 and KT-35703
val <T : Any> KClass1<T>.primaryConstructor: KFunction1<T>? get() = null!!
interface KClass1<F : Any>
interface KFunction1<out R>
fun f(type: KClass1<*>): KFunction1<Any>? =
// What happens here:
// 1. Create captured type for type argument T (it's built upon star-projection from `KClass<*>` that's argument is <: Any)
// 2. Approximate resulting descriptor, now it 'KClass1<*>.primaryConstructor: KFunction1<*>'
// Note that star-projection in 'KFunction1<*>' is obtained from KClass and its `projectionType` is Any (not-nullable).
// Of course that situation is already strange
// 3. When checking subtyping after call completion we get that 'KFunction1<*>' is not a subtype of 'KFunction1<Any>' in new type checker.
// The answer is correct, but this old type checker used `projectionType` for this and it was resulting in KFunction1<*> <: KFunction1<Any>
//
// So to fix the issue we use 'out starProjectionType' instead of star-projection itself in approximation
// Note that in new inference there should be no approximation for IN-position types (they must remain captured)
type.primaryConstructor
@@ -10065,6 +10065,11 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
runTest("compiler/testData/diagnostics/tests/inference/starApproximationFlexible.kt");
}
@TestMetadata("starApproximationFromDifferentTypeParameter.kt")
public void testStarApproximationFromDifferentTypeParameter() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/starApproximationFromDifferentTypeParameter.kt");
}
@TestMetadata("tooEagerSmartcast.kt")
public void testTooEagerSmartcast() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/tooEagerSmartcast.kt");
@@ -10060,6 +10060,11 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing
runTest("compiler/testData/diagnostics/tests/inference/starApproximationFlexible.kt");
}
@TestMetadata("starApproximationFromDifferentTypeParameter.kt")
public void testStarApproximationFromDifferentTypeParameter() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/starApproximationFromDifferentTypeParameter.kt");
}
@TestMetadata("tooEagerSmartcast.kt")
public void testTooEagerSmartcast() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/tooEagerSmartcast.kt");
@@ -404,6 +404,11 @@ interface ClassicTypeSystemContext : TypeSystemInferenceExtensionContext, TypeSy
return this.constructor.projection
}
override fun CapturedTypeMarker.typeParameter(): TypeParameterMarker? {
require(this is NewCapturedType, this::errorMessage)
return this.constructor.typeParameter
}
override fun CapturedTypeMarker.captureStatus(): CaptureStatus {
require(this is NewCapturedType, this::errorMessage)
return this.captureStatus
@@ -63,7 +63,7 @@ internal fun captureFromArguments(
val arguments = type.arguments
if (arguments.all { it.projectionKind == Variance.INVARIANT }) return null
val capturedArguments = arguments.map { projection ->
val capturedArguments = arguments.zip(type.constructor.parameters).map { (projection, parameter) ->
if (projection.projectionKind == Variance.INVARIANT) return@map projection
val lowerType =
@@ -73,7 +73,7 @@ internal fun captureFromArguments(
null
}
NewCapturedType(status, lowerType, projection).asTypeProjection() // todo optimization: do not create type projection
NewCapturedType(status, lowerType, projection, parameter).asTypeProjection() // todo optimization: do not create type projection
}
val substitutor = TypeConstructorSubstitution.create(type.constructor, capturedArguments).buildSubstitutor()
@@ -112,8 +112,9 @@ class NewCapturedType(
override val annotations: Annotations = Annotations.EMPTY,
override val isMarkedNullable: Boolean = false
) : SimpleType(), CapturedTypeMarker {
internal constructor(captureStatus: CaptureStatus, lowerType: UnwrappedType?, projection: TypeProjection) :
this(captureStatus, NewCapturedTypeConstructor(projection), lowerType)
internal constructor(
captureStatus: CaptureStatus, lowerType: UnwrappedType?, projection: TypeProjection, typeParameter: TypeParameterDescriptor
) : this(captureStatus, NewCapturedTypeConstructor(projection, typeParameter = typeParameter), lowerType)
override val arguments: List<TypeProjection> get() = listOf()
@@ -140,7 +141,8 @@ class NewCapturedType(
class NewCapturedTypeConstructor(
override val projection: TypeProjection,
private var supertypesComputation: (() -> List<UnwrappedType>)? = null,
private val original: NewCapturedTypeConstructor? = null
private val original: NewCapturedTypeConstructor? = null,
val typeParameter: TypeParameterDescriptor? = null
) : CapturedTypeConstructor {
constructor(
@@ -177,7 +179,8 @@ class NewCapturedTypeConstructor(
supertypes.map { it.refine(kotlinTypeRefiner) }
}
},
original ?: this
original ?: this,
typeParameter = typeParameter
)
override fun equals(other: Any?): Boolean {
@@ -153,6 +153,7 @@ interface TypeSystemInferenceExtensionContext : TypeSystemContext, TypeSystemBui
fun KotlinTypeMarker.mayBeTypeVariable(): Boolean
fun CapturedTypeMarker.typeConstructorProjection(): TypeArgumentMarker
fun CapturedTypeMarker.typeParameter(): TypeParameterMarker?
fun DefinitelyNotNullTypeMarker.original(): SimpleTypeMarker