From acc563381190b01d65037eed159fe48237f7d5bd Mon Sep 17 00:00:00 2001 From: Ilya Chernikov Date: Sun, 12 Apr 2020 18:20:31 +0200 Subject: [PATCH] [NI] Fix inference of lambda with receiver when wrapped... in when/if or another lambda. #KT-37419 fixed --- ...irOldFrontendDiagnosticsTestGenerated.java | 5 ++ .../KotlinConstraintSystemCompleter.kt | 9 ++- .../inference/regressions/kt37419.fir.kt | 45 +++++++++++++++ .../tests/inference/regressions/kt37419.kt | 45 +++++++++++++++ .../tests/inference/regressions/kt37419.txt | 56 +++++++++++++++++++ .../tests/regressions/kt30245.fir.kt | 31 ++++++---- .../diagnostics/tests/regressions/kt30245.kt | 31 ++++++---- .../diagnostics/tests/regressions/kt30245.txt | 19 +++++++ .../checkers/DiagnosticsTestGenerated.java | 5 ++ .../DiagnosticsUsingJavacTestGenerated.java | 5 ++ 10 files changed, 228 insertions(+), 23 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/inference/regressions/kt37419.fir.kt create mode 100644 compiler/testData/diagnostics/tests/inference/regressions/kt37419.kt create mode 100644 compiler/testData/diagnostics/tests/inference/regressions/kt37419.txt diff --git a/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java index 2ba444407ab..730cea22a34 100644 --- a/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java @@ -11478,6 +11478,11 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirOldFronte runTest("compiler/testData/diagnostics/tests/inference/regressions/kt37043_2.kt"); } + @TestMetadata("kt37419.kt") + public void testKt37419() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/regressions/kt37419.kt"); + } + @TestMetadata("kt37650.kt") public void testKt37650() throws Exception { runTest("compiler/testData/diagnostics/tests/inference/regressions/kt37650.kt"); diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/KotlinConstraintSystemCompleter.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/KotlinConstraintSystemCompleter.kt index 799aab5cda3..8a1b9c79658 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/KotlinConstraintSystemCompleter.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/components/KotlinConstraintSystemCompleter.kt @@ -263,9 +263,12 @@ class KotlinConstraintSystemCompleter( c.notFixedTypeVariables.getValue(variable), TypeVariableDirectionCalculator.ResolveDirection.TO_SUPERTYPE ) as KotlinType - val isExtensionWithoutParameters = - functionalType.isExtensionFunctionType && functionalType.arguments.size == 2 && parameterTypes?.isEmpty() == true - if (parameterTypes?.all { type -> type != null } == true && !isExtensionWithoutParameters) return this + + val isExtensionFunction = functionalType.isExtensionFunctionType + val isExtensionFunctionWithReceiverAsDeclaredParameter = + isExtensionFunction && functionalType.arguments.size - 1 == parameterTypes?.count { it != null } + if (parameterTypes?.all { it != null } == true && (!isExtensionFunction || isExtensionFunctionWithReceiverAsDeclaredParameter)) return this + if (!functionalType.isSuitable()) return this val returnVariable = typeVariableCreator() csBuilder.registerVariable(returnVariable) diff --git a/compiler/testData/diagnostics/tests/inference/regressions/kt37419.fir.kt b/compiler/testData/diagnostics/tests/inference/regressions/kt37419.fir.kt new file mode 100644 index 00000000000..d5c351124cf --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/regressions/kt37419.fir.kt @@ -0,0 +1,45 @@ +// !LANGUAGE: +NewInference +// !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_VARIABLE + +interface Receiver +interface Parameter +typealias LambdaWithReceiver = Receiver.(Parameter) -> Unit + +fun Receiver.method(param: Parameter): LambdaWithReceiver = TODO() + +enum class E { VALUE } + +fun id(x: K): K = x + +class SomeClass { + val e = E.VALUE + + val withoutType: LambdaWithReceiver + get() = when (e) { + E.VALUE -> { param -> + method(param) + } + } + + val withExplicitType: LambdaWithReceiver + get() = when (e) { + E.VALUE -> { param: Parameter -> + method(param) + } + } +} + +class OtherClass { + val ok: LambdaWithReceiver + get() = { param: Parameter -> + method(param) + } +} + +val e2 = E.VALUE +val staticWithExplicitType: LambdaWithReceiver + get() = when (e2) { + E.VALUE -> { param: Parameter -> + method(param) + } + } diff --git a/compiler/testData/diagnostics/tests/inference/regressions/kt37419.kt b/compiler/testData/diagnostics/tests/inference/regressions/kt37419.kt new file mode 100644 index 00000000000..e7f76461b7e --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/regressions/kt37419.kt @@ -0,0 +1,45 @@ +// !LANGUAGE: +NewInference +// !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_VARIABLE + +interface Receiver +interface Parameter +typealias LambdaWithReceiver = Receiver.(Parameter) -> Unit + +fun Receiver.method(param: Parameter): LambdaWithReceiver = TODO() + +enum class E { VALUE } + +fun id(x: K): K = x + +class SomeClass { + val e = E.VALUE + + val withoutType: LambdaWithReceiver + get() = when (e) { + E.VALUE -> { param -> + method(param) + } + } + + val withExplicitType: LambdaWithReceiver + get() = when (e) { + E.VALUE -> { param: Parameter -> + method(param) + } + } +} + +class OtherClass { + val ok: LambdaWithReceiver + get() = { param: Parameter -> + method(param) + } +} + +val e2 = E.VALUE +val staticWithExplicitType: LambdaWithReceiver + get() = when (e2) { + E.VALUE -> { param: Parameter -> + method(param) + } + } diff --git a/compiler/testData/diagnostics/tests/inference/regressions/kt37419.txt b/compiler/testData/diagnostics/tests/inference/regressions/kt37419.txt new file mode 100644 index 00000000000..3684aa649c7 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/regressions/kt37419.txt @@ -0,0 +1,56 @@ +package + +public val e2: E +public val staticWithExplicitType: LambdaWithReceiver /* = Receiver.(Parameter) -> kotlin.Unit */ +public fun id(/*0*/ x: K): K +public fun Receiver.method(/*0*/ param: Parameter): LambdaWithReceiver /* = Receiver.(Parameter) -> kotlin.Unit */ + +public final enum class E : kotlin.Enum { + enum entry VALUE + + private constructor E() + public final override /*1*/ /*fake_override*/ val name: kotlin.String + public final override /*1*/ /*fake_override*/ val ordinal: kotlin.Int + protected final override /*1*/ /*fake_override*/ fun clone(): kotlin.Any + public final override /*1*/ /*fake_override*/ fun compareTo(/*0*/ other: E): kotlin.Int + public final override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + protected/*protected and package*/ final override /*1*/ /*fake_override*/ /*isHiddenForResolutionEverywhereBesideSupercalls*/ fun finalize(): kotlin.Unit + public final override /*1*/ /*fake_override*/ /*isHiddenForResolutionEverywhereBesideSupercalls*/ fun getDeclaringClass(): java.lang.Class! + public final override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + // Static members + public final /*synthesized*/ fun valueOf(/*0*/ value: kotlin.String): E + public final /*synthesized*/ fun values(): kotlin.Array +} + +public final class OtherClass { + public constructor OtherClass() + public final val ok: LambdaWithReceiver /* = Receiver.(Parameter) -> kotlin.Unit */ + 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 Parameter { + 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 Receiver { + 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 SomeClass { + public constructor SomeClass() + public final val e: E + public final val withExplicitType: LambdaWithReceiver /* = Receiver.(Parameter) -> kotlin.Unit */ + public final val withoutType: LambdaWithReceiver /* = Receiver.(Parameter) -> kotlin.Unit */ + 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 typealias LambdaWithReceiver = Receiver.(Parameter) -> kotlin.Unit diff --git a/compiler/testData/diagnostics/tests/regressions/kt30245.fir.kt b/compiler/testData/diagnostics/tests/regressions/kt30245.fir.kt index 46fb6b9a25c..436c654e577 100644 --- a/compiler/testData/diagnostics/tests/regressions/kt30245.fir.kt +++ b/compiler/testData/diagnostics/tests/regressions/kt30245.fir.kt @@ -11,6 +11,8 @@ fun test() { val f02: Sample.() -> Unit = id Unit> { s: Sample -> } } +enum class E { VALUE } + typealias E0 = Int.() -> Int class W1(val f: E0) { // overload ambiguity is not supported yet - see commented examples with "overload" keyword below @@ -68,15 +70,18 @@ fun test2() { // to extension lambda 1 val w23 = W2 { s -> s.length } // oi+ ni+ val i23: E1 = id { s -> s.length } // oi+ ni+ val w24 = W2 { s: String -> this + s.length } // oi+ ni+ -// val i24: E1 = id { s: String -> this + s.length } //oi- ni- + val i24: E1 = id { s: String -> this + s.length } //oi- ni+ val w25 = W2 { s: String -> s.length } // oi+ ni+ -// val i25: E1 = id { s: String -> s.length } // oi- ni- - - // yet unsupported cases with ambiguity for the lambda conversion (commented constructors in wrappers above) -// val w26 = W2 { i, s -> i + s.length } // overload oi- ni- -// val i26: E1 = id { i, s -> i + s.length } // overload oi- ni- -// val w27 = W2 { i, s: String -> i + s.length } // overload oi- ni- -// val i27: E1 = id { i, s: String -> i + s.length } // overload oi- ni- + val i25: E1 = id { s: String -> s.length } // oi- ni+ + val w26 = W2(id { s: String -> this + s.length }) // oi- ni+ + val w26a = W2(id { s -> this + s.length }) // oi+ ni+ + val i26: E1 = id { s: String -> this + s.length } // oi- ni+ + val i26a: E1 = id { s -> this + s.length } // oi+ ni+ + val e = E.VALUE + val w27 = W2(when (e) { E.VALUE -> { s: String -> this + s.length } }) // oi- ni+ + val w27a = W2(when (e) { E.VALUE -> { s -> this + s.length } }) // oi+ ni+ + val i27: E1 = when (e) { E.VALUE -> { s: String -> this + s.length } } // oi+ ni+ + val i27a: E1 = when (e) { E.VALUE -> { s -> this + s.length } } // oi+ ni+ val w28 = W2 { i: Int, s -> i + s.length } // oi- ni- val i28: E1 = id { i: Int, s -> i + s.length } // oi- ni- @@ -84,8 +89,14 @@ fun test2() { // to extension lambda 1 val i29: E1 = id { i: Int, s: String -> i + s.length } // oi+ ni+ // yet unsupported cases with ambiguity for the lambda conversion (commented constructors in wrappers above) -// val o2a = W2 { i: Int -> i } // overload oi- ni+ -// val o2b = W2 { i -> i } // overload oi- ni- +// val w2a = W2 { i, s -> i + s.length } // overload oi- ni- +// val i2a: E1 = id { i, s -> i + s.length } // overload oi- ni- +// val w2b = W2 { i, s: String -> i + s.length } // overload oi- ni- +// val i2b: E1 = id { i, s: String -> i + s.length } // overload oi- ni- + + // yet unsupported cases with ambiguity for the lambda conversion (commented constructors in wrappers above) +// val o2c = W2 { i: Int -> i } // overload oi- ni+ +// val o2d = W2 { i -> i } // overload oi- ni- } fun test3() { // to non-extension lambda 1 diff --git a/compiler/testData/diagnostics/tests/regressions/kt30245.kt b/compiler/testData/diagnostics/tests/regressions/kt30245.kt index 09b46b1d116..eca619784db 100644 --- a/compiler/testData/diagnostics/tests/regressions/kt30245.kt +++ b/compiler/testData/diagnostics/tests/regressions/kt30245.kt @@ -11,6 +11,8 @@ fun test() { val f02: Sample.() -> Unit = id Unit> { s: Sample -> } } +enum class E { VALUE } + typealias E0 = Int.() -> Int class W1(val f: E0) { // overload ambiguity is not supported yet - see commented examples with "overload" keyword below @@ -68,15 +70,18 @@ fun test2() { // to extension lambda 1 val w23 = W2 { s -> s.length } // oi+ ni+ val i23: E1 = id { s -> s.length } // oi+ ni+ val w24 = W2 { s: String -> this + s.length } // oi+ ni+ -// val i24: E1 = id { s: String -> this + s.length } //oi- ni- + val i24: E1 = id { s: String -> this + s.length } //oi- ni+ val w25 = W2 { s: String -> s.length } // oi+ ni+ -// val i25: E1 = id { s: String -> s.length } // oi- ni- - - // yet unsupported cases with ambiguity for the lambda conversion (commented constructors in wrappers above) -// val w26 = W2 { i, s -> i + s.length } // overload oi- ni- -// val i26: E1 = id { i, s -> i + s.length } // overload oi- ni- -// val w27 = W2 { i, s: String -> i + s.length } // overload oi- ni- -// val i27: E1 = id { i, s: String -> i + s.length } // overload oi- ni- + val i25: E1 = id { s: String -> s.length } // oi- ni+ + val w26 = W2(id { s: String -> this + s.length }) // oi- ni+ + val w26a = W2(id { s -> this + s.length }) // oi+ ni+ + val i26: E1 = id { s: String -> this + s.length } // oi- ni+ + val i26a: E1 = id { s -> this + s.length } // oi+ ni+ + val e = E.VALUE + val w27 = W2(when (e) { E.VALUE -> { s: String -> this + s.length } }) // oi- ni+ + val w27a = W2(when (e) { E.VALUE -> { s -> this + s.length } }) // oi+ ni+ + val i27: E1 = when (e) { E.VALUE -> { s: String -> this + s.length } } // oi+ ni+ + val i27a: E1 = when (e) { E.VALUE -> { s -> this + s.length } } // oi+ ni+ val w28 = W2 { i: Int, s -> i + s.length } // oi- ni- val i28: E1 = id { i: Int, s -> i + s.length } // oi- ni- @@ -84,8 +89,14 @@ fun test2() { // to extension lambda 1 val i29: E1 = id { i: Int, s: String -> i + s.length } // oi+ ni+ // yet unsupported cases with ambiguity for the lambda conversion (commented constructors in wrappers above) -// val o2a = W2 { i: Int -> i } // overload oi- ni+ -// val o2b = W2 { i -> i } // overload oi- ni- +// val w2a = W2 { i, s -> i + s.length } // overload oi- ni- +// val i2a: E1 = id { i, s -> i + s.length } // overload oi- ni- +// val w2b = W2 { i, s: String -> i + s.length } // overload oi- ni- +// val i2b: E1 = id { i, s: String -> i + s.length } // overload oi- ni- + + // yet unsupported cases with ambiguity for the lambda conversion (commented constructors in wrappers above) +// val o2c = W2 { i: Int -> i } // overload oi- ni+ +// val o2d = W2 { i -> i } // overload oi- ni- } fun test3() { // to non-extension lambda 1 diff --git a/compiler/testData/diagnostics/tests/regressions/kt30245.txt b/compiler/testData/diagnostics/tests/regressions/kt30245.txt index a111f39317e..fb04e2179b3 100644 --- a/compiler/testData/diagnostics/tests/regressions/kt30245.txt +++ b/compiler/testData/diagnostics/tests/regressions/kt30245.txt @@ -22,6 +22,25 @@ public final class B : A { public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String } +public final enum class E : kotlin.Enum { + enum entry VALUE + + private constructor E() + public final override /*1*/ /*fake_override*/ val name: kotlin.String + public final override /*1*/ /*fake_override*/ val ordinal: kotlin.Int + protected final override /*1*/ /*fake_override*/ fun clone(): kotlin.Any + public final override /*1*/ /*fake_override*/ fun compareTo(/*0*/ other: E): kotlin.Int + public final override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + protected/*protected and package*/ final override /*1*/ /*fake_override*/ /*isHiddenForResolutionEverywhereBesideSupercalls*/ fun finalize(): kotlin.Unit + public final override /*1*/ /*fake_override*/ /*isHiddenForResolutionEverywhereBesideSupercalls*/ fun getDeclaringClass(): java.lang.Class! + public final override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + // Static members + public final /*synthesized*/ fun valueOf(/*0*/ value: kotlin.String): E + public final /*synthesized*/ fun values(): kotlin.Array +} + public final class Sample { public constructor Sample() public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index 5ea99bee7e6..b72b48aa1d6 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -11485,6 +11485,11 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTestWithFirVali runTest("compiler/testData/diagnostics/tests/inference/regressions/kt37043_2.kt"); } + @TestMetadata("kt37419.kt") + public void testKt37419() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/regressions/kt37419.kt"); + } + @TestMetadata("kt37650.kt") public void testKt37650() throws Exception { runTest("compiler/testData/diagnostics/tests/inference/regressions/kt37650.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java index ade8fd0e75d..c1c17db84b0 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java @@ -11480,6 +11480,11 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing runTest("compiler/testData/diagnostics/tests/inference/regressions/kt37043_2.kt"); } + @TestMetadata("kt37419.kt") + public void testKt37419() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/regressions/kt37419.kt"); + } + @TestMetadata("kt37650.kt") public void testKt37650() throws Exception { runTest("compiler/testData/diagnostics/tests/inference/regressions/kt37650.kt");