[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 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 a: A
} }
val test = 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 NOT_A_LOOP_LABEL by error<PsiElement>()
val VARIABLE_EXPECTED by error<PsiElement>(PositioningStrategy.ASSIGNMENT_LHS) val VARIABLE_EXPECTED by error<PsiElement>(PositioningStrategy.ASSIGNMENT_LHS)
val DELEGATION_IN_INTERFACE by error<PsiElement>() 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) { val NESTED_CLASS_NOT_ALLOWED by error<KtNamedDeclaration>(PositioningStrategy.DECLARATION_NAME) {
parameter<String>("declaration") parameter<String>("declaration")
} }
@@ -92,6 +92,7 @@ object FirErrors {
val NOT_A_LOOP_LABEL by error0<PsiElement>() val NOT_A_LOOP_LABEL by error0<PsiElement>()
val VARIABLE_EXPECTED by error0<PsiElement>(SourceElementPositioningStrategies.ASSIGNMENT_LHS) val VARIABLE_EXPECTED by error0<PsiElement>(SourceElementPositioningStrategies.ASSIGNMENT_LHS)
val DELEGATION_IN_INTERFACE by error0<PsiElement>() 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 NESTED_CLASS_NOT_ALLOWED by error1<KtNamedDeclaration, String>(SourceElementPositioningStrategies.DECLARATION_NAME)
val INCORRECT_CHARACTER_LITERAL by error0<PsiElement>() val INCORRECT_CHARACTER_LITERAL by error0<PsiElement>()
val EMPTY_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 private val FirSimpleFunction.matchesToStringSignature: Boolean
get() = valueParameters.isEmpty() get() = valueParameters.isEmpty()
val Name.isDelegated: Boolean get() = asString().startsWith("<\$\$delegate_")
val ConeTypeProjection.isConflictingOrNotInvariant: Boolean get() = kind != ProjectionKind.INVARIANT || this is ConeKotlinTypeConflictingProjection val ConeTypeProjection.isConflictingOrNotInvariant: Boolean get() = kind != ProjectionKind.INVARIANT || this is ConeKotlinTypeConflictingProjection
fun checkTypeMismatch( 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.ClassKind
import org.jetbrains.kotlin.descriptors.Modality 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.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.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.analysis.diagnostics.withSuppressedDiagnostics import org.jetbrains.kotlin.fir.analysis.diagnostics.withSuppressedDiagnostics
import org.jetbrains.kotlin.fir.declarations.FirClass import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.declarations.modality
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
import org.jetbrains.kotlin.fir.resolve.toSymbol import org.jetbrains.kotlin.fir.resolve.toSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
@@ -85,6 +82,9 @@ object FirSupertypesChecker : FirClassChecker() {
val fullyExpandedType = coneType.fullyExpandedType(context.session) val fullyExpandedType = coneType.fullyExpandedType(context.session)
val symbol = fullyExpandedType.toSymbol(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()) { if (coneType.typeArguments.isNotEmpty()) {
for ((index, typeArgument) in coneType.typeArguments.withIndex()) { for ((index, typeArgument) in coneType.typeArguments.withIndex()) {
@@ -107,9 +107,19 @@ object FirSupertypesChecker : FirClassChecker() {
} }
} }
} }
}
}
if (symbol is FirRegularClassSymbol && symbol.classId == StandardClassIds.Enum) { for (subDeclaration in declaration.declarations) {
reporter.reportOn(superTypeRef.source, FirErrors.CLASS_CANNOT_BE_EXTENDED_DIRECTLY, symbol, context) 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 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.LanguageFeatureMessageRenderer
import org.jetbrains.kotlin.diagnostics.rendering.Renderers.RENDER_POSITION_VARIANCE import org.jetbrains.kotlin.diagnostics.rendering.Renderers.RENDER_POSITION_VARIANCE
import org.jetbrains.kotlin.diagnostics.rendering.Renderers.STRING 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.NOT_RENDERED
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.NULLABLE_STRING 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_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.RENDER_TYPE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.SYMBOL 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.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.TO_STRING
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.VARIABLE_NAME import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.VARIABLE_NAME
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.VISIBILITY 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_NONE_APPLICABLE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.DELEGATE_SPECIAL_FUNCTION_RETURN_TYPE_MISMATCH 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_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.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_MODIFIER_PAIR
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.DEPRECATED_SINCE_KOTLIN_OUTSIDE_KOTLIN_SUBPACKAGE 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(NOT_A_LOOP_LABEL, "The label does not denote a loop") // *
map.put(VARIABLE_EXPECTED, "Variable expected") map.put(VARIABLE_EXPECTED, "Variable expected")
map.put(DELEGATION_IN_INTERFACE, "Interfaces cannot use delegation") 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(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_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) 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 {} interface T {}
@@ -12,4 +12,4 @@ open enum class EN() {
A 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 // JAVAC_EXPECTED_FILE
class TestIface(r : Runnable) : Runnable by r {} 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 // FILE: main.kt
import foo.A 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, token,
) )
} }
add(FirErrors.DELEGATION_NOT_TO_INTERFACE) { firDiagnostic ->
DelegationNotToInterfaceImpl(
firDiagnostic as FirPsiDiagnostic,
token,
)
}
add(FirErrors.NESTED_CLASS_NOT_ALLOWED) { firDiagnostic -> add(FirErrors.NESTED_CLASS_NOT_ALLOWED) { firDiagnostic ->
NestedClassNotAllowedImpl( NestedClassNotAllowedImpl(
firDiagnostic.a, firDiagnostic.a,
@@ -121,6 +121,10 @@ sealed class KtFirDiagnostic<PSI: PsiElement> : KtDiagnosticWithPsi<PSI> {
override val diagnosticClass get() = DelegationInInterface::class override val diagnosticClass get() = DelegationInInterface::class
} }
abstract class DelegationNotToInterface : KtFirDiagnostic<PsiElement>() {
override val diagnosticClass get() = DelegationNotToInterface::class
}
abstract class NestedClassNotAllowed : KtFirDiagnostic<KtNamedDeclaration>() { abstract class NestedClassNotAllowed : KtFirDiagnostic<KtNamedDeclaration>() {
override val diagnosticClass get() = NestedClassNotAllowed::class override val diagnosticClass get() = NestedClassNotAllowed::class
abstract val declaration: String abstract val declaration: String
@@ -161,6 +161,13 @@ internal class DelegationInInterfaceImpl(
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic) 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( internal class NestedClassNotAllowedImpl(
override val declaration: String, override val declaration: String,
firDiagnostic: FirPsiDiagnostic, firDiagnostic: FirPsiDiagnostic,