[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,
|
||||
)
|
||||
}
|
||||
add(FirErrors.UNSUPPORTED_CLASS_LITERALS_WITH_EMPTY_LHS) { firDiagnostic ->
|
||||
UnsupportedClassLiteralsWithEmptyLhsImpl(
|
||||
firDiagnostic as KtPsiDiagnostic,
|
||||
token,
|
||||
)
|
||||
}
|
||||
add(FirErrors.NOTHING_TO_OVERRIDE) { firDiagnostic ->
|
||||
NothingToOverrideImpl(
|
||||
firSymbolBuilder.callableBuilder.buildCallableSymbol(firDiagnostic.a),
|
||||
|
||||
+4
@@ -1730,6 +1730,10 @@ sealed interface KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
|
||||
val lhsType: KtType
|
||||
}
|
||||
|
||||
interface UnsupportedClassLiteralsWithEmptyLhs : KtFirDiagnostic<KtElement> {
|
||||
override val diagnosticClass get() = UnsupportedClassLiteralsWithEmptyLhs::class
|
||||
}
|
||||
|
||||
interface NothingToOverride : KtFirDiagnostic<KtModifierListOwner> {
|
||||
override val diagnosticClass get() = NothingToOverride::class
|
||||
val declaration: KtCallableSymbol
|
||||
|
||||
+5
@@ -2080,6 +2080,11 @@ internal class ExpressionOfNullableTypeInClassLiteralLhsImpl(
|
||||
token: KtLifetimeToken,
|
||||
) : KtAbstractFirDiagnostic<PsiElement>(firDiagnostic, token), KtFirDiagnostic.ExpressionOfNullableTypeInClassLiteralLhs
|
||||
|
||||
internal class UnsupportedClassLiteralsWithEmptyLhsImpl(
|
||||
firDiagnostic: KtPsiDiagnostic,
|
||||
token: KtLifetimeToken,
|
||||
) : KtAbstractFirDiagnostic<KtElement>(firDiagnostic, token), KtFirDiagnostic.UnsupportedClassLiteralsWithEmptyLhs
|
||||
|
||||
internal class NothingToOverrideImpl(
|
||||
override val declaration: KtCallableSymbol,
|
||||
firDiagnostic: KtPsiDiagnostic,
|
||||
|
||||
+6
@@ -297,6 +297,12 @@ public class DiagnosticCompilerTestFE10TestdataTestGenerated extends AbstractDia
|
||||
runTest("compiler/testData/diagnostics/tests/Dollar.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("emptyLhsClassLiterals.kt")
|
||||
public void testEmptyLhsClassLiterals() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/emptyLhsClassLiterals.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("EnumEntryAsType.kt")
|
||||
public void testEnumEntryAsType() throws Exception {
|
||||
|
||||
+6
@@ -297,6 +297,12 @@ public class LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated
|
||||
runTest("compiler/testData/diagnostics/tests/Dollar.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("emptyLhsClassLiterals.kt")
|
||||
public void testEmptyLhsClassLiterals() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/emptyLhsClassLiterals.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("EnumEntryAsType.kt")
|
||||
public void testEnumEntryAsType() throws Exception {
|
||||
|
||||
+6
@@ -297,6 +297,12 @@ public class FirLightTreeOldFrontendDiagnosticsTestGenerated extends AbstractFir
|
||||
runTest("compiler/testData/diagnostics/tests/Dollar.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("emptyLhsClassLiterals.kt")
|
||||
public void testEmptyLhsClassLiterals() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/emptyLhsClassLiterals.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("EnumEntryAsType.kt")
|
||||
public void testEnumEntryAsType() throws Exception {
|
||||
|
||||
+6
@@ -297,6 +297,12 @@ public class FirPsiOldFrontendDiagnosticsTestGenerated extends AbstractFirPsiDia
|
||||
runTest("compiler/testData/diagnostics/tests/Dollar.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("emptyLhsClassLiterals.kt")
|
||||
public void testEmptyLhsClassLiterals() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/emptyLhsClassLiterals.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("EnumEntryAsType.kt")
|
||||
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> {
|
||||
parameter<ConeKotlinType>("lhsType")
|
||||
}
|
||||
val UNSUPPORTED_CLASS_LITERALS_WITH_EMPTY_LHS by error<KtElement>()
|
||||
}
|
||||
|
||||
val OVERRIDES by object : DiagnosticGroup("overrides") {
|
||||
|
||||
@@ -463,6 +463,7 @@ object FirErrors {
|
||||
val CLASS_LITERAL_LHS_NOT_A_CLASS 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 UNSUPPORTED_CLASS_LITERALS_WITH_EMPTY_LHS by error0<KtElement>()
|
||||
|
||||
// overrides
|
||||
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.UNSIGNED_LITERAL_WITHOUT_DECLARATIONS_ON_CLASSPATH
|
||||
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_FEATURE
|
||||
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",
|
||||
RENDER_TYPE
|
||||
)
|
||||
map.put(UNSUPPORTED_CLASS_LITERALS_WITH_EMPTY_LHS, "Class literals with empty left hand side are unsupported")
|
||||
|
||||
// Value classes
|
||||
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(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(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(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 ->
|
||||
FirErrors.AMBIGUOUS_ANNOTATION_ARGUMENT.createOn(source, listOfNotNull(symbolFromCompilerPhase, symbolFromAnnotationArgumentsPhase))
|
||||
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}")
|
||||
}
|
||||
|
||||
|
||||
+4
-2
@@ -463,11 +463,13 @@ class LightTreeRawFirExpressionBuilder(
|
||||
if (it.isExpression()) firReceiverExpression = getAsFirExpression(it, "No receiver in class literal")
|
||||
}
|
||||
|
||||
val classLiteralSource = classLiteralExpression.toFirSourceElement()
|
||||
|
||||
return buildGetClassCall {
|
||||
source = classLiteralExpression.toFirSourceElement()
|
||||
source = classLiteralSource
|
||||
argumentList = buildUnaryArgumentList(
|
||||
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
|
||||
): 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) {
|
||||
return buildErrorExpression(source = null, diagnosticFn())
|
||||
return buildErrorExpression(source = sourceWhenThisIsNull?.toFirSourceElement(), diagnosticFn())
|
||||
}
|
||||
|
||||
val result = when (val fir = convertElement(this, null)) {
|
||||
@@ -2929,7 +2932,11 @@ open class PsiRawFirBuilder(
|
||||
override fun visitClassLiteralExpression(expression: KtClassLiteralExpression, data: FirElement?): FirElement {
|
||||
return buildGetClassCall {
|
||||
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"
|
||||
}
|
||||
|
||||
object ConeUnsupportedClassLiteralsWithEmptyLhs : ConeDiagnostic {
|
||||
override val reason: String get() = "No receiver in class literal"
|
||||
}
|
||||
|
||||
enum class DiagnosticKind {
|
||||
ExpressionExpected,
|
||||
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() {
|
||||
<!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");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("emptyLhsClassLiterals.kt")
|
||||
public void testEmptyLhsClassLiterals() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/emptyLhsClassLiterals.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("EnumEntryAsType.kt")
|
||||
public void testEnumEntryAsType() throws Exception {
|
||||
|
||||
Reference in New Issue
Block a user