KT-9883 prohibit using spread operator for nullable value
#KT-9883 Fixed
This commit is contained in:
@@ -448,6 +448,7 @@ public interface Errors {
|
||||
|
||||
DiagnosticFactory0<KtExpression> VARARG_OUTSIDE_PARENTHESES = DiagnosticFactory0.create(ERROR);
|
||||
DiagnosticFactory0<LeafPsiElement> NON_VARARG_SPREAD = DiagnosticFactory0.create(ERROR);
|
||||
DiagnosticFactory0<LeafPsiElement> SPREAD_OF_NULLABLE = DiagnosticFactory0.create(ERROR);
|
||||
|
||||
DiagnosticFactory0<KtExpression> MANY_FUNCTION_LITERAL_ARGUMENTS = DiagnosticFactory0.create(ERROR);
|
||||
|
||||
|
||||
+1
@@ -185,6 +185,7 @@ public class DefaultErrorMessages {
|
||||
|
||||
MAP.put(VARARG_OUTSIDE_PARENTHESES, "Passing value as a vararg is only allowed inside a parenthesized argument list");
|
||||
MAP.put(NON_VARARG_SPREAD, "The spread operator (*foo) may only be applied in a vararg position");
|
||||
MAP.put(SPREAD_OF_NULLABLE, "The spread operator (*foo) may not be applied to an argument of nullable type");
|
||||
|
||||
MAP.put(MANY_FUNCTION_LITERAL_ARGUMENTS, "Only one function literal is allowed outside a parenthesized argument list");
|
||||
MAP.put(PROPERTY_WITH_NO_TYPE_NO_INITIALIZER, "This property must either have a type annotation, be initialized or be delegated");
|
||||
|
||||
@@ -21,6 +21,7 @@ import com.google.common.collect.Sets
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.builtins.ReflectionTypes
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.diagnostics.Errors.SUPER_CANT_BE_EXTENSION_RECEIVER
|
||||
import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
@@ -349,6 +350,15 @@ public class CandidateResolver(
|
||||
else if (ErrorUtils.containsUninferredParameter(expectedType)) {
|
||||
matchStatus = ArgumentMatchStatus.MATCH_MODULO_UNINFERRED_TYPES
|
||||
}
|
||||
|
||||
val spreadElement = argument.getSpreadElement()
|
||||
if (spreadElement != null && !type.isFlexible() && type.isMarkedNullable) {
|
||||
val dataFlowValue = DataFlowValueFactory.createDataFlowValue(expression, type, context)
|
||||
val smartCastResult = SmartCastManager.checkAndRecordPossibleCast(dataFlowValue, expectedType, expression, context, null, false)
|
||||
if (smartCastResult == null || !smartCastResult.isCorrect) {
|
||||
context.trace.report(Errors.SPREAD_OF_NULLABLE.on(spreadElement));
|
||||
}
|
||||
}
|
||||
}
|
||||
argumentTypes.add(resultingType)
|
||||
candidateCall.recordArgumentMatchStatus(argument, matchStatus)
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
public class A {
|
||||
public int foo(int x, String ... args) {
|
||||
return x + args.length;
|
||||
}
|
||||
|
||||
public static String[] ar = new String[] { "a", "b"};
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
fun bar(args: Array<String>?): Int {
|
||||
var res = 0
|
||||
|
||||
if (args != null) {
|
||||
res += A().foo(1, *args)
|
||||
}
|
||||
|
||||
res += A().foo(1, *A.ar)
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
if (bar(null) != 3) return "Fail"
|
||||
|
||||
if (bar(A.ar) != 6) return "Fail"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
// !DIAGNOSTICS:-UNUSED_PARAMETER
|
||||
|
||||
// KT-9883 prohibit using spread operator for nullable value
|
||||
|
||||
// FILE: A.java
|
||||
|
||||
public class A {
|
||||
public void foo(int x, String ... args) {}
|
||||
public static String[] ar;
|
||||
}
|
||||
|
||||
|
||||
// FILE: 1.kt
|
||||
val args: Array<String>? = null
|
||||
|
||||
fun bar(x: Int, vararg s: String) {}
|
||||
|
||||
fun baz(s: String) {}
|
||||
|
||||
fun f() {
|
||||
A().foo(1, <!SPREAD_OF_NULLABLE!>*<!>args)
|
||||
bar(2, <!SPREAD_OF_NULLABLE!>*<!><!TYPE_MISMATCH!>args<!>)
|
||||
baz(<!NON_VARARG_SPREAD, SPREAD_OF_NULLABLE!>*<!>args)
|
||||
}
|
||||
|
||||
fun g(args: Array<String>?) {
|
||||
|
||||
if (args != null) {
|
||||
A().foo(1, *<!DEBUG_INFO_SMARTCAST!>args<!>)
|
||||
}
|
||||
A().foo(1, *A.ar)
|
||||
}
|
||||
|
||||
class B {
|
||||
var args: Array<String>? = null
|
||||
}
|
||||
|
||||
fun h(b: B) {
|
||||
if (b.args != null) {
|
||||
A().foo(1, <!SPREAD_OF_NULLABLE!>*<!><!SMARTCAST_IMPOSSIBLE!>b.args<!>)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
package
|
||||
|
||||
public val args: kotlin.Array<kotlin.String>? = null
|
||||
public fun bar(/*0*/ x: kotlin.Int, /*1*/ vararg s: kotlin.String /*kotlin.Array<out kotlin.String>*/): kotlin.Unit
|
||||
public fun baz(/*0*/ s: kotlin.String): kotlin.Unit
|
||||
public fun f(): kotlin.Unit
|
||||
public fun g(/*0*/ args: kotlin.Array<kotlin.String>?): kotlin.Unit
|
||||
public fun h(/*0*/ b: B): kotlin.Unit
|
||||
|
||||
public open class A {
|
||||
public constructor A()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open fun foo(/*0*/ x: kotlin.Int, /*1*/ vararg args: kotlin.String! /*kotlin.Array<(out) kotlin.String!>!*/): kotlin.Unit
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
|
||||
// Static members
|
||||
public final var ar: kotlin.Array<(out) kotlin.String!>!
|
||||
}
|
||||
|
||||
public final class B {
|
||||
public constructor B()
|
||||
public final var args: kotlin.Array<kotlin.String>?
|
||||
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
|
||||
}
|
||||
@@ -16995,6 +16995,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("NullableTypeForVarargArgument.kt")
|
||||
public void testNullableTypeForVarargArgument() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/varargs/NullableTypeForVarargArgument.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("UnaryVsVararg.kt")
|
||||
public void testUnaryVsVararg() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/varargs/UnaryVsVararg.kt");
|
||||
|
||||
+7
@@ -119,6 +119,12 @@ public class BlackBoxWithJavaCodegenTestGenerated extends AbstractBlackBoxCodege
|
||||
doTestWithJava(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("varargs")
|
||||
public void testVarargs() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxWithJava/varargs/");
|
||||
doTestWithJava(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/boxWithJava/annotatedFileClasses")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
@@ -722,4 +728,5 @@ public class BlackBoxWithJavaCodegenTestGenerated extends AbstractBlackBoxCodege
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user