[FIR] Implement DELEGATION_NOT_TO_INTERFACE

This commit is contained in:
Ivan Kochurkin
2021-06-25 22:43:41 +03:00
committed by teamcityserver
parent c3a6ba52f6
commit fb9ce06ff5
12 changed files with 49 additions and 15 deletions
@@ -1,9 +1,9 @@
open class A
interface B : <!DELEGATION_IN_INTERFACE, INTERFACE_WITH_SUPERCLASS!>A<!> by <!UNRESOLVED_REFERENCE!>a<!> {
interface B : <!DELEGATION_IN_INTERFACE, DELEGATION_NOT_TO_INTERFACE, INTERFACE_WITH_SUPERCLASS!>A<!> by <!UNRESOLVED_REFERENCE!>a<!> {
val a: A
}
val test = A()
interface C : <!DELEGATION_IN_INTERFACE, INTERFACE_WITH_SUPERCLASS!>A<!> by test
interface C : <!DELEGATION_IN_INTERFACE, DELEGATION_NOT_TO_INTERFACE, INTERFACE_WITH_SUPERCLASS!>A<!> by test
@@ -60,6 +60,7 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
val NOT_A_LOOP_LABEL by error<PsiElement>()
val VARIABLE_EXPECTED by error<PsiElement>(PositioningStrategy.ASSIGNMENT_LHS)
val DELEGATION_IN_INTERFACE by error<PsiElement>()
val DELEGATION_NOT_TO_INTERFACE by error<PsiElement>()
val NESTED_CLASS_NOT_ALLOWED by error<KtNamedDeclaration>(PositioningStrategy.DECLARATION_NAME) {
parameter<String>("declaration")
}
@@ -92,6 +92,7 @@ object FirErrors {
val NOT_A_LOOP_LABEL by error0<PsiElement>()
val VARIABLE_EXPECTED by error0<PsiElement>(SourceElementPositioningStrategies.ASSIGNMENT_LHS)
val DELEGATION_IN_INTERFACE by error0<PsiElement>()
val DELEGATION_NOT_TO_INTERFACE by error0<PsiElement>()
val NESTED_CLASS_NOT_ALLOWED by error1<KtNamedDeclaration, String>(SourceElementPositioningStrategies.DECLARATION_NAME)
val INCORRECT_CHARACTER_LITERAL by error0<PsiElement>()
val EMPTY_CHARACTER_LITERAL by error0<PsiElement>()
@@ -521,6 +521,8 @@ private val FirSimpleFunction.matchesHashCodeSignature: Boolean
private val FirSimpleFunction.matchesToStringSignature: Boolean
get() = valueParameters.isEmpty()
val Name.isDelegated: Boolean get() = asString().startsWith("<\$\$delegate_")
val ConeTypeProjection.isConflictingOrNotInvariant: Boolean get() = kind != ProjectionKind.INVARIANT || this is ConeKotlinTypeConflictingProjection
fun checkTypeMismatch(
@@ -7,17 +7,14 @@ package org.jetbrains.kotlin.fir.analysis.checkers.declaration
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.fir.analysis.checkers.checkInconsistentTypeParameters
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.fir.analysis.checkers.*
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.extractTypeRefAndSourceFromTypeArgument
import org.jetbrains.kotlin.fir.analysis.checkers.isConflictingOrNotInvariant
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.analysis.diagnostics.withSuppressedDiagnostics
import org.jetbrains.kotlin.fir.declarations.FirClass
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.declarations.modality
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
import org.jetbrains.kotlin.fir.resolve.toSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
@@ -85,6 +82,9 @@ object FirSupertypesChecker : FirClassChecker() {
val fullyExpandedType = coneType.fullyExpandedType(context.session)
val symbol = fullyExpandedType.toSymbol(context.session)
if (symbol is FirRegularClassSymbol && symbol.classId == StandardClassIds.Enum) {
reporter.reportOn(superTypeRef.source, FirErrors.CLASS_CANNOT_BE_EXTENDED_DIRECTLY, symbol, context)
}
if (coneType.typeArguments.isNotEmpty()) {
for ((index, typeArgument) in coneType.typeArguments.withIndex()) {
@@ -107,9 +107,19 @@ object FirSupertypesChecker : FirClassChecker() {
}
}
}
}
}
if (symbol is FirRegularClassSymbol && symbol.classId == StandardClassIds.Enum) {
reporter.reportOn(superTypeRef.source, FirErrors.CLASS_CANNOT_BE_EXTENDED_DIRECTLY, symbol, context)
for (subDeclaration in declaration.declarations) {
if (subDeclaration is FirField) {
if (subDeclaration.visibility == Visibilities.Local &&
subDeclaration.name.isSpecial &&
subDeclaration.name.isDelegated
) {
val subDeclFir = subDeclaration.returnTypeRef.toRegularClass(context.session)
if (subDeclFir is FirRegularClass && subDeclFir.classKind != ClassKind.INTERFACE) {
reporter.reportOn(subDeclaration.returnTypeRef.source, FirErrors.DELEGATION_NOT_TO_INTERFACE, context)
}
}
}
}
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.fir.analysis.diagnostics
import org.jetbrains.kotlin.diagnostics.rendering.DefaultErrorMessages
import org.jetbrains.kotlin.diagnostics.rendering.LanguageFeatureMessageRenderer
import org.jetbrains.kotlin.diagnostics.rendering.Renderers.RENDER_POSITION_VARIANCE
import org.jetbrains.kotlin.diagnostics.rendering.Renderers.STRING
@@ -16,10 +17,10 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.NAME
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.NOT_RENDERED
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.NULLABLE_STRING
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.RENDER_CLASS_OR_OBJECT
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.RENDER_COLLECTION_OF_TYPES
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.RENDER_TYPE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.SYMBOL
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.SYMBOLS
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.RENDER_COLLECTION_OF_TYPES
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.TO_STRING
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.VARIABLE_NAME
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.VISIBILITY
@@ -99,6 +100,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.DELEGATE_SPECIAL_
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.DELEGATE_SPECIAL_FUNCTION_NONE_APPLICABLE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.DELEGATE_SPECIAL_FUNCTION_RETURN_TYPE_MISMATCH
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.DELEGATION_IN_INTERFACE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.DELEGATION_NOT_TO_INTERFACE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.DELEGATION_SUPER_CALL_IN_ENUM_CONSTRUCTOR
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.DEPRECATED_MODIFIER_PAIR
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.DEPRECATED_SINCE_KOTLIN_OUTSIDE_KOTLIN_SUBPACKAGE
@@ -414,6 +416,7 @@ class FirDefaultErrorMessages {
map.put(NOT_A_LOOP_LABEL, "The label does not denote a loop") // *
map.put(VARIABLE_EXPECTED, "Variable expected")
map.put(DELEGATION_IN_INTERFACE, "Interfaces cannot use delegation")
map.put(DELEGATION_NOT_TO_INTERFACE, "Only interfaces can be delegated to")
map.put(NESTED_CLASS_NOT_ALLOWED, "{0} is not allowed here", TO_STRING)
map.put(VAL_OR_VAR_ON_LOOP_PARAMETER, "''{0}'' on loop parameter is not allowed", TO_STRING)
map.put(VAL_OR_VAR_ON_FUN_PARAMETER, "''{0}'' on function parameter is not allowed", TO_STRING)
@@ -2,7 +2,7 @@ open class Foo() {
}
class Barrr() : <!SUPERTYPE_NOT_INITIALIZED!>Foo<!> by Foo() {}
class Barrr() : <!DELEGATION_NOT_TO_INTERFACE, SUPERTYPE_NOT_INITIALIZED!>Foo<!> by Foo() {}
interface T {}
@@ -12,4 +12,4 @@ open enum class EN() {
A
}
class Test2(e : EN) : EN by e {}
class Test2(e : EN) : <!DELEGATION_NOT_TO_INTERFACE!>EN<!> by e {}
@@ -1,4 +1,4 @@
// JAVAC_EXPECTED_FILE
class TestIface(r : Runnable) : Runnable by r {}
class TestObject(o : Object) : <!SUPERTYPE_NOT_INITIALIZED!>Object<!> by o {}
class TestObject(o : Object) : <!DELEGATION_NOT_TO_INTERFACE, SUPERTYPE_NOT_INITIALIZED!>Object<!> by o {}
@@ -11,4 +11,4 @@ public abstract class A {
// FILE: main.kt
import foo.A
class DelegatedA(val a: A) : <!SUPERTYPE_NOT_INITIALIZED!>A<!> by a
class DelegatedA(val a: A) : <!DELEGATION_NOT_TO_INTERFACE, SUPERTYPE_NOT_INITIALIZED!>A<!> by a
@@ -138,6 +138,12 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
token,
)
}
add(FirErrors.DELEGATION_NOT_TO_INTERFACE) { firDiagnostic ->
DelegationNotToInterfaceImpl(
firDiagnostic as FirPsiDiagnostic,
token,
)
}
add(FirErrors.NESTED_CLASS_NOT_ALLOWED) { firDiagnostic ->
NestedClassNotAllowedImpl(
firDiagnostic.a,
@@ -121,6 +121,10 @@ sealed class KtFirDiagnostic<PSI: PsiElement> : KtDiagnosticWithPsi<PSI> {
override val diagnosticClass get() = DelegationInInterface::class
}
abstract class DelegationNotToInterface : KtFirDiagnostic<PsiElement>() {
override val diagnosticClass get() = DelegationNotToInterface::class
}
abstract class NestedClassNotAllowed : KtFirDiagnostic<KtNamedDeclaration>() {
override val diagnosticClass get() = NestedClassNotAllowed::class
abstract val declaration: String
@@ -161,6 +161,13 @@ internal class DelegationInInterfaceImpl(
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
}
internal class DelegationNotToInterfaceImpl(
firDiagnostic: FirPsiDiagnostic,
override val token: ValidityToken,
) : KtFirDiagnostic.DelegationNotToInterface(), KtAbstractFirDiagnostic<PsiElement> {
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
}
internal class NestedClassNotAllowedImpl(
override val declaration: String,
firDiagnostic: FirPsiDiagnostic,