From 4202c9c1a467582f13d2d56e9f6f933ac9a35c69 Mon Sep 17 00:00:00 2001 From: Denis Zharkov Date: Fri, 10 Jan 2020 16:06:15 +0300 Subject: [PATCH] NI: Fix regression for star-projections approximation See the test added ^KT-35703 Fixed --- .../jetbrains/kotlin/fir/types/ConeTypes.kt | 11 +++++++--- .../fir/resolve/calls/ConeInferenceContext.kt | 5 +++++ .../kotlin/fir/types/ConeTypeContext.kt | 2 +- ...irOldFrontendDiagnosticsTestGenerated.java | 5 +++++ .../components/NewTypeSubstitutor.kt | 5 ++++- .../kotlin/types/TypeApproximator.kt | 6 ++++-- ...oximationFromDifferentTypeParameter.fir.kt | 20 +++++++++++++++++++ ...ApproximationFromDifferentTypeParameter.kt | 20 +++++++++++++++++++ .../checkers/DiagnosticsTestGenerated.java | 5 +++++ .../DiagnosticsUsingJavacTestGenerated.java | 5 +++++ .../types/checker/ClassicTypeSystemContext.kt | 5 +++++ .../kotlin/types/checker/NewCapturedType.kt | 15 ++++++++------ .../kotlin/types/model/TypeSystemContext.kt | 1 + 13 files changed, 92 insertions(+), 13 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/inference/starApproximationFromDifferentTypeParameter.fir.kt create mode 100644 compiler/testData/diagnostics/tests/inference/starApproximationFromDifferentTypeParameter.kt diff --git a/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/ConeTypes.kt b/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/ConeTypes.kt index d5b64793ad4..d1fd3c073a0 100644 --- a/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/ConeTypes.kt +++ b/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/ConeTypes.kt @@ -144,7 +144,8 @@ fun ConeKotlinType.lowerBoundIfFlexible() = (this as? ConeFlexibleType)?.lowerBo class ConeCapturedTypeConstructor( val projection: ConeKotlinTypeProjection, - var supertypes: List? = null + var supertypes: List? = 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 ) ) diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ConeInferenceContext.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ConeInferenceContext.kt index a1b2ee13922..f66f57e5717 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ConeInferenceContext.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ConeInferenceContext.kt @@ -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 diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/ConeTypeContext.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/ConeTypeContext.kt index 53e5009a02b..4ed1d6daf0d 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/ConeTypeContext.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/ConeTypeContext.kt @@ -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) { diff --git a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java index e6e1862b24d..e71df75af78 100644 --- a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java +++ b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java @@ -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"); diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/NewTypeSubstitutor.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/NewTypeSubstitutor.kt index fba419b71a9..8f827a053d8 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/NewTypeSubstitutor.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/NewTypeSubstitutor.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 { diff --git a/compiler/resolution/src/org/jetbrains/kotlin/types/TypeApproximator.kt b/compiler/resolution/src/org/jetbrains/kotlin/types/TypeApproximator.kt index c3ff7d12115..872f35a29ee 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/types/TypeApproximator.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/types/TypeApproximator.kt @@ -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 diff --git a/compiler/testData/diagnostics/tests/inference/starApproximationFromDifferentTypeParameter.fir.kt b/compiler/testData/diagnostics/tests/inference/starApproximationFromDifferentTypeParameter.fir.kt new file mode 100644 index 00000000000..9c8c4f1d4be --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/starApproximationFromDifferentTypeParameter.fir.kt @@ -0,0 +1,20 @@ +// SKIP_TXT +// !LANGUAGE: +NewInference + +// See KT-14453 and KT-35703 +val KClass1.primaryConstructor: KFunction1? get() = null!! + +interface KClass1 +interface KFunction1 +fun f(type: KClass1<*>): KFunction1? = + // 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' in new type checker. + // The answer is correct, but this old type checker used `projectionType` for this and it was resulting in KFunction1<*> <: KFunction1 + // + // 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 diff --git a/compiler/testData/diagnostics/tests/inference/starApproximationFromDifferentTypeParameter.kt b/compiler/testData/diagnostics/tests/inference/starApproximationFromDifferentTypeParameter.kt new file mode 100644 index 00000000000..9c8c4f1d4be --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/starApproximationFromDifferentTypeParameter.kt @@ -0,0 +1,20 @@ +// SKIP_TXT +// !LANGUAGE: +NewInference + +// See KT-14453 and KT-35703 +val KClass1.primaryConstructor: KFunction1? get() = null!! + +interface KClass1 +interface KFunction1 +fun f(type: KClass1<*>): KFunction1? = + // 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' in new type checker. + // The answer is correct, but this old type checker used `projectionType` for this and it was resulting in KFunction1<*> <: KFunction1 + // + // 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 diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index 653977fb788..7cc557bd6a7 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -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"); diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java index ac5e4e069a6..3fc3d8e6e4e 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java @@ -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"); diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/checker/ClassicTypeSystemContext.kt b/core/descriptors/src/org/jetbrains/kotlin/types/checker/ClassicTypeSystemContext.kt index 65ac8473f56..9e49a1cc951 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/checker/ClassicTypeSystemContext.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/checker/ClassicTypeSystemContext.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 diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/checker/NewCapturedType.kt b/core/descriptors/src/org/jetbrains/kotlin/types/checker/NewCapturedType.kt index 2ee573d171a..06a26934326 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/checker/NewCapturedType.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/checker/NewCapturedType.kt @@ -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 get() = listOf() @@ -140,7 +141,8 @@ class NewCapturedType( class NewCapturedTypeConstructor( override val projection: TypeProjection, private var supertypesComputation: (() -> List)? = 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 { diff --git a/core/type-system/src/org/jetbrains/kotlin/types/model/TypeSystemContext.kt b/core/type-system/src/org/jetbrains/kotlin/types/model/TypeSystemContext.kt index 69cf6c675cc..831cf847684 100644 --- a/core/type-system/src/org/jetbrains/kotlin/types/model/TypeSystemContext.kt +++ b/core/type-system/src/org/jetbrains/kotlin/types/model/TypeSystemContext.kt @@ -153,6 +153,7 @@ interface TypeSystemInferenceExtensionContext : TypeSystemContext, TypeSystemBui fun KotlinTypeMarker.mayBeTypeVariable(): Boolean fun CapturedTypeMarker.typeConstructorProjection(): TypeArgumentMarker + fun CapturedTypeMarker.typeParameter(): TypeParameterMarker? fun DefinitelyNotNullTypeMarker.original(): SimpleTypeMarker