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