[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> 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, Pair<LanguageFeature, LanguageVersionSettings>> UNSUPPORTED_FEATURE = DiagnosticFactory1.create(ERROR);
|
||||||
DiagnosticFactory1<PsiElement, Throwable> EXCEPTION_FROM_ANALYZER = 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<KtExpression> VARARG_OUTSIDE_PARENTHESES = DiagnosticFactory0.create(ERROR);
|
||||||
DiagnosticFactory0<LeafPsiElement> NON_VARARG_SPREAD = DiagnosticFactory0.create(ERROR);
|
DiagnosticFactory0<LeafPsiElement> NON_VARARG_SPREAD = DiagnosticFactory0.create(ERROR);
|
||||||
DiagnosticFactory0<LeafPsiElement> SPREAD_OF_NULLABLE = 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);
|
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(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(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_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(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");
|
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(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(AMBIGUOUS_LABEL, "Ambiguous label");
|
||||||
MAP.put(UNSUPPORTED, "Unsupported [{0}]", STRING);
|
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(UNSUPPORTED_FEATURE, "{0}", new LanguageFeatureMessageRenderer(LanguageFeatureMessageRenderer.Type.UNSUPPORTED));
|
||||||
MAP.put(EXPERIMENTAL_FEATURE_WARNING, "{0}", new LanguageFeatureMessageRenderer(LanguageFeatureMessageRenderer.Type.WARNING));
|
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.incremental.components.LookupTracker
|
||||||
import org.jetbrains.kotlin.psi.KtFile
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
import org.jetbrains.kotlin.resolve.*
|
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.*
|
||||||
import org.jetbrains.kotlin.resolve.lazy.declarations.DeclarationProviderFactory
|
import org.jetbrains.kotlin.resolve.lazy.declarations.DeclarationProviderFactory
|
||||||
import org.jetbrains.kotlin.resolve.lazy.declarations.FileBasedDeclarationProviderFactory
|
import org.jetbrains.kotlin.resolve.lazy.declarations.FileBasedDeclarationProviderFactory
|
||||||
@@ -60,6 +62,8 @@ fun StorageComponentContainer.configureModule(
|
|||||||
|
|
||||||
private fun StorageComponentContainer.configurePlatformIndependentComponents() {
|
private fun StorageComponentContainer.configurePlatformIndependentComponents() {
|
||||||
useImpl<SupertypeLoopCheckerImpl>()
|
useImpl<SupertypeLoopCheckerImpl>()
|
||||||
|
useInstance(CommonSupertypeCalculatorImpl)
|
||||||
|
useInstance(IsDescriptorFromSourcePredicateImpl)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun StorageComponentContainer.configureModule(
|
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.FqName;
|
||||||
import org.jetbrains.kotlin.name.FqNameUnsafe;
|
import org.jetbrains.kotlin.name.FqNameUnsafe;
|
||||||
import org.jetbrains.kotlin.psi.*;
|
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.inference.ConstraintSystemCompleter;
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
|
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
|
||||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo;
|
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo;
|
||||||
@@ -120,6 +121,7 @@ public interface BindingContext {
|
|||||||
new BasicWritableSlice<>(DO_NOTHING);
|
new BasicWritableSlice<>(DO_NOTHING);
|
||||||
|
|
||||||
WritableSlice<Call, ResolvedCall<?>> RESOLVED_CALL = 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<Call, TailRecursionKind> TAIL_RECURSION_CALL = Slices.createSimpleSlice();
|
||||||
WritableSlice<KtElement, ConstraintSystemCompleter> CONSTRAINT_SYSTEM_COMPLETER = new BasicWritableSlice<>(DO_NOTHING);
|
WritableSlice<KtElement, ConstraintSystemCompleter> CONSTRAINT_SYSTEM_COMPLETER = new BasicWritableSlice<>(DO_NOTHING);
|
||||||
WritableSlice<KtElement, Call> CALL = new BasicWritableSlice<>(DO_NOTHING);
|
WritableSlice<KtElement, Call> CALL = new BasicWritableSlice<>(DO_NOTHING);
|
||||||
|
|||||||
@@ -281,7 +281,7 @@ class CallExpressionResolver(
|
|||||||
}
|
}
|
||||||
else when (resolutionResult.resultCode) {
|
else when (resolutionResult.resultCode) {
|
||||||
NAME_NOT_FOUND, CANDIDATES_WITH_WRONG_RECEIVER -> false
|
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.callUtil.CallUtilKt;
|
||||||
import org.jetbrains.kotlin.resolve.calls.context.*;
|
import org.jetbrains.kotlin.resolve.calls.context.*;
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.CoroutineInferenceUtilKt;
|
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.model.MutableDataFlowInfoForArguments;
|
||||||
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults;
|
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults;
|
||||||
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResultsImpl;
|
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResultsImpl;
|
||||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo;
|
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo;
|
||||||
import org.jetbrains.kotlin.resolve.calls.tasks.*;
|
import org.jetbrains.kotlin.resolve.calls.tasks.*;
|
||||||
import org.jetbrains.kotlin.resolve.calls.tower.NewResolutionOldInference;
|
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.calls.util.CallMaker;
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt;
|
import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt;
|
||||||
import org.jetbrains.kotlin.resolve.lazy.ForceResolveUtil;
|
import org.jetbrains.kotlin.resolve.lazy.ForceResolveUtil;
|
||||||
@@ -70,8 +72,9 @@ public class CallResolver {
|
|||||||
private ArgumentTypeResolver argumentTypeResolver;
|
private ArgumentTypeResolver argumentTypeResolver;
|
||||||
private GenericCandidateResolver genericCandidateResolver;
|
private GenericCandidateResolver genericCandidateResolver;
|
||||||
private CallCompleter callCompleter;
|
private CallCompleter callCompleter;
|
||||||
private NewResolutionOldInference newCallResolver;
|
|
||||||
private SyntheticScopes syntheticScopes;
|
private SyntheticScopes syntheticScopes;
|
||||||
|
private NewResolutionOldInference newResolutionOldInference;
|
||||||
|
private PSICallResolver PSICallResolver;
|
||||||
private final KotlinBuiltIns builtIns;
|
private final KotlinBuiltIns builtIns;
|
||||||
private final LanguageVersionSettings languageVersionSettings;
|
private final LanguageVersionSettings languageVersionSettings;
|
||||||
|
|
||||||
@@ -117,8 +120,14 @@ public class CallResolver {
|
|||||||
|
|
||||||
// component dependency cycle
|
// component dependency cycle
|
||||||
@Inject
|
@Inject
|
||||||
public void setCallCompleter(@NotNull NewResolutionOldInference newCallResolver) {
|
public void setResolutionOldInference(@NotNull NewResolutionOldInference newResolutionOldInference) {
|
||||||
this.newCallResolver = newCallResolver;
|
this.newResolutionOldInference = newResolutionOldInference;
|
||||||
|
}
|
||||||
|
|
||||||
|
// component dependency cycle
|
||||||
|
@Inject
|
||||||
|
public void setPSICallResolver(@NotNull PSICallResolver PSICallResolver) {
|
||||||
|
this.PSICallResolver = PSICallResolver;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Inject
|
@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 BasicCallResolutionContext context,
|
||||||
@NotNull ResolutionTask<D> resolutionTask,
|
@NotNull ResolutionTask<D> resolutionTask,
|
||||||
@NotNull TracingStrategy tracing
|
@NotNull TracingStrategy tracing
|
||||||
@@ -528,6 +537,16 @@ public class CallResolver {
|
|||||||
Call call = context.call;
|
Call call = context.call;
|
||||||
tracing.bindCall(context.trace, 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);
|
TemporaryBindingTrace traceToResolveCall = TemporaryBindingTrace.create(context.trace, "trace to resolve call", call);
|
||||||
BasicCallResolutionContext newContext = context.replaceBindingTrace(traceToResolveCall);
|
BasicCallResolutionContext newContext = context.replaceBindingTrace(traceToResolveCall);
|
||||||
|
|
||||||
@@ -624,11 +643,11 @@ public class CallResolver {
|
|||||||
|
|
||||||
if (!(resolutionTask.resolutionKind instanceof NewResolutionOldInference.ResolutionKind.GivenCandidates)) {
|
if (!(resolutionTask.resolutionKind instanceof NewResolutionOldInference.ResolutionKind.GivenCandidates)) {
|
||||||
assert resolutionTask.name != null;
|
assert resolutionTask.name != null;
|
||||||
return newCallResolver.runResolution(context, resolutionTask.name, resolutionTask.resolutionKind, tracing);
|
return newResolutionOldInference.runResolution(context, resolutionTask.name, resolutionTask.resolutionKind, tracing);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
assert resolutionTask.givenCandidates != null;
|
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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor;
|
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.context.ContextDependency;
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.MutableResolvedCall;
|
import org.jetbrains.kotlin.resolve.calls.model.MutableResolvedCall;
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
|
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.tower.StubOnlyResolvedCall;
|
||||||
import org.jetbrains.kotlin.types.KotlinType;
|
import org.jetbrains.kotlin.types.KotlinType;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@@ -52,8 +54,15 @@ public class OverloadResolutionResultsUtil {
|
|||||||
) {
|
) {
|
||||||
if (results.isSingleResult() && contextDependency == ContextDependency.INDEPENDENT) {
|
if (results.isSingleResult() && contextDependency == ContextDependency.INDEPENDENT) {
|
||||||
ResolvedCall<D> resultingCall = results.getResultingCall();
|
ResolvedCall<D> resultingCall = results.getResultingCall();
|
||||||
if (!((MutableResolvedCall<D>)resultingCall).hasInferredReturnType()) {
|
if (!KotlinResolutionConfigurationKt.getUSE_NEW_INFERENCE()) {
|
||||||
return null;
|
if (!((MutableResolvedCall<D>) resultingCall).hasInferredReturnType()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (resultingCall instanceof StubOnlyResolvedCall) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return results.isSingleResult() ? results.getResultingCall() : 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.psi.KtReferenceExpression
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
import org.jetbrains.kotlin.resolve.TemporaryBindingTrace
|
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.CallTransformer
|
||||||
import org.jetbrains.kotlin.resolve.calls.CandidateResolver
|
import org.jetbrains.kotlin.resolve.calls.CandidateResolver
|
||||||
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.isBinaryRemOperator
|
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.isBinaryRemOperator
|
||||||
@@ -68,7 +69,7 @@ class NewResolutionOldInference(
|
|||||||
private val languageVersionSettings: LanguageVersionSettings,
|
private val languageVersionSettings: LanguageVersionSettings,
|
||||||
private val coroutineInferenceSupport: CoroutineInferenceSupport
|
private val coroutineInferenceSupport: CoroutineInferenceSupport
|
||||||
) {
|
) {
|
||||||
sealed class ResolutionKind<D : CallableDescriptor> {
|
sealed class ResolutionKind<D : CallableDescriptor>(val kotlinCallKind: KotlinCallKind = KotlinCallKind.UNSUPPORTED) {
|
||||||
abstract internal fun createTowerProcessor(
|
abstract internal fun createTowerProcessor(
|
||||||
outer: NewResolutionOldInference,
|
outer: NewResolutionOldInference,
|
||||||
name: Name,
|
name: Name,
|
||||||
@@ -78,7 +79,7 @@ class NewResolutionOldInference(
|
|||||||
context: BasicCallResolutionContext
|
context: BasicCallResolutionContext
|
||||||
): ScopeTowerProcessor<MyCandidate>
|
): ScopeTowerProcessor<MyCandidate>
|
||||||
|
|
||||||
object Function : ResolutionKind<FunctionDescriptor>() {
|
object Function : ResolutionKind<FunctionDescriptor>(KotlinCallKind.FUNCTION) {
|
||||||
override fun createTowerProcessor(
|
override fun createTowerProcessor(
|
||||||
outer: NewResolutionOldInference, name: Name, tracing: TracingStrategy,
|
outer: NewResolutionOldInference, name: Name, tracing: TracingStrategy,
|
||||||
scopeTower: ImplicitScopeTower, explicitReceiver: DetailedReceiver?, context: BasicCallResolutionContext
|
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(
|
override fun createTowerProcessor(
|
||||||
outer: NewResolutionOldInference, name: Name, tracing: TracingStrategy,
|
outer: NewResolutionOldInference, name: Name, tracing: TracingStrategy,
|
||||||
scopeTower: ImplicitScopeTower, explicitReceiver: DetailedReceiver?, context: BasicCallResolutionContext
|
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)
|
val dataFlowValue = DataFlowValueFactory.createDataFlowValue(receiver, this)
|
||||||
return ReceiverValueWithSmartCastInfo(receiver, dataFlowInfo.getCollectedTypes(dataFlowValue), dataFlowValue.isStable)
|
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)
|
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)
|
val resultForExpr = tryResolveLHS(doubleColonExpression, c, this::shouldTryResolveLHSAsExpression, this::resolveExpressionOnLHS)
|
||||||
if (resultForExpr != null) {
|
if (resultForExpr != null) {
|
||||||
val lhs = resultForExpr.lhs
|
val lhs = resultForExpr.lhs
|
||||||
|
|||||||
@@ -0,0 +1,109 @@
|
|||||||
|
/*
|
||||||
|
* 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.resolve.calls.components.KotlinCallCompleter
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.components.NewOverloadingConflictResolver
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.context.CheckArgumentTypesMode
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.model.*
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.tower.*
|
||||||
|
import org.jetbrains.kotlin.types.UnwrappedType
|
||||||
|
import java.lang.UnsupportedOperationException
|
||||||
|
|
||||||
|
|
||||||
|
class KotlinCallResolver(
|
||||||
|
private val towerResolver: TowerResolver,
|
||||||
|
private val kotlinCallCompleter: KotlinCallCompleter,
|
||||||
|
private val overloadingConflictResolver: NewOverloadingConflictResolver
|
||||||
|
) {
|
||||||
|
|
||||||
|
fun resolveCall(
|
||||||
|
callContext: KotlinCallContext,
|
||||||
|
kotlinCall: KotlinCall,
|
||||||
|
expectedType: UnwrappedType?,
|
||||||
|
factoryProviderForInvoke: CandidateFactoryProviderForInvoke<KotlinResolutionCandidate>
|
||||||
|
): Collection<ResolvedKotlinCall> {
|
||||||
|
val scopeTower = callContext.scopeTower
|
||||||
|
|
||||||
|
kotlinCall.checkCallInvariants()
|
||||||
|
|
||||||
|
val candidateFactory = SimpleCandidateFactory(callContext, kotlinCall)
|
||||||
|
val processor = when(kotlinCall.callKind) {
|
||||||
|
KotlinCallKind.VARIABLE -> {
|
||||||
|
createVariableAndObjectProcessor(scopeTower, kotlinCall.name, candidateFactory, kotlinCall.explicitReceiver?.receiver)
|
||||||
|
}
|
||||||
|
KotlinCallKind.FUNCTION -> {
|
||||||
|
createFunctionProcessor(scopeTower, kotlinCall.name, candidateFactory, factoryProviderForInvoke, kotlinCall.explicitReceiver?.receiver)
|
||||||
|
}
|
||||||
|
KotlinCallKind.UNSUPPORTED -> throw UnsupportedOperationException()
|
||||||
|
}
|
||||||
|
|
||||||
|
val candidates = towerResolver.runResolve(scopeTower, processor, useOrder = kotlinCall.callKind != KotlinCallKind.UNSUPPORTED)
|
||||||
|
|
||||||
|
return choseMostSpecific(callContext, expectedType, candidates)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun resolveGivenCandidates(
|
||||||
|
callContext: KotlinCallContext,
|
||||||
|
kotlinCall: KotlinCall,
|
||||||
|
expectedType: UnwrappedType?,
|
||||||
|
givenCandidates: Collection<GivenCandidate>
|
||||||
|
): Collection<ResolvedKotlinCall> {
|
||||||
|
kotlinCall.checkCallInvariants()
|
||||||
|
|
||||||
|
val resolutionCandidates = givenCandidates.map {
|
||||||
|
SimpleKotlinResolutionCandidate(callContext,
|
||||||
|
kotlinCall,
|
||||||
|
if (it.dispatchReceiver == null) ExplicitReceiverKind.NO_EXPLICIT_RECEIVER else ExplicitReceiverKind.DISPATCH_RECEIVER,
|
||||||
|
it.dispatchReceiver?.let { ReceiverExpressionKotlinCallArgument(it) },
|
||||||
|
null,
|
||||||
|
it.descriptor,
|
||||||
|
listOf()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
val candidates = towerResolver.runWithEmptyTowerData(KnownResultProcessor(resolutionCandidates),
|
||||||
|
TowerResolver.SuccessfulResultCollector { it.status },
|
||||||
|
useOrder = true)
|
||||||
|
return choseMostSpecific(callContext, expectedType, candidates)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun choseMostSpecific(
|
||||||
|
callContext: KotlinCallContext,
|
||||||
|
expectedType: UnwrappedType?,
|
||||||
|
candidates: Collection<KotlinResolutionCandidate>
|
||||||
|
): Collection<ResolvedKotlinCall> {
|
||||||
|
|
||||||
|
val maximallySpecificCandidates = overloadingConflictResolver.chooseMaximallySpecificCandidates(
|
||||||
|
candidates,
|
||||||
|
CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS,
|
||||||
|
discriminateGenerics = true, // todo
|
||||||
|
isDebuggerContext = callContext.scopeTower.isDebuggerContext)
|
||||||
|
|
||||||
|
val singleResult = maximallySpecificCandidates.singleOrNull()?.let {
|
||||||
|
kotlinCallCompleter.completeCallIfNecessary(it, expectedType, callContext.lambdaAnalyzer)
|
||||||
|
}
|
||||||
|
if (singleResult != null) {
|
||||||
|
return listOf(singleResult)
|
||||||
|
}
|
||||||
|
|
||||||
|
return maximallySpecificCandidates.map {
|
||||||
|
kotlinCallCompleter.transformWhenAmbiguity(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
+21
@@ -0,0 +1,21 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
|
||||||
|
val USE_NEW_INFERENCE = false
|
||||||
|
|
||||||
|
val REPORT_MISSING_NEW_INFERENCE_DIAGNOSTIC = false
|
||||||
+328
@@ -0,0 +1,328 @@
|
|||||||
|
/*
|
||||||
|
* 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.components
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.model.*
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.tower.ResolutionCandidateApplicability.*
|
||||||
|
import org.jetbrains.kotlin.resolve.descriptorUtil.hasDefaultValue
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
class ArgumentsToParametersMapper {
|
||||||
|
|
||||||
|
data class ArgumentMapping(
|
||||||
|
// This map should be ordered by arguments as written, e.g.:
|
||||||
|
// fun foo(a: Int, b: Int) {}
|
||||||
|
// foo(b = bar(), a = qux())
|
||||||
|
// parameterToCallArgumentMap.values() should be [ 'bar()', 'foo()' ]
|
||||||
|
val parameterToCallArgumentMap: Map<ValueParameterDescriptor, ResolvedCallArgument>,
|
||||||
|
val diagnostics: List<KotlinCallDiagnostic>
|
||||||
|
)
|
||||||
|
|
||||||
|
val EmptyArgumentMapping = ArgumentMapping(emptyMap(), emptyList())
|
||||||
|
|
||||||
|
fun mapArguments(call: KotlinCall, descriptor: CallableDescriptor): ArgumentMapping =
|
||||||
|
mapArguments(call.argumentsInParenthesis, call.externalArgument, descriptor)
|
||||||
|
|
||||||
|
fun mapArguments(
|
||||||
|
argumentsInParenthesis: List<KotlinCallArgument>,
|
||||||
|
externalArgument: KotlinCallArgument?,
|
||||||
|
descriptor: CallableDescriptor
|
||||||
|
): ArgumentMapping {
|
||||||
|
// optimization for case of variable
|
||||||
|
if (argumentsInParenthesis.isEmpty() && externalArgument == null && descriptor.valueParameters.isEmpty()) {
|
||||||
|
return EmptyArgumentMapping
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
val processor = CallArgumentProcessor(descriptor)
|
||||||
|
processor.processArgumentsInParenthesis(argumentsInParenthesis)
|
||||||
|
|
||||||
|
if (externalArgument != null) {
|
||||||
|
processor.processExternalArgument(externalArgument)
|
||||||
|
}
|
||||||
|
processor.processDefaultsAndRunChecks()
|
||||||
|
|
||||||
|
return ArgumentMapping(processor.result, processor.getDiagnostics())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class CallArgumentProcessor(val descriptor: CallableDescriptor) {
|
||||||
|
val result: MutableMap<ValueParameterDescriptor, ResolvedCallArgument> = LinkedHashMap()
|
||||||
|
private var state = State.POSITION_ARGUMENTS
|
||||||
|
|
||||||
|
private val parameters: List<ValueParameterDescriptor> get() = descriptor.valueParameters
|
||||||
|
|
||||||
|
private var diagnostics: MutableList<KotlinCallDiagnostic>? = null
|
||||||
|
private var nameToParameter: Map<Name, ValueParameterDescriptor>? = null
|
||||||
|
private var varargArguments: MutableList<KotlinCallArgument>? = null
|
||||||
|
|
||||||
|
private var currentParameterIndex = 0
|
||||||
|
|
||||||
|
private fun addDiagnostic(diagnostic: KotlinCallDiagnostic) {
|
||||||
|
if (diagnostics == null) {
|
||||||
|
diagnostics = ArrayList()
|
||||||
|
}
|
||||||
|
diagnostics!!.add(diagnostic)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getDiagnostics() = diagnostics ?: emptyList<KotlinCallDiagnostic>()
|
||||||
|
|
||||||
|
private fun getParameterByName(name: Name): ValueParameterDescriptor? {
|
||||||
|
if (nameToParameter == null) {
|
||||||
|
nameToParameter = parameters.associateBy { it.name }
|
||||||
|
}
|
||||||
|
return nameToParameter!![name]
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun addVarargArgument(argument: KotlinCallArgument) {
|
||||||
|
if (varargArguments == null) {
|
||||||
|
varargArguments = ArrayList()
|
||||||
|
}
|
||||||
|
varargArguments!!.add(argument)
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum class State {
|
||||||
|
POSITION_ARGUMENTS,
|
||||||
|
VARARG_POSITION,
|
||||||
|
NAMED_ARGUMENT
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun completeVarargPositionArguments() {
|
||||||
|
assert(state == State.VARARG_POSITION) { "Incorrect state: $state" }
|
||||||
|
val parameter = parameters[currentParameterIndex]
|
||||||
|
result.put(parameter.original, ResolvedCallArgument.VarargArgument(varargArguments!!))
|
||||||
|
}
|
||||||
|
|
||||||
|
// return true, if it was mapped to vararg parameter
|
||||||
|
private fun processPositionArgument(argument: KotlinCallArgument): Boolean {
|
||||||
|
if (state == State.NAMED_ARGUMENT) {
|
||||||
|
addDiagnostic(MixingNamedAndPositionArguments(argument))
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
val parameter = parameters.getOrNull(currentParameterIndex)
|
||||||
|
if (parameter == null) {
|
||||||
|
addDiagnostic(TooManyArguments(argument, descriptor))
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!parameter.isVararg) {
|
||||||
|
currentParameterIndex++
|
||||||
|
|
||||||
|
result.put(parameter.original, ResolvedCallArgument.SimpleArgument(argument))
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
// all position arguments will be mapped to current vararg parameter
|
||||||
|
else {
|
||||||
|
addVarargArgument(argument)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun processNamedArgument(argument: KotlinCallArgument, name: Name) {
|
||||||
|
if (!descriptor.hasStableParameterNames()) {
|
||||||
|
addDiagnostic(NamedArgumentNotAllowed(argument, descriptor))
|
||||||
|
}
|
||||||
|
|
||||||
|
val parameter = findParameterByName(argument, name) ?: return
|
||||||
|
|
||||||
|
addDiagnostic(NamedArgumentReference(argument, parameter))
|
||||||
|
|
||||||
|
result[parameter.original]?.let {
|
||||||
|
addDiagnostic(ArgumentPassedTwice(argument, parameter, it))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
result[parameter.original] = ResolvedCallArgument.SimpleArgument(argument)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun findParameterByName(argument: KotlinCallArgument, name: Name): ValueParameterDescriptor? {
|
||||||
|
val parameter = getParameterByName(name)
|
||||||
|
|
||||||
|
if (descriptor is CallableMemberDescriptor && descriptor.kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) {
|
||||||
|
if (parameter == null) {
|
||||||
|
for (valueParameter in descriptor.valueParameters) {
|
||||||
|
val matchedParameter = valueParameter.overriddenDescriptors.firstOrNull {
|
||||||
|
it.containingDeclaration.hasStableParameterNames() && it.name == name
|
||||||
|
}
|
||||||
|
if (matchedParameter != null) {
|
||||||
|
addDiagnostic(NamedArgumentReference(argument, valueParameter))
|
||||||
|
addDiagnostic(NameForAmbiguousParameter(argument, valueParameter, matchedParameter))
|
||||||
|
return valueParameter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
parameter.getOverriddenParameterWithOtherName()?.let {
|
||||||
|
addDiagnostic(NameForAmbiguousParameter(argument, parameter, it))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parameter == null) addDiagnostic(NameNotFound(argument, descriptor))
|
||||||
|
|
||||||
|
return parameter
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun processArgumentsInParenthesis(arguments: List<KotlinCallArgument>) {
|
||||||
|
for (argument in arguments) {
|
||||||
|
val argumentName = argument.argumentName
|
||||||
|
|
||||||
|
// process position argument
|
||||||
|
if (argumentName == null) {
|
||||||
|
if (processPositionArgument(argument)) {
|
||||||
|
state = State.VARARG_POSITION
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// process named argument
|
||||||
|
else {
|
||||||
|
if (state == State.VARARG_POSITION) {
|
||||||
|
completeVarargPositionArguments()
|
||||||
|
}
|
||||||
|
state = State.POSITION_ARGUMENTS
|
||||||
|
|
||||||
|
processNamedArgument(argument, argumentName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (state == State.VARARG_POSITION) {
|
||||||
|
completeVarargPositionArguments()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun processExternalArgument(externalArgument: KotlinCallArgument) {
|
||||||
|
val lastParameter = parameters.lastOrNull()
|
||||||
|
if (lastParameter == null) {
|
||||||
|
addDiagnostic(TooManyArguments(externalArgument, descriptor))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lastParameter.isVararg) {
|
||||||
|
addDiagnostic(VarargArgumentOutsideParentheses(externalArgument, lastParameter))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val previousOccurrence = result[lastParameter.original]
|
||||||
|
if (previousOccurrence != null) {
|
||||||
|
addDiagnostic(TooManyArguments(externalArgument, descriptor))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
result[lastParameter.original] = ResolvedCallArgument.SimpleArgument(externalArgument)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun processDefaultsAndRunChecks() {
|
||||||
|
for ((parameter, resolvedArgument) in result) {
|
||||||
|
if (!parameter.isVararg) {
|
||||||
|
if (resolvedArgument !is ResolvedCallArgument.SimpleArgument) {
|
||||||
|
error("Incorrect resolved argument for parameter $parameter :$resolvedArgument")
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (resolvedArgument.callArgument.isSpread) {
|
||||||
|
addDiagnostic(NonVarargSpread(resolvedArgument.callArgument, parameter))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (parameter in parameters) {
|
||||||
|
if (!result.containsKey(parameter.original)) {
|
||||||
|
if (parameter.hasDefaultValue()) {
|
||||||
|
result[parameter.original] = ResolvedCallArgument.DefaultArgument
|
||||||
|
}
|
||||||
|
else if (parameter.isVararg) {
|
||||||
|
result[parameter.original] = ResolvedCallArgument.VarargArgument(emptyList())
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
addDiagnostic(NoValueForParameter(parameter, descriptor))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class TooManyArguments(val argument: KotlinCallArgument, val descriptor: CallableDescriptor) :
|
||||||
|
KotlinCallDiagnostic(INAPPLICABLE) {
|
||||||
|
override fun report(reporter: DiagnosticReporter) = reporter.onCallArgument(argument, this)
|
||||||
|
}
|
||||||
|
|
||||||
|
class NonVarargSpread (val argument: KotlinCallArgument, val parameterDescriptor: ValueParameterDescriptor) :
|
||||||
|
KotlinCallDiagnostic(INAPPLICABLE) {
|
||||||
|
override fun report(reporter: DiagnosticReporter) = reporter.onCallArgumentSpread(argument, this)
|
||||||
|
}
|
||||||
|
|
||||||
|
class MixingNamedAndPositionArguments(val argument: KotlinCallArgument) :
|
||||||
|
KotlinCallDiagnostic(INAPPLICABLE) {
|
||||||
|
override fun report(reporter: DiagnosticReporter) = reporter.onCallArgument(argument, this)
|
||||||
|
}
|
||||||
|
|
||||||
|
class NamedArgumentNotAllowed(val argument: KotlinCallArgument, val descriptor: CallableDescriptor) :
|
||||||
|
KotlinCallDiagnostic(INAPPLICABLE) {
|
||||||
|
override fun report(reporter: DiagnosticReporter) = reporter.onCallArgumentName(argument, this)
|
||||||
|
}
|
||||||
|
|
||||||
|
class NameNotFound(val argument: KotlinCallArgument, val descriptor: CallableDescriptor) :
|
||||||
|
KotlinCallDiagnostic(INAPPLICABLE) {
|
||||||
|
override fun report(reporter: DiagnosticReporter) = reporter.onCallArgumentName(argument, this)
|
||||||
|
}
|
||||||
|
|
||||||
|
class NoValueForParameter(val parameterDescriptor: ValueParameterDescriptor,
|
||||||
|
val descriptor: CallableDescriptor) :
|
||||||
|
KotlinCallDiagnostic(INAPPLICABLE) {
|
||||||
|
override fun report(reporter: DiagnosticReporter) = reporter.onCall(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
class ArgumentPassedTwice(val argument: KotlinCallArgument,
|
||||||
|
val parameterDescriptor: ValueParameterDescriptor,
|
||||||
|
val firstOccurrence: ResolvedCallArgument) :
|
||||||
|
KotlinCallDiagnostic(INAPPLICABLE) {
|
||||||
|
override fun report(reporter: DiagnosticReporter) = reporter.onCallArgumentName(argument, this)
|
||||||
|
}
|
||||||
|
|
||||||
|
class VarargArgumentOutsideParentheses(
|
||||||
|
val argument: KotlinCallArgument,
|
||||||
|
val parameterDescriptor: ValueParameterDescriptor) :
|
||||||
|
KotlinCallDiagnostic(INAPPLICABLE) {
|
||||||
|
override fun report(reporter: DiagnosticReporter) = reporter.onCallArgument(argument, this)
|
||||||
|
}
|
||||||
|
|
||||||
|
class NameForAmbiguousParameter(
|
||||||
|
val argument: KotlinCallArgument,
|
||||||
|
val parameterDescriptor: ValueParameterDescriptor,
|
||||||
|
val overriddenParameterWithOtherName: ValueParameterDescriptor
|
||||||
|
) : KotlinCallDiagnostic(CONVENTION_ERROR) {
|
||||||
|
override fun report(reporter: DiagnosticReporter) = reporter.onCallArgumentName(argument, this)
|
||||||
|
}
|
||||||
|
|
||||||
|
class NamedArgumentReference(
|
||||||
|
val argument: KotlinCallArgument,
|
||||||
|
val parameterDescriptor: ValueParameterDescriptor
|
||||||
|
) : KotlinCallDiagnostic(RESOLVED) {
|
||||||
|
override fun report(reporter: DiagnosticReporter) = reporter.onCallArgumentName(argument, this)
|
||||||
|
}
|
||||||
|
|
||||||
|
val ValueParameterDescriptor.isVararg: Boolean get() = varargElementType != null
|
||||||
|
|
||||||
|
fun ValueParameterDescriptor.getOverriddenParameterWithOtherName() = overriddenDescriptors.firstOrNull {
|
||||||
|
it.containingDeclaration.hasStableParameterNames() && it.name != name
|
||||||
|
}
|
||||||
+119
@@ -0,0 +1,119 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2017 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.resolve.calls.components
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.builtins.ReflectionTypes
|
||||||
|
import org.jetbrains.kotlin.builtins.getReturnTypeFromFunctionType
|
||||||
|
import org.jetbrains.kotlin.builtins.isFunctionType
|
||||||
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||||
|
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.model.*
|
||||||
|
import org.jetbrains.kotlin.types.ErrorUtils
|
||||||
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
import org.jetbrains.kotlin.types.UnwrappedType
|
||||||
|
import org.jetbrains.kotlin.types.typeUtil.builtIns
|
||||||
|
import org.jetbrains.kotlin.types.typeUtil.immediateSupertypes
|
||||||
|
import org.jetbrains.kotlin.types.typeUtil.isUnit
|
||||||
|
import org.jetbrains.kotlin.types.upperIfFlexible
|
||||||
|
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
|
||||||
|
class CallableReferenceResolver(
|
||||||
|
val reflectionTypes: ReflectionTypes,
|
||||||
|
val argumentsToParametersMapper: ArgumentsToParametersMapper
|
||||||
|
) {
|
||||||
|
|
||||||
|
fun resolvePropertyReference(
|
||||||
|
descriptor: PropertyDescriptor,
|
||||||
|
propertyReference: ChosenCallableReferenceDescriptor,
|
||||||
|
outerCall: KotlinCall,
|
||||||
|
scopeOwnerDescriptor: DeclarationDescriptor
|
||||||
|
): ResolvedPropertyReference {
|
||||||
|
val mutable = descriptor.isVar && run {
|
||||||
|
val setter = descriptor.setter
|
||||||
|
setter == null || Visibilities.isVisible(propertyReference.candidate.dispatchReceiver?.receiverValue, setter, scopeOwnerDescriptor)
|
||||||
|
}
|
||||||
|
|
||||||
|
val reflectionType = reflectionTypes.getKPropertyType(Annotations.EMPTY, listOfNotNull(propertyReference.dispatchNotBoundReceiver,
|
||||||
|
propertyReference.extensionNotBoundReceiver), descriptor.type.unwrap(), mutable)
|
||||||
|
|
||||||
|
return ResolvedPropertyReference(outerCall, propertyReference, reflectionType)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createFakeArgumentsAndMapArguments(
|
||||||
|
functionReference: ChosenCallableReferenceDescriptor,
|
||||||
|
argumentCount: Int?
|
||||||
|
): Pair<List<UnwrappedType>, ArgumentsToParametersMapper.ArgumentMapping?> {
|
||||||
|
if (argumentCount == null) {
|
||||||
|
return functionReference.candidate.descriptor.valueParameters.map { it.varargElementType?.unwrap() ?: it.type.unwrap() } to null
|
||||||
|
}
|
||||||
|
|
||||||
|
val fakeArguments = (0..(argumentCount - 1)).map { FakeKotlinCallArgumentForCallableReference(functionReference, it) }
|
||||||
|
|
||||||
|
val argumentsToParametersMapping = argumentsToParametersMapper.mapArguments(fakeArguments, null, functionReference.candidate.descriptor)
|
||||||
|
val parameters = Array<UnwrappedType?>(argumentCount) { null }
|
||||||
|
|
||||||
|
for ((parameter, resolvedArgument) in argumentsToParametersMapping.parameterToCallArgumentMap) {
|
||||||
|
for (argument in resolvedArgument.arguments) {
|
||||||
|
val index = (argument as FakeKotlinCallArgumentForCallableReference).index
|
||||||
|
parameters[index] = parameter.type.unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return parameters.map { it ?: ErrorUtils.createErrorType("Wrong parameters mapping") } to argumentsToParametersMapping
|
||||||
|
}
|
||||||
|
|
||||||
|
fun resolveFunctionReference(
|
||||||
|
functionReference: ChosenCallableReferenceDescriptor,
|
||||||
|
outerCall: KotlinCall,
|
||||||
|
expectedType: UnwrappedType
|
||||||
|
): ResolvedFunctionReference {
|
||||||
|
val functionType =
|
||||||
|
if (expectedType.isFunctionType) {
|
||||||
|
expectedType
|
||||||
|
}
|
||||||
|
else if (ReflectionTypes.isNumberedKFunction(expectedType)) {
|
||||||
|
expectedType.immediateSupertypes().first { it.isFunctionType }
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
|
val parameterTypes = ArrayList<UnwrappedType>(functionType?.arguments?.size ?: 2)
|
||||||
|
parameterTypes.addIfNotNull(functionReference.dispatchNotBoundReceiver)
|
||||||
|
parameterTypes.addIfNotNull(functionReference.extensionNotBoundReceiver)
|
||||||
|
|
||||||
|
// (A, B, C) -> Int if A -- receiver, then B & C -- parameters
|
||||||
|
// here parameterTypes contains only receivers, all parameters will be added later
|
||||||
|
val argumentCount = functionType?.arguments?.let { it.size - parameterTypes.size - 1 }?.takeIf { it >= 0 }
|
||||||
|
val (parameters, mapping) = createFakeArgumentsAndMapArguments(functionReference, argumentCount)
|
||||||
|
parameterTypes.addAll(parameters)
|
||||||
|
|
||||||
|
val unitExpectedType = functionType?.let(KotlinType::getReturnTypeFromFunctionType)?.takeIf { it.upperIfFlexible().isUnit() }
|
||||||
|
// coercion to unit
|
||||||
|
val returnType = unitExpectedType ?: functionReference.candidate.descriptor.returnType
|
||||||
|
?: ErrorUtils.createErrorType("Error return type")
|
||||||
|
|
||||||
|
val kFunctionType = reflectionTypes.getKFunctionType(Annotations.EMPTY, null, parameterTypes, null, returnType, expectedType.builtIns)
|
||||||
|
|
||||||
|
return ResolvedFunctionReference(outerCall, functionReference, kFunctionType, mapping)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
+299
@@ -0,0 +1,299 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2017 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.resolve.calls.components
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.builtins.getValueParameterTypesFromFunctionType
|
||||||
|
import org.jetbrains.kotlin.builtins.isExtensionFunctionType
|
||||||
|
import org.jetbrains.kotlin.builtins.isFunctionType
|
||||||
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.model.ArgumentConstraintPosition
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.model.LambdaTypeVariable
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.model.*
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.tower.isSuccess
|
||||||
|
import org.jetbrains.kotlin.types.UnwrappedType
|
||||||
|
import org.jetbrains.kotlin.types.checker.intersectWrappedTypes
|
||||||
|
import org.jetbrains.kotlin.types.typeUtil.builtIns
|
||||||
|
import org.jetbrains.kotlin.types.typeUtil.supertypes
|
||||||
|
import org.jetbrains.kotlin.utils.SmartList
|
||||||
|
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||||
|
import java.lang.UnsupportedOperationException
|
||||||
|
|
||||||
|
internal object CheckArguments : ResolutionPart {
|
||||||
|
override fun SimpleKotlinResolutionCandidate.process(): List<KotlinCallDiagnostic> {
|
||||||
|
val diagnostics = SmartList<KotlinCallDiagnostic>()
|
||||||
|
for (parameterDescriptor in descriptorWithFreshTypes.valueParameters) {
|
||||||
|
// error was reported in ArgumentsToParametersMapper
|
||||||
|
val resolvedCallArgument = argumentMappingByOriginal[parameterDescriptor.original] ?: continue
|
||||||
|
for (argument in resolvedCallArgument.arguments) {
|
||||||
|
|
||||||
|
val diagnostic = checkArgument(callContext, kotlinCall, csBuilder, argument, argument.getExpectedType(parameterDescriptor))
|
||||||
|
diagnostics.addIfNotNull(diagnostic)
|
||||||
|
|
||||||
|
if (diagnostic != null && !diagnostic.candidateApplicability.isSuccess) break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return diagnostics
|
||||||
|
}
|
||||||
|
|
||||||
|
fun checkArgument(
|
||||||
|
callContext: KotlinCallContext,
|
||||||
|
kotlinCall: KotlinCall,
|
||||||
|
csBuilder: ConstraintSystemBuilder,
|
||||||
|
argument: KotlinCallArgument,
|
||||||
|
expectedType: UnwrappedType
|
||||||
|
): KotlinCallDiagnostic? {
|
||||||
|
return when (argument) {
|
||||||
|
is ExpressionKotlinCallArgument -> checkExpressionArgument(csBuilder, argument, expectedType, isReceiver = false)
|
||||||
|
is SubKotlinCallArgument -> checkSubCallArgument(csBuilder, argument, expectedType, isReceiver = false)
|
||||||
|
is LambdaKotlinCallArgument -> processLambdaArgument(kotlinCall, csBuilder, argument, expectedType)
|
||||||
|
is CallableReferenceKotlinCallArgument -> processCallableReferenceArgument(callContext, kotlinCall, csBuilder, argument, expectedType)
|
||||||
|
else -> error("Incorrect argument type: $argument, ${argument.javaClass.canonicalName}.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun computeParameterTypes(
|
||||||
|
argument: LambdaKotlinCallArgument,
|
||||||
|
expectedType: UnwrappedType,
|
||||||
|
createFreshType: () -> UnwrappedType
|
||||||
|
): List<UnwrappedType> {
|
||||||
|
argument.parametersTypes?.map { it ?: createFreshType() } ?.let { return it }
|
||||||
|
|
||||||
|
if (expectedType.isFunctionType) {
|
||||||
|
return expectedType.getValueParameterTypesFromFunctionType().map { createFreshType() }
|
||||||
|
}
|
||||||
|
|
||||||
|
// if expected type is non-functional type and there is no declared parameters
|
||||||
|
return emptyList()
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun computeReceiver(
|
||||||
|
argument: LambdaKotlinCallArgument,
|
||||||
|
expectedType: UnwrappedType,
|
||||||
|
createFreshType: () -> UnwrappedType
|
||||||
|
) : UnwrappedType? {
|
||||||
|
if (argument is FunctionExpression) return argument.receiverType
|
||||||
|
|
||||||
|
if (expectedType.isExtensionFunctionType) return createFreshType()
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun computeReturnType(
|
||||||
|
argument: LambdaKotlinCallArgument,
|
||||||
|
createFreshType: () -> UnwrappedType
|
||||||
|
) : UnwrappedType {
|
||||||
|
if (argument is FunctionExpression) return argument.receiverType ?: createFreshType()
|
||||||
|
|
||||||
|
return createFreshType()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun processLambdaArgument(
|
||||||
|
kotlinCall: KotlinCall,
|
||||||
|
csBuilder: ConstraintSystemBuilder,
|
||||||
|
argument: LambdaKotlinCallArgument,
|
||||||
|
expectedType: UnwrappedType
|
||||||
|
): KotlinCallDiagnostic? {
|
||||||
|
// initial checks
|
||||||
|
if (expectedType.isFunctionType) {
|
||||||
|
val expectedParameterCount = expectedType.getValueParameterTypesFromFunctionType().size
|
||||||
|
|
||||||
|
argument.parametersTypes?.size?.let {
|
||||||
|
if (expectedParameterCount != it) return ExpectedLambdaParametersCountMismatch(argument, expectedParameterCount, it)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argument is FunctionExpression) {
|
||||||
|
if (argument.receiverType != null && !expectedType.isExtensionFunctionType) return UnexpectedReceiver(argument)
|
||||||
|
if (argument.receiverType == null && expectedType.isExtensionFunctionType) return MissingReceiver(argument)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val builtIns = expectedType.builtIns
|
||||||
|
val freshVariables = SmartList<LambdaTypeVariable>()
|
||||||
|
val receiver = computeReceiver(argument, expectedType) {
|
||||||
|
LambdaTypeVariable(argument, LambdaTypeVariable.Kind.RECEIVER, builtIns).apply { freshVariables.add(this) }.defaultType
|
||||||
|
}
|
||||||
|
|
||||||
|
val parameters = computeParameterTypes(argument, expectedType) {
|
||||||
|
LambdaTypeVariable(argument, LambdaTypeVariable.Kind.PARAMETER, builtIns).apply { freshVariables.add(this) }.defaultType
|
||||||
|
}
|
||||||
|
|
||||||
|
val returnType = computeReturnType(argument) {
|
||||||
|
LambdaTypeVariable(argument, LambdaTypeVariable.Kind.RETURN_TYPE, builtIns).apply { freshVariables.add(this) }.defaultType
|
||||||
|
}
|
||||||
|
|
||||||
|
val resolvedArgument = ResolvedLambdaArgument(kotlinCall, argument, freshVariables, receiver, parameters, returnType)
|
||||||
|
|
||||||
|
freshVariables.forEach(csBuilder::registerVariable)
|
||||||
|
csBuilder.addSubtypeConstraint(resolvedArgument.type, expectedType, ArgumentConstraintPosition(argument))
|
||||||
|
csBuilder.addLambdaArgument(resolvedArgument)
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
fun processCallableReferenceArgument(
|
||||||
|
callContext: KotlinCallContext,
|
||||||
|
kotlinCall: KotlinCall,
|
||||||
|
csBuilder: ConstraintSystemBuilder,
|
||||||
|
argument: CallableReferenceKotlinCallArgument,
|
||||||
|
expectedType: UnwrappedType
|
||||||
|
): KotlinCallDiagnostic? {
|
||||||
|
val position = ArgumentConstraintPosition(argument)
|
||||||
|
|
||||||
|
if (argument !is ChosenCallableReferenceDescriptor) {
|
||||||
|
val lhsType = argument.lhsType
|
||||||
|
if (lhsType != null) {
|
||||||
|
// todo: case with two receivers
|
||||||
|
val expectedReceiverType = expectedType.supertypes().firstOrNull { it.isFunctionType }?.arguments?.first()?.type?.unwrap()
|
||||||
|
if (expectedReceiverType != null) {
|
||||||
|
// (lhsType) -> .. <: (expectedReceiverType) -> ... => expectedReceiverType <: lhsType
|
||||||
|
csBuilder.addSubtypeConstraint(expectedReceiverType, lhsType, position)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
val descriptor = argument.candidate.descriptor
|
||||||
|
when (descriptor) {
|
||||||
|
is FunctionDescriptor -> {
|
||||||
|
// todo store resolved
|
||||||
|
val resolvedFunctionReference = callContext.callableReferenceResolver.resolveFunctionReference(
|
||||||
|
argument, kotlinCall, expectedType)
|
||||||
|
|
||||||
|
csBuilder.addSubtypeConstraint(resolvedFunctionReference.reflectionType, expectedType, position)
|
||||||
|
return resolvedFunctionReference.argumentsMapping?.diagnostics?.let {
|
||||||
|
ErrorCallableMapping(resolvedFunctionReference)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is PropertyDescriptor -> {
|
||||||
|
|
||||||
|
// todo store resolved
|
||||||
|
val resolvedPropertyReference = callContext.callableReferenceResolver.resolvePropertyReference(descriptor,
|
||||||
|
argument, kotlinCall, callContext.scopeTower.lexicalScope.ownerDescriptor)
|
||||||
|
csBuilder.addSubtypeConstraint(resolvedPropertyReference.reflectionType, expectedType, position)
|
||||||
|
}
|
||||||
|
else -> throw UnsupportedOperationException("Callable reference resolved to an unsupported descriptor: $descriptor")
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun checkExpressionArgument(
|
||||||
|
csBuilder: ConstraintSystemBuilder,
|
||||||
|
expressionArgument: ExpressionKotlinCallArgument,
|
||||||
|
expectedType: UnwrappedType,
|
||||||
|
isReceiver: Boolean
|
||||||
|
): KotlinCallDiagnostic? {
|
||||||
|
// todo run this approximation only once for call
|
||||||
|
val argumentType = expressionArgument.stableType
|
||||||
|
|
||||||
|
fun unstableSmartCastOrSubtypeError(
|
||||||
|
unstableType: UnwrappedType?, expectedType: UnwrappedType, position: ArgumentConstraintPosition
|
||||||
|
): KotlinCallDiagnostic? {
|
||||||
|
if (unstableType != null) {
|
||||||
|
if (csBuilder.addSubtypeConstraintIfCompatible(unstableType, expectedType, position)) {
|
||||||
|
return UnstableSmartCast(expressionArgument, unstableType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
csBuilder.addSubtypeConstraint(argumentType, expectedType, position)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
val expectedNullableType = expectedType.makeNullableAsSpecified(true)
|
||||||
|
val position = ArgumentConstraintPosition(expressionArgument)
|
||||||
|
if (expressionArgument.isSafeCall) {
|
||||||
|
if (!csBuilder.addSubtypeConstraintIfCompatible(argumentType, expectedNullableType, position)) {
|
||||||
|
return unstableSmartCastOrSubtypeError(expressionArgument.unstableType, expectedNullableType, position)?.let { return it }
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!csBuilder.addSubtypeConstraintIfCompatible(argumentType, expectedType, position)) {
|
||||||
|
if (!isReceiver) {
|
||||||
|
return unstableSmartCastOrSubtypeError(expressionArgument.unstableType, expectedType, position)?.let { return it }
|
||||||
|
}
|
||||||
|
|
||||||
|
val unstableType = expressionArgument.unstableType
|
||||||
|
if (unstableType != null && csBuilder.addSubtypeConstraintIfCompatible(unstableType, expectedType, position)) {
|
||||||
|
return UnstableSmartCast(expressionArgument, unstableType)
|
||||||
|
}
|
||||||
|
else if (csBuilder.addSubtypeConstraintIfCompatible(argumentType, expectedNullableType, position)) {
|
||||||
|
return UnsafeCallError(expressionArgument)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
csBuilder.addSubtypeConstraint(argumentType, expectedType, position)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
// if expression is not stable and has smart casts, then we create this type
|
||||||
|
private val ExpressionKotlinCallArgument.unstableType: UnwrappedType?
|
||||||
|
get() {
|
||||||
|
if (receiver.isStable || receiver.possibleTypes.isEmpty()) return null
|
||||||
|
return intersectWrappedTypes(receiver.possibleTypes + receiver.receiverValue.type)
|
||||||
|
}
|
||||||
|
|
||||||
|
// with all smart casts if stable
|
||||||
|
internal val ExpressionKotlinCallArgument.stableType: UnwrappedType
|
||||||
|
get() {
|
||||||
|
if (!receiver.isStable || receiver.possibleTypes.isEmpty()) return receiver.receiverValue.type.unwrap()
|
||||||
|
return intersectWrappedTypes(receiver.possibleTypes + receiver.receiverValue.type)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
internal fun checkSubCallArgument(
|
||||||
|
csBuilder: ConstraintSystemBuilder,
|
||||||
|
subCallArgument: SubKotlinCallArgument,
|
||||||
|
expectedType: UnwrappedType,
|
||||||
|
isReceiver: Boolean
|
||||||
|
): KotlinCallDiagnostic? {
|
||||||
|
val resolvedCall = subCallArgument.resolvedCall
|
||||||
|
val expectedNullableType = expectedType.makeNullableAsSpecified(true)
|
||||||
|
val position = ArgumentConstraintPosition(subCallArgument)
|
||||||
|
|
||||||
|
csBuilder.addInnerCall(resolvedCall)
|
||||||
|
|
||||||
|
// subArgument cannot has stable smartcast
|
||||||
|
val currentReturnType = subCallArgument.receiver.receiverValue.type.unwrap()
|
||||||
|
if (subCallArgument.isSafeCall) {
|
||||||
|
csBuilder.addSubtypeConstraint(currentReturnType, expectedNullableType, position)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isReceiver && !csBuilder.addSubtypeConstraintIfCompatible(currentReturnType, expectedType, position) &&
|
||||||
|
csBuilder.addSubtypeConstraintIfCompatible(currentReturnType, expectedNullableType, position)
|
||||||
|
) {
|
||||||
|
return UnsafeCallError(subCallArgument)
|
||||||
|
}
|
||||||
|
|
||||||
|
csBuilder.addSubtypeConstraint(currentReturnType, expectedType, position)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun KotlinCallArgument.getExpectedType(parameter: ValueParameterDescriptor) =
|
||||||
|
if (this.isSpread) {
|
||||||
|
parameter.type.unwrap()
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
parameter.varargElementType?.unwrap() ?: parameter.type.unwrap()
|
||||||
|
}
|
||||||
+37
@@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* 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.components
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||||
|
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.types.UnwrappedType
|
||||||
|
|
||||||
|
interface IsDescriptorFromSourcePredicate: (CallableDescriptor) -> Boolean
|
||||||
|
|
||||||
|
interface CommonSupertypeCalculator: (Collection<UnwrappedType>) -> UnwrappedType
|
||||||
|
|
||||||
|
interface LambdaAnalyzer {
|
||||||
|
fun analyzeAndGetRelatedCalls(
|
||||||
|
topLevelCall: KotlinCall,
|
||||||
|
lambdaArgument: LambdaKotlinCallArgument,
|
||||||
|
receiverType: UnwrappedType?,
|
||||||
|
parameters: List<UnwrappedType>,
|
||||||
|
expectedReturnType: UnwrappedType? // null means, that return type is not proper i.e. it depends on some type variables
|
||||||
|
): List<KotlinCallArgument>
|
||||||
|
}
|
||||||
+265
@@ -0,0 +1,265 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2017 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.resolve.calls.components
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.components.ConstraintInjector
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.components.FixationOrderCalculator
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.components.ResultTypeResolver
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.model.ExpectedTypeConstraintPosition
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.model.LambdaTypeVariable
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.model.NewTypeVariable
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.model.NotEnoughInformationForTypeParameter
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.returnTypeOrNothing
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.model.*
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.tower.ResolutionCandidateApplicability
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.tower.ResolutionCandidateStatus
|
||||||
|
import org.jetbrains.kotlin.types.TypeSubstitutor
|
||||||
|
import org.jetbrains.kotlin.types.TypeUtils
|
||||||
|
import org.jetbrains.kotlin.types.UnwrappedType
|
||||||
|
import org.jetbrains.kotlin.types.Variance
|
||||||
|
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
|
||||||
|
import org.jetbrains.kotlin.utils.SmartList
|
||||||
|
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||||
|
|
||||||
|
class KotlinCallCompleter(
|
||||||
|
val resultTypeResolver: ResultTypeResolver,
|
||||||
|
val fixationOrderCalculator: FixationOrderCalculator
|
||||||
|
) {
|
||||||
|
interface Context {
|
||||||
|
val innerCalls: List<ResolvedKotlinCall.OnlyResolvedKotlinCall>
|
||||||
|
val hasContradiction: Boolean
|
||||||
|
fun buildCurrentSubstitutor(): TypeSubstitutor
|
||||||
|
fun buildResultingSubstitutor(): TypeSubstitutor
|
||||||
|
val lambdaArguments: List<ResolvedLambdaArgument>
|
||||||
|
|
||||||
|
// type can be proper if it not contains not fixed type variables
|
||||||
|
fun canBeProper(type: UnwrappedType): Boolean
|
||||||
|
fun asFixationOrderCalculatorContext(): FixationOrderCalculator.Context
|
||||||
|
fun asResultTypeResolverContext(): ResultTypeResolver.Context
|
||||||
|
|
||||||
|
// mutable operations
|
||||||
|
fun asConstraintInjectorContext(): ConstraintInjector.Context
|
||||||
|
fun addError(error: KotlinCallDiagnostic)
|
||||||
|
fun fixVariable(variable: NewTypeVariable, resultType: UnwrappedType)
|
||||||
|
fun getBuilder(): ConstraintSystemBuilder
|
||||||
|
}
|
||||||
|
|
||||||
|
fun transformWhenAmbiguity(candidate: KotlinResolutionCandidate): ResolvedKotlinCall =
|
||||||
|
toCompletedBaseResolvedCall(candidate.lastCall.constraintSystem.asCallCompleterContext(), candidate)
|
||||||
|
|
||||||
|
fun completeCallIfNecessary(
|
||||||
|
candidate: KotlinResolutionCandidate,
|
||||||
|
expectedType: UnwrappedType?,
|
||||||
|
lambdaAnalyzer: LambdaAnalyzer
|
||||||
|
): ResolvedKotlinCall {
|
||||||
|
val topLevelCall =
|
||||||
|
if (candidate is VariableAsFunctionKotlinResolutionCandidate) {
|
||||||
|
candidate.invokeCandidate
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
candidate as SimpleKotlinResolutionCandidate
|
||||||
|
}
|
||||||
|
|
||||||
|
if (topLevelCall.prepareForCompletion(expectedType)) {
|
||||||
|
val c = candidate.lastCall.constraintSystem.asCallCompleterContext()
|
||||||
|
|
||||||
|
topLevelCall.competeCall(c, lambdaAnalyzer)
|
||||||
|
return toCompletedBaseResolvedCall(c, candidate)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResolvedKotlinCall.OnlyResolvedKotlinCall(candidate)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun toCompletedBaseResolvedCall(
|
||||||
|
c: Context,
|
||||||
|
candidate: KotlinResolutionCandidate
|
||||||
|
): ResolvedKotlinCall.CompletedResolvedKotlinCall {
|
||||||
|
val currentSubstitutor = c.buildResultingSubstitutor()
|
||||||
|
val completedCall = candidate.toCompletedCall(currentSubstitutor)
|
||||||
|
val competedCalls = c.innerCalls.map {
|
||||||
|
it.candidate.toCompletedCall(currentSubstitutor)
|
||||||
|
}
|
||||||
|
return ResolvedKotlinCall.CompletedResolvedKotlinCall(completedCall, competedCalls)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun KotlinResolutionCandidate.toCompletedCall(substitutor: TypeSubstitutor): CompletedKotlinCall {
|
||||||
|
if (this is VariableAsFunctionKotlinResolutionCandidate) {
|
||||||
|
val variable = resolvedVariable.toCompletedCall(substitutor)
|
||||||
|
val invoke = invokeCandidate.toCompletedCall(substitutor)
|
||||||
|
|
||||||
|
return CompletedKotlinCall.VariableAsFunction(kotlinCall, variable, invoke)
|
||||||
|
}
|
||||||
|
return (this as SimpleKotlinResolutionCandidate).toCompletedCall(substitutor)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun SimpleKotlinResolutionCandidate.toCompletedCall(substitutor: TypeSubstitutor): CompletedKotlinCall.Simple {
|
||||||
|
val resultingDescriptor = if (descriptorWithFreshTypes.typeParameters.isNotEmpty()) descriptorWithFreshTypes.substitute(substitutor)!! else descriptorWithFreshTypes
|
||||||
|
|
||||||
|
val typeArguments = descriptorWithFreshTypes.typeParameters.map { substitutor.safeSubstitute(it.defaultType, Variance.INVARIANT).unwrap() }
|
||||||
|
|
||||||
|
val status = computeStatus(this, resultingDescriptor)
|
||||||
|
return CompletedKotlinCall.Simple(kotlinCall, candidateDescriptor, resultingDescriptor, status, explicitReceiverKind,
|
||||||
|
dispatchReceiverArgument?.receiver, extensionReceiver?.receiver, typeArguments, argumentMappingByOriginal)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun computeStatus(candidate: SimpleKotlinResolutionCandidate, resultingDescriptor: CallableDescriptor): ResolutionCandidateStatus {
|
||||||
|
val smartCasts = reportSmartCasts(candidate, resultingDescriptor).takeIf { it.isNotEmpty() } ?: return candidate.status
|
||||||
|
return ResolutionCandidateStatus(candidate.status.diagnostics + smartCasts)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createSmartCastDiagnostic(argument: KotlinCallArgument, expectedResultType: UnwrappedType): SmartCastDiagnostic? {
|
||||||
|
if (argument !is ExpressionKotlinCallArgument) return null
|
||||||
|
if (!KotlinTypeChecker.DEFAULT.isSubtypeOf(argument.receiver.receiverValue.type, expectedResultType)) {
|
||||||
|
return SmartCastDiagnostic(argument, expectedResultType.unwrap())
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun reportSmartCastOnReceiver(
|
||||||
|
candidate: KotlinResolutionCandidate,
|
||||||
|
receiver: SimpleKotlinCallArgument?,
|
||||||
|
parameter: ReceiverParameterDescriptor?
|
||||||
|
): SmartCastDiagnostic? {
|
||||||
|
if (receiver == null || parameter == null) return null
|
||||||
|
val expectedType = parameter.type.unwrap().let { if (receiver.isSafeCall) it.makeNullableAsSpecified(true) else it }
|
||||||
|
|
||||||
|
val smartCastDiagnostic = createSmartCastDiagnostic(receiver, expectedType) ?: return null
|
||||||
|
|
||||||
|
// todo may be we have smart cast to Int?
|
||||||
|
return smartCastDiagnostic.takeIf {
|
||||||
|
candidate.status.diagnostics.filterIsInstance<UnsafeCallError>().none {
|
||||||
|
it.receiver == receiver
|
||||||
|
}
|
||||||
|
&&
|
||||||
|
candidate.status.diagnostics.filterIsInstance<UnstableSmartCast>().none {
|
||||||
|
it.expressionArgument == receiver
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun reportSmartCasts(candidate: SimpleKotlinResolutionCandidate, resultingDescriptor: CallableDescriptor): List<KotlinCallDiagnostic> = SmartList<KotlinCallDiagnostic>().apply {
|
||||||
|
addIfNotNull(reportSmartCastOnReceiver(candidate, candidate.extensionReceiver, resultingDescriptor.extensionReceiverParameter))
|
||||||
|
addIfNotNull(reportSmartCastOnReceiver(candidate, candidate.dispatchReceiverArgument, resultingDescriptor.dispatchReceiverParameter))
|
||||||
|
|
||||||
|
for (parameter in resultingDescriptor.valueParameters) {
|
||||||
|
for (argument in candidate.argumentMappingByOriginal[parameter.original]?.arguments ?: continue) {
|
||||||
|
val smartCastDiagnostic = createSmartCastDiagnostic(argument, argument.getExpectedType(parameter)) ?: continue
|
||||||
|
|
||||||
|
val thereIsUnstableSmartCastError = candidate.status.diagnostics.filterIsInstance<UnstableSmartCast>().any {
|
||||||
|
it.expressionArgument == argument
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!thereIsUnstableSmartCastError) {
|
||||||
|
add(smartCastDiagnostic)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// true if we should complete this call
|
||||||
|
private fun SimpleKotlinResolutionCandidate.prepareForCompletion(expectedType: UnwrappedType?): Boolean {
|
||||||
|
val returnType = descriptorWithFreshTypes.returnType?.unwrap() ?: return false
|
||||||
|
if (expectedType != null && !TypeUtils.noExpectedType(expectedType)) {
|
||||||
|
csBuilder.addSubtypeConstraint(returnType, expectedType, ExpectedTypeConstraintPosition(kotlinCall))
|
||||||
|
}
|
||||||
|
|
||||||
|
return expectedType != null || csBuilder.isProperType(returnType)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun SimpleKotlinResolutionCandidate.competeCall(c: Context, lambdaAnalyzer: LambdaAnalyzer) {
|
||||||
|
while (!oneStepToEndOrLambda(c, lambdaAnalyzer)) {
|
||||||
|
// do nothing -- be happy
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// true if it is the end (happy or not)
|
||||||
|
private fun SimpleKotlinResolutionCandidate.oneStepToEndOrLambda(c: Context, lambdaAnalyzer: LambdaAnalyzer): Boolean {
|
||||||
|
if (c.hasContradiction) return true
|
||||||
|
|
||||||
|
val lambda = c.lambdaArguments.find { canWeAnalyzeIt(c, it) }
|
||||||
|
if (lambda != null) {
|
||||||
|
analyzeLambda(c, lambdaAnalyzer, callContext, kotlinCall, lambda)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
val completionOrder = fixationOrderCalculator.computeCompletionOrder(c.asFixationOrderCalculatorContext(), descriptorWithFreshTypes.returnTypeOrNothing)
|
||||||
|
for ((variableWithConstraints, direction) in completionOrder) {
|
||||||
|
if (c.hasContradiction) return true
|
||||||
|
val variable = variableWithConstraints.typeVariable
|
||||||
|
|
||||||
|
val resultType = resultTypeResolver.findResultType(c.asResultTypeResolverContext(), variableWithConstraints, direction)
|
||||||
|
if (resultType == null) {
|
||||||
|
c.addError(NotEnoughInformationForTypeParameter(variable))
|
||||||
|
break
|
||||||
|
}
|
||||||
|
c.fixVariable(variable, resultType)
|
||||||
|
|
||||||
|
if (variable is LambdaTypeVariable) {
|
||||||
|
val resolvedLambda = c.lambdaArguments.find { it.argument == variable.lambdaArgument } ?: return true
|
||||||
|
if (canWeAnalyzeIt(c, resolvedLambda)) {
|
||||||
|
analyzeLambda(c, lambdaAnalyzer, callContext, kotlinCall, resolvedLambda)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun analyzeLambda(c: Context, lambdaAnalyzer: LambdaAnalyzer, topLevelCallContext: KotlinCallContext, topLevelCall: KotlinCall, lambda: ResolvedLambdaArgument) {
|
||||||
|
val currentSubstitutor = c.buildCurrentSubstitutor()
|
||||||
|
fun substitute(type: UnwrappedType) = currentSubstitutor.safeSubstitute(type, Variance.INVARIANT).unwrap()
|
||||||
|
|
||||||
|
val receiver = lambda.receiver?.let(::substitute)
|
||||||
|
val parameters = lambda.parameters.map(::substitute)
|
||||||
|
val expectedType = lambda.returnType.takeIf { c.canBeProper(it) }?.let(::substitute)
|
||||||
|
val callsFromLambda = lambdaAnalyzer.analyzeAndGetRelatedCalls(topLevelCall, lambda.argument, receiver, parameters, expectedType)
|
||||||
|
lambda.analyzed = true
|
||||||
|
|
||||||
|
for (innerCall in callsFromLambda) {
|
||||||
|
// todo strange code -- why top-level kotlinCall? may be it isn't right outer call
|
||||||
|
CheckArguments.checkArgument(topLevelCallContext, topLevelCall, c.getBuilder(), innerCall, lambda.returnType)
|
||||||
|
}
|
||||||
|
// when (innerCall) {
|
||||||
|
// is ResolvedKotlinCall.CompletedResolvedKotlinCall -> {
|
||||||
|
// val returnType = innerCall.completedCall.lastCall.resultingDescriptor.returnTypeOrNothing
|
||||||
|
// constraintInjector.addInitialSubtypeConstraint(injectorContext, returnType, lambda.returnType, position)
|
||||||
|
// }
|
||||||
|
// is ResolvedKotlinCall.OnlyResolvedKotlinCall -> {
|
||||||
|
// // todo register call
|
||||||
|
// val returnType = innerCall.candidate.lastCall.descriptorWithFreshTypes.returnTypeOrNothing
|
||||||
|
// c.addInnerCall(innerCall)
|
||||||
|
// constraintInjector.addInitialSubtypeConstraint(injectorContext, returnType, lambda.returnType, position)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun canWeAnalyzeIt(c: Context, lambda: ResolvedLambdaArgument): Boolean {
|
||||||
|
if (lambda.analyzed) return false
|
||||||
|
lambda.receiver?.let {
|
||||||
|
if (!c.canBeProper(it)) return false
|
||||||
|
}
|
||||||
|
return lambda.parameters.all { c.canBeProper(it) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class SmartCastDiagnostic(val expressionArgument: ExpressionKotlinCallArgument, val smartCastType: UnwrappedType): KotlinCallDiagnostic(ResolutionCandidateApplicability.RESOLVED) {
|
||||||
|
override fun report(reporter: DiagnosticReporter) = reporter.onCallArgument(expressionArgument, this)
|
||||||
|
}
|
||||||
+85
@@ -0,0 +1,85 @@
|
|||||||
|
/*
|
||||||
|
* 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.components
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.components.ConstraintInjector
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.components.ResultTypeResolver
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.components.SimpleConstraintSystemImpl
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.model.*
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.results.FlatSignature
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.results.FlatSignature.Companion.argumentValueType
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.results.OverloadingConflictResolver
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.results.TypeSpecificityComparator
|
||||||
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
class NewOverloadingConflictResolver(
|
||||||
|
builtIns: KotlinBuiltIns,
|
||||||
|
specificityComparator: TypeSpecificityComparator,
|
||||||
|
isDescriptorFromSourcePredicate: IsDescriptorFromSourcePredicate,
|
||||||
|
constraintInjector: ConstraintInjector,
|
||||||
|
typeResolver: ResultTypeResolver
|
||||||
|
) : OverloadingConflictResolver<KotlinResolutionCandidate>(
|
||||||
|
builtIns,
|
||||||
|
specificityComparator,
|
||||||
|
{
|
||||||
|
(it as? VariableAsFunctionKotlinResolutionCandidate)?.invokeCandidate?.descriptorWithFreshTypes ?:
|
||||||
|
(it as SimpleKotlinResolutionCandidate).descriptorWithFreshTypes
|
||||||
|
},
|
||||||
|
{ SimpleConstraintSystemImpl(constraintInjector, typeResolver) },
|
||||||
|
Companion::createFlatSignature,
|
||||||
|
{ (it as? VariableAsFunctionKotlinResolutionCandidate)?.resolvedVariable },
|
||||||
|
isDescriptorFromSourcePredicate
|
||||||
|
) {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private fun createFlatSignature(candidate: KotlinResolutionCandidate): FlatSignature<KotlinResolutionCandidate> {
|
||||||
|
val simpleCandidate = (candidate as? VariableAsFunctionKotlinResolutionCandidate)?.invokeCandidate ?: (candidate as SimpleKotlinResolutionCandidate)
|
||||||
|
|
||||||
|
val originalDescriptor = simpleCandidate.descriptorWithFreshTypes.original
|
||||||
|
val originalValueParameters = originalDescriptor.valueParameters
|
||||||
|
|
||||||
|
var numDefaults = 0
|
||||||
|
val valueArgumentToParameterType = HashMap<KotlinCallArgument, KotlinType>()
|
||||||
|
for ((valueParameter, resolvedValueArgument) in simpleCandidate.argumentMappingByOriginal) {
|
||||||
|
if (resolvedValueArgument is ResolvedCallArgument.DefaultArgument) {
|
||||||
|
numDefaults++
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
val originalValueParameter = originalValueParameters[valueParameter.index]
|
||||||
|
val parameterType = originalValueParameter.argumentValueType
|
||||||
|
for (valueArgument in resolvedValueArgument.arguments) {
|
||||||
|
valueArgumentToParameterType[valueArgument] = parameterType
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return FlatSignature.create(candidate,
|
||||||
|
originalDescriptor,
|
||||||
|
numDefaults,
|
||||||
|
listOfNotNull(originalDescriptor.extensionReceiverParameter?.type) +
|
||||||
|
simpleCandidate.kotlinCall.argumentsInParenthesis.map { valueArgumentToParameterType[it] } +
|
||||||
|
listOfNotNull(simpleCandidate.kotlinCall.externalArgument?.let { valueArgumentToParameterType[it] })
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
+243
@@ -0,0 +1,243 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2017 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.resolve.calls.components
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.components.TypeArgumentsToParametersMapper.TypeArgumentsMapping.NoExplicitArguments
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.model.DeclaredUpperBoundConstraintPosition
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.model.ExplicitTypeParameterConstraintPosition
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.model.TypeVariableFromCallableDescriptor
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.model.*
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.smartcasts.getReceiverValueWithSmartCast
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind.*
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.tower.ResolutionCandidateApplicability
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.tower.ResolutionCandidateApplicability.IMPOSSIBLE_TO_GENERATE
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.tower.VisibilityError
|
||||||
|
import org.jetbrains.kotlin.types.IndexedParametersSubstitution
|
||||||
|
import org.jetbrains.kotlin.types.TypeSubstitutor
|
||||||
|
import org.jetbrains.kotlin.types.UnwrappedType
|
||||||
|
import org.jetbrains.kotlin.types.Variance
|
||||||
|
import org.jetbrains.kotlin.types.typeUtil.asTypeProjection
|
||||||
|
|
||||||
|
|
||||||
|
internal object CheckVisibility : ResolutionPart {
|
||||||
|
override fun SimpleKotlinResolutionCandidate.process(): List<KotlinCallDiagnostic> {
|
||||||
|
val receiverValue = dispatchReceiverArgument?.receiver?.receiverValue
|
||||||
|
val invisibleMember = Visibilities.findInvisibleMember(receiverValue, candidateDescriptor, containingDescriptor) ?: return emptyList()
|
||||||
|
|
||||||
|
if (dispatchReceiverArgument is ExpressionKotlinCallArgument) {
|
||||||
|
val smartCastReceiver = getReceiverValueWithSmartCast(receiverValue, dispatchReceiverArgument.stableType)
|
||||||
|
if (Visibilities.findInvisibleMember(smartCastReceiver, candidateDescriptor, containingDescriptor) == null) {
|
||||||
|
return listOf(SmartCastDiagnostic(dispatchReceiverArgument, dispatchReceiverArgument.stableType))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return listOf(VisibilityError(invisibleMember))
|
||||||
|
}
|
||||||
|
|
||||||
|
private val SimpleKotlinResolutionCandidate.containingDescriptor: DeclarationDescriptor get() = callContext.scopeTower.lexicalScope.ownerDescriptor
|
||||||
|
}
|
||||||
|
|
||||||
|
internal object MapTypeArguments : ResolutionPart {
|
||||||
|
override fun SimpleKotlinResolutionCandidate.process(): List<KotlinCallDiagnostic> {
|
||||||
|
typeArgumentMappingByOriginal = callContext.typeArgumentsToParametersMapper.mapTypeArguments(kotlinCall, candidateDescriptor.original)
|
||||||
|
return typeArgumentMappingByOriginal.diagnostics
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal object NoTypeArguments : ResolutionPart {
|
||||||
|
override fun SimpleKotlinResolutionCandidate.process(): List<KotlinCallDiagnostic> {
|
||||||
|
assert(kotlinCall.typeArguments.isEmpty()) {
|
||||||
|
"Variable call cannot has explicit type arguments: ${kotlinCall.typeArguments}. Call: $kotlinCall"
|
||||||
|
}
|
||||||
|
typeArgumentMappingByOriginal = NoExplicitArguments
|
||||||
|
return typeArgumentMappingByOriginal.diagnostics
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal object MapArguments : ResolutionPart {
|
||||||
|
override fun SimpleKotlinResolutionCandidate.process(): List<KotlinCallDiagnostic> {
|
||||||
|
val mapping = callContext.argumentsToParametersMapper.mapArguments(kotlinCall, candidateDescriptor.original)
|
||||||
|
argumentMappingByOriginal = mapping.parameterToCallArgumentMap
|
||||||
|
return mapping.diagnostics
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal object NoArguments : ResolutionPart {
|
||||||
|
override fun SimpleKotlinResolutionCandidate.process(): List<KotlinCallDiagnostic> {
|
||||||
|
assert(kotlinCall.argumentsInParenthesis.isEmpty()) {
|
||||||
|
"Variable call cannot has arguments: ${kotlinCall.argumentsInParenthesis}. Call: $kotlinCall"
|
||||||
|
}
|
||||||
|
assert(kotlinCall.externalArgument == null) {
|
||||||
|
"Variable call cannot has external argument: ${kotlinCall.externalArgument}. Call: $kotlinCall"
|
||||||
|
}
|
||||||
|
argumentMappingByOriginal = emptyMap()
|
||||||
|
return emptyList()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal object CreteDescriptorWithFreshTypeVariables : ResolutionPart {
|
||||||
|
override fun SimpleKotlinResolutionCandidate.process(): List<KotlinCallDiagnostic> {
|
||||||
|
if (candidateDescriptor.typeParameters.isEmpty()) {
|
||||||
|
descriptorWithFreshTypes = candidateDescriptor
|
||||||
|
return emptyList()
|
||||||
|
}
|
||||||
|
val typeParameters = candidateDescriptor.typeParameters
|
||||||
|
|
||||||
|
val freshTypeVariables = typeParameters.map { TypeVariableFromCallableDescriptor(kotlinCall, it) }
|
||||||
|
val toFreshVariables = IndexedParametersSubstitution(typeParameters,
|
||||||
|
freshTypeVariables.map { it.defaultType.asTypeProjection() }).buildSubstitutor()
|
||||||
|
|
||||||
|
for (freshVariable in freshTypeVariables) {
|
||||||
|
csBuilder.registerVariable(freshVariable)
|
||||||
|
}
|
||||||
|
|
||||||
|
for (index in typeParameters.indices) {
|
||||||
|
val typeParameter = typeParameters[index]
|
||||||
|
val freshVariable = freshTypeVariables[index]
|
||||||
|
val position = DeclaredUpperBoundConstraintPosition(typeParameter)
|
||||||
|
|
||||||
|
for (upperBound in typeParameter.upperBounds) {
|
||||||
|
csBuilder.addSubtypeConstraint(freshVariable.defaultType, upperBound.unwrap().substitute(toFreshVariables), position)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// bad function -- error on declaration side
|
||||||
|
if (csBuilder.hasContradiction) {
|
||||||
|
descriptorWithFreshTypes = candidateDescriptor
|
||||||
|
return emptyList()
|
||||||
|
}
|
||||||
|
|
||||||
|
// optimization
|
||||||
|
if (typeArgumentMappingByOriginal == NoExplicitArguments) {
|
||||||
|
descriptorWithFreshTypes = candidateDescriptor.safeSubstitute(toFreshVariables)
|
||||||
|
csBuilder.simplify().let { assert(it.isEmpty) { "Substitutor should be empty: $it, call: $kotlinCall" } }
|
||||||
|
return emptyList()
|
||||||
|
}
|
||||||
|
|
||||||
|
// add explicit type parameter
|
||||||
|
for (index in typeParameters.indices) {
|
||||||
|
val typeParameter = typeParameters[index]
|
||||||
|
val typeArgument = typeArgumentMappingByOriginal.getTypeArgument(typeParameter)
|
||||||
|
|
||||||
|
if (typeArgument is SimpleTypeArgument) {
|
||||||
|
val freshVariable = freshTypeVariables[index]
|
||||||
|
csBuilder.addEqualityConstraint(freshVariable.defaultType, typeArgument.type, ExplicitTypeParameterConstraintPosition(typeArgument))
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
assert(typeArgument == TypeArgumentPlaceholder) {
|
||||||
|
"Unexpected typeArgument: $typeArgument, ${typeArgument.javaClass.canonicalName}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Note: here we can fix also placeholders arguments.
|
||||||
|
* Example:
|
||||||
|
* fun <X : Array<Y>, Y> foo()
|
||||||
|
*
|
||||||
|
* foo<Array<String>, *>()
|
||||||
|
*/
|
||||||
|
val toFixedTypeParameters = csBuilder.simplify()
|
||||||
|
// todo optimize -- composite substitutions before run safeSubstitute
|
||||||
|
descriptorWithFreshTypes = candidateDescriptor.safeSubstitute(toFreshVariables).safeSubstitute(toFixedTypeParameters)
|
||||||
|
|
||||||
|
return emptyList()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal object CheckExplicitReceiverKindConsistency : ResolutionPart {
|
||||||
|
private fun SimpleKotlinResolutionCandidate.hasError(): Nothing =
|
||||||
|
error("Inconsistent call: $kotlinCall. \n" +
|
||||||
|
"Candidate: $candidateDescriptor, explicitReceiverKind: $explicitReceiverKind.\n" +
|
||||||
|
"Explicit receiver: ${kotlinCall.explicitReceiver}, dispatchReceiverForInvokeExtension: ${kotlinCall.dispatchReceiverForInvokeExtension}")
|
||||||
|
|
||||||
|
override fun SimpleKotlinResolutionCandidate.process(): List<KotlinCallDiagnostic> {
|
||||||
|
when (explicitReceiverKind) {
|
||||||
|
NO_EXPLICIT_RECEIVER -> if (kotlinCall.explicitReceiver is SimpleKotlinCallArgument || kotlinCall.dispatchReceiverForInvokeExtension != null) hasError()
|
||||||
|
DISPATCH_RECEIVER, EXTENSION_RECEIVER -> if (kotlinCall.explicitReceiver == null || kotlinCall.dispatchReceiverForInvokeExtension != null) hasError()
|
||||||
|
BOTH_RECEIVERS -> if (kotlinCall.explicitReceiver == null || kotlinCall.dispatchReceiverForInvokeExtension == null) hasError()
|
||||||
|
}
|
||||||
|
return emptyList()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal object CheckReceivers : ResolutionPart {
|
||||||
|
private fun SimpleKotlinResolutionCandidate.checkReceiver(
|
||||||
|
receiverArgument: SimpleKotlinCallArgument?,
|
||||||
|
receiverParameter: ReceiverParameterDescriptor?
|
||||||
|
): KotlinCallDiagnostic? {
|
||||||
|
if ((receiverArgument == null) != (receiverParameter == null)) {
|
||||||
|
error("Inconsistency receiver state for call $kotlinCall and candidate descriptor: $candidateDescriptor")
|
||||||
|
}
|
||||||
|
if (receiverArgument == null || receiverParameter == null) return null
|
||||||
|
|
||||||
|
val expectedType = receiverParameter.type.unwrap()
|
||||||
|
|
||||||
|
return when (receiverArgument) {
|
||||||
|
is ExpressionKotlinCallArgument -> checkExpressionArgument(csBuilder, receiverArgument, expectedType, isReceiver = true)
|
||||||
|
is SubKotlinCallArgument -> checkSubCallArgument(csBuilder, receiverArgument, expectedType, isReceiver = true)
|
||||||
|
else -> incorrectReceiver(receiverArgument)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun incorrectReceiver(callReceiver: SimpleKotlinCallArgument): Nothing =
|
||||||
|
error("Incorrect receiver type: $callReceiver. Class name: ${callReceiver.javaClass.canonicalName}")
|
||||||
|
|
||||||
|
override fun SimpleKotlinResolutionCandidate.process() =
|
||||||
|
listOfNotNull(checkReceiver(dispatchReceiverArgument, descriptorWithFreshTypes.dispatchReceiverParameter),
|
||||||
|
checkReceiver(extensionReceiver, descriptorWithFreshTypes.extensionReceiverParameter))
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun <D : CallableDescriptor> D.safeSubstitute(substitutor: TypeSubstitutor): D =
|
||||||
|
@Suppress("UNCHECKED_CAST") (substitute(substitutor) as D)
|
||||||
|
|
||||||
|
fun UnwrappedType.substitute(substitutor: TypeSubstitutor): UnwrappedType = substitutor.substitute(this, Variance.INVARIANT)!!.unwrap()
|
||||||
|
|
||||||
|
|
||||||
|
class UnstableSmartCast(val expressionArgument: ExpressionKotlinCallArgument, val targetType: UnwrappedType) :
|
||||||
|
KotlinCallDiagnostic(ResolutionCandidateApplicability.MAY_THROW_RUNTIME_ERROR) {
|
||||||
|
override fun report(reporter: DiagnosticReporter) = reporter.onCallArgument(expressionArgument, this)
|
||||||
|
}
|
||||||
|
|
||||||
|
class UnsafeCallError(val receiver: SimpleKotlinCallArgument) : KotlinCallDiagnostic(ResolutionCandidateApplicability.MAY_THROW_RUNTIME_ERROR) {
|
||||||
|
override fun report(reporter: DiagnosticReporter) = reporter.onCallReceiver(receiver, this)
|
||||||
|
}
|
||||||
|
|
||||||
|
class ExpectedLambdaParametersCountMismatch(
|
||||||
|
val lambdaArgument: LambdaKotlinCallArgument,
|
||||||
|
val expected: Int,
|
||||||
|
val actual: Int
|
||||||
|
) : KotlinCallDiagnostic(IMPOSSIBLE_TO_GENERATE) {
|
||||||
|
override fun report(reporter: DiagnosticReporter) = reporter.onCallArgument(lambdaArgument, this)
|
||||||
|
}
|
||||||
|
|
||||||
|
class UnexpectedReceiver(val functionExpression: FunctionExpression) : KotlinCallDiagnostic(IMPOSSIBLE_TO_GENERATE) {
|
||||||
|
override fun report(reporter: DiagnosticReporter) = reporter.onCallArgument(functionExpression, this)
|
||||||
|
}
|
||||||
|
|
||||||
|
class MissingReceiver(val functionExpression: FunctionExpression) : KotlinCallDiagnostic(IMPOSSIBLE_TO_GENERATE) {
|
||||||
|
override fun report(reporter: DiagnosticReporter) = reporter.onCallArgument(functionExpression, this)
|
||||||
|
}
|
||||||
|
|
||||||
|
class ErrorCallableMapping(val functionReference: ResolvedFunctionReference) : KotlinCallDiagnostic(IMPOSSIBLE_TO_GENERATE) {
|
||||||
|
override fun report(reporter: DiagnosticReporter) = reporter.onCallArgument(functionReference.argument, this)
|
||||||
|
}
|
||||||
+44
@@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2017 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.resolve.calls.components
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.model.KotlinCallDiagnostic
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.model.ResolutionPart
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.model.SimpleKotlinResolutionCandidate
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.tower.InfixCallNoInfixModifier
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.tower.InvokeConventionCallNoOperatorModifier
|
||||||
|
|
||||||
|
object CheckInfixResolutionPart : ResolutionPart {
|
||||||
|
override fun SimpleKotlinResolutionCandidate.process(): List<KotlinCallDiagnostic> {
|
||||||
|
if (kotlinCall.isInfixCall && (candidateDescriptor !is FunctionDescriptor || !candidateDescriptor.isInfix)) {
|
||||||
|
return listOf(InfixCallNoInfixModifier)
|
||||||
|
}
|
||||||
|
|
||||||
|
return emptyList()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object CheckOperatorResolutionPart : ResolutionPart {
|
||||||
|
override fun SimpleKotlinResolutionCandidate.process(): List<KotlinCallDiagnostic> {
|
||||||
|
if (kotlinCall.isOperatorCall && (candidateDescriptor !is FunctionDescriptor || !candidateDescriptor.isOperator)) {
|
||||||
|
return listOf(InvokeConventionCallNoOperatorModifier)
|
||||||
|
}
|
||||||
|
|
||||||
|
return emptyList()
|
||||||
|
}
|
||||||
|
}
|
||||||
+67
@@ -0,0 +1,67 @@
|
|||||||
|
/*
|
||||||
|
* 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.components
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.model.*
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.tower.ResolutionCandidateApplicability
|
||||||
|
|
||||||
|
class TypeArgumentsToParametersMapper {
|
||||||
|
|
||||||
|
sealed class TypeArgumentsMapping(val diagnostics: List<KotlinCallDiagnostic>) {
|
||||||
|
|
||||||
|
abstract fun getTypeArgument(typeParameterDescriptor: TypeParameterDescriptor): TypeArgument
|
||||||
|
|
||||||
|
object NoExplicitArguments : TypeArgumentsMapping(emptyList()) {
|
||||||
|
override fun getTypeArgument(typeParameterDescriptor: TypeParameterDescriptor): TypeArgument {
|
||||||
|
return TypeArgumentPlaceholder
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TypeArgumentsMappingImpl(
|
||||||
|
diagnostics: List<KotlinCallDiagnostic>,
|
||||||
|
private val typeParameterToArgumentMap: Map<TypeParameterDescriptor, TypeArgument>
|
||||||
|
): TypeArgumentsMapping(diagnostics) {
|
||||||
|
override fun getTypeArgument(typeParameterDescriptor: TypeParameterDescriptor): TypeArgument {
|
||||||
|
return typeParameterToArgumentMap[typeParameterDescriptor] ?:
|
||||||
|
error("No argument for parameter: $typeParameterDescriptor. Reported diagnostics: $diagnostics")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun mapTypeArguments(call: KotlinCall, descriptor: CallableDescriptor): TypeArgumentsMapping {
|
||||||
|
if (call.typeArguments.isEmpty()) {
|
||||||
|
return TypeArgumentsMapping.NoExplicitArguments
|
||||||
|
}
|
||||||
|
|
||||||
|
if (call.typeArguments.size != descriptor.typeParameters.size) {
|
||||||
|
return TypeArgumentsMapping.TypeArgumentsMappingImpl(
|
||||||
|
listOf(WrongCountOfTypeArguments(descriptor, call.typeArguments.size)), emptyMap())
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
val typeParameterToArgumentMap = descriptor.typeParameters.zip(call.typeArguments).associate { it }
|
||||||
|
return TypeArgumentsMapping.TypeArgumentsMappingImpl(listOf(), typeParameterToArgumentMap)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class WrongCountOfTypeArguments(val descriptor: CallableDescriptor, val currentCount: Int) :
|
||||||
|
KotlinCallDiagnostic(ResolutionCandidateApplicability.INAPPLICABLE) {
|
||||||
|
override fun report(reporter: DiagnosticReporter) = reporter.onTypeArguments(this)
|
||||||
|
}
|
||||||
+47
@@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* 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.inference
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintPosition
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.model.NewTypeVariable
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.model.ResolvedKotlinCall
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.model.ResolvedLambdaArgument
|
||||||
|
import org.jetbrains.kotlin.types.TypeSubstitutor
|
||||||
|
import org.jetbrains.kotlin.types.UnwrappedType
|
||||||
|
|
||||||
|
|
||||||
|
interface ConstraintSystemBuilder {
|
||||||
|
val hasContradiction: Boolean
|
||||||
|
|
||||||
|
fun registerVariable(variable: NewTypeVariable)
|
||||||
|
|
||||||
|
fun addSubtypeConstraint(lowerType: UnwrappedType, upperType: UnwrappedType, position: ConstraintPosition)
|
||||||
|
fun addEqualityConstraint(a: UnwrappedType, b: UnwrappedType, position: ConstraintPosition)
|
||||||
|
|
||||||
|
fun addInnerCall(innerCall: ResolvedKotlinCall.OnlyResolvedKotlinCall)
|
||||||
|
fun addLambdaArgument(resolvedLambdaArgument: ResolvedLambdaArgument)
|
||||||
|
|
||||||
|
fun addSubtypeConstraintIfCompatible(lowerType: UnwrappedType, upperType: UnwrappedType, position: ConstraintPosition): Boolean
|
||||||
|
|
||||||
|
fun isProperType(type: UnwrappedType): Boolean
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function removes variables for which we know exact type.
|
||||||
|
* @return substitutor from typeVariable to result
|
||||||
|
*/
|
||||||
|
fun simplify(): TypeSubstitutor
|
||||||
|
}
|
||||||
+40
@@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* 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.inference
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage
|
||||||
|
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
||||||
|
import org.jetbrains.kotlin.types.TypeConstructorSubstitution
|
||||||
|
import org.jetbrains.kotlin.types.TypeSubstitutor
|
||||||
|
import org.jetbrains.kotlin.types.UnwrappedType
|
||||||
|
import org.jetbrains.kotlin.types.Variance
|
||||||
|
import org.jetbrains.kotlin.types.typeUtil.asTypeProjection
|
||||||
|
|
||||||
|
fun ConstraintStorage.buildCurrentSubstitutor() = TypeConstructorSubstitution.createByConstructorsMap(fixedTypeVariables.entries.associate {
|
||||||
|
it.key to it.value.asTypeProjection()
|
||||||
|
}).buildSubstitutor()
|
||||||
|
|
||||||
|
val CallableDescriptor.returnTypeOrNothing: UnwrappedType
|
||||||
|
get() {
|
||||||
|
returnType?.let { return it.unwrap() }
|
||||||
|
|
||||||
|
return builtIns.nothingType
|
||||||
|
}
|
||||||
|
|
||||||
|
fun TypeSubstitutor.substitute(type: UnwrappedType): UnwrappedType = safeSubstitute(type, Variance.INVARIANT).unwrap()
|
||||||
|
|
||||||
+31
@@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* 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.inference
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.components.KotlinCallCompleter
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.model.KotlinCallDiagnostic
|
||||||
|
|
||||||
|
interface NewConstraintSystem {
|
||||||
|
val diagnostics: List<KotlinCallDiagnostic>
|
||||||
|
|
||||||
|
fun getBuilder(): ConstraintSystemBuilder
|
||||||
|
|
||||||
|
// after this method we shouldn't mutate system via ConstraintSystemBuilder
|
||||||
|
fun asReadOnlyStorage(): ConstraintStorage
|
||||||
|
fun asCallCompleterContext(): KotlinCallCompleter.Context
|
||||||
|
}
|
||||||
+161
@@ -0,0 +1,161 @@
|
|||||||
|
/*
|
||||||
|
* 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.inference.components
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.types.TypeApproximator
|
||||||
|
import org.jetbrains.kotlin.types.TypeApproximatorConfiguration
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.model.*
|
||||||
|
import org.jetbrains.kotlin.types.*
|
||||||
|
import org.jetbrains.kotlin.types.checker.CaptureStatus
|
||||||
|
import org.jetbrains.kotlin.types.checker.NewCapturedType
|
||||||
|
import org.jetbrains.kotlin.types.checker.NewCapturedTypeConstructor
|
||||||
|
import org.jetbrains.kotlin.types.typeUtil.asTypeProjection
|
||||||
|
import org.jetbrains.kotlin.types.typeUtil.contains
|
||||||
|
import org.jetbrains.kotlin.utils.SmartSet
|
||||||
|
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
// todo problem: intersection types in constrains: A <: Number, B <: Inv<A & Any> =>? B <: Inv<out Number & Any>
|
||||||
|
class ConstraintIncorporator(val typeApproximator: TypeApproximator) {
|
||||||
|
|
||||||
|
interface Context {
|
||||||
|
val allTypeVariablesWithConstraints: Collection<VariableWithConstraints>
|
||||||
|
|
||||||
|
// if such type variable is fixed then it is error
|
||||||
|
fun getTypeVariable(typeConstructor: TypeConstructor): NewTypeVariable?
|
||||||
|
|
||||||
|
fun getConstraintsForVariable(typeVariable: NewTypeVariable): Collection<Constraint>
|
||||||
|
|
||||||
|
fun addNewIncorporatedConstraint(lowerType: UnwrappedType, upperType: UnwrappedType, position: IncorporationConstraintPosition)
|
||||||
|
}
|
||||||
|
|
||||||
|
// \alpha is typeVariable, \beta -- other type variable registered in ConstraintStorage
|
||||||
|
fun incorporate(c: Context, typeVariable: NewTypeVariable, constraint: Constraint, position: IncorporationConstraintPosition) {
|
||||||
|
// we shouldn't incorporate recursive constraint -- It is too dangerous
|
||||||
|
if (constraint.type.contains { it.constructor == typeVariable.freshTypeConstructor }) return
|
||||||
|
|
||||||
|
directWithVariable(c, typeVariable, constraint, position)
|
||||||
|
otherInsideMyConstraint(c, typeVariable, constraint, position)
|
||||||
|
insideOtherConstraint(c, typeVariable, constraint, position)
|
||||||
|
}
|
||||||
|
|
||||||
|
// A <:(=) \alpha <:(=) B => A <: B
|
||||||
|
private fun directWithVariable(c: Context, typeVariable: NewTypeVariable, constraint: Constraint, position: IncorporationConstraintPosition) {
|
||||||
|
// \alpha <: constraint.type
|
||||||
|
if (constraint.kind != ConstraintKind.LOWER) {
|
||||||
|
c.getConstraintsForVariable(typeVariable).forEach {
|
||||||
|
if (it.kind != ConstraintKind.UPPER) {
|
||||||
|
c.addNewIncorporatedConstraint(it.type, constraint.type, position)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// constraint.type <: \alpha
|
||||||
|
if (constraint.kind != ConstraintKind.UPPER) {
|
||||||
|
c.getConstraintsForVariable(typeVariable).forEach {
|
||||||
|
if (it.kind != ConstraintKind.LOWER) {
|
||||||
|
c.addNewIncorporatedConstraint(constraint.type, it.type, position)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// \alpha <: Inv<\beta>, \beta <: Number => \alpha <: Inv<out Number>
|
||||||
|
private fun otherInsideMyConstraint(c: Context, typeVariable: NewTypeVariable, constraint: Constraint, position: IncorporationConstraintPosition) {
|
||||||
|
val otherInMyConstraint = SmartSet.create<NewTypeVariable>()
|
||||||
|
constraint.type.contains {
|
||||||
|
otherInMyConstraint.addIfNotNull(c.getTypeVariable(it.constructor))
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
for (otherTypeVariable in otherInMyConstraint) {
|
||||||
|
// to avoid ConcurrentModificationException
|
||||||
|
val otherConstraints = ArrayList(c.getConstraintsForVariable(otherTypeVariable))
|
||||||
|
for (otherConstraint in otherConstraints) {
|
||||||
|
generateNewConstraint(c, typeVariable, constraint, otherTypeVariable, otherConstraint, position)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// \alpha <: Number, \beta <: Inv<\alpha> => \beta <: Inv<out Number>
|
||||||
|
private fun insideOtherConstraint(c: Context, typeVariable: NewTypeVariable, constraint: Constraint, position: IncorporationConstraintPosition) {
|
||||||
|
for (typeVariableWithConstraint in c.allTypeVariablesWithConstraints) {
|
||||||
|
val constraintsWhichConstraintMyVariable = typeVariableWithConstraint.constraints.filter {
|
||||||
|
it.type.contains { it.constructor == typeVariable.freshTypeConstructor }
|
||||||
|
}
|
||||||
|
constraintsWhichConstraintMyVariable.forEach {
|
||||||
|
generateNewConstraint(c, typeVariableWithConstraint.typeVariable, it, typeVariable, constraint, position)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun generateNewConstraint(
|
||||||
|
c: Context,
|
||||||
|
targetVariable: NewTypeVariable,
|
||||||
|
baseConstraint: Constraint,
|
||||||
|
otherVariable: NewTypeVariable,
|
||||||
|
otherConstraint: Constraint,
|
||||||
|
position: IncorporationConstraintPosition
|
||||||
|
) {
|
||||||
|
val typeForApproximation = when (otherConstraint.kind) {
|
||||||
|
ConstraintKind.EQUALITY -> {
|
||||||
|
baseConstraint.type.substitute(otherVariable, otherConstraint.type)
|
||||||
|
}
|
||||||
|
ConstraintKind.UPPER -> {
|
||||||
|
val newCapturedTypeConstructor = NewCapturedTypeConstructor(TypeProjectionImpl(Variance.OUT_VARIANCE, otherConstraint.type),
|
||||||
|
listOf(otherConstraint.type))
|
||||||
|
val temporaryCapturedType = NewCapturedType(CaptureStatus.FOR_INCORPORATION,
|
||||||
|
newCapturedTypeConstructor,
|
||||||
|
lowerType = null)
|
||||||
|
baseConstraint.type.substitute(otherVariable, temporaryCapturedType)
|
||||||
|
}
|
||||||
|
ConstraintKind.LOWER -> {
|
||||||
|
val newCapturedTypeConstructor = NewCapturedTypeConstructor(TypeProjectionImpl(Variance.IN_VARIANCE, otherConstraint.type),
|
||||||
|
emptyList())
|
||||||
|
val temporaryCapturedType = NewCapturedType(CaptureStatus.FOR_INCORPORATION,
|
||||||
|
newCapturedTypeConstructor,
|
||||||
|
lowerType = otherConstraint.type)
|
||||||
|
baseConstraint.type.substitute(otherVariable, temporaryCapturedType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (baseConstraint.kind != ConstraintKind.UPPER) {
|
||||||
|
c.addNewIncorporatedConstraint(approximateCapturedTypes(typeForApproximation, toSuper = false), targetVariable.defaultType, position)
|
||||||
|
}
|
||||||
|
if (baseConstraint.kind != ConstraintKind.LOWER) {
|
||||||
|
c.addNewIncorporatedConstraint(targetVariable.defaultType, approximateCapturedTypes(typeForApproximation, toSuper = true), position)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun UnwrappedType.substitute(typeVariable: NewTypeVariable, value: UnwrappedType): UnwrappedType {
|
||||||
|
val substitutor = TypeSubstitutor.create(mapOf(typeVariable.freshTypeConstructor to value.asTypeProjection()))
|
||||||
|
val type = substitutor.substitute(this, Variance.INVARIANT) ?: error("Impossible to substitute in $this: $typeVariable -> $value")
|
||||||
|
return type.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun approximateCapturedTypes(type: UnwrappedType, toSuper: Boolean): UnwrappedType =
|
||||||
|
if (toSuper) typeApproximator.approximateToSuperType(type, CapturedTypesApproximatorConfiguration) ?: type
|
||||||
|
else typeApproximator.approximateToSubType(type, CapturedTypesApproximatorConfiguration) ?: type
|
||||||
|
|
||||||
|
|
||||||
|
private object CapturedTypesApproximatorConfiguration : TypeApproximatorConfiguration.AllFlexibleSameValue() {
|
||||||
|
override val allFlexible get() = true
|
||||||
|
override val capturedType get() = { it: NewCapturedType -> it.captureStatus != CaptureStatus.FOR_INCORPORATION }
|
||||||
|
override val intersection get() = IntersectionStrategy.ALLOWED
|
||||||
|
override val typeVariable: (TypeVariableTypeConstructor) -> Boolean get() = { true }
|
||||||
|
}
|
||||||
|
}
|
||||||
+172
@@ -0,0 +1,172 @@
|
|||||||
|
/*
|
||||||
|
* 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.inference.components
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.model.*
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.model.KotlinCallDiagnostic
|
||||||
|
import org.jetbrains.kotlin.types.FlexibleType
|
||||||
|
import org.jetbrains.kotlin.types.SimpleType
|
||||||
|
import org.jetbrains.kotlin.types.TypeConstructor
|
||||||
|
import org.jetbrains.kotlin.types.UnwrappedType
|
||||||
|
import org.jetbrains.kotlin.types.checker.CaptureStatus
|
||||||
|
import org.jetbrains.kotlin.types.checker.NewCapturedType
|
||||||
|
import org.jetbrains.kotlin.types.checker.NewKotlinTypeChecker
|
||||||
|
import org.jetbrains.kotlin.types.typeUtil.contains
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
class ConstraintInjector(val constraintIncorporator: ConstraintIncorporator) {
|
||||||
|
private val ALLOWED_DEPTH_DELTA_FOR_INCORPORATION = 3
|
||||||
|
|
||||||
|
interface Context {
|
||||||
|
val allTypeVariables: Map<TypeConstructor, NewTypeVariable>
|
||||||
|
|
||||||
|
var maxTypeDepthFromInitialConstraints: Int
|
||||||
|
val notFixedTypeVariables: MutableMap<TypeConstructor, MutableVariableWithConstraints>
|
||||||
|
|
||||||
|
fun addInitialConstraint(initialConstraint: InitialConstraint)
|
||||||
|
fun addError(error: KotlinCallDiagnostic)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun addInitialSubtypeConstraint(c: Context, lowerType: UnwrappedType, upperType: UnwrappedType, position: ConstraintPosition) {
|
||||||
|
c.addInitialConstraint(InitialConstraint(lowerType, upperType, ConstraintKind.UPPER, position))
|
||||||
|
updateAllowedTypeDepth(c, lowerType)
|
||||||
|
updateAllowedTypeDepth(c, upperType)
|
||||||
|
addSubTypeConstraintAndIncorporateIt(c, lowerType, upperType, position)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun addInitialEqualityConstraint(c: Context, a: UnwrappedType, b: UnwrappedType, position: ConstraintPosition) {
|
||||||
|
c.addInitialConstraint(InitialConstraint(a, b, ConstraintKind.EQUALITY, position))
|
||||||
|
updateAllowedTypeDepth(c, a)
|
||||||
|
updateAllowedTypeDepth(c, b)
|
||||||
|
addSubTypeConstraintAndIncorporateIt(c, a, b, position)
|
||||||
|
addSubTypeConstraintAndIncorporateIt(c, b, a, position)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun addSubTypeConstraintAndIncorporateIt(c: Context, lowerType: UnwrappedType, upperType: UnwrappedType, position: ConstraintPosition) {
|
||||||
|
val incorporatePosition = IncorporationConstraintPosition(position)
|
||||||
|
val possibleNewConstraints = Stack<Pair<NewTypeVariable, Constraint>>()
|
||||||
|
val typeCheckerContext = TypeCheckerContext(c, position, lowerType, upperType, possibleNewConstraints)
|
||||||
|
typeCheckerContext.runIsSubtypeOf(lowerType, upperType)
|
||||||
|
|
||||||
|
while (possibleNewConstraints.isNotEmpty()) {
|
||||||
|
val (typeVariable, constraint) = possibleNewConstraints.pop()
|
||||||
|
val constraints = c.notFixedTypeVariables[typeVariable.freshTypeConstructor] ?: typeCheckerContext.fixedTypeVariable(typeVariable)
|
||||||
|
|
||||||
|
// it is important, that we add constraint here(not inside TypeCheckerContext), because inside incorporation we read constraints
|
||||||
|
constraints.addConstraint(constraint)?.let {
|
||||||
|
constraintIncorporator.incorporate(typeCheckerContext, typeVariable, it, incorporatePosition)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateAllowedTypeDepth(c: Context, initialType: UnwrappedType) {
|
||||||
|
c.maxTypeDepthFromInitialConstraints = Math.max(c.maxTypeDepthFromInitialConstraints, initialType.typeDepth())
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun UnwrappedType.typeDepth() =
|
||||||
|
when (this) {
|
||||||
|
is SimpleType -> typeDepth()
|
||||||
|
is FlexibleType -> Math.max(lowerBound.typeDepth(), upperBound.typeDepth())
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun SimpleType.typeDepth(): Int {
|
||||||
|
val maxInArguments = arguments.asSequence().map {
|
||||||
|
if (it.isStarProjection) 1 else it.type.unwrap().typeDepth()
|
||||||
|
}.max() ?: 0
|
||||||
|
|
||||||
|
return maxInArguments + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Context.isAllowedType(type: UnwrappedType) = type.typeDepth() <= maxTypeDepthFromInitialConstraints + ALLOWED_DEPTH_DELTA_FOR_INCORPORATION
|
||||||
|
|
||||||
|
private inner class TypeCheckerContext(
|
||||||
|
val c: Context,
|
||||||
|
val position: ConstraintPosition,
|
||||||
|
val baseLowerType: UnwrappedType,
|
||||||
|
val baseUpperType: UnwrappedType,
|
||||||
|
val possibleNewConstraints: MutableList<Pair<NewTypeVariable, Constraint>> = ArrayList()
|
||||||
|
) : TypeCheckerContextForConstraintSystem(), ConstraintIncorporator.Context {
|
||||||
|
|
||||||
|
fun runIsSubtypeOf(lowerType: UnwrappedType, upperType: UnwrappedType) {
|
||||||
|
with(NewKotlinTypeChecker) {
|
||||||
|
if (!this@TypeCheckerContext.isSubtypeOf(lowerType, upperType)) {
|
||||||
|
// todo improve error reporting -- add information about base types
|
||||||
|
c.addError(NewConstraintError(lowerType, upperType, position))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// from TypeCheckerContextForConstraintSystem
|
||||||
|
override fun isMyTypeVariable(type: SimpleType): Boolean = c.allTypeVariables.containsKey(type.constructor)
|
||||||
|
override fun addUpperConstraint(typeVariable: TypeConstructor, superType: UnwrappedType) =
|
||||||
|
addConstraint(typeVariable, superType, ConstraintKind.UPPER)
|
||||||
|
|
||||||
|
override fun addLowerConstraint(typeVariable: TypeConstructor, subType: UnwrappedType) =
|
||||||
|
addConstraint(typeVariable, subType, ConstraintKind.LOWER)
|
||||||
|
|
||||||
|
private fun addConstraint(typeVariableConstructor: TypeConstructor, type: UnwrappedType, kind: ConstraintKind) {
|
||||||
|
val typeVariable = c.allTypeVariables[typeVariableConstructor]
|
||||||
|
?: error("Should by type variableConstructor: $typeVariableConstructor. ${c.allTypeVariables.values}")
|
||||||
|
|
||||||
|
if (type.contains {
|
||||||
|
val captureStatus = (it as? NewCapturedType)?.captureStatus
|
||||||
|
assert(captureStatus != CaptureStatus.FOR_INCORPORATION) {
|
||||||
|
"Captured type for incorporation shouldn't escape from incorporation: $type\n" + renderBaseConstraint()
|
||||||
|
}
|
||||||
|
captureStatus != null && captureStatus != CaptureStatus.FROM_EXPRESSION
|
||||||
|
}) {
|
||||||
|
c.addError(CapturedTypeFromSubtyping(typeVariable, type, position))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!c.isAllowedType(type)) return
|
||||||
|
|
||||||
|
val newConstraint = Constraint(kind, type, position)
|
||||||
|
possibleNewConstraints.add(typeVariable to newConstraint)
|
||||||
|
}
|
||||||
|
|
||||||
|
// from ConstraintIncorporator.Context
|
||||||
|
override fun addNewIncorporatedConstraint(lowerType: UnwrappedType, upperType: UnwrappedType, position: IncorporationConstraintPosition) {
|
||||||
|
if (c.isAllowedType(lowerType) && c.isAllowedType(upperType)) {
|
||||||
|
runIsSubtypeOf(lowerType, upperType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override val allTypeVariablesWithConstraints: Collection<VariableWithConstraints>
|
||||||
|
get() = c.notFixedTypeVariables.values
|
||||||
|
|
||||||
|
override fun getTypeVariable(typeConstructor: TypeConstructor): NewTypeVariable? {
|
||||||
|
val typeVariable = c.allTypeVariables[typeConstructor]
|
||||||
|
if (typeVariable != null && !c.notFixedTypeVariables.containsKey(typeConstructor)) {
|
||||||
|
fixedTypeVariable(typeVariable)
|
||||||
|
}
|
||||||
|
return typeVariable
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getConstraintsForVariable(typeVariable: NewTypeVariable) =
|
||||||
|
c.notFixedTypeVariables[typeVariable.freshTypeConstructor]?.constraints
|
||||||
|
?: fixedTypeVariable(typeVariable)
|
||||||
|
|
||||||
|
fun fixedTypeVariable(variable: NewTypeVariable): Nothing {
|
||||||
|
error("Type variable $variable should not be fixed!\n" +
|
||||||
|
renderBaseConstraint())
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun renderBaseConstraint() = "Base constraint: $baseLowerType <: $baseUpperType from position: $position"
|
||||||
|
}
|
||||||
|
}
|
||||||
+209
@@ -0,0 +1,209 @@
|
|||||||
|
/*
|
||||||
|
* 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.inference.components
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.model.Constraint
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintKind
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.model.LambdaTypeVariable
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.model.VariableWithConstraints
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.model.ResolvedLambdaArgument
|
||||||
|
import org.jetbrains.kotlin.types.*
|
||||||
|
import org.jetbrains.kotlin.types.checker.NewKotlinTypeChecker
|
||||||
|
import org.jetbrains.kotlin.types.checker.isIntersectionType
|
||||||
|
import org.jetbrains.kotlin.utils.DFS
|
||||||
|
import org.jetbrains.kotlin.utils.SmartList
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
private typealias Variable = VariableWithConstraints
|
||||||
|
|
||||||
|
class FixationOrderCalculator {
|
||||||
|
enum class ResolveDirection {
|
||||||
|
TO_SUBTYPE,
|
||||||
|
TO_SUPERTYPE,
|
||||||
|
UNKNOWN
|
||||||
|
}
|
||||||
|
|
||||||
|
data class NodeWithDirection(val variableWithConstraints: VariableWithConstraints, val direction: ResolveDirection) {
|
||||||
|
override fun toString() = "$variableWithConstraints to $direction"
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Context {
|
||||||
|
val notFixedTypeVariables: Map<TypeConstructor, VariableWithConstraints>
|
||||||
|
val lambdaArguments: List<ResolvedLambdaArgument>
|
||||||
|
}
|
||||||
|
|
||||||
|
fun computeCompletionOrder(
|
||||||
|
c: Context,
|
||||||
|
topReturnType: UnwrappedType
|
||||||
|
): List<NodeWithDirection> = DependencyGraph(c).getCompletionOrder(topReturnType)
|
||||||
|
|
||||||
|
private class DependencyGraph(val c: Context) {
|
||||||
|
private val directions = HashMap<Variable, ResolveDirection>()
|
||||||
|
|
||||||
|
// first in the list -- first fix
|
||||||
|
fun getCompletionOrder(topReturnType: UnwrappedType): List<NodeWithDirection> {
|
||||||
|
setupDirections(topReturnType)
|
||||||
|
|
||||||
|
return topologicalOrderWith0Priority().map { NodeWithDirection(it, directions[it] ?: ResolveDirection.UNKNOWN) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun topologicalOrderWith0Priority(): List<Variable> {
|
||||||
|
val handler = object : DFS.CollectingNodeHandler<Variable, Variable, LinkedHashSet<Variable>>(LinkedHashSet()) {
|
||||||
|
override fun afterChildren(current: Variable) {
|
||||||
|
// we have guaranty that from end of 0 edge there is no other edges with priority 0
|
||||||
|
result.addAll(get0Edges(current))
|
||||||
|
|
||||||
|
result.add(current)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (typeVariable in c.notFixedTypeVariables.values) {
|
||||||
|
DFS.doDfs(typeVariable, DFS.Neighbors(this::getEdges), DFS.VisitedWithSet<Variable>(), handler)
|
||||||
|
}
|
||||||
|
return handler.result().toList()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun setupDirections(topReturnType: UnwrappedType) {
|
||||||
|
topReturnType.visitType(ResolveDirection.TO_SUBTYPE) { variableWithConstraints, direction ->
|
||||||
|
enterToNode(variableWithConstraints, direction)
|
||||||
|
}
|
||||||
|
for (resolvedLambdaArgument in c.lambdaArguments) {
|
||||||
|
inner@ for (typeVariable in resolvedLambdaArgument.myTypeVariables) {
|
||||||
|
if (typeVariable.kind == LambdaTypeVariable.Kind.RETURN_TYPE) continue@inner
|
||||||
|
|
||||||
|
c.notFixedTypeVariables[typeVariable.freshTypeConstructor]?.let {
|
||||||
|
enterToNode(it, ResolveDirection.TO_SUBTYPE)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun enterToNode(variable: Variable, direction: ResolveDirection) {
|
||||||
|
if (direction == ResolveDirection.UNKNOWN) return
|
||||||
|
|
||||||
|
val previous = directions[variable]
|
||||||
|
if (previous != null) {
|
||||||
|
if (previous != direction) {
|
||||||
|
directions[variable] = ResolveDirection.UNKNOWN
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
directions[variable] = direction
|
||||||
|
|
||||||
|
for ((otherVariable, otherDirection) in get12Edges(variable, direction)) {
|
||||||
|
enterToNode(otherVariable, otherDirection)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getEdges(variable: Variable): List<Variable> {
|
||||||
|
val direction = directions[variable] ?: ResolveDirection.UNKNOWN
|
||||||
|
return get12Edges(variable, direction).map(NodeWithDirection::variableWithConstraints) + get0Edges(variable)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Now we use only priority 0 and {1, 2}.
|
||||||
|
* Current vision of edge priority for type variable \alpha to variable \beta:
|
||||||
|
* 0 -- { \beta -> \alpha } i.e. return type depend of all parameters types of lambda
|
||||||
|
* 1 -- \alpha <: Inv<\beta> or \alpha >: Pair<Inv<\beta & Any>, Int> ot \alpha <: \beta & Any
|
||||||
|
* 2 -- \alpha <: \beta or \alpha >: \beta?
|
||||||
|
*/
|
||||||
|
private fun get12Edges(variableWithConstraints: Variable, direction: ResolveDirection, include2: Boolean = true): List<NodeWithDirection> {
|
||||||
|
fun isNotInterestingConstraint(direction: ResolveDirection, constraint: Constraint): Boolean {
|
||||||
|
return (direction == ResolveDirection.TO_SUBTYPE && constraint.kind == ConstraintKind.UPPER) ||
|
||||||
|
(direction == ResolveDirection.TO_SUPERTYPE && constraint.kind == ConstraintKind.LOWER)
|
||||||
|
}
|
||||||
|
|
||||||
|
val result = SmartList<NodeWithDirection>()
|
||||||
|
|
||||||
|
for (constraint in variableWithConstraints.constraints) {
|
||||||
|
if (isNotInterestingConstraint(direction, constraint)) continue
|
||||||
|
|
||||||
|
if (include2 || !c.notFixedTypeVariables.containsKey(constraint.type.constructor)) { // because we collect only type 1 of edges
|
||||||
|
constraint.type.visitType(direction) { variable, direction ->
|
||||||
|
result.add(NodeWithDirection(variable, direction))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun get0Edges(variable: Variable): List<Variable> {
|
||||||
|
val typeVariable = variable.typeVariable
|
||||||
|
if (typeVariable !is LambdaTypeVariable || typeVariable.kind != LambdaTypeVariable.Kind.RETURN_TYPE) return emptyList()
|
||||||
|
|
||||||
|
val resolvedLambdaArgument = c.lambdaArguments.find { it.argument == typeVariable.lambdaArgument } ?:
|
||||||
|
error("Missing resolved lambda argument for ${typeVariable.lambdaArgument}")
|
||||||
|
|
||||||
|
return resolvedLambdaArgument.myTypeVariables.mapNotNull {
|
||||||
|
if (it.kind == LambdaTypeVariable.Kind.RETURN_TYPE) return@mapNotNull null
|
||||||
|
c.notFixedTypeVariables[it.freshTypeConstructor]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun UnwrappedType.visitType(startDirection: ResolveDirection, action: (variable: Variable, direction: ResolveDirection) -> Unit) =
|
||||||
|
when (this) {
|
||||||
|
is SimpleType -> visitType(startDirection, action)
|
||||||
|
is FlexibleType -> {
|
||||||
|
lowerBound.visitType(startDirection, action)
|
||||||
|
upperBound.visitType(startDirection, action)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun SimpleType.visitType(startDirection: ResolveDirection, action: (variable: Variable, direction: ResolveDirection) -> Unit) {
|
||||||
|
if (isIntersectionType) {
|
||||||
|
constructor.supertypes.forEach {
|
||||||
|
it.unwrap().visitType(startDirection, action)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (arguments.isEmpty()) {
|
||||||
|
c.notFixedTypeVariables[constructor]?.let {
|
||||||
|
action(it, startDirection)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val parameters = constructor.parameters
|
||||||
|
if (parameters.size != arguments.size) return // incorrect type
|
||||||
|
|
||||||
|
fun ResolveDirection.opposite() = when (this) {
|
||||||
|
ResolveDirection.UNKNOWN -> ResolveDirection.UNKNOWN
|
||||||
|
ResolveDirection.TO_SUPERTYPE -> ResolveDirection.TO_SUBTYPE
|
||||||
|
ResolveDirection.TO_SUBTYPE -> ResolveDirection.TO_SUPERTYPE
|
||||||
|
}
|
||||||
|
|
||||||
|
for ((argument, parameter) in arguments.zip(parameters)) {
|
||||||
|
if (argument.isStarProjection) continue
|
||||||
|
|
||||||
|
val variance = NewKotlinTypeChecker.effectiveVariance(parameter.variance, argument.projectionKind) ?: Variance.INVARIANT
|
||||||
|
val innerDirection = when (variance) {
|
||||||
|
Variance.INVARIANT -> ResolveDirection.UNKNOWN
|
||||||
|
Variance.OUT_VARIANCE -> startDirection
|
||||||
|
Variance.IN_VARIANCE -> startDirection.opposite()
|
||||||
|
}
|
||||||
|
|
||||||
|
argument.type.unwrap().visitType(innerDirection, action)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+108
@@ -0,0 +1,108 @@
|
|||||||
|
/*
|
||||||
|
* 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.inference.components
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.components.CommonSupertypeCalculator
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.components.FixationOrderCalculator.ResolveDirection
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.model.Constraint
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintKind
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.model.VariableWithConstraints
|
||||||
|
import org.jetbrains.kotlin.resolve.constants.IntegerValueTypeConstructor
|
||||||
|
import org.jetbrains.kotlin.types.TypeUtils
|
||||||
|
import org.jetbrains.kotlin.types.UnwrappedType
|
||||||
|
import org.jetbrains.kotlin.types.checker.intersectTypes
|
||||||
|
import org.jetbrains.kotlin.types.singleBestRepresentative
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
class ResultTypeResolver(val commonSupertypeCalculator: CommonSupertypeCalculator) {
|
||||||
|
interface Context {
|
||||||
|
fun isProperType(type: UnwrappedType): Boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
fun findResultType(c: Context, variableWithConstraints: VariableWithConstraints, direction: ResolveDirection): UnwrappedType? {
|
||||||
|
findResultIfThereIsEqualsConstraint(c, variableWithConstraints, allowedFixToNotProperType = false)?.let { return it }
|
||||||
|
|
||||||
|
if (direction == ResolveDirection.TO_SUBTYPE || direction == ResolveDirection.UNKNOWN) {
|
||||||
|
val lowerConstraints = variableWithConstraints.constraints.filter { it.kind == ConstraintKind.LOWER && c.isProperType(it.type) }
|
||||||
|
if (lowerConstraints.isNotEmpty()) {
|
||||||
|
return commonSupertypeCalculator(convertLowerTypesWithKnowledgeOfNumberTypes(lowerConstraints))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// direction == TO_LOWER or there is no LOWER bounds
|
||||||
|
val upperConstraints = variableWithConstraints.constraints.filter { it.kind == ConstraintKind.UPPER && c.isProperType(it.type) }
|
||||||
|
if (upperConstraints.isNotEmpty()) {
|
||||||
|
return intersectTypes(upperConstraints.map { it.type })
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
fun findResultIfThereIsEqualsConstraint(
|
||||||
|
c: Context,
|
||||||
|
variableWithConstraints: VariableWithConstraints,
|
||||||
|
allowedFixToNotProperType: Boolean = false
|
||||||
|
): UnwrappedType? {
|
||||||
|
val properEqualsConstraint = variableWithConstraints.constraints.filter {
|
||||||
|
it.kind == ConstraintKind.EQUALITY && c.isProperType(it.type)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (properEqualsConstraint.isNotEmpty()) {
|
||||||
|
return properEqualsConstraint.map { it.type }.singleBestRepresentative()?.unwrap()
|
||||||
|
?: properEqualsConstraint.first().type // seems like constraint system has contradiction
|
||||||
|
}
|
||||||
|
if (!allowedFixToNotProperType) return null
|
||||||
|
|
||||||
|
val notProperEqualsConstraint = variableWithConstraints.constraints.filter { it.kind == ConstraintKind.EQUALITY }
|
||||||
|
|
||||||
|
// may be we should just firstOrNull
|
||||||
|
return notProperEqualsConstraint.singleOrNull()?.type
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun convertLowerTypesWithKnowledgeOfNumberTypes(lowerConstraints: Collection<Constraint>): Collection<UnwrappedType> {
|
||||||
|
if (lowerConstraints.isEmpty()) return emptyList()
|
||||||
|
if (lowerConstraints.size == 1) return listOf(lowerConstraints.first().type)
|
||||||
|
|
||||||
|
val (numberLowerBounds, generalLowerBounds) = lowerConstraints.map { it.type }.partition { it.constructor is IntegerValueTypeConstructor }
|
||||||
|
|
||||||
|
val numberType = commonSupertypeForNumberTypes(numberLowerBounds) ?: return generalLowerBounds
|
||||||
|
return generalLowerBounds + numberType
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun commonSupertypeForNumberTypes(numberLowerBounds: Collection<UnwrappedType>): UnwrappedType? {
|
||||||
|
if (numberLowerBounds.isEmpty()) return null
|
||||||
|
val intersectionOfSupertypes = getIntersectionOfSupertypes(numberLowerBounds)
|
||||||
|
return TypeUtils.getDefaultPrimitiveNumberType(intersectionOfSupertypes)?.unwrap() ?:
|
||||||
|
commonSupertypeCalculator(numberLowerBounds)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getIntersectionOfSupertypes(types: Collection<UnwrappedType>): Set<UnwrappedType> {
|
||||||
|
val upperBounds = HashSet<UnwrappedType>()
|
||||||
|
for (type in types) {
|
||||||
|
val supertypes = type.constructor.supertypes.map { it.unwrap() }
|
||||||
|
if (upperBounds.isEmpty()) {
|
||||||
|
upperBounds.addAll(supertypes)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
upperBounds.retainAll(supertypes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return upperBounds
|
||||||
|
}
|
||||||
|
}
|
||||||
+67
@@ -0,0 +1,67 @@
|
|||||||
|
/*
|
||||||
|
* 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.inference.components
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.model.KotlinCallKind
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.model.NewConstraintSystemImpl
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.model.SimpleConstraintSystemConstraintPosition
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.model.TypeVariableFromCallableDescriptor
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.model.KotlinCall
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.model.KotlinCallArgument
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.model.ReceiverKotlinCallArgument
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.model.TypeArgument
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.results.SimpleConstraintSystem
|
||||||
|
import org.jetbrains.kotlin.types.TypeConstructorSubstitution
|
||||||
|
import org.jetbrains.kotlin.types.TypeSubstitutor
|
||||||
|
import org.jetbrains.kotlin.types.UnwrappedType
|
||||||
|
import org.jetbrains.kotlin.types.typeUtil.asTypeProjection
|
||||||
|
import java.lang.UnsupportedOperationException
|
||||||
|
|
||||||
|
|
||||||
|
class SimpleConstraintSystemImpl(constraintInjector: ConstraintInjector, resultTypeResolver: ResultTypeResolver) : SimpleConstraintSystem {
|
||||||
|
val csBuilder: ConstraintSystemBuilder = NewConstraintSystemImpl(constraintInjector, resultTypeResolver).getBuilder()
|
||||||
|
|
||||||
|
override fun registerTypeVariables(typeParameters: Collection<TypeParameterDescriptor>): TypeSubstitutor {
|
||||||
|
val substitutionMap = typeParameters.associate {
|
||||||
|
val variable = TypeVariableFromCallableDescriptor(ThrowableKotlinCall, it)
|
||||||
|
csBuilder.registerVariable(variable)
|
||||||
|
|
||||||
|
it.defaultType.constructor to variable.defaultType.asTypeProjection()
|
||||||
|
}
|
||||||
|
return TypeConstructorSubstitution.createByConstructorsMap(substitutionMap).buildSubstitutor()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun addSubtypeConstraint(subType: UnwrappedType, superType: UnwrappedType) {
|
||||||
|
csBuilder.addSubtypeConstraint(subType, superType, SimpleConstraintSystemConstraintPosition)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hasContradiction() = csBuilder.hasContradiction
|
||||||
|
|
||||||
|
private object ThrowableKotlinCall : KotlinCall {
|
||||||
|
override val callKind: KotlinCallKind get() = throw UnsupportedOperationException()
|
||||||
|
override val explicitReceiver: ReceiverKotlinCallArgument? get() = throw UnsupportedOperationException()
|
||||||
|
override val name: Name get() = throw UnsupportedOperationException()
|
||||||
|
override val typeArguments: List<TypeArgument> get() = throw UnsupportedOperationException()
|
||||||
|
override val argumentsInParenthesis: List<KotlinCallArgument> get() = throw UnsupportedOperationException()
|
||||||
|
override val externalArgument: KotlinCallArgument? get() = throw UnsupportedOperationException()
|
||||||
|
override val isInfixCall: Boolean get() = throw UnsupportedOperationException()
|
||||||
|
override val isOperatorCall: Boolean get() = throw UnsupportedOperationException()
|
||||||
|
}
|
||||||
|
}
|
||||||
+137
@@ -0,0 +1,137 @@
|
|||||||
|
/*
|
||||||
|
* 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.inference.components
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.types.*
|
||||||
|
import org.jetbrains.kotlin.types.checker.*
|
||||||
|
import org.jetbrains.kotlin.types.typeUtil.builtIns
|
||||||
|
|
||||||
|
abstract class TypeCheckerContextForConstraintSystem : TypeCheckerContext(errorTypeEqualsToAnything = true, allowedTypeVariable = false) {
|
||||||
|
|
||||||
|
abstract fun isMyTypeVariable(type: SimpleType): Boolean
|
||||||
|
|
||||||
|
// super and sub type isSingleClassifierType
|
||||||
|
abstract fun addUpperConstraint(typeVariable: TypeConstructor, superType: UnwrappedType)
|
||||||
|
abstract fun addLowerConstraint(typeVariable: TypeConstructor, subType: UnwrappedType)
|
||||||
|
|
||||||
|
override final fun addSubtypeConstraint(subType: UnwrappedType, superType: UnwrappedType): Boolean? {
|
||||||
|
assertInputTypes(subType, superType)
|
||||||
|
|
||||||
|
var answer: Boolean? = null
|
||||||
|
|
||||||
|
if (superType.anyBound(this::isMyTypeVariable)) {
|
||||||
|
answer = simplifyLowerConstraint(superType, subType)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (subType.anyBound(this::isMyTypeVariable)) {
|
||||||
|
return simplifyUpperConstraint(subType, superType) && (answer ?: true)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return simplifyConstraintForPossibleIntersectionSubType(subType, superType) ?: answer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Foo <: T! <=> Foo <: T? <=> Foo & Any <: T
|
||||||
|
* Foo <: T? <=> Foo & Any <: T
|
||||||
|
* Foo <: T -- leave as is
|
||||||
|
*/
|
||||||
|
fun simplifyLowerConstraint(typeVariable: UnwrappedType, subType: UnwrappedType): Boolean {
|
||||||
|
@Suppress("NAME_SHADOWING")
|
||||||
|
val typeVariable = typeVariable.upperIfFlexible()
|
||||||
|
|
||||||
|
if (typeVariable.isMarkedNullable) {
|
||||||
|
addLowerConstraint(typeVariable.constructor, intersectTypes(listOf(subType, subType.builtIns.anyType)))
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
addLowerConstraint(typeVariable.constructor, subType)
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* T! <: Foo <=> T <: Foo
|
||||||
|
* T? <: Foo <=> T <: Foo && Nothing? <: Foo
|
||||||
|
* T <: Foo -- leave as is
|
||||||
|
*/
|
||||||
|
fun simplifyUpperConstraint(typeVariable: UnwrappedType, superType: UnwrappedType): Boolean {
|
||||||
|
@Suppress("NAME_SHADOWING")
|
||||||
|
val typeVariable = typeVariable.lowerIfFlexible()
|
||||||
|
|
||||||
|
addUpperConstraint(typeVariable.constructor, superType)
|
||||||
|
|
||||||
|
if (typeVariable.isMarkedNullable) {
|
||||||
|
// here is important that superType is singleClassifierType
|
||||||
|
return if (superType.anyBound(this::isMyTypeVariable)) {
|
||||||
|
simplifyLowerConstraint(superType, typeVariable)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
isSubtypeOfByTypeChecker(typeVariable.builtIns.nullableNothingType, superType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
fun simplifyConstraintForPossibleIntersectionSubType(subType: UnwrappedType, superType: UnwrappedType): Boolean? {
|
||||||
|
@Suppress("NAME_SHADOWING")
|
||||||
|
val subType = subType.lowerIfFlexible()
|
||||||
|
|
||||||
|
if (!subType.isIntersectionType) return null
|
||||||
|
|
||||||
|
assert(!subType.isMarkedNullable) { "Intersection type should not be marked nullable!: $subType" }
|
||||||
|
|
||||||
|
// TODO: may be we lose flexibility here
|
||||||
|
val subIntersectionTypes = (subType.constructor as IntersectionTypeConstructor).supertypes.map { it.lowerIfFlexible() }
|
||||||
|
|
||||||
|
val typeVariables = subIntersectionTypes.filter(this::isMyTypeVariable).takeIf { it.isNotEmpty() } ?: return null
|
||||||
|
val notTypeVariables = subIntersectionTypes.filterNot(this::isMyTypeVariable)
|
||||||
|
|
||||||
|
// todo: may be we can do better then that.
|
||||||
|
if (notTypeVariables.isNotEmpty() && NewKotlinTypeChecker.isSubtypeOf(intersectTypes(notTypeVariables), superType)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return typeVariables.all { simplifyUpperConstraint(it, superType) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isSubtypeOfByTypeChecker(subType: UnwrappedType, superType: UnwrappedType) =
|
||||||
|
with(NewKotlinTypeChecker) { this@TypeCheckerContextForConstraintSystem.isSubtypeOf(subType, superType) }
|
||||||
|
|
||||||
|
private fun assertInputTypes(subType: UnwrappedType, superType: UnwrappedType) {
|
||||||
|
fun correctSubType(subType: SimpleType) = subType.isSingleClassifierType || subType.isIntersectionType || isMyTypeVariable(subType)
|
||||||
|
fun correctSuperType(superType: SimpleType) = superType.isSingleClassifierType || isMyTypeVariable(superType)
|
||||||
|
|
||||||
|
assert(subType.bothBounds(::correctSubType)) {
|
||||||
|
"Not singleClassifierType and not intersection subType: $subType"
|
||||||
|
}
|
||||||
|
assert(superType.bothBounds(::correctSuperType)) {
|
||||||
|
"Not singleClassifierType superType: $superType"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private inline fun UnwrappedType.bothBounds(f: (SimpleType) -> Boolean) = when (this) {
|
||||||
|
is SimpleType -> f(this)
|
||||||
|
is FlexibleType -> f(lowerBound) && f(upperBound)
|
||||||
|
}
|
||||||
|
|
||||||
|
private inline fun UnwrappedType.anyBound(f: (SimpleType) -> Boolean) = when (this) {
|
||||||
|
is SimpleType -> f(this)
|
||||||
|
is FlexibleType -> f(lowerBound) || f(upperBound)
|
||||||
|
}
|
||||||
|
}
|
||||||
+63
@@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
* 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.inference.model
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.model.*
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.tower.ResolutionCandidateApplicability
|
||||||
|
import org.jetbrains.kotlin.types.UnwrappedType
|
||||||
|
|
||||||
|
|
||||||
|
sealed class ConstraintPosition
|
||||||
|
|
||||||
|
class ExplicitTypeParameterConstraintPosition(val typeArgument: SimpleTypeArgument) : ConstraintPosition() {
|
||||||
|
override fun toString() = "TypeParameter $typeArgument"
|
||||||
|
}
|
||||||
|
class ExpectedTypeConstraintPosition(val topLevelCall: KotlinCall) : ConstraintPosition() {
|
||||||
|
override fun toString() = "ExpectedType for call $topLevelCall"
|
||||||
|
}
|
||||||
|
class DeclaredUpperBoundConstraintPosition(val typeParameterDescriptor: TypeParameterDescriptor) : ConstraintPosition() {
|
||||||
|
override fun toString() = "DeclaredUpperBound ${typeParameterDescriptor.name} from ${typeParameterDescriptor.containingDeclaration}"
|
||||||
|
}
|
||||||
|
class ArgumentConstraintPosition(val argument: KotlinCallArgument) : ConstraintPosition() {
|
||||||
|
override fun toString() = "Argument $argument"
|
||||||
|
}
|
||||||
|
class FixVariableConstraintPosition(val variable: NewTypeVariable) : ConstraintPosition() {
|
||||||
|
override fun toString() = "Fix variable $variable"
|
||||||
|
}
|
||||||
|
|
||||||
|
class IncorporationConstraintPosition(val from: ConstraintPosition) : ConstraintPosition() {
|
||||||
|
override fun toString() = "Incorporate $from"
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated("Should be used only in SimpleConstraintSystemImpl")
|
||||||
|
object SimpleConstraintSystemConstraintPosition : ConstraintPosition()
|
||||||
|
|
||||||
|
|
||||||
|
class NewConstraintError(val lowerType: UnwrappedType, val upperType: UnwrappedType, val position: ConstraintPosition):
|
||||||
|
KotlinCallDiagnostic(ResolutionCandidateApplicability.INAPPLICABLE) {
|
||||||
|
override fun report(reporter: DiagnosticReporter) = reporter.constraintError(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
class CapturedTypeFromSubtyping(val typeVariable: NewTypeVariable, val constraintType: UnwrappedType, val position: ConstraintPosition) :
|
||||||
|
KotlinCallDiagnostic(ResolutionCandidateApplicability.INAPPLICABLE) {
|
||||||
|
override fun report(reporter: DiagnosticReporter) = reporter.constraintError(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
class NotEnoughInformationForTypeParameter(val typeVariable: NewTypeVariable) : KotlinCallDiagnostic(ResolutionCandidateApplicability.INAPPLICABLE) {
|
||||||
|
override fun report(reporter: DiagnosticReporter) = reporter.constraintError(this)
|
||||||
|
}
|
||||||
+134
@@ -0,0 +1,134 @@
|
|||||||
|
/*
|
||||||
|
* 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.inference.model
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.substitute
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.model.ResolvedKotlinCall
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.model.KotlinCallDiagnostic
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.model.ResolvedLambdaArgument
|
||||||
|
import org.jetbrains.kotlin.types.TypeConstructor
|
||||||
|
import org.jetbrains.kotlin.types.TypeSubstitutor
|
||||||
|
import org.jetbrains.kotlin.types.UnwrappedType
|
||||||
|
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Every type variable can be in the following states:
|
||||||
|
* - not fixed => there is several constraints for this type variable(possible no one).
|
||||||
|
* for this type variable we have VariableWithConstraints in map notFixedTypeVariables
|
||||||
|
* - fixed to proper type or not proper type. For such type variable there is no VariableWithConstraints in notFixedTypeVariables.
|
||||||
|
* Also we should guaranty that there is no other constraints in other VariableWithConstraints which depends on this fixed type variable.
|
||||||
|
*
|
||||||
|
* Note: fixedTypeVariables can contains a proper and not proper type.
|
||||||
|
*
|
||||||
|
* Fixing procedure(to proper types). First of all we should determinate fixing order.
|
||||||
|
* After it, for every type variable we do the following:
|
||||||
|
* - determinate result proper type
|
||||||
|
* - add equality constraint, for example: T = Int
|
||||||
|
* - run incorporation and generate all new constraints
|
||||||
|
* - after is we remove VariableWithConstraints for type variable T from map notFixedTypeVariables
|
||||||
|
* - also we remove all constraint in other variable which contains T
|
||||||
|
* - add result type to fixedTypeVariables.
|
||||||
|
*
|
||||||
|
* Note fixing procedure to not proper type the same. The only difference in determination result type.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
interface ConstraintStorage {
|
||||||
|
val allTypeVariables: Map<TypeConstructor, NewTypeVariable>
|
||||||
|
val notFixedTypeVariables: Map<TypeConstructor, VariableWithConstraints>
|
||||||
|
val initialConstraints: List<InitialConstraint>
|
||||||
|
val maxTypeDepthFromInitialConstraints: Int
|
||||||
|
val errors: List<KotlinCallDiagnostic>
|
||||||
|
val fixedTypeVariables: Map<TypeConstructor, UnwrappedType>
|
||||||
|
val lambdaArguments: List<ResolvedLambdaArgument>
|
||||||
|
val innerCalls: List<ResolvedKotlinCall.OnlyResolvedKotlinCall>
|
||||||
|
|
||||||
|
object Empty : ConstraintStorage {
|
||||||
|
override val allTypeVariables: Map<TypeConstructor, NewTypeVariable> get() = emptyMap()
|
||||||
|
override val notFixedTypeVariables: Map<TypeConstructor, VariableWithConstraints> get() = emptyMap()
|
||||||
|
override val initialConstraints: List<InitialConstraint> get() = emptyList()
|
||||||
|
override val maxTypeDepthFromInitialConstraints: Int get() = 1
|
||||||
|
override val errors: List<KotlinCallDiagnostic> get() = emptyList()
|
||||||
|
override val fixedTypeVariables: Map<TypeConstructor, UnwrappedType> get() = emptyMap()
|
||||||
|
override val lambdaArguments: List<ResolvedLambdaArgument> get() = emptyList()
|
||||||
|
override val innerCalls: List<ResolvedKotlinCall.OnlyResolvedKotlinCall> get() = emptyList()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class ConstraintKind {
|
||||||
|
LOWER,
|
||||||
|
UPPER,
|
||||||
|
EQUALITY
|
||||||
|
}
|
||||||
|
|
||||||
|
class Constraint(
|
||||||
|
val kind: ConstraintKind,
|
||||||
|
val type: UnwrappedType, // flexible types here is allowed
|
||||||
|
val position: ConstraintPosition,
|
||||||
|
val typeHashCode: Int = type.hashCode()
|
||||||
|
) {
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
if (this === other) return true
|
||||||
|
if (other?.javaClass != javaClass) return false
|
||||||
|
|
||||||
|
other as Constraint
|
||||||
|
|
||||||
|
if (typeHashCode != other.typeHashCode) return false
|
||||||
|
if (kind != other.kind) return false
|
||||||
|
if (position != other.position) return false
|
||||||
|
if (type != other.type) return false
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode() = typeHashCode
|
||||||
|
|
||||||
|
override fun toString() = "$kind($type) from $position"
|
||||||
|
}
|
||||||
|
|
||||||
|
interface VariableWithConstraints {
|
||||||
|
val typeVariable: NewTypeVariable
|
||||||
|
val constraints: List<Constraint>
|
||||||
|
}
|
||||||
|
|
||||||
|
class InitialConstraint(
|
||||||
|
val a: UnwrappedType,
|
||||||
|
val b: UnwrappedType,
|
||||||
|
val constraintKind: ConstraintKind, // see [checkConstraint]
|
||||||
|
val position: ConstraintPosition
|
||||||
|
) {
|
||||||
|
override fun toString(): String {
|
||||||
|
val sign =
|
||||||
|
when (constraintKind) {
|
||||||
|
ConstraintKind.EQUALITY -> "=="
|
||||||
|
ConstraintKind.LOWER -> ":>"
|
||||||
|
ConstraintKind.UPPER -> "<:"
|
||||||
|
}
|
||||||
|
return "$a $sign $b from $position"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun InitialConstraint.checkConstraint(substitutor: TypeSubstitutor): Boolean {
|
||||||
|
val newA = substitutor.substitute(a)
|
||||||
|
val newB = substitutor.substitute(a)
|
||||||
|
val typeChecker = KotlinTypeChecker.DEFAULT
|
||||||
|
return when (constraintKind) {
|
||||||
|
ConstraintKind.EQUALITY -> typeChecker.equalTypes(newA, newB)
|
||||||
|
ConstraintKind.UPPER -> typeChecker.isSubtypeOf(newA, newB)
|
||||||
|
ConstraintKind.LOWER -> typeChecker.isSubtypeOf(newB, newA)
|
||||||
|
}
|
||||||
|
}
|
||||||
+97
@@ -0,0 +1,97 @@
|
|||||||
|
/*
|
||||||
|
* 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.inference.model
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.model.ResolvedKotlinCall
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.model.KotlinCallDiagnostic
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.model.ResolvedLambdaArgument
|
||||||
|
import org.jetbrains.kotlin.types.TypeConstructor
|
||||||
|
import org.jetbrains.kotlin.types.UnwrappedType
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
|
||||||
|
class MutableVariableWithConstraints(
|
||||||
|
override val typeVariable: NewTypeVariable,
|
||||||
|
constraints: Collection<Constraint> = emptyList()
|
||||||
|
) : VariableWithConstraints {
|
||||||
|
override val constraints: List<Constraint> get() = mutableConstraints
|
||||||
|
private val mutableConstraints = MyArrayList(constraints)
|
||||||
|
|
||||||
|
// return new actual constraint, if this constraint is new
|
||||||
|
fun addConstraint(constraint: Constraint): Constraint? {
|
||||||
|
val previousConstraintWithSameType = constraints.filter { it.typeHashCode == constraint.typeHashCode && it.type == constraint.type }
|
||||||
|
|
||||||
|
if (previousConstraintWithSameType.any { newConstraintIsUseless(it.kind, constraint.kind) }) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
val actualConstraint = if (previousConstraintWithSameType.isNotEmpty()) {
|
||||||
|
// i.e. previous is LOWER and new is UPPER or opposite situation
|
||||||
|
Constraint(ConstraintKind.EQUALITY, constraint.type, constraint.position, constraint.typeHashCode)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
constraint
|
||||||
|
}
|
||||||
|
mutableConstraints.add(actualConstraint)
|
||||||
|
return actualConstraint
|
||||||
|
}
|
||||||
|
|
||||||
|
fun removeLastConstraints(shouldRemove: (Constraint) -> Boolean) {
|
||||||
|
mutableConstraints.removeLast(shouldRemove)
|
||||||
|
}
|
||||||
|
|
||||||
|
// todo optimize it!
|
||||||
|
fun removeConstrains(shouldRemove: (Constraint) -> Boolean) {
|
||||||
|
val newConstraints = mutableConstraints.filter { !shouldRemove(it) }
|
||||||
|
mutableConstraints.clear()
|
||||||
|
mutableConstraints.addAll(newConstraints)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun newConstraintIsUseless(oldKind: ConstraintKind, newKind: ConstraintKind) =
|
||||||
|
when (oldKind) {
|
||||||
|
ConstraintKind.EQUALITY -> true
|
||||||
|
ConstraintKind.LOWER -> newKind == ConstraintKind.LOWER
|
||||||
|
ConstraintKind.UPPER -> newKind == ConstraintKind.UPPER
|
||||||
|
}
|
||||||
|
|
||||||
|
private class MyArrayList<E>(c: Collection<E>): ArrayList<E>(c) {
|
||||||
|
fun removeLast(predicate: (E) -> Boolean) {
|
||||||
|
val newSize = indexOfLast { !predicate(it) } + 1
|
||||||
|
|
||||||
|
if (newSize != size) {
|
||||||
|
removeRange(newSize, size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return "Constraints for $typeVariable"
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// todo may be we should use LinkedHasMap
|
||||||
|
class MutableConstraintStorage : ConstraintStorage {
|
||||||
|
override val allTypeVariables: MutableMap<TypeConstructor, NewTypeVariable> = HashMap()
|
||||||
|
override val notFixedTypeVariables: MutableMap<TypeConstructor, MutableVariableWithConstraints> = HashMap()
|
||||||
|
override val initialConstraints: MutableList<InitialConstraint> = ArrayList()
|
||||||
|
override var maxTypeDepthFromInitialConstraints: Int = 1
|
||||||
|
override val errors: MutableList<KotlinCallDiagnostic> = ArrayList()
|
||||||
|
override val fixedTypeVariables: MutableMap<TypeConstructor, UnwrappedType> = HashMap()
|
||||||
|
override val lambdaArguments: MutableList<ResolvedLambdaArgument> = ArrayList()
|
||||||
|
override val innerCalls: MutableList<ResolvedKotlinCall.OnlyResolvedKotlinCall> = ArrayList()
|
||||||
|
}
|
||||||
+254
@@ -0,0 +1,254 @@
|
|||||||
|
/*
|
||||||
|
* 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.inference.model
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.components.KotlinCallCompleter
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.NewConstraintSystem
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.buildCurrentSubstitutor
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.components.ConstraintInjector
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.components.FixationOrderCalculator
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.components.ResultTypeResolver
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.model.KotlinCallDiagnostic
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.model.ResolvedKotlinCall
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.model.ResolvedLambdaArgument
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.tower.isSuccess
|
||||||
|
import org.jetbrains.kotlin.types.*
|
||||||
|
import org.jetbrains.kotlin.types.typeUtil.asTypeProjection
|
||||||
|
import org.jetbrains.kotlin.types.typeUtil.contains
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
class NewConstraintSystemImpl(val constraintInjector: ConstraintInjector, val resultTypeResolver: ResultTypeResolver):
|
||||||
|
NewConstraintSystem,
|
||||||
|
ConstraintSystemBuilder,
|
||||||
|
ConstraintInjector.Context,
|
||||||
|
ResultTypeResolver.Context,
|
||||||
|
KotlinCallCompleter.Context,
|
||||||
|
FixationOrderCalculator.Context
|
||||||
|
{
|
||||||
|
val storage = MutableConstraintStorage()
|
||||||
|
private var state = State.BUILDING
|
||||||
|
|
||||||
|
private enum class State {
|
||||||
|
BUILDING,
|
||||||
|
FREEZED,
|
||||||
|
COMPLETION
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun checkState(vararg allowedState: State) {
|
||||||
|
assert(state in allowedState) {
|
||||||
|
"State $state is not allowed. AllowedStates: ${allowedState.joinToString()}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override val diagnostics: List<KotlinCallDiagnostic>
|
||||||
|
get() = storage.errors
|
||||||
|
|
||||||
|
override fun getBuilder() = apply { checkState(State.BUILDING, State.COMPLETION) }
|
||||||
|
|
||||||
|
override fun asConstraintInjectorContext() = apply { checkState(State.BUILDING, State.COMPLETION) }
|
||||||
|
|
||||||
|
override fun asReadOnlyStorage(): ConstraintStorage {
|
||||||
|
checkState(State.BUILDING, State.FREEZED)
|
||||||
|
state = State.FREEZED
|
||||||
|
return storage
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun asCallCompleterContext(): KotlinCallCompleter.Context {
|
||||||
|
checkState(State.BUILDING, State.COMPLETION)
|
||||||
|
state = State.COMPLETION
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConstraintSystemBuilder
|
||||||
|
override fun registerVariable(variable: NewTypeVariable) {
|
||||||
|
checkState(State.BUILDING, State.COMPLETION)
|
||||||
|
|
||||||
|
storage.allTypeVariables[variable.freshTypeConstructor] = variable
|
||||||
|
storage.notFixedTypeVariables[variable.freshTypeConstructor] = MutableVariableWithConstraints(variable)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun addSubtypeConstraint(lowerType: UnwrappedType, upperType: UnwrappedType, position: ConstraintPosition) =
|
||||||
|
constraintInjector.addInitialSubtypeConstraint(apply { checkState(State.BUILDING, State.COMPLETION) }, lowerType, upperType, position)
|
||||||
|
|
||||||
|
override fun addEqualityConstraint(a: UnwrappedType, b: UnwrappedType, position: ConstraintPosition) =
|
||||||
|
constraintInjector.addInitialEqualityConstraint(apply { checkState(State.BUILDING, State.COMPLETION) }, a, b, position)
|
||||||
|
|
||||||
|
override fun addLambdaArgument(resolvedLambdaArgument: ResolvedLambdaArgument) {
|
||||||
|
checkState(State.BUILDING, State.COMPLETION)
|
||||||
|
storage.lambdaArguments.add(resolvedLambdaArgument)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun addSubtypeConstraintIfCompatible(lowerType: UnwrappedType, upperType: UnwrappedType, position: ConstraintPosition): Boolean {
|
||||||
|
checkState(State.BUILDING, State.COMPLETION)
|
||||||
|
|
||||||
|
if (hasContradiction) return false
|
||||||
|
addSubtypeConstraint(lowerType, upperType, position)
|
||||||
|
if (!hasContradiction) return true
|
||||||
|
|
||||||
|
val shouldRemove = { c: Constraint -> c.position === position ||
|
||||||
|
(c.position is IncorporationConstraintPosition && c.position.from === position) }
|
||||||
|
|
||||||
|
for (variableWithConstraint in storage.notFixedTypeVariables.values) {
|
||||||
|
variableWithConstraint.removeLastConstraints(shouldRemove)
|
||||||
|
}
|
||||||
|
storage.errors.clear()
|
||||||
|
storage.initialConstraints.removeAt(storage.initialConstraints.lastIndex)
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getVariablesForFixation(): Map<NewTypeVariable, UnwrappedType> {
|
||||||
|
val fixedVariables = LinkedHashMap<NewTypeVariable, UnwrappedType>()
|
||||||
|
|
||||||
|
for (variableWithConstrains in storage.notFixedTypeVariables.values) {
|
||||||
|
val resultType = resultTypeResolver.findResultIfThereIsEqualsConstraint(apply { checkState(State.BUILDING) }, variableWithConstrains,
|
||||||
|
allowedFixToNotProperType = false)
|
||||||
|
if (resultType != null) {
|
||||||
|
fixedVariables[variableWithConstrains.typeVariable] = resultType
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fixedVariables
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun simplify(): TypeSubstitutor {
|
||||||
|
checkState(State.BUILDING)
|
||||||
|
|
||||||
|
var fixedVariables = getVariablesForFixation()
|
||||||
|
while (fixedVariables.isNotEmpty()) {
|
||||||
|
for ((variable, resultType) in fixedVariables) {
|
||||||
|
fixVariable(variable, resultType)
|
||||||
|
}
|
||||||
|
fixedVariables = getVariablesForFixation()
|
||||||
|
}
|
||||||
|
|
||||||
|
return storage.buildCurrentSubstitutor()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConstraintSystemBuilder, KotlinCallCompleter.Context
|
||||||
|
override val hasContradiction: Boolean
|
||||||
|
get() = diagnostics.any { !it.candidateApplicability.isSuccess }.apply { checkState(State.BUILDING, State.COMPLETION) }
|
||||||
|
|
||||||
|
override fun addInnerCall(innerCall: ResolvedKotlinCall.OnlyResolvedKotlinCall) {
|
||||||
|
checkState(State.BUILDING, State.COMPLETION)
|
||||||
|
storage.innerCalls.add(innerCall)
|
||||||
|
|
||||||
|
val otherSystem = innerCall.candidate.lastCall.constraintSystem.asReadOnlyStorage()
|
||||||
|
storage.allTypeVariables.putAll(otherSystem.allTypeVariables)
|
||||||
|
for ((variable, constraints) in otherSystem.notFixedTypeVariables) {
|
||||||
|
notFixedTypeVariables[variable] = MutableVariableWithConstraints(constraints.typeVariable, constraints.constraints)
|
||||||
|
}
|
||||||
|
storage.initialConstraints.addAll(otherSystem.initialConstraints)
|
||||||
|
storage.maxTypeDepthFromInitialConstraints = Math.max(storage.maxTypeDepthFromInitialConstraints, otherSystem.maxTypeDepthFromInitialConstraints)
|
||||||
|
storage.errors.addAll(otherSystem.errors)
|
||||||
|
storage.fixedTypeVariables.putAll(otherSystem.fixedTypeVariables)
|
||||||
|
storage.lambdaArguments.addAll(otherSystem.lambdaArguments)
|
||||||
|
storage.innerCalls.addAll(otherSystem.innerCalls)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ResultTypeResolver.Context, ConstraintSystemBuilder
|
||||||
|
override fun isProperType(type: UnwrappedType): Boolean {
|
||||||
|
checkState(State.BUILDING, State.COMPLETION)
|
||||||
|
return !type.contains {
|
||||||
|
storage.allTypeVariables.containsKey(it.constructor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConstraintInjector.Context
|
||||||
|
override val allTypeVariables: Map<TypeConstructor, NewTypeVariable> get() {
|
||||||
|
checkState(State.BUILDING, State.COMPLETION)
|
||||||
|
return storage.allTypeVariables
|
||||||
|
}
|
||||||
|
|
||||||
|
override var maxTypeDepthFromInitialConstraints: Int
|
||||||
|
get() = storage.maxTypeDepthFromInitialConstraints
|
||||||
|
set(value) {
|
||||||
|
checkState(State.BUILDING, State.COMPLETION)
|
||||||
|
storage.maxTypeDepthFromInitialConstraints = value
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun addInitialConstraint(initialConstraint: InitialConstraint) {
|
||||||
|
checkState(State.BUILDING, State.COMPLETION)
|
||||||
|
storage.initialConstraints.add(initialConstraint)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConstraintInjector.Context, FixationOrderCalculator.Context
|
||||||
|
override val notFixedTypeVariables: MutableMap<TypeConstructor, MutableVariableWithConstraints> get() {
|
||||||
|
checkState(State.BUILDING, State.COMPLETION)
|
||||||
|
return storage.notFixedTypeVariables
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConstraintInjector.Context, KotlinCallCompleter.Context
|
||||||
|
override fun addError(error: KotlinCallDiagnostic) {
|
||||||
|
checkState(State.BUILDING, State.COMPLETION)
|
||||||
|
storage.errors.add(error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FixationOrderCalculator.Context, KotlinCallCompleter.Context
|
||||||
|
override val lambdaArguments: List<ResolvedLambdaArgument> get() {
|
||||||
|
checkState(State.COMPLETION)
|
||||||
|
return storage.lambdaArguments
|
||||||
|
}
|
||||||
|
|
||||||
|
// KotlinCallCompleter.Context
|
||||||
|
override fun asResultTypeResolverContext() = apply { checkState(State.COMPLETION) }
|
||||||
|
|
||||||
|
override fun asFixationOrderCalculatorContext() = apply { checkState(State.COMPLETION) }
|
||||||
|
|
||||||
|
override fun fixVariable(variable: NewTypeVariable, resultType: UnwrappedType) {
|
||||||
|
checkState(State.BUILDING, State.COMPLETION)
|
||||||
|
|
||||||
|
constraintInjector.addInitialEqualityConstraint(this, variable.defaultType, resultType, FixVariableConstraintPosition(variable))
|
||||||
|
notFixedTypeVariables.remove(variable.freshTypeConstructor)
|
||||||
|
|
||||||
|
for (variableWithConstraint in notFixedTypeVariables.values) {
|
||||||
|
variableWithConstraint.removeConstrains {
|
||||||
|
it.type.contains { it.constructor == variable.freshTypeConstructor }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
storage.fixedTypeVariables[variable.freshTypeConstructor] = resultType
|
||||||
|
}
|
||||||
|
|
||||||
|
override val innerCalls: List<ResolvedKotlinCall.OnlyResolvedKotlinCall> get() {
|
||||||
|
checkState(State.COMPLETION)
|
||||||
|
return storage.innerCalls
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun canBeProper(type: UnwrappedType): Boolean {
|
||||||
|
checkState(State.COMPLETION)
|
||||||
|
return !type.contains { storage.notFixedTypeVariables.containsKey(it.constructor) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun buildCurrentSubstitutor(): TypeSubstitutor {
|
||||||
|
checkState(State.COMPLETION)
|
||||||
|
return storage.buildCurrentSubstitutor()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun buildResultingSubstitutor(): TypeSubstitutor {
|
||||||
|
checkState(State.COMPLETION)
|
||||||
|
val currentSubstitutorMap = storage.fixedTypeVariables.entries.associate {
|
||||||
|
it.key to it.value.asTypeProjection()
|
||||||
|
}
|
||||||
|
val uninferredSubstitutorMap = storage.notFixedTypeVariables.entries.associate { (freshTypeConstructor, typeVariable) ->
|
||||||
|
freshTypeConstructor to ErrorUtils.createErrorTypeWithCustomConstructor("Uninferred type", typeVariable.typeVariable.freshTypeConstructor).asTypeProjection()
|
||||||
|
}
|
||||||
|
|
||||||
|
return TypeConstructorSubstitution.createByConstructorsMap(currentSubstitutorMap + uninferredSubstitutorMap).buildSubstitutor()
|
||||||
|
}
|
||||||
|
}
|
||||||
+76
@@ -0,0 +1,76 @@
|
|||||||
|
/*
|
||||||
|
* 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.inference.model
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||||
|
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.model.KotlinCall
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.model.LambdaKotlinCallArgument
|
||||||
|
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
||||||
|
import org.jetbrains.kotlin.types.*
|
||||||
|
import org.jetbrains.kotlin.types.checker.NewTypeVariableConstructor
|
||||||
|
|
||||||
|
|
||||||
|
class TypeVariableTypeConstructor(private val builtIns: KotlinBuiltIns, val debugName: String): TypeConstructor, NewTypeVariableConstructor {
|
||||||
|
override fun getParameters(): List<TypeParameterDescriptor> = emptyList()
|
||||||
|
override fun getSupertypes(): Collection<KotlinType> = emptyList()
|
||||||
|
override fun isFinal(): Boolean = false
|
||||||
|
override fun isDenotable(): Boolean = false
|
||||||
|
override fun getDeclarationDescriptor(): ClassifierDescriptor? = null
|
||||||
|
|
||||||
|
override fun getBuiltIns() = builtIns
|
||||||
|
|
||||||
|
override fun toString() = "TypeVariable($debugName)"
|
||||||
|
}
|
||||||
|
|
||||||
|
sealed class NewTypeVariable(builtIns: KotlinBuiltIns, name: String) {
|
||||||
|
val freshTypeConstructor: TypeConstructor = TypeVariableTypeConstructor(builtIns, name)
|
||||||
|
|
||||||
|
val defaultType: SimpleType = KotlinTypeFactory.simpleType(
|
||||||
|
Annotations.EMPTY, freshTypeConstructor, arguments = emptyList(),
|
||||||
|
nullable = false, memberScope = ErrorUtils.createErrorScope("Type variable", true))
|
||||||
|
|
||||||
|
override fun toString() = freshTypeConstructor.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
class TypeVariableFromCallableDescriptor(
|
||||||
|
val call: KotlinCall,
|
||||||
|
val originalTypeParameter: TypeParameterDescriptor
|
||||||
|
) : NewTypeVariable(originalTypeParameter.builtIns, originalTypeParameter.name.identifier)
|
||||||
|
|
||||||
|
class LambdaTypeVariable(
|
||||||
|
val lambdaArgument: LambdaKotlinCallArgument,
|
||||||
|
val kind: Kind,
|
||||||
|
builtIns: KotlinBuiltIns
|
||||||
|
) : NewTypeVariable(builtIns, createDebugName(lambdaArgument, kind)) {
|
||||||
|
enum class Kind {
|
||||||
|
RECEIVER,
|
||||||
|
PARAMETER,
|
||||||
|
RETURN_TYPE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createDebugName(lambdaArgument: LambdaKotlinCallArgument, kind: LambdaTypeVariable.Kind): String {
|
||||||
|
val text = lambdaArgument.toString().let { it.substring(0..(Math.min(20, it.lastIndex))) }
|
||||||
|
return when (kind) {
|
||||||
|
LambdaTypeVariable.Kind.RECEIVER -> "Receiver[$text]"
|
||||||
|
LambdaTypeVariable.Kind.PARAMETER -> "Parameter[$text]"
|
||||||
|
LambdaTypeVariable.Kind.RETURN_TYPE -> "Result[$text]"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
* 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.model
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValueWithSmartCastInfo
|
||||||
|
import org.jetbrains.kotlin.resolve.scopes.receivers.TransientReceiver
|
||||||
|
import org.jetbrains.kotlin.types.checker.prepareArgumentTypeRegardingCaptureTypes
|
||||||
|
|
||||||
|
|
||||||
|
class FakeKotlinCallArgumentForCallableReference(
|
||||||
|
val callableReference: ChosenCallableReferenceDescriptor,
|
||||||
|
val index: Int
|
||||||
|
) : KotlinCallArgument {
|
||||||
|
override val isSpread: Boolean get() = false
|
||||||
|
override val argumentName: Name? get() = null
|
||||||
|
}
|
||||||
|
|
||||||
|
class ReceiverExpressionKotlinCallArgument private constructor(
|
||||||
|
override val receiver: ReceiverValueWithSmartCastInfo,
|
||||||
|
override val isSafeCall: Boolean = false,
|
||||||
|
val isVariableReceiverForInvoke: Boolean = false
|
||||||
|
) : ExpressionKotlinCallArgument {
|
||||||
|
override val isSpread: Boolean get() = false
|
||||||
|
override val argumentName: Name? get() = null
|
||||||
|
override fun toString() = "$receiver" + if(isSafeCall) "?" else ""
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
// we create ReceiverArgument and fix capture types
|
||||||
|
operator fun invoke(
|
||||||
|
receiver: ReceiverValueWithSmartCastInfo,
|
||||||
|
isSafeCall: Boolean = false,
|
||||||
|
isVariableReceiverForInvoke: Boolean = false
|
||||||
|
): ReceiverExpressionKotlinCallArgument {
|
||||||
|
val newType = prepareArgumentTypeRegardingCaptureTypes(receiver.receiverValue.type.unwrap())
|
||||||
|
val newReceiver = if (newType != null) {
|
||||||
|
ReceiverValueWithSmartCastInfo(receiver.receiverValue.replaceType(newType), receiver.possibleTypes, receiver.isStable)
|
||||||
|
} else receiver
|
||||||
|
|
||||||
|
return ReceiverExpressionKotlinCallArgument(newReceiver, isSafeCall, isVariableReceiverForInvoke)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class EmptyLabeledReturn(builtIns: KotlinBuiltIns) : ExpressionKotlinCallArgument {
|
||||||
|
override val isSpread: Boolean get() = false
|
||||||
|
override val argumentName: Name? get() = null
|
||||||
|
override val receiver = ReceiverValueWithSmartCastInfo(TransientReceiver(builtIns.unitType), emptySet(), true)
|
||||||
|
override val isSafeCall: Boolean get() = false
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* 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.model
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.tower.ResolutionCandidateApplicability
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.tower.ResolutionCandidateApplicability.INAPPLICABLE
|
||||||
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
|
||||||
|
abstract class KotlinCallDiagnostic(val candidateApplicability: ResolutionCandidateApplicability) {
|
||||||
|
abstract fun report(reporter: DiagnosticReporter)
|
||||||
|
}
|
||||||
|
|
||||||
|
interface DiagnosticReporter {
|
||||||
|
fun onExplicitReceiver(diagnostic: KotlinCallDiagnostic)
|
||||||
|
|
||||||
|
fun onCall(diagnostic: KotlinCallDiagnostic)
|
||||||
|
|
||||||
|
fun onTypeArguments(diagnostic: KotlinCallDiagnostic)
|
||||||
|
|
||||||
|
fun onCallName(diagnostic: KotlinCallDiagnostic)
|
||||||
|
|
||||||
|
fun onTypeArgument(typeArgument: TypeArgument, diagnostic: KotlinCallDiagnostic)
|
||||||
|
|
||||||
|
fun onCallReceiver(callReceiver: SimpleKotlinCallArgument, diagnostic: KotlinCallDiagnostic)
|
||||||
|
|
||||||
|
fun onCallArgument(callArgument: KotlinCallArgument, diagnostic: KotlinCallDiagnostic)
|
||||||
|
fun onCallArgumentName(callArgument: KotlinCallArgument, diagnostic: KotlinCallDiagnostic)
|
||||||
|
fun onCallArgumentSpread(callArgument: KotlinCallArgument, diagnostic: KotlinCallDiagnostic)
|
||||||
|
|
||||||
|
fun constraintError(diagnostic: KotlinCallDiagnostic)
|
||||||
|
}
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
/*
|
||||||
|
* 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.model
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
|
||||||
|
|
||||||
|
interface KotlinCall {
|
||||||
|
val callKind: KotlinCallKind
|
||||||
|
|
||||||
|
val explicitReceiver: ReceiverKotlinCallArgument?
|
||||||
|
|
||||||
|
// a.(foo)() -- (foo) is dispatchReceiverForInvoke
|
||||||
|
val dispatchReceiverForInvokeExtension: SimpleKotlinCallArgument? get() = null
|
||||||
|
|
||||||
|
val name: Name
|
||||||
|
|
||||||
|
val typeArguments: List<TypeArgument>
|
||||||
|
|
||||||
|
val argumentsInParenthesis: List<KotlinCallArgument>
|
||||||
|
|
||||||
|
val externalArgument: KotlinCallArgument?
|
||||||
|
|
||||||
|
val isInfixCall: Boolean
|
||||||
|
val isOperatorCall: Boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun SimpleKotlinCallArgument.checkReceiverInvariants() {
|
||||||
|
assert(!isSpread) {
|
||||||
|
"Receiver cannot be a spread: $this"
|
||||||
|
}
|
||||||
|
assert(argumentName == null) {
|
||||||
|
"Argument name should be null for receiver: $this, but it is $argumentName"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun KotlinCall.checkCallInvariants() {
|
||||||
|
assert(explicitReceiver !is LambdaKotlinCallArgument && explicitReceiver !is CallableReferenceKotlinCallArgument) {
|
||||||
|
"Lambda argument or callable reference is not allowed as explicit receiver: $explicitReceiver"
|
||||||
|
}
|
||||||
|
|
||||||
|
(explicitReceiver as? SimpleKotlinCallArgument)?.checkReceiverInvariants()
|
||||||
|
dispatchReceiverForInvokeExtension?.checkReceiverInvariants()
|
||||||
|
|
||||||
|
if (callKind != KotlinCallKind.FUNCTION) {
|
||||||
|
assert(externalArgument == null) {
|
||||||
|
"External argument is not allowed not for function call: $externalArgument."
|
||||||
|
}
|
||||||
|
assert(argumentsInParenthesis.isEmpty()) {
|
||||||
|
"Arguments in parenthesis should be empty for not function call: $this "
|
||||||
|
}
|
||||||
|
assert(dispatchReceiverForInvokeExtension == null) {
|
||||||
|
"Dispatch receiver for invoke should be null for not function call: $dispatchReceiverForInvokeExtension"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
assert(externalArgument == null || !externalArgument!!.isSpread) {
|
||||||
|
"External argument cannot nave spread element: $externalArgument"
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(externalArgument?.argumentName == null) {
|
||||||
|
"Illegal external argument with name: $externalArgument"
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(dispatchReceiverForInvokeExtension == null || !dispatchReceiverForInvokeExtension!!.isSafeCall) {
|
||||||
|
"Dispatch receiver for invoke cannot be safe: $dispatchReceiverForInvokeExtension"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+98
@@ -0,0 +1,98 @@
|
|||||||
|
/*
|
||||||
|
* 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.model
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.tower.CandidateWithBoundDispatchReceiver
|
||||||
|
import org.jetbrains.kotlin.resolve.scopes.receivers.DetailedReceiver
|
||||||
|
import org.jetbrains.kotlin.resolve.scopes.receivers.QualifierReceiver
|
||||||
|
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValueWithSmartCastInfo
|
||||||
|
import org.jetbrains.kotlin.types.UnwrappedType
|
||||||
|
|
||||||
|
|
||||||
|
interface ReceiverKotlinCallArgument {
|
||||||
|
val receiver: DetailedReceiver
|
||||||
|
}
|
||||||
|
|
||||||
|
class QualifierReceiverKotlinCallArgument(override val receiver: QualifierReceiver) : ReceiverKotlinCallArgument {
|
||||||
|
override fun toString() = "$receiver"
|
||||||
|
}
|
||||||
|
|
||||||
|
interface KotlinCallArgument {
|
||||||
|
val isSpread: Boolean
|
||||||
|
val argumentName: Name?
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SimpleKotlinCallArgument : KotlinCallArgument, ReceiverKotlinCallArgument {
|
||||||
|
override val receiver: ReceiverValueWithSmartCastInfo
|
||||||
|
|
||||||
|
val isSafeCall: Boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ExpressionKotlinCallArgument : SimpleKotlinCallArgument
|
||||||
|
|
||||||
|
interface SubKotlinCallArgument : SimpleKotlinCallArgument {
|
||||||
|
val resolvedCall: ResolvedKotlinCall.OnlyResolvedKotlinCall
|
||||||
|
}
|
||||||
|
|
||||||
|
interface LambdaKotlinCallArgument : KotlinCallArgument {
|
||||||
|
override val isSpread: Boolean
|
||||||
|
get() = false
|
||||||
|
|
||||||
|
/**
|
||||||
|
* parametersTypes == null means, that there is no declared arguments
|
||||||
|
* null inside array means that this type is not declared explicitly
|
||||||
|
*/
|
||||||
|
val parametersTypes: Array<UnwrappedType?>?
|
||||||
|
}
|
||||||
|
|
||||||
|
interface FunctionExpression : LambdaKotlinCallArgument {
|
||||||
|
override val parametersTypes: Array<UnwrappedType?>
|
||||||
|
|
||||||
|
// null means that there function can not have receiver
|
||||||
|
val receiverType: UnwrappedType?
|
||||||
|
|
||||||
|
// null means that return type is not declared, for fun(){ ... } returnType == Unit
|
||||||
|
val returnType: UnwrappedType?
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CallableReferenceKotlinCallArgument : KotlinCallArgument {
|
||||||
|
override val isSpread: Boolean
|
||||||
|
get() = false
|
||||||
|
|
||||||
|
// Foo::bar lhsType = Foo. For a::bar where a is expression, this type is null
|
||||||
|
val lhsType: UnwrappedType?
|
||||||
|
|
||||||
|
val constraintStorage: ConstraintStorage
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ChosenCallableReferenceDescriptor : CallableReferenceKotlinCallArgument {
|
||||||
|
val candidate: CandidateWithBoundDispatchReceiver
|
||||||
|
|
||||||
|
val extensionReceiver: ReceiverValueWithSmartCastInfo?
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
interface TypeArgument
|
||||||
|
|
||||||
|
// todo allow '_' in frontend
|
||||||
|
object TypeArgumentPlaceholder : TypeArgument
|
||||||
|
|
||||||
|
interface SimpleTypeArgument: TypeArgument {
|
||||||
|
val type: UnwrappedType
|
||||||
|
}
|
||||||
+102
@@ -0,0 +1,102 @@
|
|||||||
|
/*
|
||||||
|
* 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.model
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.components.CheckArguments
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.components.LambdaAnalyzer
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.components.*
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.components.ConstraintInjector
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.components.ResultTypeResolver
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.tower.CandidateFactory
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.tower.CandidateWithBoundDispatchReceiver
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.tower.ImplicitScopeTower
|
||||||
|
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValueWithSmartCastInfo
|
||||||
|
import org.jetbrains.kotlin.types.ErrorUtils
|
||||||
|
import org.jetbrains.kotlin.types.TypeSubstitutor
|
||||||
|
|
||||||
|
|
||||||
|
class KotlinCallContext(
|
||||||
|
val scopeTower: ImplicitScopeTower,
|
||||||
|
val lambdaAnalyzer: LambdaAnalyzer,
|
||||||
|
val argumentsToParametersMapper: ArgumentsToParametersMapper,
|
||||||
|
val typeArgumentsToParametersMapper: TypeArgumentsToParametersMapper,
|
||||||
|
val resultTypeResolver: ResultTypeResolver,
|
||||||
|
val callableReferenceResolver: CallableReferenceResolver,
|
||||||
|
val constraintInjector: ConstraintInjector
|
||||||
|
)
|
||||||
|
|
||||||
|
class SimpleCandidateFactory(val callContext: KotlinCallContext, val kotlinCall: KotlinCall): CandidateFactory<SimpleKotlinResolutionCandidate> {
|
||||||
|
|
||||||
|
// todo: try something else, because current method is ugly and unstable
|
||||||
|
private fun createReceiverArgument(
|
||||||
|
explicitReceiver: ReceiverKotlinCallArgument?,
|
||||||
|
fromResolution: ReceiverValueWithSmartCastInfo?
|
||||||
|
): SimpleKotlinCallArgument? =
|
||||||
|
explicitReceiver as? SimpleKotlinCallArgument ?: // qualifier receiver cannot be safe
|
||||||
|
fromResolution?.let { ReceiverExpressionKotlinCallArgument(it, isSafeCall = false) } // todo smartcast implicit this
|
||||||
|
|
||||||
|
override fun createCandidate(
|
||||||
|
towerCandidate: CandidateWithBoundDispatchReceiver,
|
||||||
|
explicitReceiverKind: ExplicitReceiverKind,
|
||||||
|
extensionReceiver: ReceiverValueWithSmartCastInfo?
|
||||||
|
): SimpleKotlinResolutionCandidate {
|
||||||
|
val dispatchArgumentReceiver = createReceiverArgument(kotlinCall.getExplicitDispatchReceiver(explicitReceiverKind),
|
||||||
|
towerCandidate.dispatchReceiver)
|
||||||
|
val extensionArgumentReceiver = createReceiverArgument(kotlinCall.getExplicitExtensionReceiver(explicitReceiverKind), extensionReceiver)
|
||||||
|
|
||||||
|
if (ErrorUtils.isError(towerCandidate.descriptor)) {
|
||||||
|
return ErrorKotlinResolutionCandidate(callContext, kotlinCall, explicitReceiverKind, dispatchArgumentReceiver, extensionArgumentReceiver, towerCandidate.descriptor)
|
||||||
|
}
|
||||||
|
|
||||||
|
return SimpleKotlinResolutionCandidate(callContext, kotlinCall, explicitReceiverKind, dispatchArgumentReceiver, extensionArgumentReceiver,
|
||||||
|
towerCandidate.descriptor, towerCandidate.diagnostics)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class KotlinCallKind(vararg resolutionPart: ResolutionPart) {
|
||||||
|
VARIABLE(
|
||||||
|
CheckVisibility,
|
||||||
|
CheckInfixResolutionPart,
|
||||||
|
CheckOperatorResolutionPart,
|
||||||
|
NoTypeArguments,
|
||||||
|
NoArguments,
|
||||||
|
CreteDescriptorWithFreshTypeVariables,
|
||||||
|
CheckExplicitReceiverKindConsistency,
|
||||||
|
CheckReceivers
|
||||||
|
),
|
||||||
|
FUNCTION(
|
||||||
|
CheckVisibility,
|
||||||
|
MapTypeArguments,
|
||||||
|
MapArguments,
|
||||||
|
CreteDescriptorWithFreshTypeVariables,
|
||||||
|
CheckExplicitReceiverKindConsistency,
|
||||||
|
CheckReceivers,
|
||||||
|
CheckArguments
|
||||||
|
),
|
||||||
|
UNSUPPORTED();
|
||||||
|
|
||||||
|
val resolutionSequence = resolutionPart.asList()
|
||||||
|
}
|
||||||
|
|
||||||
|
class GivenCandidate(
|
||||||
|
val descriptor: FunctionDescriptor,
|
||||||
|
val dispatchReceiver: ReceiverValueWithSmartCastInfo?,
|
||||||
|
val knownTypeParametersResultingSubstitutor: TypeSubstitutor?
|
||||||
|
)
|
||||||
|
|
||||||
+145
@@ -0,0 +1,145 @@
|
|||||||
|
/*
|
||||||
|
* 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.model
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
||||||
|
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.components.TypeArgumentsToParametersMapper
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.NewConstraintSystem
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.model.NewConstraintSystemImpl
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.tower.Candidate
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.tower.ResolutionCandidateStatus
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.tower.isSuccess
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
|
||||||
|
interface ResolutionPart {
|
||||||
|
fun SimpleKotlinResolutionCandidate.process(): List<KotlinCallDiagnostic>
|
||||||
|
}
|
||||||
|
|
||||||
|
sealed class KotlinResolutionCandidate : Candidate {
|
||||||
|
abstract val kotlinCall: KotlinCall
|
||||||
|
|
||||||
|
abstract val lastCall: SimpleKotlinResolutionCandidate
|
||||||
|
}
|
||||||
|
|
||||||
|
class VariableAsFunctionKotlinResolutionCandidate(
|
||||||
|
override val kotlinCall: KotlinCall,
|
||||||
|
val resolvedVariable: SimpleKotlinResolutionCandidate,
|
||||||
|
val invokeCandidate: SimpleKotlinResolutionCandidate
|
||||||
|
) : KotlinResolutionCandidate() {
|
||||||
|
override val isSuccessful: Boolean get() = resolvedVariable.isSuccessful && invokeCandidate.isSuccessful
|
||||||
|
override val status: ResolutionCandidateStatus
|
||||||
|
get() = ResolutionCandidateStatus(resolvedVariable.status.diagnostics + invokeCandidate.status.diagnostics)
|
||||||
|
|
||||||
|
override val lastCall: SimpleKotlinResolutionCandidate get() = invokeCandidate
|
||||||
|
}
|
||||||
|
|
||||||
|
sealed class AbstractSimpleKotlinResolutionCandidate(
|
||||||
|
val constraintSystem: NewConstraintSystem,
|
||||||
|
initialDiagnostics: Collection<KotlinCallDiagnostic> = emptyList()
|
||||||
|
) : KotlinResolutionCandidate() {
|
||||||
|
override val isSuccessful: Boolean
|
||||||
|
get() {
|
||||||
|
process(stopOnFirstError = true)
|
||||||
|
return !hasErrors
|
||||||
|
}
|
||||||
|
|
||||||
|
private var _status: ResolutionCandidateStatus? = null
|
||||||
|
|
||||||
|
override val status: ResolutionCandidateStatus
|
||||||
|
get() {
|
||||||
|
if (_status == null) {
|
||||||
|
process(stopOnFirstError = false)
|
||||||
|
_status = ResolutionCandidateStatus(diagnostics + constraintSystem.diagnostics)
|
||||||
|
}
|
||||||
|
return _status!!
|
||||||
|
}
|
||||||
|
|
||||||
|
private val diagnostics = ArrayList<KotlinCallDiagnostic>()
|
||||||
|
protected var step = 0
|
||||||
|
private set
|
||||||
|
|
||||||
|
protected var hasErrors = false
|
||||||
|
private set
|
||||||
|
|
||||||
|
private fun process(stopOnFirstError: Boolean) {
|
||||||
|
while (step < resolutionSequence.size && (!stopOnFirstError || !hasErrors)) {
|
||||||
|
addDiagnostics(resolutionSequence[step].run { lastCall.process() })
|
||||||
|
step++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun addDiagnostics(diagnostics: Collection<KotlinCallDiagnostic>) {
|
||||||
|
hasErrors = hasErrors || diagnostics.any { !it.candidateApplicability.isSuccess } ||
|
||||||
|
constraintSystem.diagnostics.any { !it.candidateApplicability.isSuccess }
|
||||||
|
this.diagnostics.addAll(diagnostics)
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
addDiagnostics(initialDiagnostics)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
abstract val resolutionSequence: List<ResolutionPart>
|
||||||
|
}
|
||||||
|
|
||||||
|
open class SimpleKotlinResolutionCandidate(
|
||||||
|
val callContext: KotlinCallContext,
|
||||||
|
override val kotlinCall: KotlinCall,
|
||||||
|
val explicitReceiverKind: ExplicitReceiverKind,
|
||||||
|
val dispatchReceiverArgument: SimpleKotlinCallArgument?,
|
||||||
|
val extensionReceiver: SimpleKotlinCallArgument?,
|
||||||
|
val candidateDescriptor: CallableDescriptor,
|
||||||
|
initialDiagnostics: Collection<KotlinCallDiagnostic>
|
||||||
|
) : AbstractSimpleKotlinResolutionCandidate(NewConstraintSystemImpl(callContext.constraintInjector, callContext.resultTypeResolver), initialDiagnostics) {
|
||||||
|
val csBuilder: ConstraintSystemBuilder get() = constraintSystem.getBuilder()
|
||||||
|
|
||||||
|
lateinit var typeArgumentMappingByOriginal: TypeArgumentsToParametersMapper.TypeArgumentsMapping
|
||||||
|
lateinit var argumentMappingByOriginal: Map<ValueParameterDescriptor, ResolvedCallArgument>
|
||||||
|
lateinit var descriptorWithFreshTypes: CallableDescriptor
|
||||||
|
|
||||||
|
override val lastCall: SimpleKotlinResolutionCandidate get() = this
|
||||||
|
override val resolutionSequence: List<ResolutionPart> get() = kotlinCall.callKind.resolutionSequence
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
val descriptor = DescriptorRenderer.COMPACT.render(candidateDescriptor)
|
||||||
|
val okOrFail = if (hasErrors) "FAIL" else "OK"
|
||||||
|
val step = "$step/${resolutionSequence.size}"
|
||||||
|
return "$okOrFail($step): $descriptor"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ErrorKotlinResolutionCandidate(
|
||||||
|
callContext: KotlinCallContext,
|
||||||
|
kotlinCall: KotlinCall,
|
||||||
|
explicitReceiverKind: ExplicitReceiverKind,
|
||||||
|
dispatchReceiverArgument: SimpleKotlinCallArgument?,
|
||||||
|
extensionReceiver: SimpleKotlinCallArgument?,
|
||||||
|
candidateDescriptor: CallableDescriptor
|
||||||
|
) : SimpleKotlinResolutionCandidate(callContext, kotlinCall, explicitReceiverKind, dispatchReceiverArgument, extensionReceiver, candidateDescriptor, listOf()) {
|
||||||
|
override val resolutionSequence: List<ResolutionPart> get() = emptyList()
|
||||||
|
|
||||||
|
init {
|
||||||
|
typeArgumentMappingByOriginal = TypeArgumentsToParametersMapper.TypeArgumentsMapping.NoExplicitArguments
|
||||||
|
argumentMappingByOriginal = emptyMap()
|
||||||
|
descriptorWithFreshTypes = candidateDescriptor
|
||||||
|
}
|
||||||
|
}
|
||||||
+97
@@ -0,0 +1,97 @@
|
|||||||
|
/*
|
||||||
|
* 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.model
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.builtins.createFunctionType
|
||||||
|
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.components.ArgumentsToParametersMapper
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.model.LambdaTypeVariable
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.model.NewTypeVariable
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
|
||||||
|
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
|
||||||
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
import org.jetbrains.kotlin.types.SimpleType
|
||||||
|
import org.jetbrains.kotlin.types.UnwrappedType
|
||||||
|
import org.jetbrains.kotlin.types.typeUtil.builtIns
|
||||||
|
|
||||||
|
|
||||||
|
sealed class ArgumentWithPostponeResolution {
|
||||||
|
abstract val outerCall: KotlinCall
|
||||||
|
abstract val argument: KotlinCallArgument
|
||||||
|
abstract val myTypeVariables: Collection<NewTypeVariable>
|
||||||
|
abstract val inputType: Collection<UnwrappedType> // parameters and implicit receiver
|
||||||
|
abstract val outputType: UnwrappedType?
|
||||||
|
|
||||||
|
var analyzed: Boolean = false
|
||||||
|
}
|
||||||
|
|
||||||
|
class ResolvedLambdaArgument(
|
||||||
|
override val outerCall: KotlinCall,
|
||||||
|
override val argument: LambdaKotlinCallArgument,
|
||||||
|
override val myTypeVariables: Collection<LambdaTypeVariable>,
|
||||||
|
val receiver: UnwrappedType?,
|
||||||
|
val parameters: List<UnwrappedType>,
|
||||||
|
val returnType: UnwrappedType
|
||||||
|
) : ArgumentWithPostponeResolution() {
|
||||||
|
val type: SimpleType = createFunctionType(returnType.builtIns, Annotations.EMPTY, receiver, parameters, null, returnType) // todo support annotations
|
||||||
|
|
||||||
|
override val inputType: Collection<UnwrappedType> get() = receiver?.let { parameters + it } ?: parameters
|
||||||
|
override val outputType: UnwrappedType get() = returnType
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class ResolvedPropertyReference(
|
||||||
|
val outerCall: KotlinCall,
|
||||||
|
val argument: ChosenCallableReferenceDescriptor,
|
||||||
|
val reflectionType: UnwrappedType
|
||||||
|
) {
|
||||||
|
val boundDispatchReceiver: ReceiverValue? get() = argument.candidate.dispatchReceiver?.receiverValue?.takeIf { it !is MockReceiverForCallableReference }
|
||||||
|
val boundExtensionReceiver: ReceiverValue? get() = argument.extensionReceiver?.receiverValue?.takeIf { it !is MockReceiverForCallableReference }
|
||||||
|
}
|
||||||
|
|
||||||
|
class ResolvedFunctionReference(
|
||||||
|
val outerCall: KotlinCall,
|
||||||
|
val argument: ChosenCallableReferenceDescriptor,
|
||||||
|
val reflectionType: UnwrappedType,
|
||||||
|
val argumentsMapping: ArgumentsToParametersMapper.ArgumentMapping?
|
||||||
|
) {
|
||||||
|
val boundDispatchReceiver: ReceiverValue? get() = argument.candidate.dispatchReceiver?.receiverValue?.takeIf { it !is MockReceiverForCallableReference }
|
||||||
|
val boundExtensionReceiver: ReceiverValue? get() = argument.extensionReceiver?.receiverValue?.takeIf { it !is MockReceiverForCallableReference }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun KotlinCall.getExplicitDispatchReceiver(explicitReceiverKind: ExplicitReceiverKind) = when (explicitReceiverKind) {
|
||||||
|
ExplicitReceiverKind.DISPATCH_RECEIVER -> explicitReceiver
|
||||||
|
ExplicitReceiverKind.BOTH_RECEIVERS -> dispatchReceiverForInvokeExtension
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
|
||||||
|
fun KotlinCall.getExplicitExtensionReceiver(explicitReceiverKind: ExplicitReceiverKind) = when (explicitReceiverKind) {
|
||||||
|
ExplicitReceiverKind.EXTENSION_RECEIVER, ExplicitReceiverKind.BOTH_RECEIVERS -> explicitReceiver
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
|
||||||
|
class MockReceiverForCallableReference(val lhsOrDeclaredType: UnwrappedType) : ReceiverValue {
|
||||||
|
override fun getType() = lhsOrDeclaredType
|
||||||
|
override fun replaceType(newType: KotlinType) = MockReceiverForCallableReference(newType.unwrap())
|
||||||
|
}
|
||||||
|
|
||||||
|
val ChosenCallableReferenceDescriptor.dispatchNotBoundReceiver : UnwrappedType?
|
||||||
|
get() = (candidate.dispatchReceiver?.receiverValue as? MockReceiverForCallableReference)?.lhsOrDeclaredType
|
||||||
|
|
||||||
|
val ChosenCallableReferenceDescriptor.extensionNotBoundReceiver : UnwrappedType?
|
||||||
|
get() = (extensionReceiver as? MockReceiverForCallableReference)?.lhsOrDeclaredType
|
||||||
+82
@@ -0,0 +1,82 @@
|
|||||||
|
/*
|
||||||
|
* 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.model
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.returnTypeOrNothing
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.tower.ResolutionCandidateStatus
|
||||||
|
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValueWithSmartCastInfo
|
||||||
|
import org.jetbrains.kotlin.types.UnwrappedType
|
||||||
|
|
||||||
|
sealed class ResolvedKotlinCall {
|
||||||
|
class CompletedResolvedKotlinCall(
|
||||||
|
val completedCall: CompletedKotlinCall,
|
||||||
|
val allInnerCalls: Collection<CompletedKotlinCall>
|
||||||
|
): ResolvedKotlinCall()
|
||||||
|
|
||||||
|
class OnlyResolvedKotlinCall(
|
||||||
|
val candidate: KotlinResolutionCandidate
|
||||||
|
) : ResolvedKotlinCall() {
|
||||||
|
val currentReturnType: UnwrappedType = candidate.lastCall.descriptorWithFreshTypes.returnTypeOrNothing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sealed class CompletedKotlinCall {
|
||||||
|
abstract val resolutionStatus: ResolutionCandidateStatus
|
||||||
|
|
||||||
|
class Simple(
|
||||||
|
val kotlinCall: KotlinCall,
|
||||||
|
val candidateDescriptor: CallableDescriptor,
|
||||||
|
val resultingDescriptor: CallableDescriptor,
|
||||||
|
override val resolutionStatus: ResolutionCandidateStatus,
|
||||||
|
val explicitReceiverKind: ExplicitReceiverKind,
|
||||||
|
val dispatchReceiver: ReceiverValueWithSmartCastInfo?,
|
||||||
|
val extensionReceiver: ReceiverValueWithSmartCastInfo?,
|
||||||
|
val typeArguments: List<UnwrappedType>,
|
||||||
|
val argumentMappingByOriginal: Map<ValueParameterDescriptor, ResolvedCallArgument>
|
||||||
|
): CompletedKotlinCall()
|
||||||
|
|
||||||
|
class VariableAsFunction(
|
||||||
|
val kotlinCall: KotlinCall,
|
||||||
|
val variableCall: Simple,
|
||||||
|
val invokeCall: Simple
|
||||||
|
): CompletedKotlinCall() {
|
||||||
|
|
||||||
|
override val resolutionStatus: ResolutionCandidateStatus =
|
||||||
|
ResolutionCandidateStatus(variableCall.resolutionStatus.diagnostics + invokeCall.resolutionStatus.diagnostics)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sealed class ResolvedCallArgument {
|
||||||
|
abstract val arguments: List<KotlinCallArgument>
|
||||||
|
|
||||||
|
object DefaultArgument : ResolvedCallArgument() {
|
||||||
|
override val arguments: List<KotlinCallArgument>
|
||||||
|
get() = emptyList()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class SimpleArgument(val callArgument: KotlinCallArgument): ResolvedCallArgument() {
|
||||||
|
override val arguments: List<KotlinCallArgument>
|
||||||
|
get() = listOf(callArgument)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class VarargArgument(override val arguments: List<KotlinCallArgument>): ResolvedCallArgument()
|
||||||
|
}
|
||||||
+1
-1
@@ -32,7 +32,7 @@ import org.jetbrains.kotlin.types.KotlinType
|
|||||||
import org.jetbrains.kotlin.types.TypeUtils
|
import org.jetbrains.kotlin.types.TypeUtils
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class OverloadingConflictResolver<C : Any>(
|
open class OverloadingConflictResolver<C : Any>(
|
||||||
private val builtIns: KotlinBuiltIns,
|
private val builtIns: KotlinBuiltIns,
|
||||||
private val specificityComparator: TypeSpecificityComparator,
|
private val specificityComparator: TypeSpecificityComparator,
|
||||||
private val getResultingDescriptor: (C) -> CallableDescriptor,
|
private val getResultingDescriptor: (C) -> CallableDescriptor,
|
||||||
|
|||||||
+30
-18
@@ -21,6 +21,9 @@ import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
|||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithVisibility
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithVisibility
|
||||||
import org.jetbrains.kotlin.incremental.components.LookupLocation
|
import org.jetbrains.kotlin.incremental.components.LookupLocation
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.model.KotlinCallDiagnostic
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.model.DiagnosticReporter
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.tower.ResolutionCandidateApplicability.*
|
||||||
import org.jetbrains.kotlin.resolve.scopes.LexicalScope
|
import org.jetbrains.kotlin.resolve.scopes.LexicalScope
|
||||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||||
import org.jetbrains.kotlin.resolve.scopes.SyntheticScopes
|
import org.jetbrains.kotlin.resolve.scopes.SyntheticScopes
|
||||||
@@ -59,9 +62,9 @@ interface CandidateWithBoundDispatchReceiver {
|
|||||||
fun copy(newDescriptor: CallableDescriptor): CandidateWithBoundDispatchReceiver
|
fun copy(newDescriptor: CallableDescriptor): CandidateWithBoundDispatchReceiver
|
||||||
}
|
}
|
||||||
|
|
||||||
data class ResolutionCandidateStatus(val diagnostics: List<ResolutionDiagnostic>) {
|
data class ResolutionCandidateStatus(val diagnostics: List<KotlinCallDiagnostic>) {
|
||||||
val resultingApplicability: ResolutionCandidateApplicability = diagnostics.asSequence().map { it.candidateLevel }.max()
|
val resultingApplicability: ResolutionCandidateApplicability = diagnostics.asSequence().map { it.candidateApplicability }.max()
|
||||||
?: ResolutionCandidateApplicability.RESOLVED
|
?: RESOLVED
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class ResolutionCandidateApplicability {
|
enum class ResolutionCandidateApplicability {
|
||||||
@@ -77,22 +80,31 @@ enum class ResolutionCandidateApplicability {
|
|||||||
HIDDEN, // removed from resolve
|
HIDDEN, // removed from resolve
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class ResolutionDiagnostic(val candidateLevel: ResolutionCandidateApplicability)
|
abstract class ResolutionDiagnostic(candidateApplicability: ResolutionCandidateApplicability): KotlinCallDiagnostic(candidateApplicability) {
|
||||||
|
override fun report(reporter: DiagnosticReporter) {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// todo error for this access from nested class
|
// todo error for this access from nested class
|
||||||
class VisibilityError(val invisibleMember: DeclarationDescriptorWithVisibility): ResolutionDiagnostic(ResolutionCandidateApplicability.RUNTIME_ERROR)
|
class VisibilityError(val invisibleMember: DeclarationDescriptorWithVisibility): ResolutionDiagnostic(RUNTIME_ERROR) {
|
||||||
class NestedClassViaInstanceReference(val classDescriptor: ClassDescriptor): ResolutionDiagnostic(ResolutionCandidateApplicability.IMPOSSIBLE_TO_GENERATE)
|
override fun report(reporter: DiagnosticReporter) {
|
||||||
class InnerClassViaStaticReference(val classDescriptor: ClassDescriptor): ResolutionDiagnostic(ResolutionCandidateApplicability.IMPOSSIBLE_TO_GENERATE)
|
reporter.onCall(this)
|
||||||
class UnsupportedInnerClassCall(val message: String): ResolutionDiagnostic(ResolutionCandidateApplicability.IMPOSSIBLE_TO_GENERATE)
|
}
|
||||||
class UsedSmartCastForDispatchReceiver(val smartCastType: KotlinType): ResolutionDiagnostic(ResolutionCandidateApplicability.RESOLVED)
|
}
|
||||||
|
|
||||||
object ErrorDescriptorDiagnostic : ResolutionDiagnostic(ResolutionCandidateApplicability.RESOLVED) // todo discuss and change to INAPPLICABLE
|
class NestedClassViaInstanceReference(val classDescriptor: ClassDescriptor): ResolutionDiagnostic(IMPOSSIBLE_TO_GENERATE)
|
||||||
object LowPriorityDescriptorDiagnostic : ResolutionDiagnostic(ResolutionCandidateApplicability.RESOLVED_LOW_PRIORITY)
|
class InnerClassViaStaticReference(val classDescriptor: ClassDescriptor): ResolutionDiagnostic(IMPOSSIBLE_TO_GENERATE)
|
||||||
object DynamicDescriptorDiagnostic: ResolutionDiagnostic(ResolutionCandidateApplicability.RESOLVED_LOW_PRIORITY)
|
class UnsupportedInnerClassCall(val message: String): ResolutionDiagnostic(IMPOSSIBLE_TO_GENERATE)
|
||||||
object UnstableSmartCastDiagnostic: ResolutionDiagnostic(ResolutionCandidateApplicability.MAY_THROW_RUNTIME_ERROR)
|
class UsedSmartCastForDispatchReceiver(val smartCastType: KotlinType): ResolutionDiagnostic(RESOLVED)
|
||||||
object HiddenExtensionRelatedToDynamicTypes : ResolutionDiagnostic(ResolutionCandidateApplicability.HIDDEN)
|
|
||||||
object HiddenDescriptor: ResolutionDiagnostic(ResolutionCandidateApplicability.HIDDEN)
|
|
||||||
|
|
||||||
object InvokeConventionCallNoOperatorModifier : ResolutionDiagnostic(ResolutionCandidateApplicability.CONVENTION_ERROR)
|
object ErrorDescriptorDiagnostic : ResolutionDiagnostic(RESOLVED) // todo discuss and change to INAPPLICABLE
|
||||||
object InfixCallNoInfixModifier : ResolutionDiagnostic(ResolutionCandidateApplicability.CONVENTION_ERROR)
|
object LowPriorityDescriptorDiagnostic : ResolutionDiagnostic(RESOLVED_LOW_PRIORITY)
|
||||||
object DeprecatedUnaryPlusAsPlus : ResolutionDiagnostic(ResolutionCandidateApplicability.CONVENTION_ERROR)
|
object DynamicDescriptorDiagnostic: ResolutionDiagnostic(RESOLVED_LOW_PRIORITY)
|
||||||
|
object UnstableSmartCastDiagnostic: ResolutionDiagnostic(MAY_THROW_RUNTIME_ERROR)
|
||||||
|
object HiddenExtensionRelatedToDynamicTypes: ResolutionDiagnostic(HIDDEN)
|
||||||
|
object HiddenDescriptor: ResolutionDiagnostic(HIDDEN)
|
||||||
|
|
||||||
|
object InvokeConventionCallNoOperatorModifier : ResolutionDiagnostic(CONVENTION_ERROR)
|
||||||
|
object InfixCallNoInfixModifier : ResolutionDiagnostic(CONVENTION_ERROR)
|
||||||
|
object DeprecatedUnaryPlusAsPlus : ResolutionDiagnostic(CONVENTION_ERROR)
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.resolve.calls.tower
|
|||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.incremental.components.LookupLocation
|
import org.jetbrains.kotlin.incremental.components.LookupLocation
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.USE_NEW_INFERENCE
|
||||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.getReceiverValueWithSmartCast
|
import org.jetbrains.kotlin.resolve.calls.smartcasts.getReceiverValueWithSmartCast
|
||||||
import org.jetbrains.kotlin.resolve.calls.util.FakeCallableDescriptorForObject
|
import org.jetbrains.kotlin.resolve.calls.util.FakeCallableDescriptorForObject
|
||||||
import org.jetbrains.kotlin.resolve.calls.util.FakeCallableDescriptorForTypeAliasObject
|
import org.jetbrains.kotlin.resolve.calls.util.FakeCallableDescriptorForTypeAliasObject
|
||||||
@@ -63,13 +64,15 @@ internal abstract class AbstractScopeTowerLevel(
|
|||||||
if (descriptor.hasLowPriorityInOverloadResolution()) diagnostics.add(LowPriorityDescriptorDiagnostic)
|
if (descriptor.hasLowPriorityInOverloadResolution()) diagnostics.add(LowPriorityDescriptorDiagnostic)
|
||||||
if (dispatchReceiverSmartCastType != null) diagnostics.add(UsedSmartCastForDispatchReceiver(dispatchReceiverSmartCastType))
|
if (dispatchReceiverSmartCastType != null) diagnostics.add(UsedSmartCastForDispatchReceiver(dispatchReceiverSmartCastType))
|
||||||
|
|
||||||
val shouldSkipVisibilityCheck = scopeTower.isDebuggerContext
|
if (!USE_NEW_INFERENCE) {
|
||||||
if (!shouldSkipVisibilityCheck) {
|
val shouldSkipVisibilityCheck = scopeTower.isDebuggerContext
|
||||||
Visibilities.findInvisibleMember(
|
if (!shouldSkipVisibilityCheck) {
|
||||||
getReceiverValueWithSmartCast(dispatchReceiver?.receiverValue, dispatchReceiverSmartCastType),
|
Visibilities.findInvisibleMember(
|
||||||
descriptor,
|
getReceiverValueWithSmartCast(dispatchReceiver?.receiverValue, dispatchReceiverSmartCastType),
|
||||||
scopeTower.lexicalScope.ownerDescriptor
|
descriptor,
|
||||||
)?.let { diagnostics.add(VisibilityError(it)) }
|
scopeTower.lexicalScope.ownerDescriptor
|
||||||
|
)?.let { diagnostics.add(VisibilityError(it)) }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return CandidateWithBoundDispatchReceiverImpl(dispatchReceiver, descriptor, diagnostics)
|
return CandidateWithBoundDispatchReceiverImpl(dispatchReceiver, descriptor, diagnostics)
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ interface CandidateFactory<out C: Candidate> {
|
|||||||
|
|
||||||
interface CandidateFactoryProviderForInvoke<C : Candidate> {
|
interface CandidateFactoryProviderForInvoke<C : Candidate> {
|
||||||
|
|
||||||
|
// variable here is resolved, invoke -- only chosen
|
||||||
fun transformCandidate(variable: C, invoke: C): C
|
fun transformCandidate(variable: C, invoke: C): C
|
||||||
|
|
||||||
fun factoryForVariable(stripExplicitReceiver: Boolean): CandidateFactory<C>
|
fun factoryForVariable(stripExplicitReceiver: Boolean): CandidateFactory<C>
|
||||||
|
|||||||
+2
-1
@@ -72,5 +72,6 @@ open class FakeCallableDescriptorForObject(
|
|||||||
override fun hashCode() = classDescriptor.hashCode()
|
override fun hashCode() = classDescriptor.hashCode()
|
||||||
|
|
||||||
override fun getContainingDeclaration() = classDescriptor.getClassObjectReferenceTarget().containingDeclaration
|
override fun getContainingDeclaration() = classDescriptor.getClassObjectReferenceTarget().containingDeclaration
|
||||||
override fun substitute(substitutor: TypeSubstitutor) = TODO("Substitution of FakeCallableDescriptorForObject is not supported")
|
|
||||||
|
override fun substitute(substitutor: TypeSubstitutor) = this
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-2
@@ -27,8 +27,9 @@ class ReceiverValueWithSmartCastInfo(
|
|||||||
val receiverValue: ReceiverValue,
|
val receiverValue: ReceiverValue,
|
||||||
val possibleTypes: Set<KotlinType>, // doesn't include receiver.type
|
val possibleTypes: Set<KotlinType>, // doesn't include receiver.type
|
||||||
val isStable: Boolean
|
val isStable: Boolean
|
||||||
): DetailedReceiver
|
): DetailedReceiver {
|
||||||
|
override fun toString() = receiverValue.toString()
|
||||||
|
}
|
||||||
|
|
||||||
interface QualifierReceiver : Receiver, DetailedReceiver {
|
interface QualifierReceiver : Receiver, DetailedReceiver {
|
||||||
val descriptor: DeclarationDescriptor
|
val descriptor: DeclarationDescriptor
|
||||||
|
|||||||
@@ -0,0 +1,343 @@
|
|||||||
|
/*
|
||||||
|
* 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.types
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.types.TypeApproximatorConfiguration.IntersectionStrategy.*
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.components.CommonSupertypeCalculator
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.model.TypeVariableTypeConstructor
|
||||||
|
import org.jetbrains.kotlin.types.checker.NewCapturedType
|
||||||
|
import org.jetbrains.kotlin.types.checker.NewCapturedTypeConstructor
|
||||||
|
import org.jetbrains.kotlin.types.checker.NewKotlinTypeChecker
|
||||||
|
import org.jetbrains.kotlin.types.checker.intersectTypes
|
||||||
|
import org.jetbrains.kotlin.types.typeUtil.*
|
||||||
|
|
||||||
|
|
||||||
|
open class TypeApproximatorConfiguration {
|
||||||
|
enum class IntersectionStrategy {
|
||||||
|
ALLOWED,
|
||||||
|
TO_FIRST,
|
||||||
|
TO_COMMON_SUPERTYPE
|
||||||
|
}
|
||||||
|
open val flexible get() = false // simple flexible types (FlexibleTypeImpl)
|
||||||
|
open val dynamic get() = false // DynamicType
|
||||||
|
open val rawType get() = false // RawTypeImpl
|
||||||
|
open val errorType get() = false
|
||||||
|
open val intersection: IntersectionStrategy = TO_COMMON_SUPERTYPE
|
||||||
|
|
||||||
|
open val typeVariable: (TypeVariableTypeConstructor) -> Boolean = { false }
|
||||||
|
open val capturedType: (NewCapturedType) -> Boolean = { false } // true means that this type we can leave as is
|
||||||
|
|
||||||
|
abstract class AllFlexibleSameValue : TypeApproximatorConfiguration() {
|
||||||
|
abstract val allFlexible: Boolean
|
||||||
|
|
||||||
|
override val flexible get() = allFlexible
|
||||||
|
override val dynamic get() = allFlexible
|
||||||
|
override val rawType get() = allFlexible
|
||||||
|
}
|
||||||
|
|
||||||
|
object LocalDeclaration : AllFlexibleSameValue() {
|
||||||
|
override val allFlexible get() = true
|
||||||
|
override val intersection get() = ALLOWED
|
||||||
|
override val errorType get() = true
|
||||||
|
}
|
||||||
|
|
||||||
|
object PublicDeclaration : AllFlexibleSameValue() {
|
||||||
|
override val allFlexible get() = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TypeApproximator(private val commonSupertypeCalculator: CommonSupertypeCalculator) {
|
||||||
|
private val referenceApproximateToSuperType = this::approximateToSuperType
|
||||||
|
private val referenceApproximateToSubType = this::approximateToSubType
|
||||||
|
|
||||||
|
|
||||||
|
// null means that this input type is the result, i.e. input type not contains not-allowed kind of types
|
||||||
|
// type <: resultType
|
||||||
|
fun approximateToSuperType(type: UnwrappedType, conf: TypeApproximatorConfiguration): UnwrappedType? {
|
||||||
|
if (type is TypeUtils.SpecialType) return null
|
||||||
|
return approximateTo(NewKotlinTypeChecker.transformToNewType(type), conf, FlexibleType::upperBound, referenceApproximateToSuperType)
|
||||||
|
}
|
||||||
|
|
||||||
|
// resultType <: type
|
||||||
|
fun approximateToSubType(type: UnwrappedType, conf: TypeApproximatorConfiguration): UnwrappedType? {
|
||||||
|
if (type is TypeUtils.SpecialType) return null
|
||||||
|
return approximateTo(NewKotlinTypeChecker.transformToNewType(type), conf, FlexibleType::lowerBound, referenceApproximateToSubType)
|
||||||
|
}
|
||||||
|
|
||||||
|
// comments for case bound = upperBound, approximateTo = toSuperType
|
||||||
|
private fun approximateTo(
|
||||||
|
type: UnwrappedType,
|
||||||
|
conf: TypeApproximatorConfiguration,
|
||||||
|
bound: FlexibleType.() -> SimpleType,
|
||||||
|
approximateTo: (SimpleType, TypeApproximatorConfiguration) -> UnwrappedType?
|
||||||
|
): UnwrappedType? {
|
||||||
|
when (type) {
|
||||||
|
is SimpleType -> return approximateTo(type, conf)
|
||||||
|
is FlexibleType -> {
|
||||||
|
if (type is DynamicType) {
|
||||||
|
return if (conf.dynamic) null else type.bound()
|
||||||
|
}
|
||||||
|
else if (type is RawType) {
|
||||||
|
return if (conf.rawType) null else type.bound()
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(type is FlexibleTypeImpl) {
|
||||||
|
"Unexpected subclass of FlexibleType: ${type::class.java.canonicalName}, type = $type"
|
||||||
|
}
|
||||||
|
|
||||||
|
if (conf.flexible) {
|
||||||
|
/**
|
||||||
|
* Let inputType = L_1..U_1; resultType = L_2..U_2
|
||||||
|
* We should create resultType such as inputType <: resultType.
|
||||||
|
* It means that if A <: inputType, then A <: U_1. And, because inputType <: resultType,
|
||||||
|
* A <: resultType => A <: U_2. I.e. for every type A such A <: U_1, A <: U_2 => U_1 <: U_2.
|
||||||
|
*
|
||||||
|
* Similar for L_1 <: L_2: Let B : resultType <: B. L_2 <: B and L_1 <: B.
|
||||||
|
* I.e. for every type B such as L_2 <: B, L_1 <: B. For example B = L_2.
|
||||||
|
*/
|
||||||
|
|
||||||
|
val lowerResult = approximateTo(type.lowerBound, conf)
|
||||||
|
val upperResult = approximateTo(type.upperBound, conf)
|
||||||
|
if (lowerResult == null && upperResult == null) return null
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If C <: L..U then C <: L.
|
||||||
|
* inputType.lower <: lowerResult => inputType.lower <: lowerResult?.lowerIfFlexible()
|
||||||
|
* i.e. this type is correct. We use this type, because this type more flexible.
|
||||||
|
*
|
||||||
|
* If U_1 <: U_2.lower .. U_2.upper, then we know only that U_1 <: U_2.upper.
|
||||||
|
*/
|
||||||
|
return FlexibleTypeImpl(lowerResult?.lowerIfFlexible() ?: type.lowerBound,
|
||||||
|
upperResult?.upperIfFlexible() ?: type.upperBound)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return type.bound().let { approximateTo(it, conf) ?: it }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun approximateIntersectionType(type: SimpleType, conf: TypeApproximatorConfiguration, toSuper: Boolean): UnwrappedType? {
|
||||||
|
val typeConstructor = type.constructor
|
||||||
|
assert(typeConstructor is IntersectionTypeConstructor) {
|
||||||
|
"Should be intersection type: $type, typeConstructor class: ${typeConstructor::class.java.canonicalName}"
|
||||||
|
}
|
||||||
|
assert(typeConstructor.supertypes.isNotEmpty()) {
|
||||||
|
"Supertypes for intersection type should not be empty: $type"
|
||||||
|
}
|
||||||
|
|
||||||
|
var thereIsApproximation = false
|
||||||
|
val newTypes = typeConstructor.supertypes.map {
|
||||||
|
val newType = if (toSuper) approximateToSuperType(it.unwrap(), conf) else approximateToSubType(it.unwrap(), conf)
|
||||||
|
if (newType != null) {
|
||||||
|
thereIsApproximation = true
|
||||||
|
newType
|
||||||
|
} else it.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For case ALLOWED:
|
||||||
|
* A <: A', B <: B' => A & B <: A' & B'
|
||||||
|
*
|
||||||
|
* For other case -- it's impossible to find some type except Nothing as subType for intersection type.
|
||||||
|
*/
|
||||||
|
val baseResult = when (conf.intersection) {
|
||||||
|
ALLOWED -> if (!thereIsApproximation) return null else intersectTypes(newTypes)
|
||||||
|
TO_FIRST -> if (toSuper) newTypes.first() else return type.defaultResult(toSuper = false)
|
||||||
|
// commonSupertypeCalculator should handle flexible types correctly
|
||||||
|
TO_COMMON_SUPERTYPE -> if (toSuper) commonSupertypeCalculator(newTypes) else return type.defaultResult(toSuper = false)
|
||||||
|
}
|
||||||
|
|
||||||
|
return if (type.isMarkedNullable) baseResult.makeNullableAsSpecified(true) else baseResult
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun approximateCapturedType(type: NewCapturedType, conf: TypeApproximatorConfiguration, toSuper: Boolean): UnwrappedType? {
|
||||||
|
val supertypes = type.constructor.supertypes
|
||||||
|
val baseSuperType = when (supertypes.size) {
|
||||||
|
0 -> type.builtIns.nullableAnyType // Let C = in Int, then superType for C and C? is Any?
|
||||||
|
1 -> supertypes.single()
|
||||||
|
else -> intersectTypes(supertypes)
|
||||||
|
}
|
||||||
|
val baseSubType = type.lowerType ?: type.builtIns.nothingType
|
||||||
|
|
||||||
|
if (conf.capturedType(type)) {
|
||||||
|
/**
|
||||||
|
* Here everything is ok if bounds for this captured type should not be approximated.
|
||||||
|
* But. If such bounds contains some unauthorized types, then we cannot leave this captured type "as is".
|
||||||
|
* And we cannot create new capture type, because meaning of new captured type is not clear.
|
||||||
|
* So, we will just approximate such types
|
||||||
|
*
|
||||||
|
* todo handle flexible types
|
||||||
|
*/
|
||||||
|
if (approximateToSuperType(baseSuperType, conf) == null && approximateToSubType(baseSubType, conf) == null) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val baseResult = if (toSuper) approximateToSuperType(baseSuperType, conf) ?: baseSuperType else approximateToSubType(baseSubType, conf) ?: baseSubType
|
||||||
|
|
||||||
|
// C = in Int, Int <: C => Int? <: C?
|
||||||
|
// C = out Number, C <: Number => C? <: Number?
|
||||||
|
return if (type.isMarkedNullable) baseResult.makeNullableAsSpecified(true) else baseResult
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun approximateToSuperType(type: SimpleType, conf: TypeApproximatorConfiguration) = approximateTo(type, conf, toSuper = true)
|
||||||
|
private fun approximateToSubType(type: SimpleType, conf: TypeApproximatorConfiguration) = approximateTo(type, conf, toSuper = false)
|
||||||
|
|
||||||
|
private fun approximateTo(type: SimpleType, conf: TypeApproximatorConfiguration, toSuper: Boolean): UnwrappedType? {
|
||||||
|
if (type.isError) {
|
||||||
|
// todo -- fix builtIns. Now builtIns here is DefaultBuiltIns
|
||||||
|
return if (conf.errorType) null else type.defaultResult(toSuper)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type.arguments.isNotEmpty()) {
|
||||||
|
return approximateParametrizedType(type, conf, toSuper)
|
||||||
|
}
|
||||||
|
|
||||||
|
val typeConstructor = type.constructor
|
||||||
|
|
||||||
|
if (typeConstructor is NewCapturedTypeConstructor) {
|
||||||
|
assert(type is NewCapturedType) { // KT-16147
|
||||||
|
"Type is inconsistent -- somewhere we create type with typeConstructor = $typeConstructor " +
|
||||||
|
"and class: ${type::class.java.canonicalName}. type.toString() = $type"
|
||||||
|
}
|
||||||
|
return approximateCapturedType(type as NewCapturedType, conf, toSuper)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeConstructor is IntersectionTypeConstructor) {
|
||||||
|
return approximateIntersectionType(type, conf, toSuper)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeConstructor is TypeVariableTypeConstructor) {
|
||||||
|
return if (conf.typeVariable(typeConstructor)) null else type.defaultResult(toSuper)
|
||||||
|
}
|
||||||
|
|
||||||
|
return null // simple classifier type
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isApproximateDirectionToSuper(effectiveVariance: Variance, toSuper: Boolean) =
|
||||||
|
when (effectiveVariance) {
|
||||||
|
Variance.OUT_VARIANCE -> toSuper
|
||||||
|
Variance.IN_VARIANCE -> !toSuper
|
||||||
|
Variance.INVARIANT -> throw AssertionError("Incorrect variance $effectiveVariance")
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun approximateParametrizedType(type: SimpleType, conf: TypeApproximatorConfiguration, toSuper: Boolean): SimpleType? {
|
||||||
|
val parameters = type.constructor.parameters
|
||||||
|
val arguments = type.arguments
|
||||||
|
if (parameters.size != arguments.size) {
|
||||||
|
return if (conf.errorType) {
|
||||||
|
ErrorUtils.createErrorType("Inconsistent type: $type (parameters.size = ${parameters.size}, arguments.size = ${arguments.size})")
|
||||||
|
}
|
||||||
|
else type.defaultResult(toSuper)
|
||||||
|
}
|
||||||
|
|
||||||
|
val newArguments = arrayOfNulls<TypeProjection?>(arguments.size)
|
||||||
|
|
||||||
|
loop@ for (index in arguments.indices) {
|
||||||
|
val parameter = parameters[index]
|
||||||
|
val argument = arguments[index]
|
||||||
|
|
||||||
|
if (argument.isStarProjection) continue
|
||||||
|
|
||||||
|
val argumentType = argument.type.unwrap()
|
||||||
|
val effectiveVariance = NewKotlinTypeChecker.effectiveVariance(parameter.variance, argument.projectionKind)
|
||||||
|
when (effectiveVariance) {
|
||||||
|
null -> {
|
||||||
|
return if (conf.errorType) {
|
||||||
|
ErrorUtils.createErrorType("Inconsistent type: $type ($index parameter has declared variance: ${parameter.variance}, " +
|
||||||
|
"but argument variance is ${argument.projectionKind})")
|
||||||
|
} else type.defaultResult(toSuper)
|
||||||
|
}
|
||||||
|
Variance.OUT_VARIANCE, Variance.IN_VARIANCE -> {
|
||||||
|
/**
|
||||||
|
* Out<Foo> <: Out<superType(Foo)>
|
||||||
|
* Inv<out Foo> <: Inv<out superType(Foo)>
|
||||||
|
|
||||||
|
* In<Foo> <: In<subType(Foo)>
|
||||||
|
* Inv<in Foo> <: Inv<in subType(Foo)>
|
||||||
|
*/
|
||||||
|
val approximatedArgument = argumentType.let {
|
||||||
|
if (isApproximateDirectionToSuper(effectiveVariance, toSuper)) approximateToSuperType(it, conf) else approximateToSubType(it, conf)
|
||||||
|
} ?: continue@loop
|
||||||
|
|
||||||
|
if (parameter.variance == Variance.INVARIANT) {
|
||||||
|
newArguments[index] = TypeProjectionImpl(effectiveVariance, approximatedArgument)
|
||||||
|
} else {
|
||||||
|
newArguments[index] = approximatedArgument.asTypeProjection()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Variance.INVARIANT -> {
|
||||||
|
if (!toSuper) {
|
||||||
|
// Inv<Foo> cannot be approximated to subType
|
||||||
|
val toSubType = approximateToSubType(argumentType, conf) ?: continue@loop
|
||||||
|
|
||||||
|
// Inv<Foo!> is supertype for Inv<Foo?>
|
||||||
|
if (!NewKotlinTypeChecker.equalTypes(argumentType, toSubType)) return type.defaultResult(toSuper)
|
||||||
|
|
||||||
|
newArguments[index] = argumentType.asTypeProjection()
|
||||||
|
continue@loop
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Example with non-trivial both type approximations:
|
||||||
|
* Inv<In<C>> where C = in Int
|
||||||
|
* Inv<In<C>> <: Inv<out In<Int>>
|
||||||
|
* Inv<In<C>> <: Inv<in In<Any?>>
|
||||||
|
*
|
||||||
|
* So such case is rare and we will chose Inv<out In<Int>> for now.
|
||||||
|
*
|
||||||
|
* Note that for case Inv<C> we will chose Inv<in Int>, because it is more informative then Inv<out Any?>.
|
||||||
|
* May be we should do the same for deeper types, but not now.
|
||||||
|
*/
|
||||||
|
if (argumentType is NewCapturedType) {
|
||||||
|
val subType = approximateToSubType(argumentType, conf) ?: continue@loop
|
||||||
|
if (!subType.isTrivialSub()) {
|
||||||
|
newArguments[index] = TypeProjectionImpl(Variance.IN_VARIANCE, subType)
|
||||||
|
continue@loop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val approximatedSuperType = approximateToSuperType(argumentType, conf) ?: continue@loop // null means that this type we can leave as is
|
||||||
|
if (approximatedSuperType.isTrivialSuper()) {
|
||||||
|
val approximatedSubType = approximateToSubType(argumentType, conf) ?: continue@loop // seems like this is never null
|
||||||
|
if (!approximatedSubType.isTrivialSub()) {
|
||||||
|
newArguments[index] = TypeProjectionImpl(Variance.IN_VARIANCE, approximatedSubType)
|
||||||
|
continue@loop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
newArguments[index] = TypeProjectionImpl(Variance.OUT_VARIANCE, approximatedSuperType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newArguments.all { it == null }) return null
|
||||||
|
|
||||||
|
val newArgumentsList = arguments.mapIndexed { index, oldArgument -> newArguments[index] ?: oldArgument }
|
||||||
|
return type.replace(newArgumentsList)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun SimpleType.defaultResult(toSuper: Boolean) = if (toSuper) builtIns.nullableAnyType else {
|
||||||
|
if (isMarkedNullable) builtIns.nullableNothingType else builtIns.nothingType
|
||||||
|
}
|
||||||
|
|
||||||
|
// Any? or Any!
|
||||||
|
private fun UnwrappedType.isTrivialSuper() = upperIfFlexible().isNullableAny()
|
||||||
|
|
||||||
|
// Nothing or Nothing!
|
||||||
|
private fun UnwrappedType.isTrivialSub() = lowerIfFlexible().isNothing()
|
||||||
|
}
|
||||||
@@ -52,6 +52,7 @@ import org.jetbrains.kotlin.name.SpecialNames
|
|||||||
import org.jetbrains.kotlin.platform.JvmBuiltIns
|
import org.jetbrains.kotlin.platform.JvmBuiltIns
|
||||||
import org.jetbrains.kotlin.psi.KtFile
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
import org.jetbrains.kotlin.resolve.*
|
import org.jetbrains.kotlin.resolve.*
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.USE_NEW_INFERENCE
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.MutableResolvedCall
|
import org.jetbrains.kotlin.resolve.calls.model.MutableResolvedCall
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||||
import org.jetbrains.kotlin.resolve.jvm.JavaDescriptorResolver
|
import org.jetbrains.kotlin.resolve.jvm.JavaDescriptorResolver
|
||||||
@@ -501,8 +502,10 @@ abstract class AbstractDiagnosticsTest : BaseDiagnosticsTest() {
|
|||||||
|
|
||||||
val lineAndColumn = DiagnosticUtils.getLineAndColumnInPsiFile(element.containingFile, element.textRange)
|
val lineAndColumn = DiagnosticUtils.getLineAndColumnInPsiFile(element.containingFile, element.textRange)
|
||||||
|
|
||||||
assertTrue("Resolved call for '${element.text}'$lineAndColumn is not completed",
|
if (!USE_NEW_INFERENCE) {
|
||||||
(resolvedCall as MutableResolvedCall<*>).isCompleted)
|
assertTrue("Resolved call for '${element.text}'$lineAndColumn is not completed",
|
||||||
|
(resolvedCall as MutableResolvedCall<*>).isCompleted)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
checkResolvedCallsInDiagnostics(bindingContext)
|
checkResolvedCallsInDiagnostics(bindingContext)
|
||||||
@@ -532,6 +535,7 @@ abstract class AbstractDiagnosticsTest : BaseDiagnosticsTest() {
|
|||||||
private fun assertResolvedCallsAreCompleted(diagnostic: Diagnostic, resolvedCalls: Collection<ResolvedCall<*>>) {
|
private fun assertResolvedCallsAreCompleted(diagnostic: Diagnostic, resolvedCalls: Collection<ResolvedCall<*>>) {
|
||||||
val element = diagnostic.psiElement
|
val element = diagnostic.psiElement
|
||||||
val lineAndColumn = DiagnosticUtils.getLineAndColumnInPsiFile(element.containingFile, element.textRange)
|
val lineAndColumn = DiagnosticUtils.getLineAndColumnInPsiFile(element.containingFile, element.textRange)
|
||||||
|
if (USE_NEW_INFERENCE) return
|
||||||
|
|
||||||
assertTrue("Resolved calls stored in ${diagnostic.factory.name}\nfor '${element.text}'$lineAndColumn are not completed",
|
assertTrue("Resolved calls stored in ${diagnostic.factory.name}\nfor '${element.text}'$lineAndColumn are not completed",
|
||||||
resolvedCalls.all { (it as MutableResolvedCall<*>).isCompleted })
|
resolvedCalls.all { (it as MutableResolvedCall<*>).isCompleted })
|
||||||
|
|||||||
@@ -230,14 +230,14 @@ public class ErrorUtils {
|
|||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public ClassifierDescriptor getContributedClassifier(@NotNull Name name, @NotNull LookupLocation location) {
|
public ClassifierDescriptor getContributedClassifier(@NotNull Name name, @NotNull LookupLocation location) {
|
||||||
throw new IllegalStateException();
|
throw new IllegalStateException(debugMessage+", required name: " + name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings({"unchecked"}) // KT-9898 Impossible implement kotlin interface from java
|
@SuppressWarnings({"unchecked"}) // KT-9898 Impossible implement kotlin interface from java
|
||||||
public Collection getContributedVariables(@NotNull Name name, @NotNull LookupLocation location) {
|
public Collection getContributedVariables(@NotNull Name name, @NotNull LookupLocation location) {
|
||||||
throw new IllegalStateException();
|
throw new IllegalStateException(debugMessage+", required name: " + name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@@ -246,7 +246,7 @@ public class ErrorUtils {
|
|||||||
// method is covariantly overridden in Kotlin, but collections in Java are invariant
|
// method is covariantly overridden in Kotlin, but collections in Java are invariant
|
||||||
@SuppressWarnings({"unchecked"})
|
@SuppressWarnings({"unchecked"})
|
||||||
public Collection getContributedFunctions(@NotNull Name name, @NotNull LookupLocation location) {
|
public Collection getContributedFunctions(@NotNull Name name, @NotNull LookupLocation location) {
|
||||||
throw new IllegalStateException();
|
throw new IllegalStateException(debugMessage+", required name: " + name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@@ -254,7 +254,7 @@ public class ErrorUtils {
|
|||||||
public Collection<DeclarationDescriptor> getContributedDescriptors(
|
public Collection<DeclarationDescriptor> getContributedDescriptors(
|
||||||
@NotNull DescriptorKindFilter kindFilter, @NotNull Function1<? super Name, Boolean> nameFilter
|
@NotNull DescriptorKindFilter kindFilter, @NotNull Function1<? super Name, Boolean> nameFilter
|
||||||
) {
|
) {
|
||||||
throw new IllegalStateException();
|
throw new IllegalStateException(debugMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
|
|||||||
@@ -18,6 +18,10 @@ package org.jetbrains.kotlin.types.checker
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||||
import org.jetbrains.kotlin.types.*
|
import org.jetbrains.kotlin.types.*
|
||||||
|
import java.util.*
|
||||||
|
import kotlin.collections.HashSet
|
||||||
|
|
||||||
|
fun intersectWrappedTypes(types: Collection<KotlinType>) = intersectTypes(types.map { it.unwrap() })
|
||||||
|
|
||||||
fun intersectTypes(types: List<UnwrappedType>): UnwrappedType {
|
fun intersectTypes(types: List<UnwrappedType>): UnwrappedType {
|
||||||
when (types.size) {
|
when (types.size) {
|
||||||
@@ -58,7 +62,92 @@ fun intersectTypes(types: List<UnwrappedType>): UnwrappedType {
|
|||||||
// types.size >= 2
|
// types.size >= 2
|
||||||
// It is incorrect see to nullability here, because of KT-12684
|
// It is incorrect see to nullability here, because of KT-12684
|
||||||
private fun intersectTypes(types: List<SimpleType>): SimpleType {
|
private fun intersectTypes(types: List<SimpleType>): SimpleType {
|
||||||
val constructor = IntersectionTypeConstructor(types)
|
return TypeIntersector.intersectTypes(types)
|
||||||
return KotlinTypeFactory.simpleType(Annotations.EMPTY, constructor, listOf(), false, constructor.createScopeForKotlinType())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
object TypeIntersector {
|
||||||
|
|
||||||
|
internal fun intersectTypes(types: List<SimpleType>): SimpleType {
|
||||||
|
assert(types.size > 1) {
|
||||||
|
"Size should be at least 2, but it is ${types.size}"
|
||||||
|
}
|
||||||
|
val inputTypes = ArrayList<SimpleType>()
|
||||||
|
for (type in types) {
|
||||||
|
if (type.constructor is IntersectionTypeConstructor) {
|
||||||
|
inputTypes.addAll(type.constructor.supertypes.map {
|
||||||
|
it.upperIfFlexible().let { if (type.isMarkedNullable) it.makeNullableAsSpecified(true) else it }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
inputTypes.add(type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val resultNullability = inputTypes.fold(ResultNullability.START, ResultNullability::combine)
|
||||||
|
/**
|
||||||
|
* resultNullability. Value description:
|
||||||
|
* ACCEPT_NULL means that all types marked nullable
|
||||||
|
* NOT_NULL means that there is one type which is subtype of Any => all types can be marked not nullable
|
||||||
|
* UNKNOWN means, that we do not know, i.e. more precisely, all singleClassifier types marked nullable if any,
|
||||||
|
* and other types is captured types or type parameters without not-null upper bound. Example: `String? & T` such types we should leave as is.
|
||||||
|
*/
|
||||||
|
val correctNullability = inputTypes.mapTo(HashSet()) {
|
||||||
|
if (resultNullability == ResultNullability.NOT_NULL) it.makeNullableAsSpecified(false) else it
|
||||||
|
}
|
||||||
|
|
||||||
|
return intersectTypesWithoutIntersectionType(correctNullability)
|
||||||
|
}
|
||||||
|
|
||||||
|
// nullability here is correct
|
||||||
|
private fun intersectTypesWithoutIntersectionType(inputTypes: Set<SimpleType>): SimpleType {
|
||||||
|
// Any and Nothing should leave
|
||||||
|
// Note that duplicates should be dropped because we have Set here.
|
||||||
|
val filteredSupertypes = inputTypes.filterNot { upper ->
|
||||||
|
inputTypes.any { upper != it && NewKotlinTypeChecker.isSubtypeOf(it, upper) }
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(filteredSupertypes.isNotEmpty()) {
|
||||||
|
"This collections cannot be empty! input types: ${inputTypes.joinToString()}"
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filteredSupertypes.size < 2) return filteredSupertypes.single()
|
||||||
|
|
||||||
|
val constructor = IntersectionTypeConstructor(inputTypes)
|
||||||
|
return KotlinTypeFactory.simpleType(Annotations.EMPTY, constructor, listOf(), false, constructor.createScopeForKotlinType())
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Let T is type parameter with upper bound Any?. resultNullability(String? & T) = UNKNOWN => String? & T
|
||||||
|
*/
|
||||||
|
private enum class ResultNullability {
|
||||||
|
START {
|
||||||
|
override fun combine(nextType: UnwrappedType) = nextType.resultNullability
|
||||||
|
},
|
||||||
|
ACCEPT_NULL {
|
||||||
|
override fun combine(nextType: UnwrappedType) = nextType.resultNullability
|
||||||
|
},
|
||||||
|
// example: type parameter without not-null supertype
|
||||||
|
UNKNOWN {
|
||||||
|
override fun combine(nextType: UnwrappedType) =
|
||||||
|
nextType.resultNullability.let {
|
||||||
|
if (it == ACCEPT_NULL) this else it
|
||||||
|
}
|
||||||
|
},
|
||||||
|
NOT_NULL {
|
||||||
|
override fun combine(nextType: UnwrappedType) = this
|
||||||
|
};
|
||||||
|
|
||||||
|
abstract fun combine(nextType: UnwrappedType): ResultNullability
|
||||||
|
|
||||||
|
protected val UnwrappedType.resultNullability: ResultNullability
|
||||||
|
get() {
|
||||||
|
if (isMarkedNullable) return ACCEPT_NULL
|
||||||
|
|
||||||
|
if (NullabilityChecker.isSubtypeOfAny(this)) {
|
||||||
|
return NOT_NULL
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return UNKNOWN
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -26,13 +26,52 @@ import org.jetbrains.kotlin.types.typeUtil.asTypeProjection
|
|||||||
import org.jetbrains.kotlin.types.typeUtil.builtIns
|
import org.jetbrains.kotlin.types.typeUtil.builtIns
|
||||||
import org.jetbrains.kotlin.utils.DO_NOTHING_2
|
import org.jetbrains.kotlin.utils.DO_NOTHING_2
|
||||||
|
|
||||||
|
// if input type is capturedType, then we approximate it to UpperBound
|
||||||
|
// null means that type should be leaved as is
|
||||||
|
fun prepareArgumentTypeRegardingCaptureTypes(argumentType: UnwrappedType): UnwrappedType? {
|
||||||
|
val simpleType = NewKotlinTypeChecker.transformToNewType(argumentType.lowerIfFlexible())
|
||||||
|
if (simpleType.constructor is IntersectionTypeConstructor){
|
||||||
|
var changed = false
|
||||||
|
val preparedSuperTypes = simpleType.constructor.supertypes.map {
|
||||||
|
prepareArgumentTypeRegardingCaptureTypes(it.unwrap())?.apply { changed = true } ?: it.unwrap()
|
||||||
|
}
|
||||||
|
if (!changed) return null
|
||||||
|
return intersectTypes(preparedSuperTypes).makeNullableAsSpecified(simpleType.isMarkedNullable)
|
||||||
|
}
|
||||||
|
if (simpleType is NewCapturedType) {
|
||||||
|
// todo may be we should respect flexible capture types also...
|
||||||
|
return simpleType.constructor.supertypes.takeIf { it.isNotEmpty() }?.let(::intersectTypes) ?: argumentType.builtIns.nullableAnyType
|
||||||
|
}
|
||||||
|
return captureFromExpression(simpleType)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun captureFromExpression(type: UnwrappedType): UnwrappedType? = when (type) {
|
||||||
|
is SimpleType -> captureFromExpression(type)
|
||||||
|
// i.e. if there is nothing to capture -- no changes, if there is something -- use lowerBound as base type
|
||||||
|
is FlexibleType -> captureFromExpression(type.lowerBound)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun captureFromExpression(type: SimpleType): UnwrappedType? {
|
||||||
|
val typeConstructor = type.constructor
|
||||||
|
if (typeConstructor is IntersectionTypeConstructor) {
|
||||||
|
var changed = false
|
||||||
|
val capturedSupertypes = typeConstructor.supertypes.map {
|
||||||
|
captureFromExpression(it.unwrap())?.apply { changed = true } ?: it.unwrap()
|
||||||
|
}
|
||||||
|
if (!changed) return null
|
||||||
|
return intersectTypes(capturedSupertypes).makeNullableAsSpecified(type.isMarkedNullable)
|
||||||
|
}
|
||||||
|
return captureFromArguments(type, CaptureStatus.FROM_EXPRESSION)
|
||||||
|
}
|
||||||
|
|
||||||
|
// this function suppose that input type is simple classifier type
|
||||||
fun captureFromArguments(
|
fun captureFromArguments(
|
||||||
type: SimpleType,
|
type: SimpleType,
|
||||||
status: CaptureStatus,
|
status: CaptureStatus,
|
||||||
acceptNewCapturedType: ((argumentIndex: Int, NewCapturedType) -> Unit) = DO_NOTHING_2
|
acceptNewCapturedType: ((argumentIndex: Int, NewCapturedType) -> Unit) = DO_NOTHING_2
|
||||||
): SimpleType {
|
): SimpleType? {
|
||||||
val arguments = type.arguments
|
val arguments = type.arguments
|
||||||
if (arguments.all { it.projectionKind == Variance.INVARIANT }) return type
|
if (arguments.all { it.projectionKind == Variance.INVARIANT }) return null
|
||||||
|
|
||||||
val newArguments = arguments.map {
|
val newArguments = arguments.map {
|
||||||
projection ->
|
projection ->
|
||||||
@@ -68,6 +107,7 @@ fun captureFromArguments(
|
|||||||
|
|
||||||
enum class CaptureStatus {
|
enum class CaptureStatus {
|
||||||
FOR_SUBTYPING,
|
FOR_SUBTYPING,
|
||||||
|
FOR_INCORPORATION,
|
||||||
FROM_EXPRESSION
|
FROM_EXPRESSION
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,7 +126,7 @@ class NewCapturedType(
|
|||||||
override val annotations: Annotations = Annotations.EMPTY,
|
override val annotations: Annotations = Annotations.EMPTY,
|
||||||
override val isMarkedNullable: Boolean = false
|
override val isMarkedNullable: Boolean = false
|
||||||
): SimpleType() {
|
): SimpleType() {
|
||||||
constructor(captureStatus: CaptureStatus, lowerType: UnwrappedType?, projection: TypeProjection) :
|
internal constructor(captureStatus: CaptureStatus, lowerType: UnwrappedType?, projection: TypeProjection) :
|
||||||
this(captureStatus, NewCapturedTypeConstructor(projection), lowerType)
|
this(captureStatus, NewCapturedTypeConstructor(projection), lowerType)
|
||||||
|
|
||||||
override val arguments: List<TypeProjection> get() = listOf()
|
override val arguments: List<TypeProjection> get() = listOf()
|
||||||
|
|||||||
@@ -250,7 +250,7 @@ object NewKotlinTypeChecker : KotlinTypeChecker {
|
|||||||
var result: MutableList<SimpleType>? = null
|
var result: MutableList<SimpleType>? = null
|
||||||
|
|
||||||
anySupertype(baseType, { false }) {
|
anySupertype(baseType, { false }) {
|
||||||
val current = captureFromArguments(it, CaptureStatus.FOR_SUBTYPING)
|
val current = captureFromArguments(it, CaptureStatus.FOR_SUBTYPING) ?: it
|
||||||
|
|
||||||
when {
|
when {
|
||||||
areEqualTypeConstructors(current.constructor, constructor) -> {
|
areEqualTypeConstructors(current.constructor, constructor) -> {
|
||||||
@@ -290,7 +290,7 @@ object NewKotlinTypeChecker : KotlinTypeChecker {
|
|||||||
return if (allPureSupertypes.isNotEmpty()) allPureSupertypes else supertypes
|
return if (allPureSupertypes.isNotEmpty()) allPureSupertypes else supertypes
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun effectiveVariance(declared: Variance, useSite: Variance): Variance? {
|
fun effectiveVariance(declared: Variance, useSite: Variance): Variance? {
|
||||||
if (declared == Variance.INVARIANT) return useSite
|
if (declared == Variance.INVARIANT) return useSite
|
||||||
if (useSite == Variance.INVARIANT) return declared
|
if (useSite == Variance.INVARIANT) return declared
|
||||||
|
|
||||||
@@ -341,12 +341,15 @@ object NullabilityChecker {
|
|||||||
fun isPossibleSubtype(context: TypeCheckerContext, subType: SimpleType, superType: SimpleType): Boolean =
|
fun isPossibleSubtype(context: TypeCheckerContext, subType: SimpleType, superType: SimpleType): Boolean =
|
||||||
context.runIsPossibleSubtype(subType, superType)
|
context.runIsPossibleSubtype(subType, superType)
|
||||||
|
|
||||||
|
fun isSubtypeOfAny(type: UnwrappedType): Boolean =
|
||||||
|
TypeCheckerContext(false).hasNotNullSupertype(type.lowerIfFlexible(), SupertypesPolicy.LowerIfFlexible)
|
||||||
|
|
||||||
private fun TypeCheckerContext.runIsPossibleSubtype(subType: SimpleType, superType: SimpleType): Boolean {
|
private fun TypeCheckerContext.runIsPossibleSubtype(subType: SimpleType, superType: SimpleType): Boolean {
|
||||||
// it makes for case String? & Any <: String
|
// it makes for case String? & Any <: String
|
||||||
assert(subType.isIntersectionType || subType.isSingleClassifierType || subType.isAllowedTypeVariable) {
|
assert(subType.isIntersectionType || subType.isSingleClassifierType || subType.isAllowedTypeVariable) {
|
||||||
"Not singleClassifierType superType: $superType"
|
"Not singleClassifierType superType: $superType"
|
||||||
}
|
}
|
||||||
assert(superType.isSingleClassifierType || subType.isAllowedTypeVariable) {
|
assert(superType.isSingleClassifierType || superType.isAllowedTypeVariable) {
|
||||||
"Not singleClassifierType superType: $superType"
|
"Not singleClassifierType superType: $superType"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -391,7 +394,7 @@ object NullabilityChecker {
|
|||||||
/**
|
/**
|
||||||
* ClassType means that type constructor for this type is type for real class or interface
|
* ClassType means that type constructor for this type is type for real class or interface
|
||||||
*/
|
*/
|
||||||
private val SimpleType.isClassType: Boolean get() = constructor.declarationDescriptor is ClassDescriptor
|
val SimpleType.isClassType: Boolean get() = constructor.declarationDescriptor is ClassDescriptor
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SingleClassifierType is one of the following types:
|
* SingleClassifierType is one of the following types:
|
||||||
@@ -401,10 +404,10 @@ private val SimpleType.isClassType: Boolean get() = constructor.declarationDescr
|
|||||||
*
|
*
|
||||||
* Such types can contains error types in our arguments, but type constructor isn't errorTypeConstructor
|
* Such types can contains error types in our arguments, but type constructor isn't errorTypeConstructor
|
||||||
*/
|
*/
|
||||||
private val SimpleType.isSingleClassifierType: Boolean
|
val SimpleType.isSingleClassifierType: Boolean
|
||||||
get() = !isError &&
|
get() = !isError &&
|
||||||
constructor.declarationDescriptor !is TypeAliasDescriptor &&
|
constructor.declarationDescriptor !is TypeAliasDescriptor &&
|
||||||
(constructor.declarationDescriptor != null || this is CapturedType || this is NewCapturedType)
|
(constructor.declarationDescriptor != null || this is CapturedType || this is NewCapturedType)
|
||||||
|
|
||||||
private val SimpleType.isIntersectionType: Boolean
|
val SimpleType.isIntersectionType: Boolean
|
||||||
get() = constructor is IntersectionTypeConstructor
|
get() = constructor is IntersectionTypeConstructor
|
||||||
@@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -91,7 +91,7 @@ public class DFS {
|
|||||||
return topologicalOrder(nodes, neighbors, new VisitedWithSet<N>());
|
return topologicalOrder(nodes, neighbors, new VisitedWithSet<N>());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static <N> void doDfs(@NotNull N current, @NotNull Neighbors<N> neighbors, @NotNull Visited<N> visited, @NotNull NodeHandler<N, ?> handler) {
|
public static <N> void doDfs(@NotNull N current, @NotNull Neighbors<N> neighbors, @NotNull Visited<N> visited, @NotNull NodeHandler<N, ?> handler) {
|
||||||
if (!visited.checkAndMarkVisited(current)) return;
|
if (!visited.checkAndMarkVisited(current)) return;
|
||||||
if (!handler.beforeChildren(current)) return;
|
if (!handler.beforeChildren(current)) return;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user