[NI] Require all proper constraints for Exact return type
Consider call `foo(bar())` where bar() returns some type variable `T`;
We had a contract that call `bar` can be completed without completion
of foo (type variables can be inferred from the current context) if `T`
has at least one proper lower constraint (ProperType <: T).
Indeed, new constraints can be added only as upper ones, so there is
no need to grow constraint system.
Unfortunately, we have Exact annotation that is used on return type of
elvis. Now, consider the following situation:
```
fun foo(a: Any) {}
fun bar(e: T): @Exact T
foo(bar("str"))
```
Here, because of Exact annotation, constraint with `Any`-type will be
added as an equal one => our prerequisite that there will be no new
lower constraints is false. `bar("str")` is inferred to Any in OI,
this seems conceptually wrong, but it's another topic of discussion.
In NI we can't just grow constraint system to use outer call because
of another important use-case:
```
fun <T> generic(i: Inv<T>) {}
fun test(a: Inv<*>?, b: Inv<*>) {
generic(a ?: b)
}
```
Common constraint system for these two calls can't be solved
(fundamentally) for this example, only if (a ?: b) and generic(result)
are computed separately.
So, to mitigate initial issue, we'll grow constraint system only if
there is at least one non-proper constraint.
#KT-31969 Fixed
This commit is contained in:
+10
@@ -10011,6 +10011,16 @@ public class FirDiagnosticsSmokeTestGenerated extends AbstractFirDiagnosticsSmok
|
||||
runTest("compiler/testData/diagnostics/tests/inference/commonSystem/kt3372toCollection.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("lessSpecificTypeForArgumentCallWithExactAnnotation.kt")
|
||||
public void testLessSpecificTypeForArgumentCallWithExactAnnotation() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/commonSystem/lessSpecificTypeForArgumentCallWithExactAnnotation.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("lessSpecificTypeForArgumentCallWithExactAnnotation_ni.kt")
|
||||
public void testLessSpecificTypeForArgumentCallWithExactAnnotation_ni() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/commonSystem/lessSpecificTypeForArgumentCallWithExactAnnotation_ni.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("nestedLambdas.kt")
|
||||
public void testNestedLambdas() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/commonSystem/nestedLambdas.kt");
|
||||
|
||||
+5
-2
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage.Empt
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.ExpectedTypeConstraintPosition
|
||||
import org.jetbrains.kotlin.resolve.calls.model.*
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.forceResolution
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.hasExactAnnotation
|
||||
import org.jetbrains.kotlin.types.ErrorUtils
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import org.jetbrains.kotlin.types.UnwrappedType
|
||||
@@ -242,14 +243,16 @@ class KotlinCallCompleter(
|
||||
val constructor = typeVariable.constructor
|
||||
val variableWithConstraints = csBuilder.currentStorage().notFixedTypeVariables[constructor] ?: return false
|
||||
val constraints = variableWithConstraints.constraints
|
||||
return constraints.isNotEmpty() && constraints.any {
|
||||
return constraints.isNotEmpty() && constraints.anyOrAll(requireAll = typeVariable.hasExactAnnotation()) {
|
||||
!it.type.typeConstructor(context).isIntegerLiteralTypeConstructor(context) &&
|
||||
(it.kind.isLower() || it.kind.isEqual()) &&
|
||||
csBuilder.isProperType(it.type)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private inline fun <T> Iterable<T>.anyOrAll(requireAll: Boolean, p: (T) -> Boolean): Boolean =
|
||||
if (requireAll) all(p) else any(p)
|
||||
|
||||
private fun KotlinResolutionCandidate.computeReturnTypeWithSmartCastInfo(
|
||||
returnType: UnwrappedType,
|
||||
resolutionCallbacks: KotlinResolutionCallbacks
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
open class View
|
||||
|
||||
fun test() {
|
||||
val target = foo<View>() ?: foo() <!NI;USELESS_ELVIS!>?: run {}<!>
|
||||
val target = foo<View>() ?: foo() ?: run {}
|
||||
}
|
||||
|
||||
fun <T : View> foo(): T? {
|
||||
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
// !LANGUAGE: -NewInference
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
|
||||
interface A
|
||||
interface B : A
|
||||
interface C : A
|
||||
|
||||
@Suppress("INVISIBLE_REFERENCE")
|
||||
fun <K> select(x: K, y: K): @kotlin.internal.Exact K = x
|
||||
|
||||
fun foo(a: Any) {}
|
||||
|
||||
fun test(b: B, c: C) {
|
||||
foo(
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Any")!>select(b, c)<!>
|
||||
)
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
package
|
||||
|
||||
public fun foo(/*0*/ a: kotlin.Any): kotlin.Unit
|
||||
@kotlin.Suppress(names = {"INVISIBLE_REFERENCE"}) public fun </*0*/ K> select(/*0*/ x: K, /*1*/ y: K): K
|
||||
public fun test(/*0*/ b: B, /*1*/ c: C): kotlin.Unit
|
||||
|
||||
public interface A {
|
||||
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 B : A {
|
||||
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 C : A {
|
||||
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
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
// !LANGUAGE: +NewInference
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
|
||||
interface A
|
||||
interface B : A
|
||||
interface C : A
|
||||
|
||||
@Suppress("INVISIBLE_REFERENCE")
|
||||
fun <K> select(x: K, y: K): @kotlin.internal.Exact K = x
|
||||
|
||||
fun foo(a: Any) {}
|
||||
|
||||
fun test(b: B, c: C) {
|
||||
foo(
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("A")!>select(b, c)<!>
|
||||
)
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
package
|
||||
|
||||
public fun foo(/*0*/ a: kotlin.Any): kotlin.Unit
|
||||
@kotlin.Suppress(names = {"INVISIBLE_REFERENCE"}) public fun </*0*/ K> select(/*0*/ x: K, /*1*/ y: K): K
|
||||
public fun test(/*0*/ b: B, /*1*/ c: C): kotlin.Unit
|
||||
|
||||
public interface A {
|
||||
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 B : A {
|
||||
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 C : A {
|
||||
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
|
||||
}
|
||||
compiler/testData/diagnostics/tests/inference/commonSystem/postponedCompletionWithExactAnnotation.kt
Vendored
+1
@@ -1,4 +1,5 @@
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
// !LANGUAGE: -NewInference
|
||||
|
||||
interface ISample
|
||||
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@ fun test(nullableSample: ISample, any: Any) {
|
||||
)
|
||||
|
||||
elvisSimple(
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("ISample")!>elvisExact(nullableSample, materialize())<!>,
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Any?")!>elvisExact(nullableSample, materialize())<!>,
|
||||
any
|
||||
)
|
||||
}
|
||||
|
||||
@@ -10018,6 +10018,16 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/commonSystem/kt3372toCollection.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("lessSpecificTypeForArgumentCallWithExactAnnotation.kt")
|
||||
public void testLessSpecificTypeForArgumentCallWithExactAnnotation() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/commonSystem/lessSpecificTypeForArgumentCallWithExactAnnotation.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("lessSpecificTypeForArgumentCallWithExactAnnotation_ni.kt")
|
||||
public void testLessSpecificTypeForArgumentCallWithExactAnnotation_ni() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/commonSystem/lessSpecificTypeForArgumentCallWithExactAnnotation_ni.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("nestedLambdas.kt")
|
||||
public void testNestedLambdas() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/commonSystem/nestedLambdas.kt");
|
||||
|
||||
Generated
+10
@@ -10013,6 +10013,16 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing
|
||||
runTest("compiler/testData/diagnostics/tests/inference/commonSystem/kt3372toCollection.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("lessSpecificTypeForArgumentCallWithExactAnnotation.kt")
|
||||
public void testLessSpecificTypeForArgumentCallWithExactAnnotation() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/commonSystem/lessSpecificTypeForArgumentCallWithExactAnnotation.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("lessSpecificTypeForArgumentCallWithExactAnnotation_ni.kt")
|
||||
public void testLessSpecificTypeForArgumentCallWithExactAnnotation_ni() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/commonSystem/lessSpecificTypeForArgumentCallWithExactAnnotation_ni.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("nestedLambdas.kt")
|
||||
public void testNestedLambdas() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/commonSystem/nestedLambdas.kt");
|
||||
|
||||
Reference in New Issue
Block a user