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 dca1ef4efc2..e3cff078d1e 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 @@ -4987,6 +4987,28 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert token, ) } + add(FirJsErrors.WRONG_EXPORTED_DECLARATION) { firDiagnostic -> + WrongExportedDeclarationImpl( + firDiagnostic.a, + firDiagnostic as KtPsiDiagnostic, + token, + ) + } + add(FirJsErrors.NON_EXPORTABLE_TYPE) { firDiagnostic -> + NonExportableTypeImpl( + firDiagnostic.a, + firSymbolBuilder.typeBuilder.buildKtType(firDiagnostic.b), + firDiagnostic as KtPsiDiagnostic, + token, + ) + } + add(FirJsErrors.NON_CONSUMABLE_EXPORTED_IDENTIFIER) { firDiagnostic -> + NonConsumableExportedIdentifierImpl( + firDiagnostic.a, + firDiagnostic as KtPsiDiagnostic, + token, + ) + } add(FirJsErrors.DELEGATION_BY_DYNAMIC) { firDiagnostic -> DelegationByDynamicImpl( firDiagnostic as KtPsiDiagnostic, 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 eab55ec01a8..fc91b37d454 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 @@ -3466,6 +3466,22 @@ sealed class KtFirDiagnostic : KtDiagnosticWithPsi { override val diagnosticClass get() = NestedJsExport::class } + abstract class WrongExportedDeclaration : KtFirDiagnostic() { + override val diagnosticClass get() = WrongExportedDeclaration::class + abstract val kind: String + } + + abstract class NonExportableType : KtFirDiagnostic() { + override val diagnosticClass get() = NonExportableType::class + abstract val kind: String + abstract val type: KtType + } + + abstract class NonConsumableExportedIdentifier : KtFirDiagnostic() { + override val diagnosticClass get() = NonConsumableExportedIdentifier::class + abstract val name: String + } + abstract class DelegationByDynamic : KtFirDiagnostic() { override val diagnosticClass get() = DelegationByDynamic::class } 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 a944490be86..b7a056b9261 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 @@ -4195,6 +4195,25 @@ internal class NestedJsExportImpl( override val token: KtLifetimeToken, ) : KtFirDiagnostic.NestedJsExport(), KtAbstractFirDiagnostic +internal class WrongExportedDeclarationImpl( + override val kind: String, + override val firDiagnostic: KtPsiDiagnostic, + override val token: KtLifetimeToken, +) : KtFirDiagnostic.WrongExportedDeclaration(), KtAbstractFirDiagnostic + +internal class NonExportableTypeImpl( + override val kind: String, + override val type: KtType, + override val firDiagnostic: KtPsiDiagnostic, + override val token: KtLifetimeToken, +) : KtFirDiagnostic.NonExportableType(), KtAbstractFirDiagnostic + +internal class NonConsumableExportedIdentifierImpl( + override val name: String, + override val firDiagnostic: KtPsiDiagnostic, + override val token: KtLifetimeToken, +) : KtFirDiagnostic.NonConsumableExportedIdentifier(), KtAbstractFirDiagnostic + internal class DelegationByDynamicImpl( override val firDiagnostic: KtPsiDiagnostic, override val token: KtLifetimeToken, diff --git a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirJsDiagnosticsList.kt b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirJsDiagnosticsList.kt index 52e2cd0927a..eff7562ec44 100644 --- a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirJsDiagnosticsList.kt +++ b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirJsDiagnosticsList.kt @@ -98,6 +98,16 @@ object JS_DIAGNOSTICS_LIST : DiagnosticList("FirJsErrors") { val EXPORT by object : DiagnosticGroup("Export") { val NESTED_JS_EXPORT by error() + val WRONG_EXPORTED_DECLARATION by error(PositioningStrategy.DECLARATION_SIGNATURE_OR_DEFAULT) { + parameter("kind") + } + val NON_EXPORTABLE_TYPE by warning(PositioningStrategy.DECLARATION_SIGNATURE_OR_DEFAULT) { + parameter("kind") + parameter("type") + } + val NON_CONSUMABLE_EXPORTED_IDENTIFIER by warning(PositioningStrategy.DEFAULT) { + parameter("name") + } } val DYNAMICS by object : DiagnosticGroup("Dynamics") { diff --git a/compiler/fir/checkers/checkers.js/build.gradle.kts b/compiler/fir/checkers/checkers.js/build.gradle.kts index 7491e5b5af9..2ba0c1ed649 100644 --- a/compiler/fir/checkers/checkers.js/build.gradle.kts +++ b/compiler/fir/checkers/checkers.js/build.gradle.kts @@ -7,6 +7,7 @@ plugins { dependencies { api(project(":core:compiler.common.js")) + api(project(":js:js.ast")) api(project(":compiler:fir:checkers")) /* diff --git a/compiler/fir/checkers/checkers.js/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/js/FirJsErrors.kt b/compiler/fir/checkers/checkers.js/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/js/FirJsErrors.kt index cbc6c353e90..32390776759 100644 --- a/compiler/fir/checkers/checkers.js/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/js/FirJsErrors.kt +++ b/compiler/fir/checkers/checkers.js/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/js/FirJsErrors.kt @@ -81,6 +81,9 @@ object FirJsErrors { // Export val NESTED_JS_EXPORT by error0() + val WRONG_EXPORTED_DECLARATION by error1(SourceElementPositioningStrategies.DECLARATION_SIGNATURE_OR_DEFAULT) + val NON_EXPORTABLE_TYPE by warning2(SourceElementPositioningStrategies.DECLARATION_SIGNATURE_OR_DEFAULT) + val NON_CONSUMABLE_EXPORTED_IDENTIFIER by warning1() // Dynamics val DELEGATION_BY_DYNAMIC by error0() diff --git a/compiler/fir/checkers/checkers.js/src/org/jetbrains/kotlin/fir/analysis/diagnostics/js/FirJsErrorsDefaultMessages.kt b/compiler/fir/checkers/checkers.js/src/org/jetbrains/kotlin/fir/analysis/diagnostics/js/FirJsErrorsDefaultMessages.kt index 632a9214459..8e5446f6838 100644 --- a/compiler/fir/checkers/checkers.js/src/org/jetbrains/kotlin/fir/analysis/diagnostics/js/FirJsErrorsDefaultMessages.kt +++ b/compiler/fir/checkers/checkers.js/src/org/jetbrains/kotlin/fir/analysis/diagnostics/js/FirJsErrorsDefaultMessages.kt @@ -46,6 +46,8 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.js.FirJsErrors.NESTED_CLASS import org.jetbrains.kotlin.fir.analysis.diagnostics.js.FirJsErrors.NESTED_EXTERNAL_DECLARATION import org.jetbrains.kotlin.fir.analysis.diagnostics.js.FirJsErrors.NESTED_JS_EXPORT import org.jetbrains.kotlin.fir.analysis.diagnostics.js.FirJsErrors.NON_ABSTRACT_MEMBER_OF_EXTERNAL_INTERFACE +import org.jetbrains.kotlin.fir.analysis.diagnostics.js.FirJsErrors.NON_CONSUMABLE_EXPORTED_IDENTIFIER +import org.jetbrains.kotlin.fir.analysis.diagnostics.js.FirJsErrors.NON_EXPORTABLE_TYPE import org.jetbrains.kotlin.fir.analysis.diagnostics.js.FirJsErrors.NON_EXTERNAL_DECLARATION_IN_INAPPROPRIATE_FILE import org.jetbrains.kotlin.fir.analysis.diagnostics.js.FirJsErrors.OVERRIDING_EXTERNAL_FUN_WITH_OPTIONAL_PARAMS import org.jetbrains.kotlin.fir.analysis.diagnostics.js.FirJsErrors.OVERRIDING_EXTERNAL_FUN_WITH_OPTIONAL_PARAMS_WITH_FAKE @@ -54,6 +56,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.js.FirJsErrors.RUNTIME_ANNO import org.jetbrains.kotlin.fir.analysis.diagnostics.js.FirJsErrors.UNCHECKED_CAST_TO_EXTERNAL_INTERFACE import org.jetbrains.kotlin.fir.analysis.diagnostics.js.FirJsErrors.WRONG_BODY_OF_EXTERNAL_DECLARATION import org.jetbrains.kotlin.fir.analysis.diagnostics.js.FirJsErrors.WRONG_DEFAULT_VALUE_FOR_EXTERNAL_FUN_PARAMETER +import org.jetbrains.kotlin.fir.analysis.diagnostics.js.FirJsErrors.WRONG_EXPORTED_DECLARATION import org.jetbrains.kotlin.fir.analysis.diagnostics.js.FirJsErrors.WRONG_EXTERNAL_DECLARATION import org.jetbrains.kotlin.fir.analysis.diagnostics.js.FirJsErrors.WRONG_INITIALIZER_OF_EXTERNAL_DECLARATION import org.jetbrains.kotlin.fir.analysis.diagnostics.js.FirJsErrors.WRONG_JS_QUALIFIER @@ -169,6 +172,18 @@ object FirJsErrorsDefaultMessages : BaseDiagnosticRendererFactory() { ) map.put(EXTERNAL_INTERFACE_AS_CLASS_LITERAL, "Can't refer to external interface from class literal") map.put(NESTED_JS_EXPORT, "@JsExport is only allowed on files and top-level declarations") + map.put(WRONG_EXPORTED_DECLARATION, "Declaration of such kind ({0}) can''t be exported to JS", CommonRenderers.STRING) + map.put( + NON_EXPORTABLE_TYPE, + "Exported declaration uses non-exportable {0} type: {1}", + CommonRenderers.STRING, + FirDiagnosticRenderers.RENDER_TYPE, + ) + map.put( + NON_CONSUMABLE_EXPORTED_IDENTIFIER, + "Exported declaration contains non-consumable identifier '${0}', that can't be represented inside TS definitions and ESM", + CommonRenderers.STRING, + ) map.checkMissingMessages(FirJsErrors) } diff --git a/compiler/fir/checkers/checkers.js/src/org/jetbrains/kotlin/fir/analysis/js/checkers/FirJsHelpers.kt b/compiler/fir/checkers/checkers.js/src/org/jetbrains/kotlin/fir/analysis/js/checkers/FirJsHelpers.kt index 32f186eea49..f18a1a3b5f3 100644 --- a/compiler/fir/checkers/checkers.js/src/org/jetbrains/kotlin/fir/analysis/js/checkers/FirJsHelpers.kt +++ b/compiler/fir/checkers/checkers.js/src/org/jetbrains/kotlin/fir/analysis/js/checkers/FirJsHelpers.kt @@ -8,22 +8,22 @@ package org.jetbrains.kotlin.fir.analysis.js.checkers import org.jetbrains.kotlin.descriptors.Modality +import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.fir.FirSession +import org.jetbrains.kotlin.fir.analysis.checkers.* import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext -import org.jetbrains.kotlin.fir.analysis.checkers.directOverriddenFunctions -import org.jetbrains.kotlin.fir.analysis.checkers.getAnnotationStringParameter -import org.jetbrains.kotlin.fir.analysis.checkers.getContainingClassSymbol -import org.jetbrains.kotlin.fir.analysis.checkers.hasAnnotationOrInsideAnnotatedClass import org.jetbrains.kotlin.fir.declarations.* +import org.jetbrains.kotlin.fir.declarations.utils.* import org.jetbrains.kotlin.fir.declarations.utils.isExpect import org.jetbrains.kotlin.fir.declarations.utils.isExternal -import org.jetbrains.kotlin.fir.declarations.utils.isInterface -import org.jetbrains.kotlin.fir.declarations.utils.modality import org.jetbrains.kotlin.fir.isSubstitutionOrIntersectionOverride +import org.jetbrains.kotlin.fir.resolve.providers.firProvider import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol import org.jetbrains.kotlin.fir.symbols.SymbolInternals import org.jetbrains.kotlin.fir.symbols.impl.* import org.jetbrains.kotlin.js.PredefinedAnnotation +import org.jetbrains.kotlin.js.common.isES5IdentifierPart +import org.jetbrains.kotlin.js.common.isES5IdentifierStart import org.jetbrains.kotlin.name.JsStandardClassIds private val FirBasedSymbol<*>.isExternal @@ -72,6 +72,13 @@ fun FirBasedSymbol<*>.getJsName(session: FirSession): String? { return getAnnotationStringParameter(JsStandardClassIds.Annotations.JsName, session) } +fun sanitizeName(name: String): String { + if (name.isEmpty()) return "_" + + val first = name.first().let { if (it.isES5IdentifierStart()) it else '_' } + return first.toString() + name.drop(1).map { if (it.isES5IdentifierPart()) it else '_' }.joinToString("") +} + fun FirBasedSymbol<*>.isNativeObject(session: FirSession): Boolean { if (hasAnnotationOrInsideAnnotatedClass(JsStandardClassIds.Annotations.JsNative, session) || isEffectivelyExternal(session)) { return true @@ -109,8 +116,35 @@ fun FirBasedSymbol<*>.isPredefinedObject(session: FirSession): Boolean { return false } +fun FirBasedSymbol<*>.isExportedObject(session: FirSession): Boolean { + val declaration = fir + + if (declaration is FirMemberDeclaration) { + val visibility = declaration.visibility + if (visibility != Visibilities.Public && visibility != Visibilities.Protected) { + return false + } + } + + return when { + hasAnnotationOrInsideAnnotatedClass(JsStandardClassIds.Annotations.JsExportIgnore, session) -> false + hasAnnotationOrInsideAnnotatedClass(JsStandardClassIds.Annotations.JsExport, session) -> true + else -> getContainingFile(session)?.hasAnnotation(JsStandardClassIds.Annotations.JsExport, session) == true + } +} + +private fun FirBasedSymbol<*>.getContainingFile(session: FirSession): FirFile? { + return when (this) { + is FirCallableSymbol<*> -> session.firProvider.getFirCallableContainerFile(this) + is FirClassLikeSymbol<*> -> session.firProvider.getFirClassifierContainerFileIfAny(this) + else -> return null + } +} + fun FirBasedSymbol<*>.isNativeObject(context: CheckerContext) = isNativeObject(context.session) fun FirBasedSymbol<*>.isNativeInterface(context: CheckerContext) = isNativeInterface(context.session) fun FirBasedSymbol<*>.isPredefinedObject(context: CheckerContext) = isPredefinedObject(context.session) + +fun FirBasedSymbol<*>.isExportedObject(context: CheckerContext) = isExportedObject(context.session) diff --git a/compiler/fir/checkers/checkers.js/src/org/jetbrains/kotlin/fir/analysis/js/checkers/JsDeclarationCheckers.kt b/compiler/fir/checkers/checkers.js/src/org/jetbrains/kotlin/fir/analysis/js/checkers/JsDeclarationCheckers.kt index 8234af156a1..0a78b010d6b 100644 --- a/compiler/fir/checkers/checkers.js/src/org/jetbrains/kotlin/fir/analysis/js/checkers/JsDeclarationCheckers.kt +++ b/compiler/fir/checkers/checkers.js/src/org/jetbrains/kotlin/fir/analysis/js/checkers/JsDeclarationCheckers.kt @@ -28,6 +28,7 @@ object JsDeclarationCheckers : DeclarationCheckers() { FirJsExternalFileChecker, FirJsNameChecker, FirJsExportAnnotationChecker, + FirJsExportDeclarationChecker, ) override val classCheckers: Set diff --git a/compiler/fir/checkers/checkers.js/src/org/jetbrains/kotlin/fir/analysis/js/checkers/declaration/FirJsExportDeclarationChecker.kt b/compiler/fir/checkers/checkers.js/src/org/jetbrains/kotlin/fir/analysis/js/checkers/declaration/FirJsExportDeclarationChecker.kt new file mode 100644 index 00000000000..4d27da0b6be --- /dev/null +++ b/compiler/fir/checkers/checkers.js/src/org/jetbrains/kotlin/fir/analysis/js/checkers/declaration/FirJsExportDeclarationChecker.kt @@ -0,0 +1,224 @@ +/* + * 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.js.checkers.declaration + +import org.jetbrains.kotlin.KtFakeSourceElementKind +import org.jetbrains.kotlin.descriptors.ClassKind +import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext +import org.jetbrains.kotlin.diagnostics.DiagnosticReporter +import org.jetbrains.kotlin.diagnostics.reportOn +import org.jetbrains.kotlin.fir.FirSession +import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirBasicDeclarationChecker +import org.jetbrains.kotlin.fir.analysis.checkers.getAnnotationFirstArgument +import org.jetbrains.kotlin.fir.analysis.checkers.isTopLevel +import org.jetbrains.kotlin.fir.analysis.diagnostics.js.FirJsErrors +import org.jetbrains.kotlin.fir.analysis.js.checkers.isEffectivelyExternal +import org.jetbrains.kotlin.fir.analysis.js.checkers.isExportedObject +import org.jetbrains.kotlin.fir.analysis.js.checkers.sanitizeName +import org.jetbrains.kotlin.fir.declarations.* +import org.jetbrains.kotlin.fir.declarations.utils.* +import org.jetbrains.kotlin.fir.expressions.FirConstExpression +import org.jetbrains.kotlin.fir.symbols.SymbolInternals +import org.jetbrains.kotlin.fir.types.* +import org.jetbrains.kotlin.js.common.RESERVED_KEYWORDS +import org.jetbrains.kotlin.js.common.SPECIAL_KEYWORDS +import org.jetbrains.kotlin.name.JsStandardClassIds + +object FirJsExportDeclarationChecker : FirBasicDeclarationChecker() { + override fun check(declaration: FirDeclaration, context: CheckerContext, reporter: DiagnosticReporter) { + if (!declaration.symbol.isExportedObject(context) || declaration !is FirMemberDeclaration) { + return + } + + fun checkTypeParameter(typeParameter: FirTypeParameterRef) { + for (upperBound in typeParameter.symbol.resolvedBounds) { + if (!upperBound.type.isExportable(context.session)) { + reporter.reportOn(typeParameter.source, FirJsErrors.NON_EXPORTABLE_TYPE, "upper bound", upperBound.type, context) + } + } + } + + fun checkValueParameter(valueParameter: FirValueParameter) { + val type = valueParameter.returnTypeRef.coneType + if (!type.isExportable(context.session)) { + reporter.reportOn(valueParameter.source, FirJsErrors.NON_EXPORTABLE_TYPE, "parameter", type, context) + } + } + + val hasJsName = declaration.hasAnnotation(JsStandardClassIds.Annotations.JsName, context.session) + + fun reportWrongExportedDeclaration(kind: String) { + reporter.reportOn(declaration.source, FirJsErrors.WRONG_EXPORTED_DECLARATION, kind, context) + } + + if (declaration.isExpect) { + reportWrongExportedDeclaration("expect") + } + + validateDeclarationOnConsumableName(declaration, context, reporter) + + when (declaration) { + is FirFunction -> { + for (typeParameter in declaration.typeParameters) { + checkTypeParameter(typeParameter) + } + + if (declaration.isInlineWithReified) { + reportWrongExportedDeclaration("inline function with reified type parameters") + return + } + + if (declaration.isSuspend) { + reportWrongExportedDeclaration("suspend function") + return + } + + if (declaration is FirConstructor && !declaration.isPrimary && !hasJsName) { + reportWrongExportedDeclaration("secondary constructor without @JsName") + } + + // Properties are checked instead of property accessors + if (declaration is FirPropertyAccessor) { + return + } + + for (parameter in declaration.valueParameters) { + checkValueParameter(parameter) + } + + val returnType = declaration.returnTypeRef.coneType + + if (!returnType.isExportable(context.session)) { + reporter.reportOn(declaration.source, FirJsErrors.NON_EXPORTABLE_TYPE, "return type", returnType, context) + } + } + + is FirProperty -> { + if (declaration.source?.kind == KtFakeSourceElementKind.PropertyFromParameter) { + return + } + + if (declaration.isExtension) { + reportWrongExportedDeclaration("extension property") + return + } + + val returnType = declaration.returnTypeRef.coneType + + if (!returnType.isExportable(context.session)) { + reporter.reportOn(declaration.source, FirJsErrors.NON_EXPORTABLE_TYPE, "return type", returnType, context) + } + } + + is FirClass -> { + for (typeParameter in declaration.typeParameters) { + checkTypeParameter(typeParameter) + } + + val wrongDeclaration: String? = when (declaration.classKind) { + ClassKind.ANNOTATION_CLASS -> "annotation class" + ClassKind.CLASS -> when { + context.isInsideInterface -> "nested class inside exported interface" + declaration.isInline -> "value class" + else -> null + } + else -> if (context.isInsideInterface) { + "${if (declaration.status.isCompanion) "companion object" else "nested/inner declaration"} inside exported interface" + } else null + } + + if (wrongDeclaration != null) { + reportWrongExportedDeclaration(wrongDeclaration) + } + } + + else -> {} + } + } + + private val CheckerContext.isInsideInterface + get(): Boolean { + val parent = containingDeclarations.lastOrNull() as? FirClass + return parent != null && parent.isInterface + } + + private val FirCallableDeclaration.isInlineWithReified: Boolean + get() = when (this) { + is FirPropertyAccessor -> { + @OptIn(SymbolInternals::class) + this.propertySymbol.fir.isInlineWithReified + } + else -> typeParameters.any { it.symbol.isReified } + } + + private fun ConeKotlinType.isExportableReturn(session: FirSession, currentlyProcessed: MutableSet = mutableSetOf()) = + isUnit || isExportable(session, currentlyProcessed) + + private fun ConeKotlinType.isExportable( + session: FirSession, + currentlyProcessed: MutableSet = mutableSetOf(), + ): Boolean { + if (!currentlyProcessed.add(this)) { + return true + } + + currentlyProcessed.add(this) + val hasNonExportableArgument = typeArguments.any { it.type?.isExportable(session, currentlyProcessed) != true } + + if (hasNonExportableArgument) { + currentlyProcessed.remove(this) + return false + } + + currentlyProcessed.remove(this) + + if (isBasicFunctionType(session)) { + typeArguments.lastOrNull()?.type?.isExportableReturn(session, currentlyProcessed) + } + + val nonNullable = withNullability(ConeNullability.NOT_NULL, session.typeContext) + val isPrimitiveExportableType = nonNullable.isAny || nonNullable.isNullableAny + || nonNullable is ConeDynamicType || isPrimitiveExportableConeKotlinType + val symbol = toSymbol(session) + + return when { + isPrimitiveExportableType -> true + @OptIn(SymbolInternals::class) + symbol?.fir is FirMemberDeclaration -> false + isEnum -> true + else -> symbol?.isEffectivelyExternal(session) == true || symbol?.isExportedObject(session) == true + } + } + + private val ConeKotlinType.isPrimitiveExportableConeKotlinType: Boolean + get() = this is ConeTypeParameterType + || isBoolean + || isThrowableOrNullableThrowable + || isString + || isPrimitiveNumberOrNullableType && !isLong + || isNothingOrNullableNothing + || isArrayType + + private fun validateDeclarationOnConsumableName( + declaration: FirMemberDeclaration, + context: CheckerContext, + reporter: DiagnosticReporter, + ) { + if (!context.isTopLevel || declaration.nameOrSpecialName.isSpecial) { + return + } + + val jsNameArgument = declaration.symbol.getAnnotationFirstArgument(JsStandardClassIds.Annotations.JsName, context.session) + val reportTarget = jsNameArgument?.source ?: declaration.source + val name = (jsNameArgument as? FirConstExpression<*>)?.value as? String ?: declaration.nameOrSpecialName.asString() + + if (name in SPECIAL_KEYWORDS || (name !in RESERVED_KEYWORDS && sanitizeName(name) == name)) { + return + } + + reporter.reportOn(reportTarget, FirJsErrors.NON_CONSUMABLE_EXPORTED_IDENTIFIER, name, context) + } +} diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirHelpers.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirHelpers.kt index 948a9ef6173..46b8a677f52 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirHelpers.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirHelpers.kt @@ -736,9 +736,13 @@ fun FirBasedSymbol<*>.hasAnnotationOrInsideAnnotatedClass(classId: ClassId, sess fun FirDeclaration.hasAnnotationOrInsideAnnotatedClass(classId: ClassId, session: FirSession) = symbol.hasAnnotationOrInsideAnnotatedClass(classId, session) -fun FirBasedSymbol<*>.getAnnotationStringParameter(classId: ClassId, session: FirSession): String? { +fun FirBasedSymbol<*>.getAnnotationFirstArgument(classId: ClassId, session: FirSession): FirExpression? { val annotation = getAnnotationByClassId(classId, session) as? FirAnnotationCall - val expression = annotation?.argumentMapping?.mapping?.values?.firstOrNull() as? FirConstExpression<*> + return annotation?.argumentMapping?.mapping?.values?.firstOrNull() +} + +fun FirBasedSymbol<*>.getAnnotationStringParameter(classId: ClassId, session: FirSession): String? { + val expression = getAnnotationFirstArgument(classId, session) as? FirConstExpression<*> return expression?.value as? String } diff --git a/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/ConeBuiltinTypeUtils.kt b/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/ConeBuiltinTypeUtils.kt index 865b9c7253f..51d15446293 100644 --- a/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/ConeBuiltinTypeUtils.kt +++ b/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/ConeBuiltinTypeUtils.kt @@ -26,7 +26,10 @@ val ConeKotlinType.isBoolean: Boolean get() = isBuiltinType(StandardClassIds.Boo val ConeKotlinType.isNullableBoolean: Boolean get() = isBuiltinType(StandardClassIds.Boolean, true) val ConeKotlinType.isBooleanOrNullableBoolean: Boolean get() = isBuiltinType(StandardClassIds.Boolean, null) +val ConeKotlinType.isThrowableOrNullableThrowable: Boolean get() = isAnyOfBuiltinType(setOf(StandardClassIds.Throwable)) + val ConeKotlinType.isChar: Boolean get() = isBuiltinType(StandardClassIds.Char, false) +val ConeKotlinType.isCharOrNullableChar: Boolean get() = isAnyOfBuiltinType(setOf(StandardClassIds.Char)) val ConeKotlinType.isString: Boolean get() = isBuiltinType(StandardClassIds.String, false) val ConeKotlinType.isEnum: Boolean get() = isBuiltinType(StandardClassIds.Enum, false) @@ -37,6 +40,8 @@ val ConeKotlinType.isUInt: Boolean get() = isBuiltinType(StandardClassIds.UInt, val ConeKotlinType.isULong: Boolean get() = isBuiltinType(StandardClassIds.ULong, false) val ConeKotlinType.isPrimitiveOrNullablePrimitive: Boolean get() = isAnyOfBuiltinType(StandardClassIds.primitiveTypes) val ConeKotlinType.isPrimitive: Boolean get() = isPrimitiveOrNullablePrimitive && nullability == ConeNullability.NOT_NULL +val ConeKotlinType.isPrimitiveNumberOrNullableType: Boolean + get() = isPrimitiveOrNullablePrimitive && !isBooleanOrNullableBoolean && !isCharOrNullableChar val ConeKotlinType.isArrayType: Boolean get() { return isBuiltinType(StandardClassIds.Array, false) || diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/FirVisibilityChecker.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/FirVisibilityChecker.kt index 4e161ad7266..626c42c8f5c 100644 --- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/FirVisibilityChecker.kt +++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/FirVisibilityChecker.kt @@ -540,15 +540,6 @@ fun FirBasedSymbol<*>.getOwnerLookupTag(): ConeClassLikeLookupTag? { } } -fun FirClassLikeSymbol<*>.getContainingClassLookupTag(): ConeClassLikeLookupTag? { - return if (classId.isLocal) { - (fir as? FirRegularClass)?.containingClassForLocal() - } else { - val ownerId = classId.outerClassId - ownerId?.let { it.toLookupTag() } - } -} - fun FirBasedSymbol<*>.isVariableOrNamedFunction(): Boolean { return this is FirVariableSymbol || this is FirNamedFunctionSymbol || this is FirPropertyAccessorSymbol } diff --git a/compiler/fir/raw-fir/raw-fir.common/src/org/jetbrains/kotlin/fir/builder/BaseFirBuilder.kt b/compiler/fir/raw-fir/raw-fir.common/src/org/jetbrains/kotlin/fir/builder/BaseFirBuilder.kt index f46d391a9fa..068c99c74cf 100644 --- a/compiler/fir/raw-fir/raw-fir.common/src/org/jetbrains/kotlin/fir/builder/BaseFirBuilder.kt +++ b/compiler/fir/raw-fir/raw-fir.common/src/org/jetbrains/kotlin/fir/builder/BaseFirBuilder.kt @@ -233,7 +233,10 @@ abstract class BaseFirBuilder(val baseSession: FirSession, val context: Conte fun constructorTypeParametersFromConstructedClass(ownerTypeParameters: List): List { return ownerTypeParameters.mapNotNull { val declaredTypeParameter = (it as? FirTypeParameter) ?: return@mapNotNull null - buildConstructedClassTypeParameterRef { symbol = declaredTypeParameter.symbol } + buildConstructedClassTypeParameterRef { + source = declaredTypeParameter.symbol.source?.fakeElement(KtFakeSourceElementKind.ConstructorTypeParameter) + symbol = declaredTypeParameter.symbol + } } } diff --git a/compiler/fir/raw-fir/raw-fir.common/src/org/jetbrains/kotlin/fir/builder/Context.kt b/compiler/fir/raw-fir/raw-fir.common/src/org/jetbrains/kotlin/fir/builder/Context.kt index 7f7e644569c..9c20a389ae2 100644 --- a/compiler/fir/raw-fir/raw-fir.common/src/org/jetbrains/kotlin/fir/builder/Context.kt +++ b/compiler/fir/raw-fir/raw-fir.common/src/org/jetbrains/kotlin/fir/builder/Context.kt @@ -13,6 +13,7 @@ import org.jetbrains.kotlin.fir.PrivateForInline import org.jetbrains.kotlin.fir.declarations.FirTypeParameterRef import org.jetbrains.kotlin.fir.declarations.builder.buildOuterClassTypeParameterRef import org.jetbrains.kotlin.fir.expressions.FirExpression +import org.jetbrains.kotlin.fir.symbols.impl.FirFileSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol import org.jetbrains.kotlin.fir.types.ConeClassLikeType import org.jetbrains.kotlin.name.ClassId @@ -48,6 +49,7 @@ class Context { var forcedElementSourceKind: KtSourceElementKind? = null val dispatchReceiverTypesStack = mutableListOf() var containerIsExpect: Boolean = false + var containingFileSymbol: FirFileSymbol? = null fun pushFirTypeParameters(isInnerOrLocal: Boolean, parameters: List) { capturedTypeParameters.add(StatusFirTypeParameterSymbolList(isInnerOrLocal, parameters.map { it.symbol })) diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/ClassMembers.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/ClassMembers.kt index ade444ae354..7c2e9e1a2aa 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/ClassMembers.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/ClassMembers.kt @@ -10,9 +10,11 @@ import org.jetbrains.kotlin.fir.declarations.utils.isLocal import org.jetbrains.kotlin.fir.declarations.utils.isSynthetic import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol import org.jetbrains.kotlin.fir.types.ConeClassLikeType import org.jetbrains.kotlin.fir.types.ConeIntersectionType import org.jetbrains.kotlin.fir.types.ConeKotlinType +import org.jetbrains.kotlin.fir.types.toLookupTag fun FirCallableSymbol<*>.dispatchReceiverClassTypeOrNull(): ConeClassLikeType? = fir.dispatchReceiverClassTypeOrNull() @@ -41,6 +43,15 @@ fun FirRegularClass.containingClassForLocal(): ConeClassLikeLookupTag? = fun FirDanglingModifierList.containingClass(): ConeClassLikeLookupTag? = containingClassAttr +fun FirClassLikeSymbol<*>.getContainingClassLookupTag(): ConeClassLikeLookupTag? { + return if (classId.isLocal) { + (fir as? FirRegularClass)?.containingClassForLocal() + } else { + val ownerId = classId.outerClassId + ownerId?.toLookupTag() + } +} + private object ContainingClassKey : FirDeclarationDataKey() var FirCallableDeclaration.containingClassForStaticMemberAttr: ConeClassLikeLookupTag? by FirDeclarationDataRegistry.data(ContainingClassKey) var FirRegularClass.containingClassForLocalAttr: ConeClassLikeLookupTag? by FirDeclarationDataRegistry.data(ContainingClassKey) diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/comparators/FirMemberDeclarationComparator.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/comparators/FirMemberDeclarationComparator.kt index eaae32ce341..3416ddceb55 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/comparators/FirMemberDeclarationComparator.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/comparators/FirMemberDeclarationComparator.kt @@ -7,9 +7,9 @@ package org.jetbrains.kotlin.fir.declarations.comparators import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.utils.classId +import org.jetbrains.kotlin.fir.declarations.utils.nameOrSpecialName import org.jetbrains.kotlin.fir.render import org.jetbrains.kotlin.fir.types.FirTypeRefComparator -import org.jetbrains.kotlin.name.Name object FirMemberDeclarationComparator : Comparator { // Comparing different kinds of callable members by assigning distinct priorities to those members. @@ -28,16 +28,6 @@ object FirMemberDeclarationComparator : Comparator { is FirBackingField -> 0 } - private val FirMemberDeclaration.name: Name - get() = when (this) { - is FirCallableDeclaration -> - this.symbol.callableId.callableName - is FirClass -> - this.classId.shortClassName - is FirTypeAlias -> - this.name - } - override fun compare(a: FirMemberDeclaration, b: FirMemberDeclaration): Int { val priorityDiff = a.priority - b.priority if (priorityDiff != 0) { @@ -51,7 +41,7 @@ object FirMemberDeclarationComparator : Comparator { return 0 } - return a.name.compareTo(b.name) + return a.nameOrSpecialName.compareTo(b.nameOrSpecialName) } } diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/utils/FirDeclarationUtil.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/utils/FirDeclarationUtil.kt index daad3d7d67b..9a888a2700f 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/utils/FirDeclarationUtil.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/utils/FirDeclarationUtil.kt @@ -9,6 +9,7 @@ import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.types.ConeClassLikeType import org.jetbrains.kotlin.fir.types.coneTypeSafe import org.jetbrains.kotlin.name.ClassId +import org.jetbrains.kotlin.name.Name val FirTypeAlias.expandedConeType: ConeClassLikeType? get() = expandedTypeRef.coneTypeSafe() @@ -45,3 +46,13 @@ val FirDeclaration.isNonLocal } val FirCallableDeclaration.isExtension get() = receiverParameter != null + +val FirMemberDeclaration.nameOrSpecialName: Name + get() = when (this) { + is FirCallableDeclaration -> + this.symbol.callableId.callableName + is FirClass -> + this.classId.shortClassName + is FirTypeAlias -> + this.name + } diff --git a/compiler/frontend.common/src/org/jetbrains/kotlin/KtSourceElement.kt b/compiler/frontend.common/src/org/jetbrains/kotlin/KtSourceElement.kt index 2c23d80fc27..5064e86d674 100644 --- a/compiler/frontend.common/src/org/jetbrains/kotlin/KtSourceElement.kt +++ b/compiler/frontend.common/src/org/jetbrains/kotlin/KtSourceElement.kt @@ -58,6 +58,10 @@ sealed class KtFakeSourceElementKind(final override val shouldSkipErrorTypeRepor // with a fake source which refers to containing class object ImplicitConstructor : KtFakeSourceElementKind() + // for constructor type parameters, because they refer to the same source + // as the class type parameters themselves + object ConstructorTypeParameter : KtFakeSourceElementKind() + // for constructors which do not have delegated constructor call the fake one is generated // with a fake sources which refers to the original constructor object DelegatingConstructorCall : KtFakeSourceElementKind() diff --git a/compiler/testData/diagnostics/tests/annotations/annotationRenderingInTypes.fir.kt b/compiler/testData/diagnostics/tests/annotations/annotationRenderingInTypes.fir.kt index 323f5e83ce2..96cfc58038a 100644 --- a/compiler/testData/diagnostics/tests/annotations/annotationRenderingInTypes.fir.kt +++ b/compiler/testData/diagnostics/tests/annotations/annotationRenderingInTypes.fir.kt @@ -3,7 +3,7 @@ fun f1(x: String) {} fun f2(f: () -> Unit) {} -fun test1() = f2(::f1) +fun test1() = Unit): Unit")!>f2(::f1) @Target(AnnotationTarget.TYPE_PARAMETER, AnnotationTarget.TYPE) @@ -12,14 +12,14 @@ annotation class Ann fun <@Ann R : @Ann Any> f3(a: Array<@Ann R>): Array<@Ann R?> = null!! fun test2(a: @Ann Array) { - val r: Array = f3(a) + val r: Array = f3(; @R|Ann|() kotlin/Array")!>a) } var test3: Int = 0 - set(s: @Ann String) {} + set(s: @Ann String) {} fun f4(fn: (@Ann Int, @Ann Int) -> Unit) {} -val test4 = f4 { single -> } +val test4 = f4 ; kotlin/Function1<@R|Ann|() kotlin/Int, kotlin/Unit>")!>{ single -> } diff --git a/compiler/testData/diagnostics/tests/annotations/rendering/cannotOverrideInvisibleMember.fir.kt b/compiler/testData/diagnostics/tests/annotations/rendering/cannotOverrideInvisibleMember.fir.kt index 0fdf564fd21..4a996367de3 100644 --- a/compiler/testData/diagnostics/tests/annotations/rendering/cannotOverrideInvisibleMember.fir.kt +++ b/compiler/testData/diagnostics/tests/annotations/rendering/cannotOverrideInvisibleMember.fir.kt @@ -11,5 +11,5 @@ open class B1 { } class D1 : B1() { - override fun foo() {} + override fun foo() {} } diff --git a/compiler/testData/diagnostics/tests/annotations/rendering/memberProjectedOut.fir.kt b/compiler/testData/diagnostics/tests/annotations/rendering/memberProjectedOut.fir.kt index 3e7b3ab4e33..81579e7c57e 100644 --- a/compiler/testData/diagnostics/tests/annotations/rendering/memberProjectedOut.fir.kt +++ b/compiler/testData/diagnostics/tests/annotations/rendering/memberProjectedOut.fir.kt @@ -11,5 +11,5 @@ class C { } fun test(a: C) { - a[1] = 25 + a[1] = 25 } diff --git a/compiler/testData/diagnostics/tests/annotations/rendering/notImplementedMembers.fir.kt b/compiler/testData/diagnostics/tests/annotations/rendering/notImplementedMembers.fir.kt index 9ac88ba867c..ec0ea3ac401 100644 --- a/compiler/testData/diagnostics/tests/annotations/rendering/notImplementedMembers.fir.kt +++ b/compiler/testData/diagnostics/tests/annotations/rendering/notImplementedMembers.fir.kt @@ -15,7 +15,7 @@ interface B { fun a(@An arg: @An Int) } -interface C : A, B +interface C : A, B @An abstract class D { @@ -23,8 +23,8 @@ abstract class D { abstract val d: @An Int } -class E : D(), A -class F : A +class E : D(), A +class F : A @An interface G { @@ -44,5 +44,5 @@ interface GI : G { override fun a(@An arg: @An Int) {} } -class AG1(val a: A, val g: G) : A by a, G by g -class AG2() : AI, GI +class AG1(val a: A, val g: G) : A by a, G by g +class AG2() : AI, GI diff --git a/compiler/testData/diagnostics/tests/annotations/rendering/tooManyArguments.fir.kt b/compiler/testData/diagnostics/tests/annotations/rendering/tooManyArguments.fir.kt index a826e31f1d8..ac78ef1cccd 100644 --- a/compiler/testData/diagnostics/tests/annotations/rendering/tooManyArguments.fir.kt +++ b/compiler/testData/diagnostics/tests/annotations/rendering/tooManyArguments.fir.kt @@ -7,5 +7,5 @@ annotation class Ann(val s: String = "") fun foo() {} val bar = foo( - 15 + 15 ) diff --git a/compiler/testData/diagnostics/tests/annotations/rendering/typeMismatchDueToTypeProjections.fir.kt b/compiler/testData/diagnostics/tests/annotations/rendering/typeMismatchDueToTypeProjections.fir.kt index 23e9343c986..20778ae8362 100644 --- a/compiler/testData/diagnostics/tests/annotations/rendering/typeMismatchDueToTypeProjections.fir.kt +++ b/compiler/testData/diagnostics/tests/annotations/rendering/typeMismatchDueToTypeProjections.fir.kt @@ -13,5 +13,5 @@ class C { class Out fun test(a: C, y: Out) { - a + y + a + ; Out")!>y } diff --git a/compiler/testData/diagnostics/tests/annotations/rendering/typeMismatchOnOverride.fir.kt b/compiler/testData/diagnostics/tests/annotations/rendering/typeMismatchOnOverride.fir.kt index 0b1634aeb75..34763332c31 100644 --- a/compiler/testData/diagnostics/tests/annotations/rendering/typeMismatchOnOverride.fir.kt +++ b/compiler/testData/diagnostics/tests/annotations/rendering/typeMismatchOnOverride.fir.kt @@ -15,12 +15,12 @@ interface A { @An interface B : A { - override val p1: Int + override val p1: Int @An - override val p2: @An String - override fun test(arg: String): Int + override val p2: @An String + override fun test(arg: String): Int } interface C : A { - override var p2: Int + override var p2: Int } diff --git a/compiler/testData/diagnostics/tests/annotations/rendering/typeMismatchOnOverrideJavaNullable.fir.kt b/compiler/testData/diagnostics/tests/annotations/rendering/typeMismatchOnOverrideJavaNullable.fir.kt index e43eb6ba4c4..b0ca546837b 100644 --- a/compiler/testData/diagnostics/tests/annotations/rendering/typeMismatchOnOverrideJavaNullable.fir.kt +++ b/compiler/testData/diagnostics/tests/annotations/rendering/typeMismatchOnOverrideJavaNullable.fir.kt @@ -27,7 +27,7 @@ import org.jetbrains.annotations.NotNull; annotation class An class B : A { - override fun foo(): String? = null + override fun foo(): String? = null } @An @@ -38,5 +38,5 @@ public interface C { } class D : C { - override fun foo(): String? = null + override fun foo(): String? = null } diff --git a/compiler/testData/diagnostics/testsWithJsStdLib/export/secondaryConstructorWithoutJsName.fir.kt b/compiler/testData/diagnostics/testsWithJsStdLib/export/secondaryConstructorWithoutJsName.fir.kt deleted file mode 100644 index fb403ddd9db..00000000000 --- a/compiler/testData/diagnostics/testsWithJsStdLib/export/secondaryConstructorWithoutJsName.fir.kt +++ /dev/null @@ -1,15 +0,0 @@ -// !OPT_IN: kotlin.js.ExperimentalJsExport -// !RENDER_DIAGNOSTICS_MESSAGES - -package foo - -@JsExport -class C(val x: String) { - constructor(x: Int): this(x.toString()) -} - -@JsExport -class C2(val x: String) { - @JsName("JsNameProvided") - constructor(x: Int): this(x.toString()) -} diff --git a/compiler/testData/diagnostics/testsWithJsStdLib/export/secondaryConstructorWithoutJsName.kt b/compiler/testData/diagnostics/testsWithJsStdLib/export/secondaryConstructorWithoutJsName.kt index 0923d49f68c..aba1f8935d4 100644 --- a/compiler/testData/diagnostics/testsWithJsStdLib/export/secondaryConstructorWithoutJsName.kt +++ b/compiler/testData/diagnostics/testsWithJsStdLib/export/secondaryConstructorWithoutJsName.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL // !OPT_IN: kotlin.js.ExperimentalJsExport // !RENDER_DIAGNOSTICS_MESSAGES diff --git a/compiler/testData/diagnostics/testsWithJsStdLib/export/secondaryConstructorWithoutJsNameInExportedFile.fir.kt b/compiler/testData/diagnostics/testsWithJsStdLib/export/secondaryConstructorWithoutJsNameInExportedFile.fir.kt deleted file mode 100644 index 2c8acd755f3..00000000000 --- a/compiler/testData/diagnostics/testsWithJsStdLib/export/secondaryConstructorWithoutJsNameInExportedFile.fir.kt +++ /dev/null @@ -1,14 +0,0 @@ -// !OPT_IN: kotlin.js.ExperimentalJsExport -// !RENDER_DIAGNOSTICS_MESSAGES -@file:JsExport - -package foo - -class C(val x: String) { - constructor(x: Int): this(x.toString()) -} - -class C2(val x: String) { - @JsName("JsNameProvided") - constructor(x: Int): this(x.toString()) -} diff --git a/compiler/testData/diagnostics/testsWithJsStdLib/export/secondaryConstructorWithoutJsNameInExportedFile.kt b/compiler/testData/diagnostics/testsWithJsStdLib/export/secondaryConstructorWithoutJsNameInExportedFile.kt index f3a91ee8d6f..2c45e591bb9 100644 --- a/compiler/testData/diagnostics/testsWithJsStdLib/export/secondaryConstructorWithoutJsNameInExportedFile.kt +++ b/compiler/testData/diagnostics/testsWithJsStdLib/export/secondaryConstructorWithoutJsNameInExportedFile.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL // !OPT_IN: kotlin.js.ExperimentalJsExport // !RENDER_DIAGNOSTICS_MESSAGES @file:JsExport diff --git a/compiler/testData/diagnostics/testsWithJsStdLib/export/wrongExportedDeclaration.fir.kt b/compiler/testData/diagnostics/testsWithJsStdLib/export/wrongExportedDeclaration.fir.kt index 2122f4cef6a..c132e0c9d9a 100644 --- a/compiler/testData/diagnostics/testsWithJsStdLib/export/wrongExportedDeclaration.fir.kt +++ b/compiler/testData/diagnostics/testsWithJsStdLib/export/wrongExportedDeclaration.fir.kt @@ -4,18 +4,18 @@ package foo -@JsExport -inline fun inlineReifiedFun(x: Any) = x is T +@JsExport +inline fun inlineReifiedFun(x: Any) = x is T -@JsExport -suspend fun suspendFun() { } +@JsExport +suspend fun suspendFun() { } -@JsExport -val String.extensionProperty +@JsExport +val String.extensionProperty get() = this.length @JsExport -annotation class AnnotationClass +annotation class AnnotationClass @JsExport interface SomeInterface @@ -25,24 +25,24 @@ external interface GoodInterface @JsExport interface InterfaceWithCompanion { - companion object { + companion object { fun foo() = 42 } } @JsExport interface OuterInterface { - class Nested + class Nested } @JsExport -value class A(val a: Int) +value class A(val a: Int) @JsExport -inline class B(val b: Int) +inline class B(val b: Int) @JsExport -inline value class C(val c: Int) +inline value class C(val c: Int) @JsExport -value inline class D(val d: Int) +value inline class D(val d: Int) diff --git a/compiler/testData/diagnostics/testsWithJsStdLib/export/wrongExportedDeclarationInExportedFile.fir.kt b/compiler/testData/diagnostics/testsWithJsStdLib/export/wrongExportedDeclarationInExportedFile.fir.kt deleted file mode 100644 index 6f3e688790a..00000000000 --- a/compiler/testData/diagnostics/testsWithJsStdLib/export/wrongExportedDeclarationInExportedFile.fir.kt +++ /dev/null @@ -1,15 +0,0 @@ -// !OPT_IN: kotlin.js.ExperimentalJsExport -// !RENDER_DIAGNOSTICS_MESSAGES - -@file:JsExport - -package foo - -inline fun inlineReifiedFun(x: Any) = x is T - -suspend fun suspendFun() { } - -val String.extensionProperty - get() = this.length - -annotation class AnnotationClass diff --git a/compiler/testData/diagnostics/testsWithJsStdLib/export/wrongExportedDeclarationInExportedFile.kt b/compiler/testData/diagnostics/testsWithJsStdLib/export/wrongExportedDeclarationInExportedFile.kt index 41073b99c69..eb8c6b1206f 100644 --- a/compiler/testData/diagnostics/testsWithJsStdLib/export/wrongExportedDeclarationInExportedFile.kt +++ b/compiler/testData/diagnostics/testsWithJsStdLib/export/wrongExportedDeclarationInExportedFile.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL // !OPT_IN: kotlin.js.ExperimentalJsExport // !RENDER_DIAGNOSTICS_MESSAGES diff --git a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/directives/FirDiagnosticsDirectives.kt b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/directives/FirDiagnosticsDirectives.kt index 1049ebdc57b..298469adc48 100644 --- a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/directives/FirDiagnosticsDirectives.kt +++ b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/directives/FirDiagnosticsDirectives.kt @@ -43,6 +43,10 @@ object FirDiagnosticsDirectives : SimpleDirectivesContainer() { description = "Defines which parser should be used for FIR compiler" ) + val RENDER_DIAGNOSTICS_MESSAGES by directive( + description = "Forces diagnostic arguments to be rendered" + ) + val FIR_DISABLE_LAZY_RESOLVE_CHECKS by directive( description = "Temporary disables lazy resolve checks until the lazy resolve contract violation is fixed" ) diff --git a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/fir/handlers/FirDiagnosticsHandler.kt b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/fir/handlers/FirDiagnosticsHandler.kt index 9677194f0d6..18d978715a3 100644 --- a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/fir/handlers/FirDiagnosticsHandler.kt +++ b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/fir/handlers/FirDiagnosticsHandler.kt @@ -70,6 +70,7 @@ class FirDiagnosticsHandler(testServices: TestServices) : FirAnalysisHandler(tes val lightTreeComparingModeEnabled = FirDiagnosticsDirectives.COMPARE_WITH_LIGHT_TREE in currentModule.directives val lightTreeEnabled = currentModule.directives.singleValue(FirDiagnosticsDirectives.FIR_PARSER) == FirParser.LightTree + val forceRenderArguments = FirDiagnosticsDirectives.RENDER_DIAGNOSTICS_MESSAGES in currentModule.directives for (file in currentModule.files) { val firFile = info.mainFirFiles[file] ?: continue @@ -84,10 +85,11 @@ class FirDiagnosticsHandler(testServices: TestServices) : FirAnalysisHandler(tes diagnostics.diagnosticCodeMetaInfos( currentModule, file, diagnosticsService, globalMetadataInfoHandler, - lightTreeEnabled, lightTreeComparingModeEnabled + lightTreeEnabled, lightTreeComparingModeEnabled, + forceRenderArguments, ) globalMetadataInfoHandler.addMetadataInfosForFile(file, diagnosticsMetadataInfos) - collectSyntaxDiagnostics(currentModule, file, firFile, lightTreeEnabled, lightTreeComparingModeEnabled) + collectSyntaxDiagnostics(currentModule, file, firFile, lightTreeEnabled, lightTreeComparingModeEnabled, forceRenderArguments) collectDebugInfoDiagnostics(currentModule, file, firFile, lightTreeEnabled, lightTreeComparingModeEnabled) } } @@ -99,7 +101,8 @@ class FirDiagnosticsHandler(testServices: TestServices) : FirAnalysisHandler(tes testFile: TestFile, firFile: FirFile, lightTreeEnabled: Boolean, - lightTreeComparingModeEnabled: Boolean + lightTreeComparingModeEnabled: Boolean, + forceRenderArguments: Boolean, ) { val metaInfos = if (firFile.psi != null) { AnalyzingUtils.getSyntaxErrorRanges(firFile.psi!!).flatMap { @@ -109,7 +112,8 @@ class FirDiagnosticsHandler(testServices: TestServices) : FirAnalysisHandler(tes testFile, globalMetadataInfoHandler1 = globalMetadataInfoHandler, lightTreeEnabled, - lightTreeComparingModeEnabled + lightTreeComparingModeEnabled, + forceRenderArguments, ) } } else { @@ -120,7 +124,8 @@ class FirDiagnosticsHandler(testServices: TestServices) : FirAnalysisHandler(tes testFile, globalMetadataInfoHandler1 = globalMetadataInfoHandler, lightTreeEnabled, - lightTreeComparingModeEnabled + lightTreeComparingModeEnabled, + forceRenderArguments, ) } } @@ -323,7 +328,8 @@ fun List.diagnosticCodeMetaInfos( diagnosticsService: DiagnosticsService, globalMetadataInfoHandler: GlobalMetadataInfoHandler, lightTreeEnabled: Boolean, - lightTreeComparingModeEnabled: Boolean + lightTreeComparingModeEnabled: Boolean, + forceRenderArguments: Boolean = false, ): List = flatMap { diagnostic -> if (!diagnosticsService.shouldRenderDiagnostic( module, @@ -339,7 +345,8 @@ fun List.diagnosticCodeMetaInfos( file, globalMetadataInfoHandler, lightTreeEnabled, - lightTreeComparingModeEnabled + lightTreeComparingModeEnabled, + forceRenderArguments, ) } diff --git a/core/compiler.common.js/src/org/jetbrains/kotlin/name/JsStandardClassIds.kt b/core/compiler.common.js/src/org/jetbrains/kotlin/name/JsStandardClassIds.kt index dccd6c246cc..1d917f4cd79 100644 --- a/core/compiler.common.js/src/org/jetbrains/kotlin/name/JsStandardClassIds.kt +++ b/core/compiler.common.js/src/org/jetbrains/kotlin/name/JsStandardClassIds.kt @@ -42,7 +42,7 @@ object JsStandardClassIds { val JsExport = "JsExport".jsId() @JvmField - val JsExportIgnore = ClassId(JsExport.asSingleFqName(), Name.identifier("Ignore")) + val JsExportIgnore = JsExport.createNestedClassId(Name.identifier("Ignore")) @JvmField val annotationsRequiringExternal = setOf(JsModule, JsQualifier) diff --git a/core/compiler.common/src/org/jetbrains/kotlin/types/TypeSystemCommonBackendContext.kt b/core/compiler.common/src/org/jetbrains/kotlin/types/TypeSystemCommonBackendContext.kt index a73041b1e55..815afb465db 100644 --- a/core/compiler.common/src/org/jetbrains/kotlin/types/TypeSystemCommonBackendContext.kt +++ b/core/compiler.common/src/org/jetbrains/kotlin/types/TypeSystemCommonBackendContext.kt @@ -40,7 +40,6 @@ interface TypeSystemCommonBackendContext : TypeSystemContext { fun KotlinTypeMarker.makeNullable(): KotlinTypeMarker = asSimpleType()?.withNullability(true) ?: this - fun TypeConstructorMarker.getPrimitiveType(): PrimitiveType? fun TypeConstructorMarker.getPrimitiveArrayType(): PrimitiveType?