diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/NewResolveOldInference.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/NewResolveOldInference.kt index c6b60d67f8a..cdc4512adb6 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/NewResolveOldInference.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/NewResolveOldInference.kt @@ -35,10 +35,13 @@ import org.jetbrains.kotlin.resolve.calls.model.ResolvedCallImpl import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCallImpl import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResultsImpl import org.jetbrains.kotlin.resolve.calls.results.ResolutionResultsHandler +import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus +import org.jetbrains.kotlin.resolve.calls.tasks.DynamicCallableDescriptors import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategy import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategyForInvoke import org.jetbrains.kotlin.resolve.scopes.receivers.* +import org.jetbrains.kotlin.types.isDynamic import org.jetbrains.kotlin.util.OperatorNameConventions import org.jetbrains.kotlin.utils.addToStdlib.check import org.jetbrains.kotlin.utils.sure @@ -46,7 +49,8 @@ import org.jetbrains.kotlin.utils.sure class NewResolveOldInference( val candidateResolver: CandidateResolver, val towerResolver: TowerResolver, - val resolutionResultsHandler: ResolutionResultsHandler + val resolutionResultsHandler: ResolutionResultsHandler, + val dynamicCallableDescriptors: DynamicCallableDescriptors ) { fun runResolve( @@ -57,7 +61,8 @@ class NewResolveOldInference( ): OverloadResolutionResultsImpl<*> { val explicitReceiver = context.call.explicitReceiver.check { it.exists() } - val scopeTower = ScopeTowerImpl(context, explicitReceiver, context.call.createLookupLocation()) + val dynamicScope = dynamicCallableDescriptors.createDynamicDescriptorScope(context.call, context.scope.ownerDescriptor) + val scopeTower = ScopeTowerImpl(context, dynamicScope, explicitReceiver, context.call.createLookupLocation()) val baseContext = Context(scopeTower, name, context, tracing) @@ -74,7 +79,7 @@ class NewResolveOldInference( val call = (context.call as? CallTransformer.CallForImplicitInvoke).sure { "Call should be CallForImplicitInvoke, but it is: ${context.call}" } - createCollectorWithReceiverValueOrEmpty(explicitReceiver) { + createProcessorWithReceiverValueOrEmpty(explicitReceiver) { createCallTowerProcessorForExplicitInvoke(baseContext, call.dispatchReceiver, it) } } @@ -87,7 +92,7 @@ class NewResolveOldInference( return convertToOverloadResults(candidates, tracing, context) } - private fun createCollectorWithReceiverValueOrEmpty( + private fun createProcessorWithReceiverValueOrEmpty( explicitReceiver: Receiver?, create: (ReceiverValue?) -> ScopeTowerProcessor ): ScopeTowerProcessor { @@ -100,7 +105,6 @@ class NewResolveOldInference( } } - private fun createFunctionTowerProcessor(baseContext: Context, explicitReceiver: Receiver?): CompositeScopeTowerProcessor { // a.foo() -- simple function call val simpleFunction = createFunctionProcessor(baseContext, explicitReceiver) @@ -109,7 +113,7 @@ class NewResolveOldInference( val invokeProcessor = InvokeTowerProcessor(baseContext, explicitReceiver) // a.foo() -- property foo is extension function with receiver a -- a.invoke() - val invokeExtensionProcessor = createCollectorWithReceiverValueOrEmpty(explicitReceiver) { InvokeExtensionTowerProcessor(baseContext, it) } + val invokeExtensionProcessor = createProcessorWithReceiverValueOrEmpty(explicitReceiver) { InvokeExtensionTowerProcessor(baseContext, it) } return CompositeScopeTowerProcessor(simpleFunction, invokeProcessor, invokeExtensionProcessor) } @@ -178,6 +182,14 @@ class NewResolveOldInference( explicitReceiverKind, null, candidateTrace, tracing, basicCallContext.dataFlowInfoForArguments // todo may be we should create new mutable info for arguments ) + + // see spec-docs/dynamic-types.md + if (extensionReceiver != null && extensionReceiver.type.isDynamic() + && !towerCandidate.descriptor.extensionReceiverParameter!!.value.type.isDynamic()) { + candidateCall.addStatus(ResolutionStatus.RECEIVER_PRESENCE_ERROR) + return Candidate(ResolutionCandidateStatus(listOf(ExtensionWithStaticTypeWithDynamicReceiver)), candidateCall) + } + val callCandidateResolutionContext = CallCandidateResolutionContext.create( candidateCall, basicCallContext, candidateTrace, tracing, basicCallContext.call, ReceiverValue.NO_RECEIVER, CandidateResolveMode.FULLY // todo diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/ScopeTower.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/ScopeTower.kt index 4f54a336e33..acd3138d16b 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/ScopeTower.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/ScopeTower.kt @@ -21,6 +21,7 @@ import org.jetbrains.kotlin.incremental.components.LookupLocation import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValue import org.jetbrains.kotlin.resolve.scopes.LexicalScope +import org.jetbrains.kotlin.resolve.scopes.MemberScope import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue import org.jetbrains.kotlin.types.KotlinType @@ -33,6 +34,8 @@ interface ScopeTower { val lexicalScope: LexicalScope + val dynamicScope: MemberScope + val location: LookupLocation val dataFlowInfo: DataFlowDecorator @@ -91,6 +94,8 @@ class UsedSmartCastForDispatchReceiver(val smartCastType: KotlinType): Resolutio object ErrorDescriptorDiagnostic : ResolutionDiagnostic(ResolutionCandidateApplicability.INAPPLICABLE) object SynthesizedDescriptorDiagnostic: ResolutionDiagnostic(ResolutionCandidateApplicability.RESOLVED_SYNTHESIZED) +object DynamicDescriptorDiagnostic: ResolutionDiagnostic(ResolutionCandidateApplicability.RESOLVED_SYNTHESIZED) object UnstableSmartCastDiagnostic: ResolutionDiagnostic(ResolutionCandidateApplicability.MAY_THROW_RUNTIME_ERROR) +object ExtensionWithStaticTypeWithDynamicReceiver: ResolutionDiagnostic(ResolutionCandidateApplicability.INAPPLICABLE) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/ScopeTowerImpl.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/ScopeTowerImpl.kt index 98c823390a2..95f0c1a139a 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/ScopeTowerImpl.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/ScopeTowerImpl.kt @@ -24,6 +24,7 @@ import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValue import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory import org.jetbrains.kotlin.resolve.scopes.ImportingScope import org.jetbrains.kotlin.resolve.scopes.LexicalScope +import org.jetbrains.kotlin.resolve.scopes.MemberScope import org.jetbrains.kotlin.resolve.scopes.receivers.ClassQualifier import org.jetbrains.kotlin.resolve.scopes.receivers.Receiver import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue @@ -43,6 +44,7 @@ internal class CandidateWithBoundDispatchReceiverImpl( internal class ScopeTowerImpl( resolutionContext: ResolutionContext<*>, + override val dynamicScope: MemberScope, private val explicitReceiver: Receiver?, override val location: LookupLocation ): ScopeTower { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/TowerLevels.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/TowerLevels.kt index 989f4d49691..8df72ea76b7 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/TowerLevels.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/TowerLevels.kt @@ -29,6 +29,7 @@ import org.jetbrains.kotlin.resolve.scopes.receivers.QualifierReceiver import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue import org.jetbrains.kotlin.types.ErrorUtils import org.jetbrains.kotlin.types.KotlinType +import org.jetbrains.kotlin.types.isDynamic import org.jetbrains.kotlin.utils.addIfNotNull import java.util.* @@ -147,6 +148,12 @@ internal class ReceiverScopeTowerLevel( } } + if (dispatchReceiver.type.isDynamic()) { + scopeTower.dynamicScope.members().mapTo(result) { + createCandidateDescriptor(it, dispatchReceiver, DynamicDescriptorDiagnostic) + } + } + return result }