NI: decrease fixation priority for variables which have only incorporated from upper bound constraints
^KT-40045 Fixed ^KT-39633 Fixed
This commit is contained in:
+10
@@ -11036,6 +11036,16 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirOldFronte
|
||||
public void testTakingExtensibilityFromDeclarationOfAnonymousFunction() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/takingExtensibilityFromDeclarationOfAnonymousFunction.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("wrongVariableFixationOrder.kt")
|
||||
public void testWrongVariableFixationOrder() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/wrongVariableFixationOrder.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("wrongVariableFixationOrder2.kt")
|
||||
public void testWrongVariableFixationOrder2() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/wrongVariableFixationOrder2.kt");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+13
-4
@@ -33,7 +33,8 @@ class ConstraintIncorporator(
|
||||
lowerType: KotlinTypeMarker,
|
||||
upperType: KotlinTypeMarker,
|
||||
shouldTryUseDifferentFlexibilityForUpperType: Boolean,
|
||||
isFromNullabilityConstraint: Boolean = false
|
||||
isFromNullabilityConstraint: Boolean = false,
|
||||
isFromDeclaredUpperBound: Boolean = false
|
||||
)
|
||||
|
||||
fun addNewIncorporatedConstraint(typeVariable: TypeVariableMarker, type: KotlinTypeMarker, constraintContext: ConstraintContext)
|
||||
@@ -80,7 +81,15 @@ class ConstraintIncorporator(
|
||||
if (constraint.kind != ConstraintKind.UPPER) {
|
||||
getConstraintsForVariable(typeVariable).forEach {
|
||||
if (it.kind != ConstraintKind.LOWER) {
|
||||
addNewIncorporatedConstraint(constraint.type, it.type, shouldBeTypeVariableFlexible)
|
||||
val isFromDeclaredUpperBound =
|
||||
it.position.from is DeclaredUpperBoundConstraintPosition && it.type.typeConstructor() !is TypeVariableTypeConstructor
|
||||
|
||||
addNewIncorporatedConstraint(
|
||||
constraint.type,
|
||||
it.type,
|
||||
shouldBeTypeVariableFlexible,
|
||||
isFromDeclaredUpperBound = isFromDeclaredUpperBound
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -250,7 +259,7 @@ class ConstraintIncorporator(
|
||||
addNewIncorporatedConstraint(targetVariable, newConstraint, constraintContext)
|
||||
}
|
||||
|
||||
fun Context.containsConstrainingTypeWithoutProjection(
|
||||
private fun Context.containsConstrainingTypeWithoutProjection(
|
||||
newConstraint: KotlinTypeMarker,
|
||||
otherConstraint: Constraint
|
||||
): Boolean {
|
||||
@@ -274,7 +283,7 @@ class ConstraintIncorporator(
|
||||
return otherConstraintCanAddNullabilityToNewOne || newConstraintCanAddNullabilityToOtherOne
|
||||
}
|
||||
|
||||
fun Context.getNestedTypeVariables(type: KotlinTypeMarker): List<TypeVariableMarker> =
|
||||
private fun Context.getNestedTypeVariables(type: KotlinTypeMarker): List<TypeVariableMarker> =
|
||||
getNestedArguments(type).mapNotNullTo(SmartList()) { getTypeVariable(it.getType().typeConstructor()) }
|
||||
|
||||
|
||||
|
||||
+16
-2
@@ -144,6 +144,8 @@ class ConstraintInjector(
|
||||
private var baseLowerType = position.initialConstraint.a
|
||||
private var baseUpperType = position.initialConstraint.b
|
||||
|
||||
private var isIncorporatingConstraintFromDeclaredUpperBound = false
|
||||
|
||||
fun extractAllConstraints() = possibleNewConstraints.also { possibleNewConstraints = null }
|
||||
|
||||
fun addPossibleNewConstraint(variable: TypeVariableMarker, constraint: Constraint) {
|
||||
@@ -252,16 +254,26 @@ class ConstraintInjector(
|
||||
)
|
||||
}
|
||||
|
||||
private fun addNewIncorporatedConstraintFromDeclaredUpperBound(runIsSubtypeOf: Runnable) {
|
||||
isIncorporatingConstraintFromDeclaredUpperBound = true
|
||||
runIsSubtypeOf.run()
|
||||
isIncorporatingConstraintFromDeclaredUpperBound = false
|
||||
}
|
||||
|
||||
// from ConstraintIncorporator.Context
|
||||
override fun addNewIncorporatedConstraint(
|
||||
lowerType: KotlinTypeMarker,
|
||||
upperType: KotlinTypeMarker,
|
||||
shouldTryUseDifferentFlexibilityForUpperType: Boolean,
|
||||
isFromNullabilityConstraint: Boolean
|
||||
isFromNullabilityConstraint: Boolean,
|
||||
isFromDeclaredUpperBound: Boolean
|
||||
) {
|
||||
if (lowerType === upperType) return
|
||||
if (c.isAllowedType(lowerType) && c.isAllowedType(upperType)) {
|
||||
runIsSubtypeOf(lowerType, upperType, shouldTryUseDifferentFlexibilityForUpperType, isFromNullabilityConstraint)
|
||||
fun runIsSubtypeOf() =
|
||||
runIsSubtypeOf(lowerType, upperType, shouldTryUseDifferentFlexibilityForUpperType, isFromNullabilityConstraint)
|
||||
|
||||
if (isFromDeclaredUpperBound) addNewIncorporatedConstraintFromDeclaredUpperBound(::runIsSubtypeOf) else runIsSubtypeOf()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -307,6 +319,8 @@ class ConstraintInjector(
|
||||
}
|
||||
}
|
||||
|
||||
val position = if (isIncorporatingConstraintFromDeclaredUpperBound) position.copy(isFromDeclaredUpperBound = true) else position
|
||||
|
||||
val newConstraint = Constraint(
|
||||
kind, targetType, position,
|
||||
derivedFrom = derivedFrom,
|
||||
|
||||
+8
-20
@@ -279,12 +279,12 @@ class KotlinConstraintSystemCompleter(
|
||||
diagnosticsHolder: KotlinDiagnosticsHolder
|
||||
): Boolean {
|
||||
while (true) {
|
||||
val variableForFixation = getVariableReadyForFixation(
|
||||
val variableForFixation = variableFixationFinder.findFirstVariableForFixation(
|
||||
this,
|
||||
getOrderedAllTypeVariables(collectVariablesFromContext, topLevelAtoms),
|
||||
postponedArguments,
|
||||
completionMode,
|
||||
topLevelAtoms,
|
||||
topLevelType,
|
||||
collectVariablesFromContext,
|
||||
postponedArguments
|
||||
topLevelType
|
||||
) ?: break
|
||||
|
||||
if (!variableForFixation.hasProperConstraint && completionMode == ConstraintSystemCompletionMode.PARTIAL)
|
||||
@@ -383,27 +383,15 @@ class KotlinConstraintSystemCompleter(
|
||||
return result.toList()
|
||||
}
|
||||
|
||||
private fun Context.getVariableReadyForFixation(
|
||||
completionMode: ConstraintSystemCompletionMode,
|
||||
topLevelAtoms: List<ResolvedAtom>,
|
||||
topLevelType: UnwrappedType,
|
||||
collectVariablesFromContext: Boolean,
|
||||
postponedArguments: List<PostponedResolvedAtom>
|
||||
) = variableFixationFinder.findFirstVariableForFixation(
|
||||
this,
|
||||
getOrderedAllTypeVariables(collectVariablesFromContext, topLevelAtoms),
|
||||
postponedArguments,
|
||||
completionMode,
|
||||
topLevelType
|
||||
)
|
||||
|
||||
private fun Context.isThereAnyReadyForFixationVariable(
|
||||
completionMode: ConstraintSystemCompletionMode,
|
||||
topLevelAtoms: List<ResolvedAtom>,
|
||||
topLevelType: UnwrappedType,
|
||||
collectVariablesFromContext: Boolean,
|
||||
postponedArguments: List<PostponedResolvedAtom>
|
||||
) = getVariableReadyForFixation(completionMode, topLevelAtoms, topLevelType, collectVariablesFromContext, postponedArguments) != null
|
||||
) = variableFixationFinder.findFirstVariableForFixation(
|
||||
this, getOrderedAllTypeVariables(collectVariablesFromContext, topLevelAtoms), postponedArguments, completionMode, topLevelType
|
||||
) != null
|
||||
|
||||
companion object {
|
||||
fun getOrderedNotAnalyzedPostponedArguments(topLevelAtoms: List<ResolvedAtom>): List<PostponedResolvedAtom> {
|
||||
|
||||
+12
-5
@@ -19,7 +19,6 @@ package org.jetbrains.kotlin.resolve.calls.inference.components
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.components.KotlinConstraintSystemCompleter.ConstraintSystemCompletionMode
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.components.KotlinConstraintSystemCompleter.ConstraintSystemCompletionMode.PARTIAL
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.Constraint
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintKind
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.DeclaredUpperBoundConstraintPosition
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.VariableWithConstraints
|
||||
import org.jetbrains.kotlin.resolve.calls.model.PostponedResolvedAtomMarker
|
||||
@@ -57,6 +56,7 @@ class VariableFixationFinder(
|
||||
WITH_COMPLEX_DEPENDENCY, // if type variable T has constraint with non fixed type variable inside (non-top-level): T <: Foo<S>
|
||||
WITH_TRIVIAL_OR_NON_PROPER_CONSTRAINTS, // proper trivial constraint from arguments, Nothing <: T
|
||||
RELATED_TO_ANY_OUTPUT_TYPE,
|
||||
FROM_INCORPORATION_OF_DECLARED_UPPER_BOUND,
|
||||
READY_FOR_FIXATION,
|
||||
READY_FOR_FIXATION_REIFIED,
|
||||
}
|
||||
@@ -71,6 +71,8 @@ class VariableFixationFinder(
|
||||
hasDependencyToOtherTypeVariables(variable) -> TypeVariableFixationReadiness.WITH_COMPLEX_DEPENDENCY
|
||||
variableHasTrivialOrNonProperConstraints(variable) -> TypeVariableFixationReadiness.WITH_TRIVIAL_OR_NON_PROPER_CONSTRAINTS
|
||||
dependencyProvider.isVariableRelatedToAnyOutputType(variable) -> TypeVariableFixationReadiness.RELATED_TO_ANY_OUTPUT_TYPE
|
||||
variableHasOnlyIncorporatedConstraintsFromDeclaredUpperBound(variable) ->
|
||||
TypeVariableFixationReadiness.FROM_INCORPORATION_OF_DECLARED_UPPER_BOUND
|
||||
isReified(variable) -> TypeVariableFixationReadiness.READY_FOR_FIXATION_REIFIED
|
||||
else -> TypeVariableFixationReadiness.READY_FOR_FIXATION
|
||||
}
|
||||
@@ -87,13 +89,19 @@ class VariableFixationFinder(
|
||||
}
|
||||
}
|
||||
|
||||
fun Context.variableHasTrivialOrNonProperConstraints(variable: TypeConstructorMarker): Boolean {
|
||||
private fun Context.variableHasTrivialOrNonProperConstraints(variable: TypeConstructorMarker): Boolean {
|
||||
return notFixedTypeVariables[variable]?.constraints?.all { constraint ->
|
||||
val isProperConstraint = isProperArgumentConstraint(constraint)
|
||||
isProperConstraint && trivialConstraintTypeInferenceOracle.isNotInterestingConstraint(constraint) || !isProperConstraint
|
||||
} ?: false
|
||||
}
|
||||
|
||||
private fun Context.variableHasOnlyIncorporatedConstraintsFromDeclaredUpperBound(variable: TypeConstructorMarker): Boolean {
|
||||
val constraints = notFixedTypeVariables[variable]?.constraints ?: return false
|
||||
|
||||
return constraints.filter { isProperArgumentConstraint(it) }.all { it.position.isFromDeclaredUpperBound }
|
||||
}
|
||||
|
||||
private fun Context.findTypeVariableForFixation(
|
||||
allTypeVariables: List<TypeConstructorMarker>,
|
||||
postponedArguments: List<PostponedResolvedAtomMarker>,
|
||||
@@ -106,10 +114,9 @@ class VariableFixationFinder(
|
||||
notFixedTypeVariables, postponedArguments, topLevelType.takeIf { completionMode == PARTIAL }, this
|
||||
)
|
||||
|
||||
val candidate = allTypeVariables.maxBy { getTypeVariableReadiness(it, dependencyProvider) } ?: return null
|
||||
val candidate = allTypeVariables.maxByOrNull { getTypeVariableReadiness(it, dependencyProvider) } ?: return null
|
||||
|
||||
val candidateReadiness = getTypeVariableReadiness(candidate, dependencyProvider)
|
||||
return when (candidateReadiness) {
|
||||
return when (getTypeVariableReadiness(candidate, dependencyProvider)) {
|
||||
TypeVariableFixationReadiness.FORBIDDEN -> null
|
||||
TypeVariableFixationReadiness.WITHOUT_PROPER_ARGUMENT_CONSTRAINT -> VariableForFixation(candidate, false)
|
||||
TypeVariableFixationReadiness.WITH_TRIVIAL_OR_NON_PROPER_CONSTRAINTS ->
|
||||
|
||||
+3
-2
@@ -81,9 +81,10 @@ class DelegatedPropertyConstraintPosition(val topLevelCall: KotlinCall) : Constr
|
||||
override fun toString() = "Constraint from call $topLevelCall for delegated property"
|
||||
}
|
||||
|
||||
class IncorporationConstraintPosition(
|
||||
data class IncorporationConstraintPosition(
|
||||
val from: ConstraintPosition,
|
||||
val initialConstraint: InitialConstraint
|
||||
val initialConstraint: InitialConstraint,
|
||||
var isFromDeclaredUpperBound: Boolean = false
|
||||
) : ConstraintPosition() {
|
||||
override fun toString() =
|
||||
"Incorporate $initialConstraint from position $from"
|
||||
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
// FIR_IDENTICAL
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER -CAST_NEVER_SUCCEEDS
|
||||
// Issue: KT-40045
|
||||
|
||||
interface AAA
|
||||
|
||||
fun <K : AAA, R : K> assign(dest: R, vararg src: K?): R = null as R
|
||||
|
||||
class DIV(val tabIndex: String): AAA
|
||||
|
||||
fun <T: AAA> jsObject(builder: T.() -> Unit): T = null as T
|
||||
|
||||
fun foo(x: DIV) {
|
||||
assign(x, jsObject { tabIndex }) // tabIndex is resolved in OI and unresolved in NI because T is inferred to Any instead of DIV
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
package
|
||||
|
||||
public fun </*0*/ K : AAA, /*1*/ R : K> assign(/*0*/ dest: R, /*1*/ vararg src: K? /*kotlin.Array<out K?>*/): R
|
||||
public fun foo(/*0*/ x: DIV): kotlin.Unit
|
||||
public fun </*0*/ T : AAA> jsObject(/*0*/ builder: T.() -> kotlin.Unit): T
|
||||
|
||||
public interface AAA {
|
||||
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
|
||||
}
|
||||
|
||||
public final class DIV : AAA {
|
||||
public constructor DIV(/*0*/ tabIndex: kotlin.String)
|
||||
public final val tabIndex: kotlin.String
|
||||
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
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
// FIR_IDENTICAL
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
// Issue: KT-39633
|
||||
|
||||
interface Proxy<in D>
|
||||
|
||||
class A<E : Any>(val left: E) : Proxy<E>
|
||||
|
||||
abstract class Api {
|
||||
abstract fun <T> magic(): T
|
||||
inline fun <reified A : Any> match(proxy: Proxy<A>): A = magic()
|
||||
inline fun <reified B : Any> f(x: B): B = g(x)
|
||||
inline fun <reified C : Any> g(x: C) = match(A(x))
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
package
|
||||
|
||||
public final class A</*0*/ E : kotlin.Any> : Proxy<E> {
|
||||
public constructor A</*0*/ E : kotlin.Any>(/*0*/ left: E)
|
||||
public final val left: E
|
||||
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
|
||||
}
|
||||
|
||||
public abstract class Api {
|
||||
public constructor Api()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public final inline fun </*0*/ reified B : kotlin.Any> f(/*0*/ x: B): B
|
||||
public final inline fun </*0*/ reified C : kotlin.Any> g(/*0*/ x: C): C
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public abstract fun </*0*/ T> magic(): T
|
||||
public final inline fun </*0*/ reified A : kotlin.Any> match(/*0*/ proxy: Proxy<A>): A
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public interface Proxy</*0*/ in D> {
|
||||
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
|
||||
}
|
||||
@@ -11043,6 +11043,16 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTestWithFirVali
|
||||
public void testTakingExtensibilityFromDeclarationOfAnonymousFunction() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/takingExtensibilityFromDeclarationOfAnonymousFunction.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("wrongVariableFixationOrder.kt")
|
||||
public void testWrongVariableFixationOrder() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/wrongVariableFixationOrder.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("wrongVariableFixationOrder2.kt")
|
||||
public void testWrongVariableFixationOrder2() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/wrongVariableFixationOrder2.kt");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Generated
+10
@@ -11038,6 +11038,16 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing
|
||||
public void testTakingExtensibilityFromDeclarationOfAnonymousFunction() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/takingExtensibilityFromDeclarationOfAnonymousFunction.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("wrongVariableFixationOrder.kt")
|
||||
public void testWrongVariableFixationOrder() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/wrongVariableFixationOrder.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("wrongVariableFixationOrder2.kt")
|
||||
public void testWrongVariableFixationOrder2() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/wrongVariableFixationOrder2.kt");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user