mirror of
https://github.com/jlengrand/kotlin.git
synced 2026-04-01 15:51:52 +00:00
NI: avoid creating useless captured types during incorporation
^KT-37546 Fixed
This commit is contained in:
@@ -6,5 +6,5 @@ FILE: definetelyNotNullForTypeParameter.kt
|
||||
}
|
||||
public final fun <F : R|kotlin/Any|> foo(computable: R|Out<F?>|): R|kotlin/Unit|
|
||||
public final fun <T : R|kotlin/Any|> bar(computable: R|Out<T?>|): R|kotlin/Unit| {
|
||||
R|/foo|<R|T?!!|>(R|/id|<R|T?|>(R|<local>/computable|))
|
||||
R|/foo|<R|T|>(R|/id|<R|T?|>(R|<local>/computable|))
|
||||
}
|
||||
|
||||
@@ -10278,6 +10278,11 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirOldFronte
|
||||
runTest("compiler/testData/diagnostics/tests/inference/capturedTypes/approximateBeforeFixation.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("avoidCreatingUselessCapturedTypes.kt")
|
||||
public void testAvoidCreatingUselessCapturedTypes() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/capturedTypes/avoidCreatingUselessCapturedTypes.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("cannotCaptureInProjection.kt")
|
||||
public void testCannotCaptureInProjection() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/capturedTypes/cannotCaptureInProjection.kt");
|
||||
|
||||
@@ -113,50 +113,94 @@ class ConstraintIncorporator(
|
||||
}
|
||||
}
|
||||
|
||||
private fun Context.approximateIfNeededAndAddNewConstraint(
|
||||
baseConstraint: Constraint,
|
||||
type: KotlinTypeMarker,
|
||||
targetVariable: TypeVariableMarker,
|
||||
otherVariable: TypeVariableMarker,
|
||||
otherConstraint: Constraint,
|
||||
needApproximation: Boolean = true
|
||||
) {
|
||||
val typeWithSubstitution = baseConstraint.type.substitute(this, otherVariable, type)
|
||||
val prepareType = { toSuper: Boolean ->
|
||||
if (needApproximation) approximateCapturedTypes(typeWithSubstitution, toSuper) else typeWithSubstitution
|
||||
}
|
||||
|
||||
when (baseConstraint.kind) {
|
||||
ConstraintKind.EQUALITY -> {
|
||||
addNewConstraint(targetVariable, baseConstraint, otherVariable, otherConstraint, typeWithSubstitution, isSubtype = false)
|
||||
addNewConstraint(targetVariable, baseConstraint, otherVariable, otherConstraint, typeWithSubstitution, isSubtype = true)
|
||||
}
|
||||
ConstraintKind.UPPER -> {
|
||||
addNewConstraint(targetVariable, baseConstraint, otherVariable, otherConstraint, prepareType(true), isSubtype = false)
|
||||
}
|
||||
ConstraintKind.LOWER -> {
|
||||
addNewConstraint(targetVariable, baseConstraint, otherVariable, otherConstraint, prepareType(false), isSubtype = true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun Context.generateNewConstraint(
|
||||
targetVariable: TypeVariableMarker,
|
||||
baseConstraint: Constraint,
|
||||
otherVariable: TypeVariableMarker,
|
||||
otherConstraint: Constraint
|
||||
) {
|
||||
val typeWithSubstitution = when (otherConstraint.kind) {
|
||||
val isBaseGenericType = baseConstraint.type.argumentsCount() != 0
|
||||
val isOtherCapturedType = otherConstraint.type.isCapturedType()
|
||||
val (type, needApproximation) = when (otherConstraint.kind) {
|
||||
ConstraintKind.EQUALITY -> {
|
||||
baseConstraint.type.substitute(this, otherVariable, otherConstraint.type)
|
||||
otherConstraint.type to true
|
||||
}
|
||||
ConstraintKind.UPPER -> {
|
||||
val temporaryCapturedType = createCapturedType(
|
||||
createTypeArgument(otherConstraint.type, TypeVariance.OUT),
|
||||
listOf(otherConstraint.type),
|
||||
null,
|
||||
CaptureStatus.FOR_INCORPORATION
|
||||
)
|
||||
baseConstraint.type.substitute(this, otherVariable, temporaryCapturedType)
|
||||
/*
|
||||
* Creating a captured type isn't needed due to its future approximation to `Nothing` or itself
|
||||
* Example:
|
||||
* targetVariable = TypeVariable(A)
|
||||
* baseConstraint = LOWER(TypeVariable(B))
|
||||
* otherConstraint = UPPER(Number)
|
||||
* incorporatedConstraint = Approx(CapturedType(out Number)) <: TypeVariable(A) => Nothing <: TypeVariable(A)
|
||||
* TODO: implement this for generics and captured types
|
||||
*/
|
||||
if (baseConstraint.kind == ConstraintKind.LOWER && !isBaseGenericType && !isOtherCapturedType) {
|
||||
nothingType() to false
|
||||
} else if (baseConstraint.kind == ConstraintKind.UPPER && !isBaseGenericType && !isOtherCapturedType) {
|
||||
otherConstraint.type to false
|
||||
} else {
|
||||
createCapturedType(
|
||||
createTypeArgument(otherConstraint.type, TypeVariance.OUT),
|
||||
listOf(otherConstraint.type),
|
||||
null,
|
||||
CaptureStatus.FOR_INCORPORATION
|
||||
) to true
|
||||
}
|
||||
}
|
||||
ConstraintKind.LOWER -> {
|
||||
val temporaryCapturedType = createCapturedType(
|
||||
createTypeArgument(otherConstraint.type, TypeVariance.IN),
|
||||
emptyList(),
|
||||
otherConstraint.type,
|
||||
CaptureStatus.FOR_INCORPORATION
|
||||
)
|
||||
baseConstraint.type.substitute(this, otherVariable, temporaryCapturedType)
|
||||
/*
|
||||
* Creating a captured type isn't needed due to its future approximation to `Any?` or itself
|
||||
* Example:
|
||||
* targetVariable = TypeVariable(A)
|
||||
* baseConstraint = UPPER(TypeVariable(B))
|
||||
* otherConstraint = LOWER(Number)
|
||||
* incorporatedConstraint = TypeVariable(A) <: Approx(CapturedType(in Number)) => TypeVariable(A) <: Any?
|
||||
* TODO: implement this for generics and captured types
|
||||
*/
|
||||
if (baseConstraint.kind == ConstraintKind.UPPER && !isBaseGenericType && !isOtherCapturedType) {
|
||||
nullableAnyType() to false
|
||||
} else if (baseConstraint.kind == ConstraintKind.LOWER && !isBaseGenericType && !isOtherCapturedType) {
|
||||
otherConstraint.type to false
|
||||
} else {
|
||||
createCapturedType(
|
||||
createTypeArgument(otherConstraint.type, TypeVariance.IN),
|
||||
emptyList(),
|
||||
otherConstraint.type,
|
||||
CaptureStatus.FOR_INCORPORATION
|
||||
) to true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
when (baseConstraint.kind) {
|
||||
ConstraintKind.EQUALITY -> {
|
||||
addNewConstraint(targetVariable, baseConstraint, otherVariable, otherConstraint, typeWithSubstitution, isSubtype = true)
|
||||
addNewConstraint(targetVariable, baseConstraint, otherVariable, otherConstraint, typeWithSubstitution, isSubtype = false)
|
||||
}
|
||||
ConstraintKind.UPPER -> {
|
||||
val generatedConstraintType = approximateCapturedTypes(typeWithSubstitution, toSuper = true)
|
||||
addNewConstraint(targetVariable, baseConstraint, otherVariable, otherConstraint, generatedConstraintType, isSubtype = false)
|
||||
}
|
||||
ConstraintKind.LOWER -> {
|
||||
val generatedConstraintType = approximateCapturedTypes(typeWithSubstitution, toSuper = false)
|
||||
addNewConstraint(targetVariable, baseConstraint, otherVariable, otherConstraint, generatedConstraintType, isSubtype = true)
|
||||
}
|
||||
}
|
||||
approximateIfNeededAndAddNewConstraint(baseConstraint, type, targetVariable, otherVariable, otherConstraint, needApproximation)
|
||||
}
|
||||
|
||||
private fun Context.addNewConstraint(
|
||||
|
||||
2238
compiler/testData/diagnostics/tests/inference/capturedTypes/avoidCreatingUselessCapturedTypes.kt
vendored
Normal file
2238
compiler/testData/diagnostics/tests/inference/capturedTypes/avoidCreatingUselessCapturedTypes.kt
vendored
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,9 @@
|
||||
package
|
||||
|
||||
public object Entities {
|
||||
private constructor Entities()
|
||||
public final val map: kotlin.collections.Map<kotlin.String, kotlin.Int>
|
||||
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
|
||||
}
|
||||
@@ -10285,6 +10285,11 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTestWithFirVali
|
||||
runTest("compiler/testData/diagnostics/tests/inference/capturedTypes/approximateBeforeFixation.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("avoidCreatingUselessCapturedTypes.kt")
|
||||
public void testAvoidCreatingUselessCapturedTypes() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/capturedTypes/avoidCreatingUselessCapturedTypes.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("cannotCaptureInProjection.kt")
|
||||
public void testCannotCaptureInProjection() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/capturedTypes/cannotCaptureInProjection.kt");
|
||||
|
||||
@@ -10280,6 +10280,11 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing
|
||||
runTest("compiler/testData/diagnostics/tests/inference/capturedTypes/approximateBeforeFixation.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("avoidCreatingUselessCapturedTypes.kt")
|
||||
public void testAvoidCreatingUselessCapturedTypes() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/capturedTypes/avoidCreatingUselessCapturedTypes.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("cannotCaptureInProjection.kt")
|
||||
public void testCannotCaptureInProjection() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/capturedTypes/cannotCaptureInProjection.kt");
|
||||
|
||||
Reference in New Issue
Block a user