diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallResolver.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallResolver.java index 4c661f53bad..87d11a073f0 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallResolver.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallResolver.java @@ -44,6 +44,7 @@ import org.jetbrains.kotlin.resolve.calls.results.ResolutionResultsHandler; import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo; import org.jetbrains.kotlin.resolve.calls.tasks.*; import org.jetbrains.kotlin.resolve.calls.tasks.collectors.CallableDescriptorCollectors; +import org.jetbrains.kotlin.resolve.calls.tower.NewResolveOldInference; import org.jetbrains.kotlin.resolve.calls.util.CallMaker; import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt; import org.jetbrains.kotlin.resolve.lazy.ForceResolveUtil; @@ -78,6 +79,7 @@ public class CallResolver { private ArgumentTypeResolver argumentTypeResolver; private GenericCandidateResolver genericCandidateResolver; private CallCompleter callCompleter; + private NewResolveOldInference newCallResolver; private final TaskPrioritizer taskPrioritizer; private final ResolutionResultsHandler resolutionResultsHandler; @NotNull private KotlinBuiltIns builtIns; @@ -85,6 +87,8 @@ public class CallResolver { private static final PerformanceCounter callResolvePerfCounter = PerformanceCounter.Companion.create("Call resolve", ExpressionTypingVisitorDispatcher.typeInfoPerfCounter); private static final PerformanceCounter candidatePerfCounter = PerformanceCounter.Companion.create("Call resolve candidate analysis", true); + public static boolean useNewResolve = System.getProperty("kotlin.internal.new_resolve") != null; + public CallResolver( @NotNull TaskPrioritizer taskPrioritizer, @NotNull ResolutionResultsHandler resolutionResultsHandler, @@ -131,6 +135,12 @@ public class CallResolver { this.callCompleter = callCompleter; } + // component dependency cycle + @Inject + public void setCallCompleter(@NotNull NewResolveOldInference newCallResolver) { + this.newCallResolver = newCallResolver; + } + @NotNull public OverloadResolutionResults resolveSimpleProperty(@NotNull BasicCallResolutionContext context) { KtExpression calleeExpression = context.call.getCalleeExpression(); @@ -592,6 +602,12 @@ public class CallResolver { } } + if (contextForMigration.resolveKind != ResolveKind.GIVEN_CANDIDATES && useNewResolve) { + assert contextForMigration.name != null; + return (OverloadResolutionResultsImpl) + newCallResolver.runResolve(context, contextForMigration.name, contextForMigration.resolveKind, tracing); + } + return doResolveCall(context, contextForMigration.lazyTasks.invoke(), contextForMigration.callTransformer, tracing); } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/model/VariableAsFunctionResolvedCall.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/model/VariableAsFunctionResolvedCall.kt index 31db54d9bd8..760e93356f7 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/model/VariableAsFunctionResolvedCall.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/model/VariableAsFunctionResolvedCall.kt @@ -20,6 +20,7 @@ import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.VariableDescriptor import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus import org.jetbrains.kotlin.resolve.DelegatingBindingTrace +import org.jetbrains.kotlin.resolve.calls.CallResolver public interface VariableAsFunctionResolvedCall { public val functionCall: ResolvedCall @@ -42,6 +43,9 @@ class VariableAsFunctionResolvedCallImpl( override fun getTrace(): DelegatingBindingTrace { //functionCall.trace is temporary trace above variableCall.trace and is committed already + if (CallResolver.useNewResolve) { + return functionCall.trace + } return variableCall.getTrace() } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/results/ResolutionResultsHandler.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/results/ResolutionResultsHandler.java index 8b7ae6ec474..0d82f227cc4 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/results/ResolutionResultsHandler.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/results/ResolutionResultsHandler.java @@ -184,7 +184,7 @@ public class ResolutionResultsHandler { } @NotNull - private OverloadResolutionResultsImpl chooseAndReportMaximallySpecific( + public OverloadResolutionResultsImpl chooseAndReportMaximallySpecific( @NotNull Set> candidates, boolean discriminateGenerics, @NotNull CheckArgumentTypesMode checkArgumentsMode diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/TaskPrioritizer.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/TaskPrioritizer.kt index 93c63661367..386cca73f60 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/TaskPrioritizer.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/TaskPrioritizer.kt @@ -99,7 +99,7 @@ public class TaskPrioritizer( taskPrioritizerContext: TaskPrioritizerContext ) { if (qualifier is ClassQualifier) { - val companionObject = qualifier.companionObjectReceiver ?: return + val companionObject = qualifier.classValueReceiver ?: return val classifierDescriptor = qualifier.classifier doComputeTasks(companionObject, taskPrioritizerContext.filterCollectors { when { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/InvokeProcessors.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/InvokeProcessors.kt new file mode 100644 index 00000000000..c76e2877b3e --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/InvokeProcessors.kt @@ -0,0 +1,213 @@ +/* + * Copyright 2010-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.resolve.calls.tower + +import com.intellij.util.SmartList +import org.jetbrains.kotlin.builtins.KotlinBuiltIns +import org.jetbrains.kotlin.descriptors.FunctionDescriptor +import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind +import org.jetbrains.kotlin.resolve.calls.tasks.createSynthesizedInvokes +import org.jetbrains.kotlin.resolve.scopes.receivers.Receiver +import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue +import org.jetbrains.kotlin.util.OperatorNameConventions +import java.util.* + + +internal abstract class AbstractInvokeTowerProcessor( + protected val functionContext: TowerContext, + private val variableProcessor: ScopeTowerProcessor +) : ScopeTowerProcessor { + // todo optimize it + private val previousActions = ArrayList.() -> Unit>() + private val candidateGroups: MutableList> = ArrayList() + + private val invokeProcessors: MutableList> = ArrayList() + + + private inner class VariableInvokeProcessor( + val variableCandidate: C, + val invokeProcessor: ScopeTowerProcessor = createInvokeProcessor(variableCandidate) + ): ScopeTowerProcessor by invokeProcessor { + override fun getCandidatesGroups(): List> + = invokeProcessor.getCandidatesGroups().map { candidateGroup -> + candidateGroup.map { functionContext.transformCandidate(variableCandidate, it) } + } + } + + protected abstract fun createInvokeProcessor(variableCandidate: C): ScopeTowerProcessor + + private fun findVariablesAndCreateNewInvokeCandidates() { + for (variableCandidates in variableProcessor.getCandidatesGroups()) { + val successfulVariables = variableCandidates.filter { + functionContext.getStatus(it).resultingApplicability.isSuccess + } + + if (successfulVariables.isNotEmpty()) { + val processors = successfulVariables.map { VariableInvokeProcessor(it) } + invokeProcessors.add(processors) + + for (previousAction in previousActions) { + processors.forEach(previousAction) + candidateGroups.addAll(processors.collectCandidateGroups()) + } + } + } + } + + private fun Collection.collectCandidateGroups(): List> { + return when (size) { + 0 -> emptyList() + 1 -> single().getCandidatesGroups() + // overload on variables see KT-10093 Resolve depends on the order of declaration for variable with implicit invoke + + else -> listOf(this.flatMap { it.getCandidatesGroups().flatten() }) + } + } + + private fun proceed(action: ScopeTowerProcessor.() -> Unit) { + candidateGroups.clear() + previousActions.add(action) + + for (processorsGroup in invokeProcessors) { + processorsGroup.forEach(action) + candidateGroups.addAll(processorsGroup.collectCandidateGroups()) + } + + variableProcessor.action() + findVariablesAndCreateNewInvokeCandidates() + } + + init { proceed { /* do nothing */ } } + + override fun processTowerLevel(level: ScopeTowerLevel) = proceed { this.processTowerLevel(level) } + + override fun processImplicitReceiver(implicitReceiver: ReceiverValue) + = proceed { this.processImplicitReceiver(implicitReceiver) } + + override fun getCandidatesGroups(): List> = SmartList(candidateGroups) +} + +// todo KT-9522 Allow invoke convention for synthetic property +internal class InvokeTowerProcessor( + functionContext: TowerContext, + private val explicitReceiver: Receiver? +) : AbstractInvokeTowerProcessor( + functionContext, + createVariableProcessor(functionContext.contextForVariable(stripExplicitReceiver = false), explicitReceiver) +) { + + // todo filter by operator + override fun createInvokeProcessor(variableCandidate: C): ScopeTowerProcessor { + val (variableReceiver, invokeContext) = functionContext.contextForInvoke(variableCandidate, useExplicitReceiver = false) + return ExplicitReceiverScopeTowerProcessor(invokeContext, variableReceiver, ScopeTowerLevel::getFunctions) + } +} + +internal class InvokeExtensionTowerProcessor( + functionContext: TowerContext, + private val explicitReceiver: ReceiverValue? +) : AbstractInvokeTowerProcessor( + functionContext, + createVariableProcessor(functionContext.contextForVariable(stripExplicitReceiver = true), explicitReceiver = null) +) { + + override fun createInvokeProcessor(variableCandidate: C): ScopeTowerProcessor { + val (variableReceiver, invokeContext) = functionContext.contextForInvoke(variableCandidate, useExplicitReceiver = true) + val invokeDescriptor = functionContext.scopeTower.getExtensionInvokeCandidateDescriptor(variableReceiver) + ?: return KnownResultProcessor(emptyList()) + return InvokeExtensionScopeTowerProcessor(invokeContext, invokeDescriptor, explicitReceiver) + } +} + +private class InvokeExtensionScopeTowerProcessor( + context: TowerContext, + val invokeCandidateDescriptor: CandidateWithBoundDispatchReceiver, + val explicitReceiver: ReceiverValue? +) : AbstractScopeTowerProcessor(context) { + override var candidates: Collection = resolve(explicitReceiver) + + private fun resolve(extensionReceiver: ReceiverValue?): Collection { + if (extensionReceiver == null) return emptyList() + + // todo + val explicitReceiverKind = if (explicitReceiver != null) ExplicitReceiverKind.BOTH_RECEIVERS else ExplicitReceiverKind.DISPATCH_RECEIVER + + val candidate = context.createCandidate(invokeCandidateDescriptor, explicitReceiverKind, extensionReceiver) + return listOf(candidate) + } + + override fun processTowerLevel(level: ScopeTowerLevel) { + candidates = emptyList() + } + + // todo optimize + override fun processImplicitReceiver(implicitReceiver: ReceiverValue) { + if (explicitReceiver == null) { + candidates = resolve(implicitReceiver) + } + else { + candidates = emptyList() + } + } +} + +// todo debug info +private fun ScopeTower.getExtensionInvokeCandidateDescriptor( + extensionFunctionReceiver: ReceiverValue +): CandidateWithBoundDispatchReceiver? { + if (!KotlinBuiltIns.isExactExtensionFunctionType(extensionFunctionReceiver.type)) return null + + return ReceiverScopeTowerLevel(this, extensionFunctionReceiver).getFunctions(OperatorNameConventions.INVOKE).single().let { + assert(it.diagnostics.isEmpty()) + val synthesizedInvoke = createSynthesizedInvokes(listOf(it.descriptor)).single() + + // here we don't add SynthesizedDescriptor diagnostic because it should has priority as member + CandidateWithBoundDispatchReceiverImpl(extensionFunctionReceiver, synthesizedInvoke, listOf()) + } +} + +// case 1.(foo())() or (foo())() +internal fun createCallTowerProcessorForExplicitInvoke( + contextForInvoke: TowerContext, + expressionForInvoke: ReceiverValue, + explicitReceiver: ReceiverValue? +): ScopeTowerProcessor { + val invokeExtensionDescriptor = contextForInvoke.scopeTower.getExtensionInvokeCandidateDescriptor(expressionForInvoke) + if (explicitReceiver != null) { + if (invokeExtensionDescriptor == null) { + // case 1.(foo())(), where foo() isn't extension function + return KnownResultProcessor(emptyList()) + } + else { + return InvokeExtensionScopeTowerProcessor(contextForInvoke, invokeExtensionDescriptor, explicitReceiver = explicitReceiver) + } + } + else { + val usualInvoke = ExplicitReceiverScopeTowerProcessor(contextForInvoke, expressionForInvoke, ScopeTowerLevel::getFunctions) // todo operator + + if (invokeExtensionDescriptor == null) { + return usualInvoke + } + else { + return CompositeScopeTowerProcessor( + usualInvoke, + InvokeExtensionScopeTowerProcessor(contextForInvoke, invokeExtensionDescriptor, explicitReceiver = null) + ) + } + } + +} \ No newline at end of file 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 new file mode 100644 index 00000000000..c6b60d67f8a --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/NewResolveOldInference.kt @@ -0,0 +1,235 @@ +/* + * Copyright 2010-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.resolve.calls.tower + +import org.jetbrains.kotlin.descriptors.CallableDescriptor +import org.jetbrains.kotlin.descriptors.FunctionDescriptor +import org.jetbrains.kotlin.descriptors.VariableDescriptor +import org.jetbrains.kotlin.diagnostics.Errors +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.resolve.TemporaryBindingTrace +import org.jetbrains.kotlin.resolve.calls.CallResolver +import org.jetbrains.kotlin.resolve.calls.CallTransformer +import org.jetbrains.kotlin.resolve.calls.CandidateResolver +import org.jetbrains.kotlin.resolve.calls.callUtil.createLookupLocation +import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext +import org.jetbrains.kotlin.resolve.calls.context.CallCandidateResolutionContext +import org.jetbrains.kotlin.resolve.calls.context.CandidateResolveMode +import org.jetbrains.kotlin.resolve.calls.context.ContextDependency +import org.jetbrains.kotlin.resolve.calls.model.MutableResolvedCall +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.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.util.OperatorNameConventions +import org.jetbrains.kotlin.utils.addToStdlib.check +import org.jetbrains.kotlin.utils.sure + +class NewResolveOldInference( + val candidateResolver: CandidateResolver, + val towerResolver: TowerResolver, + val resolutionResultsHandler: ResolutionResultsHandler +) { + + fun runResolve( + context: BasicCallResolutionContext, + name: Name, + kind: CallResolver.ResolveKind, + tracing: TracingStrategy + ): OverloadResolutionResultsImpl<*> { + val explicitReceiver = context.call.explicitReceiver.check { it.exists() } + + val scopeTower = ScopeTowerImpl(context, explicitReceiver, context.call.createLookupLocation()) + + val baseContext = Context(scopeTower, name, context, tracing) + + val processor = + when (kind) { + CallResolver.ResolveKind.VARIABLE -> createVariableProcessor(baseContext, explicitReceiver) + CallResolver.ResolveKind.FUNCTION -> createFunctionTowerProcessor(baseContext, explicitReceiver) + CallResolver.ResolveKind.CALLABLE_REFERENCE -> CompositeScopeTowerProcessor( + createFunctionTowerProcessor(baseContext, explicitReceiver), + createVariableProcessor(baseContext, explicitReceiver) + ) + CallResolver.ResolveKind.INVOKE -> { + // todo + val call = (context.call as? CallTransformer.CallForImplicitInvoke).sure { + "Call should be CallForImplicitInvoke, but it is: ${context.call}" + } + createCollectorWithReceiverValueOrEmpty(explicitReceiver) { + createCallTowerProcessorForExplicitInvoke(baseContext, call.dispatchReceiver, it) + } + } + CallResolver.ResolveKind.GIVEN_CANDIDATES -> { + throw UnsupportedOperationException("Kind $kind unsupported yet") + } + } + + val candidates = towerResolver.runResolve(baseContext, processor, useOrder = kind != CallResolver.ResolveKind.CALLABLE_REFERENCE) + return convertToOverloadResults(candidates, tracing, context) + } + + private fun createCollectorWithReceiverValueOrEmpty( + explicitReceiver: Receiver?, + create: (ReceiverValue?) -> ScopeTowerProcessor + ): ScopeTowerProcessor { + return if (explicitReceiver is Qualifier) { + (explicitReceiver as? ClassQualifier)?.classValueReceiver?.let(create) + ?: KnownResultProcessor(listOf()) + } + else { + create(explicitReceiver as ReceiverValue?) + } + } + + + private fun createFunctionTowerProcessor(baseContext: Context, explicitReceiver: Receiver?): CompositeScopeTowerProcessor { + // a.foo() -- simple function call + val simpleFunction = createFunctionProcessor(baseContext, explicitReceiver) + + // a.foo() -- property a.foo + foo.invoke() + val invokeProcessor = InvokeTowerProcessor(baseContext, explicitReceiver) + + // a.foo() -- property foo is extension function with receiver a -- a.invoke() + val invokeExtensionProcessor = createCollectorWithReceiverValueOrEmpty(explicitReceiver) { InvokeExtensionTowerProcessor(baseContext, it) } + + return CompositeScopeTowerProcessor(simpleFunction, invokeProcessor, invokeExtensionProcessor) + } + + + private fun convertToOverloadResults( + candidates: Collection, + tracing: TracingStrategy, + basicCallContext: BasicCallResolutionContext + ): OverloadResolutionResultsImpl<*> { + val resolvedCalls = candidates.mapNotNull { + val (status, resolvedCall) = it + if (resolvedCall is VariableAsFunctionResolvedCallImpl) { + // todo hacks + tracing.bindReference(resolvedCall.variableCall.trace, resolvedCall.variableCall) + tracing.bindResolvedCall(resolvedCall.variableCall.trace, resolvedCall) + + resolvedCall.variableCall.trace.addOwnDataTo(resolvedCall.functionCall.trace) + + resolvedCall.functionCall.tracingStrategy.bindReference(resolvedCall.functionCall.trace, resolvedCall.functionCall) + // resolvedCall.hackInvokeTracing.bindResolvedCall(resolvedCall.functionCall.trace, resolvedCall) + } else { + tracing.bindReference(resolvedCall.trace, resolvedCall) + tracing.bindResolvedCall(resolvedCall.trace, resolvedCall) + } + + if (resolvedCall.status.possibleTransformToSuccess()) { + for (error in status.diagnostics) { + if (error is UnsupportedInnerClassCall) { + resolvedCall.trace.report(Errors.UNSUPPORTED.on(resolvedCall.call.callElement, error.message)) + } + else if (error is NestedClassViaInstanceReference) { + tracing.nestedClassAccessViaInstanceReference(resolvedCall.trace, error.classDescriptor, resolvedCall.explicitReceiverKind) + } + else if (error is ErrorDescriptorDiagnostic) { + // todo + // return@map null + } + } + } + + resolvedCall + } + + return resolutionResultsHandler.computeResultAndReportErrors(basicCallContext, tracing, resolvedCalls as List>) + } + + private data class Candidate(val candidateStatus: ResolutionCandidateStatus, val resolvedCall: MutableResolvedCall<*>) + + private inner class Context( + override val scopeTower: ScopeTower, + override val name: Name, + private val basicCallContext: BasicCallResolutionContext, + private val tracing: TracingStrategy + ) : TowerContext { + + override fun createCandidate( + towerCandidate: CandidateWithBoundDispatchReceiver<*>, + explicitReceiverKind: ExplicitReceiverKind, + extensionReceiver: ReceiverValue? + ): Candidate { + val candidateTrace = TemporaryBindingTrace.create(basicCallContext.trace, "Context for resolve candidate") + val candidateCall = ResolvedCallImpl( + basicCallContext.call, towerCandidate.descriptor, + towerCandidate.dispatchReceiver ?: ReceiverValue.NO_RECEIVER, extensionReceiver ?: ReceiverValue.NO_RECEIVER, + explicitReceiverKind, null, candidateTrace, tracing, + basicCallContext.dataFlowInfoForArguments // todo may be we should create new mutable info for arguments + ) + val callCandidateResolutionContext = CallCandidateResolutionContext.create( + candidateCall, basicCallContext, candidateTrace, tracing, basicCallContext.call, + ReceiverValue.NO_RECEIVER, CandidateResolveMode.FULLY // todo + ) + candidateResolver.performResolutionForCandidateCall(callCandidateResolutionContext, basicCallContext.checkArguments) // todo + + val diagnostics = (towerCandidate.diagnostics + createPreviousResolveError(candidateCall.status)).filterNotNull() // todo + return Candidate(ResolutionCandidateStatus(diagnostics), candidateCall) + } + + override fun getStatus(candidate: Candidate): ResolutionCandidateStatus = candidate.candidateStatus + + override fun transformCandidate(variable: Candidate, invoke: Candidate): Candidate { + val resolvedCallImpl = VariableAsFunctionResolvedCallImpl( + invoke.resolvedCall as MutableResolvedCall, + variable.resolvedCall as MutableResolvedCall + ) + assert(variable.candidateStatus.resultingApplicability.isSuccess) { + "Variable call must be success: $variable" + } + + return Candidate(ResolutionCandidateStatus(variable.candidateStatus.diagnostics + invoke.candidateStatus.diagnostics), resolvedCallImpl) + } + + override fun contextForVariable(stripExplicitReceiver: Boolean): TowerContext { + val basicCallResolutionContext = basicCallContext.replaceCall(CallTransformer.stripCallArguments(basicCallContext.call)) + return Context(scopeTower, name, basicCallResolutionContext, tracing) + } + + override fun contextForInvoke(variable: Candidate, useExplicitReceiver: Boolean): Pair> { + assert(variable.resolvedCall.status.isSuccess) + val calleeExpression = variable.resolvedCall.call.calleeExpression + val variableDescriptor = variable.resolvedCall.resultingDescriptor + assert(variable.resolvedCall.status.isSuccess && calleeExpression != null && variableDescriptor is VariableDescriptor) { + "Unexpected varialbe candidate: $variable" + } + val variableReceiver = ExpressionReceiver.create(calleeExpression!!, + (variableDescriptor as VariableDescriptor).type, + basicCallContext.trace.bindingContext) + + // todo hack + val functionCall = CallTransformer.CallForImplicitInvoke( + basicCallContext.call.explicitReceiver.check { useExplicitReceiver } ?: ReceiverValue.NO_RECEIVER, + variableReceiver, basicCallContext.call) + val tracingForInvoke = TracingStrategyForInvoke(calleeExpression, functionCall, variableReceiver.type) + val basicCallResolutionContext = basicCallContext.replaceBindingTrace(variable.resolvedCall.trace) + .replaceContextDependency(ContextDependency.DEPENDENT) // todo + val newContext = Context(scopeTower, OperatorNameConventions.INVOKE, basicCallResolutionContext, tracingForInvoke) + + return variableReceiver to newContext + } + + } + +} \ No newline at end of file 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 new file mode 100644 index 00000000000..d84b12ed532 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/ScopeTower.kt @@ -0,0 +1,96 @@ +/* + * Copyright 2010-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.resolve.calls.tower + +import org.jetbrains.kotlin.descriptors.* +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.receivers.ReceiverValue +import org.jetbrains.kotlin.types.KotlinType + +interface ScopeTower { + /** + * Adds receivers to the list in order of locality, so that the closest (the most local) receiver goes first + * Doesn't include receivers with error types + */ + val implicitReceivers: List + + val lexicalScope: LexicalScope + + val location: LookupLocation + + val dataFlowInfo: DataFlowDecorator + + // The closest (the most local) levels goes first + val levels: Sequence +} + +interface DataFlowDecorator { + fun getDataFlowValue(receiver: ReceiverValue): DataFlowValue + + fun isStableReceiver(receiver: ReceiverValue): Boolean + + // doesn't include receiver.type + fun getSmartCastTypes(receiver: ReceiverValue): Set +} + +interface ScopeTowerLevel { + fun getVariables(name: Name): Collection> + + fun getFunctions(name: Name): Collection> +} + +interface CandidateWithBoundDispatchReceiver { + val descriptor: D + + val diagnostics: List + + val dispatchReceiver: ReceiverValue? +} + +class ResolutionCandidateStatus(val diagnostics: List) { + val resultingApplicability: ResolutionCandidateApplicability = diagnostics.asSequence().map { it.candidateLevel }.max() + ?: ResolutionCandidateApplicability.RESOLVED +} + +enum class ResolutionCandidateApplicability { + RESOLVED, // call success or has uncompleted inference or in other words possible successful candidate + RESOLVED_SYNTHESIZED, + CONVENTION_ERROR, // missing infix, operator etc + MAY_THROW_RUNTIME_ERROR, // unsafe call or unstable smart cast + RUNTIME_ERROR, // problems with visibility + IMPOSSIBLE_TO_GENERATE, // access to outer class from nested + INAPPLICABLE // arguments not matched + // todo wrong receiver +} + +abstract class ResolutionDiagnostic(val candidateLevel: ResolutionCandidateApplicability) + +// todo error for this access from nested class +class VisibilityError(val invisibleMember: DeclarationDescriptorWithVisibility): ResolutionDiagnostic(ResolutionCandidateApplicability.RUNTIME_ERROR) +class NestedClassViaInstanceReference(val classDescriptor: ClassDescriptor): ResolutionDiagnostic(ResolutionCandidateApplicability.IMPOSSIBLE_TO_GENERATE) +class InnerClassViaStaticReference(val classDescriptor: ClassDescriptor): ResolutionDiagnostic(ResolutionCandidateApplicability.IMPOSSIBLE_TO_GENERATE) +class UnsupportedInnerClassCall(val message: String): ResolutionDiagnostic(ResolutionCandidateApplicability.IMPOSSIBLE_TO_GENERATE) +class UsedSmartCastForDispatchReceiver(val smartCastType: KotlinType): ResolutionDiagnostic(ResolutionCandidateApplicability.RESOLVED_SYNTHESIZED) + +object ErrorDescriptorDiagnostic : ResolutionDiagnostic(ResolutionCandidateApplicability.INAPPLICABLE) +object SynthesizedDescriptorDiagnostic: ResolutionDiagnostic(ResolutionCandidateApplicability.RESOLVED_SYNTHESIZED) +object UnstableSmartCastDiagnostic: ResolutionDiagnostic(ResolutionCandidateApplicability.MAY_THROW_RUNTIME_ERROR) + + 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 new file mode 100644 index 00000000000..98c823390a2 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/ScopeTowerImpl.kt @@ -0,0 +1,136 @@ +/* + * Copyright 2010-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.resolve.calls.tower + +import org.jetbrains.kotlin.descriptors.CallableDescriptor +import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor +import org.jetbrains.kotlin.incremental.components.LookupLocation +import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext +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.receivers.ClassQualifier +import org.jetbrains.kotlin.resolve.scopes.receivers.Receiver +import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue +import org.jetbrains.kotlin.resolve.scopes.utils.getImplicitReceiversHierarchy +import org.jetbrains.kotlin.resolve.scopes.utils.parentsWithSelf +import org.jetbrains.kotlin.types.KotlinType +import org.jetbrains.kotlin.types.typeUtil.containsError +import org.jetbrains.kotlin.utils.addToStdlib.check +import java.util.* + + +internal class CandidateWithBoundDispatchReceiverImpl( + override val dispatchReceiver: ReceiverValue?, + override val descriptor: D, + override val diagnostics: List +) : CandidateWithBoundDispatchReceiver + +internal class ScopeTowerImpl( + resolutionContext: ResolutionContext<*>, + private val explicitReceiver: Receiver?, + override val location: LookupLocation +): ScopeTower { + override val dataFlowInfo: DataFlowDecorator = DataFlowDecoratorImpl(resolutionContext) + override val lexicalScope: LexicalScope = resolutionContext.scope + + override val implicitReceivers = resolutionContext.scope.getImplicitReceiversHierarchy(). + mapNotNull { it.value.check { !it.type.containsError() } } + + override val levels: Sequence = createPrototypeLevels().asSequence().map { it.asTowerLevel(this) } + + // we shouldn't calculate this before we entrance to some importing scope + private val receiversForSyntheticExtensions: Collection by lazy(LazyThreadSafetyMode.PUBLICATION) { + if (explicitReceiver != null) { + if (explicitReceiver is ReceiverValue) { + return@lazy dataFlowInfo.getAllPossibleTypes(explicitReceiver) + } + + if (explicitReceiver is ClassQualifier) { + explicitReceiver.classValueReceiver?.let { + return@lazy dataFlowInfo.getAllPossibleTypes(it) + } + } + + // explicit receiver is package or class without companion object + emptyList() + } + else { + implicitReceivers.flatMap { dataFlowInfo.getAllPossibleTypes(it) } + } + } + + private sealed class LevelFactory { + abstract fun asTowerLevel(resolveTower: ScopeTower): ScopeTowerLevel + + class Scope(val lexicalScope: LexicalScope): LevelFactory() { + override fun asTowerLevel(resolveTower: ScopeTower) = ScopeBasedTowerLevel(resolveTower, lexicalScope) + } + + class Receiver(val implicitReceiver: ReceiverParameterDescriptor): LevelFactory() { + override fun asTowerLevel(resolveTower: ScopeTower) = ReceiverScopeTowerLevel(resolveTower, implicitReceiver.value) + } + + class ImportingScopeFactory(val importingScope: ImportingScope, val lazyReceiversForSyntheticExtensions: () -> Collection): LevelFactory() { + override fun asTowerLevel(resolveTower: ScopeTower) = ImportingScopeBasedTowerLevel(resolveTower, importingScope, lazyReceiversForSyntheticExtensions()) + } + } + + private fun createPrototypeLevels(): List { + val result = ArrayList() + + // locals win + lexicalScope.parentsWithSelf. + filterIsInstance(). + filter { it.kind.withLocalDescriptors }. + mapTo(result) { LevelFactory.Scope(it) } + + lexicalScope.parentsWithSelf.forEach { scope -> + if (scope is LexicalScope) { + if (!scope.kind.withLocalDescriptors) result.add(LevelFactory.Scope(scope)) + + scope.implicitReceiver?.let { result.add(LevelFactory.Receiver(it)) } + } + else { + result.add(LevelFactory.ImportingScopeFactory(scope as ImportingScope, { receiversForSyntheticExtensions })) + } + } + + return result + } + +} + +private class DataFlowDecoratorImpl(private val resolutionContext: ResolutionContext<*>): DataFlowDecorator { + private val dataFlowInfo = resolutionContext.dataFlowInfo + private val cache = HashMap() + + private fun getSmartCastInfo(receiver: ReceiverValue): SmartCastInfo + = cache.getOrPut(receiver) { + val dataFlowValue = DataFlowValueFactory.createDataFlowValue(receiver, resolutionContext) + SmartCastInfo(dataFlowValue, dataFlowInfo.getPossibleTypes(dataFlowValue)) + } + + override fun getDataFlowValue(receiver: ReceiverValue): DataFlowValue = getSmartCastInfo(receiver).dataFlowValue + + override fun isStableReceiver(receiver: ReceiverValue): Boolean = getSmartCastInfo(receiver).dataFlowValue.isPredictable + + override fun getSmartCastTypes(receiver: ReceiverValue): Set = getSmartCastInfo(receiver).possibleTypes + + private data class SmartCastInfo(val dataFlowValue: DataFlowValue, val possibleTypes: Set) +} diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/ScopeTowerProcessors.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/ScopeTowerProcessors.kt new file mode 100644 index 00000000000..868ffd55a96 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/ScopeTowerProcessors.kt @@ -0,0 +1,170 @@ +/* + * Copyright 2010-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.resolve.calls.tower + +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind +import org.jetbrains.kotlin.resolve.scopes.receivers.ClassQualifier +import org.jetbrains.kotlin.resolve.scopes.receivers.QualifierReceiver +import org.jetbrains.kotlin.resolve.scopes.receivers.Receiver +import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue +import org.jetbrains.kotlin.utils.addToStdlib.check + + +internal class KnownResultProcessor( + result: Collection +): ScopeTowerProcessor { + var candidates = result + + override fun processTowerLevel(level: ScopeTowerLevel) { + candidates = emptyList() + } + + override fun processImplicitReceiver(implicitReceiver: ReceiverValue) { + candidates = emptyList() + } + + override fun getCandidatesGroups() = listOfNotNull(candidates.check { it.isNotEmpty() }) +} + +internal class CompositeScopeTowerProcessor( + vararg val processors: ScopeTowerProcessor +) : ScopeTowerProcessor { + override fun processTowerLevel(level: ScopeTowerLevel) = processors.forEach { it.processTowerLevel(level) } + + override fun processImplicitReceiver(implicitReceiver: ReceiverValue) + = processors.forEach { it.processImplicitReceiver(implicitReceiver) } + + override fun getCandidatesGroups(): List> = processors.flatMap { it.getCandidatesGroups() } +} + +internal abstract class AbstractScopeTowerProcessor( + val context: TowerContext +) : ScopeTowerProcessor { + protected val name: Name get() = context.name + + protected abstract var candidates: Collection + + override fun getCandidatesGroups() = listOfNotNull(candidates.check { it.isNotEmpty() }) +} + +internal class ExplicitReceiverScopeTowerProcessor( + context: TowerContext, + val explicitReceiver: ReceiverValue, + val collectCandidates: ScopeTowerLevel.(Name) -> Collection> +): AbstractScopeTowerProcessor(context) { + override var candidates = resolveAsMember() + + override fun processTowerLevel(level: ScopeTowerLevel) { + candidates = resolveAsExtension(level) + } + + override fun processImplicitReceiver(implicitReceiver: ReceiverValue) { + // no candidates, because we already have receiver + candidates = emptyList() + } + + private fun resolveAsMember(): Collection { + val members = ReceiverScopeTowerLevel(context.scopeTower, explicitReceiver).collectCandidates(name).filter { !it.requiresExtensionReceiver } + return members.map { context.createCandidate(it, ExplicitReceiverKind.DISPATCH_RECEIVER, extensionReceiver = null) } + } + + private fun resolveAsExtension(level: ScopeTowerLevel): Collection { + val extensions = level.collectCandidates(name).filter { it.requiresExtensionReceiver } + return extensions.map { context.createCandidate(it, ExplicitReceiverKind.EXTENSION_RECEIVER, extensionReceiver = explicitReceiver) } + } +} + +private class QualifierScopeTowerProcessor( + context: TowerContext, + val qualifier: QualifierReceiver, + val collectCandidates: ScopeTowerLevel.(Name) -> Collection> +): AbstractScopeTowerProcessor(context) { + override var candidates = resolve() + + override fun processTowerLevel(level: ScopeTowerLevel) { + // no candidates, because we done all already + candidates = emptyList() + } + + override fun processImplicitReceiver(implicitReceiver: ReceiverValue) { + // no candidates, because we done all already + candidates = emptyList() + } + + private fun resolve(): Collection { + val staticMembers = QualifierScopeTowerLevel(context.scopeTower, qualifier).collectCandidates(name) + .filter { !it.requiresExtensionReceiver } + .map { context.createCandidate(it, ExplicitReceiverKind.NO_EXPLICIT_RECEIVER, extensionReceiver = null) } + return staticMembers + } +} + +private class NoExplicitReceiverScopeTowerProcessor( + context: TowerContext, + val collectCandidates: ScopeTowerLevel.(Name) -> Collection> +) : AbstractScopeTowerProcessor(context) { + override var candidates: Collection = emptyList() + + private var descriptorsRequestImplicitReceiver = emptyList>() + + override fun processTowerLevel(level: ScopeTowerLevel) { + val descriptors = level.collectCandidates(name) + + descriptorsRequestImplicitReceiver = descriptors.filter { it.requiresExtensionReceiver } + + candidates = descriptors.filter { !it.requiresExtensionReceiver } + .map { context.createCandidate(it, ExplicitReceiverKind.NO_EXPLICIT_RECEIVER, extensionReceiver = null) } + } + + override fun processImplicitReceiver(implicitReceiver: ReceiverValue) { + candidates = descriptorsRequestImplicitReceiver + .map { context.createCandidate(it, ExplicitReceiverKind.NO_EXPLICIT_RECEIVER, extensionReceiver = implicitReceiver) } + } +} + +private fun createSimpleProcessor( + context: TowerContext, + explicitReceiver: Receiver?, + collectCandidates: ScopeTowerLevel.(Name) -> Collection> +) : ScopeTowerProcessor { + if (explicitReceiver is ReceiverValue) { + return ExplicitReceiverScopeTowerProcessor(context, explicitReceiver, collectCandidates) + } + else if (explicitReceiver is QualifierReceiver) { + val qualifierProcessor = QualifierScopeTowerProcessor(context, explicitReceiver, collectCandidates) + + // todo enum entry, object. + val classValue = (explicitReceiver as? ClassQualifier)?.classValueReceiver ?: return qualifierProcessor + return CompositeScopeTowerProcessor( + qualifierProcessor, + ExplicitReceiverScopeTowerProcessor(context, classValue, collectCandidates) + ) + } + else { + assert(explicitReceiver == null) { + "Illegal explicit receiver: $explicitReceiver(${explicitReceiver!!.javaClass.simpleName})" + } + return NoExplicitReceiverScopeTowerProcessor(context, collectCandidates) + } +} + +internal fun createVariableProcessor(context: TowerContext, explicitReceiver: Receiver?) + = createSimpleProcessor(context, explicitReceiver, ScopeTowerLevel::getVariables) + +internal fun createFunctionProcessor(context: TowerContext, explicitReceiver: Receiver?) + = createSimpleProcessor(context, explicitReceiver, ScopeTowerLevel::getFunctions) 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 new file mode 100644 index 00000000000..989f4d49691 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/TowerLevels.kt @@ -0,0 +1,247 @@ +/* + * Copyright 2010-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.resolve.calls.tower + +import com.intellij.util.SmartList +import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.incremental.components.LookupLocation +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.resolve.calls.util.FakeCallableDescriptorForObject +import org.jetbrains.kotlin.resolve.descriptorUtil.hasClassValueDescriptor +import org.jetbrains.kotlin.resolve.scopes.ImportingScope +import org.jetbrains.kotlin.resolve.scopes.LexicalScope +import org.jetbrains.kotlin.resolve.scopes.ResolutionScope +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.utils.addIfNotNull +import java.util.* + +internal abstract class AbstractScopeTowerLevel( + protected val scopeTower: ScopeTower +): ScopeTowerLevel { + protected val location: LookupLocation get() = scopeTower.location + + protected fun createCandidateDescriptor( + descriptor: D, + dispatchReceiver: ReceiverValue?, + specialError: ResolutionDiagnostic? = null, + dispatchReceiverSmartCastType: KotlinType? = null + ): CandidateWithBoundDispatchReceiver { + val diagnostics = SmartList() + diagnostics.addIfNotNull(specialError) + + if (ErrorUtils.isError(descriptor)) diagnostics.add(ErrorDescriptorDiagnostic) + if (descriptor.isSynthesized) diagnostics.add(SynthesizedDescriptorDiagnostic) + if (dispatchReceiverSmartCastType != null) diagnostics.add(UsedSmartCastForDispatchReceiver(dispatchReceiverSmartCastType)) + + Visibilities.findInvisibleMember( + dispatchReceiver ?: ReceiverValue.NO_RECEIVER, descriptor, + scopeTower.lexicalScope.ownerDescriptor + )?.let { diagnostics.add(VisibilityError(it)) } + + return CandidateWithBoundDispatchReceiverImpl(dispatchReceiver, descriptor, diagnostics) + } + +} + +// todo create error for constructors call and for implicit receiver +// todo KT-9538 Unresolved inner class via subclass reference +// todo Future plan: move constructors and fake variables for objects to class member scope. +internal abstract class ConstructorsAndFakeVariableHackLevelScope(scopeTower: ScopeTower) : AbstractScopeTowerLevel(scopeTower) { + + protected fun createConstructors( + classifier: ClassifierDescriptor?, + dispatchReceiver: ReceiverValue?, + dispatchReceiverSmartCastType: KotlinType? = null, + checkClass: (ClassDescriptor) -> ResolutionDiagnostic? = { null } + ): Collection> { + val classDescriptor = getClassWithConstructors(classifier) ?: return emptyList() + + val specialError = checkClass(classDescriptor) + return classDescriptor.constructors.map { + + val dispatchReceiverHack = if (dispatchReceiver == null && it.dispatchReceiverParameter != null) { + it.dispatchReceiverParameter?.value // todo this is hack for Scope Level + } + else if (dispatchReceiver != null && it.dispatchReceiverParameter == null) { // should be reported error + null + } + else { + dispatchReceiver + } + + createCandidateDescriptor(it, dispatchReceiverHack, specialError, dispatchReceiverSmartCastType) + } + } + + protected fun createVariableDescriptor( + classifier: ClassifierDescriptor?, + dispatchReceiverSmartCastType: KotlinType? = null, + checkClass: (ClassDescriptor) -> ResolutionDiagnostic? = { null } + ): CandidateWithBoundDispatchReceiver? { + val fakeVariable = getFakeDescriptorForObject(classifier) ?: return null + return createCandidateDescriptor(fakeVariable, null, checkClass(fakeVariable.classDescriptor), dispatchReceiverSmartCastType) + } + + + private fun getClassWithConstructors(classifier: ClassifierDescriptor?): ClassDescriptor? { + if (classifier !is ClassDescriptor || ErrorUtils.isError(classifier) + // Constructors of singletons shouldn't be callable from the code + || classifier.kind.isSingleton) { + return null + } + else { + return classifier + } + } + + private fun getFakeDescriptorForObject(classifier: ClassifierDescriptor?): FakeCallableDescriptorForObject? { + if (classifier !is ClassDescriptor || !classifier.hasClassValueDescriptor) return null // todo + + return FakeCallableDescriptorForObject(classifier) + } +} + +internal class ReceiverScopeTowerLevel( + scopeTower: ScopeTower, + val dispatchReceiver: ReceiverValue +): ConstructorsAndFakeVariableHackLevelScope(scopeTower) { + private val memberScope = dispatchReceiver.type.memberScope + + private fun collectMembers( + members: ResolutionScope.() -> Collection, + additionalDescriptors: ResolutionScope.(smartCastType: KotlinType?) -> Collection> // todo + ): Collection> { + val result = ArrayList>(0) + memberScope.members().mapTo(result) { + createCandidateDescriptor(it, dispatchReceiver) + } + result.addAll(memberScope.additionalDescriptors(null)) + + val smartCastPossibleTypes = scopeTower.dataFlowInfo.getSmartCastTypes(dispatchReceiver) + val unstableError = if (scopeTower.dataFlowInfo.isStableReceiver(dispatchReceiver)) null else UnstableSmartCastDiagnostic + + for (possibleType in smartCastPossibleTypes) { + possibleType.memberScope.members().mapTo(result) { + createCandidateDescriptor(it, dispatchReceiver, unstableError, dispatchReceiverSmartCastType = possibleType) + } + + possibleType.memberScope.additionalDescriptors(possibleType).mapTo(result) { + it.addDiagnostic(unstableError) + } + } + + return result + } + + // todo add static methods & fields with error + override fun getVariables(name: Name): Collection> { + return collectMembers({ getContributedVariables(name, location) }) { + smartCastType -> + listOfNotNull(createVariableDescriptor(getContributedClassifier(name, location), smartCastType){ NestedClassViaInstanceReference(it) } ) + } + } + + override fun getFunctions(name: Name): Collection> { + return collectMembers({ getContributedFunctions(name, location) }) { + smartCastType -> + createConstructors(getContributedClassifier(name, location), dispatchReceiver, smartCastType) { + if (it.isInner) null else NestedClassViaInstanceReference(it) + } + } + } +} + +internal class QualifierScopeTowerLevel(scopeTower: ScopeTower, qualifier: QualifierReceiver) : ConstructorsAndFakeVariableHackLevelScope(scopeTower) { + private val qualifierScope = qualifier.getNestedClassesAndPackageMembersScope() + + override fun getVariables(name: Name): Collection> { + val result = ArrayList>(0) + qualifierScope.getContributedVariables(name, location).mapTo(result) { + createCandidateDescriptor(it, dispatchReceiver = null) + } + result.addIfNotNull(createVariableDescriptor(qualifierScope.getContributedClassifier(name, location))) + return result + } + + override fun getFunctions(name: Name): Collection> { + val functions = qualifierScope.getContributedFunctions(name, location).map { + createCandidateDescriptor(it, dispatchReceiver = null) + } + val constructors = createConstructors(qualifierScope.getContributedClassifier(name, location), dispatchReceiver = null) { + if (it.isInner) InnerClassViaStaticReference(it) else null + } + return functions + constructors + } +} + +internal open class ScopeBasedTowerLevel protected constructor( + scopeTower: ScopeTower, + private val resolutionScope: ResolutionScope +) : ConstructorsAndFakeVariableHackLevelScope(scopeTower) { + + internal constructor(scopeTower: ScopeTower, lexicalScope: LexicalScope): this(scopeTower, lexicalScope as ResolutionScope) + + override fun getVariables(name: Name): Collection> { + val result = ArrayList>(0) + resolutionScope.getContributedVariables(name, location).mapTo(result) { + createCandidateDescriptor(it, dispatchReceiver = null) + } + result.addIfNotNull(createVariableDescriptor(resolutionScope.getContributedClassifier(name, location))) + return result + } + + override fun getFunctions(name: Name): Collection> { + val result = ArrayList>(0) + resolutionScope.getContributedFunctions(name, location).mapTo(result) { + createCandidateDescriptor(it, dispatchReceiver = null) + } + + // todo report errors for constructors if there is no match receiver + result.addAll(createConstructors(resolutionScope.getContributedClassifier(name, location), dispatchReceiver = null) { + if (!it.isInner) return@createConstructors null + + // todo add constructors functions to member class member scope + // KT-3335 Creating imported super class' inner class fails in codegen + UnsupportedInnerClassCall("Constructor call for inner class from subclass unsupported") + }) + return result + } +} + +internal class ImportingScopeBasedTowerLevel( + scopeTower: ScopeTower, + private val importingScope: ImportingScope, + private val receiversForSyntheticExtensions: Collection +): ScopeBasedTowerLevel(scopeTower, importingScope) { + + override fun getVariables(name: Name): Collection> { + val synthetic = importingScope.getContributedSyntheticExtensionProperties(receiversForSyntheticExtensions, name, location).map { + createCandidateDescriptor(it, dispatchReceiver = null) + } + return super.getVariables(name) + synthetic + } + + override fun getFunctions(name: Name): Collection> { + val synthetic = importingScope.getContributedSyntheticExtensionFunctions(receiversForSyntheticExtensions, name, location).map { + createCandidateDescriptor(it, dispatchReceiver = null) + } + return super.getFunctions(name) + synthetic + } +} \ No newline at end of file diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/TowerResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/TowerResolver.kt new file mode 100644 index 00000000000..bb1f06973a5 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/TowerResolver.kt @@ -0,0 +1,118 @@ +/* + * Copyright 2010-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.resolve.calls.tower + +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind +import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue +import org.jetbrains.kotlin.utils.addToStdlib.check + +interface TowerContext { + val name: Name + val scopeTower: ScopeTower + + fun createCandidate( + towerCandidate: CandidateWithBoundDispatchReceiver<*>, + explicitReceiverKind: ExplicitReceiverKind, + extensionReceiver: ReceiverValue? + ): C + + fun getStatus(candidate: C): ResolutionCandidateStatus + + fun transformCandidate(variable: C, invoke: C): C + + fun contextForVariable(stripExplicitReceiver: Boolean): TowerContext + + // foo() -> ReceiverValue(foo), context for invoke + fun contextForInvoke(variable: C, useExplicitReceiver: Boolean): Pair> +} + +internal interface ScopeTowerProcessor { + + fun processTowerLevel(level: ScopeTowerLevel) + fun processImplicitReceiver(implicitReceiver: ReceiverValue) + + // Candidates with matched receivers (dispatch receiver was already matched in ScopeTowerLevel) + // Candidates in one groups have same priority, first group has highest priority. + fun getCandidatesGroups(): List> +} + +class TowerResolver { + internal fun runResolve( + context: TowerContext, + processor: ScopeTowerProcessor, + useOrder: Boolean = true + ): Collection { + + val resultCollector = ResultCollector { context.getStatus(it) } + + fun collectCandidates(action: ScopeTowerProcessor.() -> Unit): Collection? { + processor.action() + val candidatesGroups = if (useOrder) { + processor.getCandidatesGroups() + } + else { + listOf(processor.getCandidatesGroups().flatMap { it }) + } + + for (candidatesGroup in candidatesGroups) { + resultCollector.pushCandidates(candidatesGroup) + resultCollector.getResolved()?.let { return it } + } + return null + } + + // possible there is explicit member + collectCandidates { /* do nothing */ }?.let { return it } + + for (level in context.scopeTower.levels) { + collectCandidates { processTowerLevel(level) }?.let { return it } + + for (implicitReceiver in context.scopeTower.implicitReceivers) { + collectCandidates { processImplicitReceiver(implicitReceiver) }?.let { return it } + } + } + + return resultCollector.getFinalCandidates() + } + + + //todo collect all candidates + internal class ResultCollector(private val getStatus: (C) -> ResolutionCandidateStatus) { + private var currentCandidates: Collection = emptyList() + private var currentLevel: ResolutionCandidateApplicability? = null + + fun getResolved() = currentCandidates.check { currentLevel == ResolutionCandidateApplicability.RESOLVED } + + fun getSyntheticResolved() = currentCandidates.check { currentLevel == ResolutionCandidateApplicability.RESOLVED_SYNTHESIZED } + + fun getErrors() = currentCandidates.check { + currentLevel == null || currentLevel!! > ResolutionCandidateApplicability.RESOLVED_SYNTHESIZED + } + + fun getFinalCandidates() = getResolved() ?: getSyntheticResolved() ?: getErrors() ?: emptyList() + + fun pushCandidates(candidates: Collection) { + if (candidates.isEmpty()) return + val minimalLevel = candidates.map { getStatus(it).resultingApplicability }.min()!! + if (currentLevel == null || currentLevel!! > minimalLevel) { + currentLevel = minimalLevel + currentCandidates = candidates.filter { getStatus(it).resultingApplicability == minimalLevel } + } + } + } +} diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/TowerUtils.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/TowerUtils.kt new file mode 100644 index 00000000000..94d41c59a06 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/TowerUtils.kt @@ -0,0 +1,55 @@ +/* + * Copyright 2010-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.resolve.calls.tower + +import org.jetbrains.kotlin.descriptors.CallableDescriptor +import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor +import org.jetbrains.kotlin.resolve.calls.callResolverUtil.isOrOverridesSynthesized +import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus +import org.jetbrains.kotlin.resolve.descriptorUtil.hasLowPriorityInOverloadResolution +import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue + + +internal fun CandidateWithBoundDispatchReceiver.addDiagnostic(error: ResolutionDiagnostic?): CandidateWithBoundDispatchReceiver { + if (error == null) return this + return CandidateWithBoundDispatchReceiverImpl(dispatchReceiver, descriptor, diagnostics + error) +} + +@Deprecated("Temporary error") +internal class PreviousResolutionError(candidateLevel: ResolutionCandidateApplicability): ResolutionDiagnostic(candidateLevel) + +@Deprecated("Temporary error") +internal fun createPreviousResolveError(status: ResolutionStatus): PreviousResolutionError? { + val level = when (status) { + ResolutionStatus.SUCCESS, ResolutionStatus.INCOMPLETE_TYPE_INFERENCE -> return null + ResolutionStatus.UNSAFE_CALL_ERROR -> ResolutionCandidateApplicability.MAY_THROW_RUNTIME_ERROR + else -> ResolutionCandidateApplicability.INAPPLICABLE + } + return PreviousResolutionError(level) +} + +internal val ResolutionCandidateApplicability.isSuccess: Boolean + get() = this == ResolutionCandidateApplicability.RESOLVED || this == ResolutionCandidateApplicability.RESOLVED_SYNTHESIZED + +internal val CallableDescriptor.isSynthesized: Boolean // todo dynamics calls + get() = (this is CallableMemberDescriptor && isOrOverridesSynthesized(this)) + || hasLowPriorityInOverloadResolution() + +internal val CandidateWithBoundDispatchReceiver<*>.requiresExtensionReceiver: Boolean + get() = descriptor.extensionReceiverParameter != null + +internal fun DataFlowDecorator.getAllPossibleTypes(receiver: ReceiverValue) = getSmartCastTypes(receiver) + receiver.type \ No newline at end of file diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/scopes/receivers/Qualifier.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/scopes/receivers/Qualifier.kt index 4d48352674f..daf71f48868 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/scopes/receivers/Qualifier.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/scopes/receivers/Qualifier.kt @@ -91,7 +91,7 @@ class ClassifierQualifierWithEmptyScope( class ClassQualifier( referenceExpression: KtSimpleNameExpression, override val classifier: ClassDescriptor, - val companionObjectReceiver: ReceiverValue? + val classValueReceiver: ReceiverValue? ) : ClassifierQualifier(referenceExpression) { override val scope: MemberScope get() { diff --git a/compiler/testData/diagnostics/tests/scopes/implicitReceiverMemberVsParameter.kt b/compiler/testData/diagnostics/tests/scopes/implicitReceiverMemberVsParameter.kt new file mode 100644 index 00000000000..81ef11ffd22 --- /dev/null +++ b/compiler/testData/diagnostics/tests/scopes/implicitReceiverMemberVsParameter.kt @@ -0,0 +1,5 @@ +class A(val foo: Int) + +fun A.test(foo: String) { + val a: String = foo +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/scopes/implicitReceiverMemberVsParameter.txt b/compiler/testData/diagnostics/tests/scopes/implicitReceiverMemberVsParameter.txt new file mode 100644 index 00000000000..c69b2381394 --- /dev/null +++ b/compiler/testData/diagnostics/tests/scopes/implicitReceiverMemberVsParameter.txt @@ -0,0 +1,11 @@ +package + +public fun A.test(/*0*/ foo: kotlin.String): kotlin.Unit + +public final class A { + public constructor A(/*0*/ foo: kotlin.Int) + public final val foo: kotlin.Int + 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/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index fc612a514d8..00192c943d2 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -13533,6 +13533,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { doTest(fileName); } + @TestMetadata("implicitReceiverMemberVsParameter.kt") + public void testImplicitReceiverMemberVsParameter() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/scopes/implicitReceiverMemberVsParameter.kt"); + doTest(fileName); + } + @TestMetadata("initializerScopeOfExtensionProperty.kt") public void testInitializerScopeOfExtensionProperty() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/scopes/initializerScopeOfExtensionProperty.kt");