Create new Tower Resolve

This commit is contained in:
Stanislav Erokhin
2015-10-13 20:08:40 +03:00
parent c08545359e
commit 63fa71606f
16 changed files with 1315 additions and 3 deletions
@@ -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<VariableDescriptor> 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<F>)
newCallResolver.runResolve(context, contextForMigration.name, contextForMigration.resolveKind, tracing);
}
return doResolveCall(context, contextForMigration.lazyTasks.invoke(), contextForMigration.callTransformer, tracing);
}
@@ -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<FunctionDescriptor>
@@ -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()
}
@@ -184,7 +184,7 @@ public class ResolutionResultsHandler {
}
@NotNull
private <D extends CallableDescriptor> OverloadResolutionResultsImpl<D> chooseAndReportMaximallySpecific(
public <D extends CallableDescriptor> OverloadResolutionResultsImpl<D> chooseAndReportMaximallySpecific(
@NotNull Set<MutableResolvedCall<D>> candidates,
boolean discriminateGenerics,
@NotNull CheckArgumentTypesMode checkArgumentsMode
@@ -99,7 +99,7 @@ public class TaskPrioritizer(
taskPrioritizerContext: TaskPrioritizerContext<D, F>
) {
if (qualifier is ClassQualifier) {
val companionObject = qualifier.companionObjectReceiver ?: return
val companionObject = qualifier.classValueReceiver ?: return
val classifierDescriptor = qualifier.classifier
doComputeTasks(companionObject, taskPrioritizerContext.filterCollectors {
when {
@@ -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<C>(
protected val functionContext: TowerContext<C>,
private val variableProcessor: ScopeTowerProcessor<C>
) : ScopeTowerProcessor<C> {
// todo optimize it
private val previousActions = ArrayList<ScopeTowerProcessor<C>.() -> Unit>()
private val candidateGroups: MutableList<Collection<C>> = ArrayList()
private val invokeProcessors: MutableList<Collection<VariableInvokeProcessor>> = ArrayList()
private inner class VariableInvokeProcessor(
val variableCandidate: C,
val invokeProcessor: ScopeTowerProcessor<C> = createInvokeProcessor(variableCandidate)
): ScopeTowerProcessor<C> by invokeProcessor {
override fun getCandidatesGroups(): List<Collection<C>>
= invokeProcessor.getCandidatesGroups().map { candidateGroup ->
candidateGroup.map { functionContext.transformCandidate(variableCandidate, it) }
}
}
protected abstract fun createInvokeProcessor(variableCandidate: C): ScopeTowerProcessor<C>
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<VariableInvokeProcessor>.collectCandidateGroups(): List<Collection<C>> {
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<C>.() -> 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<Collection<C>> = SmartList(candidateGroups)
}
// todo KT-9522 Allow invoke convention for synthetic property
internal class InvokeTowerProcessor<C>(
functionContext: TowerContext<C>,
private val explicitReceiver: Receiver?
) : AbstractInvokeTowerProcessor<C>(
functionContext,
createVariableProcessor(functionContext.contextForVariable(stripExplicitReceiver = false), explicitReceiver)
) {
// todo filter by operator
override fun createInvokeProcessor(variableCandidate: C): ScopeTowerProcessor<C> {
val (variableReceiver, invokeContext) = functionContext.contextForInvoke(variableCandidate, useExplicitReceiver = false)
return ExplicitReceiverScopeTowerProcessor(invokeContext, variableReceiver, ScopeTowerLevel::getFunctions)
}
}
internal class InvokeExtensionTowerProcessor<C>(
functionContext: TowerContext<C>,
private val explicitReceiver: ReceiverValue?
) : AbstractInvokeTowerProcessor<C>(
functionContext,
createVariableProcessor(functionContext.contextForVariable(stripExplicitReceiver = true), explicitReceiver = null)
) {
override fun createInvokeProcessor(variableCandidate: C): ScopeTowerProcessor<C> {
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<C>(
context: TowerContext<C>,
val invokeCandidateDescriptor: CandidateWithBoundDispatchReceiver<FunctionDescriptor>,
val explicitReceiver: ReceiverValue?
) : AbstractScopeTowerProcessor<C>(context) {
override var candidates: Collection<C> = resolve(explicitReceiver)
private fun resolve(extensionReceiver: ReceiverValue?): Collection<C> {
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<FunctionDescriptor>? {
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 <C> createCallTowerProcessorForExplicitInvoke(
contextForInvoke: TowerContext<C>,
expressionForInvoke: ReceiverValue,
explicitReceiver: ReceiverValue?
): ScopeTowerProcessor<C> {
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)
)
}
}
}
@@ -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<Candidate>
): ScopeTowerProcessor<Candidate> {
return if (explicitReceiver is Qualifier) {
(explicitReceiver as? ClassQualifier)?.classValueReceiver?.let(create)
?: KnownResultProcessor<Candidate>(listOf())
}
else {
create(explicitReceiver as ReceiverValue?)
}
}
private fun createFunctionTowerProcessor(baseContext: Context, explicitReceiver: Receiver?): CompositeScopeTowerProcessor<Candidate> {
// 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<Candidate>,
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<CallableDescriptor>(basicCallContext, tracing, resolvedCalls as List<MutableResolvedCall<CallableDescriptor>>)
}
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<Candidate> {
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<FunctionDescriptor>,
variable.resolvedCall as MutableResolvedCall<VariableDescriptor>
)
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<Candidate> {
val basicCallResolutionContext = basicCallContext.replaceCall(CallTransformer.stripCallArguments(basicCallContext.call))
return Context(scopeTower, name, basicCallResolutionContext, tracing)
}
override fun contextForInvoke(variable: Candidate, useExplicitReceiver: Boolean): Pair<ReceiverValue, TowerContext<Candidate>> {
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
}
}
}
@@ -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<ReceiverValue>
val lexicalScope: LexicalScope
val location: LookupLocation
val dataFlowInfo: DataFlowDecorator
// The closest (the most local) levels goes first
val levels: Sequence<ScopeTowerLevel>
}
interface DataFlowDecorator {
fun getDataFlowValue(receiver: ReceiverValue): DataFlowValue
fun isStableReceiver(receiver: ReceiverValue): Boolean
// doesn't include receiver.type
fun getSmartCastTypes(receiver: ReceiverValue): Set<KotlinType>
}
interface ScopeTowerLevel {
fun getVariables(name: Name): Collection<CandidateWithBoundDispatchReceiver<VariableDescriptor>>
fun getFunctions(name: Name): Collection<CandidateWithBoundDispatchReceiver<FunctionDescriptor>>
}
interface CandidateWithBoundDispatchReceiver<out D : CallableDescriptor> {
val descriptor: D
val diagnostics: List<ResolutionDiagnostic>
val dispatchReceiver: ReceiverValue?
}
class ResolutionCandidateStatus(val diagnostics: List<ResolutionDiagnostic>) {
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)
@@ -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<D : CallableDescriptor>(
override val dispatchReceiver: ReceiverValue?,
override val descriptor: D,
override val diagnostics: List<ResolutionDiagnostic>
) : CandidateWithBoundDispatchReceiver<D>
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<ScopeTowerLevel> = createPrototypeLevels().asSequence().map { it.asTowerLevel(this) }
// we shouldn't calculate this before we entrance to some importing scope
private val receiversForSyntheticExtensions: Collection<KotlinType> 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<KotlinType>): LevelFactory() {
override fun asTowerLevel(resolveTower: ScopeTower) = ImportingScopeBasedTowerLevel(resolveTower, importingScope, lazyReceiversForSyntheticExtensions())
}
}
private fun createPrototypeLevels(): List<LevelFactory> {
val result = ArrayList<LevelFactory>()
// locals win
lexicalScope.parentsWithSelf.
filterIsInstance<LexicalScope>().
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<ReceiverValue, SmartCastInfo>()
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<KotlinType> = getSmartCastInfo(receiver).possibleTypes
private data class SmartCastInfo(val dataFlowValue: DataFlowValue, val possibleTypes: Set<KotlinType>)
}
@@ -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<C>(
result: Collection<C>
): ScopeTowerProcessor<C> {
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<C>(
vararg val processors: ScopeTowerProcessor<C>
) : ScopeTowerProcessor<C> {
override fun processTowerLevel(level: ScopeTowerLevel) = processors.forEach { it.processTowerLevel(level) }
override fun processImplicitReceiver(implicitReceiver: ReceiverValue)
= processors.forEach { it.processImplicitReceiver(implicitReceiver) }
override fun getCandidatesGroups(): List<Collection<C>> = processors.flatMap { it.getCandidatesGroups() }
}
internal abstract class AbstractScopeTowerProcessor<C>(
val context: TowerContext<C>
) : ScopeTowerProcessor<C> {
protected val name: Name get() = context.name
protected abstract var candidates: Collection<C>
override fun getCandidatesGroups() = listOfNotNull(candidates.check { it.isNotEmpty() })
}
internal class ExplicitReceiverScopeTowerProcessor<C>(
context: TowerContext<C>,
val explicitReceiver: ReceiverValue,
val collectCandidates: ScopeTowerLevel.(Name) -> Collection<CandidateWithBoundDispatchReceiver<*>>
): AbstractScopeTowerProcessor<C>(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<C> {
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<C> {
val extensions = level.collectCandidates(name).filter { it.requiresExtensionReceiver }
return extensions.map { context.createCandidate(it, ExplicitReceiverKind.EXTENSION_RECEIVER, extensionReceiver = explicitReceiver) }
}
}
private class QualifierScopeTowerProcessor<C>(
context: TowerContext<C>,
val qualifier: QualifierReceiver,
val collectCandidates: ScopeTowerLevel.(Name) -> Collection<CandidateWithBoundDispatchReceiver<*>>
): AbstractScopeTowerProcessor<C>(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<C> {
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<C>(
context: TowerContext<C>,
val collectCandidates: ScopeTowerLevel.(Name) -> Collection<CandidateWithBoundDispatchReceiver<*>>
) : AbstractScopeTowerProcessor<C>(context) {
override var candidates: Collection<C> = emptyList()
private var descriptorsRequestImplicitReceiver = emptyList<CandidateWithBoundDispatchReceiver<*>>()
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 <C> createSimpleProcessor(
context: TowerContext<C>,
explicitReceiver: Receiver?,
collectCandidates: ScopeTowerLevel.(Name) -> Collection<CandidateWithBoundDispatchReceiver<*>>
) : ScopeTowerProcessor<C> {
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 <C> createVariableProcessor(context: TowerContext<C>, explicitReceiver: Receiver?)
= createSimpleProcessor(context, explicitReceiver, ScopeTowerLevel::getVariables)
internal fun <C> createFunctionProcessor(context: TowerContext<C>, explicitReceiver: Receiver?)
= createSimpleProcessor(context, explicitReceiver, ScopeTowerLevel::getFunctions)
@@ -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 <D : CallableDescriptor> createCandidateDescriptor(
descriptor: D,
dispatchReceiver: ReceiverValue?,
specialError: ResolutionDiagnostic? = null,
dispatchReceiverSmartCastType: KotlinType? = null
): CandidateWithBoundDispatchReceiver<D> {
val diagnostics = SmartList<ResolutionDiagnostic>()
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<CandidateWithBoundDispatchReceiver<FunctionDescriptor>> {
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<VariableDescriptor>? {
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 <D: CallableDescriptor> collectMembers(
members: ResolutionScope.() -> Collection<D>,
additionalDescriptors: ResolutionScope.(smartCastType: KotlinType?) -> Collection<CandidateWithBoundDispatchReceiver<D>> // todo
): Collection<CandidateWithBoundDispatchReceiver<D>> {
val result = ArrayList<CandidateWithBoundDispatchReceiver<D>>(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<CandidateWithBoundDispatchReceiver<VariableDescriptor>> {
return collectMembers({ getContributedVariables(name, location) }) {
smartCastType ->
listOfNotNull(createVariableDescriptor(getContributedClassifier(name, location), smartCastType){ NestedClassViaInstanceReference(it) } )
}
}
override fun getFunctions(name: Name): Collection<CandidateWithBoundDispatchReceiver<FunctionDescriptor>> {
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<CandidateWithBoundDispatchReceiver<VariableDescriptor>> {
val result = ArrayList<CandidateWithBoundDispatchReceiver<VariableDescriptor>>(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<CandidateWithBoundDispatchReceiver<FunctionDescriptor>> {
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<CandidateWithBoundDispatchReceiver<VariableDescriptor>> {
val result = ArrayList<CandidateWithBoundDispatchReceiver<VariableDescriptor>>(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<CandidateWithBoundDispatchReceiver<FunctionDescriptor>> {
val result = ArrayList<CandidateWithBoundDispatchReceiver<FunctionDescriptor>>(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<KotlinType>
): ScopeBasedTowerLevel(scopeTower, importingScope) {
override fun getVariables(name: Name): Collection<CandidateWithBoundDispatchReceiver<VariableDescriptor>> {
val synthetic = importingScope.getContributedSyntheticExtensionProperties(receiversForSyntheticExtensions, name, location).map {
createCandidateDescriptor(it, dispatchReceiver = null)
}
return super.getVariables(name) + synthetic
}
override fun getFunctions(name: Name): Collection<CandidateWithBoundDispatchReceiver<FunctionDescriptor>> {
val synthetic = importingScope.getContributedSyntheticExtensionFunctions(receiversForSyntheticExtensions, name, location).map {
createCandidateDescriptor(it, dispatchReceiver = null)
}
return super.getFunctions(name) + synthetic
}
}
@@ -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<C> {
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<C>
// foo() -> ReceiverValue(foo), context for invoke
fun contextForInvoke(variable: C, useExplicitReceiver: Boolean): Pair<ReceiverValue, TowerContext<C>>
}
internal interface ScopeTowerProcessor<C> {
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<Collection<C>>
}
class TowerResolver {
internal fun <C> runResolve(
context: TowerContext<C>,
processor: ScopeTowerProcessor<C>,
useOrder: Boolean = true
): Collection<C> {
val resultCollector = ResultCollector<C> { context.getStatus(it) }
fun collectCandidates(action: ScopeTowerProcessor<C>.() -> Unit): Collection<C>? {
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<C>(private val getStatus: (C) -> ResolutionCandidateStatus) {
private var currentCandidates: Collection<C> = 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<C>) {
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 }
}
}
}
}
@@ -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 <D : CallableDescriptor> CandidateWithBoundDispatchReceiver<D>.addDiagnostic(error: ResolutionDiagnostic?): CandidateWithBoundDispatchReceiver<D> {
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
@@ -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() {
@@ -0,0 +1,5 @@
class A(val foo: Int)
fun A.test(foo: String) {
val <!UNUSED_VARIABLE!>a<!>: String = foo
}
@@ -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
}
@@ -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");