From 55dc2c11f709f55c72b6fe39cd186c2894265bdb Mon Sep 17 00:00:00 2001 From: Stanislav Erokhin Date: Mon, 8 May 2017 16:02:09 +0300 Subject: [PATCH] [NI] Support callable reference resolution in NI. Missing parts: - report results about callable references into trace --- .../resolve/calls/tower/NewCallArguments.kt | 16 +- .../resolve/calls/tower/PSICallResolver.kt | 52 ++- .../DoubleColonExpressionResolver.kt | 2 +- .../components/CallableReferenceResolution.kt | 305 ++++++++++++++++++ .../components/CallableReferenceResolver.kt | 150 ++++----- .../CheckArgumentsResolutionPart.kt | 74 ++--- .../calls/components/KotlinCallCompleter.kt | 9 + .../calls/components/ResolutionParts.kt | 13 +- .../inference/ConstraintSystemBuilder.kt | 2 + .../inference/model/ConstraintStorage.kt | 3 + .../model/MutableConstraintStorage.kt | 2 + .../model/NewConstraintSystemImpl.kt | 7 + .../resolve/calls/model/ArgumentsImpl.kt | 1 - .../calls/model/KotlinCallArguments.kt | 54 +++- .../calls/model/KotlinResolverContext.kt | 15 +- .../calls/model/ResolutionCandidate.kt | 3 + .../calls/model/ResolvedCallElements.kt | 56 +--- .../resolve/calls/results/FlatSignature.kt | 17 + .../types/expressions/CoercionStrategy.java | 0 19 files changed, 570 insertions(+), 211 deletions(-) create mode 100644 compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/CallableReferenceResolution.kt rename compiler/{frontend => resolution}/src/org/jetbrains/kotlin/types/expressions/CoercionStrategy.java (100%) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/NewCallArguments.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/NewCallArguments.kt index 9993a04de74..7156b62eefd 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/NewCallArguments.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/NewCallArguments.kt @@ -16,13 +16,13 @@ package org.jetbrains.kotlin.resolve.calls.tower +import com.intellij.psi.impl.source.tree.LeafPsiElement import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.calls.callUtil.getCall import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext -import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage import org.jetbrains.kotlin.resolve.calls.model.* import org.jetbrains.kotlin.resolve.calls.model.LambdaKotlinCallArgument import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo @@ -110,8 +110,8 @@ class CallableReferenceKotlinCallArgumentImpl( override val dataFlowInfoAfterThisArgument: DataFlowInfo, val ktCallableReferenceExpression: KtCallableReferenceExpression, override val argumentName: Name?, - override val lhsType: UnwrappedType?, - override val constraintStorage: ConstraintStorage + override val lhsResult: LHSResult, + override val rhsName: Name ) : CallableReferenceKotlinCallArgument, PSIKotlinCallArgument() class SubKotlinCallArgumentImpl( @@ -137,6 +137,16 @@ class ExpressionKotlinCallArgumentImpl( override val isSafeCall: Boolean get() = false } +class FakeValueArgumentForLeftCallableReference(val ktExpression: KtCallableReferenceExpression): ValueArgument { + override fun getArgumentExpression() = ktExpression.receiverExpression + + override fun getArgumentName(): ValueArgumentName? = null + override fun isNamed(): Boolean = false + override fun asElement(): KtElement = getArgumentExpression() ?: ktExpression + override fun getSpreadElement(): LeafPsiElement? = null + override fun isExternal(): Boolean = false +} + internal fun createSimplePSICallArgument( context: BasicCallResolutionContext, valueArgument: ValueArgument, diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/PSICallResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/PSICallResolver.kt index e428d3628d0..2bf1b613e8d 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/PSICallResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/PSICallResolver.kt @@ -16,8 +16,10 @@ package org.jetbrains.kotlin.resolve.calls.tower +import org.jetbrains.kotlin.builtins.ReflectionTypes import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.descriptors.CallableDescriptor +import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor import org.jetbrains.kotlin.diagnostics.Errors @@ -28,9 +30,10 @@ import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.ModifierCheckerCore import org.jetbrains.kotlin.resolve.TemporaryBindingTrace import org.jetbrains.kotlin.resolve.TypeResolver -import org.jetbrains.kotlin.resolve.calls.* -import org.jetbrains.kotlin.resolve.calls.callResolverUtil.ResolveArgumentsMode +import org.jetbrains.kotlin.resolve.calls.ArgumentTypeResolver +import org.jetbrains.kotlin.resolve.calls.KotlinCallResolver import org.jetbrains.kotlin.resolve.calls.callUtil.createLookupLocation +import org.jetbrains.kotlin.resolve.calls.callUtil.getCalleeExpressionIfAny import org.jetbrains.kotlin.resolve.calls.callUtil.isSafeCall import org.jetbrains.kotlin.resolve.calls.components.ArgumentsToParametersMapper import org.jetbrains.kotlin.resolve.calls.components.CallableReferenceResolver @@ -40,7 +43,6 @@ import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext import org.jetbrains.kotlin.resolve.calls.context.ContextDependency import org.jetbrains.kotlin.resolve.calls.inference.components.ConstraintInjector import org.jetbrains.kotlin.resolve.calls.inference.components.ResultTypeResolver -import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage import org.jetbrains.kotlin.resolve.calls.model.* import org.jetbrains.kotlin.resolve.calls.results.* import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo @@ -75,6 +77,7 @@ class PSICallResolver( val resultTypeResolver: ResultTypeResolver, val callableReferenceResolver: CallableReferenceResolver, val constraintInjector: ConstraintInjector, + val reflectionTypes: ReflectionTypes, private val kotlinToResolvedCallTransformer: KotlinToResolvedCallTransformer, private val kotlinCallResolver: KotlinCallResolver, private val typeApproximator: TypeApproximator, @@ -146,7 +149,7 @@ class PSICallResolver( private fun createCallContext(scopeTower: ASTScopeTower, resolutionCallbacks: KotlinResolutionCallbacks) = KotlinCallContext(scopeTower, resolutionCallbacks, argumentsToParametersMapper, typeArgumentsToParametersMapper, resultTypeResolver, - callableReferenceResolver, constraintInjector) + callableReferenceResolver, constraintInjector, reflectionTypes) private fun convertToOverloadResolutionResults( context: BasicCallResolutionContext, @@ -456,17 +459,44 @@ class PSICallResolver( if (ktExpression is KtCallableReferenceExpression) { checkNoSpread(outerCallContext, valueArgument) - // todo analyze left expression and get constraint system - val (lhsResult, rightResults) = doubleColonExpressionResolver.resolveCallableReference( - ktExpression, ExpressionTypingContext.newContext(context), ResolveArgumentsMode.SHAPE_FUNCTION_ARGUMENTS) - + val expressionTypingContext = ExpressionTypingContext.newContext(context) + val lhsResult = if (ktExpression.isEmptyLHS) null else doubleColonExpressionResolver.resolveDoubleColonLHS(ktExpression, expressionTypingContext) val newDataFlowInfo = (lhsResult as? DoubleColonLHS.Expression)?.dataFlowInfo ?: startDataFlowInfo + val name = ktExpression.callableReference.getReferencedNameAsName() - // todo ChosenCallableReferenceDescriptor + val lhsNewResult = when (lhsResult) { + null -> LHSResult.Empty + is DoubleColonLHS.Expression -> { + if (lhsResult.isObjectQualifier) { + val classifier = lhsResult.type.constructor.declarationDescriptor + val calleeExpression = ktExpression.receiverExpression?.getCalleeExpressionIfAny() + if (calleeExpression is KtSimpleNameExpression && classifier is ClassDescriptor) { + LHSResult.Object(ClassQualifier(calleeExpression, classifier)) + } + else { + LHSResult.Empty // this is error case actually + } + } + else { + val fakeArgument = FakeValueArgumentForLeftCallableReference(ktExpression) + + val kotlinCallArgument = createSimplePSICallArgument(context, fakeArgument, lhsResult.typeInfo) + kotlinCallArgument?.let { LHSResult.Expression(it as SimpleKotlinCallArgument) } ?: LHSResult.Empty + } + } + is DoubleColonLHS.Type -> { + val qualifier = expressionTypingContext.trace.get(BindingContext.QUALIFIER, ktExpression.receiverExpression!!) + if (qualifier is ClassQualifier) { + LHSResult.Type(qualifier) + } + else { + LHSResult.Empty // this is error case actually + } + } + } return CallableReferenceKotlinCallArgumentImpl(valueArgument, startDataFlowInfo, newDataFlowInfo, - ktExpression, argumentName, (lhsResult as? DoubleColonLHS.Type)?.type?.unwrap(), - ConstraintStorage.Empty) + ktExpression, argumentName, lhsNewResult, name) } // valueArgument.getArgumentExpression()!! instead of ktExpression is hack -- type info should be stored also for parenthesized expression diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DoubleColonExpressionResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DoubleColonExpressionResolver.kt index 7e752565026..74bc01ba057 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DoubleColonExpressionResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DoubleColonExpressionResolver.kt @@ -75,7 +75,7 @@ sealed class DoubleColonLHS(val type: KotlinType) { * (Obj)::class // not an object qualifier (can only be treated as an expression, not as a type) * { Obj }()::class // not an object qualifier */ - class Expression(typeInfo: KotlinTypeInfo, val isObjectQualifier: Boolean) : DoubleColonLHS(typeInfo.type!!) { + class Expression(val typeInfo: KotlinTypeInfo, val isObjectQualifier: Boolean) : DoubleColonLHS(typeInfo.type!!) { val dataFlowInfo: DataFlowInfo = typeInfo.dataFlowInfo } diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/CallableReferenceResolution.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/CallableReferenceResolution.kt new file mode 100644 index 00000000000..1cf2d0c45d4 --- /dev/null +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/CallableReferenceResolution.kt @@ -0,0 +1,305 @@ +/* + * Copyright 2010-2017 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.components + +import org.jetbrains.kotlin.builtins.ReflectionTypes +import org.jetbrains.kotlin.builtins.getReturnTypeFromFunctionType +import org.jetbrains.kotlin.builtins.isFunctionType +import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.descriptors.annotations.Annotations +import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemOperation +import org.jetbrains.kotlin.resolve.calls.inference.model.ArgumentConstraintPosition +import org.jetbrains.kotlin.resolve.calls.model.* +import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind +import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind.DISPATCH_RECEIVER +import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind.EXTENSION_RECEIVER +import org.jetbrains.kotlin.resolve.calls.tower.* +import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns +import org.jetbrains.kotlin.resolve.scopes.receivers.* +import org.jetbrains.kotlin.types.ErrorUtils +import org.jetbrains.kotlin.types.KotlinType +import org.jetbrains.kotlin.types.UnwrappedType +import org.jetbrains.kotlin.types.expressions.CoercionStrategy +import org.jetbrains.kotlin.types.typeUtil.immediateSupertypes +import org.jetbrains.kotlin.types.typeUtil.isUnit +import org.jetbrains.kotlin.types.upperIfFlexible +import org.jetbrains.kotlin.utils.SmartList + +sealed class CallableReceiver { + class UnboundReference(val qualifier: QualifierReceiver) : CallableReceiver() + class BoundValueReference(val qualifier: QualifierReceiver) : CallableReceiver() + class ScopeReceiver(val receiver: ReceiverValueWithSmartCastInfo) : CallableReceiver() + class ExplicitValueReceiver(val receiver: SimpleKotlinCallArgument) : CallableReceiver() +} + +private val CallableReceiver.asReceiverValueForVisibilityChecks: ReceiverValue + get() = when(this) { + is CallableReceiver.ScopeReceiver -> receiver.receiverValue + is CallableReceiver.ExplicitValueReceiver -> receiver.receiver.receiverValue + is CallableReceiver.BoundValueReference -> qualifier.classValueReceiver ?: Visibilities.ALWAYS_SUITABLE_RECEIVER + is CallableReceiver.UnboundReference -> (qualifier.descriptor as? ClassDescriptor)?.defaultType?.let(::TransientReceiver) + ?: Visibilities.ALWAYS_SUITABLE_RECEIVER + } + +/** + * Suppose we have class A with staticM, memberM, memberExtM. + * For A::staticM both receivers will be null + * For A::memberM dispatchReceiver = UnboundReceiver, extensionReceiver = null + * For a::memberExtM dispatchReceiver = ExplicitValueReceiver, extensionReceiver = ExplicitValueReceiver + * + * For class B with companion object B::companionM dispatchReceiver = BoundValueReference + */ +class CallableReferenceCandidate( + val candidate: CallableDescriptor, + val dispatchReceiver: CallableReceiver?, + val extensionReceiver: CallableReceiver?, + val reflectionCandidateType: UnwrappedType, + val numDefaults: Int, + override val status: ResolutionCandidateStatus +) : Candidate { + override val isSuccessful get() = status.resultingApplicability.isSuccess +} + +/** + * cases: class A {}, class B { companion object }, object C, enum class D { E } + * A::foo <-> Type + * a::foo <-> Expression + * B::foo <-> Type + * C::foo <-> Object + * D.E::foo <-> Expression + */ +fun createCallableReferenceProcessor(factory: CallableReferencesCandidateFactory): ScopeTowerProcessor { + val lhsResult = factory.argument.lhsResult + when (lhsResult) { + LHSResult.Empty, is LHSResult.Expression -> { + val explicitReceiver = (lhsResult as? LHSResult.Expression)?.lshCallArgument?.receiver + return factory.createCallableProcessor(explicitReceiver) + } + is LHSResult.Type -> { + val static = factory.createCallableProcessor(lhsResult.qualifier) + val unbound = factory.createCallableProcessor(lhsResult.unboundDetailedReceiver) + + // note that if we use CompositeScopeTowerProcessor then static will win over unbound members + val staticOrUnbound = CompositeSimpleScopeTowerProcessor(static, unbound) + + val asValue = lhsResult.qualifier.classValueReceiverWithSmartCastInfo ?: return staticOrUnbound + return CompositeScopeTowerProcessor(staticOrUnbound, factory.createCallableProcessor(asValue)) + } + is LHSResult.Object -> { + // callable reference to nested class constructor + val static = factory.createCallableProcessor(lhsResult.qualifier) + val boundObjectReference = factory.createCallableProcessor(lhsResult.objectValueReceiver) + + return CompositeSimpleScopeTowerProcessor(static, boundObjectReference) + } + } +} + +class CallableReferencesCandidateFactory( + val argument: CallableReferenceKotlinCallArgument, + val outerCallContext: KotlinCallContext, + val compatibilityChecker: ((ConstraintSystemOperation) -> Unit) -> Unit, + val expectedType: UnwrappedType? +) : CandidateFactory { + + fun createCallableProcessor(explicitReceiver: DetailedReceiver?) = + createCallableReferenceProcessor(outerCallContext.scopeTower, argument.rhsName, this, explicitReceiver) + + override fun createCandidate( + towerCandidate: CandidateWithBoundDispatchReceiver, + explicitReceiverKind: ExplicitReceiverKind, + extensionReceiver: ReceiverValueWithSmartCastInfo? + ): CallableReferenceCandidate { + + val dispatchCallableReceiver = towerCandidate.dispatchReceiver?.let { toCallableReceiver(it, explicitReceiverKind == DISPATCH_RECEIVER) } + val extensionCallableReceiver = extensionReceiver?.let { toCallableReceiver(it, explicitReceiverKind == EXTENSION_RECEIVER) } + val candidateDescriptor = towerCandidate.descriptor + + val (reflectionCandidateType, defaults) = buildReflectionType(candidateDescriptor, + dispatchCallableReceiver, + extensionCallableReceiver, + expectedType) + + if (candidateDescriptor !is CallableMemberDescriptor) { + val status = ResolutionCandidateStatus(listOf(NotCallableMemberReference(argument, candidateDescriptor))) + return CallableReferenceCandidate(candidateDescriptor, dispatchCallableReceiver, extensionCallableReceiver, + reflectionCandidateType, defaults, status) + } + + val diagnostics = SmartList() + val invisibleMember = Visibilities.findInvisibleMember(dispatchCallableReceiver?.asReceiverValueForVisibilityChecks, + candidateDescriptor, outerCallContext.scopeTower.lexicalScope.ownerDescriptor) + if (invisibleMember != null) { + diagnostics.add(VisibilityError(invisibleMember)) + } + // todo smartcast on receiver diagnostic and CheckInstantiationOfAbstractClass + + compatibilityChecker { + if (it.hasContradiction || expectedType == null) return@compatibilityChecker + + val toFreshSubstitutor = CreateDescriptorWithFreshTypeVariables.createToFreshVariableSubstitutorAndAddInitialConstraints(candidateDescriptor, it, kotlinCall = null) + val reflectionType = toFreshSubstitutor.safeSubstitute(reflectionCandidateType) + + it.addSubtypeConstraint(reflectionType, expectedType, ArgumentConstraintPosition(argument)) + if (it.hasContradiction) diagnostics.add(CallableReferenceNotCompatible(argument, candidateDescriptor, expectedType, reflectionType)) + } + + return CallableReferenceCandidate(candidateDescriptor, dispatchCallableReceiver, extensionCallableReceiver, + reflectionCandidateType, defaults, ResolutionCandidateStatus(diagnostics)) + } + + private fun getArgumentAndReturnTypeUseMappingByExpectedType( + descriptor: FunctionDescriptor, + expectedType: UnwrappedType?, + unboundReceiverCount: Int + ): Triple, CoercionStrategy, Int>? { + if (expectedType == null) return null + + val functionType = + if (expectedType.isFunctionType) { + expectedType + } + else if (ReflectionTypes.isNumberedKFunction(expectedType)) { + expectedType.immediateSupertypes().first { it.isFunctionType } + } + else { + return null + } + + + val expectedArgumentCount = functionType.arguments.size - unboundReceiverCount - 1 // 1 -- return type + if (expectedArgumentCount < 0) return null + + val fakeArguments = (0..(expectedArgumentCount - 1)).map { FakeKotlinCallArgumentForCallableReference(it) } + val argumentMapping = outerCallContext.argumentsToParametersMapper.mapArguments(fakeArguments, externalArgument = null, descriptor = descriptor) + if (argumentMapping.diagnostics.any { !it.candidateApplicability.isSuccess }) return null + + /** + * (A, B, C) -> Unit + * fun foo(a: A, b: B = B(), vararg c: C) + */ + var defaults = 0 + val mappedArguments = arrayOfNulls(fakeArguments.size) + for ((valueParameter, resolvedArgument) in argumentMapping.parameterToCallArgumentMap) { + for (fakeArgument in resolvedArgument.arguments) { + val index = (fakeArgument as FakeKotlinCallArgumentForCallableReference).index + val substitutedParameter = descriptor.valueParameters.getOrNull(valueParameter.index) ?: continue + + mappedArguments[index] = substitutedParameter.varargElementType ?: substitutedParameter.type + } + if (resolvedArgument == ResolvedCallArgument.DefaultArgument) defaults++ + } + if (mappedArguments.any { it == null }) return null + + val unitExpectedType = functionType.let(KotlinType::getReturnTypeFromFunctionType).takeIf { it.upperIfFlexible().isUnit() } + val coercion = if (unitExpectedType != null) CoercionStrategy.COERCION_TO_UNIT else CoercionStrategy.NO_COERCION + + @Suppress("UNCHECKED_CAST") + return Triple(mappedArguments as Array, coercion, defaults) + } + + private fun buildReflectionType( + descriptor: CallableDescriptor, + dispatchReceiver: CallableReceiver?, + extensionReceiver: CallableReceiver?, + expectedType: UnwrappedType? + ): Pair { + val argumentsAndReceivers = ArrayList(descriptor.valueParameters.size + 2) + + if (dispatchReceiver is CallableReceiver.UnboundReference) { + argumentsAndReceivers.add(descriptor.dispatchReceiverParameter?.type + ?: error("Dispatch receiver should be not null for descriptor: $descriptor")) + } + if (extensionReceiver is CallableReceiver.UnboundReference) { + argumentsAndReceivers.add(descriptor.extensionReceiverParameter?.type + ?: error("Extension receiver should be not null for descriptor: $descriptor")) + } + + val descriptorReturnType = descriptor.returnType + ?: ErrorUtils.createErrorType("Error return type for descriptor: $descriptor") + + when (descriptor) { + is PropertyDescriptor -> { + val mutable = descriptor.isVar && run { + val setter = descriptor.setter + setter == null || Visibilities.isVisible(dispatchReceiver?.asReceiverValueForVisibilityChecks, setter, + outerCallContext.scopeTower.lexicalScope.ownerDescriptor) + } + + return outerCallContext.reflectionTypes.getKPropertyType(Annotations.EMPTY, argumentsAndReceivers, descriptorReturnType, mutable) to 0 + } + is FunctionDescriptor -> { + val returnType: KotlinType + val defaults: Int + val argumentsAndExpectedTypeCoercion = getArgumentAndReturnTypeUseMappingByExpectedType(descriptor, expectedType, + unboundReceiverCount = argumentsAndReceivers.size) + + if (argumentsAndExpectedTypeCoercion == null) { + descriptor.valueParameters.mapTo(argumentsAndReceivers) { it.type } + returnType = descriptorReturnType + defaults = 0 + } + else { + val (arguments, coercion) = argumentsAndExpectedTypeCoercion + defaults = argumentsAndExpectedTypeCoercion.third + argumentsAndReceivers.addAll(arguments) + + returnType = if (coercion == CoercionStrategy.COERCION_TO_UNIT) descriptor.builtIns.unitType else descriptorReturnType + } + + return outerCallContext.reflectionTypes.getKFunctionType(Annotations.EMPTY, null, argumentsAndReceivers, null, + returnType, descriptor.builtIns) to defaults + } + else -> error("Unsupported descriptor type: $descriptor") + } + } + + private fun toCallableReceiver(receiver: ReceiverValueWithSmartCastInfo, isExplicit: Boolean): CallableReceiver { + if (!isExplicit) return CallableReceiver.ScopeReceiver(receiver) + + val lhsResult = argument.lhsResult + return when (lhsResult) { + is LHSResult.Expression -> CallableReceiver.ExplicitValueReceiver(lhsResult.lshCallArgument) + is LHSResult.Type -> { + if (lhsResult.qualifier.classValueReceiver?.type == receiver.receiverValue.type) { + CallableReceiver.BoundValueReference(lhsResult.qualifier) + } + else { + CallableReceiver.UnboundReference(lhsResult.qualifier) + } + } + is LHSResult.Object -> CallableReceiver.BoundValueReference(lhsResult.qualifier) + else -> throw IllegalStateException("Unsupported kind of lhsResult: $lhsResult") + } + } +} + +class CallableReferenceNotCompatible( + val argument: CallableReferenceKotlinCallArgument, + val candidate: CallableMemberDescriptor, + val expectedType: UnwrappedType, + val callableReverenceType: UnwrappedType +) : KotlinCallDiagnostic(ResolutionCandidateApplicability.INAPPLICABLE) { + override fun report(reporter: DiagnosticReporter) = reporter.onCallArgument(argument, this) +} + +class NotCallableMemberReference( + val argument: CallableReferenceKotlinCallArgument, + val candidate: CallableDescriptor +) : KotlinCallDiagnostic(ResolutionCandidateApplicability.INAPPLICABLE) { + override fun report(reporter: DiagnosticReporter) = reporter.onCallArgument(argument, this) +} \ No newline at end of file diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/CallableReferenceResolver.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/CallableReferenceResolver.kt index d1623fcb904..5b83f760ec3 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/CallableReferenceResolver.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/CallableReferenceResolver.kt @@ -16,104 +16,64 @@ package org.jetbrains.kotlin.resolve.calls.components -import org.jetbrains.kotlin.builtins.ReflectionTypes -import org.jetbrains.kotlin.builtins.getReturnTypeFromFunctionType -import org.jetbrains.kotlin.builtins.isFunctionType -import org.jetbrains.kotlin.descriptors.DeclarationDescriptor -import org.jetbrains.kotlin.descriptors.PropertyDescriptor -import org.jetbrains.kotlin.descriptors.Visibilities -import org.jetbrains.kotlin.descriptors.annotations.Annotations -import org.jetbrains.kotlin.resolve.calls.model.* -import org.jetbrains.kotlin.types.ErrorUtils -import org.jetbrains.kotlin.types.KotlinType +import org.jetbrains.kotlin.builtins.KotlinBuiltIns +import org.jetbrains.kotlin.resolve.calls.context.CheckArgumentTypesMode +import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemOperation +import org.jetbrains.kotlin.resolve.calls.inference.components.ConstraintInjector +import org.jetbrains.kotlin.resolve.calls.inference.components.ResultTypeResolver +import org.jetbrains.kotlin.resolve.calls.inference.components.SimpleConstraintSystemImpl +import org.jetbrains.kotlin.resolve.calls.model.KotlinCallContext +import org.jetbrains.kotlin.resolve.calls.model.CallableReferenceKotlinCallArgument +import org.jetbrains.kotlin.resolve.calls.results.FlatSignature +import org.jetbrains.kotlin.resolve.calls.results.OverloadingConflictResolver +import org.jetbrains.kotlin.resolve.calls.results.TypeSpecificityComparator +import org.jetbrains.kotlin.resolve.calls.tower.TowerResolver import org.jetbrains.kotlin.types.UnwrappedType -import org.jetbrains.kotlin.types.typeUtil.builtIns -import org.jetbrains.kotlin.types.typeUtil.immediateSupertypes -import org.jetbrains.kotlin.types.typeUtil.isUnit -import org.jetbrains.kotlin.types.upperIfFlexible -import org.jetbrains.kotlin.utils.addIfNotNull -import java.util.* -class CallableReferenceResolver( - val reflectionTypes: ReflectionTypes, - val argumentsToParametersMapper: ArgumentsToParametersMapper -) { - - fun resolvePropertyReference( - descriptor: PropertyDescriptor, - propertyReference: ChosenCallableReferenceDescriptor, - outerCall: KotlinCall, - scopeOwnerDescriptor: DeclarationDescriptor - ): ResolvedPropertyReference { - val mutable = descriptor.isVar && run { - val setter = descriptor.setter - setter == null || Visibilities.isVisible(propertyReference.candidate.dispatchReceiver?.receiverValue, setter, scopeOwnerDescriptor) - } - - val reflectionType = reflectionTypes.getKPropertyType(Annotations.EMPTY, listOfNotNull(propertyReference.dispatchNotBoundReceiver, - propertyReference.extensionNotBoundReceiver), descriptor.type.unwrap(), mutable) - - return ResolvedPropertyReference(outerCall, propertyReference, reflectionType) - } - - private fun createFakeArgumentsAndMapArguments( - functionReference: ChosenCallableReferenceDescriptor, - argumentCount: Int? - ): Pair, ArgumentsToParametersMapper.ArgumentMapping?> { - if (argumentCount == null) { - return functionReference.candidate.descriptor.valueParameters.map { it.varargElementType?.unwrap() ?: it.type.unwrap() } to null - } - - val fakeArguments = (0..(argumentCount - 1)).map { FakeKotlinCallArgumentForCallableReference(functionReference, it) } - - val argumentsToParametersMapping = argumentsToParametersMapper.mapArguments(fakeArguments, null, functionReference.candidate.descriptor) - val parameters = Array(argumentCount) { null } - - for ((parameter, resolvedArgument) in argumentsToParametersMapping.parameterToCallArgumentMap) { - for (argument in resolvedArgument.arguments) { - val index = (argument as FakeKotlinCallArgumentForCallableReference).index - parameters[index] = parameter.type.unwrap() - } - } - - return parameters.map { it ?: ErrorUtils.createErrorType("Wrong parameters mapping") } to argumentsToParametersMapping - } - - fun resolveFunctionReference( - functionReference: ChosenCallableReferenceDescriptor, - outerCall: KotlinCall, - expectedType: UnwrappedType - ): ResolvedFunctionReference { - val functionType = - if (expectedType.isFunctionType) { - expectedType - } - else if (ReflectionTypes.isNumberedKFunction(expectedType)) { - expectedType.immediateSupertypes().first { it.isFunctionType } - } - else { - null - } - - val parameterTypes = ArrayList(functionType?.arguments?.size ?: 2) - parameterTypes.addIfNotNull(functionReference.dispatchNotBoundReceiver) - parameterTypes.addIfNotNull(functionReference.extensionNotBoundReceiver) - - // (A, B, C) -> Int if A -- receiver, then B & C -- parameters - // here parameterTypes contains only receivers, all parameters will be added later - val argumentCount = functionType?.arguments?.let { it.size - parameterTypes.size - 1 }?.takeIf { it >= 0 } - val (parameters, mapping) = createFakeArgumentsAndMapArguments(functionReference, argumentCount) - parameterTypes.addAll(parameters) - - val unitExpectedType = functionType?.let(KotlinType::getReturnTypeFromFunctionType)?.takeIf { it.upperIfFlexible().isUnit() } - // coercion to unit - val returnType = unitExpectedType ?: functionReference.candidate.descriptor.returnType - ?: ErrorUtils.createErrorType("Error return type") - - val kFunctionType = reflectionTypes.getKFunctionType(Annotations.EMPTY, null, parameterTypes, null, returnType, expectedType.builtIns) - - return ResolvedFunctionReference(outerCall, functionReference, kFunctionType, mapping) +class CallableReferenceOverloadConflictResolver( + builtIns: KotlinBuiltIns, + specificityComparator: TypeSpecificityComparator, + isDescriptorFromSourcePredicate: IsDescriptorFromSourcePredicate, + constraintInjector: ConstraintInjector, + typeResolver: ResultTypeResolver +) : OverloadingConflictResolver( + builtIns, + specificityComparator, + { it.candidate }, + { SimpleConstraintSystemImpl(constraintInjector, typeResolver) }, + Companion::createFlatSignature, + { null }, + isDescriptorFromSourcePredicate + ) { + companion object { + private fun createFlatSignature(candidate: CallableReferenceCandidate) = + FlatSignature.createFromReflectionType(candidate, candidate.candidate, candidate.numDefaults, candidate.reflectionCandidateType) + } +} + +class PostponeCallableReferenceArgument( + val argument: CallableReferenceKotlinCallArgument, + val expectedType: UnwrappedType +) + +class CallableReferenceResolver( + val towerResolver: TowerResolver, + val callableReferenceOverloadConflictResolver: CallableReferenceOverloadConflictResolver +) { + + fun runRLSResolution( + outerCallContext: KotlinCallContext, + callableReference: CallableReferenceKotlinCallArgument, + expectedType: UnwrappedType?, // this type can have not fixed type variable inside + compatibilityChecker: ((ConstraintSystemOperation) -> Unit) -> Unit // you can run anything throw this operation and all this operation will be roll backed + ): Set { + val factory = CallableReferencesCandidateFactory(callableReference, outerCallContext, compatibilityChecker, expectedType) + val processor = createCallableReferenceProcessor(factory) + val candidates = towerResolver.runResolve(outerCallContext.scopeTower, processor, useOrder = true) + return callableReferenceOverloadConflictResolver.chooseMaximallySpecificCandidates(candidates, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS, + discriminateGenerics = false, + isDebuggerContext = outerCallContext.scopeTower.isDebuggerContext) } } diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/CheckArgumentsResolutionPart.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/CheckArgumentsResolutionPart.kt index 93295ff153b..12b277b3348 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/CheckArgumentsResolutionPart.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/CheckArgumentsResolutionPart.kt @@ -19,7 +19,10 @@ package org.jetbrains.kotlin.resolve.calls.components import org.jetbrains.kotlin.builtins.getValueParameterTypesFromFunctionType import org.jetbrains.kotlin.builtins.isExtensionFunctionType import org.jetbrains.kotlin.builtins.isFunctionType -import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.descriptors.ClassifierDescriptorWithTypeParameters +import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor +import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor +import org.jetbrains.kotlin.resolve.calls.components.CreateDescriptorWithFreshTypeVariables.createToFreshVariableSubstitutorAndAddInitialConstraints import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder import org.jetbrains.kotlin.resolve.calls.inference.addSubtypeConstraintIfCompatible import org.jetbrains.kotlin.resolve.calls.inference.model.ArgumentConstraintPosition @@ -32,12 +35,10 @@ import org.jetbrains.kotlin.types.checker.hasSupertypeWithGivenTypeConstructor import org.jetbrains.kotlin.types.checker.intersectWrappedTypes import org.jetbrains.kotlin.types.lowerIfFlexible import org.jetbrains.kotlin.types.typeUtil.builtIns -import org.jetbrains.kotlin.types.typeUtil.immediateSupertypes import org.jetbrains.kotlin.types.typeUtil.supertypes import org.jetbrains.kotlin.types.upperIfFlexible import org.jetbrains.kotlin.utils.SmartList import org.jetbrains.kotlin.utils.addIfNotNull -import java.lang.UnsupportedOperationException internal object CheckArguments : ResolutionPart { override fun SimpleKotlinResolutionCandidate.process(): List { @@ -47,7 +48,8 @@ internal object CheckArguments : ResolutionPart { val resolvedCallArgument = argumentMappingByOriginal[parameterDescriptor.original] ?: continue for (argument in resolvedCallArgument.arguments) { - val diagnostic = checkArgument(callContext, kotlinCall, csBuilder, argument, argument.getExpectedType(parameterDescriptor)) + val diagnostic = checkArgument(callContext, kotlinCall, csBuilder, argument, argument.getExpectedType(parameterDescriptor), + postponeCallableReferenceArguments) diagnostics.addIfNotNull(diagnostic) if (diagnostic != null && !diagnostic.candidateApplicability.isSuccess) break @@ -61,13 +63,23 @@ internal object CheckArguments : ResolutionPart { kotlinCall: KotlinCall, csBuilder: ConstraintSystemBuilder, argument: KotlinCallArgument, - expectedType: UnwrappedType + expectedType: UnwrappedType, + postponeCallableReferenceArguments: MutableList? = null ): KotlinCallDiagnostic? { return when (argument) { is ExpressionKotlinCallArgument -> checkExpressionArgument(csBuilder, argument, expectedType, isReceiver = false) is SubKotlinCallArgument -> checkSubCallArgument(csBuilder, argument, expectedType, isReceiver = false) is LambdaKotlinCallArgument -> processLambdaArgument(kotlinCall, csBuilder, argument, expectedType) - is CallableReferenceKotlinCallArgument -> processCallableReferenceArgument(callContext, kotlinCall, csBuilder, argument, expectedType) + is CallableReferenceKotlinCallArgument -> { + if (postponeCallableReferenceArguments == null) { + processCallableReferenceArgument(callContext, kotlinCall, csBuilder, argument, expectedType) + } + else { + // callable reference resolution will be run after choosing single descriptor + postponeCallableReferenceArguments.add(PostponeCallableReferenceArgument(argument, expectedType)) + null + } + } else -> error("Incorrect argument type: $argument, ${argument.javaClass.canonicalName}.") } } @@ -158,43 +170,27 @@ internal object CheckArguments : ResolutionPart { argument: CallableReferenceKotlinCallArgument, expectedType: UnwrappedType ): KotlinCallDiagnostic? { - val position = ArgumentConstraintPosition(argument) - - if (argument !is ChosenCallableReferenceDescriptor) { - val lhsType = argument.lhsType - if (lhsType != null) { - // todo: case with two receivers - val expectedReceiverType = expectedType.supertypes().firstOrNull { it.isFunctionType }?.arguments?.first()?.type?.unwrap() - if (expectedReceiverType != null) { - // (lhsType) -> .. <: (expectedReceiverType) -> ... => expectedReceiverType <: lhsType - csBuilder.addSubtypeConstraint(expectedReceiverType, lhsType, position) - } - } - - return null + val subLHSCall = ((argument.lhsResult as? LHSResult.Expression)?.lshCallArgument as? SubKotlinCallArgument) + if (subLHSCall != null) { + csBuilder.addInnerCall(subLHSCall.resolvedCall) + } + val candidates = callContext.callableReferenceResolver.runRLSResolution(callContext, argument, expectedType) { checkCallableReference -> + csBuilder.runTransaction { checkCallableReference(this); false } + } + val chosenCandidate = when (candidates.size) { + 0 -> return NoneCallableReferenceCandidates(argument) + 1 -> candidates.single() + else -> return CallableReferenceCandidatesAmbiguity(argument, candidates) } - val descriptor = argument.candidate.descriptor - when (descriptor) { - is FunctionDescriptor -> { - // todo store resolved - val resolvedFunctionReference = callContext.callableReferenceResolver.resolveFunctionReference( - argument, kotlinCall, expectedType) - csBuilder.addSubtypeConstraint(resolvedFunctionReference.reflectionType, expectedType, position) - return resolvedFunctionReference.argumentsMapping?.diagnostics?.let { - ErrorCallableMapping(resolvedFunctionReference) - } - } - is PropertyDescriptor -> { + val toFreshSubstitutor = createToFreshVariableSubstitutorAndAddInitialConstraints(chosenCandidate.candidate, csBuilder, kotlinCall = null) + val reflectionType = toFreshSubstitutor.safeSubstitute(chosenCandidate.reflectionCandidateType) + csBuilder.addSubtypeConstraint(reflectionType, expectedType, ArgumentConstraintPosition(argument)) + + val resolvedCallableReference = ResolvedCallableReferenceArgument(kotlinCall, argument, toFreshSubstitutor.freshVariables, chosenCandidate) + csBuilder.addCallableReferenceArgument(resolvedCallableReference) - // todo store resolved - val resolvedPropertyReference = callContext.callableReferenceResolver.resolvePropertyReference(descriptor, - argument, kotlinCall, callContext.scopeTower.lexicalScope.ownerDescriptor) - csBuilder.addSubtypeConstraint(resolvedPropertyReference.reflectionType, expectedType, position) - } - else -> throw UnsupportedOperationException("Callable reference resolved to an unsupported descriptor: $descriptor") - } return null } } diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/KotlinCallCompleter.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/KotlinCallCompleter.kt index b4399c7ebc3..f137f65b7f7 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/KotlinCallCompleter.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/KotlinCallCompleter.kt @@ -77,6 +77,7 @@ class KotlinCallCompleter( is VariableAsFunctionKotlinResolutionCandidate -> candidate.invokeCandidate else -> candidate as SimpleKotlinResolutionCandidate } + resolveCallableReferenceArguments(topLevelCall) if (topLevelCall.prepareForCompletion(expectedType)) { val c = candidate.lastCall.constraintSystem.asCallCompleterContext() @@ -88,6 +89,14 @@ class KotlinCallCompleter( return ResolvedKotlinCall.OnlyResolvedKotlinCall(candidate) } + private fun resolveCallableReferenceArguments(candidate: SimpleKotlinResolutionCandidate) { + for (callableReferenceArgument in candidate.postponeCallableReferenceArguments) { + CheckArguments.processCallableReferenceArgument(candidate.callContext, candidate.kotlinCall, candidate.csBuilder, + callableReferenceArgument.argument, callableReferenceArgument.expectedType) + } + candidate.postponeCallableReferenceArguments.clear() + } + private fun toCompletedBaseResolvedCall( c: Context, candidate: KotlinResolutionCandidate, diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ResolutionParts.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ResolutionParts.kt index 5960748d6c2..a03f59c76b5 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ResolutionParts.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ResolutionParts.kt @@ -262,6 +262,13 @@ class MissingReceiver(val functionExpression: FunctionExpression) : KotlinCallDi override fun report(reporter: DiagnosticReporter) = reporter.onCallArgument(functionExpression, this) } -class ErrorCallableMapping(val functionReference: ResolvedFunctionReference) : KotlinCallDiagnostic(IMPOSSIBLE_TO_GENERATE) { - override fun report(reporter: DiagnosticReporter) = reporter.onCallArgument(functionReference.argument, this) -} \ No newline at end of file +class NoneCallableReferenceCandidates(val argument: CallableReferenceKotlinCallArgument) : KotlinCallDiagnostic(IMPOSSIBLE_TO_GENERATE) { + override fun report(reporter: DiagnosticReporter) = reporter.onCallArgument(argument, this) +} + +class CallableReferenceCandidatesAmbiguity( + val argument: CallableReferenceKotlinCallArgument, + val candidates: Collection +) : KotlinCallDiagnostic(IMPOSSIBLE_TO_GENERATE) { + override fun report(reporter: DiagnosticReporter) = reporter.onCallArgument(argument, this) +} diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/ConstraintSystemBuilder.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/ConstraintSystemBuilder.kt index 63c44258e8c..ed58e66717b 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/ConstraintSystemBuilder.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/ConstraintSystemBuilder.kt @@ -19,6 +19,7 @@ package org.jetbrains.kotlin.resolve.calls.inference import org.jetbrains.kotlin.resolve.calls.inference.components.NewTypeSubstitutor import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintPosition import org.jetbrains.kotlin.resolve.calls.inference.model.NewTypeVariable +import org.jetbrains.kotlin.resolve.calls.model.ResolvedCallableReferenceArgument import org.jetbrains.kotlin.resolve.calls.model.ResolvedKotlinCall import org.jetbrains.kotlin.resolve.calls.model.ResolvedLambdaArgument import org.jetbrains.kotlin.types.UnwrappedType @@ -36,6 +37,7 @@ interface ConstraintSystemOperation { interface ConstraintSystemBuilder : ConstraintSystemOperation { fun addInnerCall(innerCall: ResolvedKotlinCall.OnlyResolvedKotlinCall) fun addLambdaArgument(resolvedLambdaArgument: ResolvedLambdaArgument) + fun addCallableReferenceArgument(resolvedCallableReferenceArgument: ResolvedCallableReferenceArgument) // if runOperations return true, then this operation will be applied, and function return true fun runTransaction(runOperations: ConstraintSystemOperation.() -> Boolean): Boolean diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/model/ConstraintStorage.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/model/ConstraintStorage.kt index 37cb12c4ad3..6c43f263976 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/model/ConstraintStorage.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/model/ConstraintStorage.kt @@ -19,6 +19,7 @@ package org.jetbrains.kotlin.resolve.calls.inference.model import org.jetbrains.kotlin.resolve.calls.inference.substitute import org.jetbrains.kotlin.resolve.calls.model.ResolvedKotlinCall import org.jetbrains.kotlin.resolve.calls.model.KotlinCallDiagnostic +import org.jetbrains.kotlin.resolve.calls.model.ResolvedCallableReferenceArgument import org.jetbrains.kotlin.resolve.calls.model.ResolvedLambdaArgument import org.jetbrains.kotlin.types.TypeConstructor import org.jetbrains.kotlin.types.TypeSubstitutor @@ -55,6 +56,7 @@ interface ConstraintStorage { val errors: List val fixedTypeVariables: Map val lambdaArguments: List + val callableReferenceArguments: List val innerCalls: List object Empty : ConstraintStorage { @@ -65,6 +67,7 @@ interface ConstraintStorage { override val errors: List get() = emptyList() override val fixedTypeVariables: Map get() = emptyMap() override val lambdaArguments: List get() = emptyList() + override val callableReferenceArguments: List get() = emptyList() override val innerCalls: List get() = emptyList() } } diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/model/MutableConstraintStorage.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/model/MutableConstraintStorage.kt index fb22b62a816..8499d23c144 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/model/MutableConstraintStorage.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/model/MutableConstraintStorage.kt @@ -19,6 +19,7 @@ package org.jetbrains.kotlin.resolve.calls.inference.model import org.jetbrains.kotlin.resolve.calls.inference.trimToSize import org.jetbrains.kotlin.resolve.calls.model.ResolvedKotlinCall import org.jetbrains.kotlin.resolve.calls.model.KotlinCallDiagnostic +import org.jetbrains.kotlin.resolve.calls.model.ResolvedCallableReferenceArgument import org.jetbrains.kotlin.resolve.calls.model.ResolvedLambdaArgument import org.jetbrains.kotlin.types.TypeConstructor import org.jetbrains.kotlin.types.UnwrappedType @@ -84,5 +85,6 @@ internal class MutableConstraintStorage : ConstraintStorage { override val errors: MutableList = ArrayList() override val fixedTypeVariables: MutableMap = LinkedHashMap() override val lambdaArguments: MutableList = ArrayList() + override val callableReferenceArguments: MutableList = ArrayList() override val innerCalls: MutableList = ArrayList() } \ No newline at end of file diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/model/NewConstraintSystemImpl.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/model/NewConstraintSystemImpl.kt index 1591097c233..ff7385380ce 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/model/NewConstraintSystemImpl.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/model/NewConstraintSystemImpl.kt @@ -20,6 +20,7 @@ import org.jetbrains.kotlin.resolve.calls.components.KotlinCallCompleter import org.jetbrains.kotlin.resolve.calls.inference.* import org.jetbrains.kotlin.resolve.calls.inference.components.* import org.jetbrains.kotlin.resolve.calls.model.KotlinCallDiagnostic +import org.jetbrains.kotlin.resolve.calls.model.ResolvedCallableReferenceArgument import org.jetbrains.kotlin.resolve.calls.model.ResolvedKotlinCall import org.jetbrains.kotlin.resolve.calls.model.ResolvedLambdaArgument import org.jetbrains.kotlin.resolve.calls.tower.isSuccess @@ -140,6 +141,11 @@ class NewConstraintSystemImpl(val constraintInjector: ConstraintInjector, val re storage.lambdaArguments.add(resolvedLambdaArgument) } + override fun addCallableReferenceArgument(resolvedCallableReferenceArgument: ResolvedCallableReferenceArgument) { + checkState(State.BUILDING, State.COMPLETION) + storage.callableReferenceArguments.add(resolvedCallableReferenceArgument) + } + private fun getVariablesForFixation(): Map { val fixedVariables = LinkedHashMap() @@ -185,6 +191,7 @@ class NewConstraintSystemImpl(val constraintInjector: ConstraintInjector, val re storage.errors.addAll(otherSystem.errors) storage.fixedTypeVariables.putAll(otherSystem.fixedTypeVariables) storage.lambdaArguments.addAll(otherSystem.lambdaArguments) + storage.callableReferenceArguments.addAll(otherSystem.callableReferenceArguments) storage.innerCalls.addAll(otherSystem.innerCalls) } diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/ArgumentsImpl.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/ArgumentsImpl.kt index ff4be7522ee..927d4e91a80 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/ArgumentsImpl.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/ArgumentsImpl.kt @@ -24,7 +24,6 @@ import org.jetbrains.kotlin.types.checker.prepareArgumentTypeRegardingCaptureTyp class FakeKotlinCallArgumentForCallableReference( - val callableReference: ChosenCallableReferenceDescriptor, val index: Int ) : KotlinCallArgument { override val isSpread: Boolean get() = false diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/KotlinCallArguments.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/KotlinCallArguments.kt index bed7b68c267..d9bb79c94da 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/KotlinCallArguments.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/KotlinCallArguments.kt @@ -16,12 +16,13 @@ package org.jetbrains.kotlin.resolve.calls.model +import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.name.Name -import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage -import org.jetbrains.kotlin.resolve.calls.tower.CandidateWithBoundDispatchReceiver +import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.scopes.receivers.DetailedReceiver import org.jetbrains.kotlin.resolve.scopes.receivers.QualifierReceiver import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValueWithSmartCastInfo +import org.jetbrains.kotlin.resolve.scopes.receivers.TransientReceiver import org.jetbrains.kotlin.types.UnwrappedType @@ -71,20 +72,51 @@ interface FunctionExpression : LambdaKotlinCallArgument { val returnType: UnwrappedType? } +/** + * cases: class A {}, class B { companion object }, object C, enum class D { E } + * A::foo <-> Type + * a::foo <-> Expression + * B::foo <-> Type + * C::foo <-> Object + * D.E::foo <-> Expression + */ +sealed class LHSResult { + class Type(val qualifier: QualifierReceiver): LHSResult() { + val unboundDetailedReceiver: ReceiverValueWithSmartCastInfo + + init { + assert(qualifier.descriptor is ClassDescriptor) { + "Should be ClassDescriptor: ${qualifier.descriptor}" + } + + val unboundReceiver = TransientReceiver((qualifier.descriptor as ClassDescriptor).defaultType) + unboundDetailedReceiver = ReceiverValueWithSmartCastInfo(unboundReceiver, emptySet(), isStable = true) + } + } + + class Object(val qualifier: QualifierReceiver): LHSResult() { + val objectValueReceiver: ReceiverValueWithSmartCastInfo + + init { + assert(DescriptorUtils.isObject(qualifier.descriptor)) { + "Should be object descriptor: ${qualifier.descriptor}" + } + objectValueReceiver = qualifier.classValueReceiverWithSmartCastInfo ?: error("class value should be not null for $qualifier") + } + } + class Expression(val lshCallArgument: SimpleKotlinCallArgument): LHSResult() + + // todo this case is forbid for now + object Empty: LHSResult() +} + interface CallableReferenceKotlinCallArgument : KotlinCallArgument { override val isSpread: Boolean get() = false - // Foo::bar lhsType = Foo. For a::bar where a is expression, this type is null - val lhsType: UnwrappedType? + val lhsResult: LHSResult - val constraintStorage: ConstraintStorage -} - -interface ChosenCallableReferenceDescriptor : CallableReferenceKotlinCallArgument { - val candidate: CandidateWithBoundDispatchReceiver - - val extensionReceiver: ReceiverValueWithSmartCastInfo? + val rhsName: Name } diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/KotlinResolverContext.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/KotlinResolverContext.kt index 1397d65fd40..75d621a15d6 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/KotlinResolverContext.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/KotlinResolverContext.kt @@ -16,6 +16,7 @@ package org.jetbrains.kotlin.resolve.calls.model +import org.jetbrains.kotlin.builtins.ReflectionTypes import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.resolve.calls.components.CheckArguments import org.jetbrains.kotlin.resolve.calls.components.KotlinResolutionCallbacks @@ -38,7 +39,8 @@ class KotlinCallContext( val typeArgumentsToParametersMapper: TypeArgumentsToParametersMapper, val resultTypeResolver: ResultTypeResolver, val callableReferenceResolver: CallableReferenceResolver, - val constraintInjector: ConstraintInjector + val constraintInjector: ConstraintInjector, + val reflectionTypes: ReflectionTypes ) class SimpleCandidateFactory(val callContext: KotlinCallContext, val kotlinCall: KotlinCall): CandidateFactory { @@ -51,6 +53,17 @@ class SimpleCandidateFactory(val callContext: KotlinCallContext, val kotlinCall: explicitReceiver as? SimpleKotlinCallArgument ?: // qualifier receiver cannot be safe fromResolution?.let { ReceiverExpressionKotlinCallArgument(it, isSafeCall = false) } // todo smartcast implicit this + private fun KotlinCall.getExplicitDispatchReceiver(explicitReceiverKind: ExplicitReceiverKind) = when (explicitReceiverKind) { + ExplicitReceiverKind.DISPATCH_RECEIVER -> explicitReceiver + ExplicitReceiverKind.BOTH_RECEIVERS -> dispatchReceiverForInvokeExtension + else -> null + } + + private fun KotlinCall.getExplicitExtensionReceiver(explicitReceiverKind: ExplicitReceiverKind) = when (explicitReceiverKind) { + ExplicitReceiverKind.EXTENSION_RECEIVER, ExplicitReceiverKind.BOTH_RECEIVERS -> explicitReceiver + else -> null + } + override fun createCandidate( towerCandidate: CandidateWithBoundDispatchReceiver, explicitReceiverKind: ExplicitReceiverKind, diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/ResolutionCandidate.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/ResolutionCandidate.kt index ce96b9f0755..c0710e855a0 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/ResolutionCandidate.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/ResolutionCandidate.kt @@ -19,6 +19,7 @@ package org.jetbrains.kotlin.resolve.calls.model import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor import org.jetbrains.kotlin.renderer.DescriptorRenderer +import org.jetbrains.kotlin.resolve.calls.components.PostponeCallableReferenceArgument import org.jetbrains.kotlin.resolve.calls.components.TypeArgumentsToParametersMapper import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder import org.jetbrains.kotlin.resolve.calls.inference.NewConstraintSystem @@ -28,6 +29,7 @@ import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind import org.jetbrains.kotlin.resolve.calls.tower.Candidate import org.jetbrains.kotlin.resolve.calls.tower.ResolutionCandidateStatus import org.jetbrains.kotlin.resolve.calls.tower.isSuccess +import org.jetbrains.kotlin.utils.SmartList import java.util.* @@ -112,6 +114,7 @@ open class SimpleKotlinResolutionCandidate( initialDiagnostics: Collection ) : AbstractSimpleKotlinResolutionCandidate(NewConstraintSystemImpl(callContext.constraintInjector, callContext.resultTypeResolver), initialDiagnostics) { val csBuilder: ConstraintSystemBuilder get() = constraintSystem.getBuilder() + val postponeCallableReferenceArguments = SmartList() lateinit var typeArgumentMappingByOriginal: TypeArgumentsToParametersMapper.TypeArgumentsMapping lateinit var argumentMappingByOriginal: Map diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/ResolvedCallElements.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/ResolvedCallElements.kt index bd78cd00a19..7ac774e308e 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/ResolvedCallElements.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/ResolvedCallElements.kt @@ -18,12 +18,9 @@ package org.jetbrains.kotlin.resolve.calls.model import org.jetbrains.kotlin.builtins.createFunctionType import org.jetbrains.kotlin.descriptors.annotations.Annotations -import org.jetbrains.kotlin.resolve.calls.components.ArgumentsToParametersMapper +import org.jetbrains.kotlin.resolve.calls.components.CallableReferenceCandidate import org.jetbrains.kotlin.resolve.calls.inference.model.LambdaTypeVariable import org.jetbrains.kotlin.resolve.calls.inference.model.NewTypeVariable -import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind -import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue -import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.SimpleType import org.jetbrains.kotlin.types.UnwrappedType import org.jetbrains.kotlin.types.typeUtil.builtIns @@ -55,45 +52,12 @@ class ResolvedLambdaArgument( lateinit var resultArguments: List } - -class ResolvedPropertyReference( - val outerCall: KotlinCall, - val argument: ChosenCallableReferenceDescriptor, - val reflectionType: UnwrappedType -) { - val boundDispatchReceiver: ReceiverValue? get() = argument.candidate.dispatchReceiver?.receiverValue?.takeIf { it !is MockReceiverForCallableReference } - val boundExtensionReceiver: ReceiverValue? get() = argument.extensionReceiver?.receiverValue?.takeIf { it !is MockReceiverForCallableReference } -} - -class ResolvedFunctionReference( - val outerCall: KotlinCall, - val argument: ChosenCallableReferenceDescriptor, - val reflectionType: UnwrappedType, - val argumentsMapping: ArgumentsToParametersMapper.ArgumentMapping? -) { - val boundDispatchReceiver: ReceiverValue? get() = argument.candidate.dispatchReceiver?.receiverValue?.takeIf { it !is MockReceiverForCallableReference } - val boundExtensionReceiver: ReceiverValue? get() = argument.extensionReceiver?.receiverValue?.takeIf { it !is MockReceiverForCallableReference } -} - - -fun KotlinCall.getExplicitDispatchReceiver(explicitReceiverKind: ExplicitReceiverKind) = when (explicitReceiverKind) { - ExplicitReceiverKind.DISPATCH_RECEIVER -> explicitReceiver - ExplicitReceiverKind.BOTH_RECEIVERS -> dispatchReceiverForInvokeExtension - else -> null -} - -fun KotlinCall.getExplicitExtensionReceiver(explicitReceiverKind: ExplicitReceiverKind) = when (explicitReceiverKind) { - ExplicitReceiverKind.EXTENSION_RECEIVER, ExplicitReceiverKind.BOTH_RECEIVERS -> explicitReceiver - else -> null -} - -class MockReceiverForCallableReference(val lhsOrDeclaredType: UnwrappedType) : ReceiverValue { - override fun getType() = lhsOrDeclaredType - override fun replaceType(newType: KotlinType) = MockReceiverForCallableReference(newType.unwrap()) -} - -val ChosenCallableReferenceDescriptor.dispatchNotBoundReceiver : UnwrappedType? - get() = (candidate.dispatchReceiver?.receiverValue as? MockReceiverForCallableReference)?.lhsOrDeclaredType - -val ChosenCallableReferenceDescriptor.extensionNotBoundReceiver : UnwrappedType? - get() = (extensionReceiver as? MockReceiverForCallableReference)?.lhsOrDeclaredType +class ResolvedCallableReferenceArgument( + override val outerCall: KotlinCall, + override val argument: CallableReferenceKotlinCallArgument, + override val myTypeVariables: Collection, + val callableResolutionCandidate: CallableReferenceCandidate +) : ArgumentWithPostponeResolution() { + override val inputType: Collection get() = emptyList() + override val outputType: UnwrappedType? = null +} \ No newline at end of file diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/results/FlatSignature.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/results/FlatSignature.kt index 9e06407887e..9aee2f24071 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/results/FlatSignature.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/results/FlatSignature.kt @@ -51,6 +51,23 @@ class FlatSignature private constructor( val isGeneric = typeParameters.isNotEmpty() companion object { + fun createFromReflectionType( + origin: T, + descriptor: CallableDescriptor, + numDefaults: Int, + reflectionType: UnwrappedType + ): FlatSignature { + return FlatSignature(origin, + descriptor.typeParameters, + reflectionType.arguments.map { it.type }, // should we drop return type? + hasExtensionReceiver = false, + hasVarargs = descriptor.valueParameters.any { it.varargElementType != null }, + numDefaults = numDefaults, + isHeader = descriptor is MemberDescriptor && descriptor.isHeader, + isSyntheticMember = descriptor is SyntheticMemberDescriptor<*> + ) + } + fun create( origin: T, descriptor: CallableDescriptor, diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/CoercionStrategy.java b/compiler/resolution/src/org/jetbrains/kotlin/types/expressions/CoercionStrategy.java similarity index 100% rename from compiler/frontend/src/org/jetbrains/kotlin/types/expressions/CoercionStrategy.java rename to compiler/resolution/src/org/jetbrains/kotlin/types/expressions/CoercionStrategy.java