Report error on expression of nullable type in class literal
#KT-15740 Fixed
This commit is contained in:
@@ -631,6 +631,7 @@ public interface Errors {
|
|||||||
DiagnosticFactory0<KtExpression> CLASS_LITERAL_LHS_NOT_A_CLASS = DiagnosticFactory0.create(ERROR);
|
DiagnosticFactory0<KtExpression> CLASS_LITERAL_LHS_NOT_A_CLASS = DiagnosticFactory0.create(ERROR);
|
||||||
DiagnosticFactory0<KtExpression> ARRAY_CLASS_LITERAL_REQUIRES_ARGUMENT = DiagnosticFactory0.create(ERROR);
|
DiagnosticFactory0<KtExpression> ARRAY_CLASS_LITERAL_REQUIRES_ARGUMENT = DiagnosticFactory0.create(ERROR);
|
||||||
DiagnosticFactory0<KtExpression> NULLABLE_TYPE_IN_CLASS_LITERAL_LHS = DiagnosticFactory0.create(ERROR);
|
DiagnosticFactory0<KtExpression> NULLABLE_TYPE_IN_CLASS_LITERAL_LHS = DiagnosticFactory0.create(ERROR);
|
||||||
|
DiagnosticFactory1<KtExpression, KotlinType> EXPRESSION_OF_NULLABLE_TYPE_IN_CLASS_LITERAL_LHS = DiagnosticFactory1.create(ERROR);
|
||||||
|
|
||||||
// Destructuring-declarations
|
// Destructuring-declarations
|
||||||
|
|
||||||
|
|||||||
+1
@@ -880,6 +880,7 @@ public class DefaultErrorMessages {
|
|||||||
MAP.put(CLASS_LITERAL_LHS_NOT_A_CLASS, "Only classes are allowed on the left hand side of a class literal");
|
MAP.put(CLASS_LITERAL_LHS_NOT_A_CLASS, "Only classes are allowed on the left hand side of a class literal");
|
||||||
MAP.put(ARRAY_CLASS_LITERAL_REQUIRES_ARGUMENT, "Array class literal requires a type argument, please specify one in angle brackets");
|
MAP.put(ARRAY_CLASS_LITERAL_REQUIRES_ARGUMENT, "Array class literal requires a type argument, please specify one in angle brackets");
|
||||||
MAP.put(NULLABLE_TYPE_IN_CLASS_LITERAL_LHS, "Type in a class literal must not be nullable");
|
MAP.put(NULLABLE_TYPE_IN_CLASS_LITERAL_LHS, "Type in a class literal must not be nullable");
|
||||||
|
MAP.put(EXPRESSION_OF_NULLABLE_TYPE_IN_CLASS_LITERAL_LHS, "Expression in a class literal has a nullable type ''{0}'', use !! to make the type non-nullable", RENDER_TYPE);
|
||||||
|
|
||||||
//Inline
|
//Inline
|
||||||
MAP.put(NON_PUBLIC_CALL_FROM_PUBLIC_INLINE, "Public-API inline function cannot access non-public-API ''{0}''", SHORT_NAMES_IN_TYPES, SHORT_NAMES_IN_TYPES);
|
MAP.put(NON_PUBLIC_CALL_FROM_PUBLIC_INLINE, "Public-API inline function cannot access non-public-API ''{0}''", SHORT_NAMES_IN_TYPES, SHORT_NAMES_IN_TYPES);
|
||||||
|
|||||||
+4
-6
@@ -66,12 +66,10 @@ open class KotlinScriptDefinitionFromAnnotatedTemplate(
|
|||||||
private val acceptedAnnotations: List<KClass<out Annotation>> by lazy {
|
private val acceptedAnnotations: List<KClass<out Annotation>> by lazy {
|
||||||
val resolveMethod = ScriptDependenciesResolver::resolve
|
val resolveMethod = ScriptDependenciesResolver::resolve
|
||||||
val resolverMethodAnnotations =
|
val resolverMethodAnnotations =
|
||||||
resolver::class.memberFunctions.find {
|
resolver?.let { it::class }?.memberFunctions?.find { function ->
|
||||||
it.name == resolveMethod.name &&
|
function.name == resolveMethod.name &&
|
||||||
sameSignature(it, resolveMethod)
|
sameSignature(function, resolveMethod)
|
||||||
}
|
}?.annotations?.filterIsInstance<AcceptedAnnotations>()
|
||||||
?.annotations
|
|
||||||
?.filterIsInstance<AcceptedAnnotations>()
|
|
||||||
resolverMethodAnnotations?.flatMap {
|
resolverMethodAnnotations?.flatMap {
|
||||||
val v = it.supportedAnnotationClasses
|
val v = it.supportedAnnotationClasses
|
||||||
v.toList() // TODO: inline after KT-9453 is resolved (now it fails with "java.lang.Class cannot be cast to kotlin.reflect.KClass")
|
v.toList() // TODO: inline after KT-9453 is resolved (now it fails with "java.lang.Class cannot be cast to kotlin.reflect.KClass")
|
||||||
|
|||||||
+11
-2
@@ -50,6 +50,8 @@ import org.jetbrains.kotlin.resolve.source.toSourceElement
|
|||||||
import org.jetbrains.kotlin.types.*
|
import org.jetbrains.kotlin.types.*
|
||||||
import org.jetbrains.kotlin.types.TypeUtils.NO_EXPECTED_TYPE
|
import org.jetbrains.kotlin.types.TypeUtils.NO_EXPECTED_TYPE
|
||||||
import org.jetbrains.kotlin.types.expressions.typeInfoFactory.createTypeInfo
|
import org.jetbrains.kotlin.types.expressions.typeInfoFactory.createTypeInfo
|
||||||
|
import org.jetbrains.kotlin.types.typeUtil.builtIns
|
||||||
|
import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
|
||||||
import org.jetbrains.kotlin.types.typeUtil.makeNullable
|
import org.jetbrains.kotlin.types.typeUtil.makeNullable
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||||
import java.lang.UnsupportedOperationException
|
import java.lang.UnsupportedOperationException
|
||||||
@@ -105,12 +107,19 @@ class DoubleColonExpressionResolver(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun checkClassLiteral(c: ExpressionTypingContext, expression: KtClassLiteralExpression, result: DoubleColonLHS) {
|
private fun checkClassLiteral(c: ExpressionTypingContext, expression: KtClassLiteralExpression, result: DoubleColonLHS) {
|
||||||
|
val type = result.type
|
||||||
|
|
||||||
if (result is DoubleColonLHS.Expression) {
|
if (result is DoubleColonLHS.Expression) {
|
||||||
if (!result.isObject) reportUnsupportedIfNeeded(expression, c)
|
if (!result.isObject) {
|
||||||
|
if (!type.isSubtypeOf(type.builtIns.anyType)) {
|
||||||
|
c.trace.report(EXPRESSION_OF_NULLABLE_TYPE_IN_CLASS_LITERAL_LHS.on(expression.receiverExpression!!, type))
|
||||||
|
}
|
||||||
|
reportUnsupportedIfNeeded(expression, c)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
val type = (result as DoubleColonLHS.Type).type
|
result as DoubleColonLHS.Type
|
||||||
val descriptor = type.constructor.declarationDescriptor
|
val descriptor = type.constructor.declarationDescriptor
|
||||||
if (result.possiblyBareType.isBare) {
|
if (result.possiblyBareType.isBare) {
|
||||||
if (descriptor is ClassDescriptor && KotlinBuiltIns.isNonPrimitiveArray(descriptor)) {
|
if (descriptor is ClassDescriptor && KotlinBuiltIns.isNonPrimitiveArray(descriptor)) {
|
||||||
|
|||||||
+15
@@ -0,0 +1,15 @@
|
|||||||
|
// FILE: J.java
|
||||||
|
|
||||||
|
public interface J {
|
||||||
|
String platformString();
|
||||||
|
}
|
||||||
|
|
||||||
|
// FILE: test.kt
|
||||||
|
|
||||||
|
fun f1(x: Int?): Any = x::<!UNSAFE_CALL!>hashCode<!>
|
||||||
|
fun <T> f2(t: T): Any = t::<!UNSAFE_CALL!>hashCode<!>
|
||||||
|
fun <S : String?> f3(s: S): Any = s::<!UNSAFE_CALL!>hashCode<!>
|
||||||
|
fun <U : Any> f4(u: U?): Any = u::<!UNSAFE_CALL!>hashCode<!>
|
||||||
|
fun f5(c: List<*>): Any = c[0]::<!UNSAFE_CALL!>hashCode<!>
|
||||||
|
|
||||||
|
fun f6(j: J): Any = j.platformString()::hashCode
|
||||||
+16
@@ -0,0 +1,16 @@
|
|||||||
|
package
|
||||||
|
|
||||||
|
public /*synthesized*/ fun J(/*0*/ function: () -> kotlin.String!): J
|
||||||
|
public fun f1(/*0*/ x: kotlin.Int?): kotlin.Any
|
||||||
|
public fun </*0*/ T> f2(/*0*/ t: T): kotlin.Any
|
||||||
|
public fun </*0*/ S : kotlin.String?> f3(/*0*/ s: S): kotlin.Any
|
||||||
|
public fun </*0*/ U : kotlin.Any> f4(/*0*/ u: U?): kotlin.Any
|
||||||
|
public fun f5(/*0*/ c: kotlin.collections.List<*>): kotlin.Any
|
||||||
|
public fun f6(/*0*/ j: J): kotlin.Any
|
||||||
|
|
||||||
|
public interface J {
|
||||||
|
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 abstract fun platformString(): kotlin.String!
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
+2
-2
@@ -23,8 +23,8 @@ class Test {
|
|||||||
fun <T> List<T>.testCallable4(): () -> Unit = <!RESERVED_SYNTAX_IN_CALLABLE_REFERENCE_LHS!>b<T><!>?::<!UNSAFE_CALL!>foo<!>
|
fun <T> List<T>.testCallable4(): () -> Unit = <!RESERVED_SYNTAX_IN_CALLABLE_REFERENCE_LHS!>b<T><!>?::<!UNSAFE_CALL!>foo<!>
|
||||||
|
|
||||||
fun <T> List<T>.testClassLiteral1() = <!RESERVED_SYNTAX_IN_CALLABLE_REFERENCE_LHS!>a<T><!>::class
|
fun <T> List<T>.testClassLiteral1() = <!RESERVED_SYNTAX_IN_CALLABLE_REFERENCE_LHS!>a<T><!>::class
|
||||||
fun <T> List<T>.<!KCLASS_WITH_NULLABLE_ARGUMENT_IN_SIGNATURE!>testClassLiteral2<!>() = <!RESERVED_SYNTAX_IN_CALLABLE_REFERENCE_LHS!>b<!>?::class
|
fun <T> List<T>.<!KCLASS_WITH_NULLABLE_ARGUMENT_IN_SIGNATURE!>testClassLiteral2<!>() = <!RESERVED_SYNTAX_IN_CALLABLE_REFERENCE_LHS, EXPRESSION_OF_NULLABLE_TYPE_IN_CLASS_LITERAL_LHS!>b<!>?::class
|
||||||
fun <T> List<T>.<!KCLASS_WITH_NULLABLE_ARGUMENT_IN_SIGNATURE!>testClassLiteral3<!>() = <!RESERVED_SYNTAX_IN_CALLABLE_REFERENCE_LHS!>b<T, Any><!>::class
|
fun <T> List<T>.<!KCLASS_WITH_NULLABLE_ARGUMENT_IN_SIGNATURE!>testClassLiteral3<!>() = <!RESERVED_SYNTAX_IN_CALLABLE_REFERENCE_LHS, EXPRESSION_OF_NULLABLE_TYPE_IN_CLASS_LITERAL_LHS!>b<T, Any><!>::class
|
||||||
|
|
||||||
fun <T> List<T>.testUnresolved1() = <!UNRESOLVED_REFERENCE!>unresolved<!><T>::<!UNRESOLVED_REFERENCE_WRONG_RECEIVER!>foo<!>
|
fun <T> List<T>.testUnresolved1() = <!UNRESOLVED_REFERENCE!>unresolved<!><T>::<!UNRESOLVED_REFERENCE_WRONG_RECEIVER!>foo<!>
|
||||||
fun <T> List<T>.testUnresolved2() = <!RESERVED_SYNTAX_IN_CALLABLE_REFERENCE_LHS!>a<<!UNRESOLVED_REFERENCE!>unresolved<!>><!>::foo
|
fun <T> List<T>.testUnresolved2() = <!RESERVED_SYNTAX_IN_CALLABLE_REFERENCE_LHS!>a<<!UNRESOLVED_REFERENCE!>unresolved<!>><!>::foo
|
||||||
|
|||||||
+15
@@ -0,0 +1,15 @@
|
|||||||
|
// FILE: J.java
|
||||||
|
|
||||||
|
public interface J {
|
||||||
|
String platformString();
|
||||||
|
}
|
||||||
|
|
||||||
|
// FILE: test.kt
|
||||||
|
|
||||||
|
fun f1(x: Int?): Any = <!EXPRESSION_OF_NULLABLE_TYPE_IN_CLASS_LITERAL_LHS!>x<!>::class
|
||||||
|
fun <T> f2(t: T): Any = <!EXPRESSION_OF_NULLABLE_TYPE_IN_CLASS_LITERAL_LHS!>t<!>::class
|
||||||
|
fun <S : String?> f3(s: S): Any = <!EXPRESSION_OF_NULLABLE_TYPE_IN_CLASS_LITERAL_LHS!>s<!>::class
|
||||||
|
fun <U : Any> f4(u: U?): Any = <!EXPRESSION_OF_NULLABLE_TYPE_IN_CLASS_LITERAL_LHS!>u<!>::class
|
||||||
|
fun f5(c: List<*>): Any = <!EXPRESSION_OF_NULLABLE_TYPE_IN_CLASS_LITERAL_LHS!>c[0]<!>::class
|
||||||
|
|
||||||
|
fun f6(j: J): Any = j.platformString()::class
|
||||||
+16
@@ -0,0 +1,16 @@
|
|||||||
|
package
|
||||||
|
|
||||||
|
public /*synthesized*/ fun J(/*0*/ function: () -> kotlin.String!): J
|
||||||
|
public fun f1(/*0*/ x: kotlin.Int?): kotlin.Any
|
||||||
|
public fun </*0*/ T> f2(/*0*/ t: T): kotlin.Any
|
||||||
|
public fun </*0*/ S : kotlin.String?> f3(/*0*/ s: S): kotlin.Any
|
||||||
|
public fun </*0*/ U : kotlin.Any> f4(/*0*/ u: U?): kotlin.Any
|
||||||
|
public fun f5(/*0*/ c: kotlin.collections.List<*>): kotlin.Any
|
||||||
|
public fun f6(/*0*/ j: J): kotlin.Any
|
||||||
|
|
||||||
|
public interface J {
|
||||||
|
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 abstract fun platformString(): kotlin.String!
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
@@ -1818,6 +1818,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("expressionWithNullableType.kt")
|
||||||
|
public void testExpressionWithNullableType() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/callableReference/bound/expressionWithNullableType.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("functionCallWithoutArguments.kt")
|
@TestMetadata("functionCallWithoutArguments.kt")
|
||||||
public void testFunctionCallWithoutArguments() throws Exception {
|
public void testFunctionCallWithoutArguments() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/callableReference/bound/functionCallWithoutArguments.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/callableReference/bound/functionCallWithoutArguments.kt");
|
||||||
@@ -3022,6 +3028,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("expressionWithNullableType.kt")
|
||||||
|
public void testExpressionWithNullableType() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/classLiteral/expressionWithNullableType.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("genericArrays.kt")
|
@TestMetadata("genericArrays.kt")
|
||||||
public void testGenericArrays() throws Exception {
|
public void testGenericArrays() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/classLiteral/genericArrays.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/classLiteral/genericArrays.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user