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 558b10ae2be..5a59a3fb92b 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 @@ -10579,14 +10579,9 @@ public class DiagnosisCompilerTestFE10TestdataTestGenerated extends AbstractDiag KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/extensions/contextReceivers"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true); } - @TestMetadata("ambiguityInGroupSimple.kt") - public void testAmbiguityInGroupSimple() throws Exception { - runTest("compiler/testData/diagnostics/tests/extensions/contextReceivers/ambiguityInGroupSimple.kt"); - } - - @TestMetadata("ambiguityInGroupWithInheritance.kt") - public void testAmbiguityInGroupWithInheritance() throws Exception { - runTest("compiler/testData/diagnostics/tests/extensions/contextReceivers/ambiguityInGroupWithInheritance.kt"); + @TestMetadata("ambiguityInGroup.kt") + public void testAmbiguityInGroup() throws Exception { + runTest("compiler/testData/diagnostics/tests/extensions/contextReceivers/ambiguityInGroup.kt"); } @TestMetadata("dp.kt") 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 f91d38a2aed..1572857f64d 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 @@ -10577,15 +10577,9 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti } @Test - @TestMetadata("ambiguityInGroupSimple.kt") - public void testAmbiguityInGroupSimple() throws Exception { - runTest("compiler/testData/diagnostics/tests/extensions/contextReceivers/ambiguityInGroupSimple.kt"); - } - - @Test - @TestMetadata("ambiguityInGroupWithInheritance.kt") - public void testAmbiguityInGroupWithInheritance() throws Exception { - runTest("compiler/testData/diagnostics/tests/extensions/contextReceivers/ambiguityInGroupWithInheritance.kt"); + @TestMetadata("ambiguityInGroup.kt") + public void testAmbiguityInGroup() throws Exception { + runTest("compiler/testData/diagnostics/tests/extensions/contextReceivers/ambiguityInGroup.kt"); } @Test 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 72ff958b928..15d0bc33249 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 @@ -10577,15 +10577,9 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac } @Test - @TestMetadata("ambiguityInGroupSimple.kt") - public void testAmbiguityInGroupSimple() throws Exception { - runTest("compiler/testData/diagnostics/tests/extensions/contextReceivers/ambiguityInGroupSimple.kt"); - } - - @Test - @TestMetadata("ambiguityInGroupWithInheritance.kt") - public void testAmbiguityInGroupWithInheritance() throws Exception { - runTest("compiler/testData/diagnostics/tests/extensions/contextReceivers/ambiguityInGroupWithInheritance.kt"); + @TestMetadata("ambiguityInGroup.kt") + public void testAmbiguityInGroup() throws Exception { + runTest("compiler/testData/diagnostics/tests/extensions/contextReceivers/ambiguityInGroup.kt"); } @Test diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java index e8eee16c8b5..9c0dc3eec18 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java @@ -1199,6 +1199,7 @@ public interface Errors { // Context receivers DiagnosticFactory1 NO_CONTEXT_RECEIVER = DiagnosticFactory1.create(ERROR); DiagnosticFactory1 MULTIPLE_ARGUMENTS_APPLICABLE_FOR_CONTEXT_RECEIVER = DiagnosticFactory1.create(ERROR); + DiagnosticFactory0 AMBIBIGUOS_CALL_WITH_IMPLICIT_CONTEXT_RECEIVER = DiagnosticFactory0.create(ERROR); // Error sets ImmutableSet> UNRESOLVED_REFERENCE_DIAGNOSTICS = ImmutableSet.of( diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java index 186287ae112..0d8aaa8674b 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java @@ -1090,6 +1090,7 @@ public class DefaultErrorMessages { MAP.put(NO_CONTEXT_RECEIVER, "No required context receiver found: {0}", TO_STRING); MAP.put(MULTIPLE_ARGUMENTS_APPLICABLE_FOR_CONTEXT_RECEIVER, "Multiple arguments applicable for context receiver: {0}", TO_STRING); + MAP.put(AMBIBIGUOS_CALL_WITH_IMPLICIT_CONTEXT_RECEIVER, "With implicit context receiver, call is ambiguous. Specify the receiver explicitly"); MAP.setImmutable(); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/DiagnosticReporterByTrackingStrategy.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/DiagnosticReporterByTrackingStrategy.kt index daeaa627186..7be5c20118e 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/DiagnosticReporterByTrackingStrategy.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/DiagnosticReporterByTrackingStrategy.kt @@ -111,6 +111,10 @@ class DiagnosticReporterByTrackingStrategy( ) ) } + ContextReceiverAmbiguity::class.java -> { + val callElement = psiKotlinCall.psiCall.callElement + trace.report(AMBIBIGUOS_CALL_WITH_IMPLICIT_CONTEXT_RECEIVER.on(callElement)) + } } } diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/ImplicitScopeTower.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/ImplicitScopeTower.kt index be6f6cf6202..95fb5b712e9 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/ImplicitScopeTower.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/ImplicitScopeTower.kt @@ -112,6 +112,12 @@ abstract class ResolutionDiagnostic(candidateApplicability: CandidateApplicabili } } +class ContextReceiverAmbiguity : ResolutionDiagnostic(RESOLVED_WITH_ERROR) { + override fun report(reporter: DiagnosticReporter) { + reporter.onCall(this) + } +} + // todo error for this access from nested class class VisibilityError(val invisibleMember: DeclarationDescriptorWithVisibility) : ResolutionDiagnostic(RUNTIME_ERROR) { override fun report(reporter: DiagnosticReporter) { diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/ScopeTowerProcessors.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/ScopeTowerProcessors.kt index 13366414d40..01181444977 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/ScopeTowerProcessors.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/ScopeTowerProcessors.kt @@ -153,6 +153,31 @@ private class NoExplicitReceiverScopeTowerProcessor( ExplicitReceiverKind.NO_EXPLICIT_RECEIVER, data.implicitReceiver ) + is TowerData.BothTowerLevelAndContextReceiversGroup -> { + val collected = mutableListOf() + val receiversWithCandidates = mutableMapOf>() + for (contextReceiver in data.contextReceiversGroup) { + val collectedFromReceiver = data.level.collectCandidates(contextReceiver).toMutableList() + collectedFromReceiver.removeIf { collectedCandidate -> + val duplicate = collected.find { it.descriptor == collectedCandidate.descriptor } + if (duplicate != null) { + duplicate.diagnostics.add(ContextReceiverAmbiguity()) + true + } else { + false + } + } + collected.addAll(collectedFromReceiver) + receiversWithCandidates[contextReceiver] = collectedFromReceiver + } + receiversWithCandidates.flatMap { + createCandidates( + it.value, + ExplicitReceiverKind.NO_EXPLICIT_RECEIVER, + it.key + ) + } + } else -> emptyList() } diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/TowerResolver.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/TowerResolver.kt index fa78000a953..f7b10f93e08 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/TowerResolver.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/TowerResolver.kt @@ -67,6 +67,10 @@ sealed class TowerData { class OnlyImplicitReceiver(val implicitReceiver: ReceiverValueWithSmartCastInfo) : TowerData() class TowerLevel(val level: ScopeTowerLevel) : TowerData() class BothTowerLevelAndImplicitReceiver(val level: ScopeTowerLevel, val implicitReceiver: ReceiverValueWithSmartCastInfo) : TowerData() + class BothTowerLevelAndContextReceiversGroup( + val level: ScopeTowerLevel, + val contextReceiversGroup: List + ) : TowerData() // Has the same meaning as BothTowerLevelAndImplicitReceiver, but it's only used for names lookup, so it doesn't need implicit receiver class ForLookupForNoExplicitReceiver(val level: ScopeTowerLevel) : TowerData() } @@ -222,9 +226,16 @@ class TowerResolver { } is ScopeResolutionStep.ContextReceiversGroupsResolution -> if (scope is LexicalScope) { val contextReceiversGroup = implicitScopeTower.getContextReceivers(scope) + if (contextReceiversGroup.isNotEmpty()) { TowerData.TowerLevel(ContextReceiversGroupScopeTowerLevel(implicitScopeTower, contextReceiversGroup)) .process()?.let { return it } + TowerData.BothTowerLevelAndContextReceiversGroup(syntheticLevel, contextReceiversGroup).process() + ?.let { return it } + for (nonLocalLevel in nonLocalLevels) { + TowerData.BothTowerLevelAndContextReceiversGroup(nonLocalLevel, contextReceiversGroup).process() + ?.let { return it } + } } } is ScopeResolutionStep.ImportingScopesResolution -> if (scope is ImportingScope) { diff --git a/compiler/testData/diagnostics/tests/extensions/contextReceivers/ambiguityInGroup.fir.kt b/compiler/testData/diagnostics/tests/extensions/contextReceivers/ambiguityInGroup.fir.kt new file mode 100644 index 00000000000..15104a1ce9c --- /dev/null +++ b/compiler/testData/diagnostics/tests/extensions/contextReceivers/ambiguityInGroup.fir.kt @@ -0,0 +1,22 @@ +interface Common { + fun supertypeMember() {} +} +interface C1 : Common { + fun member() {} +} +interface C2 : Common { + fun member() {} +} + +fun Common.supertypeExtension() {} + +context(Common) +fun supertypeContextual() {} + +context(C1, C2) +fun test() { + supertypeMember() + member() + supertypeExtension() + supertypeContextual() +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/extensions/contextReceivers/ambiguityInGroup.kt b/compiler/testData/diagnostics/tests/extensions/contextReceivers/ambiguityInGroup.kt new file mode 100644 index 00000000000..c3242c0f489 --- /dev/null +++ b/compiler/testData/diagnostics/tests/extensions/contextReceivers/ambiguityInGroup.kt @@ -0,0 +1,22 @@ +interface Common { + fun supertypeMember() {} +} +interface C1 : Common { + fun member() {} +} +interface C2 : Common { + fun member() {} +} + +fun Common.supertypeExtension() {} + +context(Common) +fun supertypeContextual() {} + +context(C1, C2) +fun test() { + supertypeMember() + member() + supertypeExtension() + supertypeContextual() +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/extensions/contextReceivers/ambiguityInGroupWithInheritance.txt b/compiler/testData/diagnostics/tests/extensions/contextReceivers/ambiguityInGroup.txt similarity index 69% rename from compiler/testData/diagnostics/tests/extensions/contextReceivers/ambiguityInGroupWithInheritance.txt rename to compiler/testData/diagnostics/tests/extensions/contextReceivers/ambiguityInGroup.txt index cedf6957697..6bcf257f98d 100644 --- a/compiler/testData/diagnostics/tests/extensions/contextReceivers/ambiguityInGroupWithInheritance.txt +++ b/compiler/testData/diagnostics/tests/extensions/contextReceivers/ambiguityInGroup.txt @@ -1,23 +1,28 @@ package -public fun foo(): kotlin.Unit +public fun supertypeContextual(): kotlin.Unit public fun test(): kotlin.Unit -public fun Common.bar(): kotlin.Unit +public fun Common.supertypeExtension(): kotlin.Unit public interface C1 : Common { public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open fun member(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun supertypeMember(): kotlin.Unit public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String } public interface C2 : Common { public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open fun member(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun supertypeMember(): kotlin.Unit public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String } public interface Common { public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open fun supertypeMember(): kotlin.Unit public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String } diff --git a/compiler/testData/diagnostics/tests/extensions/contextReceivers/ambiguityInGroupSimple.fir.kt b/compiler/testData/diagnostics/tests/extensions/contextReceivers/ambiguityInGroupSimple.fir.kt deleted file mode 100644 index cd6828d4c70..00000000000 --- a/compiler/testData/diagnostics/tests/extensions/contextReceivers/ambiguityInGroupSimple.fir.kt +++ /dev/null @@ -1,11 +0,0 @@ -interface C1 { - fun foo() {} -} -interface C2 { - fun foo() {} -} - -context(C1, C2) -fun bar() { - foo() -} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/extensions/contextReceivers/ambiguityInGroupSimple.kt b/compiler/testData/diagnostics/tests/extensions/contextReceivers/ambiguityInGroupSimple.kt deleted file mode 100644 index 38a5a363db5..00000000000 --- a/compiler/testData/diagnostics/tests/extensions/contextReceivers/ambiguityInGroupSimple.kt +++ /dev/null @@ -1,11 +0,0 @@ -interface C1 { - fun foo() {} -} -interface C2 { - fun foo() {} -} - -context(C1, C2) -fun bar() { - foo() -} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/extensions/contextReceivers/ambiguityInGroupSimple.txt b/compiler/testData/diagnostics/tests/extensions/contextReceivers/ambiguityInGroupSimple.txt deleted file mode 100644 index 8f83c69e42f..00000000000 --- a/compiler/testData/diagnostics/tests/extensions/contextReceivers/ambiguityInGroupSimple.txt +++ /dev/null @@ -1,17 +0,0 @@ -package - -public fun bar(): kotlin.Unit - -public interface C1 { - public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean - public open fun foo(): kotlin.Unit - public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int - public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String -} - -public interface C2 { - public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean - public open fun foo(): kotlin.Unit - 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/ambiguityInGroupWithInheritance.fir.kt b/compiler/testData/diagnostics/tests/extensions/contextReceivers/ambiguityInGroupWithInheritance.fir.kt deleted file mode 100644 index a57b366e941..00000000000 --- a/compiler/testData/diagnostics/tests/extensions/contextReceivers/ambiguityInGroupWithInheritance.fir.kt +++ /dev/null @@ -1,14 +0,0 @@ -interface Common -interface C1 : Common -interface C2 : Common - -context(Common) -fun foo() {} - -fun Common.bar() {} - -context(C1, C2) -fun test() { - foo() - bar() -} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/extensions/contextReceivers/ambiguityInGroupWithInheritance.kt b/compiler/testData/diagnostics/tests/extensions/contextReceivers/ambiguityInGroupWithInheritance.kt deleted file mode 100644 index a757e62e711..00000000000 --- a/compiler/testData/diagnostics/tests/extensions/contextReceivers/ambiguityInGroupWithInheritance.kt +++ /dev/null @@ -1,14 +0,0 @@ -interface Common -interface C1 : Common -interface C2 : Common - -context(Common) -fun foo() {} - -fun Common.bar() {} - -context(C1, C2) -fun test() { - foo() - bar() -} \ No newline at end of file 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 e17f96306a2..b4777b3ea0d 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 @@ -10583,15 +10583,9 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest { } @Test - @TestMetadata("ambiguityInGroupSimple.kt") - public void testAmbiguityInGroupSimple() throws Exception { - runTest("compiler/testData/diagnostics/tests/extensions/contextReceivers/ambiguityInGroupSimple.kt"); - } - - @Test - @TestMetadata("ambiguityInGroupWithInheritance.kt") - public void testAmbiguityInGroupWithInheritance() throws Exception { - runTest("compiler/testData/diagnostics/tests/extensions/contextReceivers/ambiguityInGroupWithInheritance.kt"); + @TestMetadata("ambiguityInGroup.kt") + public void testAmbiguityInGroup() throws Exception { + runTest("compiler/testData/diagnostics/tests/extensions/contextReceivers/ambiguityInGroup.kt"); } @Test