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 ca170172d9a..558b10ae2be 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,6 +10579,16 @@ 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("dp.kt") public void testDp() throws Exception { runTest("compiler/testData/diagnostics/tests/extensions/contextReceivers/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 303fefe2101..f91d38a2aed 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 @@ -10576,6 +10576,18 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/extensions/contextReceivers"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true); } + @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"); + } + @Test @TestMetadata("dp.kt") public void testDp() 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 24097ff9afe..72ff958b928 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 @@ -10576,6 +10576,18 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/extensions/contextReceivers"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true); } + @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"); + } + @Test @TestMetadata("dp.kt") public void testDp() throws Exception { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java index dafee7bb565..e8eee16c8b5 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java @@ -1198,6 +1198,7 @@ public interface Errors { // Context receivers DiagnosticFactory1 NO_CONTEXT_RECEIVER = DiagnosticFactory1.create(ERROR); + DiagnosticFactory1 MULTIPLE_ARGUMENTS_APPLICABLE_FOR_CONTEXT_RECEIVER = DiagnosticFactory1.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 45dbd9002f5..186287ae112 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java @@ -1089,6 +1089,7 @@ public class DefaultErrorMessages { MAP.put(CONTRACT_NOT_ALLOWED, "{0}", TO_STRING); 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.setImmutable(); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/BodyResolver.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/BodyResolver.java index eddd2c9e6c8..438b69787bb 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/BodyResolver.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/BodyResolver.java @@ -162,7 +162,7 @@ public class BodyResolver { descriptor, localContext != null ? localContext.inferenceSession : null ), scope -> new LexicalScopeImpl( - scope, descriptor, scope.isOwnerDescriptorAccessibleByLabel(), scope.getImplicitReceivers(), + scope, descriptor, scope.isOwnerDescriptorAccessibleByLabel(), scope.getImplicitReceiver(), scope.getContextReceiversGroup(), LexicalScopeKind.CONSTRUCTOR_HEADER ), localContext @@ -439,7 +439,7 @@ public class BodyResolver { ) { // Initializing a scope will report errors if any. new LexicalScopeImpl( - scopeForConstructorResolution, descriptor, true, Collections.emptyList(), LexicalScopeKind.CLASS_HEADER, + scopeForConstructorResolution, descriptor, true, null, Collections.emptyList(), LexicalScopeKind.CLASS_HEADER, new TraceBasedLocalRedeclarationChecker(trace, overloadChecker), new Function1() { @Override @@ -780,8 +780,8 @@ public class BodyResolver { LexicalScope originalScope, ConstructorDescriptor unsubstitutedPrimaryConstructor ) { - return new LexicalScopeImpl(originalScope, unsubstitutedPrimaryConstructor, false, Collections.emptyList(), - LexicalScopeKind.DEFAULT_VALUE, LocalRedeclarationChecker.DO_NOTHING.INSTANCE, + return new LexicalScopeImpl(originalScope, unsubstitutedPrimaryConstructor, false, null, + Collections.emptyList(), LexicalScopeKind.DEFAULT_VALUE, LocalRedeclarationChecker.DO_NOTHING.INSTANCE, handler -> { for (ValueParameterDescriptor valueParameter : unsubstitutedPrimaryConstructor.getValueParameters()) { handler.addVariableDescriptor(valueParameter); @@ -863,12 +863,7 @@ public class BodyResolver { LexicalScope accessorDeclaringScope = c.getDeclaringScope(accessor); assert accessorDeclaringScope != null : "Scope for accessor " + accessor.getText() + " should exists"; LexicalScope headerScope = ScopeUtils.makeScopeForPropertyHeader(accessorDeclaringScope, descriptor); - List implicitReceivers = new ArrayList<>(); - ReceiverParameterDescriptor extensionReceiverParameter = descriptor.getExtensionReceiverParameter(); - if (extensionReceiverParameter != null) { - implicitReceivers.add(extensionReceiverParameter); - } - return new LexicalScopeImpl(headerScope, descriptor, true, implicitReceivers, + return new LexicalScopeImpl(headerScope, descriptor, true, descriptor.getExtensionReceiverParameter(), descriptor.getContextReceiverParameters(), LexicalScopeKind.PROPERTY_ACCESSOR_BODY); } @@ -1029,7 +1024,7 @@ public class BodyResolver { KtProperty property = (KtProperty) function.getParent(); SourceElement propertySourceElement = KotlinSourceElementKt.toSourceElement(property); SyntheticFieldDescriptor fieldDescriptor = new SyntheticFieldDescriptor(accessorDescriptor, propertySourceElement); - innerScope = new LexicalScopeImpl(innerScope, functionDescriptor, true, Collections.emptyList(), + innerScope = new LexicalScopeImpl(innerScope, functionDescriptor, true, null, Collections.emptyList(), LexicalScopeKind.PROPERTY_ACCESSOR_BODY, LocalRedeclarationChecker.DO_NOTHING.INSTANCE, handler -> { handler.addVariableDescriptor(fieldDescriptor); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/FunctionDescriptorUtil.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/FunctionDescriptorUtil.java index 47e47dc53fd..b7df1a5ee03 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/FunctionDescriptorUtil.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/FunctionDescriptorUtil.java @@ -16,7 +16,6 @@ package org.jetbrains.kotlin.resolve; -import com.google.common.collect.Lists; import kotlin.Unit; import org.jetbrains.annotations.NotNull; import org.jetbrains.kotlin.descriptors.*; @@ -25,7 +24,6 @@ import org.jetbrains.kotlin.resolve.scopes.*; import org.jetbrains.kotlin.types.*; import org.jetbrains.kotlin.types.typeUtil.TypeUtilsKt; -import java.util.ArrayList; import java.util.List; public class FunctionDescriptorUtil { @@ -67,20 +65,9 @@ public class FunctionDescriptorUtil { @NotNull FunctionDescriptor descriptor, @NotNull LocalRedeclarationChecker redeclarationChecker ) { - List implicitReceivers = new ArrayList<>(); - ReceiverParameterDescriptor extensionReceiverParameter = descriptor.getExtensionReceiverParameter(); - if (descriptor.getExtensionReceiverParameter() != null) { - implicitReceivers.add(extensionReceiverParameter); - } - List contextReceiverParameters = descriptor.getContextReceiverParameters(); - if (!contextReceiverParameters.isEmpty()) { - implicitReceivers.addAll( - Lists.reverse(contextReceiverParameters) - ); - } return new LexicalScopeImpl( - outerScope, descriptor, true, implicitReceivers, - LexicalScopeKind.FUNCTION_INNER_SCOPE, redeclarationChecker, + outerScope, descriptor, true, descriptor.getExtensionReceiverParameter(), + descriptor.getContextReceiverParameters(), LexicalScopeKind.FUNCTION_INNER_SCOPE, redeclarationChecker, handler -> { for (TypeParameterDescriptor typeParameter : descriptor.getTypeParameters()) { handler.addClassifierDescriptor(typeParameter); 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 b108868716e..daeaa627186 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/DiagnosticReporterByTrackingStrategy.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/DiagnosticReporterByTrackingStrategy.kt @@ -102,6 +102,15 @@ class DiagnosticReporterByTrackingStrategy( ) ) } + MultipleArgumentsApplicableForContextReceiver::class.java -> { + val callElement = psiKotlinCall.psiCall.callElement + trace.report( + MULTIPLE_ARGUMENTS_APPLICABLE_FOR_CONTEXT_RECEIVER.on( + callElement, + (diagnostic as MultipleArgumentsApplicableForContextReceiver).receiverDescriptor.value.toString() + ) + ) + } } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/DslScopeViolationCallChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/DslScopeViolationCallChecker.kt index fcb14773a62..e0005a11c19 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/DslScopeViolationCallChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/DslScopeViolationCallChecker.kt @@ -49,7 +49,8 @@ object DslScopeViolationCallChecker : CallChecker { ) { val receiversUntilOneFromTheCall = context.scope.parentsWithSelf - .flatMap { (it as? LexicalScope)?.implicitReceivers ?: emptyList() } + .filterIsInstance() + .flatMap { listOfNotNull(it.implicitReceiver) + it.contextReceiversGroup } .map { it.value } .takeWhile { it != callImplicitReceiver }.toList() diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/NewResolutionOldInference.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/NewResolutionOldInference.kt index 25fbaa85ec7..2a60c5888eb 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/NewResolutionOldInference.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/NewResolutionOldInference.kt @@ -366,8 +366,13 @@ class NewResolutionOldInference( ) : ImplicitScopeTower { private val cache = HashMap() - override fun getImplicitReceivers(scope: LexicalScope): List = - scope.implicitReceivers.map { cache.getOrPut(it.value) { resolutionContext.transformToReceiverWithSmartCastInfo(it.value) } } + override fun getImplicitReceiver(scope: LexicalScope): ReceiverValueWithSmartCastInfo? = + scope.implicitReceiver?.value?.let { + cache.getOrPut(it) { resolutionContext.transformToReceiverWithSmartCastInfo(it) } + } + + override fun getContextReceivers(scope: LexicalScope): List = + scope.contextReceiversGroup.map { cache.getOrPut(it.value) { resolutionContext.transformToReceiverWithSmartCastInfo(it.value) } } override fun getNameForGivenImportAlias(name: Name): Name? = (resolutionContext.call.callElement.containingFile as? KtFile)?.getNameForGivenImportAlias(name) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/PSICallResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/PSICallResolver.kt index e2fecccc486..29ffa2eabb9 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/PSICallResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/PSICallResolver.kt @@ -400,8 +400,16 @@ class PSICallResolver( override val implicitsResolutionFilter: ImplicitsExtensionsResolutionFilter get() = this@PSICallResolver.implicitsResolutionFilter private val cache = HashMap() - override fun getImplicitReceivers(scope: LexicalScope): List = - scope.implicitReceivers.map { cache.getOrPut(it) { context.transformToReceiverWithSmartCastInfo(it.value) } } + override fun getImplicitReceiver(scope: LexicalScope): ReceiverValueWithSmartCastInfo? { + val implicitReceiver = scope.implicitReceiver ?: return null + + return cache.getOrPut(implicitReceiver) { + context.transformToReceiverWithSmartCastInfo(implicitReceiver.value) + } + } + + override fun getContextReceivers(scope: LexicalScope): List = + scope.contextReceiversGroup.map { cache.getOrPut(it) { context.transformToReceiverWithSmartCastInfo(it.value) } } override fun getNameForGivenImportAlias(name: Name): Name? = (context.call.callElement.containingFile as? KtFile)?.getNameForGivenImportAlias(name) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/ClassResolutionScopesSupport.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/ClassResolutionScopesSupport.kt index 8ced6769c9e..50a791b6896 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/ClassResolutionScopesSupport.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/ClassResolutionScopesSupport.kt @@ -33,7 +33,7 @@ class ClassResolutionScopesSupport( private val getOuterScope: () -> LexicalScope ) { private fun scopeWithGenerics(parent: LexicalScope): LexicalScopeImpl { - return LexicalScopeImpl(parent, classDescriptor, false, emptyList(), LexicalScopeKind.CLASS_HEADER) { + return LexicalScopeImpl(parent, classDescriptor, false, null, emptyList(), LexicalScopeKind.CLASS_HEADER) { classDescriptor.declaredTypeParameters.forEach { addClassifierDescriptor(it) } } } @@ -67,7 +67,8 @@ class ClassResolutionScopesSupport( scopeWithGenerics, classDescriptor, true, - classDescriptor.contextReceivers + classDescriptor.thisAsReceiverParameter, + classDescriptor.thisAsReceiverParameter, + classDescriptor.contextReceivers, LexicalScopeKind.CLASS_MEMBER_SCOPE ) } @@ -94,7 +95,8 @@ class ClassResolutionScopesSupport( val lexicalChainedScope = LexicalChainedScope.create( parentForNewScope, ownerDescriptor, isOwnerDescriptorAccessibleByLabel = false, - implicitReceivers = listOfNotNull(companionObjectDescriptor?.thisAsReceiverParameter), + implicitReceiver = companionObjectDescriptor?.thisAsReceiverParameter, + contextReceiversGroup = emptyList(), kind = LexicalScopeKind.CLASS_INHERITANCE, classDescriptor.staticScope, classDescriptor.unsubstitutedInnerClassesScope, @@ -144,6 +146,7 @@ fun scopeForInitializerResolution( classDescriptor.scopeForMemberDeclarationResolution, parentDescriptor, false, + null, emptyList(), LexicalScopeKind.CLASS_INITIALIZER ) { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ValueParameterResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ValueParameterResolver.kt index 2eff1e26158..d88c02385b5 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ValueParameterResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ValueParameterResolver.kt @@ -50,7 +50,7 @@ class ValueParameterResolver( inferenceSession: InferenceSession? ) { val scopeForDefaultValue = - LexicalScopeImpl(declaringScope, declaringScope.ownerDescriptor, false, listOf(), LexicalScopeKind.DEFAULT_VALUE) + LexicalScopeImpl(declaringScope, declaringScope.ownerDescriptor, false, null, listOf(), LexicalScopeKind.DEFAULT_VALUE) val contextForDefaultValue = ExpressionTypingContext.newContext( trace, scopeForDefaultValue, dataFlowInfo, TypeUtils.NO_EXPECTED_TYPE, diff --git a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/ConstraintSystemBuilder.kt b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/ConstraintSystemBuilder.kt index 81b8b43d921..c4d8d76b86a 100644 --- a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/ConstraintSystemBuilder.kt +++ b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/ConstraintSystemBuilder.kt @@ -87,3 +87,30 @@ private fun ConstraintSystemBuilder.addConstraintIfCompatible( } !hasContradiction } + +fun ConstraintSystemBuilder.isSubtypeConstraintCompatible( + lowerType: KotlinTypeMarker, + upperType: KotlinTypeMarker, + position: ConstraintPosition +): Boolean = isConstraintCompatible(lowerType, upperType, position, ConstraintKind.LOWER) + +private fun ConstraintSystemBuilder.isConstraintCompatible( + lowerType: KotlinTypeMarker, + upperType: KotlinTypeMarker, + position: ConstraintPosition, + kind: ConstraintKind +): Boolean { + var isCompatible = false + runTransaction { + if (!hasContradiction) { + when (kind) { + ConstraintKind.LOWER -> addSubtypeConstraint(lowerType, upperType, position) + ConstraintKind.UPPER -> addSubtypeConstraint(upperType, lowerType, position) + ConstraintKind.EQUALITY -> addEqualityConstraint(lowerType, upperType, position) + } + } + isCompatible = !hasContradiction + false + } + return isCompatible +} \ No newline at end of file diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ResolutionParts.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ResolutionParts.kt index d1cfa7f4d43..3da4359f1f5 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ResolutionParts.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ResolutionParts.kt @@ -16,12 +16,9 @@ import org.jetbrains.kotlin.resolve.calls.components.CheckReceivers.checkReceive import org.jetbrains.kotlin.resolve.calls.components.TypeArgumentsToParametersMapper.TypeArgumentsMapping.NoExplicitArguments import org.jetbrains.kotlin.resolve.calls.components.candidate.CallableReferenceResolutionCandidate import org.jetbrains.kotlin.resolve.calls.components.candidate.ResolutionCandidate -import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemOperation -import org.jetbrains.kotlin.resolve.calls.inference.NewConstraintSystem -import org.jetbrains.kotlin.resolve.calls.inference.addSubtypeConstraintIfCompatible +import org.jetbrains.kotlin.resolve.calls.inference.* import org.jetbrains.kotlin.resolve.calls.inference.components.* import org.jetbrains.kotlin.resolve.calls.inference.model.* -import org.jetbrains.kotlin.resolve.calls.inference.substitute import org.jetbrains.kotlin.resolve.calls.model.* import org.jetbrains.kotlin.resolve.calls.smartcasts.getReceiverValueWithSmartCast import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind.* @@ -807,30 +804,60 @@ internal object ErrorDescriptorResolutionPart : ResolutionPart() { } internal object CheckContextReceiversResolutionPart : ResolutionPart() { - private fun ResolutionCandidate.checkReceiver( - implicitReceivers: Collection, + private data class ApplicableArgumentWithConstraint( + val argument: SimpleKotlinCallArgument, + val argumentType: UnwrappedType, + val expectedType: UnwrappedType, + val position: ConstraintPosition + ) + + private fun ResolutionCandidate.findContextReceiver( + implicitReceiversGroups: List>, candidateContextReceiverParameter: ReceiverParameterDescriptor ): SimpleKotlinCallArgument? { - val csBuilder = getSystem().getBuilder() - for (implicitReceiver in implicitReceivers) { - val argument = ReceiverExpressionKotlinCallArgument(implicitReceiver) + + fun ReceiverValueWithSmartCastInfo.createArgumentIfCompatible(): ApplicableArgumentWithConstraint? { + val csBuilder = getSystem().getBuilder() + val argument = ReceiverExpressionKotlinCallArgument(this) val expectedTypeUnprepared = argument.getExpectedType(candidateContextReceiverParameter, callComponents.languageVersionSettings) val expectedType = prepareExpectedType(expectedTypeUnprepared) val argumentType = captureFromTypeParameterUpperBoundIfNeeded(argument.receiver.stableType, expectedType) val position = ReceiverConstraintPositionImpl(argument) - if (csBuilder.addSubtypeConstraintIfCompatible(argumentType, expectedType, position)) return argument + return if (csBuilder.isSubtypeConstraintCompatible(argumentType, expectedType, position)) + ApplicableArgumentWithConstraint(argument, argumentType, expectedType, position) + else null + } + + for (implicitReceiverGroup in implicitReceiversGroups) { + val applicableArguments = implicitReceiverGroup.mapNotNull { it.createArgumentIfCompatible() }.toList() + if (applicableArguments.size == 1) { + val (argument, argumentType, expectedType, position) = applicableArguments.single() + csBuilder.addSubtypeConstraint(argumentType, expectedType, position) + return argument + } + if (applicableArguments.size > 1) { + diagnosticsFromResolutionParts.add(MultipleArgumentsApplicableForContextReceiver(candidateContextReceiverParameter)) + return null + } } diagnosticsFromResolutionParts.add(NoContextReceiver(candidateContextReceiverParameter)) return null } override fun ResolutionCandidate.process(workIndex: Int) { - val implicitReceivers = scopeTower.lexicalScope.parentsWithSelf - .flatMap { if (it is LexicalScope) scopeTower.getImplicitReceivers(it) else emptyList() }.toList() + val parentLexicalScopes = scopeTower.lexicalScope.parentsWithSelf.filterIsInstance() + val implicitReceiversGroups = mutableListOf>() + for (scope in parentLexicalScopes) { + scopeTower.getImplicitReceiver(scope)?.let { implicitReceiversGroups.add(listOf(it)) } + val contextReceiversGroup = scopeTower.getContextReceivers(scope) + if (contextReceiversGroup.isNotEmpty()) { + implicitReceiversGroups.add(contextReceiversGroup) + } + } val contextReceiversArguments = mutableListOf() for (candidateContextReceiverParameter in candidateDescriptor.contextReceiverParameters) { - contextReceiversArguments.add(findContextReceiver(implicitReceivers, candidateContextReceiverParameter) ?: return) + contextReceiversArguments.add(findContextReceiver(implicitReceiversGroups, candidateContextReceiverParameter) ?: return) } resolvedCall.contextReceiversArguments = contextReceiversArguments } diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/KotlinCallDiagnostics.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/KotlinCallDiagnostics.kt index 592743aa5e7..c76139bf660 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/KotlinCallDiagnostics.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/KotlinCallDiagnostics.kt @@ -279,6 +279,12 @@ class NoContextReceiver(val receiverDescriptor: ReceiverParameterDescriptor) : K } } +class MultipleArgumentsApplicableForContextReceiver(val receiverDescriptor: ReceiverParameterDescriptor) : KotlinCallDiagnostic(INAPPLICABLE) { + override fun report(reporter: DiagnosticReporter) { + reporter.onCall(this) + } +} + class KotlinConstraintSystemDiagnostic( val error: ConstraintSystemError ) : KotlinCallDiagnostic(error.applicability) { 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 7860afb6337..be6f6cf6202 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 @@ -37,7 +37,9 @@ import org.jetbrains.kotlin.types.TypeApproximator interface ImplicitScopeTower { val lexicalScope: LexicalScope - fun getImplicitReceivers(scope: LexicalScope): List + fun getImplicitReceiver(scope: LexicalScope): ReceiverValueWithSmartCastInfo? + + fun getContextReceivers(scope: LexicalScope): List fun getNameForGivenImportAlias(name: Name): Name? diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/TowerLevels.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/TowerLevels.kt index ad3a1e637e6..3f1c33ddea6 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/TowerLevels.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/TowerLevels.kt @@ -201,6 +201,80 @@ internal class MemberScopeTowerLevel( } } +internal class ContextReceiversGroupScopeTowerLevel( + scopeTower: ImplicitScopeTower, + val contextReceiversGroup: List +) : AbstractScopeTowerLevel(scopeTower) { + + private val syntheticScopes = scopeTower.syntheticScopes + + private fun collectMembers( + getMembers: ResolutionScope.(KotlinType?) -> Collection + ): Collection { + val result = ArrayList(0) + + for (contextReceiver in contextReceiversGroup) { + val receiverValue = contextReceiver.receiverValue + if (receiverValue.type is AbstractStubType && receiverValue.type.memberScope is ErrorUtils.ErrorScope) { + return arrayListOf() + } + receiverValue.type.memberScope.getMembers(receiverValue.type).mapTo(result) { + createCandidateDescriptor(it, contextReceiver) + } + if (receiverValue.type.isDynamic()) { + scopeTower.dynamicScope.getMembers(null).mapTo(result) { + createCandidateDescriptor(it, contextReceiver, DynamicDescriptorDiagnostic) + } + } + } + + return result + } + + override fun getVariables( + name: Name, + extensionReceiver: ReceiverValueWithSmartCastInfo? + ): Collection { + return contextReceiversGroup.map { contextReceiver -> + collectMembers { getContributedVariablesAndIntercept(name, location, contextReceiver, extensionReceiver, scopeTower) } + }.flatten() + } + + override fun getObjects( + name: Name, + extensionReceiver: ReceiverValueWithSmartCastInfo? + ): Collection { + return emptyList() + } + + override fun getFunctions( + name: Name, + extensionReceiver: ReceiverValueWithSmartCastInfo? + ): Collection { + val collectMembers = { contextReceiver: ReceiverValueWithSmartCastInfo -> + collectMembers { + getContributedFunctionsAndIntercept( + name, + location, + contextReceiver, + extensionReceiver, + scopeTower + ) + it.getInnerConstructors( + name, + location + ) + syntheticScopes.collectSyntheticMemberFunctions(listOfNotNull(it), name, location) + } + } + return contextReceiversGroup.map(collectMembers).flatten() + } + + override fun recordLookup(name: Name) { + for (type in contextReceiversGroup.map { it.allOriginalTypes }.flatten()) { + type.memberScope.recordLookup(name, location) + } + } +} + internal class QualifierScopeTowerLevel(scopeTower: ImplicitScopeTower, val qualifier: QualifierReceiver) : AbstractScopeTowerLevel(scopeTower) { override fun getVariables(name: Name, extensionReceiver: ReceiverValueWithSmartCastInfo?) = qualifier.staticScope 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 06f8215a88d..fa78000a953 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 @@ -100,6 +100,12 @@ class TowerResolver { name: Name ): Collection = Task(this, processor, resultCollector, useOrder, name).run() + sealed interface ScopeResolutionStep { + data class LexicalScopesResolution(val resolveExtensionsForImplicitReceiver: Boolean) : ScopeResolutionStep + object ContextReceiversGroupsResolution : ScopeResolutionStep + object ImportingScopesResolution : ScopeResolutionStep + } + private inner class Task( private val implicitScopeTower: ImplicitScopeTower, private val processor: ScopeTowerProcessor, @@ -135,27 +141,40 @@ class TowerResolver { } } - lexicalScope.parentsWithSelf.forEach { scope -> - if (scope is LexicalScope) { - if (!scope.kind.withLocalDescriptors) { - addLevel( - ScopeBasedTowerLevel(this@createNonLocalLevels, scope), - scope.mayFitForName(name) - ) - } - - getImplicitReceivers(scope).forEach { - addLevel( - MemberScopeTowerLevel(this@createNonLocalLevels, it), - it.mayFitForName(name) - ) - } - } else { + val parentScopes = lexicalScope.parentsWithSelf + val lexicalScopes = parentScopes.filterIsInstance() + lexicalScopes.forEach { scope -> + if (!scope.kind.withLocalDescriptors) { addLevel( - ImportingScopeBasedTowerLevel(this@createNonLocalLevels, scope as ImportingScope), + ScopeBasedTowerLevel(this@createNonLocalLevels, scope), scope.mayFitForName(name) ) } + + getImplicitReceiver(scope)?.let { + addLevel( + MemberScopeTowerLevel(this@createNonLocalLevels, it), + it.mayFitForName(name) + ) + } + } + + lexicalScopes.forEach { scope -> + val contextReceiversGroup = getContextReceivers(scope) + if (contextReceiversGroup.isNotEmpty()) { + addLevel( + ContextReceiversGroupScopeTowerLevel(this@createNonLocalLevels, contextReceiversGroup), + contextReceiversGroup.any { it.mayFitForName(name) } + ) + } + } + + val importingScopes = parentScopes - lexicalScopes + importingScopes.forEach { scope -> + addLevel( + ImportingScopeBasedTowerLevel(this@createNonLocalLevels, scope as ImportingScope), + scope.mayFitForName(name) + ) } return mainResult @@ -189,31 +208,57 @@ class TowerResolver { TowerData.TowerLevel(localLevel).process()?.let { return it } } - fun processScope(scope: HierarchicalScope, resolveExtensionsForImplicitReceiver: Boolean): Collection? { - if (scope is LexicalScope) { - // statics - if (!scope.kind.withLocalDescriptors) { - TowerData.TowerLevel(ScopeBasedTowerLevel(implicitScopeTower, scope)) + fun processScope(scope: HierarchicalScope, scopeResolutionStep: ScopeResolutionStep): Collection? { + when (scopeResolutionStep) { + is ScopeResolutionStep.LexicalScopesResolution -> if (scope is LexicalScope) { + if (!scope.kind.withLocalDescriptors) { + TowerData.TowerLevel(ScopeBasedTowerLevel(implicitScopeTower, scope)) + .process(scope.mayFitForName(name))?.let { return it } + } + + implicitScopeTower.getImplicitReceiver(scope)?.let { rv -> + processImplicitReceiver(rv, scopeResolutionStep.resolveExtensionsForImplicitReceiver)?.let { return it } + } + } + is ScopeResolutionStep.ContextReceiversGroupsResolution -> if (scope is LexicalScope) { + val contextReceiversGroup = implicitScopeTower.getContextReceivers(scope) + if (contextReceiversGroup.isNotEmpty()) { + TowerData.TowerLevel(ContextReceiversGroupScopeTowerLevel(implicitScopeTower, contextReceiversGroup)) + .process()?.let { return it } + } + } + is ScopeResolutionStep.ImportingScopesResolution -> if (scope is ImportingScope) { + TowerData.TowerLevel(ImportingScopeBasedTowerLevel(implicitScopeTower, scope)) .process(scope.mayFitForName(name))?.let { return it } } - - implicitScopeTower.getImplicitReceivers(scope).forEach { rv -> - processImplicitReceiver(rv, resolveExtensionsForImplicitReceiver)?.let { return it } - } - } else { - TowerData.TowerLevel(ImportingScopeBasedTowerLevel(implicitScopeTower, scope as ImportingScope)) - .process(scope.mayFitForName(name))?.let { return it } } return null } if (implicitScopeTower.implicitsResolutionFilter === ImplicitsExtensionsResolutionFilter.Default) { - for (scope in implicitScopeTower.lexicalScope.parentsWithSelf) { - processScope(scope, true)?.let { return it } - } + val scopes = implicitScopeTower.lexicalScope.parentsWithSelf + scopes.forEach { scope -> processScope(scope, ScopeResolutionStep.LexicalScopesResolution(true))?.let { return it } } + scopes.forEach { scope -> processScope(scope, ScopeResolutionStep.ContextReceiversGroupsResolution)?.let { return it } } + scopes.forEach { scope -> processScope(scope, ScopeResolutionStep.ImportingScopesResolution)?.let { return it } } } else { - for (scopeInfo in implicitScopeTower.allScopesWithImplicitsResolutionInfo()) { - processScope(scopeInfo.scope, scopeInfo.resolveExtensionsForImplicitReceiver)?.let { return it } + val scopeInfos = implicitScopeTower.allScopesWithImplicitsResolutionInfo() + scopeInfos.forEach { scopeInfo -> + processScope( + scopeInfo.scope, + ScopeResolutionStep.LexicalScopesResolution(scopeInfo.resolveExtensionsForImplicitReceiver) + )?.let { return it } + } + scopeInfos.forEach { scopeInfo -> + processScope( + scopeInfo.scope, + ScopeResolutionStep.ContextReceiversGroupsResolution + )?.let { return it } + } + scopeInfos.forEach { scopeInfo -> + processScope( + scopeInfo.scope, + ScopeResolutionStep.ImportingScopesResolution + )?.let { return it } } } diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/scopes/LexicalChainedScope.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/scopes/LexicalChainedScope.kt index 9002b63e74c..db427162645 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/scopes/LexicalChainedScope.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/scopes/LexicalChainedScope.kt @@ -32,7 +32,8 @@ class LexicalChainedScope private constructor( parent: LexicalScope, override val ownerDescriptor: DeclarationDescriptor, override val isOwnerDescriptorAccessibleByLabel: Boolean, - override val implicitReceivers: List, + override val implicitReceiver: ReceiverParameterDescriptor?, + override val contextReceiversGroup: List, override val kind: LexicalScopeKind, // NB. Here can be very special subtypes of MemberScope (e.g., DeprecatedMemberScope). // Please, do not leak them outside of LexicalChainedScope, because other parts of compiler are not ready to work with them @@ -80,7 +81,9 @@ class LexicalChainedScope private constructor( "; for descriptor: ", ownerDescriptor.name, " with implicitReceiver: ", - if (implicitReceivers.isEmpty()) "NONE" else implicitReceivers.joinToString { it.value.toString() }, + implicitReceiver?.value ?: "NONE", + " with contextReceiversGroup: ", + if (contextReceiversGroup.isEmpty()) "NONE" else contextReceiversGroup.joinToString { it.value.toString() }, " {" ) p.pushIndent() @@ -111,13 +114,14 @@ class LexicalChainedScope private constructor( parent: LexicalScope, ownerDescriptor: DeclarationDescriptor, isOwnerDescriptorAccessibleByLabel: Boolean, - implicitReceivers: List, + implicitReceiver: ReceiverParameterDescriptor?, + contextReceiversGroup: List, kind: LexicalScopeKind, vararg memberScopes: MemberScope?, isStaticScope: Boolean = false ): LexicalScope = LexicalChainedScope( - parent, ownerDescriptor, isOwnerDescriptorAccessibleByLabel, implicitReceivers, kind, + parent, ownerDescriptor, isOwnerDescriptorAccessibleByLabel, implicitReceiver, contextReceiversGroup, kind, listOfNonEmptyScopes(*memberScopes).toTypedArray(), isStaticScope ) diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/scopes/LexicalScopeImpl.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/scopes/LexicalScopeImpl.kt index 6d9a076971e..bfc77271438 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/scopes/LexicalScopeImpl.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/scopes/LexicalScopeImpl.kt @@ -23,7 +23,8 @@ class LexicalScopeImpl @JvmOverloads constructor( parent: HierarchicalScope, override val ownerDescriptor: DeclarationDescriptor, override val isOwnerDescriptorAccessibleByLabel: Boolean, - override val implicitReceivers: List, + override val implicitReceiver: ReceiverParameterDescriptor?, + override val contextReceiversGroup: List, override val kind: LexicalScopeKind, redeclarationChecker: LocalRedeclarationChecker = LocalRedeclarationChecker.DO_NOTHING, initialize: LexicalScopeImpl.InitializeHandler.() -> Unit = {} @@ -43,7 +44,9 @@ class LexicalScopeImpl @JvmOverloads constructor( "; for descriptor: ", ownerDescriptor.name, " with implicitReceiver: ", - if (implicitReceivers.isEmpty()) "NONE" else implicitReceivers.joinToString { it.value.toString() }, + implicitReceiver?.value ?: "NONE", + " with contextReceiversGroup: ", + if (contextReceiversGroup.isEmpty()) "NONE" else contextReceiversGroup.joinToString { it.value.toString() }, " {" ) p.pushIndent() diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/scopes/LexicalWritableScope.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/scopes/LexicalWritableScope.kt index 6be44fcfb0a..ee5dca45933 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/scopes/LexicalWritableScope.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/scopes/LexicalWritableScope.kt @@ -30,7 +30,9 @@ class LexicalWritableScope( override val kind: LexicalScopeKind ) : LexicalScopeStorage(parent, redeclarationChecker) { - override val implicitReceivers: List + override val implicitReceiver: ReceiverParameterDescriptor? + get() = null + override val contextReceiversGroup: List get() = emptyList() private var canWrite: Boolean = true @@ -111,7 +113,9 @@ class LexicalWritableScope( "; for descriptor: ", ownerDescriptor.name, " with implicitReceivers: ", - if (implicitReceivers.isEmpty()) "NONE" else implicitReceivers.joinToString { it.value.toString() }, + implicitReceiver?.value ?: "NONE", + " with contextReceiversGroup: ", + if (contextReceiversGroup.isEmpty()) "NONE" else contextReceiversGroup.joinToString { it.value.toString() }, " {" ) p.pushIndent() diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/scopes/ScopeUtils.java b/compiler/resolution/src/org/jetbrains/kotlin/resolve/scopes/ScopeUtils.java index fc257c82cb6..65e22a4abff 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/scopes/ScopeUtils.java +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/scopes/ScopeUtils.java @@ -36,7 +36,8 @@ public final class ScopeUtils { @NotNull LexicalScope parent, @NotNull PropertyDescriptor propertyDescriptor ) { - return new LexicalScopeImpl(parent, propertyDescriptor, false, Collections.emptyList(), LexicalScopeKind.PROPERTY_HEADER, + return new LexicalScopeImpl(parent, propertyDescriptor, false, null, Collections.emptyList(), + LexicalScopeKind.PROPERTY_HEADER, // redeclaration on type parameters should be reported early, see: DescriptorResolver.resolvePropertyDescriptor() LocalRedeclarationChecker.DO_NOTHING.INSTANCE, handler -> { @@ -52,7 +53,8 @@ public final class ScopeUtils { @NotNull LexicalScope propertyHeader, @NotNull PropertyDescriptor propertyDescriptor ) { - return new LexicalScopeImpl(propertyHeader, propertyDescriptor, false, Collections.emptyList(), LexicalScopeKind.PROPERTY_INITIALIZER_OR_DELEGATE); + return new LexicalScopeImpl(propertyHeader, propertyDescriptor, false, null, Collections.emptyList(), + LexicalScopeKind.PROPERTY_INITIALIZER_OR_DELEGATE); } @NotNull @@ -60,14 +62,9 @@ public final class ScopeUtils { @NotNull LexicalScope parent, @NotNull VariableDescriptorWithAccessors variableDescriptor ) { - List implicitReceivers = new ArrayList<>(); - ReceiverParameterDescriptor extensionReceiverParameter = variableDescriptor.getExtensionReceiverParameter(); - if (extensionReceiverParameter != null) { - implicitReceivers.add(extensionReceiverParameter); - } // todo: very strange scope! - return new LexicalScopeImpl(parent, variableDescriptor, true, implicitReceivers, - LexicalScopeKind.PROPERTY_DELEGATE_METHOD + return new LexicalScopeImpl(parent, variableDescriptor, true, variableDescriptor.getExtensionReceiverParameter(), + /* TODO: Context receivers? */ Collections.emptyList(), LexicalScopeKind.PROPERTY_DELEGATE_METHOD ); } diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/scopes/Scopes.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/scopes/Scopes.kt index 5ae34be3060..3b4befa08ff 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/scopes/Scopes.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/scopes/Scopes.kt @@ -36,7 +36,8 @@ interface LexicalScope : HierarchicalScope { val ownerDescriptor: DeclarationDescriptor val isOwnerDescriptorAccessibleByLabel: Boolean - val implicitReceivers: List + val implicitReceiver: ReceiverParameterDescriptor? + val contextReceiversGroup: List val kind: LexicalScopeKind @@ -50,7 +51,9 @@ interface LexicalScope : HierarchicalScope { override val isOwnerDescriptorAccessibleByLabel: Boolean get() = false - override val implicitReceivers: List + override val implicitReceiver: ReceiverParameterDescriptor? + get() = null + override val contextReceiversGroup: List get() = emptyList() override val kind: LexicalScopeKind diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/scopes/utils/ScopeUtils.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/scopes/utils/ScopeUtils.kt index c8ec684acdb..64b7f4ac944 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/scopes/utils/ScopeUtils.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/scopes/utils/ScopeUtils.kt @@ -36,7 +36,7 @@ val HierarchicalScope.parents: Sequence * Adds receivers to the list in order of locality, so that the closest (the most local) receiver goes first */ fun LexicalScope.getImplicitReceiversHierarchy(): List = collectFromMeAndParent { - (it as? LexicalScope)?.implicitReceivers + if (it is LexicalScope) listOfNotNull(it.implicitReceiver) + it.contextReceiversGroup else null }.flatten() fun LexicalScope.getDeclarationsByLabel(labelName: Name): Collection = collectAllFromMeAndParent { @@ -261,7 +261,7 @@ fun LexicalScope.replaceImportingScopes(importingScopeChain: ImportingScope?): L fun LexicalScope.createScopeForDestructuring(newReceiver: ReceiverParameterDescriptor?): LexicalScope { return LexicalScopeImpl( parent, ownerDescriptor, isOwnerDescriptorAccessibleByLabel, - listOfNotNull(newReceiver), + newReceiver, listOf(), LexicalScopeKind.FUNCTION_HEADER_FOR_DESTRUCTURING ) } @@ -324,7 +324,8 @@ class ErrorLexicalScope : LexicalScope { override val ownerDescriptor: DeclarationDescriptor = ErrorUtils.createErrorClass("") override val isOwnerDescriptorAccessibleByLabel: Boolean = false - override val implicitReceivers: List = emptyList() + override val implicitReceiver: ReceiverParameterDescriptor? = null + override val contextReceiversGroup: List = emptyList() override val kind: LexicalScopeKind = LexicalScopeKind.THROWING override fun getContributedClassifier(name: Name, location: LookupLocation): ClassifierDescriptor? = null diff --git a/compiler/testData/diagnostics/tests/extensions/contextReceivers/ambiguityInGroupSimple.fir.kt b/compiler/testData/diagnostics/tests/extensions/contextReceivers/ambiguityInGroupSimple.fir.kt new file mode 100644 index 00000000000..cd6828d4c70 --- /dev/null +++ b/compiler/testData/diagnostics/tests/extensions/contextReceivers/ambiguityInGroupSimple.fir.kt @@ -0,0 +1,11 @@ +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 new file mode 100644 index 00000000000..38a5a363db5 --- /dev/null +++ b/compiler/testData/diagnostics/tests/extensions/contextReceivers/ambiguityInGroupSimple.kt @@ -0,0 +1,11 @@ +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 new file mode 100644 index 00000000000..8f83c69e42f --- /dev/null +++ b/compiler/testData/diagnostics/tests/extensions/contextReceivers/ambiguityInGroupSimple.txt @@ -0,0 +1,17 @@ +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 new file mode 100644 index 00000000000..a57b366e941 --- /dev/null +++ b/compiler/testData/diagnostics/tests/extensions/contextReceivers/ambiguityInGroupWithInheritance.fir.kt @@ -0,0 +1,14 @@ +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 new file mode 100644 index 00000000000..a757e62e711 --- /dev/null +++ b/compiler/testData/diagnostics/tests/extensions/contextReceivers/ambiguityInGroupWithInheritance.kt @@ -0,0 +1,14 @@ +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.txt b/compiler/testData/diagnostics/tests/extensions/contextReceivers/ambiguityInGroupWithInheritance.txt new file mode 100644 index 00000000000..cedf6957697 --- /dev/null +++ b/compiler/testData/diagnostics/tests/extensions/contextReceivers/ambiguityInGroupWithInheritance.txt @@ -0,0 +1,23 @@ +package + +public fun foo(): kotlin.Unit +public fun test(): kotlin.Unit +public fun Common.bar(): 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 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 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 override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} 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 c7819d5f0c8..e17f96306a2 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 @@ -10582,6 +10582,18 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest { KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/extensions/contextReceivers"), Pattern.compile("^(.*)\\.kts?$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true); } + @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"); + } + @Test @TestMetadata("dp.kt") public void testDp() throws Exception { diff --git a/compiler/tests-common/tests/org/jetbrains/kotlin/resolve/ExpectedResolveDataUtil.java b/compiler/tests-common/tests/org/jetbrains/kotlin/resolve/ExpectedResolveDataUtil.java index 671b109a52d..88f0322bf8d 100644 --- a/compiler/tests-common/tests/org/jetbrains/kotlin/resolve/ExpectedResolveDataUtil.java +++ b/compiler/tests-common/tests/org/jetbrains/kotlin/resolve/ExpectedResolveDataUtil.java @@ -148,7 +148,7 @@ public class ExpectedResolveDataUtil { emptyModule.initialize(PackageFragmentProvider.Empty.INSTANCE); LexicalScopeImpl lexicalScope = new LexicalScopeImpl(ImportingScope.Empty.INSTANCE, classDescriptor, false, - Collections.singletonList(classDescriptor.getThisAsReceiverParameter()), + classDescriptor.getThisAsReceiverParameter(), Collections.emptyList(), LexicalScopeKind.SYNTHETIC); LanguageVersionSettings languageVersionSettings = CommonConfigurationKeysKt.getLanguageVersionSettings(environment.getConfiguration()); diff --git a/compiler/tests/org/jetbrains/kotlin/types/DefaultModalityModifiersTest.java b/compiler/tests/org/jetbrains/kotlin/types/DefaultModalityModifiersTest.java index f6dcfba0e2b..3fab73cf253 100644 --- a/compiler/tests/org/jetbrains/kotlin/types/DefaultModalityModifiersTest.java +++ b/compiler/tests/org/jetbrains/kotlin/types/DefaultModalityModifiersTest.java @@ -100,7 +100,7 @@ public class DefaultModalityModifiersTest extends KotlinTestWithEnvironment { DeclarationDescriptor classDescriptor = bindingContext.getBindingContext().get(BindingContext.DECLARATION_TO_DESCRIPTOR, aClass); return new LexicalScopeImpl( - ScopeUtilsKt.memberScopeAsImportingScope(libraryScope), root, false, Collections.emptyList(), + ScopeUtilsKt.memberScopeAsImportingScope(libraryScope), root, false, null, Collections.emptyList(), LexicalScopeKind.SYNTHETIC, LocalRedeclarationChecker.DO_NOTHING.INSTANCE, handler -> { handler.addClassifierDescriptor((ClassifierDescriptor) classDescriptor); diff --git a/compiler/tests/org/jetbrains/kotlin/types/KotlinTypeCheckerTest.java b/compiler/tests/org/jetbrains/kotlin/types/KotlinTypeCheckerTest.java index 4db77e1c2a8..6a8db7f79da 100644 --- a/compiler/tests/org/jetbrains/kotlin/types/KotlinTypeCheckerTest.java +++ b/compiler/tests/org/jetbrains/kotlin/types/KotlinTypeCheckerTest.java @@ -551,7 +551,7 @@ public class KotlinTypeCheckerTest extends KotlinTestWithEnvironment { ); LexicalScope scope = new LexicalScopeImpl(scopeWithImports, scopeWithImports.getOwnerDescriptor(), false, - Collections.singletonList(receiverParameterDescriptor), LexicalScopeKind.SYNTHETIC); + receiverParameterDescriptor, Collections.emptyList(), LexicalScopeKind.SYNTHETIC); assertType(scope, expression, expectedType); } diff --git a/compiler/tests/org/jetbrains/kotlin/types/TypeSubstitutorTest.java b/compiler/tests/org/jetbrains/kotlin/types/TypeSubstitutorTest.java index a0e6a39e5e9..810cc2e68db 100644 --- a/compiler/tests/org/jetbrains/kotlin/types/TypeSubstitutorTest.java +++ b/compiler/tests/org/jetbrains/kotlin/types/TypeSubstitutorTest.java @@ -91,7 +91,7 @@ public class TypeSubstitutorTest extends KotlinTestWithEnvironment { LocalRedeclarationChecker redeclarationChecker = new ThrowingLocalRedeclarationChecker(new OverloadChecker(TypeSpecificityComparator.NONE.INSTANCE)); LexicalScope typeParameters = new LexicalScopeImpl( - topLevelScope, module, false, Collections.emptyList(), LexicalScopeKind.SYNTHETIC, + topLevelScope, module, false, null, Collections.emptyList(), LexicalScopeKind.SYNTHETIC, redeclarationChecker, handler -> { for (TypeParameterDescriptor parameterDescriptor : contextClass.getTypeConstructor().getParameters()) { @@ -101,7 +101,8 @@ public class TypeSubstitutorTest extends KotlinTestWithEnvironment { } ); return LexicalChainedScope.Companion.create( - typeParameters, module, false, Collections.emptyList(), LexicalScopeKind.SYNTHETIC, + typeParameters, module, false, null, Collections.emptyList(), + LexicalScopeKind.SYNTHETIC, contextClass.getDefaultType().getMemberScope(), module.getBuiltIns().getBuiltInsPackageScope() ); diff --git a/compiler/tests/org/jetbrains/kotlin/types/TypeUnifierTest.java b/compiler/tests/org/jetbrains/kotlin/types/TypeUnifierTest.java index 18bfa87f00c..1f0f6bc9f31 100644 --- a/compiler/tests/org/jetbrains/kotlin/types/TypeUnifierTest.java +++ b/compiler/tests/org/jetbrains/kotlin/types/TypeUnifierTest.java @@ -198,7 +198,7 @@ public class TypeUnifierTest extends KotlinTestWithEnvironment { private TypeProjection makeType(String typeStr) { LexicalScope withX = new LexicalScopeImpl( builtinsImportingScope, module, - false, Collections.emptyList(), LexicalScopeKind.SYNTHETIC, LocalRedeclarationChecker.DO_NOTHING.INSTANCE, + false, null, Collections.emptyList(), LexicalScopeKind.SYNTHETIC, LocalRedeclarationChecker.DO_NOTHING.INSTANCE, handler -> { handler.addClassifierDescriptor(x); handler.addClassifierDescriptor(y); diff --git a/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/resolve/LazyScriptDescriptor.kt b/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/resolve/LazyScriptDescriptor.kt index e65d187682d..156b4d2fefe 100644 --- a/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/resolve/LazyScriptDescriptor.kt +++ b/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/resolve/LazyScriptDescriptor.kt @@ -374,7 +374,8 @@ class LazyScriptDescriptor( outerScope, receiverClassDescriptor, true, - listOf(receiverClassDescriptor.thisAsReceiverParameter), + receiverClassDescriptor.thisAsReceiverParameter, + listOf(), LexicalScopeKind.CLASS_MEMBER_SCOPE ).addImportingScope( AllUnderImportScope.create(receiverClassDescriptor, emptyList()) diff --git a/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/repl/ReplImplicitsExtensionsResolutionFilter.kt b/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/repl/ReplImplicitsExtensionsResolutionFilter.kt index 3815deda85c..8954c06ae6c 100644 --- a/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/repl/ReplImplicitsExtensionsResolutionFilter.kt +++ b/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/repl/ReplImplicitsExtensionsResolutionFilter.kt @@ -41,7 +41,8 @@ class ReplImplicitsExtensionsResolutionFilter( ): Sequence { val processedReceivers = mutableSetOf() return scopes.map { scope -> - val receivers = (scope as? LexicalScope)?.implicitReceivers?.map { it.value } + val receivers = (if (scope is LexicalScope) listOfNotNull(scope.implicitReceiver) + scope.contextReceiversGroup else null) + ?.map { it.value } val keep = receivers?.all { lock.read { when (val descriptorFqName = (it as? ImplicitClassReceiver)?.declarationDescriptor?.fqNameSafe?.asString()) {