[FIR] Prohibit class literals with empty left-hand side
^KT-59165 Fixed
This commit is contained in:
committed by
Space Team
parent
d748fe7696
commit
713c2136cc
+6
@@ -2440,6 +2440,12 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
|
|||||||
token,
|
token,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
add(FirErrors.UNSUPPORTED_CLASS_LITERALS_WITH_EMPTY_LHS) { firDiagnostic ->
|
||||||
|
UnsupportedClassLiteralsWithEmptyLhsImpl(
|
||||||
|
firDiagnostic as KtPsiDiagnostic,
|
||||||
|
token,
|
||||||
|
)
|
||||||
|
}
|
||||||
add(FirErrors.NOTHING_TO_OVERRIDE) { firDiagnostic ->
|
add(FirErrors.NOTHING_TO_OVERRIDE) { firDiagnostic ->
|
||||||
NothingToOverrideImpl(
|
NothingToOverrideImpl(
|
||||||
firSymbolBuilder.callableBuilder.buildCallableSymbol(firDiagnostic.a),
|
firSymbolBuilder.callableBuilder.buildCallableSymbol(firDiagnostic.a),
|
||||||
|
|||||||
+4
@@ -1730,6 +1730,10 @@ sealed interface KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
|
|||||||
val lhsType: KtType
|
val lhsType: KtType
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface UnsupportedClassLiteralsWithEmptyLhs : KtFirDiagnostic<KtElement> {
|
||||||
|
override val diagnosticClass get() = UnsupportedClassLiteralsWithEmptyLhs::class
|
||||||
|
}
|
||||||
|
|
||||||
interface NothingToOverride : KtFirDiagnostic<KtModifierListOwner> {
|
interface NothingToOverride : KtFirDiagnostic<KtModifierListOwner> {
|
||||||
override val diagnosticClass get() = NothingToOverride::class
|
override val diagnosticClass get() = NothingToOverride::class
|
||||||
val declaration: KtCallableSymbol
|
val declaration: KtCallableSymbol
|
||||||
|
|||||||
+5
@@ -2080,6 +2080,11 @@ internal class ExpressionOfNullableTypeInClassLiteralLhsImpl(
|
|||||||
token: KtLifetimeToken,
|
token: KtLifetimeToken,
|
||||||
) : KtAbstractFirDiagnostic<PsiElement>(firDiagnostic, token), KtFirDiagnostic.ExpressionOfNullableTypeInClassLiteralLhs
|
) : KtAbstractFirDiagnostic<PsiElement>(firDiagnostic, token), KtFirDiagnostic.ExpressionOfNullableTypeInClassLiteralLhs
|
||||||
|
|
||||||
|
internal class UnsupportedClassLiteralsWithEmptyLhsImpl(
|
||||||
|
firDiagnostic: KtPsiDiagnostic,
|
||||||
|
token: KtLifetimeToken,
|
||||||
|
) : KtAbstractFirDiagnostic<KtElement>(firDiagnostic, token), KtFirDiagnostic.UnsupportedClassLiteralsWithEmptyLhs
|
||||||
|
|
||||||
internal class NothingToOverrideImpl(
|
internal class NothingToOverrideImpl(
|
||||||
override val declaration: KtCallableSymbol,
|
override val declaration: KtCallableSymbol,
|
||||||
firDiagnostic: KtPsiDiagnostic,
|
firDiagnostic: KtPsiDiagnostic,
|
||||||
|
|||||||
+6
@@ -297,6 +297,12 @@ public class DiagnosticCompilerTestFE10TestdataTestGenerated extends AbstractDia
|
|||||||
runTest("compiler/testData/diagnostics/tests/Dollar.kt");
|
runTest("compiler/testData/diagnostics/tests/Dollar.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("emptyLhsClassLiterals.kt")
|
||||||
|
public void testEmptyLhsClassLiterals() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/emptyLhsClassLiterals.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("EnumEntryAsType.kt")
|
@TestMetadata("EnumEntryAsType.kt")
|
||||||
public void testEnumEntryAsType() throws Exception {
|
public void testEnumEntryAsType() throws Exception {
|
||||||
|
|||||||
+6
@@ -297,6 +297,12 @@ public class LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated
|
|||||||
runTest("compiler/testData/diagnostics/tests/Dollar.kt");
|
runTest("compiler/testData/diagnostics/tests/Dollar.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("emptyLhsClassLiterals.kt")
|
||||||
|
public void testEmptyLhsClassLiterals() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/emptyLhsClassLiterals.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("EnumEntryAsType.kt")
|
@TestMetadata("EnumEntryAsType.kt")
|
||||||
public void testEnumEntryAsType() throws Exception {
|
public void testEnumEntryAsType() throws Exception {
|
||||||
|
|||||||
+6
@@ -297,6 +297,12 @@ public class FirLightTreeOldFrontendDiagnosticsTestGenerated extends AbstractFir
|
|||||||
runTest("compiler/testData/diagnostics/tests/Dollar.kt");
|
runTest("compiler/testData/diagnostics/tests/Dollar.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("emptyLhsClassLiterals.kt")
|
||||||
|
public void testEmptyLhsClassLiterals() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/emptyLhsClassLiterals.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("EnumEntryAsType.kt")
|
@TestMetadata("EnumEntryAsType.kt")
|
||||||
public void testEnumEntryAsType() throws Exception {
|
public void testEnumEntryAsType() throws Exception {
|
||||||
|
|||||||
+6
@@ -297,6 +297,12 @@ public class FirPsiOldFrontendDiagnosticsTestGenerated extends AbstractFirPsiDia
|
|||||||
runTest("compiler/testData/diagnostics/tests/Dollar.kt");
|
runTest("compiler/testData/diagnostics/tests/Dollar.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("emptyLhsClassLiterals.kt")
|
||||||
|
public void testEmptyLhsClassLiterals() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/emptyLhsClassLiterals.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("EnumEntryAsType.kt")
|
@TestMetadata("EnumEntryAsType.kt")
|
||||||
public void testEnumEntryAsType() throws Exception {
|
public void testEnumEntryAsType() throws Exception {
|
||||||
|
|||||||
+1
@@ -806,6 +806,7 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
|||||||
val EXPRESSION_OF_NULLABLE_TYPE_IN_CLASS_LITERAL_LHS by error<PsiElement> {
|
val EXPRESSION_OF_NULLABLE_TYPE_IN_CLASS_LITERAL_LHS by error<PsiElement> {
|
||||||
parameter<ConeKotlinType>("lhsType")
|
parameter<ConeKotlinType>("lhsType")
|
||||||
}
|
}
|
||||||
|
val UNSUPPORTED_CLASS_LITERALS_WITH_EMPTY_LHS by error<KtElement>()
|
||||||
}
|
}
|
||||||
|
|
||||||
val OVERRIDES by object : DiagnosticGroup("overrides") {
|
val OVERRIDES by object : DiagnosticGroup("overrides") {
|
||||||
|
|||||||
@@ -463,6 +463,7 @@ object FirErrors {
|
|||||||
val CLASS_LITERAL_LHS_NOT_A_CLASS by error0<KtExpression>()
|
val CLASS_LITERAL_LHS_NOT_A_CLASS by error0<KtExpression>()
|
||||||
val NULLABLE_TYPE_IN_CLASS_LITERAL_LHS by error0<KtExpression>()
|
val NULLABLE_TYPE_IN_CLASS_LITERAL_LHS by error0<KtExpression>()
|
||||||
val EXPRESSION_OF_NULLABLE_TYPE_IN_CLASS_LITERAL_LHS by error1<PsiElement, ConeKotlinType>()
|
val EXPRESSION_OF_NULLABLE_TYPE_IN_CLASS_LITERAL_LHS by error1<PsiElement, ConeKotlinType>()
|
||||||
|
val UNSUPPORTED_CLASS_LITERALS_WITH_EMPTY_LHS by error0<KtElement>()
|
||||||
|
|
||||||
// overrides
|
// overrides
|
||||||
val NOTHING_TO_OVERRIDE by error1<KtModifierListOwner, FirCallableSymbol<*>>(SourceElementPositioningStrategies.OVERRIDE_MODIFIER)
|
val NOTHING_TO_OVERRIDE by error1<KtModifierListOwner, FirCallableSymbol<*>>(SourceElementPositioningStrategies.OVERRIDE_MODIFIER)
|
||||||
|
|||||||
+3
-1
@@ -595,6 +595,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNSAFE_INFIX_CALL
|
|||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNSAFE_OPERATOR_CALL
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNSAFE_OPERATOR_CALL
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNSIGNED_LITERAL_WITHOUT_DECLARATIONS_ON_CLASSPATH
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNSIGNED_LITERAL_WITHOUT_DECLARATIONS_ON_CLASSPATH
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNSUPPORTED
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNSUPPORTED
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNSUPPORTED_CLASS_LITERALS_WITH_EMPTY_LHS
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNSUPPORTED_CONTEXTUAL_DECLARATION_CALL
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNSUPPORTED_CONTEXTUAL_DECLARATION_CALL
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNSUPPORTED_FEATURE
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNSUPPORTED_FEATURE
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNUSED_VARIABLE
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNUSED_VARIABLE
|
||||||
@@ -1359,6 +1360,7 @@ object FirErrorsDefaultMessages : BaseDiagnosticRendererFactory() {
|
|||||||
"Expression in a class literal has a nullable type ''{0}'', use !! to make the type non-nullable",
|
"Expression in a class literal has a nullable type ''{0}'', use !! to make the type non-nullable",
|
||||||
RENDER_TYPE
|
RENDER_TYPE
|
||||||
)
|
)
|
||||||
|
map.put(UNSUPPORTED_CLASS_LITERALS_WITH_EMPTY_LHS, "Class literals with empty left hand side are unsupported")
|
||||||
|
|
||||||
// Value classes
|
// Value classes
|
||||||
map.put(VALUE_CLASS_NOT_TOP_LEVEL, "Value class cannot be local or inner")
|
map.put(VALUE_CLASS_NOT_TOP_LEVEL, "Value class cannot be local or inner")
|
||||||
@@ -2002,7 +2004,7 @@ object FirErrorsDefaultMessages : BaseDiagnosticRendererFactory() {
|
|||||||
map.put(USELESS_CAST, "No cast needed")
|
map.put(USELESS_CAST, "No cast needed")
|
||||||
map.put(UNCHECKED_CAST, "Unchecked cast: ''{0}'' to ''{1}''", RENDER_TYPE, RENDER_TYPE)
|
map.put(UNCHECKED_CAST, "Unchecked cast: ''{0}'' to ''{1}''", RENDER_TYPE, RENDER_TYPE)
|
||||||
map.put(USELESS_IS_CHECK, "Check for instance is always ''{0}''", TO_STRING)
|
map.put(USELESS_IS_CHECK, "Check for instance is always ''{0}''", TO_STRING)
|
||||||
map.put(DYNAMIC_NOT_ALLOWED, "Dynamic types are not allowed in this position");
|
map.put(DYNAMIC_NOT_ALLOWED, "Dynamic types are not allowed in this position")
|
||||||
map.put(IS_ENUM_ENTRY, "'is' over enum entry is not allowed, use comparison instead")
|
map.put(IS_ENUM_ENTRY, "'is' over enum entry is not allowed, use comparison instead")
|
||||||
map.put(ENUM_ENTRY_AS_TYPE, "Use of enum entry names as types is not allowed, use enum type instead")
|
map.put(ENUM_ENTRY_AS_TYPE, "Use of enum entry names as types is not allowed, use enum type instead")
|
||||||
|
|
||||||
|
|||||||
+1
@@ -151,6 +151,7 @@ private fun ConeDiagnostic.toKtDiagnostic(
|
|||||||
is ConeAmbiguouslyResolvedAnnotationArgument ->
|
is ConeAmbiguouslyResolvedAnnotationArgument ->
|
||||||
FirErrors.AMBIGUOUS_ANNOTATION_ARGUMENT.createOn(source, listOfNotNull(symbolFromCompilerPhase, symbolFromAnnotationArgumentsPhase))
|
FirErrors.AMBIGUOUS_ANNOTATION_ARGUMENT.createOn(source, listOfNotNull(symbolFromCompilerPhase, symbolFromAnnotationArgumentsPhase))
|
||||||
is ConeAmbiguousFunctionTypeKinds -> FirErrors.AMBIGUOUS_FUNCTION_TYPE_KIND.createOn(source, kinds)
|
is ConeAmbiguousFunctionTypeKinds -> FirErrors.AMBIGUOUS_FUNCTION_TYPE_KIND.createOn(source, kinds)
|
||||||
|
is ConeUnsupportedClassLiteralsWithEmptyLhs -> FirErrors.UNSUPPORTED_CLASS_LITERALS_WITH_EMPTY_LHS.createOn(source)
|
||||||
else -> throw IllegalArgumentException("Unsupported diagnostic type: ${this.javaClass}")
|
else -> throw IllegalArgumentException("Unsupported diagnostic type: ${this.javaClass}")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+4
-2
@@ -463,11 +463,13 @@ class LightTreeRawFirExpressionBuilder(
|
|||||||
if (it.isExpression()) firReceiverExpression = getAsFirExpression(it, "No receiver in class literal")
|
if (it.isExpression()) firReceiverExpression = getAsFirExpression(it, "No receiver in class literal")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val classLiteralSource = classLiteralExpression.toFirSourceElement()
|
||||||
|
|
||||||
return buildGetClassCall {
|
return buildGetClassCall {
|
||||||
source = classLiteralExpression.toFirSourceElement()
|
source = classLiteralSource
|
||||||
argumentList = buildUnaryArgumentList(
|
argumentList = buildUnaryArgumentList(
|
||||||
firReceiverExpression
|
firReceiverExpression
|
||||||
?: buildErrorExpression(null, ConeSyntaxDiagnostic("No receiver in class literal"))
|
?: buildErrorExpression(classLiteralSource, ConeUnsupportedClassLiteralsWithEmptyLhs)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-3
@@ -276,9 +276,12 @@ open class PsiRawFirBuilder(
|
|||||||
kind: DiagnosticKind = DiagnosticKind.ExpressionExpected
|
kind: DiagnosticKind = DiagnosticKind.ExpressionExpected
|
||||||
): FirExpression = toFirExpression { ConeSimpleDiagnostic(errorReason, kind) }
|
): FirExpression = toFirExpression { ConeSimpleDiagnostic(errorReason, kind) }
|
||||||
|
|
||||||
private inline fun KtElement?.toFirExpression(diagnosticFn: () -> ConeDiagnostic): FirExpression {
|
private inline fun KtElement?.toFirExpression(
|
||||||
|
sourceWhenThisIsNull: PsiElement? = null,
|
||||||
|
diagnosticFn: () -> ConeDiagnostic,
|
||||||
|
): FirExpression {
|
||||||
if (this == null) {
|
if (this == null) {
|
||||||
return buildErrorExpression(source = null, diagnosticFn())
|
return buildErrorExpression(source = sourceWhenThisIsNull?.toFirSourceElement(), diagnosticFn())
|
||||||
}
|
}
|
||||||
|
|
||||||
val result = when (val fir = convertElement(this, null)) {
|
val result = when (val fir = convertElement(this, null)) {
|
||||||
@@ -2929,7 +2932,11 @@ open class PsiRawFirBuilder(
|
|||||||
override fun visitClassLiteralExpression(expression: KtClassLiteralExpression, data: FirElement?): FirElement {
|
override fun visitClassLiteralExpression(expression: KtClassLiteralExpression, data: FirElement?): FirElement {
|
||||||
return buildGetClassCall {
|
return buildGetClassCall {
|
||||||
source = expression.toFirSourceElement()
|
source = expression.toFirSourceElement()
|
||||||
argumentList = buildUnaryArgumentList(expression.receiverExpression.toFirExpression("No receiver in class literal"))
|
argumentList = buildUnaryArgumentList(
|
||||||
|
expression.receiverExpression.toFirExpression(sourceWhenThisIsNull = expression) {
|
||||||
|
ConeUnsupportedClassLiteralsWithEmptyLhs
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -71,6 +71,10 @@ class ConeAmbiguousFunctionTypeKinds(val kinds: List<FunctionTypeKind>) : ConeDi
|
|||||||
get() = "There are multiple function kinds for functional type ref"
|
get() = "There are multiple function kinds for functional type ref"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
object ConeUnsupportedClassLiteralsWithEmptyLhs : ConeDiagnostic {
|
||||||
|
override val reason: String get() = "No receiver in class literal"
|
||||||
|
}
|
||||||
|
|
||||||
enum class DiagnosticKind {
|
enum class DiagnosticKind {
|
||||||
ExpressionExpected,
|
ExpressionExpected,
|
||||||
NotLoopLabel,
|
NotLoopLabel,
|
||||||
|
|||||||
Vendored
-17
@@ -1,17 +0,0 @@
|
|||||||
fun regular() {
|
|
||||||
::class
|
|
||||||
|
|
||||||
with(Any()) {
|
|
||||||
::class
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun Any.extension() {
|
|
||||||
::class
|
|
||||||
}
|
|
||||||
|
|
||||||
class A {
|
|
||||||
fun member() {
|
|
||||||
::class
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Vendored
+1
@@ -1,3 +1,4 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
fun regular() {
|
fun regular() {
|
||||||
<!UNSUPPORTED_CLASS_LITERALS_WITH_EMPTY_LHS!>::class<!>
|
<!UNSUPPORTED_CLASS_LITERALS_WITH_EMPTY_LHS!>::class<!>
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
|
// ISSUE: KT-59165
|
||||||
|
|
||||||
|
fun regular() {
|
||||||
|
<!UNSUPPORTED_CLASS_LITERALS_WITH_EMPTY_LHS!>::class<!> // K1: Error, K2: compiles
|
||||||
|
}
|
||||||
Generated
+6
@@ -297,6 +297,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
|
|||||||
runTest("compiler/testData/diagnostics/tests/Dollar.kt");
|
runTest("compiler/testData/diagnostics/tests/Dollar.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("emptyLhsClassLiterals.kt")
|
||||||
|
public void testEmptyLhsClassLiterals() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/emptyLhsClassLiterals.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("EnumEntryAsType.kt")
|
@TestMetadata("EnumEntryAsType.kt")
|
||||||
public void testEnumEntryAsType() throws Exception {
|
public void testEnumEntryAsType() throws Exception {
|
||||||
|
|||||||
Reference in New Issue
Block a user