[FIR JS] Support DYNAMIC_RECEIVER_NOT_ALLOWED

This commit is contained in:
Nikolay Lunyak
2023-01-04 15:05:45 +02:00
committed by Space Team
parent 0f876f665a
commit 227969d787
21 changed files with 68 additions and 51 deletions
@@ -2022,6 +2022,12 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
token,
)
}
add(FirErrors.DYNAMIC_RECEIVER_NOT_ALLOWED) { firDiagnostic ->
DynamicReceiverNotAllowedImpl(
firDiagnostic as KtPsiDiagnostic,
token,
)
}
add(FirErrors.INCOMPATIBLE_TYPES) { firDiagnostic ->
IncompatibleTypesImpl(
firSymbolBuilder.typeBuilder.buildKtType(firDiagnostic.a),
@@ -1435,6 +1435,10 @@ sealed class KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
override val diagnosticClass get() = DynamicUpperBound::class
}
abstract class DynamicReceiverNotAllowed : KtFirDiagnostic<KtElement>() {
override val diagnosticClass get() = DynamicReceiverNotAllowed::class
}
abstract class IncompatibleTypes : KtFirDiagnostic<KtElement>() {
override val diagnosticClass get() = IncompatibleTypes::class
abstract val typeA: KtType
@@ -1727,6 +1727,11 @@ internal class DynamicUpperBoundImpl(
override val token: KtLifetimeToken,
) : KtFirDiagnostic.DynamicUpperBound(), KtAbstractFirDiagnostic<KtTypeReference>
internal class DynamicReceiverNotAllowedImpl(
override val firDiagnostic: KtPsiDiagnostic,
override val token: KtLifetimeToken,
) : KtFirDiagnostic.DynamicReceiverNotAllowed(), KtAbstractFirDiagnostic<KtElement>
internal class IncompatibleTypesImpl(
override val typeA: KtType,
override val typeB: KtType,
@@ -674,6 +674,8 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
val DYNAMIC_UPPER_BOUND by error<KtTypeReference>()
val DYNAMIC_RECEIVER_NOT_ALLOWED by error<KtElement>()
val INCOMPATIBLE_TYPES by error<KtElement> {
parameter<ConeKotlinType>("typeA")
parameter<ConeKotlinType>("typeB")
@@ -417,6 +417,7 @@ object FirErrors {
val DEPRECATED_TYPE_PARAMETER_SYNTAX by error0<KtDeclaration>(SourceElementPositioningStrategies.TYPE_PARAMETERS_LIST)
val MISPLACED_TYPE_PARAMETER_CONSTRAINTS by warning0<KtTypeParameter>()
val DYNAMIC_UPPER_BOUND by error0<KtTypeReference>()
val DYNAMIC_RECEIVER_NOT_ALLOWED by error0<KtElement>()
val INCOMPATIBLE_TYPES by error2<KtElement, ConeKotlinType, ConeKotlinType>()
val INCOMPATIBLE_TYPES_WARNING by warning2<KtElement, ConeKotlinType, ConeKotlinType>()
val TYPE_VARIANCE_CONFLICT_ERROR by error4<PsiElement, FirTypeParameterSymbol, Variance, Variance, ConeKotlinType>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE_OR_DEFAULT)
@@ -38,6 +38,7 @@ object CommonDeclarationCheckers : DeclarationCheckers() {
get() = setOf(
FirKClassWithIncorrectTypeArgumentChecker,
FirImplicitNothingReturnTypeChecker,
FirDynamicReceiverChecker,
)
override val functionCheckers: Set<FirFunctionChecker>
@@ -0,0 +1,29 @@
/*
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.fir.analysis.checkers.declaration
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.diagnostics.reportOn
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction
import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration
import org.jetbrains.kotlin.fir.declarations.hasAnnotation
import org.jetbrains.kotlin.fir.types.ConeDynamicType
import org.jetbrains.kotlin.fir.types.coneType
import org.jetbrains.kotlin.name.StandardClassIds.Annotations.DynamicExtension
object FirDynamicReceiverChecker : FirCallableDeclarationChecker() {
override fun check(declaration: FirCallableDeclaration, context: CheckerContext, reporter: DiagnosticReporter) {
if (
declaration.receiverParameter?.typeRef?.coneType is ConeDynamicType &&
!declaration.hasAnnotation(DynamicExtension, context.session) &&
declaration !is FirAnonymousFunction
) {
reporter.reportOn(declaration.receiverParameter?.source, FirErrors.DYNAMIC_RECEIVER_NOT_ALLOWED, context)
}
}
}
@@ -168,6 +168,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.DESERIALIZATION_E
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.DIVISION_BY_ZERO
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.DSL_SCOPE_VIOLATION
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.DUPLICATE_LABEL_IN_WHEN
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.DYNAMIC_RECEIVER_NOT_ALLOWED
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.DYNAMIC_UPPER_BOUND
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ELSE_MISPLACED_IN_WHEN
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EMPTY_CHARACTER_LITERAL
@@ -1251,6 +1252,8 @@ object FirErrorsDefaultMessages : BaseDiagnosticRendererFactory() {
map.put(DYNAMIC_UPPER_BOUND, "Dynamic type can not be used as an upper bound")
map.put(DYNAMIC_RECEIVER_NOT_ALLOWED, "Dynamic receiver is prohibited")
// Reflection
map.put(
EXTENSION_IN_CLASS_REFERENCE_NOT_ALLOWED,
@@ -20,7 +20,7 @@ public class J {
import p.*
class K: J.C() {
fun <!UNSUPPORTED!>dynamic<!>.test() {
fun <!DYNAMIC_RECEIVER_NOT_ALLOWED, UNSUPPORTED!>dynamic<!>.test() {
sam(null)
sam(
name = null,
@@ -1,9 +0,0 @@
object X1
object X2
class Inv<T>
fun dynamic.foo() = X1
fun <T> Inv<T>.foo() = X2
fun test(): X2 = Inv<Any>().foo()
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
object X1
object X2
@@ -41,7 +41,7 @@ fun testReassignmentWithStaticCalls(d: dynamic) {
val Any.onAnyVal: Int get() = 1
val Any?.onNullableAnyVal: Int get() = 1
val String.onStringVal: Int get() = 1
val dynamic.onDynamicVal: Int get() = 1
val <!DYNAMIC_RECEIVER_NOT_ALLOWED!>dynamic<!>.onDynamicVal: Int get() = 1
class C {
fun test(d: dynamic) {
@@ -47,7 +47,7 @@ var String.onStringVar: Int
get() = 1
set(v) {}
var dynamic.onDynamicVar: Int
var <!DYNAMIC_RECEIVER_NOT_ALLOWED!>dynamic<!>.onDynamicVar: Int
get() = 1
set(v) {}
@@ -25,7 +25,7 @@ fun test(d: dynamic) {
fun Any.onAny() {}
fun Any?.onNullableAny() {}
fun String.onString() {}
fun dynamic.onDynamic() {}
fun <!DYNAMIC_RECEIVER_NOT_ALLOWED!>dynamic<!>.onDynamic() {}
class C {
fun test(d: dynamic) {
@@ -11,7 +11,7 @@ fun test(d: dynamic) {
d.<!DEBUG_INFO_DYNAMIC!>varOnDynamic<!> = 1
}
fun dynamic.extTest() {
fun <!DYNAMIC_RECEIVER_NOT_ALLOWED!>dynamic<!>.extTest() {
<!DEBUG_INFO_DYNAMIC!>onDynamic<!>()
<!DEBUG_INFO_DYNAMIC!>onNullableDynamic<!>()
@@ -32,12 +32,12 @@ fun dynamic.extTest() {
}
fun dynamic.onDynamic() {}
fun dynamic?.onNullableDynamic() {}
fun <!DYNAMIC_RECEIVER_NOT_ALLOWED!>dynamic<!>.onDynamic() {}
fun <!DYNAMIC_RECEIVER_NOT_ALLOWED!>dynamic?<!>.onNullableDynamic() {}
val dynamic.valOnDynamic: Int get() = 1
val <!DYNAMIC_RECEIVER_NOT_ALLOWED!>dynamic<!>.valOnDynamic: Int get() = 1
var dynamic.varOnDynamic: Int
var <!DYNAMIC_RECEIVER_NOT_ALLOWED!>dynamic<!>.varOnDynamic: Int
get() = 1
set(v) {}
@@ -51,8 +51,8 @@ class ForMemberExtensions {
d.<!DEBUG_INFO_DYNAMIC!>memberExtensionVal<!> = 1
}
val dynamic.memberExtensionVal: Int get() = 1
var dynamic.memberExtensionVar: Int
val <!DYNAMIC_RECEIVER_NOT_ALLOWED!>dynamic<!>.memberExtensionVal: Int get() = 1
var <!DYNAMIC_RECEIVER_NOT_ALLOWED!>dynamic<!>.memberExtensionVar: Int
get() = 1
set(v) {}
}
@@ -1,18 +0,0 @@
fun dynamic.test() {
val v1 = foo()
v1.isDynamic() // to check that anything is resolvable
val v2 = foo(1)
v2.isDynamic() // to check that anything is resolvable
val v3 = foo(1, "")
v3.isDynamic() // to check that anything is resolvable
val v4 = foo<String>()
v4.isDynamic() // to check that anything is resolvable
val v5 = foo
v5.isDynamic() // to check that anything is resolvable
foo = 1
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
fun <!DYNAMIC_RECEIVER_NOT_ALLOWED!>dynamic<!>.test() {
val v1 = foo()
v1.isDynamic() // to check that anything is resolvable
@@ -1,11 +0,0 @@
// !MARK_DYNAMIC_CALLS
// !DIAGNOSTICS: -UNUSED_PARAMETER
fun dynamic.foo(s: String, a: Any) {}
fun dynamic.foo(s: Any, a: String) {}
fun test(d: dynamic) {
d.<!DEBUG_INFO_DYNAMIC!>foo<!>(1, "")
d.<!DEBUG_INFO_DYNAMIC!>foo<!>("", "")
d.<!DEBUG_INFO_DYNAMIC!>foo<!>(1, 1)
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// !MARK_DYNAMIC_CALLS
// !DIAGNOSTICS: -UNUSED_PARAMETER
@@ -1,7 +1,7 @@
// !MARK_DYNAMIC_CALLS
// !DIAGNOSTICS: -UNUSED_PARAMETER
fun dynamic.test() {
fun <!DYNAMIC_RECEIVER_NOT_ALLOWED!>dynamic<!>.test() {
<!DEBUG_INFO_DYNAMIC!>foo<!>()
<!DEBUG_INFO_DYNAMIC!>ext<!>()
@@ -57,7 +57,7 @@ class C {
val withInvoke = WithInvoke()
fun dynamic.test() {
fun <!DYNAMIC_RECEIVER_NOT_ALLOWED!>dynamic<!>.test() {
s()
this()
@@ -149,6 +149,7 @@ object StandardClassIds {
val DeprecatedSinceKotlin = "DeprecatedSinceKotlin".baseId()
val HidesMembers = "HidesMembers".internalId()
val DynamicExtension = "DynamicExtension".internalId()
val Retention = "Retention".annotationId()
val Target = "Target".annotationId()