[FE 1.0] Don't fail candidates which were marked with compatibility resolve previously

^KT-52431 Fixed
^KT-52393 Fixed
This commit is contained in:
Victor Petukhov
2022-05-20 14:09:22 +02:00
committed by teamcity
parent 73d676d9de
commit 02a430875f
17 changed files with 198 additions and 23 deletions
@@ -15593,6 +15593,18 @@ public class DiagnosisCompilerTestFE10TestdataTestGenerated extends AbstractDiag
runTest("compiler/testData/diagnostics/tests/inference/emptyIntersectionTypes/kt52364.kt");
}
@Test
@TestMetadata("kt52393.kt")
public void testKt52393() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/emptyIntersectionTypes/kt52393.kt");
}
@Test
@TestMetadata("kt52431.kt")
public void testKt52431() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/emptyIntersectionTypes/kt52431.kt");
}
@Test
@TestMetadata("nullableEmptyIntersection.kt")
public void testNullableEmptyIntersection() throws Exception {
@@ -15593,6 +15593,18 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
runTest("compiler/testData/diagnostics/tests/inference/emptyIntersectionTypes/kt52364.kt");
}
@Test
@TestMetadata("kt52393.kt")
public void testKt52393() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/emptyIntersectionTypes/kt52393.kt");
}
@Test
@TestMetadata("kt52431.kt")
public void testKt52431() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/emptyIntersectionTypes/kt52431.kt");
}
@Test
@TestMetadata("nullableEmptyIntersection.kt")
public void testNullableEmptyIntersection() throws Exception {
@@ -15593,6 +15593,18 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
runTest("compiler/testData/diagnostics/tests/inference/emptyIntersectionTypes/kt52364.kt");
}
@Test
@TestMetadata("kt52393.kt")
public void testKt52393() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/emptyIntersectionTypes/kt52393.kt");
}
@Test
@TestMetadata("kt52431.kt")
public void testKt52431() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/emptyIntersectionTypes/kt52431.kt");
}
@Test
@TestMetadata("nullableEmptyIntersection.kt")
public void testNullableEmptyIntersection() throws Exception {
@@ -581,10 +581,10 @@ internal object CheckIncompatibleTypeVariableUpperBounds : ResolutionStage() {
val upperTypes = variableWithConstraints.constraints.extractUpperTypesToCheckIntersectionEmptiness()
// TODO: consider reporting errors on bounded type variables by incompatible types but with other lower constraints
if (
variableWithConstraints.constraints.none { it.kind.isLower() }
&& upperTypes.computeEmptyIntersectionTypeKind().isDefinitelyEmpty()
) {
if (upperTypes.size <= 1 || variableWithConstraints.constraints.any { it.kind.isLower() })
continue
if (upperTypes.computeEmptyIntersectionTypeKind().isDefinitelyEmpty()) {
sink.yieldDiagnostic(
@Suppress("UNCHECKED_CAST")
InferredEmptyIntersectionDiagnostic(
@@ -152,7 +152,8 @@ class InferredEmptyIntersectionError(
class OnlyInputTypesDiagnostic(val typeVariable: TypeVariableMarker) : ConstraintSystemError(INAPPLICABLE)
object LowerPriorityToPreserveCompatibility : ConstraintSystemError(RESOLVED_NEED_PRESERVE_COMPATIBILITY)
class LowerPriorityToPreserveCompatibility(val needToReportWarning: Boolean) :
ConstraintSystemError(RESOLVED_NEED_PRESERVE_COMPATIBILITY)
fun Constraint.isExpectedTypePosition() =
position.from is ExpectedTypeConstraintPosition<*> || position.from is DelegatedPropertyConstraintPosition<*>
@@ -450,9 +450,13 @@ class NewConstraintSystemImpl(
languageVersionSettings.supportsFeature(LanguageFeature.ForbidInferringTypeVariablesIntoEmptyIntersection)
val upperTypes = intersectionTypeConstructor.supertypes()
// Diagnostic with these incompatible types has already been reported at the resolution stage
if (upperTypes.size <= 1 || storage.errors.any { it is InferredEmptyIntersection && it.incompatibleTypes == upperTypes })
return
if (upperTypes.computeEmptyIntersectionTypeKind().isDefinitelyEmpty()) {
// Remove existing errors from resolution stage because a completion error is more precise
storage.errors.removeIf { it is InferredEmptyIntersectionError || it is InferredEmptyIntersectionWarning }
storage.errors.removeIf { it is InferredEmptyIntersection }
val errorFactory =
if (isInferredEmptyIntersectionForbidden) ::InferredEmptyIntersectionError else ::InferredEmptyIntersectionWarning
addError(errorFactory(upperTypes, variable))
@@ -892,18 +892,23 @@ internal object CheckIncompatibleTypeVariableUpperBounds : ResolutionPart() {
for (variableWithConstraints in getSystem().getBuilder().currentStorage().notFixedTypeVariables.values) {
val upperTypes = variableWithConstraints.constraints.extractUpperTypesToCheckIntersectionEmptiness()
// TODO: consider reporting errors on bounded type variables by incompatible types but with other lower constraints
if (
variableWithConstraints.constraints.none { it.kind.isLower() }
&& upperTypes.computeEmptyIntersectionTypeKind().isDefinitelyEmpty()
) {
val isInferredEmptyIntersectionForbidden =
callComponents.languageVersionSettings.supportsFeature(LanguageFeature.ForbidInferringTypeVariablesIntoEmptyIntersection)
when {
// TODO: consider reporting errors on bounded type variables by incompatible types but with other lower constraints
upperTypes.size <= 1 || variableWithConstraints.constraints.any { it.kind.isLower() } ->
continue
wasPreviouslyDiscriminated(upperTypes) -> {
markCandidateForCompatibilityResolve(needToReportWarning = false)
continue
}
upperTypes.computeEmptyIntersectionTypeKind().isDefinitelyEmpty() -> {
val isInferredEmptyIntersectionForbidden =
callComponents.languageVersionSettings.supportsFeature(LanguageFeature.ForbidInferringTypeVariablesIntoEmptyIntersection)
val errorFactory = if (isInferredEmptyIntersectionForbidden || wasPreviouslyDiscriminated(upperTypes))
::InferredEmptyIntersectionError
else ::InferredEmptyIntersectionWarning
addError(errorFactory(upperTypes, variableWithConstraints.typeVariable))
val errorFactory = if (isInferredEmptyIntersectionForbidden)
::InferredEmptyIntersectionError
else ::InferredEmptyIntersectionWarning
addError(errorFactory(upperTypes, variableWithConstraints.typeVariable))
}
}
}
}
@@ -160,12 +160,15 @@ open class MutableResolvedCallAtom(
override fun toString(): String = "$atom, candidate = $candidateDescriptor"
}
fun ResolutionCandidate.markCandidateForCompatibilityResolve() {
fun ResolutionCandidate.markCandidateForCompatibilityResolve(needToReportWarning: Boolean = true) {
if (callComponents.languageVersionSettings.supportsFeature(LanguageFeature.DisableCompatibilityModeForNewInference)) return
addDiagnostic(LowerPriorityToPreserveCompatibility.asDiagnostic())
addDiagnostic(LowerPriorityToPreserveCompatibility(needToReportWarning).asDiagnostic())
}
fun CallableReferencesCandidateFactory.markCandidateForCompatibilityResolve(diagnostics: SmartList<KotlinCallDiagnostic>) {
fun CallableReferencesCandidateFactory.markCandidateForCompatibilityResolve(
diagnostics: SmartList<KotlinCallDiagnostic>,
needToReportWarning: Boolean = true,
) {
if (callComponents.languageVersionSettings.supportsFeature(LanguageFeature.DisableCompatibilityModeForNewInference)) return
diagnostics.add(LowerPriorityToPreserveCompatibility.asDiagnostic())
diagnostics.add(LowerPriorityToPreserveCompatibility(needToReportWarning).asDiagnostic())
}
@@ -18,6 +18,9 @@ package org.jetbrains.kotlin.resolve.calls.tower
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus
import org.jetbrains.kotlin.resolve.calls.components.candidate.ResolutionCandidate
import org.jetbrains.kotlin.resolve.calls.inference.model.LowerPriorityToPreserveCompatibility
import org.jetbrains.kotlin.resolve.calls.model.constraintSystemError
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
import org.jetbrains.kotlin.resolve.descriptorUtil.HIDES_MEMBERS_NAME_LIST
import org.jetbrains.kotlin.resolve.scopes.HierarchicalScope
@@ -437,13 +440,21 @@ class TowerResolver {
}
if (firstGroupWithResolved == null) return null
if (compatibilityCandidate != null && compatibilityGroup !== firstGroupWithResolved) {
if (compatibilityCandidate != null
&& compatibilityGroup !== firstGroupWithResolved
&& needToReportCompatibilityWarning(compatibilityCandidate)
) {
firstGroupWithResolved.forEach { it.addCompatibilityWarning(compatibilityCandidate) }
}
return firstGroupWithResolved.filter(::isSuccessfulCandidate)
}
private fun needToReportCompatibilityWarning(candidate: C) = candidate is ResolutionCandidate &&
candidate.diagnostics.any {
(it.constraintSystemError as? LowerPriorityToPreserveCompatibility)?.needToReportWarning == true
}
private fun isSuccessfulCandidate(candidate: C): Boolean {
return candidate.resultingApplicability == CandidateApplicability.RESOLVED
|| candidate.resultingApplicability == CandidateApplicability.RESOLVED_WITH_ERROR
@@ -0,0 +1,17 @@
class Wrapper<T>
class WrapperFunctions {
infix fun <T : Comparable<T>, S : T?> Wrapper<in S>.greaterEq(t: T): Unit = Unit
infix fun <T : Comparable<T>, S : T?> Wrapper<in S>.greaterEq(other: Wrapper<in S>): Unit = Unit // if this function is removed, it also works
}
fun main() {
val wrapper = Wrapper<Long>()
val number: Int = 5 // doesn't work
// val number: Long = 5 // works
with (WrapperFunctions()) {
<!ARGUMENT_TYPE_MISMATCH!>wrapper <!NONE_APPLICABLE!>greaterEq<!> number<!>
}
}
@@ -0,0 +1,17 @@
class Wrapper<T>
class WrapperFunctions {
infix fun <T : Comparable<T>, S : T?> Wrapper<in S>.greaterEq(t: T): Unit = Unit
infix fun <T : Comparable<T>, S : T?> Wrapper<in S>.greaterEq(other: Wrapper<in S>): Unit = Unit // if this function is removed, it also works
}
fun main() {
val wrapper = Wrapper<Long>()
val number: Int = 5 // doesn't work
// val number: Long = 5 // works
with (WrapperFunctions()) {
wrapper <!INFERRED_TYPE_VARIABLE_INTO_EMPTY_INTERSECTION_WARNING!>greaterEq<!> number
}
}
@@ -0,0 +1,19 @@
package
public fun main(): kotlin.Unit
public final class Wrapper</*0*/ T> {
public constructor Wrapper</*0*/ T>()
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 WrapperFunctions {
public constructor WrapperFunctions()
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 infix fun </*0*/ T : kotlin.Comparable<T>, /*1*/ S : T?> Wrapper<in S>.greaterEq(/*0*/ t: T): kotlin.Unit
public final infix fun </*0*/ T : kotlin.Comparable<T>, /*1*/ S : T?> Wrapper<in S>.greaterEq(/*0*/ other: Wrapper<in S>): kotlin.Unit
}
@@ -0,0 +1,13 @@
interface Expression<K>
interface ExpressionWithColumnType<K> : Expression<K>
class Column<T>: ExpressionWithColumnType<T>
infix fun <T : Comparable<T>, S : T?> ExpressionWithColumnType<in S>.less(t: T) {}
infix fun <T : Comparable<T>, S : T?> Expression<in S>.less(other: Expression<in S>) {}
fun main(x: Column<Long?>, y: Double) {
x <!NONE_APPLICABLE!>less<!> y // error in 1.7.20, no error in 1.7.0
}
@@ -0,0 +1,13 @@
interface Expression<K>
interface ExpressionWithColumnType<K> : Expression<K>
class Column<T>: ExpressionWithColumnType<T>
infix fun <T : Comparable<T>, S : T?> ExpressionWithColumnType<in S>.less(t: T) {}
infix fun <T : Comparable<T>, S : T?> Expression<in S>.less(other: Expression<in S>) {}
fun main(x: Column<Long?>, y: Double) {
x <!INFERRED_TYPE_VARIABLE_INTO_EMPTY_INTERSECTION_WARNING!>less<!> y // error in 1.7.20, no error in 1.7.0
}
@@ -0,0 +1,24 @@
package
public fun main(/*0*/ x: Column<kotlin.Long?>, /*1*/ y: kotlin.Double): kotlin.Unit
public infix fun </*0*/ T : kotlin.Comparable<T>, /*1*/ S : T?> Expression<in S>.less(/*0*/ other: Expression<in S>): kotlin.Unit
public infix fun </*0*/ T : kotlin.Comparable<T>, /*1*/ S : T?> ExpressionWithColumnType<in S>.less(/*0*/ t: T): kotlin.Unit
public final class Column</*0*/ T> : ExpressionWithColumnType<T> {
public constructor Column</*0*/ T>()
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 interface Expression</*0*/ K> {
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 interface ExpressionWithColumnType</*0*/ K> : Expression<K> {
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
}
+1 -1
View File
@@ -8,5 +8,5 @@ fun <T : Comparable<T>, S : T?> Expression<in S>.greater(other: T): GreaterOp =
fun foo(countExpr: Expression<Long>) {
countExpr.greater(0)
countExpr.<!INFERRED_TYPE_VARIABLE_INTO_EMPTY_INTERSECTION_WARNING!>greater<!>("0")
countExpr.<!INFERRED_TYPE_VARIABLE_INTO_EMPTY_INTERSECTION_WARNING!>greater<!><String, Nothing>("0")
countExpr.greater<String, Nothing>("0")
}
@@ -15599,6 +15599,18 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
runTest("compiler/testData/diagnostics/tests/inference/emptyIntersectionTypes/kt52364.kt");
}
@Test
@TestMetadata("kt52393.kt")
public void testKt52393() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/emptyIntersectionTypes/kt52393.kt");
}
@Test
@TestMetadata("kt52431.kt")
public void testKt52431() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/emptyIntersectionTypes/kt52431.kt");
}
@Test
@TestMetadata("nullableEmptyIntersection.kt")
public void testNullableEmptyIntersection() throws Exception {