diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java index 5602232b8b4..7abc07e97da 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java @@ -10612,6 +10612,12 @@ public class DiagnosisCompilerTestFE10TestdataTestGenerated extends AbstractDiag runTest("compiler/testData/diagnostics/tests/extensions/contextReceivers/insideDeclaration.kt"); } + @Test + @TestMetadata("labelsFromClassNameForbidden.kt") + public void testLabelsFromClassNameForbidden() throws Exception { + runTest("compiler/testData/diagnostics/tests/extensions/contextReceivers/labelsFromClassNameForbidden.kt"); + } + @Test @TestMetadata("lazy.kt") public void testLazy() throws Exception { diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/PsiSourceCompilerForInline.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/PsiSourceCompilerForInline.kt index 958610cd83e..e80fce70d56 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/PsiSourceCompilerForInline.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/PsiSourceCompilerForInline.kt @@ -437,7 +437,7 @@ fun getDeclarationLabels(lambdaOrFun: PsiElement?, descriptor: DeclarationDescri val result = HashSet() if (lambdaOrFun != null) { - val label = LabelResolver.getLabelNamesIfAny(lambdaOrFun, addContextReceiverNames = false) + val label = LabelResolver.getLabelNamesIfAny(lambdaOrFun, addClassNameLabels = false) if (label.isNotEmpty()) { result.add(label.single().asString()) } diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java index dcb27cef464..50c0a31e357 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java @@ -10612,6 +10612,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti runTest("compiler/testData/diagnostics/tests/extensions/contextReceivers/insideDeclaration.kt"); } + @Test + @TestMetadata("labelsFromClassNameForbidden.kt") + public void testLabelsFromClassNameForbidden() throws Exception { + runTest("compiler/testData/diagnostics/tests/extensions/contextReceivers/labelsFromClassNameForbidden.kt"); + } + @Test @TestMetadata("lazy.kt") public void testLazy() throws Exception { diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java index b1d87339036..4a821d9e20d 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java @@ -10612,6 +10612,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac runTest("compiler/testData/diagnostics/tests/extensions/contextReceivers/insideDeclaration.kt"); } + @Test + @TestMetadata("labelsFromClassNameForbidden.kt") + public void testLabelsFromClassNameForbidden() throws Exception { + runTest("compiler/testData/diagnostics/tests/extensions/contextReceivers/labelsFromClassNameForbidden.kt"); + } + @Test @TestMetadata("lazy.kt") public void testLazy() throws Exception { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/FunctionDescriptorResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/FunctionDescriptorResolver.kt index 222911ec8fe..7a885039a77 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/FunctionDescriptorResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/FunctionDescriptorResolver.kt @@ -228,32 +228,36 @@ class FunctionDescriptorResolver( } } - val receiverToLabelMap = linkedMapOf() val extensionReceiver = receiverType?.let { - val splitter = AnnotationSplitter(storageManager, receiverType.annotations, EnumSet.of(AnnotationUseSiteTarget.RECEIVER)) + val splitter = AnnotationSplitter(storageManager, it.annotations, EnumSet.of(AnnotationUseSiteTarget.RECEIVER)) DescriptorFactory.createExtensionReceiverParameterForCallable( functionDescriptor, it, splitter.getAnnotationsForTarget(AnnotationUseSiteTarget.RECEIVER) ) - }?.apply { - val extensionReceiverName = receiverTypeRef?.nameForReceiverLabel() - if (extensionReceiverName != null) { - receiverToLabelMap[this] = extensionReceiverName - } } - - val contextReceiverDescriptors = contextReceiverTypes.mapNotNull { type -> - val splitter = AnnotationSplitter(storageManager, type.annotations, EnumSet.of(AnnotationUseSiteTarget.RECEIVER)) + val contextReceiverDescriptors = contextReceiverTypes.mapNotNull { + val splitter = AnnotationSplitter(storageManager, it.annotations, EnumSet.of(AnnotationUseSiteTarget.RECEIVER)) DescriptorFactory.createContextReceiverParameterForCallable( - functionDescriptor, type, splitter.getAnnotationsForTarget(AnnotationUseSiteTarget.RECEIVER) + functionDescriptor, it, splitter.getAnnotationsForTarget(AnnotationUseSiteTarget.RECEIVER) ) } - contextReceiverDescriptors.zip(0 until contextReceivers.size).reversed() - .forEach { (contextReceiverDescriptor, i) -> - contextReceivers[i].name()?.let { - receiverToLabelMap[contextReceiverDescriptor] = it + + if (languageVersionSettings.supportsFeature(LanguageFeature.ContextReceivers)) { + val receiverToLabelMap = linkedMapOf() + if (receiverTypeRef != null && extensionReceiver != null) { + receiverTypeRef.nameForReceiverLabel()?.let { + receiverToLabelMap[extensionReceiver] = it } } - trace.record(BindingContext.DESCRIPTOR_TO_NAMED_RECEIVERS, functionDescriptor, receiverToLabelMap) + contextReceiverDescriptors.zip(0 until contextReceivers.size).reversed() + .forEach { (contextReceiverDescriptor, i) -> + contextReceivers[i].name()?.let { + receiverToLabelMap[contextReceiverDescriptor] = it + } + } + + trace.record(BindingContext.DESCRIPTOR_TO_NAMED_RECEIVERS, functionDescriptor, receiverToLabelMap) + } + functionDescriptor.initialize( extensionReceiver, getDispatchReceiverParameterIfNeeded(container), diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/LabelResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/LabelResolver.kt index de22a258a0b..97a45912340 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/LabelResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/LabelResolver.kt @@ -17,6 +17,7 @@ package org.jetbrains.kotlin.types.expressions import com.intellij.psi.PsiElement +import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.diagnostics.Errors.LABEL_NAME_CLASH import org.jetbrains.kotlin.diagnostics.Errors.UNRESOLVED_REFERENCE @@ -33,12 +34,12 @@ object LabelResolver { private fun getElementsByLabelName( labelName: Name, labelExpression: KtSimpleNameExpression, - isThisExpression: Boolean + classNameLabelsEnabled: Boolean ): Set { val elements = linkedSetOf() var parent: PsiElement? = labelExpression.parent while (parent != null) { - val names = getLabelNamesIfAny(parent, isThisExpression) + val names = getLabelNamesIfAny(parent, classNameLabelsEnabled) if (names.contains(labelName)) { elements.add(getExpressionUnderLabel(parent as KtExpression)) } @@ -47,7 +48,7 @@ object LabelResolver { return elements } - fun getLabelNamesIfAny(element: PsiElement, addContextReceiverNames: Boolean): List { + fun getLabelNamesIfAny(element: PsiElement, addClassNameLabels: Boolean): List { val result = mutableListOf() when (element) { is KtLabeledExpression -> result.addIfNotNull(element.getLabelNameAsName()) @@ -60,10 +61,10 @@ object LabelResolver { is KtPropertyAccessor -> element.property else -> return result } - if (addContextReceiverNames) { + if (addClassNameLabels) { + functionOrProperty.receiverTypeReference?.nameForReceiverLabel()?.let { result.add(Name.identifier(it)) } functionOrProperty.contextReceivers .mapNotNullTo(result) { it.name()?.let { s -> Name.identifier(s) } } - functionOrProperty.receiverTypeReference?.nameForReceiverLabel()?.let { result.add(Name.identifier(it)) } } val name = functionOrProperty.nameAsName ?: getLabelForFunctionalExpression(functionOrProperty) result.addIfNotNull(name) @@ -129,9 +130,9 @@ object LabelResolver { labelName: Name, labelExpression: KtSimpleNameExpression, trace: BindingTrace, - isThisExpression: Boolean + classNameLabelsEnabled: Boolean ): KtElement? { - val list = getElementsByLabelName(labelName, labelExpression, isThisExpression) + val list = getElementsByLabelName(labelName, labelExpression, classNameLabelsEnabled) if (list.isEmpty()) return null if (list.size > 1) { @@ -175,15 +176,28 @@ object LabelResolver { return LabeledReceiverResolutionResult.labelResolutionSuccess(thisReceiver) } 0 -> { - val element = resolveNamedLabel(labelName, targetLabel, context.trace, expression is KtThisExpression) + val element = resolveNamedLabel( + labelName, targetLabel, context.trace, + classNameLabelsEnabled = expression is KtThisExpression + && context.languageVersionSettings.supportsFeature(LanguageFeature.ContextReceivers) + ) val declarationDescriptor = context.trace.bindingContext[DECLARATION_TO_DESCRIPTOR, element] if (declarationDescriptor is FunctionDescriptor) { - val receiverToLabelMap = - context.trace.bindingContext[DESCRIPTOR_TO_NAMED_RECEIVERS, if (declarationDescriptor is PropertyAccessorDescriptor) declarationDescriptor.correspondingProperty else declarationDescriptor] - val thisReceiver = receiverToLabelMap?.entries?.find { + val receiverToLabelMap = context.trace.bindingContext[ + DESCRIPTOR_TO_NAMED_RECEIVERS, + if (declarationDescriptor is PropertyAccessorDescriptor) declarationDescriptor.correspondingProperty else declarationDescriptor + ] + val thisReceivers = receiverToLabelMap?.entries?.filter { it.value == labelName.identifier - }?.key ?: declarationDescriptor.extensionReceiverParameter - if (thisReceiver != null) { + }?.map { it.key } ?: emptyList() + val thisReceiver = when { + thisReceivers.isEmpty() -> declarationDescriptor.extensionReceiverParameter + thisReceivers.size == 1 -> thisReceivers.single() + else -> { + BindingContextUtils.reportAmbiguousLabel(context.trace, targetLabel, declarationsByLabel) + return LabeledReceiverResolutionResult.labelResolutionFailed() + } + }?.also { context.trace.record(LABEL_TARGET, targetLabel, element) context.trace.record(REFERENCE_TARGET, referenceExpression, declarationDescriptor) } diff --git a/compiler/testData/diagnostics/tests/extensions/contextReceivers/fromKEEP/decimateEveryEvenThird.fir.kt b/compiler/testData/diagnostics/tests/extensions/contextReceivers/fromKEEP/decimateEveryEvenThird.fir.kt index af2a1e3cc74..09de60e9dd8 100644 --- a/compiler/testData/diagnostics/tests/extensions/contextReceivers/fromKEEP/decimateEveryEvenThird.fir.kt +++ b/compiler/testData/diagnostics/tests/extensions/contextReceivers/fromKEEP/decimateEveryEvenThird.fir.kt @@ -1,3 +1,4 @@ +// !LANGUAGE: +ContextReceivers // WITH_RUNTIME fun List.decimateEveryEvenThird() = sequence { diff --git a/compiler/testData/diagnostics/tests/extensions/contextReceivers/fromKEEP/decimateEveryEvenThird.kt b/compiler/testData/diagnostics/tests/extensions/contextReceivers/fromKEEP/decimateEveryEvenThird.kt index a21ed5116f9..60357f53e48 100644 --- a/compiler/testData/diagnostics/tests/extensions/contextReceivers/fromKEEP/decimateEveryEvenThird.kt +++ b/compiler/testData/diagnostics/tests/extensions/contextReceivers/fromKEEP/decimateEveryEvenThird.kt @@ -1,3 +1,4 @@ +// !LANGUAGE: +ContextReceivers // WITH_RUNTIME fun List.decimateEveryEvenThird() = sequence { diff --git a/compiler/testData/diagnostics/tests/extensions/contextReceivers/labelsFromClassNameForbidden.fir.kt b/compiler/testData/diagnostics/tests/extensions/contextReceivers/labelsFromClassNameForbidden.fir.kt new file mode 100644 index 00000000000..cbedd3274ee --- /dev/null +++ b/compiler/testData/diagnostics/tests/extensions/contextReceivers/labelsFromClassNameForbidden.fir.kt @@ -0,0 +1,12 @@ +fun List.f() { + this@List.size +} + +context(String) +fun Int.f() { + this@String.length + this@Int.toDouble() +} + +context(String) +val p: String get() = this@String \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/extensions/contextReceivers/labelsFromClassNameForbidden.kt b/compiler/testData/diagnostics/tests/extensions/contextReceivers/labelsFromClassNameForbidden.kt new file mode 100644 index 00000000000..70b15961aff --- /dev/null +++ b/compiler/testData/diagnostics/tests/extensions/contextReceivers/labelsFromClassNameForbidden.kt @@ -0,0 +1,12 @@ +fun List.f() { + this@List.size +} + +context(String) +fun Int.f() { + this@String.length + this@Int.toDouble() +} + +context(String) +val p: String get() = this@String \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/extensions/contextReceivers/labelsFromClassNameForbidden.txt b/compiler/testData/diagnostics/tests/extensions/contextReceivers/labelsFromClassNameForbidden.txt new file mode 100644 index 00000000000..bd1f2961a86 --- /dev/null +++ b/compiler/testData/diagnostics/tests/extensions/contextReceivers/labelsFromClassNameForbidden.txt @@ -0,0 +1,5 @@ +package + +public val p: kotlin.String +public fun kotlin.Int.f(): kotlin.Unit +public fun kotlin.collections.List.f(): kotlin.Unit diff --git a/compiler/testData/diagnostics/tests/extensions/contextReceivers/thisWithReceiverLabelsFunctions.fir.kt b/compiler/testData/diagnostics/tests/extensions/contextReceivers/thisWithReceiverLabelsFunctions.fir.kt index 864f4e29cbf..2310245ddf0 100644 --- a/compiler/testData/diagnostics/tests/extensions/contextReceivers/thisWithReceiverLabelsFunctions.fir.kt +++ b/compiler/testData/diagnostics/tests/extensions/contextReceivers/thisWithReceiverLabelsFunctions.fir.kt @@ -4,7 +4,17 @@ class A(val a: T) class B(val b: Any) class C(val c: Any) -context(A, A, B) fun f() { +context(A) fun A.f() { + this@A.a.length +} + +context(A, B) fun f() { + this@A.a.length + this@B.b + this +} + +context(A, A, B) fun f() { this@A.a.length this@B.b this diff --git a/compiler/testData/diagnostics/tests/extensions/contextReceivers/thisWithReceiverLabelsFunctions.kt b/compiler/testData/diagnostics/tests/extensions/contextReceivers/thisWithReceiverLabelsFunctions.kt index 05df251b007..d93326e61bc 100644 --- a/compiler/testData/diagnostics/tests/extensions/contextReceivers/thisWithReceiverLabelsFunctions.kt +++ b/compiler/testData/diagnostics/tests/extensions/contextReceivers/thisWithReceiverLabelsFunctions.kt @@ -4,16 +4,26 @@ class A(val a: T) class B(val b: Any) class C(val c: Any) -context(A, A, B) fun f() { +context(A) fun A.f() { + this@A.a.length +} + +context(A, B) fun f() { this@A.a.length this@B.b this } +context(A, A, B) fun f() { + this@A.a.length + this@B.b + this +} + context(A, A, B) fun C.f() { - this@A.a.length + this@A.a.length this@B.b this@C.c this@f.c this.c -} \ No newline at end of file +} diff --git a/compiler/testData/diagnostics/tests/extensions/contextReceivers/thisWithReceiverLabelsFunctions.txt b/compiler/testData/diagnostics/tests/extensions/contextReceivers/thisWithReceiverLabelsFunctions.txt index 19195f3ba6a..63bb3195997 100644 --- a/compiler/testData/diagnostics/tests/extensions/contextReceivers/thisWithReceiverLabelsFunctions.txt +++ b/compiler/testData/diagnostics/tests/extensions/contextReceivers/thisWithReceiverLabelsFunctions.txt @@ -1,6 +1,8 @@ package public fun f(): kotlin.Unit +public fun f(): kotlin.Unit +public fun A.f(): kotlin.Unit public fun C.f(): kotlin.Unit public final class A { @@ -26,3 +28,4 @@ public final class C { public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String } + diff --git a/compiler/testData/diagnostics/tests/extensions/contextReceivers/thisWithReceiverLabelsProperties.fir.kt b/compiler/testData/diagnostics/tests/extensions/contextReceivers/thisWithReceiverLabelsProperties.fir.kt index 283e4875f64..e07422625ab 100644 --- a/compiler/testData/diagnostics/tests/extensions/contextReceivers/thisWithReceiverLabelsProperties.fir.kt +++ b/compiler/testData/diagnostics/tests/extensions/contextReceivers/thisWithReceiverLabelsProperties.fir.kt @@ -4,7 +4,21 @@ class A(val a: T) class B(val b: Any) class C(val c: Any) -context(A, A, B) var p: Int +context(A, B) var p: Int + get() { + this@A.a.length + this@B.b + this + return 1 + } + set(value) { + this@A.a.length + this@B.b + this + field = value + } + +context(A, A, B) var p: Int get() { this@A.a.toDouble() this@A.a.length diff --git a/compiler/testData/diagnostics/tests/extensions/contextReceivers/thisWithReceiverLabelsProperties.kt b/compiler/testData/diagnostics/tests/extensions/contextReceivers/thisWithReceiverLabelsProperties.kt index 023997b2d6a..067a94a4fd5 100644 --- a/compiler/testData/diagnostics/tests/extensions/contextReceivers/thisWithReceiverLabelsProperties.kt +++ b/compiler/testData/diagnostics/tests/extensions/contextReceivers/thisWithReceiverLabelsProperties.kt @@ -4,9 +4,8 @@ class A(val a: T) class B(val b: Any) class C(val c: Any) -context(A, A, B) var p: Int +context(A, B) var p: Int get() { - this@A.a.toDouble() this@A.a.length this@B.b this @@ -19,12 +18,27 @@ context(A, A, B) var p: Int field = value } +context(A, A, B) var p: Int + get() { + this@A.a.toDouble() + this@A.a.length + this@B.b + this + return 1 + } + set(value) { + this@A.a.length + this@B.b + this + field = value + } + context(A, A, B) val C.p: Int get() { - this@A.a.length + this@A.a.length this@B.b this@C.c this@p.c this.c return 1 - } \ No newline at end of file + } diff --git a/compiler/testData/diagnostics/tests/extensions/contextReceivers/thisWithReceiverLabelsProperties.txt b/compiler/testData/diagnostics/tests/extensions/contextReceivers/thisWithReceiverLabelsProperties.txt index 2d507b6ba6e..1e76e0bf481 100644 --- a/compiler/testData/diagnostics/tests/extensions/contextReceivers/thisWithReceiverLabelsProperties.txt +++ b/compiler/testData/diagnostics/tests/extensions/contextReceivers/thisWithReceiverLabelsProperties.txt @@ -1,5 +1,6 @@ package +public var p: kotlin.Int public var p: kotlin.Int public val C.p: kotlin.Int diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java index 6272ac3842c..830050c0459 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java @@ -10618,6 +10618,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest { runTest("compiler/testData/diagnostics/tests/extensions/contextReceivers/insideDeclaration.kt"); } + @Test + @TestMetadata("labelsFromClassNameForbidden.kt") + public void testLabelsFromClassNameForbidden() throws Exception { + runTest("compiler/testData/diagnostics/tests/extensions/contextReceivers/labelsFromClassNameForbidden.kt"); + } + @Test @TestMetadata("lazy.kt") public void testLazy() throws Exception {