Skip to content

Commit 7a9e1b2

Browse files
committed
Improve diagnostic on overload resolution ambiguity
Report type mismatch on argument when a nullable argument is passed to non-null parameter. Note that this affects only functions with simple types without generics #KT-2007 Fixed #KT-9282 Fixed
1 parent 16de991 commit 7a9e1b2

File tree

11 files changed

+82
-11
lines changed

11 files changed

+82
-11
lines changed

compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CandidateResolver.kt

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ import org.jetbrains.kotlin.types.checker.ErrorTypesAreEqualToAnything
5353
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
5454
import org.jetbrains.kotlin.types.expressions.DoubleColonExpressionResolver
5555
import org.jetbrains.kotlin.types.typeUtil.containsTypeProjectionsInTopLevelArguments
56+
import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
5657
import java.util.*
5758

5859
class CandidateResolver(
@@ -376,7 +377,7 @@ class CandidateResolver(
376377
if (!ArgumentTypeResolver.isSubtypeOfForArgumentType(type, expectedType)) {
377378
val smartCast = smartCastValueArgumentTypeIfPossible(expression, newContext.expectedType, type, newContext)
378379
if (smartCast == null) {
379-
resultStatus = OTHER_ERROR
380+
resultStatus = tryNotNullableArgument(type, expectedType) ?: OTHER_ERROR
380381
matchStatus = ArgumentMatchStatus.TYPE_MISMATCH
381382
}
382383
else {
@@ -417,6 +418,14 @@ class CandidateResolver(
417418
}
418419
}
419420

421+
private fun tryNotNullableArgument(argumentType: KotlinType, parameterType: KotlinType): ResolutionStatus? {
422+
if (!argumentType.isMarkedNullable || parameterType.isMarkedNullable) return null
423+
424+
val notNullableArgumentType = argumentType.makeNotNullable()
425+
val isApplicable = ArgumentTypeResolver.isSubtypeOfForArgumentType(notNullableArgumentType, parameterType)
426+
return if (isApplicable) NULLABLE_ARGUMENT_TYPE_MISMATCH else null
427+
}
428+
420429
private fun CallCandidateResolutionContext<*>.checkReceiverTypeError(): Unit = check {
421430
val extensionReceiver = candidateDescriptor.extensionReceiverParameter
422431
val dispatchReceiver = candidateDescriptor.dispatchReceiverParameter

compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/results/ResolutionStatus.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ public enum ResolutionStatus {
2626
WRONG_NUMBER_OF_TYPE_ARGUMENTS_ERROR,
2727
UNSTABLE_SMARTCAST_ERROR,
2828
INVISIBLE_MEMBER_ERROR,
29+
NULLABLE_ARGUMENT_TYPE_MISMATCH,
2930
OTHER_ERROR,
3031
ARGUMENTS_MAPPING_ERROR,
3132
// '1.foo()' shouldn't be resolved to 'fun String.foo()'
@@ -44,6 +45,7 @@ public enum ResolutionStatus {
4445
EnumSet.of(WRONG_NUMBER_OF_TYPE_ARGUMENTS_ERROR),
4546
EnumSet.of(UNSTABLE_SMARTCAST_ERROR),
4647
EnumSet.of(INVISIBLE_MEMBER_ERROR),
48+
EnumSet.of(NULLABLE_ARGUMENT_TYPE_MISMATCH),
4749
EnumSet.of(OTHER_ERROR),
4850
EnumSet.of(ARGUMENTS_MAPPING_ERROR),
4951
EnumSet.of(RECEIVER_TYPE_ERROR),
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// FILE: J.java
2+
3+
import org.jetbrains.annotations.*;
4+
5+
public class J {
6+
void foo(String x) {}
7+
void foo(@NotNull Double x) {}
8+
void foo(@Nullable Byte x) {}
9+
}
10+
11+
// FILE: test.kt
12+
13+
fun test(j: J, nullStr: String?, nullByte: Byte?, nullDouble: Double?) {
14+
j.foo(nullStr)
15+
j.foo(<!TYPE_MISMATCH!>nullDouble<!>)
16+
j.foo(nullByte)
17+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package
2+
3+
public fun test(/*0*/ j: J, /*1*/ nullStr: kotlin.String?, /*2*/ nullByte: kotlin.Byte?, /*3*/ nullDouble: kotlin.Double?): kotlin.Unit
4+
5+
public open class J {
6+
public constructor J()
7+
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
8+
public/*package*/ open fun foo(/*0*/ @org.jetbrains.annotations.Nullable x: kotlin.Byte?): kotlin.Unit
9+
public/*package*/ open fun foo(/*0*/ @org.jetbrains.annotations.NotNull x: kotlin.Double): kotlin.Unit
10+
public/*package*/ open fun foo(/*0*/ x: kotlin.String!): kotlin.Unit
11+
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
12+
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
13+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// !DIAGNOSTICS: -UNUSED_PARAMETER
2+
3+
fun foo(x: String) {}
4+
fun foo(x: Int) {}
5+
fun foo(x: Int, y: String) {}
6+
7+
fun bar(nullX: Int?, nullY: String?, notNullY: String) {
8+
foo(<!TYPE_MISMATCH!>nullX<!>)
9+
foo(<!TYPE_MISMATCH!>nullX<!>, notNullY)
10+
foo(<!TYPE_MISMATCH!>nullX<!>, <!TYPE_MISMATCH!>nullY<!>)
11+
<!NONE_APPLICABLE!>foo<!>()
12+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package
2+
3+
public fun bar(/*0*/ nullX: kotlin.Int?, /*1*/ nullY: kotlin.String?, /*2*/ notNullY: kotlin.String): kotlin.Unit
4+
public fun foo(/*0*/ x: kotlin.Int): kotlin.Unit
5+
public fun foo(/*0*/ x: kotlin.Int, /*1*/ y: kotlin.String): kotlin.Unit
6+
public fun foo(/*0*/ x: kotlin.String): kotlin.Unit

compiler/testData/diagnostics/tests/platformTypes/nullabilityWarnings/arithmetic.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,15 +33,15 @@ fun test() {
3333
platformJ++
3434

3535
1 + platformNN
36-
1 <!NONE_APPLICABLE!>+<!> platformN
36+
1 + <!TYPE_MISMATCH!>platformN<!>
3737
1 + platformJ
3838

3939
platformNN + 1
4040
platformN <!UNSAFE_OPERATOR_CALL!>+<!> 1
4141
platformJ + 1
4242

4343
1 <!INFIX_MODIFIER_REQUIRED!>plus<!> platformNN
44-
1 <!NONE_APPLICABLE!>plus<!> platformN
44+
1 <!INFIX_MODIFIER_REQUIRED!>plus<!> <!TYPE_MISMATCH!>platformN<!>
4545
1 <!INFIX_MODIFIER_REQUIRED!>plus<!> platformJ
4646

4747
platformNN <!INFIX_MODIFIER_REQUIRED!>plus<!> 1

compiler/testData/diagnostics/tests/smartCasts/varnotnull/plusplusMinusminus.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ fun bar(arg: Long?): Long {
1414
return i<!UNSAFE_CALL!>--<!> <!DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>+<!> i
1515
}
1616
if (i++ == 7L) {
17-
return i++ <!NONE_APPLICABLE!>+<!> i
17+
return i++ <!UNSAFE_OPERATOR_CALL!>+<!> <!TYPE_MISMATCH!>i<!>
1818
}
1919
return 0L
2020
}

compiler/testData/diagnostics/tests/syntheticExtensions/samAdapters/ParameterTypeAnnotation.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// FILE: KotlinFile.kt
22
fun foo(javaInterface: JavaInterface) {
3-
javaInterface.doIt(<!NULL_FOR_NONNULL_TYPE!>null<!>) <!TYPE_MISMATCH!>{ }<!>
3+
javaInterface.doIt(<!NULL_FOR_NONNULL_TYPE!>null<!>) { }
44
javaInterface.doIt("", <!NULL_FOR_NONNULL_TYPE!>null<!>)
55
}
66

compiler/testData/resolvedCalls/enhancedSignatures/map/mapMerge.txt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ fun valuesNullable(map: MutableMap<Int, String?>) {
1111
// ORIGINAL: fun merge(K, V, (V, V) -> V?): V? defined in kotlin.collections.MutableMap
1212
// SUBSTITUTED: fun merge(Int, String, (String, String) -> String?): String? defined in kotlin.collections.MutableMap
1313
map.merge(1, null) { old, new -> old + new }
14-
// OTHER_ERROR
15-
// ORIGINAL: fun merge(K, V, BiFunction<in V, in V, out V?>): V? defined in kotlin.collections.MutableMap
16-
// SUBSTITUTED: fun merge(Int, String, BiFunction<in String, in String, out String?>): String? defined in kotlin.collections.MutableMap
14+
// NULLABLE_ARGUMENT_TYPE_MISMATCH
15+
// ORIGINAL: fun merge(K, V, (V, V) -> V?): V? defined in kotlin.collections.MutableMap
16+
// SUBSTITUTED: fun merge(Int, String, (String, String) -> String?): String? defined in kotlin.collections.MutableMap
1717
}
1818

1919
fun <T> valuesT(map: MutableMap<Int, T>, newValue: T) {
@@ -32,9 +32,9 @@ fun <T : Any> valuesTNotNull(map: MutableMap<Int, T>, newValue: T) {
3232

3333
fun <T : Any> valuesTNullable(map: MutableMap<Int, T?>, newValue: T?) {
3434
map.merge(1, newValue) { old, new -> new }
35-
// OTHER_ERROR
36-
// ORIGINAL: fun merge(K, V, BiFunction<in V, in V, out V?>): V? defined in kotlin.collections.MutableMap
37-
// SUBSTITUTED: fun merge(Int, T, BiFunction<in T, in T, out T?>): T? defined in kotlin.collections.MutableMap
35+
// NULLABLE_ARGUMENT_TYPE_MISMATCH
36+
// ORIGINAL: fun merge(K, V, (V, V) -> V?): V? defined in kotlin.collections.MutableMap
37+
// SUBSTITUTED: fun merge(Int, T, (T, T) -> T?): T? defined in kotlin.collections.MutableMap
3838
map.merge(1, newValue!!) { old, new -> new }
3939
// SUCCESS
4040
// ORIGINAL: fun merge(K, V, (V, V) -> V?): V? defined in kotlin.collections.MutableMap

compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14011,6 +14011,18 @@ public void testNullableArgumentForIn() throws Exception {
1401114011
doTest(fileName);
1401214012
}
1401314013

14014+
@TestMetadata("nullableArgumentToNonNullParameterPlatform.kt")
14015+
public void testNullableArgumentToNonNullParameterPlatform() throws Exception {
14016+
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/nullableTypes/nullableArgumentToNonNullParameterPlatform.kt");
14017+
doTest(fileName);
14018+
}
14019+
14020+
@TestMetadata("nullableArgumentToNonNullParameterSimple.kt")
14021+
public void testNullableArgumentToNonNullParameterSimple() throws Exception {
14022+
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/nullableTypes/nullableArgumentToNonNullParameterSimple.kt");
14023+
doTest(fileName);
14024+
}
14025+
1401414026
@TestMetadata("redundantNullable.kt")
1401514027
public void testRedundantNullable() throws Exception {
1401614028
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/nullableTypes/redundantNullable.kt");

0 commit comments

Comments
 (0)