From 227969d787e40c2aff2f5c468729686cea178459 Mon Sep 17 00:00:00 2001 From: Nikolay Lunyak Date: Wed, 4 Jan 2023 15:05:45 +0200 Subject: [PATCH] [FIR JS] Support DYNAMIC_RECEIVER_NOT_ALLOWED --- .../diagnostics/KtFirDataClassConverters.kt | 6 ++++ .../api/fir/diagnostics/KtFirDiagnostics.kt | 4 +++ .../fir/diagnostics/KtFirDiagnosticsImpl.kt | 5 ++++ .../diagnostics/FirDiagnosticsList.kt | 2 ++ .../fir/analysis/diagnostics/FirErrors.kt | 1 + .../checkers/CommonDeclarationCheckers.kt | 1 + .../declaration/FirDynamicReceiverChecker.kt | 29 +++++++++++++++++++ .../diagnostics/FirErrorsDefaultMessages.kt | 3 ++ .../withInvisibleSynthesized.fir.kt | 2 +- .../dynamicTypes/dynamicVsGeneric.fir.kt | 9 ------ .../dynamicTypes/dynamicVsGeneric.kt | 1 + .../dynamicTypes/extensionVals.fir.kt | 2 +- .../dynamicTypes/extensionVars.fir.kt | 2 +- .../dynamicTypes/extensions.fir.kt | 2 +- .../dynamicTypes/extensionsToDynamic.fir.kt | 14 ++++----- .../implicitDynamicReceiver.fir.kt | 18 ------------ .../dynamicTypes/implicitDynamicReceiver.kt | 1 + .../dynamicTypes/overloadingAmbiguity.fir.kt | 11 ------- .../dynamicTypes/overloadingAmbiguity.kt | 1 + .../staticCallsInDynamicContext.fir.kt | 4 +-- .../jetbrains/kotlin/name/StandardClassIds.kt | 1 + 21 files changed, 68 insertions(+), 51 deletions(-) create mode 100644 compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirDynamicReceiverChecker.kt delete mode 100644 compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/dynamicVsGeneric.fir.kt delete mode 100644 compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/implicitDynamicReceiver.fir.kt delete mode 100644 compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/overloadingAmbiguity.fir.kt diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDataClassConverters.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDataClassConverters.kt index 39af2d399aa..c674a65f095 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDataClassConverters.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDataClassConverters.kt @@ -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), diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnostics.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnostics.kt index 1a93918b446..1d4661da439 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnostics.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnostics.kt @@ -1435,6 +1435,10 @@ sealed class KtFirDiagnostic : KtDiagnosticWithPsi { override val diagnosticClass get() = DynamicUpperBound::class } + abstract class DynamicReceiverNotAllowed : KtFirDiagnostic() { + override val diagnosticClass get() = DynamicReceiverNotAllowed::class + } + abstract class IncompatibleTypes : KtFirDiagnostic() { override val diagnosticClass get() = IncompatibleTypes::class abstract val typeA: KtType diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnosticsImpl.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnosticsImpl.kt index 314171ee09b..8bcd2f7edbb 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnosticsImpl.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnosticsImpl.kt @@ -1727,6 +1727,11 @@ internal class DynamicUpperBoundImpl( override val token: KtLifetimeToken, ) : KtFirDiagnostic.DynamicUpperBound(), KtAbstractFirDiagnostic +internal class DynamicReceiverNotAllowedImpl( + override val firDiagnostic: KtPsiDiagnostic, + override val token: KtLifetimeToken, +) : KtFirDiagnostic.DynamicReceiverNotAllowed(), KtAbstractFirDiagnostic + internal class IncompatibleTypesImpl( override val typeA: KtType, override val typeB: KtType, diff --git a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt index b90a670ca97..18de3caaed4 100644 --- a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt +++ b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt @@ -674,6 +674,8 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") { val DYNAMIC_UPPER_BOUND by error() + val DYNAMIC_RECEIVER_NOT_ALLOWED by error() + val INCOMPATIBLE_TYPES by error { parameter("typeA") parameter("typeB") diff --git a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt index 0deb1a06694..a4a513f577e 100644 --- a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt +++ b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt @@ -417,6 +417,7 @@ object FirErrors { val DEPRECATED_TYPE_PARAMETER_SYNTAX by error0(SourceElementPositioningStrategies.TYPE_PARAMETERS_LIST) val MISPLACED_TYPE_PARAMETER_CONSTRAINTS by warning0() val DYNAMIC_UPPER_BOUND by error0() + val DYNAMIC_RECEIVER_NOT_ALLOWED by error0() val INCOMPATIBLE_TYPES by error2() val INCOMPATIBLE_TYPES_WARNING by warning2() val TYPE_VARIANCE_CONFLICT_ERROR by error4(SourceElementPositioningStrategies.DECLARATION_SIGNATURE_OR_DEFAULT) diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonDeclarationCheckers.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonDeclarationCheckers.kt index 61c4c51b271..6bac144ab23 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonDeclarationCheckers.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonDeclarationCheckers.kt @@ -38,6 +38,7 @@ object CommonDeclarationCheckers : DeclarationCheckers() { get() = setOf( FirKClassWithIncorrectTypeArgumentChecker, FirImplicitNothingReturnTypeChecker, + FirDynamicReceiverChecker, ) override val functionCheckers: Set diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirDynamicReceiverChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirDynamicReceiverChecker.kt new file mode 100644 index 00000000000..42ca95f2da9 --- /dev/null +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirDynamicReceiverChecker.kt @@ -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) + } + } +} \ No newline at end of file diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrorsDefaultMessages.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrorsDefaultMessages.kt index d9492579a6a..5ca9de4c48c 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrorsDefaultMessages.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrorsDefaultMessages.kt @@ -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, diff --git a/compiler/testData/diagnostics/tests/dynamicTypes/withInvisibleSynthesized.fir.kt b/compiler/testData/diagnostics/tests/dynamicTypes/withInvisibleSynthesized.fir.kt index f10ce8fde54..d79cef78101 100644 --- a/compiler/testData/diagnostics/tests/dynamicTypes/withInvisibleSynthesized.fir.kt +++ b/compiler/testData/diagnostics/tests/dynamicTypes/withInvisibleSynthesized.fir.kt @@ -20,7 +20,7 @@ public class J { import p.* class K: J.C() { - fun dynamic.test() { + fun dynamic.test() { sam(null) sam( name = null, diff --git a/compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/dynamicVsGeneric.fir.kt b/compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/dynamicVsGeneric.fir.kt deleted file mode 100644 index 3fa50ae9805..00000000000 --- a/compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/dynamicVsGeneric.fir.kt +++ /dev/null @@ -1,9 +0,0 @@ -object X1 -object X2 - -class Inv - -fun dynamic.foo() = X1 -fun Inv.foo() = X2 - -fun test(): X2 = Inv().foo() diff --git a/compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/dynamicVsGeneric.kt b/compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/dynamicVsGeneric.kt index de608354e73..37828702408 100644 --- a/compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/dynamicVsGeneric.kt +++ b/compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/dynamicVsGeneric.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL object X1 object X2 diff --git a/compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/extensionVals.fir.kt b/compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/extensionVals.fir.kt index d466157ce4d..ebc8d05d636 100644 --- a/compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/extensionVals.fir.kt +++ b/compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/extensionVals.fir.kt @@ -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.onDynamicVal: Int get() = 1 class C { fun test(d: dynamic) { diff --git a/compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/extensionVars.fir.kt b/compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/extensionVars.fir.kt index a791fc20aaf..e1e0972cf37 100644 --- a/compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/extensionVars.fir.kt +++ b/compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/extensionVars.fir.kt @@ -47,7 +47,7 @@ var String.onStringVar: Int get() = 1 set(v) {} -var dynamic.onDynamicVar: Int +var dynamic.onDynamicVar: Int get() = 1 set(v) {} diff --git a/compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/extensions.fir.kt b/compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/extensions.fir.kt index 1928b0ce01c..2f9cc32d4db 100644 --- a/compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/extensions.fir.kt +++ b/compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/extensions.fir.kt @@ -25,7 +25,7 @@ fun test(d: dynamic) { fun Any.onAny() {} fun Any?.onNullableAny() {} fun String.onString() {} -fun dynamic.onDynamic() {} +fun dynamic.onDynamic() {} class C { fun test(d: dynamic) { diff --git a/compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/extensionsToDynamic.fir.kt b/compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/extensionsToDynamic.fir.kt index fa382fff4a5..ac2749c87a1 100644 --- a/compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/extensionsToDynamic.fir.kt +++ b/compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/extensionsToDynamic.fir.kt @@ -11,7 +11,7 @@ fun test(d: dynamic) { d.varOnDynamic = 1 } -fun dynamic.extTest() { +fun dynamic.extTest() { onDynamic() onNullableDynamic() @@ -32,12 +32,12 @@ fun dynamic.extTest() { } -fun dynamic.onDynamic() {} -fun dynamic?.onNullableDynamic() {} +fun dynamic.onDynamic() {} +fun dynamic?.onNullableDynamic() {} -val dynamic.valOnDynamic: Int get() = 1 +val dynamic.valOnDynamic: Int get() = 1 -var dynamic.varOnDynamic: Int +var dynamic.varOnDynamic: Int get() = 1 set(v) {} @@ -51,8 +51,8 @@ class ForMemberExtensions { d.memberExtensionVal = 1 } - val dynamic.memberExtensionVal: Int get() = 1 - var dynamic.memberExtensionVar: Int + val dynamic.memberExtensionVal: Int get() = 1 + var dynamic.memberExtensionVar: Int get() = 1 set(v) {} } diff --git a/compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/implicitDynamicReceiver.fir.kt b/compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/implicitDynamicReceiver.fir.kt deleted file mode 100644 index af01eb120a8..00000000000 --- a/compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/implicitDynamicReceiver.fir.kt +++ /dev/null @@ -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() - v4.isDynamic() // to check that anything is resolvable - - val v5 = foo - v5.isDynamic() // to check that anything is resolvable - - foo = 1 -} diff --git a/compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/implicitDynamicReceiver.kt b/compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/implicitDynamicReceiver.kt index b1701f648ed..93d380db008 100644 --- a/compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/implicitDynamicReceiver.kt +++ b/compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/implicitDynamicReceiver.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL fun dynamic.test() { val v1 = foo() v1.isDynamic() // to check that anything is resolvable diff --git a/compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/overloadingAmbiguity.fir.kt b/compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/overloadingAmbiguity.fir.kt deleted file mode 100644 index b2cd32f75a9..00000000000 --- a/compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/overloadingAmbiguity.fir.kt +++ /dev/null @@ -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.foo(1, "") - d.foo("", "") - d.foo(1, 1) -} diff --git a/compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/overloadingAmbiguity.kt b/compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/overloadingAmbiguity.kt index 57612fb6669..4be0dc21557 100644 --- a/compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/overloadingAmbiguity.kt +++ b/compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/overloadingAmbiguity.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL // !MARK_DYNAMIC_CALLS // !DIAGNOSTICS: -UNUSED_PARAMETER diff --git a/compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/staticCallsInDynamicContext.fir.kt b/compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/staticCallsInDynamicContext.fir.kt index 2b322cc893c..5f94f9ce08a 100644 --- a/compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/staticCallsInDynamicContext.fir.kt +++ b/compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/staticCallsInDynamicContext.fir.kt @@ -1,7 +1,7 @@ // !MARK_DYNAMIC_CALLS // !DIAGNOSTICS: -UNUSED_PARAMETER -fun dynamic.test() { +fun dynamic.test() { foo() ext() @@ -57,7 +57,7 @@ class C { val withInvoke = WithInvoke() - fun dynamic.test() { + fun dynamic.test() { s() this() diff --git a/core/compiler.common/src/org/jetbrains/kotlin/name/StandardClassIds.kt b/core/compiler.common/src/org/jetbrains/kotlin/name/StandardClassIds.kt index c3497c4ff38..4de7aebec4f 100644 --- a/core/compiler.common/src/org/jetbrains/kotlin/name/StandardClassIds.kt +++ b/core/compiler.common/src/org/jetbrains/kotlin/name/StandardClassIds.kt @@ -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()