[NI] New inference -- initial commit.

This commit is contained in:
Stanislav Erokhin
2016-08-01 08:19:11 +03:00
parent 036090be91
commit b012681a53
64 changed files with 6089 additions and 63 deletions
@@ -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);
@@ -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);
}
}
@@ -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)
}
@@ -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
}
@@ -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;
@@ -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)
}
}
@@ -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)
}
}
@@ -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
}
@@ -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)
}
}
}
@@ -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
@@ -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
}
@@ -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)
}
}
@@ -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()
}
@@ -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>
}
@@ -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)
}
@@ -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] })
)
}
}
}
@@ -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)
}
@@ -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()
}
}
@@ -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)
}
@@ -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
}
@@ -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()
@@ -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
}
@@ -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 }
}
}
@@ -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"
}
}
@@ -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)
}
}
}
}
@@ -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
}
}
@@ -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()
}
}
@@ -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)
}
}
@@ -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)
}
@@ -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)
}
}
@@ -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()
}
@@ -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()
}
}
@@ -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"
}
}
}
@@ -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
}
@@ -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?
)
@@ -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
}
}
@@ -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
@@ -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()
}
@@ -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,
@@ -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>
@@ -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
}
@@ -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;