From 60d56b30bf9e7d967105a64004cd90178e169afa Mon Sep 17 00:00:00 2001 From: Mikhail Glukhikh Date: Mon, 1 Feb 2016 16:07:39 +0300 Subject: [PATCH] Safe call arguments are now handled as nullable in generic resolver #KT-9985 Fixed --- .../resolve/calls/GenericCandidateResolver.kt | 24 +++++++---- .../diagnostics/tests/generics/kt9985.kt | 42 +++++++++++++++++++ .../diagnostics/tests/generics/kt9985.txt | 27 ++++++++++++ .../diagnostics/testsWithStdLib/kt9985.kt | 3 ++ .../diagnostics/testsWithStdLib/kt9985.txt | 3 ++ .../checkers/DiagnosticsTestGenerated.java | 6 +++ .../DiagnosticsTestWithStdLibGenerated.java | 6 +++ 7 files changed, 103 insertions(+), 8 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/generics/kt9985.kt create mode 100644 compiler/testData/diagnostics/tests/generics/kt9985.txt create mode 100644 compiler/testData/diagnostics/testsWithStdLib/kt9985.kt create mode 100644 compiler/testData/diagnostics/testsWithStdLib/kt9985.txt diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/GenericCandidateResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/GenericCandidateResolver.kt index 32b81339f41..1a89b9fe151 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/GenericCandidateResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/GenericCandidateResolver.kt @@ -36,6 +36,7 @@ import org.jetbrains.kotlin.resolve.calls.inference.* import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPosition import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.RECEIVER_POSITION import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.VALUE_PARAMETER_POSITION +import org.jetbrains.kotlin.resolve.calls.resolvedCallUtil.getExplicitReceiverValue import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus.INCOMPLETE_TYPE_INFERENCE import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus.OTHER_ERROR @@ -154,28 +155,35 @@ class GenericCandidateResolver(private val argumentTypeResolver: ArgumentTypeRes val resolutionResults = getResolutionResultsCachedData(argumentExpression, context)?.resolutionResults if (resolutionResults == null || !resolutionResults.isSingleResult) return false - val resultingCall = resolutionResults.resultingCall - if (resultingCall.isCompleted) return false + val nestedCall = resolutionResults.resultingCall + if (nestedCall.isCompleted) return false - val argumentConstraintSystem = resultingCall.constraintSystem ?: return false + val nestedConstraintSystem = nestedCall.constraintSystem ?: return false - val candidateDescriptor = resultingCall.candidateDescriptor + val candidateDescriptor = nestedCall.candidateDescriptor val returnType = candidateDescriptor.returnType ?: return false - val nestedTypeVariables = argumentConstraintSystem.getNestedTypeVariables(returnType) + val nestedTypeVariables = nestedConstraintSystem.getNestedTypeVariables(returnType) // we add an additional type variable only if no information is inferred for it. // otherwise we add currently inferred return type as before - if (nestedTypeVariables.any { argumentConstraintSystem.getTypeBounds(it).bounds.isNotEmpty() }) return false + if (nestedTypeVariables.any { nestedConstraintSystem.getTypeBounds(it).bounds.isNotEmpty() }) return false val candidateWithFreshVariables = FunctionDescriptorUtil.alphaConvertTypeParameters(candidateDescriptor) val conversion = candidateDescriptor.typeParameters.zip(candidateWithFreshVariables.typeParameters).toMap() val freshVariables = returnType.getNestedTypeParameters().mapNotNull { conversion[it] } - builder.registerTypeVariables(resultingCall.call.toHandle(), freshVariables, external = true) + builder.registerTypeVariables(nestedCall.call.toHandle(), freshVariables, external = true) + // Looks not too nice, but safe call result must be nullable if receiver is nullable + val argumentExpressionType = candidateWithFreshVariables.returnType?.let { + if (nestedCall.isSafeCall && nestedCall.getExplicitReceiverValue()?.type?.let {TypeUtils.isNullableType(it) } ?: true ) { + TypeUtils.makeNullable(it) + } + else it + } builder.addSubtypeConstraint( - candidateWithFreshVariables.returnType, + argumentExpressionType, builder.compositeSubstitutor().substitute(effectiveExpectedType, Variance.INVARIANT), constraintPosition ) diff --git a/compiler/testData/diagnostics/tests/generics/kt9985.kt b/compiler/testData/diagnostics/tests/generics/kt9985.kt new file mode 100644 index 00000000000..db1b604f0f3 --- /dev/null +++ b/compiler/testData/diagnostics/tests/generics/kt9985.kt @@ -0,0 +1,42 @@ +// !CHECK_TYPE +// Incorrect "type mismatch" error for generic extension safe call (required not-null, found nullable) + +// FILE: B.java + +public class B { + public String gav() { + return "" + } + + public static B create() { + return new B(); + } +} + +// FILE: A.kt + +class A { + fun gav() = "" +} +fun foo(x: R) = x +fun A.bar() = "" +fun B.bar() = "" + +fun foo(l: A?) { + // No errors should be here + foo(l?.bar()) checkType { _() } + foo(l?.gav()) checkType { _() } +} + +fun fooNotNull(l: A) { + // No errors should be here + foo(l?.bar()) checkType { _() } + foo(l?.gav()) checkType { _() } +} + +fun bar() { + val l = B.create() + foo(l?.bar()) checkType { _() } + foo(l?.gav()) checkType { _() } +} + diff --git a/compiler/testData/diagnostics/tests/generics/kt9985.txt b/compiler/testData/diagnostics/tests/generics/kt9985.txt new file mode 100644 index 00000000000..fa8a5d087a6 --- /dev/null +++ b/compiler/testData/diagnostics/tests/generics/kt9985.txt @@ -0,0 +1,27 @@ +package + +public fun bar(): kotlin.Unit +public fun foo(/*0*/ l: A?): kotlin.Unit +public fun foo(/*0*/ x: R): R +public fun fooNotNull(/*0*/ l: A): kotlin.Unit +public fun A.bar(): kotlin.String +public fun B.bar(): kotlin.String + +public final class A { + public constructor A() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public final fun gav(): kotlin.String + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public open class B { + public constructor B() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open fun gav(): kotlin.String! + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + // Static members + public open fun create(): B! +} diff --git a/compiler/testData/diagnostics/testsWithStdLib/kt9985.kt b/compiler/testData/diagnostics/testsWithStdLib/kt9985.kt new file mode 100644 index 00000000000..a99da78ab1c --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/kt9985.kt @@ -0,0 +1,3 @@ +fun foo(l: List?) { + Pair(l?.joinToString(), "") +} diff --git a/compiler/testData/diagnostics/testsWithStdLib/kt9985.txt b/compiler/testData/diagnostics/testsWithStdLib/kt9985.txt new file mode 100644 index 00000000000..15942d2bbf4 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/kt9985.txt @@ -0,0 +1,3 @@ +package + +public fun foo(/*0*/ l: kotlin.collections.List?): kotlin.Unit diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index a589334f54d..77f52d18456 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -6867,6 +6867,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { doTest(fileName); } + @TestMetadata("kt9985.kt") + public void testKt9985() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/generics/kt9985.kt"); + doTest(fileName); + } + @TestMetadata("Projections.kt") public void testProjections() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/generics/Projections.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java index e717bb527a0..46f61d02666 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java @@ -101,6 +101,12 @@ public class DiagnosticsTestWithStdLibGenerated extends AbstractDiagnosticsTestW doTest(fileName); } + @TestMetadata("kt9985.kt") + public void testKt9985() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/kt9985.kt"); + doTest(fileName); + } + @TestMetadata("outstar.kt") public void testOutstar() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/outstar.kt");