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:
Victor Petukhov
2020-07-17 13:36:11 +03:00
parent 081248f859
commit b0ac046b05
12 changed files with 156 additions and 33 deletions
@@ -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");
}
}
}
@@ -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()) }
@@ -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,
@@ -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> {
@@ -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 ->
@@ -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"
@@ -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
}
@@ -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
}
@@ -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))
}
@@ -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");
}
}
}
@@ -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");
}
}
}