[FIR] Remove hack for @OnlyInputTypes

#KT-65704
This commit is contained in:
Kirill Rakhman
2024-02-08 12:21:06 +01:00
committed by Space Team
parent b90598823e
commit ef29879740
8 changed files with 33 additions and 39 deletions
@@ -28,6 +28,8 @@ FILE: onlyInputTypesCapturedTypeWithRecursiveBounds.kt
}
private final fun test(node: R|Foo<*>|): R|kotlin/Unit| {
R|<local>/node|.R|SubstitutionOverride</Foo.data: R|kotlin/collections/Map<CapturedType(*), kotlin/Any?>|>|.R|kotlin/collections/get|<R|it(kotlin/Enum<*> & I)|, R|kotlin/Any?|>(Q|MyEnum|.R|/MyEnum.EnumEntry|)
lval map: R|kotlin/collections/Map<out it(kotlin/Enum<*> & I), kotlin/Any?>| = R|<local>/node|.R|SubstitutionOverride</Foo.data: R|kotlin/collections/Map<CapturedType(*), kotlin/Any?>|>|
R|<local>/map|.R|kotlin/collections/get|<R|it(kotlin/Enum<*> & I)|, R|kotlin/Any?|>(Q|MyEnum|.R|/MyEnum.EnumEntry|)
}
public open class FooEnumMap<P : R|kotlin/Enum<P>|, R|I|> : R|kotlin/Any| {
public constructor<P : R|kotlin/Enum<P>|, R|I|>(data: R|java/util/EnumMap<P, kotlin/Any?>|): R|FooEnumMap<P>| {
@@ -40,6 +42,8 @@ FILE: onlyInputTypesCapturedTypeWithRecursiveBounds.kt
}
private final fun test(node: R|FooEnumMap<*>|): R|kotlin/Unit| {
R|<local>/node|.R|SubstitutionOverride</FooEnumMap.data: R|java/util/EnumMap<CapturedType(*), kotlin/Any?>|>|.R|kotlin/collections/get|<R|ft<it(kotlin/Enum<*> & I), it(kotlin/Enum<*>? & I?)>|, R|kotlin/Any!|>(Q|MyEnum|.R|/MyEnum.EnumEntry|)
lval map: R|java/util/EnumMap<out it(kotlin/Enum<*> & I), kotlin/Any?>| = R|<local>/node|.R|SubstitutionOverride</FooEnumMap.data: R|java/util/EnumMap<CapturedType(*), kotlin/Any?>|>|
R|<local>/map|.R|kotlin/collections/get|<R|ft<it(kotlin/Enum<out ft<it(kotlin/Enum<out ft<it(kotlin/Enum<*> & I), it(kotlin/Enum<*>? & I?)>> & I), it(kotlin/Enum<*>? & I?)>> & I), it(kotlin/Enum<*>? & I?)>|, R|kotlin/Any!|>(Q|MyEnum|.R|/MyEnum.EnumEntry|)
}
public open class Foo2<P : R|I|> : R|kotlin/Any| {
public constructor<P : R|I|>(data: R|kotlin/collections/Map<P, kotlin/Any?>|): R|Foo2<P>| {
@@ -52,6 +56,8 @@ FILE: onlyInputTypesCapturedTypeWithRecursiveBounds.kt
}
private final fun test(node: R|Foo2<*>|): R|kotlin/Unit| {
R|<local>/node|.R|SubstitutionOverride</Foo2.data: R|kotlin/collections/Map<CapturedType(*), kotlin/Any?>|>|.R|kotlin/collections/get|<R|I|, R|kotlin/Any?|>(Q|MyEnum|.R|/MyEnum.EnumEntry|)
lval map: R|kotlin/collections/Map<out I, kotlin/Any?>| = R|<local>/node|.R|SubstitutionOverride</Foo2.data: R|kotlin/collections/Map<CapturedType(*), kotlin/Any?>|>|
R|<local>/map|.R|kotlin/collections/get|<R|I|, R|kotlin/Any?|>(Q|MyEnum|.R|/MyEnum.EnumEntry|)
}
public abstract interface I2 : R|kotlin/Any| {
}
@@ -12,18 +12,26 @@ open class Foo<P>(val data: Map<P, Any?>) where P : Enum<P>, P : I
private fun test(node: Foo<*>) {
node.data.get(MyEnum.EnumEntry)
val map = node.data
map.get(MyEnum.EnumEntry)
}
open class FooEnumMap<P>(val data: EnumMap<P, Any?>) where P : Enum<P>, P : I
private fun test(node: FooEnumMap<*>) {
node.data.get(MyEnum.EnumEntry)
val map = node.data
// TODO inferred type argument is giant multi-level type KT-65704
// R|<local>/map|.R|kotlin/collections/get|<R|ft<it(kotlin/Enum<out ft<it(kotlin/Enum<out ft<it(kotlin/Enum<*> & I), it(kotlin/Enum<*>? & I?)>> & I), it(kotlin/Enum<*>? & I?)>> & I), it(kotlin/Enum<*>? & I?)>|, R|kotlin/Any!|>(Q|MyEnum|.R|/MyEnum.EnumEntry|)
map.get(MyEnum.EnumEntry)
}
open class Foo2<P : I>(val data: Map<P, Any?>)
private fun test(node: Foo2<*>) {
node.data.get(MyEnum.EnumEntry)
val map = node.data
map.get(MyEnum.EnumEntry)
}
interface I2
@@ -34,4 +42,5 @@ open class Foo3<P>(val data: Map<P, Any?>) where P : I, P : I2
fun test3(node: Foo3<*>) {
node.data.get(C)
}
}
@@ -419,20 +419,8 @@ class ConstraintSystemCompleter(components: BodyResolveComponents) {
TypeVariableDirectionCalculator.ResolveDirection.UNKNOWN
)
val resultTypeForOnlyInputTypes =
if (with(ConeConstraintSystemUtilContext) { variableWithConstraints.typeVariable.hasOnlyInputTypesAttribute() }) {
inferenceComponents.resultTypeResolver.findResultType(
c,
variableWithConstraints,
TypeVariableDirectionCalculator.ResolveDirection.UNKNOWN,
isForOnlyInputTypes = true
)
} else {
resultType
}
val variable = variableWithConstraints.typeVariable
c.fixVariable(variable, resultType, ConeFixVariableConstraintPosition(variable), resultTypeForOnlyInputTypes)
c.fixVariable(variable, resultType, ConeFixVariableConstraintPosition(variable))
}
companion object {
@@ -401,7 +401,7 @@ object NewCommonSuperTypeCalculator {
return false // arguments for contravariant parameters are intersected, recursion should not be possible
val originalTypesSet = originalTypesForCst.toSet()
val typeArgumentsTypeSet = typeArgumentsForSuperConstructorParameter.map { it.getType().lowerBoundIfFlexible() }.toSet()
val typeArgumentsTypeSet = typeArgumentsForSuperConstructorParameter.map { it.getType().lowerBoundIfFlexible().originalIfDefinitelyNotNullable() }.toSet()
if (originalTypesSet.size != typeArgumentsTypeSet.size)
return false
@@ -414,7 +414,7 @@ object NewCommonSuperTypeCalculator {
var starProjectionFound = false
for (supertype in supertypesIfCapturedStarProjection(argumentType).orEmpty()) {
if (supertype.lowerBoundIfFlexible().typeConstructor() !in originalTypeConstructorSet)
if (supertype.lowerBoundIfFlexible().originalIfDefinitelyNotNullable().typeConstructor() !in originalTypeConstructorSet)
return false
else starProjectionFound = true
}
@@ -429,7 +429,7 @@ object NewCommonSuperTypeCalculator {
for (type in types) {
if (isCapturedStarProjection(type)) {
for (supertype in supertypesIfCapturedStarProjection(type).orEmpty()) {
yield(supertype.lowerBoundIfFlexible().typeConstructor())
yield(supertype.lowerBoundIfFlexible().originalIfDefinitelyNotNullable().typeConstructor())
}
} else {
yield(type.typeConstructor())
@@ -36,7 +36,6 @@ abstract class ConstraintSystemCompletionContext : VariableFixationFinder.Contex
variable: TypeVariableMarker,
resultType: KotlinTypeMarker,
position: FixVariableConstraintPosition<*>,
resultTypeForOnlyInputTypes: KotlinTypeMarker = resultType
)
abstract fun couldBeResolvedWithUnrestrictedBuilderInference(): Boolean
@@ -59,8 +59,8 @@ class ResultTypeResolver(
return if (direction == ResolveDirection.TO_SUBTYPE) nothingType() else nullableAnyType()
}
fun findResultType(c: Context, variableWithConstraints: VariableWithConstraints, direction: ResolveDirection, isForOnlyInputTypes: Boolean = false): KotlinTypeMarker {
findResultTypeOrNull(c, variableWithConstraints, direction, isForOnlyInputTypes)?.let { return it }
fun findResultType(c: Context, variableWithConstraints: VariableWithConstraints, direction: ResolveDirection): KotlinTypeMarker {
findResultTypeOrNull(c, variableWithConstraints, direction)?.let { return it }
// no proper constraints
return c.getDefaultType(direction, variableWithConstraints.constraints, variableWithConstraints.typeVariable)
@@ -70,7 +70,6 @@ class ResultTypeResolver(
c: Context,
variableWithConstraints: VariableWithConstraints,
direction: ResolveDirection,
isForOnlyInputTypes: Boolean = false,
): KotlinTypeMarker? {
val resultTypeFromEqualConstraint = findResultIfThereIsEqualsConstraint(c, variableWithConstraints)
if (resultTypeFromEqualConstraint != null) {
@@ -85,7 +84,7 @@ class ResultTypeResolver(
}
}
val subType = c.findSubType(variableWithConstraints, isForOnlyInputTypes)
val subType = c.findSubType(variableWithConstraints)
// Super type should be the most flexible, sub type should be the least one
val superType = c.findSuperType(variableWithConstraints).makeFlexibleIfNecessary(c, variableWithConstraints.constraints)
@@ -210,11 +209,12 @@ class ResultTypeResolver(
return constraints.singleOrNull { it.kind.isLower() }?.isNullabilityConstraint ?: false
}
private fun Context.findSubType(variableWithConstraints: VariableWithConstraints, isForOnlyInputTypes: Boolean): KotlinTypeMarker? {
val lowerConstraintTypes = prepareLowerConstraints(variableWithConstraints.constraints, isForOnlyInputTypes)
private fun Context.findSubType(variableWithConstraints: VariableWithConstraints): KotlinTypeMarker? {
val lowerConstraintTypes = prepareLowerConstraints(variableWithConstraints.constraints)
if (lowerConstraintTypes.isNotEmpty()) {
val types = sinkIntegerLiteralTypes(lowerConstraintTypes)
// TODO Improve handling of flexible types with recursive captured type arguments to not produce giant multi-level-deep types KT-65704
var commonSuperType = computeCommonSuperType(types)
if (commonSuperType.contains { it.asSimpleType()?.isStubTypeForVariableInSubtyping() == true }) {
@@ -268,7 +268,7 @@ class ResultTypeResolver(
private fun Context.computeCommonSuperType(types: List<KotlinTypeMarker>): KotlinTypeMarker =
with(NewCommonSuperTypeCalculator) { commonSuperType(types) }
private fun Context.prepareLowerConstraints(constraints: List<Constraint>, isForOnlyInputTypes: Boolean): List<KotlinTypeMarker> {
private fun Context.prepareLowerConstraints(constraints: List<Constraint>): List<KotlinTypeMarker> {
var atLeastOneProper = false
var atLeastOneNonProper = false
@@ -277,14 +277,7 @@ class ResultTypeResolver(
for (constraint in constraints) {
if (constraint.kind != ConstraintKind.LOWER) continue
var type = constraint.type
// The call to commonSuperTypes will replace arguments that have recursive supertypes with star projections,
// which will lead to a different resulting type than approximating it first.
// This breaks the @OnlyInputTypes check for captured types with recursive super types.
if (isForOnlyInputTypes && isK2 && hasRecursiveTypeParametersWithGivenSelfType(type.typeConstructor())) {
type = typeApproximator.approximateToSuperType(type, TypeApproximatorConfiguration.InternalTypesApproximation) ?: type
}
val type = constraint.type
lowerConstraintTypes.add(type)
@@ -567,7 +567,6 @@ class NewConstraintSystemImpl(
variable: TypeVariableMarker,
resultType: KotlinTypeMarker,
position: FixVariableConstraintPosition<*>,
resultTypeForOnlyInputTypes: KotlinTypeMarker,
) = with(utilContext) {
checkState(State.BUILDING, State.COMPLETION)
@@ -594,7 +593,7 @@ class NewConstraintSystemImpl(
// Substitute freshly fixed type variable into missed constraints
substituteMissedConstraints()
postponeOnlyInputTypesCheck(variableWithConstraints, resultTypeForOnlyInputTypes)
postponeOnlyInputTypesCheck(variableWithConstraints, resultType)
doPostponedComputationsIfAllVariablesAreFixed()
}
@@ -288,7 +288,7 @@ abstract class AbstractTypeApproximator(
toSuper: Boolean,
depth: Int
): KotlinTypeMarker? {
fun KotlinTypeMarker.replaceRecursionWithStarProjection(capturedType: CapturedTypeMarker, toSuper: Boolean): KotlinTypeMarker {
fun KotlinTypeMarker.replaceRecursionWithStarProjection(capturedType: CapturedTypeMarker): KotlinTypeMarker {
// This replacement is important for resolving the code like below in K2.
// fun bar(y: FieldOrRef<*>) = y.field
// interface FieldOrRef<FF : AbstractField<FF>> { val field: FF }
@@ -311,7 +311,7 @@ abstract class AbstractTypeApproximator(
return getType().lowerBoundIfFlexible().originalIfDefinitelyNotNullable()
}
return if (isK2 && toSuper && getArguments().any { it.unwrapForComparison() == capturedType }) {
return if (isK2 && getArguments().any { it.unwrapForComparison() == capturedType }) {
replaceArguments {
when {
it.unwrapForComparison() != capturedType -> it
@@ -326,7 +326,7 @@ abstract class AbstractTypeApproximator(
val supertypes = capturedType.typeConstructor().supertypes()
val baseSuperType = when (supertypes.size) {
0 -> nullableAnyType() // Let C = in Int, then superType for C and C? is Any?
1 -> supertypes.single().replaceRecursionWithStarProjection(capturedType, toSuper)
1 -> supertypes.single().replaceRecursionWithStarProjection(capturedType)
// Consider the following example:
// A.getA()::class.java, where `getA()` returns some class from Java
@@ -347,7 +347,7 @@ abstract class AbstractTypeApproximator(
else -> {
val projection = capturedType.typeConstructorProjection()
if (projection.isStarProjection()) intersectTypes(supertypes.map { it.replaceRecursionWithStarProjection(capturedType, toSuper) })
if (projection.isStarProjection()) intersectTypes(supertypes.map { it.replaceRecursionWithStarProjection(capturedType) })
else projection.getType()
}
}