[NI] New inference -- initial commit.
This commit is contained in:
@@ -63,6 +63,10 @@ public interface Errors {
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
DiagnosticFactory1<PsiElement, String> UNSUPPORTED = DiagnosticFactory1.create(ERROR);
|
||||
|
||||
DiagnosticFactory1<PsiElement, String> NEW_INFERENCE_ERROR = DiagnosticFactory1.create(ERROR);
|
||||
DiagnosticFactory1<PsiElement, String> NEW_INFERENCE_DIAGNOSTIC = DiagnosticFactory1.create(WARNING);
|
||||
|
||||
DiagnosticFactory1<PsiElement, Pair<LanguageFeature, LanguageVersionSettings>> UNSUPPORTED_FEATURE = DiagnosticFactory1.create(ERROR);
|
||||
DiagnosticFactory1<PsiElement, Throwable> EXCEPTION_FROM_ANALYZER = DiagnosticFactory1.create(ERROR);
|
||||
|
||||
@@ -586,6 +590,7 @@ public interface Errors {
|
||||
DiagnosticFactory0<KtExpression> VARARG_OUTSIDE_PARENTHESES = DiagnosticFactory0.create(ERROR);
|
||||
DiagnosticFactory0<LeafPsiElement> NON_VARARG_SPREAD = DiagnosticFactory0.create(ERROR);
|
||||
DiagnosticFactory0<LeafPsiElement> SPREAD_OF_NULLABLE = DiagnosticFactory0.create(ERROR);
|
||||
DiagnosticFactory0<LeafPsiElement> SPREAD_OF_LAMBDA_OR_CALLABLE_REFERENCE = DiagnosticFactory0.create(ERROR);
|
||||
|
||||
DiagnosticFactory0<KtExpression> MANY_LAMBDA_EXPRESSION_ARGUMENTS = DiagnosticFactory0.create(ERROR);
|
||||
|
||||
|
||||
+3
@@ -202,6 +202,7 @@ public class DefaultErrorMessages {
|
||||
MAP.put(VARARG_OUTSIDE_PARENTHESES, "Passing value as a vararg is only allowed inside a parenthesized argument list");
|
||||
MAP.put(NON_VARARG_SPREAD, "The spread operator (*foo) may only be applied in a vararg position");
|
||||
MAP.put(SPREAD_OF_NULLABLE, "The spread operator (*foo) may not be applied to an argument of nullable type");
|
||||
MAP.put(SPREAD_OF_LAMBDA_OR_CALLABLE_REFERENCE, "The spread operator (*foo) cannot be applied to lambda argument or callable reference");
|
||||
|
||||
MAP.put(MANY_LAMBDA_EXPRESSION_ARGUMENTS, "Only one lambda expression is allowed outside a parenthesized argument list");
|
||||
MAP.put(PROPERTY_WITH_NO_TYPE_NO_INITIALIZER, "This property must either have a type annotation, be initialized or be delegated");
|
||||
@@ -573,6 +574,8 @@ public class DefaultErrorMessages {
|
||||
MAP.put(UNSAFE_IMPLICIT_INVOKE_CALL, "Reference has a nullable type ''{0}'', use explicit ''?.invoke()'' to make a function-like call instead", RENDER_TYPE);
|
||||
MAP.put(AMBIGUOUS_LABEL, "Ambiguous label");
|
||||
MAP.put(UNSUPPORTED, "Unsupported [{0}]", STRING);
|
||||
MAP.put(NEW_INFERENCE_ERROR, "New inference error [{0}]", STRING);
|
||||
MAP.put(NEW_INFERENCE_DIAGNOSTIC, "New inference [{0}]", STRING);
|
||||
|
||||
MAP.put(UNSUPPORTED_FEATURE, "{0}", new LanguageFeatureMessageRenderer(LanguageFeatureMessageRenderer.Type.UNSUPPORTED));
|
||||
MAP.put(EXPERIMENTAL_FEATURE_WARNING, "{0}", new LanguageFeatureMessageRenderer(LanguageFeatureMessageRenderer.Type.WARNING));
|
||||
|
||||
@@ -28,6 +28,8 @@ import org.jetbrains.kotlin.extensions.StorageComponentContainerContributor
|
||||
import org.jetbrains.kotlin.incremental.components.LookupTracker
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.resolve.*
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.CommonSupertypeCalculatorImpl
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.IsDescriptorFromSourcePredicateImpl
|
||||
import org.jetbrains.kotlin.resolve.lazy.*
|
||||
import org.jetbrains.kotlin.resolve.lazy.declarations.DeclarationProviderFactory
|
||||
import org.jetbrains.kotlin.resolve.lazy.declarations.FileBasedDeclarationProviderFactory
|
||||
@@ -60,6 +62,8 @@ fun StorageComponentContainer.configureModule(
|
||||
|
||||
private fun StorageComponentContainer.configurePlatformIndependentComponents() {
|
||||
useImpl<SupertypeLoopCheckerImpl>()
|
||||
useInstance(CommonSupertypeCalculatorImpl)
|
||||
useInstance(IsDescriptorFromSourcePredicateImpl)
|
||||
}
|
||||
|
||||
fun StorageComponentContainer.configureModule(
|
||||
|
||||
@@ -29,6 +29,7 @@ import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor;
|
||||
import org.jetbrains.kotlin.name.FqName;
|
||||
import org.jetbrains.kotlin.name.FqNameUnsafe;
|
||||
import org.jetbrains.kotlin.psi.*;
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedKotlinCall;
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemCompleter;
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo;
|
||||
@@ -120,6 +121,7 @@ public interface BindingContext {
|
||||
new BasicWritableSlice<>(DO_NOTHING);
|
||||
|
||||
WritableSlice<Call, ResolvedCall<?>> RESOLVED_CALL = new BasicWritableSlice<>(DO_NOTHING);
|
||||
WritableSlice<Call, ResolvedKotlinCall.OnlyResolvedKotlinCall> ONLY_RESOLVED_CALL = new BasicWritableSlice<>(DO_NOTHING);
|
||||
WritableSlice<Call, TailRecursionKind> TAIL_RECURSION_CALL = Slices.createSimpleSlice();
|
||||
WritableSlice<KtElement, ConstraintSystemCompleter> CONSTRAINT_SYSTEM_COMPLETER = new BasicWritableSlice<>(DO_NOTHING);
|
||||
WritableSlice<KtElement, Call> CALL = new BasicWritableSlice<>(DO_NOTHING);
|
||||
|
||||
@@ -281,7 +281,7 @@ class CallExpressionResolver(
|
||||
}
|
||||
else when (resolutionResult.resultCode) {
|
||||
NAME_NOT_FOUND, CANDIDATES_WITH_WRONG_RECEIVER -> false
|
||||
else -> true
|
||||
else -> !USE_NEW_INFERENCE || resolutionResult.isSuccess
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -35,12 +35,14 @@ import org.jetbrains.kotlin.resolve.calls.callResolverUtil.ResolveArgumentsMode;
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilKt;
|
||||
import org.jetbrains.kotlin.resolve.calls.context.*;
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.CoroutineInferenceUtilKt;
|
||||
import org.jetbrains.kotlin.resolve.calls.model.KotlinCallKind;
|
||||
import org.jetbrains.kotlin.resolve.calls.model.MutableDataFlowInfoForArguments;
|
||||
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults;
|
||||
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResultsImpl;
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo;
|
||||
import org.jetbrains.kotlin.resolve.calls.tasks.*;
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.NewResolutionOldInference;
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.PSICallResolver;
|
||||
import org.jetbrains.kotlin.resolve.calls.util.CallMaker;
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt;
|
||||
import org.jetbrains.kotlin.resolve.lazy.ForceResolveUtil;
|
||||
@@ -70,8 +72,9 @@ public class CallResolver {
|
||||
private ArgumentTypeResolver argumentTypeResolver;
|
||||
private GenericCandidateResolver genericCandidateResolver;
|
||||
private CallCompleter callCompleter;
|
||||
private NewResolutionOldInference newCallResolver;
|
||||
private SyntheticScopes syntheticScopes;
|
||||
private NewResolutionOldInference newResolutionOldInference;
|
||||
private PSICallResolver PSICallResolver;
|
||||
private final KotlinBuiltIns builtIns;
|
||||
private final LanguageVersionSettings languageVersionSettings;
|
||||
|
||||
@@ -117,8 +120,14 @@ public class CallResolver {
|
||||
|
||||
// component dependency cycle
|
||||
@Inject
|
||||
public void setCallCompleter(@NotNull NewResolutionOldInference newCallResolver) {
|
||||
this.newCallResolver = newCallResolver;
|
||||
public void setResolutionOldInference(@NotNull NewResolutionOldInference newResolutionOldInference) {
|
||||
this.newResolutionOldInference = newResolutionOldInference;
|
||||
}
|
||||
|
||||
// component dependency cycle
|
||||
@Inject
|
||||
public void setPSICallResolver(@NotNull PSICallResolver PSICallResolver) {
|
||||
this.PSICallResolver = PSICallResolver;
|
||||
}
|
||||
|
||||
@Inject
|
||||
@@ -520,7 +529,7 @@ public class CallResolver {
|
||||
});
|
||||
}
|
||||
|
||||
private <D extends CallableDescriptor> OverloadResolutionResultsImpl<D> doResolveCallOrGetCachedResults(
|
||||
private <D extends CallableDescriptor> OverloadResolutionResults<D> doResolveCallOrGetCachedResults(
|
||||
@NotNull BasicCallResolutionContext context,
|
||||
@NotNull ResolutionTask<D> resolutionTask,
|
||||
@NotNull TracingStrategy tracing
|
||||
@@ -528,6 +537,16 @@ public class CallResolver {
|
||||
Call call = context.call;
|
||||
tracing.bindCall(context.trace, call);
|
||||
|
||||
if (KotlinResolutionConfigurationKt.getUSE_NEW_INFERENCE() && (resolutionTask.resolutionKind.getKotlinCallKind() != KotlinCallKind.UNSUPPORTED)) {
|
||||
assert resolutionTask.name != null;
|
||||
return PSICallResolver.runResolutionAndInference(context, resolutionTask.name, resolutionTask.resolutionKind, tracing);
|
||||
}
|
||||
|
||||
if (KotlinResolutionConfigurationKt.getUSE_NEW_INFERENCE() && resolutionTask.resolutionKind instanceof NewResolutionOldInference.ResolutionKind.GivenCandidates) {
|
||||
assert resolutionTask.givenCandidates != null;
|
||||
return PSICallResolver.runResolutionAndInferenceForGivenCandidates(context, resolutionTask.givenCandidates, tracing);
|
||||
}
|
||||
|
||||
TemporaryBindingTrace traceToResolveCall = TemporaryBindingTrace.create(context.trace, "trace to resolve call", call);
|
||||
BasicCallResolutionContext newContext = context.replaceBindingTrace(traceToResolveCall);
|
||||
|
||||
@@ -624,11 +643,11 @@ public class CallResolver {
|
||||
|
||||
if (!(resolutionTask.resolutionKind instanceof NewResolutionOldInference.ResolutionKind.GivenCandidates)) {
|
||||
assert resolutionTask.name != null;
|
||||
return newCallResolver.runResolution(context, resolutionTask.name, resolutionTask.resolutionKind, tracing);
|
||||
return newResolutionOldInference.runResolution(context, resolutionTask.name, resolutionTask.resolutionKind, tracing);
|
||||
}
|
||||
else {
|
||||
assert resolutionTask.givenCandidates != null;
|
||||
return newCallResolver.runResolutionForGivenCandidates(context, tracing, resolutionTask.givenCandidates);
|
||||
return newResolutionOldInference.runResolutionForGivenCandidates(context, tracing, resolutionTask.givenCandidates);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+155
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
* Copyright 2010-2016 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
|
||||
|
||||
import org.jetbrains.kotlin.builtins.functions.FunctionInvokeDescriptor
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.diagnostics.Errors.*
|
||||
import org.jetbrains.kotlin.diagnostics.Errors.BadNamedArgumentsTarget.*
|
||||
import org.jetbrains.kotlin.psi.Call
|
||||
import org.jetbrains.kotlin.psi.KtPsiUtil
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.BindingTrace
|
||||
import org.jetbrains.kotlin.resolve.calls.components.*
|
||||
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.*
|
||||
import org.jetbrains.kotlin.resolve.calls.model.*
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.SmartCastManager
|
||||
import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategy
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.*
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
|
||||
|
||||
class DiagnosticReporterByTrackingStrategy(
|
||||
val context: BasicCallResolutionContext,
|
||||
val trace: BindingTrace,
|
||||
val psiKotlinCall: PSIKotlinCall
|
||||
): DiagnosticReporter {
|
||||
private val tracingStrategy: TracingStrategy get() = psiKotlinCall.tracingStrategy
|
||||
private val call: Call get() = psiKotlinCall.psiCall
|
||||
|
||||
override fun onExplicitReceiver(diagnostic: KotlinCallDiagnostic) {
|
||||
|
||||
}
|
||||
|
||||
override fun onCall(diagnostic: KotlinCallDiagnostic) {
|
||||
when (diagnostic.javaClass) {
|
||||
VisibilityError::class.java -> tracingStrategy.invisibleMember(trace, (diagnostic as VisibilityError).invisibleMember)
|
||||
NoValueForParameter::class.java -> tracingStrategy.noValueForParameter(trace, (diagnostic as NoValueForParameter).parameterDescriptor)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onTypeArguments(diagnostic: KotlinCallDiagnostic) {
|
||||
|
||||
}
|
||||
|
||||
override fun onCallName(diagnostic: KotlinCallDiagnostic) {
|
||||
|
||||
}
|
||||
|
||||
override fun onTypeArgument(typeArgument: TypeArgument, diagnostic: KotlinCallDiagnostic) {
|
||||
|
||||
}
|
||||
|
||||
override fun onCallReceiver(callReceiver: SimpleKotlinCallArgument, diagnostic: KotlinCallDiagnostic) {
|
||||
when (diagnostic.javaClass) {
|
||||
UnsafeCallError::class.java -> {
|
||||
val implicitInvokeCheck = (callReceiver as? ReceiverExpressionKotlinCallArgument)?.isVariableReceiverForInvoke ?: false
|
||||
tracingStrategy.unsafeCall(trace, callReceiver.receiver.receiverValue.type, implicitInvokeCheck)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCallArgument(callArgument: KotlinCallArgument, diagnostic: KotlinCallDiagnostic) {
|
||||
when (diagnostic.javaClass) {
|
||||
SmartCastDiagnostic::class.java -> reportSmartCast(diagnostic as SmartCastDiagnostic)
|
||||
UnstableSmartCast::class.java -> reportUnstableSmartCast(diagnostic as UnstableSmartCast)
|
||||
TooManyArguments::class.java ->
|
||||
trace.report(TOO_MANY_ARGUMENTS.on(callArgument.psiExpression!!, (diagnostic as TooManyArguments).descriptor))
|
||||
VarargArgumentOutsideParentheses::class.java ->
|
||||
trace.report(VARARG_OUTSIDE_PARENTHESES.on(callArgument.psiExpression!!))
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCallArgumentName(callArgument: KotlinCallArgument, diagnostic: KotlinCallDiagnostic) {
|
||||
val nameReference = callArgument.psiCallArgument.valueArgument.getArgumentName()?.referenceExpression ?:
|
||||
error("Argument name should be not null for argument: $callArgument")
|
||||
when (diagnostic.javaClass) {
|
||||
NamedArgumentReference::class.java ->
|
||||
trace.record(BindingContext.REFERENCE_TARGET, nameReference, (diagnostic as NamedArgumentReference).parameterDescriptor)
|
||||
NameForAmbiguousParameter::class.java -> trace.report(NAME_FOR_AMBIGUOUS_PARAMETER.on(nameReference))
|
||||
NameNotFound::class.java -> trace.report(NAMED_PARAMETER_NOT_FOUND.on(nameReference, nameReference))
|
||||
|
||||
NamedArgumentNotAllowed::class.java -> trace.report(NAMED_ARGUMENTS_NOT_ALLOWED.on(
|
||||
nameReference,
|
||||
if ((diagnostic as NamedArgumentNotAllowed).descriptor is FunctionInvokeDescriptor) INVOKE_ON_FUNCTION_TYPE else NON_KOTLIN_FUNCTION
|
||||
))
|
||||
ArgumentPassedTwice::class.java -> trace.report(ARGUMENT_PASSED_TWICE.on(nameReference))
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCallArgumentSpread(callArgument: KotlinCallArgument, diagnostic: KotlinCallDiagnostic) {
|
||||
|
||||
}
|
||||
|
||||
private fun reportSmartCast(smartCastDiagnostic: SmartCastDiagnostic) {
|
||||
val expressionArgument = smartCastDiagnostic.expressionArgument
|
||||
if (expressionArgument is ExpressionKotlinCallArgumentImpl) {
|
||||
val context = context.replaceDataFlowInfo(expressionArgument.dataFlowInfoBeforeThisArgument)
|
||||
val argumentExpression = KtPsiUtil.getLastElementDeparenthesized(expressionArgument.valueArgument.getArgumentExpression (), context.statementFilter)
|
||||
val dataFlowValue = DataFlowValueFactory.createDataFlowValue(expressionArgument.receiver.receiverValue, context)
|
||||
SmartCastManager.checkAndRecordPossibleCast(
|
||||
dataFlowValue, smartCastDiagnostic.smartCastType, argumentExpression, context, call,
|
||||
recordExpressionType = true)
|
||||
}
|
||||
else if(expressionArgument is ReceiverExpressionKotlinCallArgument) {
|
||||
val receiverValue = expressionArgument.receiver.receiverValue
|
||||
val dataFlowValue = DataFlowValueFactory.createDataFlowValue(receiverValue, context)
|
||||
SmartCastManager.checkAndRecordPossibleCast(
|
||||
dataFlowValue, smartCastDiagnostic.smartCastType, (receiverValue as? ExpressionReceiver)?.expression, context, call,
|
||||
recordExpressionType = true)
|
||||
}
|
||||
}
|
||||
|
||||
private fun reportUnstableSmartCast(unstableSmartCast: UnstableSmartCast) {
|
||||
// todo hack -- remove it after removing SmartCastManager
|
||||
reportSmartCast(SmartCastDiagnostic(unstableSmartCast.expressionArgument, unstableSmartCast.targetType))
|
||||
}
|
||||
|
||||
override fun constraintError(diagnostic: KotlinCallDiagnostic) {
|
||||
when (diagnostic.javaClass) {
|
||||
NewConstraintError::class.java -> {
|
||||
val constraintError = diagnostic as NewConstraintError
|
||||
(constraintError.position as? ArgumentConstraintPosition)?.let {
|
||||
val expression = it.argument.psiExpression ?: return
|
||||
trace.report(Errors.TYPE_MISMATCH.on(expression, constraintError.upperType, constraintError.lowerType))
|
||||
}
|
||||
(constraintError.position as? ExplicitTypeParameterConstraintPosition)?.let {
|
||||
val typeArgumentReference = (it.typeArgument as SimpleTypeArgumentImpl).typeReference
|
||||
trace.report(UPPER_BOUND_VIOLATED.on(typeArgumentReference, constraintError.upperType, constraintError.lowerType))
|
||||
}
|
||||
}
|
||||
CapturedTypeFromSubtyping::class.java -> {
|
||||
val capturedError = diagnostic as CapturedTypeFromSubtyping
|
||||
(capturedError.position as? ArgumentConstraintPosition)?.let {
|
||||
val expression = it.argument.psiExpression ?: return
|
||||
trace.report(NEW_INFERENCE_ERROR.on(expression, "Capture type from subtyping ${capturedError.constraintType} for variable ${capturedError.typeVariable}"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright 2010-2016 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
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.diagnostics.*
|
||||
import org.jetbrains.kotlin.psi.Call
|
||||
import org.jetbrains.kotlin.psi.ValueArgument
|
||||
import org.jetbrains.kotlin.resolve.BindingTrace
|
||||
import org.jetbrains.kotlin.resolve.calls.model.*
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.ResolutionCandidateApplicability
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import java.util.*
|
||||
|
||||
// this file is example for future use
|
||||
|
||||
|
||||
object CallDiagnosticToDiagnostic {
|
||||
private val diagnosticMap: MutableMap<Class<out KotlinCallDiagnostic>, KotlinCallDiagnostic.(PsiElement) -> ParametrizedDiagnostic<*>> = HashMap()
|
||||
|
||||
private fun <E: PsiElement, C: KotlinCallDiagnostic> checkPut(klass: Class<C>, factory: C.(PsiElement) -> ParametrizedDiagnostic<E>?) {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
diagnosticMap.put(klass, factory as KotlinCallDiagnostic.(PsiElement) -> ParametrizedDiagnostic<*>)
|
||||
}
|
||||
|
||||
private inline fun <reified E: PsiElement, C: KotlinCallDiagnostic> put(factory0: DiagnosticFactory0<E>, klass: Class<C>) {
|
||||
checkPut<E, C>(klass) {
|
||||
(it as? E)?.let { factory0.on(it) }
|
||||
}
|
||||
}
|
||||
|
||||
private inline fun <reified E: PsiElement, A, C: KotlinCallDiagnostic> put(factory1: DiagnosticFactory1<E, A>, klass: Class<C>, crossinline getA: C.() -> A) {
|
||||
checkPut<E, C>(klass) {
|
||||
(it as? E)?.let { factory1.on(it, getA()) }
|
||||
}
|
||||
}
|
||||
|
||||
private inline fun <reified E: PsiElement, A, B, C: KotlinCallDiagnostic> put(
|
||||
factory2: DiagnosticFactory2<E, A, B>, klass: Class<C>, crossinline getA: C.() -> A, crossinline getB: C.() -> B) {
|
||||
checkPut<E, C>(klass) {
|
||||
(it as? E)?.let { factory2.on(it, getA(), getB()) }
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
// put(Errors.UNSAFE_CALL, UnsafeCallDiagnostic::class.java, UnsafeCallDiagnostic::receiverType)
|
||||
put(Errors.TYPE_MISMATCH, TypeMismatchDiagnostic::class.java, TypeMismatchDiagnostic::expectedType, TypeMismatchDiagnostic::actualType)
|
||||
}
|
||||
|
||||
|
||||
// null means, that E is not subtype of required type for diagnostic factory
|
||||
fun <E : PsiElement> toDiagnostic(element: E, diagnostic: KotlinCallDiagnostic): ParametrizedDiagnostic<E>? {
|
||||
val diagnosticClass = diagnostic.javaClass
|
||||
val factory = diagnosticMap[diagnosticClass] ?: error("Illegal call diagnostic class: ${diagnosticClass.canonicalName}")
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return factory(diagnostic, element) as ParametrizedDiagnostic<E>?
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
abstract class DiagnosticReporterImpl(private val bindingTrace: BindingTrace, private val call: Call) : DiagnosticReporter {
|
||||
|
||||
override fun onCallArgument(callArgument: KotlinCallArgument, diagnostic: KotlinCallDiagnostic) {
|
||||
val d = CallDiagnosticToDiagnostic.toDiagnostic((callArgument as ValueArgument).asElement(), diagnostic)
|
||||
if (d != null) {
|
||||
bindingTrace.report(d)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class TypeMismatchDiagnostic(
|
||||
val callArgument: KotlinCallArgument,
|
||||
val expectedType: KotlinType,
|
||||
val actualType: KotlinType
|
||||
) : KotlinCallDiagnostic(ResolutionCandidateApplicability.INAPPLICABLE) {
|
||||
override fun report(reporter: DiagnosticReporter) = reporter.onCallArgument(callArgument, this)
|
||||
}
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright 2010-2016 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.results
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults.Code
|
||||
|
||||
abstract class AbstractOverloadResolutionResults<D : CallableDescriptor> : OverloadResolutionResults<D> {
|
||||
override fun isSuccess() = resultCode.isSuccess
|
||||
override fun isSingleResult() = resultingCalls.size == 1 && resultCode != OverloadResolutionResults.Code.CANDIDATES_WITH_WRONG_RECEIVER
|
||||
override fun isNothing() = resultCode == OverloadResolutionResults.Code.NAME_NOT_FOUND
|
||||
override fun isAmbiguity() = resultCode == OverloadResolutionResults.Code.AMBIGUITY
|
||||
override fun isIncomplete() = resultCode == OverloadResolutionResults.Code.INCOMPLETE_TYPE_INFERENCE
|
||||
}
|
||||
|
||||
class SingleOverloadResolutionResult<D: CallableDescriptor>(val result: ResolvedCall<D>) : AbstractOverloadResolutionResults<D>() {
|
||||
override fun getAllCandidates(): Collection<ResolvedCall<D>>? = null
|
||||
override fun getResultingCalls(): Collection<ResolvedCall<D>> = listOf(result)
|
||||
override fun getResultingCall() = result
|
||||
|
||||
override fun getResultingDescriptor(): D = result.resultingDescriptor
|
||||
|
||||
override fun getResultCode(): Code = when (result.status) {
|
||||
ResolutionStatus.SUCCESS -> Code.SUCCESS
|
||||
ResolutionStatus.RECEIVER_TYPE_ERROR -> Code.CANDIDATES_WITH_WRONG_RECEIVER
|
||||
ResolutionStatus.INCOMPLETE_TYPE_INFERENCE -> Code.INCOMPLETE_TYPE_INFERENCE
|
||||
else -> Code.SINGLE_CANDIDATE_ARGUMENT_MISMATCH
|
||||
}
|
||||
}
|
||||
|
||||
open class NameNotFoundResolutionResult<D : CallableDescriptor> : AbstractOverloadResolutionResults<D>() {
|
||||
override fun getAllCandidates(): Collection<ResolvedCall<D>>? = null
|
||||
override fun getResultingCalls(): Collection<ResolvedCall<D>> = emptyList()
|
||||
override fun getResultingCall() = error("No candidates")
|
||||
override fun getResultingDescriptor() = error("No candidates")
|
||||
override fun getResultCode() = Code.NAME_NOT_FOUND
|
||||
}
|
||||
|
||||
class ManyCandidates<D : CallableDescriptor>(
|
||||
val candidates: Collection<ResolvedCall<D>>
|
||||
) : AbstractOverloadResolutionResults<D>() {
|
||||
override fun getAllCandidates(): Collection<ResolvedCall<D>>? = null
|
||||
override fun getResultingCalls(): Collection<ResolvedCall<D>> = candidates
|
||||
override fun getResultingCall() = error("Many candidates")
|
||||
override fun getResultingDescriptor() = error("Many candidates")
|
||||
override fun getResultCode() =
|
||||
when(candidates.first().status) {
|
||||
ResolutionStatus.RECEIVER_TYPE_ERROR -> Code.CANDIDATES_WITH_WRONG_RECEIVER
|
||||
ResolutionStatus.SUCCESS -> Code.AMBIGUITY
|
||||
ResolutionStatus.INCOMPLETE_TYPE_INFERENCE -> Code.INCOMPLETE_TYPE_INFERENCE
|
||||
else -> Code.MANY_FAILED_CANDIDATES
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
class AllCandidates<D : CallableDescriptor>(private val allCandidates: Collection<ResolvedCall<D>>): NameNotFoundResolutionResult<D>() {
|
||||
override fun getAllCandidates() = allCandidates
|
||||
}
|
||||
+12
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2015 JetBrains s.r.o.
|
||||
* Copyright 2010-2016 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.
|
||||
@@ -20,9 +20,11 @@ import com.google.common.collect.Lists;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor;
|
||||
import org.jetbrains.kotlin.resolve.calls.KotlinResolutionConfigurationKt;
|
||||
import org.jetbrains.kotlin.resolve.calls.context.ContextDependency;
|
||||
import org.jetbrains.kotlin.resolve.calls.model.MutableResolvedCall;
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.StubOnlyResolvedCall;
|
||||
import org.jetbrains.kotlin.types.KotlinType;
|
||||
|
||||
import java.util.Collection;
|
||||
@@ -52,8 +54,15 @@ public class OverloadResolutionResultsUtil {
|
||||
) {
|
||||
if (results.isSingleResult() && contextDependency == ContextDependency.INDEPENDENT) {
|
||||
ResolvedCall<D> resultingCall = results.getResultingCall();
|
||||
if (!((MutableResolvedCall<D>)resultingCall).hasInferredReturnType()) {
|
||||
return null;
|
||||
if (!KotlinResolutionConfigurationKt.getUSE_NEW_INFERENCE()) {
|
||||
if (!((MutableResolvedCall<D>) resultingCall).hasInferredReturnType()) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (resultingCall instanceof StubOnlyResolvedCall) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
return results.isSingleResult() ? results.getResultingCall() : null;
|
||||
|
||||
+347
@@ -0,0 +1,347 @@
|
||||
/*
|
||||
* Copyright 2010-2016 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.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.psi.Call
|
||||
import org.jetbrains.kotlin.psi.KtPsiUtil
|
||||
import org.jetbrains.kotlin.psi.ValueArgument
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.BindingTrace
|
||||
import org.jetbrains.kotlin.resolve.calls.*
|
||||
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.getEffectiveExpectedType
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.isFakeElement
|
||||
import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker
|
||||
import org.jetbrains.kotlin.resolve.calls.checkers.CallCheckerContext
|
||||
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext
|
||||
import org.jetbrains.kotlin.resolve.calls.context.CallPosition
|
||||
import org.jetbrains.kotlin.resolve.calls.model.*
|
||||
import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
|
||||
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.TypeUtils
|
||||
import org.jetbrains.kotlin.types.UnwrappedType
|
||||
import org.jetbrains.kotlin.types.expressions.DataFlowAnalyzer
|
||||
import java.util.*
|
||||
import kotlin.collections.HashMap
|
||||
|
||||
|
||||
class KotlinToResolvedCallTransformer(
|
||||
private val callCheckers: Iterable<CallChecker>,
|
||||
private val languageFeatureSettings: LanguageVersionSettings,
|
||||
private val dataFlowAnalyzer: DataFlowAnalyzer,
|
||||
private val argumentTypeResolver: ArgumentTypeResolver
|
||||
) {
|
||||
|
||||
fun <D : CallableDescriptor> transformAndReport(
|
||||
baseResolvedCall: ResolvedKotlinCall,
|
||||
context: BasicCallResolutionContext,
|
||||
trace: BindingTrace? // if trace is not null then all information will be reported to this trace
|
||||
): ResolvedCall<D> {
|
||||
if (baseResolvedCall is ResolvedKotlinCall.CompletedResolvedKotlinCall) {
|
||||
baseResolvedCall.allInnerCalls.forEach { transformAndReportCompletedCall<D>(it, context, trace) }
|
||||
return transformAndReportCompletedCall(baseResolvedCall.completedCall, context, trace)
|
||||
}
|
||||
|
||||
val onlyResolvedCall = (baseResolvedCall as ResolvedKotlinCall.OnlyResolvedKotlinCall)
|
||||
trace?.record(BindingContext.ONLY_RESOLVED_CALL, onlyResolvedCall.candidate.kotlinCall.psiKotlinCall.psiCall, onlyResolvedCall)
|
||||
|
||||
return StubOnlyResolvedCall(onlyResolvedCall.candidate.lastCall)
|
||||
}
|
||||
|
||||
private fun <D : CallableDescriptor> transformAndReportCompletedCall(
|
||||
completedCall: CompletedKotlinCall,
|
||||
context: BasicCallResolutionContext,
|
||||
trace: BindingTrace?
|
||||
): ResolvedCall<D> {
|
||||
fun <C> C.runIfTraceNotNull(action: (BasicCallResolutionContext, BindingTrace, C) -> Unit): C {
|
||||
if (trace != null) action(context, trace, this)
|
||||
return this
|
||||
}
|
||||
|
||||
val resolvedCall = when (completedCall) {
|
||||
is CompletedKotlinCall.Simple -> {
|
||||
NewResolvedCallImpl<D>(completedCall).runIfTraceNotNull(this::bindResolvedCall).runIfTraceNotNull(this::runArgumentsChecks)
|
||||
}
|
||||
is CompletedKotlinCall.VariableAsFunction -> {
|
||||
val resolvedCall = NewVariableAsFunctionResolvedCallImpl(
|
||||
completedCall,
|
||||
NewResolvedCallImpl(completedCall.variableCall),
|
||||
NewResolvedCallImpl<FunctionDescriptor>(completedCall.invokeCall).runIfTraceNotNull(this::runArgumentsChecks)
|
||||
).runIfTraceNotNull(this::bindResolvedCall)
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
(resolvedCall as ResolvedCall<D>)
|
||||
}
|
||||
}
|
||||
runCallCheckers(resolvedCall, context)
|
||||
|
||||
return resolvedCall
|
||||
}
|
||||
|
||||
private fun runCallCheckers(resolvedCall: ResolvedCall<*>, context: BasicCallResolutionContext) {
|
||||
val calleeExpression = if (resolvedCall is VariableAsFunctionResolvedCall)
|
||||
resolvedCall.variableCall.call.calleeExpression
|
||||
else
|
||||
resolvedCall.call.calleeExpression
|
||||
val reportOn =
|
||||
if (calleeExpression != null && !calleeExpression.isFakeElement) calleeExpression
|
||||
else resolvedCall.call.callElement
|
||||
|
||||
val callCheckerContext = CallCheckerContext(context, languageFeatureSettings)
|
||||
for (callChecker in callCheckers) {
|
||||
callChecker.check(resolvedCall, reportOn, callCheckerContext)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// todo very beginning code
|
||||
private fun runArgumentsChecks(
|
||||
context: BasicCallResolutionContext,
|
||||
trace: BindingTrace,
|
||||
resolvedCall: NewResolvedCallImpl<*>
|
||||
) {
|
||||
|
||||
for (valueArgument in resolvedCall.call.valueArguments) {
|
||||
val argumentMapping = resolvedCall.getArgumentMapping(valueArgument!!)
|
||||
val (expectedType, callPosition) = when (argumentMapping) {
|
||||
is ArgumentMatch -> Pair(
|
||||
getEffectiveExpectedType(argumentMapping.valueParameter, valueArgument),
|
||||
CallPosition.ValueArgumentPosition(resolvedCall, argumentMapping.valueParameter, valueArgument))
|
||||
else -> Pair(TypeUtils.NO_EXPECTED_TYPE, CallPosition.Unknown)
|
||||
}
|
||||
val newContext =
|
||||
context.replaceDataFlowInfo(resolvedCall.dataFlowInfoForArguments.getInfo(valueArgument))
|
||||
.replaceExpectedType(expectedType)
|
||||
.replaceCallPosition(callPosition)
|
||||
.replaceBindingTrace(trace)
|
||||
|
||||
// todo
|
||||
// if (valueArgument.isExternal()) continue
|
||||
|
||||
val deparenthesized = valueArgument.getArgumentExpression()?.let {
|
||||
KtPsiUtil.getLastElementDeparenthesized(it, context.statementFilter)
|
||||
} ?: continue
|
||||
|
||||
var recordedType = context.trace.getType(deparenthesized)
|
||||
|
||||
// For the cases like 'foo(1)' the type of '1' depends on expected type (it can be Int, Byte, etc.),
|
||||
// so while the expected type is not known, it's IntegerValueType(1), and should be updated when the expected type is known.
|
||||
if (recordedType != null && !recordedType.constructor.isDenotable) {
|
||||
recordedType = argumentTypeResolver.updateResultArgumentTypeIfNotDenotable(newContext, deparenthesized) ?: recordedType
|
||||
}
|
||||
|
||||
// dataFlowAnalyzer.checkType(recordedType, deparenthesized, newContext)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun bindResolvedCall(context: BasicCallResolutionContext, trace: BindingTrace, simpleResolvedCall: NewResolvedCallImpl<*>) {
|
||||
reportCallDiagnostic(context, trace, simpleResolvedCall.completedCall)
|
||||
val tracing = simpleResolvedCall.completedCall.kotlinCall.psiKotlinCall.tracingStrategy
|
||||
|
||||
tracing.bindReference(trace, simpleResolvedCall)
|
||||
tracing.bindResolvedCall(trace, simpleResolvedCall)
|
||||
}
|
||||
|
||||
private fun bindResolvedCall(context: BasicCallResolutionContext, trace: BindingTrace, variableAsFunction: NewVariableAsFunctionResolvedCallImpl) {
|
||||
reportCallDiagnostic(context, trace, variableAsFunction.variableCall.completedCall)
|
||||
reportCallDiagnostic(context, trace, variableAsFunction.functionCall.completedCall)
|
||||
|
||||
val outerTracingStrategy = variableAsFunction.completedCall.kotlinCall.psiKotlinCall.tracingStrategy
|
||||
outerTracingStrategy.bindReference(trace, variableAsFunction.variableCall)
|
||||
outerTracingStrategy.bindResolvedCall(trace, variableAsFunction)
|
||||
variableAsFunction.functionCall.kotlinCall.psiKotlinCall.tracingStrategy.bindReference(trace, variableAsFunction.functionCall)
|
||||
}
|
||||
|
||||
private fun reportCallDiagnostic(
|
||||
context: BasicCallResolutionContext,
|
||||
trace: BindingTrace,
|
||||
completedCall: CompletedKotlinCall.Simple
|
||||
) {
|
||||
var reported: Boolean
|
||||
val reportTrackedTrace = object : BindingTrace by trace {
|
||||
override fun report(diagnostic: Diagnostic) {
|
||||
trace.report(diagnostic)
|
||||
reported = true
|
||||
}
|
||||
}
|
||||
val diagnosticReporter = DiagnosticReporterByTrackingStrategy(context, reportTrackedTrace, completedCall.kotlinCall.psiKotlinCall)
|
||||
|
||||
for (diagnostic in completedCall.resolutionStatus.diagnostics) {
|
||||
reported = false
|
||||
diagnostic.report(diagnosticReporter)
|
||||
if (!reported && REPORT_MISSING_NEW_INFERENCE_DIAGNOSTIC) {
|
||||
if (diagnostic.candidateApplicability.isSuccess) {
|
||||
trace.report(Errors.NEW_INFERENCE_DIAGNOSTIC.on(diagnosticReporter.psiKotlinCall.psiCall.callElement, "Missing diagnostic: $diagnostic"))
|
||||
}
|
||||
else {
|
||||
trace.report(Errors.NEW_INFERENCE_ERROR.on(diagnosticReporter.psiKotlinCall.psiCall.callElement, "Missing diagnostic: $diagnostic"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sealed class NewAbstractResolvedCall<D : CallableDescriptor>(): ResolvedCall<D> {
|
||||
abstract val argumentMappingByOriginal: Map<ValueParameterDescriptor, ResolvedCallArgument>
|
||||
abstract val kotlinCall: KotlinCall
|
||||
|
||||
private var argumentToParameterMap: Map<ValueArgument, ArgumentMatchImpl>? = null
|
||||
private val _valueArguments: Map<ValueParameterDescriptor, ResolvedValueArgument> by lazy(this::createValueArguments)
|
||||
|
||||
override fun getCall(): Call = kotlinCall.psiKotlinCall.psiCall
|
||||
|
||||
override fun getValueArguments(): Map<ValueParameterDescriptor, ResolvedValueArgument> = _valueArguments
|
||||
|
||||
override fun getValueArgumentsByIndex(): List<ResolvedValueArgument>? {
|
||||
val arguments = ArrayList<ResolvedValueArgument?>(candidateDescriptor.valueParameters.size)
|
||||
for (i in 0..candidateDescriptor.valueParameters.size - 1) {
|
||||
arguments.add(null)
|
||||
}
|
||||
|
||||
for ((parameterDescriptor, value) in valueArguments) {
|
||||
val oldValue = arguments.set(parameterDescriptor.index, value)
|
||||
if (oldValue != null) {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
if (arguments.any { it == null }) return null
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return arguments as List<ResolvedValueArgument>
|
||||
}
|
||||
|
||||
override fun getArgumentMapping(valueArgument: ValueArgument): ArgumentMapping {
|
||||
if (argumentToParameterMap == null) {
|
||||
argumentToParameterMap = argumentToParameterMap(resultingDescriptor, valueArguments)
|
||||
}
|
||||
val argumentMatch = argumentToParameterMap!![valueArgument] ?: return ArgumentUnmapped
|
||||
return argumentMatch
|
||||
}
|
||||
|
||||
override fun getDataFlowInfoForArguments() = object : DataFlowInfoForArguments {
|
||||
override fun getResultInfo() = kotlinCall.psiKotlinCall.resultDataFlowInfo
|
||||
override fun getInfo(valueArgument: ValueArgument): DataFlowInfo {
|
||||
val externalPsiCallArgument = kotlinCall.externalArgument?.psiCallArgument
|
||||
if (externalPsiCallArgument?.valueArgument == valueArgument) {
|
||||
return externalPsiCallArgument.dataFlowInfoAfterThisArgument
|
||||
}
|
||||
kotlinCall.argumentsInParenthesis.find { it.psiCallArgument.valueArgument == valueArgument }?.let {
|
||||
return it.psiCallArgument.dataFlowInfoAfterThisArgument
|
||||
}
|
||||
|
||||
// valueArgument is not found
|
||||
// may be we should return initial DataFlowInfo but I think that it isn't important
|
||||
return kotlinCall.psiKotlinCall.resultDataFlowInfo
|
||||
}
|
||||
}
|
||||
|
||||
private fun argumentToParameterMap(
|
||||
resultingDescriptor: CallableDescriptor,
|
||||
valueArguments: Map<ValueParameterDescriptor, ResolvedValueArgument>
|
||||
): Map<ValueArgument, ArgumentMatchImpl> =
|
||||
HashMap<ValueArgument, ArgumentMatchImpl>().also { result ->
|
||||
for (parameter in resultingDescriptor.valueParameters) {
|
||||
val resolvedArgument = valueArguments[parameter] ?: continue
|
||||
for (arguments in resolvedArgument.arguments) {
|
||||
result[arguments] = ArgumentMatchImpl(parameter).apply { recordMatchStatus(ArgumentMatchStatus.SUCCESS) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun createValueArguments(): Map<ValueParameterDescriptor, ResolvedValueArgument> {
|
||||
val result = HashMap<ValueParameterDescriptor, ResolvedValueArgument>()
|
||||
for (parameter in candidateDescriptor.valueParameters) {
|
||||
val resolvedCallArgument = argumentMappingByOriginal[parameter.original] ?: continue
|
||||
val valueArgument = when (resolvedCallArgument) {
|
||||
ResolvedCallArgument.DefaultArgument -> DefaultValueArgument.DEFAULT
|
||||
is ResolvedCallArgument.SimpleArgument -> ExpressionValueArgument(resolvedCallArgument.callArgument.psiCallArgument.valueArgument)
|
||||
is ResolvedCallArgument.VarargArgument -> VarargValueArgument().apply {
|
||||
resolvedCallArgument.arguments.map { it.psiCallArgument.valueArgument }.forEach(this::addArgument)
|
||||
}
|
||||
}
|
||||
result[parameter] = valueArgument
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
class NewResolvedCallImpl<D : CallableDescriptor>(
|
||||
val completedCall: CompletedKotlinCall.Simple
|
||||
): NewAbstractResolvedCall<D>() {
|
||||
override val kotlinCall: KotlinCall get() = completedCall.kotlinCall
|
||||
|
||||
override fun getStatus(): ResolutionStatus = completedCall.resolutionStatus.resultingApplicability.toResolutionStatus()
|
||||
|
||||
override val argumentMappingByOriginal: Map<ValueParameterDescriptor, ResolvedCallArgument>
|
||||
get() = completedCall.argumentMappingByOriginal
|
||||
|
||||
override fun getCandidateDescriptor(): D = completedCall.candidateDescriptor as D
|
||||
override fun getResultingDescriptor(): D = completedCall.resultingDescriptor as D
|
||||
override fun getExtensionReceiver(): ReceiverValue? = completedCall.extensionReceiver?.receiverValue
|
||||
override fun getDispatchReceiver(): ReceiverValue? = completedCall.dispatchReceiver?.receiverValue
|
||||
override fun getExplicitReceiverKind(): ExplicitReceiverKind = completedCall.explicitReceiverKind
|
||||
|
||||
override fun getTypeArguments(): Map<TypeParameterDescriptor, KotlinType> {
|
||||
val typeParameters = candidateDescriptor.typeParameters.takeIf { it.isNotEmpty() } ?: return emptyMap()
|
||||
|
||||
val result = HashMap<TypeParameterDescriptor, UnwrappedType>()
|
||||
for ((parameter, argument) in typeParameters.zip(completedCall.typeArguments)) {
|
||||
result[parameter] = argument
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
override fun getSmartCastDispatchReceiverType(): KotlinType? = null // todo
|
||||
|
||||
fun ResolutionCandidateApplicability.toResolutionStatus(): ResolutionStatus = when (this) {
|
||||
ResolutionCandidateApplicability.RESOLVED, ResolutionCandidateApplicability.RESOLVED_LOW_PRIORITY -> ResolutionStatus.SUCCESS
|
||||
else -> ResolutionStatus.OTHER_ERROR
|
||||
}
|
||||
}
|
||||
|
||||
class NewVariableAsFunctionResolvedCallImpl(
|
||||
val completedCall: CompletedKotlinCall.VariableAsFunction,
|
||||
override val variableCall: NewResolvedCallImpl<VariableDescriptor>,
|
||||
override val functionCall: NewResolvedCallImpl<FunctionDescriptor>
|
||||
): VariableAsFunctionResolvedCall, ResolvedCall<FunctionDescriptor> by functionCall
|
||||
|
||||
class StubOnlyResolvedCall<D : CallableDescriptor>(val candidate: SimpleKotlinResolutionCandidate): NewAbstractResolvedCall<D>() {
|
||||
override fun getStatus() = ResolutionStatus.UNKNOWN_STATUS
|
||||
|
||||
override fun getCandidateDescriptor(): D = candidate.candidateDescriptor as D
|
||||
override fun getResultingDescriptor(): D = candidateDescriptor
|
||||
override fun getExtensionReceiver() = candidate.extensionReceiver?.receiver?.receiverValue
|
||||
override fun getDispatchReceiver() = candidate.dispatchReceiverArgument?.receiver?.receiverValue
|
||||
override fun getExplicitReceiverKind() = candidate.explicitReceiverKind
|
||||
|
||||
override fun getTypeArguments(): Map<TypeParameterDescriptor, KotlinType> = emptyMap()
|
||||
|
||||
override fun getSmartCastDispatchReceiverType(): KotlinType? = null
|
||||
|
||||
override val argumentMappingByOriginal: Map<ValueParameterDescriptor, ResolvedCallArgument>
|
||||
get() = candidate.argumentMappingByOriginal
|
||||
override val kotlinCall: KotlinCall get() = candidate.kotlinCall
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright 2010-2016 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.builtins.createFunctionType
|
||||
import org.jetbrains.kotlin.builtins.getReturnTypeFromFunctionType
|
||||
import org.jetbrains.kotlin.builtins.isFunctionType
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
import org.jetbrains.kotlin.psi.KtPsiUtil
|
||||
import org.jetbrains.kotlin.psi.psiUtil.lastBlockStatementOrThis
|
||||
import org.jetbrains.kotlin.resolve.BindingTrace
|
||||
import org.jetbrains.kotlin.resolve.calls.components.LambdaAnalyzer
|
||||
import org.jetbrains.kotlin.types.TypeApproximator
|
||||
import org.jetbrains.kotlin.types.TypeApproximatorConfiguration
|
||||
import org.jetbrains.kotlin.resolve.calls.context.ContextDependency
|
||||
import org.jetbrains.kotlin.resolve.calls.model.KotlinCall
|
||||
import org.jetbrains.kotlin.resolve.calls.model.KotlinCallArgument
|
||||
import org.jetbrains.kotlin.resolve.calls.model.LambdaKotlinCallArgument
|
||||
import org.jetbrains.kotlin.resolve.calls.util.CallMaker
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import org.jetbrains.kotlin.types.UnwrappedType
|
||||
import org.jetbrains.kotlin.types.expressions.ExpressionTypingServices
|
||||
import org.jetbrains.kotlin.types.expressions.KotlinTypeInfo
|
||||
|
||||
class LambdaAnalyzerImpl(
|
||||
val expressionTypingServices: ExpressionTypingServices,
|
||||
val trace: BindingTrace,
|
||||
val typeApproximator: TypeApproximator
|
||||
): LambdaAnalyzer {
|
||||
|
||||
override fun analyzeAndGetRelatedCalls(
|
||||
topLevelCall: KotlinCall,
|
||||
lambdaArgument: LambdaKotlinCallArgument,
|
||||
receiverType: UnwrappedType?,
|
||||
parameters: List<UnwrappedType>,
|
||||
expectedReturnType: UnwrappedType?
|
||||
): List<KotlinCallArgument> {
|
||||
val psiCallArgument = lambdaArgument.psiCallArgument
|
||||
val outerCallContext = (psiCallArgument as? LambdaKotlinCallArgumentImpl)?.outerCallContext ?:
|
||||
(psiCallArgument as FunctionExpressionImpl).outerCallContext
|
||||
val expression: KtExpression = (psiCallArgument as? LambdaKotlinCallArgumentImpl)?.ktLambdaExpression ?:
|
||||
(psiCallArgument as FunctionExpressionImpl).ktFunction
|
||||
|
||||
val builtIns = outerCallContext.scope.ownerDescriptor.builtIns
|
||||
val expectedType = createFunctionType(builtIns, Annotations.EMPTY, receiverType, parameters, null,
|
||||
expectedReturnType ?: TypeUtils.NO_EXPECTED_TYPE)
|
||||
|
||||
val approximatesExpectedType = typeApproximator.approximateToSubType(expectedType, TypeApproximatorConfiguration.LocalDeclaration) ?: expectedType
|
||||
|
||||
val actualContext = outerCallContext.replaceBindingTrace(trace).
|
||||
replaceContextDependency(ContextDependency.DEPENDENT).replaceExpectedType(approximatesExpectedType)
|
||||
|
||||
|
||||
val functionTypeInfo = expressionTypingServices.getTypeInfo(expression, actualContext)
|
||||
val lastExpressionType = functionTypeInfo.type?.let {
|
||||
if (it.isFunctionType) it.getReturnTypeFromFunctionType() else it
|
||||
}
|
||||
val lastExpressionTypeInfo = KotlinTypeInfo(lastExpressionType, functionTypeInfo.dataFlowInfo)
|
||||
|
||||
val lastExpression: KtExpression?
|
||||
if (psiCallArgument is LambdaKotlinCallArgumentImpl) {
|
||||
lastExpression = psiCallArgument.ktLambdaExpression.bodyExpression?.statements?.lastOrNull()
|
||||
}
|
||||
else {
|
||||
lastExpression = (psiCallArgument as FunctionExpressionImpl).ktFunction.bodyExpression?.lastBlockStatementOrThis()
|
||||
}
|
||||
|
||||
val deparentesized = KtPsiUtil.deparenthesize(lastExpression) ?: return emptyList()
|
||||
|
||||
val simpleArgument = createSimplePSICallArgument(actualContext, CallMaker.makeExternalValueArgument(deparentesized), lastExpressionTypeInfo)
|
||||
|
||||
return listOfNotNull(simpleArgument)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
/*
|
||||
* 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.tower
|
||||
|
||||
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
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValueWithSmartCastInfo
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.TransientReceiver
|
||||
import org.jetbrains.kotlin.types.UnwrappedType
|
||||
import org.jetbrains.kotlin.types.checker.prepareArgumentTypeRegardingCaptureTypes
|
||||
import org.jetbrains.kotlin.types.expressions.KotlinTypeInfo
|
||||
|
||||
class SimpleTypeArgumentImpl(
|
||||
val typeReference: KtTypeReference,
|
||||
override val type: UnwrappedType
|
||||
): SimpleTypeArgument
|
||||
|
||||
// all arguments should be inherited from this class.
|
||||
// But receivers is not, because for them there is no corresponding valueArgument
|
||||
abstract class PSIKotlinCallArgument : KotlinCallArgument {
|
||||
abstract val valueArgument: ValueArgument
|
||||
abstract val dataFlowInfoBeforeThisArgument: DataFlowInfo
|
||||
abstract val dataFlowInfoAfterThisArgument: DataFlowInfo
|
||||
|
||||
override fun toString() = valueArgument.getArgumentExpression()?.text?.replace('\n', ' ') ?: valueArgument.toString()
|
||||
}
|
||||
|
||||
val KotlinCallArgument.psiCallArgument: PSIKotlinCallArgument get() {
|
||||
assert(this is PSIKotlinCallArgument) {
|
||||
"Incorrect KotlinCallArgument: $this. Java class: ${javaClass.canonicalName}"
|
||||
}
|
||||
return this as PSIKotlinCallArgument
|
||||
}
|
||||
|
||||
val KotlinCallArgument.psiExpression: KtExpression? get() {
|
||||
if (this is ReceiverExpressionKotlinCallArgument) {
|
||||
return (receiver.receiverValue as? ExpressionReceiver)?.expression
|
||||
}
|
||||
return psiCallArgument.valueArgument.getArgumentExpression()
|
||||
}
|
||||
|
||||
class ParseErrorKotlinCallArgument(
|
||||
override val valueArgument: ValueArgument,
|
||||
override val dataFlowInfoAfterThisArgument: DataFlowInfo,
|
||||
builtIns: KotlinBuiltIns
|
||||
): ExpressionKotlinCallArgument, PSIKotlinCallArgument() {
|
||||
override val receiver = ReceiverValueWithSmartCastInfo(TransientReceiver(builtIns.nothingType), emptySet(), isStable = true)
|
||||
|
||||
override val isSafeCall: Boolean get() = false
|
||||
|
||||
override val isSpread: Boolean get() = valueArgument.getSpreadElement() != null
|
||||
override val argumentName: Name? get() = valueArgument.getArgumentName()?.asName
|
||||
|
||||
override val dataFlowInfoBeforeThisArgument: DataFlowInfo
|
||||
get() = dataFlowInfoAfterThisArgument
|
||||
}
|
||||
|
||||
class LambdaKotlinCallArgumentImpl(
|
||||
val outerCallContext: BasicCallResolutionContext,
|
||||
override val valueArgument: ValueArgument,
|
||||
override val dataFlowInfoBeforeThisArgument: DataFlowInfo,
|
||||
val ktLambdaExpression: KtLambdaExpression,
|
||||
override val argumentName: Name?,
|
||||
override val parametersTypes: Array<UnwrappedType?>?
|
||||
) : LambdaKotlinCallArgument, PSIKotlinCallArgument() {
|
||||
override val dataFlowInfoAfterThisArgument: DataFlowInfo
|
||||
get() = dataFlowInfoBeforeThisArgument
|
||||
}
|
||||
|
||||
class FunctionExpressionImpl(
|
||||
val outerCallContext: BasicCallResolutionContext,
|
||||
override val valueArgument: ValueArgument,
|
||||
override val dataFlowInfoBeforeThisArgument: DataFlowInfo,
|
||||
val ktFunction: KtNamedFunction,
|
||||
override val argumentName: Name?,
|
||||
override val receiverType: UnwrappedType?,
|
||||
override val parametersTypes: Array<UnwrappedType?>,
|
||||
override val returnType: UnwrappedType?
|
||||
) : FunctionExpression, PSIKotlinCallArgument() {
|
||||
override val dataFlowInfoAfterThisArgument: DataFlowInfo
|
||||
get() = dataFlowInfoBeforeThisArgument
|
||||
}
|
||||
|
||||
class CallableReferenceKotlinCallArgumentImpl(
|
||||
override val valueArgument: ValueArgument,
|
||||
override val dataFlowInfoBeforeThisArgument: DataFlowInfo,
|
||||
override val dataFlowInfoAfterThisArgument: DataFlowInfo,
|
||||
val ktCallableReferenceExpression: KtCallableReferenceExpression,
|
||||
override val argumentName: Name?,
|
||||
override val lhsType: UnwrappedType?,
|
||||
override val constraintStorage: ConstraintStorage
|
||||
) : CallableReferenceKotlinCallArgument, PSIKotlinCallArgument()
|
||||
|
||||
class SubKotlinCallArgumentImpl(
|
||||
override val valueArgument: ValueArgument,
|
||||
override val dataFlowInfoBeforeThisArgument: DataFlowInfo,
|
||||
override val dataFlowInfoAfterThisArgument: DataFlowInfo,
|
||||
override val receiver: ReceiverValueWithSmartCastInfo,
|
||||
override val resolvedCall: ResolvedKotlinCall.OnlyResolvedKotlinCall
|
||||
): PSIKotlinCallArgument(), SubKotlinCallArgument {
|
||||
override val isSpread: Boolean get() = valueArgument.getSpreadElement() != null
|
||||
override val argumentName: Name? get() = valueArgument.getArgumentName()?.asName
|
||||
override val isSafeCall: Boolean get() = false
|
||||
}
|
||||
|
||||
class ExpressionKotlinCallArgumentImpl(
|
||||
override val valueArgument: ValueArgument,
|
||||
override val dataFlowInfoBeforeThisArgument: DataFlowInfo,
|
||||
override val dataFlowInfoAfterThisArgument: DataFlowInfo,
|
||||
override val receiver: ReceiverValueWithSmartCastInfo
|
||||
): PSIKotlinCallArgument(), ExpressionKotlinCallArgument {
|
||||
override val isSpread: Boolean get() = valueArgument.getSpreadElement() != null
|
||||
override val argumentName: Name? get() = valueArgument.getArgumentName()?.asName
|
||||
override val isSafeCall: Boolean get() = false
|
||||
}
|
||||
|
||||
internal fun createSimplePSICallArgument(
|
||||
context: BasicCallResolutionContext,
|
||||
valueArgument: ValueArgument,
|
||||
typeInfo: KotlinTypeInfo
|
||||
): PSIKotlinCallArgument? {
|
||||
val ktExpression = KtPsiUtil.getLastElementDeparenthesized(valueArgument.getArgumentExpression(), context.statementFilter) ?: return null
|
||||
val onlyResolvedCall = ktExpression.getCall(context.trace.bindingContext)?.let {
|
||||
context.trace.bindingContext.get(BindingContext.ONLY_RESOLVED_CALL, it)
|
||||
}
|
||||
val baseType = onlyResolvedCall?.currentReturnType ?: typeInfo.type?.unwrap() ?: return null
|
||||
val preparedType = prepareArgumentTypeRegardingCaptureTypes(baseType) ?: baseType
|
||||
|
||||
val receiverToCast = context.transformToReceiverWithSmartCastInfo(
|
||||
ExpressionReceiver.create(ktExpression, preparedType, context.trace.bindingContext)
|
||||
)
|
||||
|
||||
return if (onlyResolvedCall == null) {
|
||||
ExpressionKotlinCallArgumentImpl(valueArgument, context.dataFlowInfo, typeInfo.dataFlowInfo, receiverToCast)
|
||||
}
|
||||
else {
|
||||
SubKotlinCallArgumentImpl(valueArgument, context.dataFlowInfo, typeInfo.dataFlowInfo, receiverToCast, onlyResolvedCall)
|
||||
}
|
||||
|
||||
}
|
||||
+5
-4
@@ -28,6 +28,7 @@ import org.jetbrains.kotlin.psi.Call
|
||||
import org.jetbrains.kotlin.psi.KtReferenceExpression
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.TemporaryBindingTrace
|
||||
import org.jetbrains.kotlin.resolve.calls.model.KotlinCallKind
|
||||
import org.jetbrains.kotlin.resolve.calls.CallTransformer
|
||||
import org.jetbrains.kotlin.resolve.calls.CandidateResolver
|
||||
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.isBinaryRemOperator
|
||||
@@ -68,7 +69,7 @@ class NewResolutionOldInference(
|
||||
private val languageVersionSettings: LanguageVersionSettings,
|
||||
private val coroutineInferenceSupport: CoroutineInferenceSupport
|
||||
) {
|
||||
sealed class ResolutionKind<D : CallableDescriptor> {
|
||||
sealed class ResolutionKind<D : CallableDescriptor>(val kotlinCallKind: KotlinCallKind = KotlinCallKind.UNSUPPORTED) {
|
||||
abstract internal fun createTowerProcessor(
|
||||
outer: NewResolutionOldInference,
|
||||
name: Name,
|
||||
@@ -78,7 +79,7 @@ class NewResolutionOldInference(
|
||||
context: BasicCallResolutionContext
|
||||
): ScopeTowerProcessor<MyCandidate>
|
||||
|
||||
object Function : ResolutionKind<FunctionDescriptor>() {
|
||||
object Function : ResolutionKind<FunctionDescriptor>(KotlinCallKind.FUNCTION) {
|
||||
override fun createTowerProcessor(
|
||||
outer: NewResolutionOldInference, name: Name, tracing: TracingStrategy,
|
||||
scopeTower: ImplicitScopeTower, explicitReceiver: DetailedReceiver?, context: BasicCallResolutionContext
|
||||
@@ -88,7 +89,7 @@ class NewResolutionOldInference(
|
||||
}
|
||||
}
|
||||
|
||||
object Variable : ResolutionKind<VariableDescriptor>() {
|
||||
object Variable : ResolutionKind<VariableDescriptor>(KotlinCallKind.VARIABLE) {
|
||||
override fun createTowerProcessor(
|
||||
outer: NewResolutionOldInference, name: Name, tracing: TracingStrategy,
|
||||
scopeTower: ImplicitScopeTower, explicitReceiver: DetailedReceiver?, context: BasicCallResolutionContext
|
||||
@@ -456,7 +457,7 @@ class NewResolutionOldInference(
|
||||
|
||||
}
|
||||
|
||||
private fun ResolutionContext<*>.transformToReceiverWithSmartCastInfo(receiver: ReceiverValue): ReceiverValueWithSmartCastInfo {
|
||||
fun ResolutionContext<*>.transformToReceiverWithSmartCastInfo(receiver: ReceiverValue): ReceiverValueWithSmartCastInfo {
|
||||
val dataFlowValue = DataFlowValueFactory.createDataFlowValue(receiver, this)
|
||||
return ReceiverValueWithSmartCastInfo(receiver, dataFlowInfo.getCollectedTypes(dataFlowValue), dataFlowValue.isStable)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,487 @@
|
||||
/*
|
||||
* Copyright 2010-2016 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.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.incremental.components.LookupLocation
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
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.callUtil.createLookupLocation
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.isSafeCall
|
||||
import org.jetbrains.kotlin.resolve.calls.components.ArgumentsToParametersMapper
|
||||
import org.jetbrains.kotlin.resolve.calls.components.CallableReferenceResolver
|
||||
import org.jetbrains.kotlin.resolve.calls.components.LambdaAnalyzer
|
||||
import org.jetbrains.kotlin.resolve.calls.components.TypeArgumentsToParametersMapper
|
||||
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
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
|
||||
import org.jetbrains.kotlin.resolve.calls.tasks.DynamicCallableDescriptors
|
||||
import org.jetbrains.kotlin.resolve.calls.tasks.ResolutionCandidate
|
||||
import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategy
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
||||
import org.jetbrains.kotlin.resolve.lazy.ForceResolveUtil
|
||||
import org.jetbrains.kotlin.resolve.scopes.LexicalScope
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||
import org.jetbrains.kotlin.resolve.scopes.SyntheticScopes
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.*
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.expressions.ControlStructureTypingUtils.ControlStructureDataFlowInfo
|
||||
import org.jetbrains.kotlin.types.expressions.DoubleColonExpressionResolver
|
||||
import org.jetbrains.kotlin.types.expressions.DoubleColonLHS
|
||||
import org.jetbrains.kotlin.types.expressions.ExpressionTypingContext
|
||||
import org.jetbrains.kotlin.types.expressions.ExpressionTypingServices
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
|
||||
import java.util.*
|
||||
|
||||
class PSICallResolver(
|
||||
private val typeResolver: TypeResolver,
|
||||
private val expressionTypingServices: ExpressionTypingServices,
|
||||
private val doubleColonExpressionResolver: DoubleColonExpressionResolver,
|
||||
private val languageVersionSettings: LanguageVersionSettings,
|
||||
private val dynamicCallableDescriptors: DynamicCallableDescriptors,
|
||||
private val syntheticScopes: SyntheticScopes,
|
||||
private val argumentsToParametersMapper: ArgumentsToParametersMapper,
|
||||
val typeArgumentsToParametersMapper: TypeArgumentsToParametersMapper,
|
||||
val resultTypeResolver: ResultTypeResolver,
|
||||
val callableReferenceResolver: CallableReferenceResolver,
|
||||
val constraintInjector: ConstraintInjector,
|
||||
private val kotlinToResolvedCallTransformer: KotlinToResolvedCallTransformer,
|
||||
private val kotlinCallResolver: KotlinCallResolver,
|
||||
private val typeApproximator: TypeApproximator
|
||||
) {
|
||||
private val GIVEN_CANDIDATES_NAME = Name.special("<given candidates>")
|
||||
|
||||
fun <D : CallableDescriptor> runResolutionAndInference(
|
||||
context: BasicCallResolutionContext,
|
||||
name: Name,
|
||||
resolutionKind: NewResolutionOldInference.ResolutionKind<D>,
|
||||
tracingStrategy: TracingStrategy
|
||||
) : OverloadResolutionResults<D> {
|
||||
val kotlinCall = toKotlinCall(context, resolutionKind.kotlinCallKind, context.call, name, tracingStrategy)
|
||||
val scopeTower = ASTScopeTower(context)
|
||||
val lambdaAnalyzer = LambdaAnalyzerImpl(expressionTypingServices, context.trace, typeApproximator)
|
||||
|
||||
val callContext = createCallContext(scopeTower, lambdaAnalyzer)
|
||||
val factoryProviderForInvoke = FactoryProviderForInvoke(context, callContext, kotlinCall)
|
||||
|
||||
val result = kotlinCallResolver.resolveCall(callContext, kotlinCall, calculateExpectedType(context), factoryProviderForInvoke)
|
||||
if (result.isEmpty() && reportAdditionalDiagnosticIfNoCandidates(context, scopeTower, resolutionKind.kotlinCallKind, kotlinCall)) {
|
||||
return OverloadResolutionResultsImpl.nameNotFound()
|
||||
}
|
||||
|
||||
return convertToOverloadResolutionResults(context, result, tracingStrategy)
|
||||
}
|
||||
|
||||
// actually, `D` is at least FunctionDescriptor, but right now because of CallResolver it isn't possible change upper bound for `D`
|
||||
fun <D : CallableDescriptor> runResolutionAndInferenceForGivenCandidates(
|
||||
context: BasicCallResolutionContext,
|
||||
resolutionCandidates: Collection<ResolutionCandidate<D>>,
|
||||
tracingStrategy: TracingStrategy
|
||||
): OverloadResolutionResults<D> {
|
||||
val dispatchReceiver = resolutionCandidates.firstNotNullResult { it.dispatchReceiver }
|
||||
|
||||
val kotlinCall = toKotlinCall(context, KotlinCallKind.FUNCTION, context.call, GIVEN_CANDIDATES_NAME, tracingStrategy, dispatchReceiver)
|
||||
val scopeTower = ASTScopeTower(context)
|
||||
val lambdaAnalyzer = LambdaAnalyzerImpl(expressionTypingServices, context.trace, typeApproximator)
|
||||
val callContext = createCallContext(scopeTower, lambdaAnalyzer)
|
||||
|
||||
val givenCandidates = resolutionCandidates.map {
|
||||
GivenCandidate(it.descriptor as FunctionDescriptor,
|
||||
it.dispatchReceiver?.let { context.transformToReceiverWithSmartCastInfo(it) },
|
||||
it.knownTypeParametersResultingSubstitutor)
|
||||
}
|
||||
|
||||
val result = kotlinCallResolver.resolveGivenCandidates(callContext, kotlinCall, calculateExpectedType(context), givenCandidates)
|
||||
return convertToOverloadResolutionResults(context, result, tracingStrategy)
|
||||
|
||||
}
|
||||
|
||||
private fun calculateExpectedType(context: BasicCallResolutionContext): UnwrappedType? {
|
||||
val expectedType = context.expectedType.unwrap()
|
||||
|
||||
return if (context.contextDependency == ContextDependency.DEPENDENT) {
|
||||
assert(expectedType == TypeUtils.NO_EXPECTED_TYPE)
|
||||
null
|
||||
}
|
||||
else {
|
||||
if (expectedType.isError) TypeUtils.NO_EXPECTED_TYPE else expectedType
|
||||
}
|
||||
}
|
||||
|
||||
private fun createCallContext(scopeTower: ASTScopeTower, lambdaAnalyzer: LambdaAnalyzer) =
|
||||
KotlinCallContext(scopeTower, lambdaAnalyzer, argumentsToParametersMapper, typeArgumentsToParametersMapper, resultTypeResolver,
|
||||
callableReferenceResolver, constraintInjector)
|
||||
|
||||
private fun <D : CallableDescriptor> convertToOverloadResolutionResults(
|
||||
context: BasicCallResolutionContext,
|
||||
result: Collection<ResolvedKotlinCall>,
|
||||
tracingStrategy: TracingStrategy
|
||||
): OverloadResolutionResults<D> {
|
||||
val trace = context.trace
|
||||
when (result.size) {
|
||||
0 -> {
|
||||
tracingStrategy.unresolvedReference(trace)
|
||||
return OverloadResolutionResultsImpl.nameNotFound()
|
||||
}
|
||||
1 -> {
|
||||
val singleCandidate = result.single()
|
||||
val resolvedCall = kotlinToResolvedCallTransformer.transformAndReport<D>(singleCandidate, context, trace)
|
||||
return SingleOverloadResolutionResult(resolvedCall)
|
||||
}
|
||||
else -> {
|
||||
val resolvedCalls = result.map { kotlinToResolvedCallTransformer.transformAndReport<D>(it, context, trace = null) }
|
||||
if (result.areAllCompletedAndFailed()) {
|
||||
tracingStrategy.noneApplicable(trace, resolvedCalls)
|
||||
tracingStrategy.recordAmbiguity(trace, resolvedCalls)
|
||||
}
|
||||
else {
|
||||
tracingStrategy.recordAmbiguity(trace, resolvedCalls)
|
||||
if (resolvedCalls.first().status == ResolutionStatus.INCOMPLETE_TYPE_INFERENCE) {
|
||||
tracingStrategy.cannotCompleteResolve(trace, resolvedCalls)
|
||||
}
|
||||
else {
|
||||
tracingStrategy.ambiguity(trace, resolvedCalls)
|
||||
}
|
||||
}
|
||||
return ManyCandidates(resolvedCalls)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun Collection<ResolvedKotlinCall>.areAllCompletedAndFailed() =
|
||||
all {
|
||||
it is ResolvedKotlinCall.CompletedResolvedKotlinCall &&
|
||||
!it.completedCall.resolutionStatus.resultingApplicability.isSuccess
|
||||
}
|
||||
|
||||
// true if we found something
|
||||
private fun reportAdditionalDiagnosticIfNoCandidates(
|
||||
context: BasicCallResolutionContext,
|
||||
scopeTower: ImplicitScopeTower,
|
||||
kind: KotlinCallKind,
|
||||
kotlinCall: KotlinCall
|
||||
): Boolean {
|
||||
val reference = context.call.calleeExpression as? KtReferenceExpression ?: return false
|
||||
|
||||
val errorCandidates = when (kind) {
|
||||
KotlinCallKind.FUNCTION ->
|
||||
collectErrorCandidatesForFunction(scopeTower, kotlinCall.name, kotlinCall.explicitReceiver?.receiver)
|
||||
KotlinCallKind.VARIABLE ->
|
||||
collectErrorCandidatesForVariable(scopeTower, kotlinCall.name, kotlinCall.explicitReceiver?.receiver)
|
||||
else -> emptyList()
|
||||
}
|
||||
|
||||
for (candidate in errorCandidates) {
|
||||
if (candidate is ErrorCandidate.Classifier) {
|
||||
context.trace.record(BindingContext.REFERENCE_TARGET, reference, candidate.descriptor)
|
||||
context.trace.report(Errors.RESOLUTION_TO_CLASSIFIER.on(reference, candidate.descriptor, candidate.kind, candidate.errorMessage))
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
private inner class ASTScopeTower(
|
||||
val context: BasicCallResolutionContext
|
||||
): ImplicitScopeTower {
|
||||
// todo may be for invoke for case variable + invoke we should create separate dynamicScope(by newCall for invoke)
|
||||
override val dynamicScope: MemberScope = dynamicCallableDescriptors.createDynamicDescriptorScope(context.call, context.scope.ownerDescriptor)
|
||||
// same for location
|
||||
override val location: LookupLocation = context.call.createLookupLocation()
|
||||
|
||||
override val syntheticScopes: SyntheticScopes get() = this@PSICallResolver.syntheticScopes
|
||||
override val isDebuggerContext: Boolean get() = context.isDebuggerContext
|
||||
override val lexicalScope: LexicalScope get() = context.scope
|
||||
private val cache = HashMap<ReceiverParameterDescriptor, ReceiverValueWithSmartCastInfo>()
|
||||
|
||||
override fun getImplicitReceiver(scope: LexicalScope): ReceiverValueWithSmartCastInfo? {
|
||||
val implicitReceiver = scope.implicitReceiver ?: return null
|
||||
|
||||
return cache.getOrPut(implicitReceiver) {
|
||||
context.transformToReceiverWithSmartCastInfo(implicitReceiver.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private inner class FactoryProviderForInvoke(
|
||||
val context: BasicCallResolutionContext,
|
||||
val callContext: KotlinCallContext,
|
||||
val kotlinCall: PSIKotlinCallImpl
|
||||
) : CandidateFactoryProviderForInvoke<KotlinResolutionCandidate> {
|
||||
|
||||
init {
|
||||
assert(kotlinCall.dispatchReceiverForInvokeExtension == null) { kotlinCall }
|
||||
}
|
||||
|
||||
override fun transformCandidate(
|
||||
variable: KotlinResolutionCandidate,
|
||||
invoke: KotlinResolutionCandidate
|
||||
): VariableAsFunctionKotlinResolutionCandidate {
|
||||
assert(variable is SimpleKotlinResolutionCandidate) {
|
||||
"VariableAsFunction variable is not allowed here: $variable"
|
||||
}
|
||||
assert(invoke is SimpleKotlinResolutionCandidate) {
|
||||
"VariableAsFunction candidate is not allowed here: $invoke"
|
||||
}
|
||||
|
||||
return VariableAsFunctionKotlinResolutionCandidate(kotlinCall, variable as SimpleKotlinResolutionCandidate, invoke as SimpleKotlinResolutionCandidate)
|
||||
}
|
||||
|
||||
override fun factoryForVariable(stripExplicitReceiver: Boolean): CandidateFactory<SimpleKotlinResolutionCandidate> {
|
||||
val explicitReceiver = if (stripExplicitReceiver) null else kotlinCall.explicitReceiver
|
||||
val variableCall = PSIKotlinCallForVariable(kotlinCall, explicitReceiver, kotlinCall.name)
|
||||
return SimpleCandidateFactory(callContext, variableCall)
|
||||
}
|
||||
|
||||
override fun factoryForInvoke(variable: KotlinResolutionCandidate, useExplicitReceiver: Boolean):
|
||||
Pair<ReceiverValueWithSmartCastInfo, CandidateFactory<KotlinResolutionCandidate>>? {
|
||||
assert(variable is SimpleKotlinResolutionCandidate) {
|
||||
"VariableAsFunction variable is not allowed here: $variable"
|
||||
}
|
||||
if (isRecursiveVariableResolution(variable as SimpleKotlinResolutionCandidate)) return null
|
||||
|
||||
assert(variable.isSuccessful) {
|
||||
"Variable call should be successful: $variable " +
|
||||
"Descriptor: ${variable.descriptorWithFreshTypes}"
|
||||
}
|
||||
val variableCallArgument = createReceiverCallArgument(variable)
|
||||
|
||||
val explicitReceiver = kotlinCall.explicitReceiver
|
||||
val callForInvoke = if (useExplicitReceiver && explicitReceiver is SimpleKotlinCallArgument) {
|
||||
PSIKotlinCallForInvoke(kotlinCall, explicitReceiver, variableCallArgument)
|
||||
}
|
||||
else {
|
||||
PSIKotlinCallForInvoke(kotlinCall, variableCallArgument, null)
|
||||
}
|
||||
|
||||
return variableCallArgument.receiver to SimpleCandidateFactory(callContext, callForInvoke)
|
||||
}
|
||||
|
||||
// todo: create special check that there is no invoke on variable
|
||||
private fun isRecursiveVariableResolution(variable: SimpleKotlinResolutionCandidate): Boolean {
|
||||
val variableType = variable.candidateDescriptor.returnType
|
||||
return variableType is DeferredType && variableType.isComputing
|
||||
}
|
||||
|
||||
// todo: review
|
||||
private fun createReceiverCallArgument(variable: SimpleKotlinResolutionCandidate): ExpressionKotlinCallArgument =
|
||||
ReceiverExpressionKotlinCallArgument(createReceiverValueWithSmartCastInfo(variable), isVariableReceiverForInvoke = true)
|
||||
|
||||
// todo: decrease hacks count
|
||||
private fun createReceiverValueWithSmartCastInfo(variable: SimpleKotlinResolutionCandidate): ReceiverValueWithSmartCastInfo {
|
||||
val callForVariable = variable.kotlinCall as PSIKotlinCallForVariable
|
||||
val calleeExpression = callForVariable.baseCall.psiCall.calleeExpression as? KtReferenceExpression ?:
|
||||
error("Unexpected call : ${callForVariable.baseCall.psiCall}")
|
||||
|
||||
val temporaryTrace = TemporaryBindingTrace.create(context.trace, "Context for resolve candidate")
|
||||
val type = variable.descriptorWithFreshTypes.returnType!!.unwrap()
|
||||
val variableReceiver = ExpressionReceiver.create(calleeExpression, type, temporaryTrace.bindingContext)
|
||||
|
||||
temporaryTrace.record(BindingContext.REFERENCE_TARGET, calleeExpression, variable.descriptorWithFreshTypes)
|
||||
val dataFlowValue = DataFlowValueFactory.createDataFlowValue(variableReceiver, temporaryTrace.bindingContext, context.scope.ownerDescriptor)
|
||||
return ReceiverValueWithSmartCastInfo(variableReceiver, context.dataFlowInfo.getCollectedTypes(dataFlowValue), dataFlowValue.isStable)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun toKotlinCall(
|
||||
context: BasicCallResolutionContext,
|
||||
kotlinCallKind: KotlinCallKind,
|
||||
oldCall: Call,
|
||||
name: Name,
|
||||
tracingStrategy: TracingStrategy,
|
||||
forcedExplicitReceiver: Receiver? = null
|
||||
): PSIKotlinCallImpl {
|
||||
val resolvedExplicitReceiver = resolveExplicitReceiver(context, forcedExplicitReceiver?: oldCall.explicitReceiver, oldCall.isSafeCall())
|
||||
val resolvedTypeArguments = resolveTypeArguments(context, oldCall.typeArguments)
|
||||
|
||||
// this is hack for special calls. Note that special call has only arguments in parenthesis.
|
||||
val givenDataFlowInfo: ControlStructureDataFlowInfo? = context.dataFlowInfoForArguments as? ControlStructureDataFlowInfo
|
||||
|
||||
val argumentsInParenthesis = if (oldCall.callType != Call.CallType.ARRAY_SET_METHOD && oldCall.functionLiteralArguments.isEmpty()) {
|
||||
oldCall.valueArguments
|
||||
}
|
||||
else {
|
||||
oldCall.valueArguments.dropLast(1)
|
||||
}
|
||||
|
||||
val (resolvedArgumentsInParenthesis, dataFlowInfoAfterArgumentsInParenthesis) = resolveArgumentsInParenthesis(
|
||||
context, context.dataFlowInfoForArguments.resultInfo, argumentsInParenthesis, givenDataFlowInfo)
|
||||
|
||||
val externalLambdaArguments = oldCall.functionLiteralArguments
|
||||
val externalArgument = if (oldCall.callType == Call.CallType.ARRAY_SET_METHOD) {
|
||||
assert(externalLambdaArguments.isEmpty()) {
|
||||
"Unexpected lambda parameters for call $oldCall"
|
||||
}
|
||||
oldCall.valueArguments.last()
|
||||
}
|
||||
else {
|
||||
if (externalLambdaArguments.size > 2) {
|
||||
externalLambdaArguments.drop(1).forEach {
|
||||
context.trace.report(Errors.MANY_LAMBDA_EXPRESSION_ARGUMENTS.on(it.getLambdaExpression()))
|
||||
}
|
||||
}
|
||||
|
||||
externalLambdaArguments.firstOrNull()
|
||||
}
|
||||
|
||||
val astExternalArgument = externalArgument?.let { resolveValueArgument(context, dataFlowInfoAfterArgumentsInParenthesis, it) }
|
||||
val resultDataFlowInfo = astExternalArgument?.dataFlowInfoAfterThisArgument ?: dataFlowInfoAfterArgumentsInParenthesis
|
||||
|
||||
return PSIKotlinCallImpl(kotlinCallKind, oldCall, tracingStrategy, resolvedExplicitReceiver, name, resolvedTypeArguments, resolvedArgumentsInParenthesis,
|
||||
astExternalArgument, context.dataFlowInfo, resultDataFlowInfo)
|
||||
}
|
||||
|
||||
private fun resolveExplicitReceiver(context: BasicCallResolutionContext, oldReceiver: Receiver?, isSafeCall: Boolean): ReceiverKotlinCallArgument? =
|
||||
when(oldReceiver) {
|
||||
null -> null
|
||||
is QualifierReceiver -> QualifierReceiverKotlinCallArgument(oldReceiver) // todo report warning if isSafeCall
|
||||
is ReceiverValue -> {
|
||||
val detailedReceiver = context.transformToReceiverWithSmartCastInfo(oldReceiver)
|
||||
ReceiverExpressionKotlinCallArgument(detailedReceiver, isSafeCall)
|
||||
}
|
||||
else -> error("Incorrect receiver: $oldReceiver")
|
||||
}
|
||||
|
||||
private fun resolveType(context: BasicCallResolutionContext, typeReference: KtTypeReference?): UnwrappedType? {
|
||||
if (typeReference == null) return null
|
||||
|
||||
val type = typeResolver.resolveType(context.scope, typeReference, context.trace, checkBounds = true)
|
||||
ForceResolveUtil.forceResolveAllContents(type)
|
||||
return type.unwrap()
|
||||
}
|
||||
|
||||
private fun resolveTypeArguments(context: BasicCallResolutionContext, typeArguments: List<KtTypeProjection>): List<TypeArgument> =
|
||||
typeArguments.map { projection ->
|
||||
if (projection.projectionKind != KtProjectionKind.NONE) {
|
||||
context.trace.report(Errors.PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT.on(projection))
|
||||
}
|
||||
ModifierCheckerCore.check(projection, context.trace, null, languageVersionSettings)
|
||||
|
||||
resolveType(context, projection.typeReference)?.let { SimpleTypeArgumentImpl(projection.typeReference!!, it) } ?: TypeArgumentPlaceholder
|
||||
}
|
||||
|
||||
private fun resolveArgumentsInParenthesis(
|
||||
context: BasicCallResolutionContext,
|
||||
dataFlowInfoForArguments: DataFlowInfo,
|
||||
arguments: List<ValueArgument>,
|
||||
givenDataFlowInfo: ControlStructureDataFlowInfo?
|
||||
): Pair<List<KotlinCallArgument>, DataFlowInfo> {
|
||||
if (givenDataFlowInfo != null) {
|
||||
val resolvedArguments = arguments.map {
|
||||
resolveValueArgument(context, givenDataFlowInfo.getInfo(it), it)
|
||||
}
|
||||
return resolvedArguments to givenDataFlowInfo.resultInfo
|
||||
}
|
||||
|
||||
var dataFlowInfo = dataFlowInfoForArguments
|
||||
|
||||
val resolvedArguments = arguments.map {
|
||||
val argument = resolveValueArgument(context, dataFlowInfo, it)
|
||||
dataFlowInfo = argument.dataFlowInfoAfterThisArgument
|
||||
argument
|
||||
}
|
||||
|
||||
return resolvedArguments to dataFlowInfo
|
||||
}
|
||||
|
||||
private fun resolveValueArgument(
|
||||
outerCallContext: BasicCallResolutionContext,
|
||||
startDataFlowInfo: DataFlowInfo,
|
||||
valueArgument: ValueArgument
|
||||
): PSIKotlinCallArgument {
|
||||
val parseErrorArgument = ParseErrorKotlinCallArgument(valueArgument, startDataFlowInfo, outerCallContext.scope.ownerDescriptor.builtIns)
|
||||
val ktExpression = KtPsiUtil.deparenthesize(valueArgument.getArgumentExpression()) ?:
|
||||
return parseErrorArgument
|
||||
|
||||
val argumentName = valueArgument.getArgumentName()?.asName
|
||||
|
||||
val lambdaArgument: PSIKotlinCallArgument? = when (ktExpression) {
|
||||
is KtLambdaExpression ->
|
||||
LambdaKotlinCallArgumentImpl(outerCallContext, valueArgument, startDataFlowInfo, ktExpression, argumentName,
|
||||
resolveParametersTypes(outerCallContext, ktExpression.functionLiteral))
|
||||
is KtNamedFunction -> {
|
||||
val receiverType = resolveType(outerCallContext, ktExpression.receiverTypeReference)
|
||||
val parametersTypes = resolveParametersTypes(outerCallContext, ktExpression) ?: emptyArray()
|
||||
val returnType = resolveType(outerCallContext, ktExpression.typeReference)
|
||||
FunctionExpressionImpl(outerCallContext, valueArgument, startDataFlowInfo, ktExpression, argumentName, receiverType, parametersTypes, returnType)
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
if (lambdaArgument != null) {
|
||||
checkNoSpread(outerCallContext, valueArgument)
|
||||
return lambdaArgument
|
||||
}
|
||||
|
||||
val context = outerCallContext.replaceContextDependency(ContextDependency.DEPENDENT)
|
||||
.replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE).replaceDataFlowInfo(startDataFlowInfo)
|
||||
|
||||
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 newDataFlowInfo = (lhsResult as? DoubleColonLHS.Expression)?.dataFlowInfo ?: startDataFlowInfo
|
||||
|
||||
// todo ChosenCallableReferenceDescriptor
|
||||
val argument = CallableReferenceKotlinCallArgumentImpl(valueArgument, startDataFlowInfo, newDataFlowInfo,
|
||||
ktExpression, argumentName, (lhsResult as? DoubleColonLHS.Type)?.type?.unwrap(),
|
||||
ConstraintStorage.Empty) // todo
|
||||
|
||||
return argument
|
||||
}
|
||||
|
||||
// valueArgument.getArgumentExpression()!! instead of ktExpression is hack -- type info should be stored also for parenthesized expression
|
||||
val typeInfo = expressionTypingServices.getTypeInfo(valueArgument.getArgumentExpression()!!, context)
|
||||
return createSimplePSICallArgument(context, valueArgument, typeInfo) ?: parseErrorArgument
|
||||
}
|
||||
|
||||
private fun checkNoSpread(context: BasicCallResolutionContext, valueArgument: ValueArgument) {
|
||||
valueArgument.getSpreadElement()?.let {
|
||||
context.trace.report(Errors.SPREAD_OF_LAMBDA_OR_CALLABLE_REFERENCE.on(it))
|
||||
}
|
||||
}
|
||||
|
||||
private fun resolveParametersTypes(context: BasicCallResolutionContext, ktFunction: KtFunction): Array<UnwrappedType?>? {
|
||||
val parameterList = ktFunction.valueParameterList ?: return null
|
||||
|
||||
return Array(parameterList.parameters.size) {
|
||||
parameterList.parameters[it]?.typeReference?.let { resolveType(context, it) }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright 2010-2016 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.psi.Call
|
||||
import org.jetbrains.kotlin.resolve.calls.model.KotlinCallKind
|
||||
import org.jetbrains.kotlin.resolve.calls.CallTransformer
|
||||
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.isConventionCall
|
||||
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.isInfixCall
|
||||
import org.jetbrains.kotlin.resolve.calls.model.*
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
|
||||
import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategy
|
||||
import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategyForInvoke
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
|
||||
val KotlinCall.psiKotlinCall: PSIKotlinCall get() {
|
||||
assert(this is PSIKotlinCall) {
|
||||
"Incorrect ASTCAll: $this. Java class: ${javaClass.canonicalName}"
|
||||
}
|
||||
return this as PSIKotlinCall
|
||||
}
|
||||
|
||||
abstract class PSIKotlinCall : KotlinCall {
|
||||
abstract val psiCall: Call
|
||||
abstract val startingDataFlowInfo: DataFlowInfo
|
||||
abstract val resultDataFlowInfo: DataFlowInfo
|
||||
abstract val tracingStrategy: TracingStrategy
|
||||
|
||||
override fun toString() = "$psiCall"
|
||||
}
|
||||
|
||||
class PSIKotlinCallImpl(
|
||||
override val callKind: KotlinCallKind,
|
||||
override val psiCall: Call,
|
||||
override val tracingStrategy: TracingStrategy,
|
||||
override val explicitReceiver: ReceiverKotlinCallArgument?,
|
||||
override val name: Name,
|
||||
override val typeArguments: List<TypeArgument>,
|
||||
override val argumentsInParenthesis: List<KotlinCallArgument>,
|
||||
override val externalArgument: KotlinCallArgument?,
|
||||
override val startingDataFlowInfo: DataFlowInfo,
|
||||
override val resultDataFlowInfo: DataFlowInfo
|
||||
) : PSIKotlinCall() {
|
||||
override val isInfixCall: Boolean get() = isInfixCall(psiCall)
|
||||
override val isOperatorCall: Boolean get() = isConventionCall(psiCall)
|
||||
}
|
||||
|
||||
class PSIKotlinCallForVariable(
|
||||
val baseCall: PSIKotlinCallImpl,
|
||||
override val explicitReceiver: ReceiverKotlinCallArgument?,
|
||||
override val name: Name
|
||||
) : PSIKotlinCall() {
|
||||
override val callKind: KotlinCallKind get() = KotlinCallKind.VARIABLE
|
||||
override val typeArguments: List<TypeArgument> get() = emptyList()
|
||||
override val argumentsInParenthesis: List<KotlinCallArgument> get() = emptyList()
|
||||
override val externalArgument: KotlinCallArgument? get() = null
|
||||
|
||||
override val startingDataFlowInfo: DataFlowInfo get() = baseCall.startingDataFlowInfo
|
||||
override val resultDataFlowInfo: DataFlowInfo get() = baseCall.startingDataFlowInfo
|
||||
|
||||
override val tracingStrategy: TracingStrategy get() = baseCall.tracingStrategy
|
||||
override val psiCall: Call = CallTransformer.stripCallArguments(baseCall.psiCall).let {
|
||||
if (explicitReceiver == null) CallTransformer.stripReceiver(it) else it
|
||||
}
|
||||
|
||||
override val isInfixCall: Boolean get() = false
|
||||
override val isOperatorCall: Boolean get() = false
|
||||
}
|
||||
|
||||
class PSIKotlinCallForInvoke(
|
||||
val baseCall: PSIKotlinCallImpl,
|
||||
override val explicitReceiver: SimpleKotlinCallArgument,
|
||||
override val dispatchReceiverForInvokeExtension: SimpleKotlinCallArgument?
|
||||
) : PSIKotlinCall() {
|
||||
override val callKind: KotlinCallKind get() = KotlinCallKind.FUNCTION
|
||||
override val name: Name get() = OperatorNameConventions.INVOKE
|
||||
override val typeArguments: List<TypeArgument> get() = baseCall.typeArguments
|
||||
override val argumentsInParenthesis: List<KotlinCallArgument> get() = baseCall.argumentsInParenthesis
|
||||
override val externalArgument: KotlinCallArgument? get() = baseCall.externalArgument
|
||||
|
||||
override val startingDataFlowInfo: DataFlowInfo get() = baseCall.startingDataFlowInfo
|
||||
override val resultDataFlowInfo: DataFlowInfo get() = baseCall.resultDataFlowInfo
|
||||
override val psiCall: Call
|
||||
override val tracingStrategy: TracingStrategy
|
||||
|
||||
override val isInfixCall: Boolean get() = false
|
||||
override val isOperatorCall: Boolean get() = true
|
||||
|
||||
init {
|
||||
val variableReceiver = dispatchReceiverForInvokeExtension ?: explicitReceiver
|
||||
val explicitExtensionReceiver = if (dispatchReceiverForInvokeExtension == null) null else explicitReceiver
|
||||
val calleeExpression = baseCall.psiCall.calleeExpression!!
|
||||
|
||||
psiCall = CallTransformer.CallForImplicitInvoke(
|
||||
explicitExtensionReceiver?.receiver?.receiverValue,
|
||||
variableReceiver.receiver.receiverValue as ExpressionReceiver, baseCall.psiCall, true)
|
||||
tracingStrategy = TracingStrategyForInvoke(calleeExpression, psiCall, variableReceiver.receiver.receiverValue.type)
|
||||
}
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 2010-2016 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.resolve.DescriptorToSourceUtils
|
||||
import org.jetbrains.kotlin.resolve.calls.components.CommonSupertypeCalculator
|
||||
import org.jetbrains.kotlin.resolve.calls.components.IsDescriptorFromSourcePredicate
|
||||
import org.jetbrains.kotlin.types.CommonSupertypes
|
||||
import org.jetbrains.kotlin.types.UnwrappedType
|
||||
|
||||
object CommonSupertypeCalculatorImpl : CommonSupertypeCalculator {
|
||||
override fun invoke(p1: Collection<UnwrappedType>): UnwrappedType = CommonSupertypes.commonSupertype(p1).unwrap()
|
||||
}
|
||||
|
||||
object IsDescriptorFromSourcePredicateImpl: IsDescriptorFromSourcePredicate {
|
||||
override fun invoke(p1: CallableDescriptor) = DescriptorToSourceUtils.descriptorToDeclaration(p1) != null
|
||||
}
|
||||
+1
-1
@@ -330,7 +330,7 @@ class DoubleColonExpressionResolver(
|
||||
return Pair(false, null)
|
||||
}
|
||||
|
||||
private fun resolveDoubleColonLHS(doubleColonExpression: KtDoubleColonExpression, c: ExpressionTypingContext): DoubleColonLHS? {
|
||||
internal fun resolveDoubleColonLHS(doubleColonExpression: KtDoubleColonExpression, c: ExpressionTypingContext): DoubleColonLHS? {
|
||||
val resultForExpr = tryResolveLHS(doubleColonExpression, c, this::shouldTryResolveLHSAsExpression, this::resolveExpressionOnLHS)
|
||||
if (resultForExpr != null) {
|
||||
val lhs = resultForExpr.lhs
|
||||
|
||||
Reference in New Issue
Block a user