K2: Don't lose constraint errors in the builder inference session

Pass constraint errors from the integration system into a candidate to
make sure it is reported later.

Related to KT-59426, KT-59437, KT-53749
#KT-55168 Submitted
This commit is contained in:
Simon Ogorodnik
2023-11-29 11:58:29 +01:00
committed by Space Team
parent cb3d65f669
commit 2f367b013a
26 changed files with 99 additions and 62 deletions
@@ -1,6 +1,6 @@
FILE: ifInBuildMap.kt
public final fun main(): R|kotlin/Unit| {
R|kotlin/collections/buildMap|<R|kotlin/String|, R|kotlin/String|>(<L> = buildMap@fun R|kotlin/collections/MutableMap<kotlin/String, kotlin/String>|.<anonymous>(): R|kotlin/Unit| <inline=Inline, kind=EXACTLY_ONCE> {
R|kotlin/collections/buildMap<CS errors: kotlin/collections/buildMap>#|<R|kotlin/String|, R|kotlin/String|>(<L> = buildMap@fun R|kotlin/collections/MutableMap<kotlin/String, kotlin/String>|.<anonymous>(): R|kotlin/Unit| <inline=Inline, kind=EXACTLY_ONCE> {
when () {
Boolean(true) -> {
R|kotlin/io/println|(String(test))
@@ -2,11 +2,11 @@
// ISSUE: KT-51143
fun main() {
buildMap {
<!NEW_INFERENCE_ERROR!>buildMap {
if (true) {
println("test")
} else {
put("foo", "bar")
}
}
}<!>
}
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.fir.resolve.inference
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction
@@ -13,6 +14,7 @@ import org.jetbrains.kotlin.fir.declarations.hasAnnotation
import org.jetbrains.kotlin.fir.expressions.FirResolvable
import org.jetbrains.kotlin.fir.expressions.FirStatement
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.languageVersionSettings
import org.jetbrains.kotlin.fir.resolve.calls.Candidate
import org.jetbrains.kotlin.fir.resolve.calls.ImplicitExtensionReceiverValue
import org.jetbrains.kotlin.fir.resolve.calls.ResolutionContext
@@ -117,7 +119,8 @@ class FirBuilderInferenceSession(
override fun inferPostponedVariables(
lambda: ResolvedLambdaAtom,
constraintSystemBuilder: ConstraintSystemBuilder,
completionMode: ConstraintSystemCompletionMode
completionMode: ConstraintSystemCompletionMode,
candidate: Candidate
): Map<ConeTypeVariableTypeConstructor, ConeKotlinType>? {
val (commonSystem, effectivelyEmptyConstraintSystem) = buildCommonSystem(constraintSystemBuilder.currentStorage())
val resultingSubstitutor by lazy { getResultingSubstitutor(commonSystem) }
@@ -142,6 +145,11 @@ class FirBuilderInferenceSession(
constraintSystemBuilder.substituteFixedVariables(resultingSubstitutor)
}
if (!session.languageVersionSettings.supportsFeature(LanguageFeature.NoAdditionalErrorsInK1DiagnosticReporter)) {
for (error in commonSystem.errors) {
candidate.system.addError(error)
}
}
updateCalls(resultingSubstitutor)
@Suppress("UNCHECKED_CAST")
@@ -79,7 +79,8 @@ class FirDelegatedPropertyInferenceSession(
override fun inferPostponedVariables(
lambda: ResolvedLambdaAtom,
constraintSystemBuilder: ConstraintSystemBuilder,
completionMode: ConstraintSystemCompletionMode
completionMode: ConstraintSystemCompletionMode,
candidate: Candidate
): Map<ConeTypeVariableTypeConstructor, ConeKotlinType>? = null
fun completeCandidates(): List<FirResolvable> {
@@ -39,7 +39,7 @@ abstract class FirInferenceSession {
lambda: ResolvedLambdaAtom,
constraintSystemBuilder: ConstraintSystemBuilder,
completionMode: ConstraintSystemCompletionMode,
// TODO: diagnostic holder
candidate: Candidate
): Map<ConeTypeVariableTypeConstructor, ConeKotlinType>?
abstract fun clear()
@@ -55,7 +55,8 @@ abstract class FirStubInferenceSession : FirInferenceSession() {
override fun inferPostponedVariables(
lambda: ResolvedLambdaAtom,
constraintSystemBuilder: ConstraintSystemBuilder,
completionMode: ConstraintSystemCompletionMode
completionMode: ConstraintSystemCompletionMode,
candidate: Candidate
): Map<ConeTypeVariableTypeConstructor, ConeKotlinType>? = null
override fun registerStubTypes(map: Map<TypeVariableMarker, StubTypeMarker>) {}
@@ -214,7 +214,7 @@ class PostponedArgumentsAnalyzer(
c.resolveForkPointsConstraints()
if (inferenceSession != null) {
val postponedVariables = inferenceSession.inferPostponedVariables(lambda, builder, completionMode)
val postponedVariables = inferenceSession.inferPostponedVariables(lambda, builder, completionMode, candidate)
if (postponedVariables == null) {
builder.removePostponedVariables()
@@ -8,28 +8,52 @@ package org.jetbrains.kotlin.fir.resolve.inference.model
import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction
import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.render
import org.jetbrains.kotlin.fir.types.ConeTypeVariable
import org.jetbrains.kotlin.fir.types.FirTypeProjection
import org.jetbrains.kotlin.resolve.calls.inference.model.*
import org.jetbrains.kotlin.types.model.TypeVariableMarker
class ConeDeclaredUpperBoundConstraintPosition : DeclaredUpperBoundConstraintPosition<Nothing?>(null)
class ConeDeclaredUpperBoundConstraintPosition : DeclaredUpperBoundConstraintPosition<Nothing?>(null) {
override fun toString(): String = "DeclaredUpperBound"
}
class ConeFixVariableConstraintPosition(variable: TypeVariableMarker) : FixVariableConstraintPosition<Nothing?>(variable, null)
class ConeFixVariableConstraintPosition(variable: TypeVariableMarker) : FixVariableConstraintPosition<Nothing?>(variable, null) {
override fun toString(): String = "Fix variable ${(variable as ConeTypeVariable).typeConstructor.name}"
}
class ConeArgumentConstraintPosition(argument: FirElement) : ArgumentConstraintPosition<FirElement>(argument)
class ConeArgumentConstraintPosition(argument: FirElement) : ArgumentConstraintPosition<FirElement>(argument) {
override fun toString(): String {
return "Argument ${argument.render()}"
}
}
object ConeExpectedTypeConstraintPosition : ExpectedTypeConstraintPosition<Nothing?>(null)
object ConeExpectedTypeConstraintPosition : ExpectedTypeConstraintPosition<Nothing?>(null) {
override fun toString(): String = "ExpectedType for some call"
}
class ConeExplicitTypeParameterConstraintPosition(
typeArgument: FirTypeProjection,
) : ExplicitTypeParameterConstraintPosition<FirTypeProjection>(typeArgument)
) : ExplicitTypeParameterConstraintPosition<FirTypeProjection>(typeArgument) {
override fun toString(): String = "TypeParameter ${typeArgument.render()}"
}
class ConeLambdaArgumentConstraintPosition(
anonymousFunction: FirAnonymousFunction
) : LambdaArgumentConstraintPosition<FirAnonymousFunction>(anonymousFunction)
) : LambdaArgumentConstraintPosition<FirAnonymousFunction>(anonymousFunction) {
override fun toString(): String {
return "LambdaArgument"
}
}
class ConeBuilderInferenceSubstitutionConstraintPosition(initialConstraint: InitialConstraint) :
BuilderInferenceSubstitutionConstraintPosition<Nothing?>(null, initialConstraint) // TODO
BuilderInferenceSubstitutionConstraintPosition<Nothing?>(null, initialConstraint) {
override fun toString(): String = "Incorporated builder inference constraint $initialConstraint " +
"into some call"
}
class ConeReceiverConstraintPosition(receiver: FirExpression) : ReceiverConstraintPosition<FirExpression>(receiver)
class ConeReceiverConstraintPosition(receiver: FirExpression) : ReceiverConstraintPosition<FirExpression>(receiver) {
override fun toString(): String = "Receiver ${argument.render()}"
}
@@ -13,10 +13,10 @@ fun main() {
override fun foo(): MutableList<String> = <!RETURN_TYPE_MISMATCH!>this@buildList<!>
}
}
buildList {
<!NEW_INFERENCE_ERROR!>buildList {
add(3)
val x: String = <!INITIALIZER_TYPE_MISMATCH!>get(0)<!>
}
}<!>
buildList {
add("3")
val x: MutableList<Int> = <!INITIALIZER_TYPE_MISMATCH!>this@buildList<!>
@@ -26,8 +26,8 @@ fun main() {
add(y)
val x: MutableList<String> = <!INITIALIZER_TYPE_MISMATCH!>this@buildList<!>
}
buildList {
<!NEW_INFERENCE_ERROR!>buildList {
add("")
val x: StringBuilder = <!INITIALIZER_TYPE_MISMATCH!>get(0)<!>
}
}<!>
}
@@ -26,7 +26,7 @@ fun <K> captureIn(x: Inv<out K>): K = null as K
fun <K> capture(x: Inv<K>): K = null as K
fun main() {
build {
<!NEW_INFERENCE_ERROR!>build {
emit("")
getInv()
captureOut(getInv())
@@ -35,7 +35,7 @@ fun main() {
// K is fixed into CapturedType(out NotFixed: TypeVariable(R))
capture(getOut())
""
}
}<!>
build {
emit("")
// K is fixed into CapturedType(in NotFixed: TypeVariable(R))
@@ -19,13 +19,13 @@ fun <K> capture(x: Inv<K>): K = null as K
fun <I> id(x: I): I = null as I
fun main() {
build {
<!NEW_INFERENCE_ERROR!>build {
emit("")
// K is fixed into CapturedType(out NotFixed: TypeVariable(R)
capture(id(getOut())) // unexpected TYPE_MISMATCH (KT-63996)
// capture(getOut()) // OK!!!
Unit
}
}<!>
build<String> {
emit("")
// K is fixed into CapturedType(out NotFixed: TypeVariable(R)
@@ -17,7 +17,7 @@ fun Any.test() {}
fun Any?.test2() {}
fun test() {
val ret1 = build {
val ret1 = <!NEW_INFERENCE_ERROR!>build {
emit(1)
emit(null)
<!BUILDER_INFERENCE_STUB_RECEIVER!>get()?.test()<!>
@@ -27,8 +27,8 @@ fun test() {
get()?.equals(1)
// there is `String?.equals` extension
get().equals("")
}
val ret2 = build {
}<!>
val ret2 = <!NEW_INFERENCE_ERROR!>build {
emit(1)
emit(null)
<!BUILDER_INFERENCE_STUB_RECEIVER!>get()?.test()<!>
@@ -40,8 +40,8 @@ fun test() {
x?.hashCode()
x?.equals(1)
x.equals("")
}
val ret3 = build {
}<!>
val ret3 = <!NEW_INFERENCE_ERROR!>build {
emit(1)
emit(null)
<!BUILDER_INFERENCE_STUB_RECEIVER!>get()?.test()<!>
@@ -68,7 +68,7 @@ fun test() {
}
""
}
}<!>
val ret4 = build {
emit(1)
emit(null)
@@ -149,15 +149,15 @@ fun test() {
""
}
val ret408 = build {
val ret408 = <!NEW_INFERENCE_ERROR!>build {
emit(1)
emit(null)
val x = get()
<!BUILDER_INFERENCE_STUB_RECEIVER!>x.test()<!>
""
}
val ret41 = build {
}<!>
val ret41 = <!NEW_INFERENCE_ERROR!>build {
emit(1)
emit(null)
<!BUILDER_INFERENCE_STUB_RECEIVER!>get()?.test()<!>
@@ -205,7 +205,7 @@ fun test() {
}
""
}
}<!>
val ret5 = build {
emit(1)
emit(null)
@@ -280,14 +280,14 @@ fun test() {
}
""
}
val ret508 = build {
val ret508 = <!NEW_INFERENCE_ERROR!>build {
emit(1)
emit(null)
val x = get()
<!BUILDER_INFERENCE_STUB_RECEIVER!>x.test()<!>
""
}
val ret51 = build {
}<!>
val ret51 = <!NEW_INFERENCE_ERROR!>build {
emit(1)
emit(null)
<!BUILDER_INFERENCE_STUB_RECEIVER!>get()?.test()<!>
@@ -310,5 +310,5 @@ fun test() {
}
""
}
}<!>
}
@@ -1,8 +1,8 @@
// ISSUE: KT-55168
fun foo(arg: Boolean) = buildList {
fun foo(arg: Boolean) = <!NEW_INFERENCE_ERROR!>buildList {
if (arg) {
removeLast()
} else {
add(42)
}
}
}<!>
@@ -0,0 +1 @@
/inconsistentTypeInference.fir.kt:(62,127): error: New inference error [NewConstraintError at Incorporate kotlin/collections/MutableList<TypeVariable(E)> <: kotlin/collections/Collection<kotlin/Int> from Incorporated builder inference constraint kotlin/collections/MutableList<Stub (chain inference): TypeVariable(E)> <: kotlin/collections/Collection<kotlin/Int> from Incorporated builder inference constraint kotlin/collections/MutableList<Stub (chain inference): TypeVariable(E)> <: kotlin/collections/Collection<TypeVariable(T)> from Receiver this@R|special/anonymous| into some call into some call from position Incorporated builder inference constraint kotlin/collections/MutableList<Stub (chain inference): TypeVariable(E)> <: kotlin/collections/Collection<kotlin/Int> from Incorporated builder inference constraint kotlin/collections/MutableList<Stub (chain inference): TypeVariable(E)> <: kotlin/collections/Collection<TypeVariable(T)> from Receiver this@R|special/anonymous| into some call into some call: kotlin/String <!: kotlin/Int].
@@ -2,9 +2,9 @@
// FIR_DUMP
fun foo() {
buildList {
<!NEW_INFERENCE_ERROR!>buildList {
add("Boom")
println(plus(1)[0])
}
}<!>
}
@@ -1,6 +1,6 @@
FILE: inconsistentTypeInference.fir.kt
public final fun foo(): R|kotlin/Unit| {
R|kotlin/collections/buildList|<R|kotlin/String|>(<L> = buildList@fun R|kotlin/collections/MutableList<kotlin/String>|.<anonymous>(): R|kotlin/Unit| <inline=Inline, kind=EXACTLY_ONCE> {
R|kotlin/collections/buildList<CS errors: kotlin/collections/buildList>#|<R|kotlin/String|>(<L> = buildList@fun R|kotlin/collections/MutableList<kotlin/String>|.<anonymous>(): R|kotlin/Unit| <inline=Inline, kind=EXACTLY_ONCE> {
this@R|special/anonymous|.R|SubstitutionOverride<kotlin/collections/MutableList.add: R|kotlin/Boolean|>|(String(Boom))
R|kotlin/io/println|(this@R|special/anonymous|.R|kotlin/collections/plus|<R|kotlin/Int|>(Int(1)).R|SubstitutionOverride<kotlin/collections/List.get: R|kotlin/Int|>|(Int(0)))
}
@@ -0,0 +1 @@
/inconsistentTypeInference2.fir.kt:(62,132): error: New inference error [NewConstraintError at Incorporate kotlin/collections/MutableList<TypeVariable(E)> <: kotlin/collections/Collection<kotlin/Int> from Incorporated builder inference constraint kotlin/collections/MutableList<Stub (chain inference): TypeVariable(E)> <: kotlin/collections/Collection<kotlin/Int> from Incorporated builder inference constraint kotlin/collections/MutableList<Stub (chain inference): TypeVariable(E)> <: kotlin/collections/Collection<TypeVariable(T)> from Receiver this@R|special/anonymous| into some call into some call from position Incorporated builder inference constraint kotlin/collections/MutableList<Stub (chain inference): TypeVariable(E)> <: kotlin/collections/Collection<kotlin/Int> from Incorporated builder inference constraint kotlin/collections/MutableList<Stub (chain inference): TypeVariable(E)> <: kotlin/collections/Collection<TypeVariable(T)> from Receiver this@R|special/anonymous| into some call into some call: kotlin/String <!: kotlin/Int].
@@ -2,8 +2,8 @@
// FIR_DUMP
fun bar() {
buildList {
<!NEW_INFERENCE_ERROR!>buildList {
add("Boom")
println(this.plus(1)[0])
}
}
}<!>
}
@@ -1,6 +1,6 @@
FILE: inconsistentTypeInference2.fir.kt
public final fun bar(): R|kotlin/Unit| {
R|kotlin/collections/buildList|<R|kotlin/String|>(<L> = buildList@fun R|kotlin/collections/MutableList<kotlin/String>|.<anonymous>(): R|kotlin/Unit| <inline=Inline, kind=EXACTLY_ONCE> {
R|kotlin/collections/buildList<CS errors: kotlin/collections/buildList>#|<R|kotlin/String|>(<L> = buildList@fun R|kotlin/collections/MutableList<kotlin/String>|.<anonymous>(): R|kotlin/Unit| <inline=Inline, kind=EXACTLY_ONCE> {
this@R|special/anonymous|.R|SubstitutionOverride<kotlin/collections/MutableList.add: R|kotlin/Boolean|>|(String(Boom))
R|kotlin/io/println|(this@R|special/anonymous|.R|kotlin/collections/plus|<R|kotlin/Int|>(Int(1)).R|SubstitutionOverride<kotlin/collections/List.get: R|kotlin/Int|>|(Int(0)))
}
@@ -7,7 +7,7 @@ fun <T : Any> myBuilder(block: Foo<T>.() -> Unit) : Foo<T> = Foo<T>().apply(bloc
fun main(arg: Any) {
val x = 57
val value = myBuilder {
val value = <!NEW_INFERENCE_ERROR!>myBuilder {
doSmthng("one ")
run { a; this }.a = 10
<!BUILDER_INFERENCE_STUB_RECEIVER!>a += 1<!>
@@ -19,6 +19,6 @@ fun main(arg: Any) {
if (arg is String) {
a = arg
}
}
}<!>
<!OVERLOAD_RESOLUTION_AMBIGUITY!>println<!>(value.a?.<!UNRESOLVED_REFERENCE!>count<!> { <!UNRESOLVED_REFERENCE!>it<!> in 'l' .. 'q' })
}
@@ -60,18 +60,18 @@ fun main(arg: Any, condition: Boolean) {
}
// See KT-54664
val value3 = myBuilder {
val value3 = <!NEW_INFERENCE_ERROR!>myBuilder {
accept("")
a = 45
bar(::a)
}
}<!>
fun baz(t: Int) {}
val value4 = myBuilder {
val value4 = <!NEW_INFERENCE_ERROR!>myBuilder {
accept("")
a = 45
b[0] = 123
baz(a)
}
}<!>
}
@@ -91,7 +91,7 @@ FILE: unsafeAssignmentExtra.fir.kt
}
)
lval value3: R|Foo<kotlin/Int>| = R|/myBuilder|<R|kotlin/Int|>(<L> = myBuilder@fun R|Foo<kotlin/Int>|.<anonymous>(): R|kotlin/Unit| <inline=NoInline> {
lval value3: R|Foo<kotlin/Int>| = R|/myBuilder<CS errors: /myBuilder>#|<R|kotlin/Int|>(<L> = myBuilder@fun R|Foo<kotlin/Int>|.<anonymous>(): R|kotlin/Unit| <inline=NoInline> {
this@R|special/anonymous|.R|SubstitutionOverride</Foo.accept: R|kotlin/Unit|>|(String())
this@R|special/anonymous|.R|SubstitutionOverride</Foo.a: R|Stub (chain inference): TypeVariable(T)|>| = Int(45)
R|/bar|(::R|SubstitutionOverride</Foo.a: R|Stub (chain inference): TypeVariable(T)|>|)
@@ -100,7 +100,7 @@ FILE: unsafeAssignmentExtra.fir.kt
local final fun baz(t: R|kotlin/Int|): R|kotlin/Unit| {
}
lval value4: R|Foo<it(kotlin/Comparable<*> & java/io/Serializable)>| = R|/myBuilder|<R|it(kotlin/Comparable<*> & java/io/Serializable)|>(<L> = myBuilder@fun R|Foo<it(kotlin/Comparable<*> & java/io/Serializable)>|.<anonymous>(): R|kotlin/Unit| <inline=NoInline> {
lval value4: R|Foo<it(kotlin/Comparable<*> & java/io/Serializable)>| = R|/myBuilder<CS errors: /myBuilder>#|<R|it(kotlin/Comparable<*> & java/io/Serializable)|>(<L> = myBuilder@fun R|Foo<it(kotlin/Comparable<*> & java/io/Serializable)>|.<anonymous>(): R|kotlin/Unit| <inline=NoInline> {
this@R|special/anonymous|.R|SubstitutionOverride</Foo.accept: R|kotlin/Unit|>|(String())
this@R|special/anonymous|.R|SubstitutionOverride</Foo.a: R|Stub (chain inference): TypeVariable(T)|>| = Int(45)
this@R|special/anonymous|.R|SubstitutionOverride</Foo.b: R|kotlin/Array<Stub (chain inference): TypeVariable(T)>|>|.R|SubstitutionOverride<kotlin/Array.set: R|kotlin/Unit|>|(Int(0), Int(123))
@@ -0,0 +1 @@
/upperBoundViolation.fir.kt:(150,260): error: New inference error [NewConstraintError at Incorporate TypeVariable(E) <: kotlin/Number from Incorporated builder inference constraint Stub (chain inference): TypeVariable(E) <: kotlin/Number from Incorporated builder inference constraint TypeVariable(T) <: kotlin/Number from DeclaredUpperBound into some call into some call from position Incorporated builder inference constraint Stub (chain inference): TypeVariable(E) <: kotlin/Number from Incorporated builder inference constraint TypeVariable(T) <: kotlin/Number from DeclaredUpperBound into some call into some call: kotlin/String <!: kotlin/Number].
@@ -4,8 +4,8 @@
fun <T : Number> printGenericNumber(t: T) = println("Number is $t")
fun main() {
buildList { // inferred into MutableList<String>
<!NEW_INFERENCE_ERROR!>buildList { // inferred into MutableList<String>
add("Boom")
printGenericNumber(this[0])
}
}<!>
}
@@ -3,7 +3,7 @@ FILE: upperBoundViolation.fir.kt
^printGenericNumber R|kotlin/io/println|(<strcat>(String(Number is ), R|<local>/t|))
}
public final fun main(): R|kotlin/Unit| {
R|kotlin/collections/buildList|<R|kotlin/String|>(<L> = buildList@fun R|kotlin/collections/MutableList<kotlin/String>|.<anonymous>(): R|kotlin/Unit| <inline=Inline, kind=EXACTLY_ONCE> {
R|kotlin/collections/buildList<CS errors: kotlin/collections/buildList>#|<R|kotlin/String|>(<L> = buildList@fun R|kotlin/collections/MutableList<kotlin/String>|.<anonymous>(): R|kotlin/Unit| <inline=Inline, kind=EXACTLY_ONCE> {
this@R|special/anonymous|.R|SubstitutionOverride<kotlin/collections/MutableList.add: R|kotlin/Boolean|>|(String(Boom))
R|/printGenericNumber|<R|kotlin/String|>(this@R|special/anonymous|.R|SubstitutionOverride<kotlin/collections/MutableList.get: R|Stub (chain inference): TypeVariable(E)|>|(Int(0)))
}
@@ -50,10 +50,10 @@ val test6 = generate {
invNullableAnyExtension()
}
val test7 = generate {
val test7 = <!NEW_INFERENCE_ERROR!>generate {
yield("baz")
genericExtension<Int>()
}
}<!>
val test8 = generate {
safeExtension()
@@ -12,8 +12,8 @@ fun test_1() {
}
fun test_2() {
<!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>sequence<!> {
yield(materialize())
<!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER, NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>sequence<!> {
yield(<!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>materialize<!>())
}
}