[NI] Don't loose diagnostic after type variable fixation
#KT-24488 Fixed
This commit is contained in:
+1
-1
@@ -152,7 +152,7 @@ class ConstraintSystemCompleter(val components: InferenceComponents) {
|
|||||||
direction: TypeVariableDirectionCalculator.ResolveDirection
|
direction: TypeVariableDirectionCalculator.ResolveDirection
|
||||||
) {
|
) {
|
||||||
val resultType = components.resultTypeResolver.findResultType(c, variableWithConstraints, direction)
|
val resultType = components.resultTypeResolver.findResultType(c, variableWithConstraints, direction)
|
||||||
c.fixVariable(variableWithConstraints.typeVariable, resultType)
|
c.fixVariable(variableWithConstraints.typeVariable, resultType, atom = null) // TODO: obtain atom for diagnostics
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun analyzePostponeArgumentIfPossible(
|
private fun analyzePostponeArgumentIfPossible(
|
||||||
|
|||||||
+5
@@ -17240,6 +17240,11 @@ public class FirDiagnosticsSmokeTestGenerated extends AbstractFirDiagnosticsSmok
|
|||||||
runTest("compiler/testData/diagnostics/tests/regressions/kt2376.kt");
|
runTest("compiler/testData/diagnostics/tests/regressions/kt2376.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("kt24488.kt")
|
||||||
|
public void testKt24488() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/regressions/kt24488.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("kt251.kt")
|
@TestMetadata("kt251.kt")
|
||||||
public void testKt251() throws Exception {
|
public void testKt251() throws Exception {
|
||||||
runTest("compiler/testData/diagnostics/tests/regressions/kt251.kt");
|
runTest("compiler/testData/diagnostics/tests/regressions/kt251.kt");
|
||||||
|
|||||||
+18
@@ -317,6 +317,24 @@ class DiagnosticReporterByTrackingStrategy(
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
(position as? FixVariableConstraintPosition)?.let {
|
||||||
|
val morePreciseDiagnosticExists = allDiagnostics.any { other ->
|
||||||
|
other is NewConstraintError && other.position.from !is FixVariableConstraintPosition
|
||||||
|
}
|
||||||
|
if (morePreciseDiagnosticExists) return
|
||||||
|
|
||||||
|
val call = it.resolvedAtom?.atom?.safeAs<PSIKotlinCall>()?.psiCall ?: call
|
||||||
|
val expression = call.calleeExpression ?: return
|
||||||
|
|
||||||
|
trace.reportDiagnosticOnce(
|
||||||
|
TYPE_MISMATCH.on(
|
||||||
|
expression,
|
||||||
|
constraintError.upperKotlinType,
|
||||||
|
constraintError.lowerKotlinType
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CapturedTypeFromSubtyping::class.java -> {
|
CapturedTypeFromSubtyping::class.java -> {
|
||||||
|
|||||||
+2
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.resolve.calls.inference.NewConstraintSystem
|
|||||||
import org.jetbrains.kotlin.resolve.calls.inference.addSubtypeConstraintIfCompatible
|
import org.jetbrains.kotlin.resolve.calls.inference.addSubtypeConstraintIfCompatible
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.components.KotlinConstraintSystemCompleter
|
import org.jetbrains.kotlin.resolve.calls.inference.components.KotlinConstraintSystemCompleter
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.components.KotlinConstraintSystemCompleter.ConstraintSystemCompletionMode
|
import org.jetbrains.kotlin.resolve.calls.inference.components.KotlinConstraintSystemCompleter.ConstraintSystemCompletionMode
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.model.Constraint
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage.Empty.hasContradiction
|
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage.Empty.hasContradiction
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.model.ExpectedTypeConstraintPosition
|
import org.jetbrains.kotlin.resolve.calls.inference.model.ExpectedTypeConstraintPosition
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.*
|
import org.jetbrains.kotlin.resolve.calls.model.*
|
||||||
@@ -19,6 +20,7 @@ import org.jetbrains.kotlin.types.ErrorUtils
|
|||||||
import org.jetbrains.kotlin.types.TypeUtils
|
import org.jetbrains.kotlin.types.TypeUtils
|
||||||
import org.jetbrains.kotlin.types.UnwrappedType
|
import org.jetbrains.kotlin.types.UnwrappedType
|
||||||
import org.jetbrains.kotlin.types.model.TypeSystemInferenceExtensionContext
|
import org.jetbrains.kotlin.types.model.TypeSystemInferenceExtensionContext
|
||||||
|
import org.jetbrains.kotlin.types.model.defaultType
|
||||||
import org.jetbrains.kotlin.types.model.isIntegerLiteralTypeConstructor
|
import org.jetbrains.kotlin.types.model.isIntegerLiteralTypeConstructor
|
||||||
import org.jetbrains.kotlin.types.model.typeConstructor
|
import org.jetbrains.kotlin.types.model.typeConstructor
|
||||||
import org.jetbrains.kotlin.types.typeUtil.contains
|
import org.jetbrains.kotlin.types.typeUtil.contains
|
||||||
|
|||||||
+10
-7
@@ -41,7 +41,7 @@ class KotlinConstraintSystemCompleter(
|
|||||||
// mutable operations
|
// mutable operations
|
||||||
fun addError(error: KotlinCallDiagnostic)
|
fun addError(error: KotlinCallDiagnostic)
|
||||||
|
|
||||||
fun fixVariable(variable: TypeVariableMarker, resultType: KotlinTypeMarker)
|
fun fixVariable(variable: TypeVariableMarker, resultType: KotlinTypeMarker, atom: ResolvedAtom?)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun runCompletion(
|
fun runCompletion(
|
||||||
@@ -87,7 +87,7 @@ class KotlinConstraintSystemCompleter(
|
|||||||
val variableWithConstraints = c.notFixedTypeVariables.getValue(variableForFixation.variable)
|
val variableWithConstraints = c.notFixedTypeVariables.getValue(variableForFixation.variable)
|
||||||
|
|
||||||
if (variableForFixation.hasProperConstraint)
|
if (variableForFixation.hasProperConstraint)
|
||||||
fixVariable(c, topLevelType, variableWithConstraints, postponedKtPrimitives)
|
fixVariable(c, topLevelType, variableWithConstraints, postponedKtPrimitives, topLevelAtoms)
|
||||||
else
|
else
|
||||||
processVariableWhenNotEnoughInformation(c, variableWithConstraints, topLevelAtoms)
|
processVariableWhenNotEnoughInformation(c, variableWithConstraints, topLevelAtoms)
|
||||||
|
|
||||||
@@ -206,19 +206,22 @@ class KotlinConstraintSystemCompleter(
|
|||||||
c: Context,
|
c: Context,
|
||||||
topLevelType: UnwrappedType,
|
topLevelType: UnwrappedType,
|
||||||
variableWithConstraints: VariableWithConstraints,
|
variableWithConstraints: VariableWithConstraints,
|
||||||
postponedResolveKtPrimitives: List<PostponedResolvedAtom>
|
postponedResolveKtPrimitives: List<PostponedResolvedAtom>,
|
||||||
|
topLevelAtoms: List<ResolvedAtom>
|
||||||
) {
|
) {
|
||||||
val direction = TypeVariableDirectionCalculator(c, postponedResolveKtPrimitives, topLevelType).getDirection(variableWithConstraints)
|
val direction = TypeVariableDirectionCalculator(c, postponedResolveKtPrimitives, topLevelType).getDirection(variableWithConstraints)
|
||||||
fixVariable(c, variableWithConstraints, direction)
|
fixVariable(c, variableWithConstraints, direction, topLevelAtoms)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun fixVariable(
|
fun fixVariable(
|
||||||
c: Context,
|
c: Context,
|
||||||
variableWithConstraints: VariableWithConstraints,
|
variableWithConstraints: VariableWithConstraints,
|
||||||
direction: TypeVariableDirectionCalculator.ResolveDirection
|
direction: TypeVariableDirectionCalculator.ResolveDirection,
|
||||||
|
topLevelAtoms: List<ResolvedAtom>
|
||||||
) {
|
) {
|
||||||
val resultType = resultTypeResolver.findResultType(c, variableWithConstraints, direction)
|
val resultType = resultTypeResolver.findResultType(c, variableWithConstraints, direction)
|
||||||
c.fixVariable(variableWithConstraints.typeVariable, resultType)
|
val resolvedAtom = findResolvedAtomBy(variableWithConstraints.typeVariable, topLevelAtoms) ?: topLevelAtoms.firstOrNull()
|
||||||
|
c.fixVariable(variableWithConstraints.typeVariable, resultType, resolvedAtom)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun processVariableWhenNotEnoughInformation(
|
private fun processVariableWhenNotEnoughInformation(
|
||||||
@@ -238,7 +241,7 @@ class KotlinConstraintSystemCompleter(
|
|||||||
else
|
else
|
||||||
ErrorUtils.createErrorType("Cannot infer type variable $typeVariable")
|
ErrorUtils.createErrorType("Cannot infer type variable $typeVariable")
|
||||||
|
|
||||||
c.fixVariable(typeVariable, resultErrorType)
|
c.fixVariable(typeVariable, resultErrorType, resolvedAtom)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun findResolvedAtomBy(typeVariable: TypeVariableMarker, topLevelAtoms: List<ResolvedAtom>): ResolvedAtom? {
|
private fun findResolvedAtomBy(typeVariable: TypeVariableMarker, topLevelAtoms: List<ResolvedAtom>): ResolvedAtom? {
|
||||||
|
|||||||
+1
-1
@@ -53,7 +53,7 @@ class ReceiverConstraintPosition(val argument: KotlinCallArgument) : ConstraintP
|
|||||||
override fun toString() = "Receiver $argument"
|
override fun toString() = "Receiver $argument"
|
||||||
}
|
}
|
||||||
|
|
||||||
class FixVariableConstraintPosition(val variable: TypeVariableMarker) : ConstraintPosition() {
|
class FixVariableConstraintPosition(val variable: TypeVariableMarker, val resolvedAtom: ResolvedAtom?) : ConstraintPosition() {
|
||||||
override fun toString() = "Fix variable $variable"
|
override fun toString() = "Fix variable $variable"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+6
-2
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.resolve.calls.inference.components.KotlinConstraintS
|
|||||||
import org.jetbrains.kotlin.resolve.calls.inference.components.ResultTypeResolver
|
import org.jetbrains.kotlin.resolve.calls.inference.components.ResultTypeResolver
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.KotlinCallDiagnostic
|
import org.jetbrains.kotlin.resolve.calls.model.KotlinCallDiagnostic
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.OnlyInputTypesDiagnostic
|
import org.jetbrains.kotlin.resolve.calls.model.OnlyInputTypesDiagnostic
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.model.ResolvedAtom
|
||||||
import org.jetbrains.kotlin.types.IntersectionTypeConstructor
|
import org.jetbrains.kotlin.types.IntersectionTypeConstructor
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
import org.jetbrains.kotlin.types.checker.NewKotlinTypeChecker
|
import org.jetbrains.kotlin.types.checker.NewKotlinTypeChecker
|
||||||
@@ -247,10 +248,13 @@ class NewConstraintSystemImpl(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// KotlinConstraintSystemCompleter.Context
|
// KotlinConstraintSystemCompleter.Context
|
||||||
override fun fixVariable(variable: TypeVariableMarker, resultType: KotlinTypeMarker) {
|
override fun fixVariable(variable: TypeVariableMarker, resultType: KotlinTypeMarker, atom: ResolvedAtom?) {
|
||||||
checkState(State.BUILDING, State.COMPLETION)
|
checkState(State.BUILDING, State.COMPLETION)
|
||||||
|
|
||||||
constraintInjector.addInitialEqualityConstraint(this, variable.defaultType(), resultType, FixVariableConstraintPosition(variable))
|
constraintInjector.addInitialEqualityConstraint(
|
||||||
|
this, variable.defaultType(), resultType, FixVariableConstraintPosition(variable, atom)
|
||||||
|
)
|
||||||
|
|
||||||
val variableWithConstraints = notFixedTypeVariables.remove(variable.freshTypeConstructor())
|
val variableWithConstraints = notFixedTypeVariables.remove(variable.freshTypeConstructor())
|
||||||
checkOnlyInputTypesAnnotation(variableWithConstraints, resultType)
|
checkOnlyInputTypesAnnotation(variableWithConstraints, resultType)
|
||||||
|
|
||||||
|
|||||||
Vendored
+4
-6
@@ -59,13 +59,11 @@ fun testVariableWithBound() {
|
|||||||
|
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("Inv<kotlin.Int>")!>c1<!>
|
<!DEBUG_INFO_EXPRESSION_TYPE("Inv<kotlin.Int>")!>c1<!>
|
||||||
|
|
||||||
// should be an error after variable fixation
|
val c2 = <!TYPE_MISMATCH!>select<!>(SubInv<String>(), createWithNumberBound())
|
||||||
val c2 = select(SubInv<String>(), createWithNumberBound())
|
|
||||||
|
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("Inv<kotlin.String>")!>c2<!>
|
<!DEBUG_INFO_EXPRESSION_TYPE("Inv<kotlin.String>")!>c2<!>
|
||||||
|
|
||||||
// should be an error after variable fixation
|
val c3 = <!TYPE_MISMATCH!>select<!>(SubInv<Double>(), createWithIntBound())
|
||||||
val c3 = select(SubInv<Double>(), createWithIntBound())
|
|
||||||
|
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("Inv<kotlin.Double>")!>c3<!>
|
<!DEBUG_INFO_EXPRESSION_TYPE("Inv<kotlin.Double>")!>c3<!>
|
||||||
}
|
}
|
||||||
@@ -78,13 +76,13 @@ fun testCapturedVariable() {
|
|||||||
|
|
||||||
val c1 = select(SubInv<Number>(), createInvOut())
|
val c1 = select(SubInv<Number>(), createInvOut())
|
||||||
|
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("Inv<kotlin.Number>")!>c1<!>
|
<!DEBUG_INFO_EXPRESSION_TYPE("Inv<out kotlin.Number>")!>c1<!>
|
||||||
|
|
||||||
val c2 = select(createSubInvOut<Number>(), createInvOut())
|
val c2 = select(createSubInvOut<Number>(), createInvOut())
|
||||||
|
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("Inv<out kotlin.Number>")!>c2<!>
|
<!DEBUG_INFO_EXPRESSION_TYPE("Inv<out kotlin.Number>")!>c2<!>
|
||||||
|
|
||||||
val c3 = select(SubInv<Number>(), createInvIn())
|
val c3 = <!TYPE_MISMATCH!>select<!>(SubInv<Number>(), createInvIn())
|
||||||
|
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("Inv<out kotlin.Number>")!>c3<!>
|
<!DEBUG_INFO_EXPRESSION_TYPE("Inv<out kotlin.Number>")!>c3<!>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,4 +2,4 @@
|
|||||||
|
|
||||||
fun <T : Any> nullable(): T? = null
|
fun <T : Any> nullable(): T? = null
|
||||||
|
|
||||||
val value = nullable<Int>() ?: <!OI;TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH!>nullable()<!>
|
val value = nullable<Int>() <!NI;TYPE_MISMATCH!>?:<!> <!OI;TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH!>nullable()<!>
|
||||||
+2
-2
@@ -11,13 +11,13 @@ fun <K> elvisExact(x: K?, y: K): @kotlin.internal.Exact K = y
|
|||||||
fun <T : Number> materialize(): T? = null
|
fun <T : Number> materialize(): T? = null
|
||||||
|
|
||||||
fun test(nullableSample: ISample, any: Any) {
|
fun test(nullableSample: ISample, any: Any) {
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("ISample?")!>elvisSimple(
|
<!DEBUG_INFO_EXPRESSION_TYPE("ISample")!><!TYPE_MISMATCH!>elvisSimple<!>(
|
||||||
nullableSample,
|
nullableSample,
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("{ISample & Number}?")!>materialize()<!>
|
<!DEBUG_INFO_EXPRESSION_TYPE("{ISample & Number}?")!>materialize()<!>
|
||||||
)<!>
|
)<!>
|
||||||
|
|
||||||
elvisSimple(
|
elvisSimple(
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("ISample?")!>elvisSimple(nullableSample, materialize())<!>,
|
<!DEBUG_INFO_EXPRESSION_TYPE("ISample")!><!TYPE_MISMATCH!>elvisSimple<!>(nullableSample, materialize())<!>,
|
||||||
any
|
any
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
// !WITH_NEW_INFERENCE
|
||||||
|
// SKIP_TXT
|
||||||
|
|
||||||
|
class Bar {
|
||||||
|
val a: Array<String>? = null
|
||||||
|
}
|
||||||
|
|
||||||
|
fun foo(bar: Bar) = bar.a?.asIterable() ?: <!OI;TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH!><!NI;NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>emptyArray<!>()<!>
|
||||||
|
|
||||||
|
fun <T> Array<out T>.asIterable(): Iterable<T> = TODO()
|
||||||
|
|
||||||
|
fun testFrontend() {
|
||||||
|
val bar = Bar()
|
||||||
|
foo(bar)
|
||||||
|
}
|
||||||
@@ -272,7 +272,7 @@ fun case_16() {
|
|||||||
// TESTCASE NUMBER: 17
|
// TESTCASE NUMBER: 17
|
||||||
val case_17 = if (nullableIntProperty == null == true == false) 0 else {
|
val case_17 = if (nullableIntProperty == null == true == false) 0 else {
|
||||||
<!DEBUG_INFO_CONSTANT, DEBUG_INFO_EXPRESSION_TYPE("kotlin.Int? & kotlin.Nothing?")!>nullableIntProperty<!>
|
<!DEBUG_INFO_CONSTANT, DEBUG_INFO_EXPRESSION_TYPE("kotlin.Int? & kotlin.Nothing?")!>nullableIntProperty<!>
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Int? & kotlin.Nothing?")!>nullableIntProperty<!><!UNSAFE_CALL!>.<!><!DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>java<!>
|
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Int? & kotlin.Nothing?")!>nullableIntProperty<!><!UNSAFE_CALL!>.<!><!DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE, NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>java<!>
|
||||||
}
|
}
|
||||||
|
|
||||||
//TESTCASE NUMBER: 18
|
//TESTCASE NUMBER: 18
|
||||||
|
|||||||
@@ -17252,6 +17252,11 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
|
|||||||
runTest("compiler/testData/diagnostics/tests/regressions/kt2376.kt");
|
runTest("compiler/testData/diagnostics/tests/regressions/kt2376.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("kt24488.kt")
|
||||||
|
public void testKt24488() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/regressions/kt24488.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("kt251.kt")
|
@TestMetadata("kt251.kt")
|
||||||
public void testKt251() throws Exception {
|
public void testKt251() throws Exception {
|
||||||
runTest("compiler/testData/diagnostics/tests/regressions/kt251.kt");
|
runTest("compiler/testData/diagnostics/tests/regressions/kt251.kt");
|
||||||
|
|||||||
Generated
+5
@@ -17242,6 +17242,11 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing
|
|||||||
runTest("compiler/testData/diagnostics/tests/regressions/kt2376.kt");
|
runTest("compiler/testData/diagnostics/tests/regressions/kt2376.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("kt24488.kt")
|
||||||
|
public void testKt24488() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/regressions/kt24488.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("kt251.kt")
|
@TestMetadata("kt251.kt")
|
||||||
public void testKt251() throws Exception {
|
public void testKt251() throws Exception {
|
||||||
runTest("compiler/testData/diagnostics/tests/regressions/kt251.kt");
|
runTest("compiler/testData/diagnostics/tests/regressions/kt251.kt");
|
||||||
|
|||||||
@@ -186,7 +186,7 @@ internal class Solver(
|
|||||||
}
|
}
|
||||||
is EqualsConstraint -> {
|
is EqualsConstraint -> {
|
||||||
(constraint.left.safeAs<TypeVariableBound>()
|
(constraint.left.safeAs<TypeVariableBound>()
|
||||||
?: constraint.right.safeAs())
|
?: constraint.right.safeAs<TypeVariableBound>())
|
||||||
?.let { return it.typeVariable }
|
?.let { return it.typeVariable }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user