mirror of
https://github.com/jlengrand/kotlin.git
synced 2026-03-31 08:31:31 +00:00
Compare commits
26 Commits
native-sup
...
new_infere
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f6081fd9dd | ||
|
|
a5222b0558 | ||
|
|
e07a135ee8 | ||
|
|
d872621edc | ||
|
|
a67e578a28 | ||
|
|
ba3a1d5d83 | ||
|
|
4b0890d9f8 | ||
|
|
2d8a56dbd9 | ||
|
|
ba61919795 | ||
|
|
b4149b0b5b | ||
|
|
4a367f3b56 | ||
|
|
04636a5497 | ||
|
|
d1af799f97 | ||
|
|
c6aeb954c8 | ||
|
|
fc3479405a | ||
|
|
8a085f8219 | ||
|
|
f51f5576c8 | ||
|
|
5c0833fb47 | ||
|
|
7d8820fc82 | ||
|
|
ab5088c4b2 | ||
|
|
b9be1b306b | ||
|
|
e245b7edf0 | ||
|
|
5f4ca7a341 | ||
|
|
b4e79424f6 | ||
|
|
6839efe48e | ||
|
|
61992aeefd |
@@ -28,7 +28,7 @@ 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.KotlinResolutionExternalPredicatesImpl
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.KotlinResolutionStatelessCallbacksImpl
|
||||
import org.jetbrains.kotlin.resolve.lazy.*
|
||||
import org.jetbrains.kotlin.resolve.lazy.declarations.DeclarationProviderFactory
|
||||
import org.jetbrains.kotlin.resolve.lazy.declarations.FileBasedDeclarationProviderFactory
|
||||
@@ -61,7 +61,7 @@ fun StorageComponentContainer.configureModule(
|
||||
|
||||
private fun StorageComponentContainer.configurePlatformIndependentComponents() {
|
||||
useImpl<SupertypeLoopCheckerImpl>()
|
||||
useImpl<KotlinResolutionExternalPredicatesImpl>()
|
||||
useImpl<KotlinResolutionStatelessCallbacksImpl>()
|
||||
}
|
||||
|
||||
fun StorageComponentContainer.configureModule(
|
||||
|
||||
@@ -29,8 +29,8 @@ 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.CallResolutionResult;
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo;
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValue;
|
||||
@@ -122,7 +122,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, CallResolutionResult> ONLY_RESOLVED_CALL = new BasicWritableSlice<>(DO_NOTHING);
|
||||
WritableSlice<KtExpression, Call> DELEGATE_EXPRESSION_TO_PROVIDE_DELEGATE_CALL = new BasicWritableSlice<>(DO_NOTHING);
|
||||
WritableSlice<Call, TailRecursionKind> TAIL_RECURSION_CALL = Slices.createSimpleSlice();
|
||||
WritableSlice<KtElement, ConstraintSystemCompleter> CONSTRAINT_SYSTEM_COMPLETER = new BasicWritableSlice<>(DO_NOTHING);
|
||||
|
||||
@@ -36,6 +36,7 @@ import org.jetbrains.kotlin.resolve.calls.context.ContextDependency
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystem
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemCompleter
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.FROM_COMPLETER
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.TypeVariableTypeConstructor
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.toHandle
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults
|
||||
@@ -52,6 +53,7 @@ import org.jetbrains.kotlin.types.expressions.ExpressionTypingServices
|
||||
import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils.createFakeExpressionOfType
|
||||
import org.jetbrains.kotlin.types.expressions.FakeCallResolver
|
||||
import org.jetbrains.kotlin.types.expressions.KotlinTypeInfo
|
||||
import org.jetbrains.kotlin.types.typeUtil.contains
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
|
||||
//TODO: check for 'operator' modifier!
|
||||
@@ -554,8 +556,17 @@ class DelegatedPropertyResolver(
|
||||
isGet = true, isComplete = true
|
||||
)
|
||||
|
||||
if (variableDescriptor.isVar && variableDescriptor.returnType !is DeferredType) {
|
||||
getGetSetValueMethod(
|
||||
variableDescriptor, delegateExpression, typeInfoForGetValueReceiver.type ?: return null,
|
||||
traceToResolveConventionMethods, scopeForDelegate, typeInfoForGetValueReceiver.dataFlowInfo,
|
||||
isGet = false, isComplete = true
|
||||
)
|
||||
}
|
||||
|
||||
val call = delegateExpression.getCall(traceToResolveConventionMethods.bindingContext)
|
||||
return call.getResolvedCall(traceToResolveConventionMethods.bindingContext)?.resultingDescriptor?.returnType
|
||||
val pretendReturnType = call.getResolvedCall(traceToResolveConventionMethods.bindingContext)?.resultingDescriptor?.returnType
|
||||
return pretendReturnType?.takeUnless { it.contains { it.constructor is TypeVariableTypeConstructor } }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.diagnostics.Errors.BadNamedArgumentsTarget.INVOKE_ON
|
||||
import org.jetbrains.kotlin.diagnostics.Errors.BadNamedArgumentsTarget.NON_KOTLIN_FUNCTION
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.*
|
||||
import org.jetbrains.kotlin.resolve.calls.model.*
|
||||
@@ -94,8 +95,14 @@ class DiagnosticReporterByTrackingStrategy(
|
||||
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))
|
||||
TooManyArguments::class.java -> {
|
||||
val psiExpression = callArgument.psiExpression
|
||||
if (psiExpression != null) {
|
||||
trace.report(TOO_MANY_ARGUMENTS.on(psiExpression, (diagnostic as TooManyArguments).descriptor))
|
||||
}
|
||||
|
||||
trace.markAsReported()
|
||||
}
|
||||
VarargArgumentOutsideParentheses::class.java ->
|
||||
trace.report(VARARG_OUTSIDE_PARENTHESES.on(callArgument.psiExpression!!))
|
||||
}
|
||||
@@ -126,28 +133,40 @@ class DiagnosticReporterByTrackingStrategy(
|
||||
|
||||
private fun reportSmartCast(smartCastDiagnostic: SmartCastDiagnostic) {
|
||||
val expressionArgument = smartCastDiagnostic.argument
|
||||
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)
|
||||
trace.markAsReported()
|
||||
val smartCastResult = when (expressionArgument) {
|
||||
is ExpressionKotlinCallArgumentImpl -> {
|
||||
trace.markAsReported()
|
||||
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)
|
||||
}
|
||||
is ReceiverExpressionKotlinCallArgument -> {
|
||||
trace.markAsReported()
|
||||
val receiverValue = expressionArgument.receiver.receiverValue
|
||||
val dataFlowValue = DataFlowValueFactory.createDataFlowValue(receiverValue, context)
|
||||
SmartCastManager.checkAndRecordPossibleCast(
|
||||
dataFlowValue, smartCastDiagnostic.smartCastType, (receiverValue as? ExpressionReceiver)?.expression, context, call,
|
||||
recordExpressionType = true)
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
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)
|
||||
trace.markAsReported()
|
||||
val resolvedCall = smartCastDiagnostic.kotlinCall?.psiKotlinCall?.psiCall?.getResolvedCall(trace.bindingContext) as? NewResolvedCallImpl<*>
|
||||
if (resolvedCall != null && smartCastResult != null) {
|
||||
if (resolvedCall.extensionReceiver == expressionArgument.receiver.receiverValue) {
|
||||
resolvedCall.updateExtensionReceiverWithSmartCastIfNeeded(smartCastResult.resultType)
|
||||
}
|
||||
if (resolvedCall.dispatchReceiver == expressionArgument.receiver.receiverValue) {
|
||||
resolvedCall.setSmartCastDispatchReceiverType(smartCastResult.resultType)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun reportUnstableSmartCast(unstableSmartCast: UnstableSmartCast) {
|
||||
// todo hack -- remove it after removing SmartCastManager
|
||||
reportSmartCast(SmartCastDiagnostic(unstableSmartCast.argument, unstableSmartCast.targetType))
|
||||
reportSmartCast(SmartCastDiagnostic(unstableSmartCast.argument, unstableSmartCast.targetType, null))
|
||||
}
|
||||
|
||||
override fun constraintError(diagnostic: KotlinCallDiagnostic) {
|
||||
|
||||
@@ -24,8 +24,7 @@ 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.resolve.calls.tower.StubOnlyVariableAsFunctionCall;
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.KotlinToResolvedCallTransformerKt;
|
||||
import org.jetbrains.kotlin.types.KotlinType;
|
||||
|
||||
import java.util.Collection;
|
||||
@@ -61,7 +60,7 @@ public class OverloadResolutionResultsUtil {
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (resultingCall instanceof StubOnlyResolvedCall || resultingCall instanceof StubOnlyVariableAsFunctionCall) {
|
||||
if (KotlinToResolvedCallTransformerKt.isNewNotCompleted(resultingCall)) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,32 +19,29 @@ package org.jetbrains.kotlin.resolve.calls.tower
|
||||
import org.jetbrains.kotlin.builtins.createFunctionType
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
import org.jetbrains.kotlin.psi.KtFunction
|
||||
import org.jetbrains.kotlin.psi.KtPsiUtil
|
||||
import org.jetbrains.kotlin.psi.KtReturnExpression
|
||||
import org.jetbrains.kotlin.psi.psiUtil.lastBlockStatementOrThis
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.BindingTrace
|
||||
import org.jetbrains.kotlin.resolve.TemporaryBindingTrace
|
||||
import org.jetbrains.kotlin.resolve.calls.ArgumentTypeResolver
|
||||
import org.jetbrains.kotlin.resolve.calls.components.KotlinResolutionCallbacks
|
||||
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext
|
||||
import org.jetbrains.kotlin.resolve.calls.context.ContextDependency
|
||||
import org.jetbrains.kotlin.resolve.calls.model.*
|
||||
import org.jetbrains.kotlin.resolve.calls.model.LambdaKotlinCallArgument
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCallAtom
|
||||
import org.jetbrains.kotlin.resolve.calls.model.SimpleKotlinCallArgument
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
|
||||
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
|
||||
import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategyImpl
|
||||
import org.jetbrains.kotlin.resolve.calls.util.CallMaker
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.expressions.DoubleColonExpressionResolver
|
||||
import org.jetbrains.kotlin.types.TypeApproximator
|
||||
import org.jetbrains.kotlin.types.TypeApproximatorConfiguration
|
||||
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
|
||||
import org.jetbrains.kotlin.types.typeUtil.asTypeProjection
|
||||
import org.jetbrains.kotlin.types.typeUtil.isUnit
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
|
||||
@@ -52,10 +49,9 @@ class KotlinResolutionCallbacksImpl(
|
||||
val topLevelCallContext: BasicCallResolutionContext,
|
||||
val expressionTypingServices: ExpressionTypingServices,
|
||||
val typeApproximator: TypeApproximator,
|
||||
val kotlinToResolvedCallTransformer: KotlinToResolvedCallTransformer,
|
||||
val argumentTypeResolver: ArgumentTypeResolver,
|
||||
val doubleColonExpressionResolver: DoubleColonExpressionResolver,
|
||||
val languageVersionSettings: LanguageVersionSettings
|
||||
val languageVersionSettings: LanguageVersionSettings,
|
||||
val kotlinToResolvedCallTransformer: KotlinToResolvedCallTransformer
|
||||
): KotlinResolutionCallbacks {
|
||||
val trace: BindingTrace = topLevelCallContext.trace
|
||||
|
||||
@@ -69,31 +65,23 @@ class KotlinResolutionCallbacksImpl(
|
||||
}
|
||||
|
||||
override fun analyzeAndGetLambdaResultArguments(
|
||||
outerCall: KotlinCall,
|
||||
lambdaArgument: LambdaKotlinCallArgument,
|
||||
isSuspend: Boolean,
|
||||
receiverType: UnwrappedType?,
|
||||
parameters: List<UnwrappedType>,
|
||||
expectedReturnType: UnwrappedType?
|
||||
): List<SimpleKotlinCallArgument> {
|
||||
val psiCallArgument = lambdaArgument.psiCallArgument
|
||||
val outerCallContext = (psiCallArgument as? LambdaKotlinCallArgumentImpl)?.outerCallContext ?:
|
||||
(psiCallArgument as FunctionExpressionImpl).outerCallContext
|
||||
val psiCallArgument = lambdaArgument.psiCallArgument as PSIFunctionKotlinCallArgument
|
||||
val outerCallContext = psiCallArgument.outerCallContext
|
||||
|
||||
fun createCallArgument(ktExpression: KtExpression, typeInfo: KotlinTypeInfo) =
|
||||
createSimplePSICallArgument(trace.bindingContext, outerCallContext.statementFilter, outerCallContext.scope.ownerDescriptor,
|
||||
CallMaker.makeExternalValueArgument(ktExpression), DataFlowInfo.EMPTY, typeInfo)
|
||||
|
||||
val expression: KtExpression = (psiCallArgument as? LambdaKotlinCallArgumentImpl)?.ktLambdaExpression ?:
|
||||
(psiCallArgument as FunctionExpressionImpl).ktFunction
|
||||
|
||||
val ktFunction: KtFunction = (psiCallArgument as? LambdaKotlinCallArgumentImpl)?.ktLambdaExpression?.functionLiteral ?:
|
||||
(psiCallArgument as FunctionExpressionImpl).ktFunction
|
||||
|
||||
val lambdaInfo = LambdaInfo(expectedReturnType ?: TypeUtils.NO_EXPECTED_TYPE,
|
||||
if (expectedReturnType == null) ContextDependency.DEPENDENT else ContextDependency.INDEPENDENT)
|
||||
|
||||
trace.record(BindingContext.NEW_INFERENCE_LAMBDA_INFO, ktFunction, lambdaInfo)
|
||||
trace.record(BindingContext.NEW_INFERENCE_LAMBDA_INFO, psiCallArgument.ktFunction, lambdaInfo)
|
||||
|
||||
val builtIns = outerCallContext.scope.ownerDescriptor.builtIns
|
||||
val expectedType = createFunctionType(builtIns, Annotations.EMPTY, receiverType, parameters, null,
|
||||
@@ -105,10 +93,10 @@ class KotlinResolutionCallbacksImpl(
|
||||
.replaceBindingTrace(trace)
|
||||
.replaceContextDependency(lambdaInfo.contextDependency)
|
||||
.replaceExpectedType(approximatesExpectedType)
|
||||
.replaceDataFlowInfo(outerCall.psiKotlinCall.resultDataFlowInfo)
|
||||
.replaceDataFlowInfo(psiCallArgument.lambdaInitialDataFlowInfo)
|
||||
|
||||
val functionTypeInfo = expressionTypingServices.getTypeInfo(expression, actualContext)
|
||||
trace.record(BindingContext.NEW_INFERENCE_LAMBDA_INFO, ktFunction, LambdaInfo.STUB_EMPTY)
|
||||
val functionTypeInfo = expressionTypingServices.getTypeInfo(psiCallArgument.expression, actualContext)
|
||||
trace.record(BindingContext.NEW_INFERENCE_LAMBDA_INFO, psiCallArgument.ktFunction, LambdaInfo.STUB_EMPTY)
|
||||
|
||||
var hasReturnWithoutExpression = false
|
||||
val returnArguments = lambdaInfo.returnStatements.mapNotNullTo(ArrayList()) { (expression, typeInfo) ->
|
||||
@@ -129,6 +117,7 @@ class KotlinResolutionCallbacksImpl(
|
||||
val lastExpressionArgument = getLastDeparentesizedExpression(psiCallArgument)?.let { lastExpression ->
|
||||
if (expectedReturnType?.isUnit() == true) return@let null // coercion to Unit
|
||||
|
||||
// todo lastExpression can be if without else
|
||||
val lastExpressionType = trace.getType(lastExpression)
|
||||
val lastExpressionTypeInfo = KotlinTypeInfo(lastExpressionType, lambdaInfo.dataFlowInfoAfter ?: functionTypeInfo.dataFlowInfo)
|
||||
createCallArgument(lastExpression, lastExpressionTypeInfo)
|
||||
@@ -151,72 +140,8 @@ class KotlinResolutionCallbacksImpl(
|
||||
return KtPsiUtil.deparenthesize(lastExpression)
|
||||
}
|
||||
|
||||
override fun bindStubResolvedCallForCandidate(candidate: KotlinResolutionCandidate) {
|
||||
override fun bindStubResolvedCallForCandidate(candidate: ResolvedCallAtom) {
|
||||
kotlinToResolvedCallTransformer.createStubResolvedCallAndWriteItToTrace<CallableDescriptor>(candidate, trace)
|
||||
}
|
||||
|
||||
override fun completeCallableReference(
|
||||
callableReferenceArgument: PostponedCallableReferenceArgument,
|
||||
resultTypeParameters: List<UnwrappedType>
|
||||
) {
|
||||
val callableCandidate = callableReferenceArgument.callableResolutionCandidate
|
||||
val psiCallArgument = callableReferenceArgument.argument.psiCallArgument as CallableReferenceKotlinCallArgumentImpl
|
||||
val callableReferenceExpression = psiCallArgument.ktCallableReferenceExpression
|
||||
val resultSubstitutor = IndexedParametersSubstitution(callableCandidate.candidate.typeParameters, resultTypeParameters.map { it.asTypeProjection() }).buildSubstitutor()
|
||||
|
||||
|
||||
// write down type for callable reference expression
|
||||
val resultType = resultSubstitutor.safeSubstitute(callableCandidate.reflectionCandidateType, Variance.INVARIANT)
|
||||
argumentTypeResolver.updateResultArgumentTypeIfNotDenotable(trace, expressionTypingServices.statementFilter,
|
||||
resultType,
|
||||
callableReferenceExpression)
|
||||
val reference = callableReferenceExpression.callableReference
|
||||
|
||||
val explicitCallableReceiver = when (callableCandidate.explicitReceiverKind) {
|
||||
ExplicitReceiverKind.DISPATCH_RECEIVER -> callableCandidate.dispatchReceiver
|
||||
ExplicitReceiverKind.EXTENSION_RECEIVER -> callableCandidate.extensionReceiver
|
||||
else -> null
|
||||
}
|
||||
|
||||
val explicitReceiver = explicitCallableReceiver?.receiver
|
||||
val psiCall = CallMaker.makeCall(reference, explicitReceiver?.receiverValue, null, reference, emptyList())
|
||||
|
||||
val tracing = TracingStrategyImpl.create(reference, psiCall)
|
||||
val temporaryTrace = TemporaryBindingTrace.create(trace, "callable reference fake call")
|
||||
|
||||
val resolvedCall = ResolvedCallImpl(psiCall, callableCandidate.candidate, callableCandidate.dispatchReceiver?.receiver?.receiverValue,
|
||||
callableCandidate.extensionReceiver?.receiver?.receiverValue, callableCandidate.explicitReceiverKind,
|
||||
null, temporaryTrace, tracing, MutableDataFlowInfoForArguments.WithoutArgumentsCheck(DataFlowInfo.EMPTY))
|
||||
resolvedCall.setResultingSubstitutor(resultSubstitutor)
|
||||
|
||||
tracing.bindCall(trace, psiCall)
|
||||
tracing.bindReference(trace, resolvedCall)
|
||||
tracing.bindResolvedCall(trace, resolvedCall)
|
||||
|
||||
resolvedCall.setStatusToSuccess()
|
||||
resolvedCall.markCallAsCompleted()
|
||||
|
||||
when (callableCandidate.candidate) {
|
||||
is FunctionDescriptor -> doubleColonExpressionResolver.bindFunctionReference(callableReferenceExpression, resultType, topLevelCallContext)
|
||||
is PropertyDescriptor -> doubleColonExpressionResolver.bindPropertyReference(callableReferenceExpression, resultType, topLevelCallContext)
|
||||
}
|
||||
|
||||
// TODO: probably we should also record key 'DATA_FLOW_INFO_BEFORE', see ExpressionTypingVisitorDispatcher.getTypeInfo
|
||||
trace.recordType(callableReferenceExpression, resultType)
|
||||
trace.record(BindingContext.PROCESSED, callableReferenceExpression)
|
||||
|
||||
doubleColonExpressionResolver.checkReferenceIsToAllowedMember(callableCandidate.candidate, topLevelCallContext.trace, callableReferenceExpression)
|
||||
}
|
||||
|
||||
override fun completeCollectionLiteralCalls(collectionLiteralArgument: PostponedCollectionLiteralArgument) {
|
||||
val psiCallArgument = collectionLiteralArgument.argument.psiCallArgument as CollectionLiteralKotlinCallArgumentImpl
|
||||
val context = psiCallArgument.outerCallContext
|
||||
|
||||
val actualContext = context
|
||||
.replaceBindingTrace(trace)
|
||||
.replaceExpectedType(collectionLiteralArgument.expectedType)
|
||||
.replaceContextDependency(ContextDependency.INDEPENDENT)
|
||||
|
||||
expressionTypingServices.getTypeInfo(psiCallArgument.collectionLiteralExpression, actualContext)
|
||||
}
|
||||
}
|
||||
@@ -24,14 +24,16 @@ import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
||||
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.isConventionCall
|
||||
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.isInfixCall
|
||||
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.isSuperOrDelegatingConstructorCall
|
||||
import org.jetbrains.kotlin.resolve.calls.components.KotlinResolutionExternalPredicates
|
||||
import org.jetbrains.kotlin.resolve.calls.components.KotlinResolutionStatelessCallbacks
|
||||
import org.jetbrains.kotlin.resolve.calls.model.CallableReferenceKotlinCallArgument
|
||||
import org.jetbrains.kotlin.resolve.calls.model.KotlinCall
|
||||
import org.jetbrains.kotlin.resolve.calls.model.SimpleKotlinCallArgument
|
||||
import org.jetbrains.kotlin.resolve.isHiddenInResolution
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
class KotlinResolutionExternalPredicatesImpl(
|
||||
class KotlinResolutionStatelessCallbacksImpl(
|
||||
private val languageVersionSettings: LanguageVersionSettings
|
||||
) : KotlinResolutionExternalPredicates {
|
||||
) : KotlinResolutionStatelessCallbacks {
|
||||
override fun isDescriptorFromSource(descriptor: CallableDescriptor) =
|
||||
DescriptorToSourceUtils.descriptorToDeclaration(descriptor) != null
|
||||
|
||||
@@ -50,4 +52,10 @@ class KotlinResolutionExternalPredicatesImpl(
|
||||
|
||||
override fun isSuperExpression(receiver: SimpleKotlinCallArgument?): Boolean =
|
||||
receiver?.psiExpression is KtSuperExpression
|
||||
|
||||
override fun getScopeTowerForCallableReferenceArgument(argument: CallableReferenceKotlinCallArgument): ImplicitScopeTower =
|
||||
(argument as CallableReferenceKotlinCallArgumentImpl).scopeTowerForResolution
|
||||
|
||||
override fun getVariableCandidateIfInvoke(functionCall: KotlinCall) =
|
||||
functionCall.safeAs<PSIKotlinCallForInvoke>()?.variableCall
|
||||
}
|
||||
@@ -16,10 +16,8 @@
|
||||
|
||||
package org.jetbrains.kotlin.resolve.calls.tower
|
||||
|
||||
import org.jetbrains.kotlin.builtins.replaceReturnType
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.impl.FunctionDescriptorImpl
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
@@ -32,22 +30,33 @@ import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||
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.components.AdditionalDiagnosticReporter
|
||||
import org.jetbrains.kotlin.resolve.calls.components.isVararg
|
||||
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext
|
||||
import org.jetbrains.kotlin.resolve.calls.context.CallPosition
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.buildResultingSubstitutor
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.components.FreshVariableNewTypeSubstitutor
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.components.NewTypeSubstitutor
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.substitute
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.substituteAndApproximateCapturedTypes
|
||||
import org.jetbrains.kotlin.resolve.calls.model.*
|
||||
import org.jetbrains.kotlin.resolve.calls.resolvedCallUtil.makeNullableTypeIfSafeReceiver
|
||||
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.constants.evaluate.ConstantExpressionEvaluator
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.CastImplicitClassReceiver
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitClassReceiver
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
|
||||
import org.jetbrains.kotlin.types.ErrorUtils
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import org.jetbrains.kotlin.types.UnwrappedType
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.checker.NewCapturedType
|
||||
import org.jetbrains.kotlin.types.expressions.DataFlowAnalyzer
|
||||
import org.jetbrains.kotlin.types.expressions.DoubleColonExpressionResolver
|
||||
import org.jetbrains.kotlin.types.expressions.ExpressionTypingServices
|
||||
import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils
|
||||
import org.jetbrains.kotlin.types.typeUtil.contains
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.cast
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
import java.util.*
|
||||
|
||||
|
||||
@@ -56,90 +65,71 @@ class KotlinToResolvedCallTransformer(
|
||||
private val languageFeatureSettings: LanguageVersionSettings,
|
||||
private val dataFlowAnalyzer: DataFlowAnalyzer,
|
||||
private val argumentTypeResolver: ArgumentTypeResolver,
|
||||
private val constantExpressionEvaluator: ConstantExpressionEvaluator
|
||||
) {
|
||||
private val constantExpressionEvaluator: ConstantExpressionEvaluator,
|
||||
private val expressionTypingServices: ExpressionTypingServices,
|
||||
private val doubleColonExpressionResolver: DoubleColonExpressionResolver,
|
||||
private val additionalDiagnosticReporter: AdditionalDiagnosticReporter
|
||||
) {
|
||||
|
||||
fun <D : CallableDescriptor> onlyTransform(
|
||||
resolvedCallAtom: ResolvedCallAtom
|
||||
): ResolvedCall<D> = transformToResolvedCall(resolvedCallAtom, completed = false)
|
||||
|
||||
fun <D : CallableDescriptor> transformAndReport(
|
||||
baseResolvedCall: ResolvedKotlinCall,
|
||||
context: BasicCallResolutionContext,
|
||||
trace: BindingTrace? // if trace is not null then all information will be reported to this trace
|
||||
baseResolvedCall: CallResolutionResult,
|
||||
context: BasicCallResolutionContext
|
||||
): ResolvedCall<D> {
|
||||
if (baseResolvedCall is ResolvedKotlinCall.CompletedResolvedKotlinCall) {
|
||||
val allResolvedCalls = baseResolvedCall.allInnerCalls.mapTo(ArrayList<ResolvedCall<*>>()) { transformAndReportCompletedCall<CallableDescriptor>(it, context, trace) }
|
||||
val result = transformAndReportCompletedCall<D>(baseResolvedCall.completedCall, context, trace)
|
||||
allResolvedCalls.add(result)
|
||||
val candidate = baseResolvedCall.resultCallAtom!!
|
||||
when (baseResolvedCall.type) {
|
||||
CallResolutionResult.Type.PARTIAL -> {
|
||||
context.trace.record(BindingContext.ONLY_RESOLVED_CALL, candidate.atom.psiKotlinCall.psiCall, baseResolvedCall)
|
||||
|
||||
if (trace != null) {
|
||||
val callCheckerContext = CallCheckerContext(context.replaceBindingTrace(trace), languageFeatureSettings)
|
||||
for (resolvedCall in allResolvedCalls) {
|
||||
runCallCheckers(resolvedCall, callCheckerContext)
|
||||
}
|
||||
runLambdaArgumentsChecks(context, trace, baseResolvedCall.lambdaArguments)
|
||||
allResolvedCalls.map {
|
||||
if (it is VariableAsFunctionResolvedCall) it.functionCall else it
|
||||
}.forEach {
|
||||
runArgumentsChecks(context, trace, it as NewResolvedCallImpl<*>)
|
||||
}
|
||||
return createStubResolvedCallAndWriteItToTrace(candidate, context.trace)
|
||||
}
|
||||
CallResolutionResult.Type.ERROR, CallResolutionResult.Type.COMPLETED -> {
|
||||
val resultSubstitutor = baseResolvedCall.constraintSystem.buildResultingSubstitutor()
|
||||
val ktPrimitiveCompleter = ResolvedAtomCompleter(resultSubstitutor, context.trace, context, this,
|
||||
expressionTypingServices, argumentTypeResolver, doubleColonExpressionResolver,
|
||||
languageFeatureSettings)
|
||||
|
||||
return result
|
||||
for (subKtPrimitive in candidate.subResolvedAtoms) {
|
||||
ktPrimitiveCompleter.completeAll(subKtPrimitive)
|
||||
}
|
||||
|
||||
return ktPrimitiveCompleter.completeResolvedCall(candidate) as ResolvedCall<D>
|
||||
}
|
||||
}
|
||||
|
||||
val onlyResolvedCall = (baseResolvedCall as ResolvedKotlinCall.OnlyResolvedKotlinCall)
|
||||
trace?.record(BindingContext.ONLY_RESOLVED_CALL, onlyResolvedCall.candidate.kotlinCall.psiKotlinCall.psiCall, onlyResolvedCall)
|
||||
|
||||
return createStubResolvedCallAndWriteItToTrace(onlyResolvedCall.candidate, trace)
|
||||
}
|
||||
|
||||
fun <D : CallableDescriptor> createStubResolvedCallAndWriteItToTrace(candidate: KotlinResolutionCandidate, trace: BindingTrace?): ResolvedCall<D> {
|
||||
val result = when (candidate) {
|
||||
is VariableAsFunctionKotlinResolutionCandidate -> {
|
||||
val variableStub = StubOnlyResolvedCall<VariableDescriptor>(candidate.resolvedVariable)
|
||||
val invokeStub = StubOnlyResolvedCall<FunctionDescriptor>(candidate.invokeCandidate)
|
||||
StubOnlyVariableAsFunctionCall(variableStub, invokeStub) as ResolvedCall<D>
|
||||
}
|
||||
is SimpleKotlinResolutionCandidate -> {
|
||||
StubOnlyResolvedCall<D>(candidate)
|
||||
}
|
||||
}
|
||||
if (trace != null) {
|
||||
val tracing = candidate.kotlinCall.psiKotlinCall.tracingStrategy
|
||||
fun <D : CallableDescriptor> createStubResolvedCallAndWriteItToTrace(candidate: ResolvedCallAtom, trace: BindingTrace): ResolvedCall<D> {
|
||||
val result = onlyTransform<D>(candidate)
|
||||
val psiKotlinCall = candidate.atom.psiKotlinCall
|
||||
val tracing = psiKotlinCall.safeAs<PSIKotlinCallForInvoke>()?.baseCall?.tracingStrategy ?: psiKotlinCall.tracingStrategy
|
||||
|
||||
tracing.bindReference(trace, result)
|
||||
tracing.bindResolvedCall(trace, result)
|
||||
}
|
||||
tracing.bindReference(trace, result)
|
||||
tracing.bindResolvedCall(trace, result)
|
||||
return result
|
||||
}
|
||||
|
||||
|
||||
private fun <D : CallableDescriptor> transformAndReportCompletedCall(
|
||||
completedCall: CompletedKotlinCall,
|
||||
context: BasicCallResolutionContext,
|
||||
trace: BindingTrace?
|
||||
fun <D : CallableDescriptor> transformToResolvedCall(
|
||||
completedCallAtom: ResolvedCallAtom,
|
||||
completed: Boolean,
|
||||
resultSubstitutor: NewTypeSubstitutor = FreshVariableNewTypeSubstitutor.Empty
|
||||
): ResolvedCall<D> {
|
||||
fun <C> C.runIfTraceNotNull(action: (BasicCallResolutionContext, BindingTrace, C) -> Unit): C {
|
||||
if (trace != null) action(context, trace, this)
|
||||
return this
|
||||
val psiKotlinCall = completedCallAtom.atom.psiKotlinCall
|
||||
return if (psiKotlinCall is PSIKotlinCallForInvoke) {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
NewVariableAsFunctionResolvedCallImpl(
|
||||
NewResolvedCallImpl(psiKotlinCall.variableCall.resolvedCall, completed, resultSubstitutor),
|
||||
NewResolvedCallImpl(completedCallAtom, completed, resultSubstitutor)
|
||||
) as ResolvedCall<D>
|
||||
}
|
||||
|
||||
return when (completedCall) {
|
||||
is CompletedKotlinCall.Simple -> {
|
||||
NewResolvedCallImpl<D>(completedCall).runIfTraceNotNull(this::bindResolvedCall)
|
||||
}
|
||||
is CompletedKotlinCall.VariableAsFunction -> {
|
||||
val resolvedCall = NewVariableAsFunctionResolvedCallImpl(
|
||||
completedCall,
|
||||
NewResolvedCallImpl(completedCall.variableCall),
|
||||
NewResolvedCallImpl<FunctionDescriptor>(completedCall.invokeCall)
|
||||
).runIfTraceNotNull(this::bindResolvedCall)
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
(resolvedCall as ResolvedCall<D>)
|
||||
}
|
||||
else {
|
||||
NewResolvedCallImpl(completedCallAtom, completed, resultSubstitutor)
|
||||
}
|
||||
}
|
||||
|
||||
private fun runCallCheckers(resolvedCall: ResolvedCall<*>, callCheckerContext: CallCheckerContext) {
|
||||
fun runCallCheckers(resolvedCall: ResolvedCall<*>, callCheckerContext: CallCheckerContext) {
|
||||
val calleeExpression = if (resolvedCall is VariableAsFunctionResolvedCall)
|
||||
resolvedCall.variableCall.call.calleeExpression
|
||||
else
|
||||
@@ -157,57 +147,8 @@ class KotlinToResolvedCallTransformer(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun runLambdaArgumentsChecks(
|
||||
context: BasicCallResolutionContext,
|
||||
trace: BindingTrace,
|
||||
lambdaArguments: List<PostponedLambdaArgument>
|
||||
) {
|
||||
for (lambdaArgument in lambdaArguments) {
|
||||
val returnType = lambdaArgument.finalReturnType
|
||||
|
||||
updateTraceForLambdaReturnType(lambdaArgument, trace, returnType)
|
||||
|
||||
for (lambdaResult in lambdaArgument.resultArguments) {
|
||||
val resultValueArgument = lambdaResult as? PSIKotlinCallArgument ?: continue
|
||||
val newContext =
|
||||
context.replaceDataFlowInfo(resultValueArgument.dataFlowInfoAfterThisArgument)
|
||||
.replaceExpectedType(returnType)
|
||||
.replaceBindingTrace(trace)
|
||||
|
||||
val argumentExpression = resultValueArgument.valueArgument.getArgumentExpression() ?: continue
|
||||
updateRecordedType(argumentExpression, newContext)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateTraceForLambdaReturnType(lambdaArgument: PostponedLambdaArgument, trace: BindingTrace, returnType: UnwrappedType) {
|
||||
val psiCallArgument = lambdaArgument.argument.psiCallArgument
|
||||
|
||||
val ktArgumentExpression: KtExpression
|
||||
val ktFunction: KtElement
|
||||
when (psiCallArgument) {
|
||||
is LambdaKotlinCallArgumentImpl -> {
|
||||
ktArgumentExpression = psiCallArgument.ktLambdaExpression
|
||||
ktFunction = ktArgumentExpression.functionLiteral
|
||||
}
|
||||
is FunctionExpressionImpl -> {
|
||||
ktArgumentExpression = psiCallArgument.ktFunction
|
||||
ktFunction = ktArgumentExpression
|
||||
}
|
||||
else -> throw AssertionError("Unexpected psiCallArgument for resolved lambda argument: $psiCallArgument")
|
||||
}
|
||||
|
||||
val functionDescriptor = trace.bindingContext.get(BindingContext.FUNCTION, ktFunction) as? FunctionDescriptorImpl ?:
|
||||
throw AssertionError("No function descriptor for resolved lambda argument")
|
||||
functionDescriptor.setReturnType(returnType)
|
||||
|
||||
val existingLambdaType = trace.getType(ktArgumentExpression) ?: throw AssertionError("No type for resolved lambda argument")
|
||||
trace.recordType(ktArgumentExpression, existingLambdaType.replaceReturnType(returnType))
|
||||
}
|
||||
|
||||
// todo very beginning code
|
||||
private fun runArgumentsChecks(
|
||||
fun runArgumentsChecks(
|
||||
context: BasicCallResolutionContext,
|
||||
trace: BindingTrace,
|
||||
resolvedCall: NewResolvedCallImpl<*>
|
||||
@@ -319,34 +260,44 @@ class KotlinToResolvedCallTransformer(
|
||||
return expressionType != null && TypeUtils.isNullableType(expressionType)
|
||||
}
|
||||
|
||||
private fun bindResolvedCall(context: BasicCallResolutionContext, trace: BindingTrace, simpleResolvedCall: NewResolvedCallImpl<*>) {
|
||||
reportCallDiagnostic(context, trace, simpleResolvedCall.completedCall)
|
||||
val tracing = simpleResolvedCall.completedCall.kotlinCall.psiKotlinCall.tracingStrategy
|
||||
internal fun bindAndReport(context: BasicCallResolutionContext, trace: BindingTrace, resolvedCall: ResolvedCall<*>) {
|
||||
resolvedCall.safeAs<NewResolvedCallImpl<*>>()?.let { bindAndReport(context, trace, it) }
|
||||
resolvedCall.safeAs<NewVariableAsFunctionResolvedCallImpl>()?.let { bindAndReport(context, trace, it) }
|
||||
}
|
||||
|
||||
private fun bindAndReport(context: BasicCallResolutionContext, trace: BindingTrace, simpleResolvedCall: NewResolvedCallImpl<*>) {
|
||||
val tracing = simpleResolvedCall.resolvedCallAtom.atom.psiKotlinCall.tracingStrategy
|
||||
|
||||
tracing.bindReference(trace, simpleResolvedCall)
|
||||
tracing.bindResolvedCall(trace, simpleResolvedCall)
|
||||
|
||||
reportCallDiagnostic(context, trace, simpleResolvedCall.resolvedCallAtom, simpleResolvedCall.resultingDescriptor)
|
||||
}
|
||||
|
||||
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
|
||||
private fun bindAndReport(context: BasicCallResolutionContext, trace: BindingTrace, variableAsFunction: NewVariableAsFunctionResolvedCallImpl) {
|
||||
val outerTracingStrategy = variableAsFunction.baseCall.tracingStrategy
|
||||
outerTracingStrategy.bindReference(trace, variableAsFunction.variableCall)
|
||||
outerTracingStrategy.bindResolvedCall(trace, variableAsFunction)
|
||||
variableAsFunction.functionCall.kotlinCall.psiKotlinCall.tracingStrategy.bindReference(trace, variableAsFunction.functionCall)
|
||||
|
||||
reportCallDiagnostic(context, trace, variableAsFunction.variableCall.resolvedCallAtom, variableAsFunction.variableCall.resultingDescriptor)
|
||||
reportCallDiagnostic(context, trace, variableAsFunction.functionCall.resolvedCallAtom, variableAsFunction.functionCall.resultingDescriptor)
|
||||
}
|
||||
|
||||
private fun reportCallDiagnostic(
|
||||
context: BasicCallResolutionContext,
|
||||
trace: BindingTrace,
|
||||
completedCall: CompletedKotlinCall.Simple
|
||||
completedCallAtom: ResolvedCallAtom,
|
||||
resultingDescriptor: CallableDescriptor
|
||||
) {
|
||||
val trackingTrace = TrackingBindingTrace(trace)
|
||||
val newContext = context.replaceBindingTrace(trackingTrace)
|
||||
val diagnosticReporter = DiagnosticReporterByTrackingStrategy(constantExpressionEvaluator, newContext, completedCall.kotlinCall.psiKotlinCall)
|
||||
val diagnosticReporter = DiagnosticReporterByTrackingStrategy(constantExpressionEvaluator, newContext, completedCallAtom.atom.psiKotlinCall)
|
||||
|
||||
for (diagnostic in completedCall.resolutionStatus.diagnostics) {
|
||||
val diagnosticHolder = KotlinDiagnosticsHolder.SimpleHolder()
|
||||
additionalDiagnosticReporter.reportAdditionalDiagnostics(completedCallAtom, resultingDescriptor, diagnosticHolder)
|
||||
|
||||
for (diagnostic in completedCallAtom.diagnostics + diagnosticHolder.getDiagnostics()) {
|
||||
trackingTrace.reported = false
|
||||
diagnostic.report(diagnosticReporter)
|
||||
|
||||
@@ -459,27 +410,65 @@ sealed class NewAbstractResolvedCall<D : CallableDescriptor>(): ResolvedCall<D>
|
||||
}
|
||||
|
||||
class NewResolvedCallImpl<D : CallableDescriptor>(
|
||||
val completedCall: CompletedKotlinCall.Simple
|
||||
val resolvedCallAtom: ResolvedCallAtom,
|
||||
val completed: Boolean,
|
||||
substitutor: NewTypeSubstitutor
|
||||
): NewAbstractResolvedCall<D>() {
|
||||
override val kotlinCall: KotlinCall get() = completedCall.kotlinCall
|
||||
private val resultingDescriptor = run {
|
||||
val candidateDescriptor = resolvedCallAtom.candidateDescriptor
|
||||
val containsCapturedTypes = resolvedCallAtom.candidateDescriptor.returnType?.contains { it is NewCapturedType } ?: false
|
||||
|
||||
override fun getStatus(): ResolutionStatus = completedCall.resolutionStatus.resultingApplicability.toResolutionStatus()
|
||||
when {
|
||||
candidateDescriptor is FunctionDescriptor ||
|
||||
(candidateDescriptor is PropertyDescriptor && (candidateDescriptor.typeParameters.isNotEmpty() || containsCapturedTypes)) ->
|
||||
// this code is very suspicious. Now it is very useful for BE, because they cannot do nothing with captured types,
|
||||
// but it seems like temporary solution.
|
||||
candidateDescriptor.substitute(resolvedCallAtom.substitutor).substituteAndApproximateCapturedTypes(substitutor)
|
||||
else ->
|
||||
candidateDescriptor
|
||||
}
|
||||
}
|
||||
|
||||
val typeArguments = resolvedCallAtom.substitutor.freshVariables.map {
|
||||
val substituted = substitutor.safeSubstitute(it.defaultType)
|
||||
TypeApproximator().approximateToSuperType(substituted, TypeApproximatorConfiguration.CapturedTypesApproximation) ?: substituted
|
||||
}
|
||||
|
||||
private var extensionReceiver = resolvedCallAtom.extensionReceiverArgument?.receiver?.receiverValue
|
||||
private var smartCastDispatchReceiverType: KotlinType? = null
|
||||
|
||||
override val kotlinCall: KotlinCall get() = resolvedCallAtom.atom
|
||||
|
||||
override fun getStatus(): ResolutionStatus = getResultApplicability(resolvedCallAtom.diagnostics).toResolutionStatus()
|
||||
|
||||
override val argumentMappingByOriginal: Map<ValueParameterDescriptor, ResolvedCallArgument>
|
||||
get() = completedCall.argumentMappingByOriginal
|
||||
get() = resolvedCallAtom.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 getCandidateDescriptor(): D = resolvedCallAtom.candidateDescriptor as D
|
||||
override fun getResultingDescriptor(): D = resultingDescriptor as D
|
||||
override fun getExtensionReceiver(): ReceiverValue? = extensionReceiver
|
||||
override fun getDispatchReceiver(): ReceiverValue? = resolvedCallAtom.dispatchReceiverArgument?.receiver?.receiverValue
|
||||
override fun getExplicitReceiverKind(): ExplicitReceiverKind = resolvedCallAtom.explicitReceiverKind
|
||||
|
||||
override fun getTypeArguments(): Map<TypeParameterDescriptor, KotlinType> {
|
||||
val typeParameters = candidateDescriptor.typeParameters.takeIf { it.isNotEmpty() } ?: return emptyMap()
|
||||
return typeParameters.zip(completedCall.typeArguments).toMap()
|
||||
return typeParameters.zip(typeArguments).toMap()
|
||||
}
|
||||
|
||||
override fun getSmartCastDispatchReceiverType(): KotlinType? = null // todo
|
||||
override fun getSmartCastDispatchReceiverType(): KotlinType? = smartCastDispatchReceiverType
|
||||
|
||||
fun updateExtensionReceiverWithSmartCastIfNeeded(smartCastExtensionReceiverType: KotlinType) {
|
||||
if (extensionReceiver is ImplicitClassReceiver) {
|
||||
extensionReceiver = CastImplicitClassReceiver(
|
||||
(extensionReceiver as ImplicitClassReceiver).classDescriptor,
|
||||
smartCastExtensionReceiverType
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun setSmartCastDispatchReceiverType(smartCastDispatchReceiverType: KotlinType) {
|
||||
this.smartCastDispatchReceiverType = smartCastDispatchReceiverType
|
||||
}
|
||||
}
|
||||
|
||||
fun ResolutionCandidateApplicability.toResolutionStatus(): ResolutionStatus = when (this) {
|
||||
@@ -489,30 +478,18 @@ fun ResolutionCandidateApplicability.toResolutionStatus(): ResolutionStatus = wh
|
||||
}
|
||||
|
||||
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() = candidate.status.resultingApplicability.toResolutionStatus()
|
||||
|
||||
override fun getCandidateDescriptor(): D = candidate.candidateDescriptor as D
|
||||
override fun getResultingDescriptor(): D = candidate.descriptorWithFreshTypes as D
|
||||
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
|
||||
): VariableAsFunctionResolvedCall, ResolvedCall<FunctionDescriptor> by functionCall {
|
||||
val baseCall get() = functionCall.resolvedCallAtom.atom.psiKotlinCall.cast<PSIKotlinCallForInvoke>().baseCall
|
||||
}
|
||||
|
||||
class StubOnlyVariableAsFunctionCall(
|
||||
override val variableCall: StubOnlyResolvedCall<VariableDescriptor>,
|
||||
override val functionCall: StubOnlyResolvedCall<FunctionDescriptor>
|
||||
) : VariableAsFunctionResolvedCall, ResolvedCall<FunctionDescriptor> by functionCall
|
||||
fun ResolvedCall<*>.isNewNotCompleted(): Boolean {
|
||||
if (this is NewVariableAsFunctionResolvedCallImpl) {
|
||||
return !functionCall.completed
|
||||
}
|
||||
if (this is NewResolvedCallImpl<*>) {
|
||||
return !completed
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -81,33 +81,47 @@ class ParseErrorKotlinCallArgument(
|
||||
get() = dataFlowInfoAfterThisArgument
|
||||
}
|
||||
|
||||
class LambdaKotlinCallArgumentImpl(
|
||||
abstract class PSIFunctionKotlinCallArgument(
|
||||
val outerCallContext: BasicCallResolutionContext,
|
||||
override val valueArgument: ValueArgument,
|
||||
override val dataFlowInfoBeforeThisArgument: DataFlowInfo,
|
||||
val ktLambdaExpression: KtLambdaExpression,
|
||||
override val argumentName: Name?,
|
||||
override val parametersTypes: Array<UnwrappedType?>?
|
||||
override val argumentName: Name?
|
||||
) : LambdaKotlinCallArgument, PSIKotlinCallArgument() {
|
||||
override val dataFlowInfoAfterThisArgument: DataFlowInfo
|
||||
override val dataFlowInfoAfterThisArgument: DataFlowInfo // todo drop this and use only lambdaInitialDataFlowInfo
|
||||
get() = dataFlowInfoBeforeThisArgument
|
||||
|
||||
abstract val ktFunction: KtFunction
|
||||
abstract val expression: KtExpression
|
||||
lateinit var lambdaInitialDataFlowInfo: DataFlowInfo
|
||||
}
|
||||
|
||||
class LambdaKotlinCallArgumentImpl(
|
||||
outerCallContext: BasicCallResolutionContext,
|
||||
valueArgument: ValueArgument,
|
||||
dataFlowInfoBeforeThisArgument: DataFlowInfo,
|
||||
argumentName: Name?,
|
||||
val ktLambdaExpression: KtLambdaExpression,
|
||||
override val parametersTypes: Array<UnwrappedType?>?
|
||||
) : PSIFunctionKotlinCallArgument(outerCallContext, valueArgument, dataFlowInfoBeforeThisArgument, argumentName) {
|
||||
override val ktFunction get() = ktLambdaExpression.functionLiteral
|
||||
override val expression get() = ktLambdaExpression
|
||||
}
|
||||
|
||||
class FunctionExpressionImpl(
|
||||
val outerCallContext: BasicCallResolutionContext,
|
||||
override val valueArgument: ValueArgument,
|
||||
override val dataFlowInfoBeforeThisArgument: DataFlowInfo,
|
||||
val ktFunction: KtNamedFunction,
|
||||
override val argumentName: Name?,
|
||||
outerCallContext: BasicCallResolutionContext,
|
||||
valueArgument: ValueArgument,
|
||||
dataFlowInfoBeforeThisArgument: DataFlowInfo,
|
||||
argumentName: Name?,
|
||||
override val ktFunction: KtNamedFunction,
|
||||
override val receiverType: UnwrappedType?,
|
||||
override val parametersTypes: Array<UnwrappedType?>,
|
||||
override val returnType: UnwrappedType?
|
||||
) : FunctionExpression, PSIKotlinCallArgument() {
|
||||
override val dataFlowInfoAfterThisArgument: DataFlowInfo
|
||||
get() = dataFlowInfoBeforeThisArgument
|
||||
) : FunctionExpression, PSIFunctionKotlinCallArgument(outerCallContext, valueArgument, dataFlowInfoBeforeThisArgument, argumentName) {
|
||||
override val expression get() = ktFunction
|
||||
}
|
||||
|
||||
class CallableReferenceKotlinCallArgumentImpl(
|
||||
val scopeTowerForResolution: ImplicitScopeTower,
|
||||
override val valueArgument: ValueArgument,
|
||||
override val dataFlowInfoBeforeThisArgument: DataFlowInfo,
|
||||
override val dataFlowInfoAfterThisArgument: DataFlowInfo,
|
||||
@@ -133,7 +147,7 @@ class SubKotlinCallArgumentImpl(
|
||||
override val dataFlowInfoBeforeThisArgument: DataFlowInfo,
|
||||
override val dataFlowInfoAfterThisArgument: DataFlowInfo,
|
||||
override val receiver: ReceiverValueWithSmartCastInfo,
|
||||
override val resolvedCall: ResolvedKotlinCall.OnlyResolvedKotlinCall
|
||||
override val callResult: CallResolutionResult
|
||||
): SimplePSIKotlinCallArgument(), SubKotlinCallArgument {
|
||||
override val isSpread: Boolean get() = valueArgument.getSpreadElement() != null
|
||||
override val argumentName: Name? get() = valueArgument.getArgumentName()?.asName
|
||||
@@ -171,6 +185,13 @@ class EmptyLabeledReturn(
|
||||
override val isSafeCall: Boolean get() = false
|
||||
}
|
||||
|
||||
internal fun KotlinCallArgument.setResultDataFlowInfoIfRelevant(resultDataFlowInfo: DataFlowInfo) {
|
||||
if (this is PSIFunctionKotlinCallArgument) {
|
||||
lambdaInitialDataFlowInfo = resultDataFlowInfo
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// context here is context for value argument analysis
|
||||
internal fun createSimplePSICallArgument(
|
||||
contextForArgument: BasicCallResolutionContext,
|
||||
@@ -195,15 +216,17 @@ internal fun createSimplePSICallArgument(
|
||||
}
|
||||
// todo hack for if expression: sometimes we not write properly type information for branches
|
||||
val baseType = typeInfoForArgument.type?.unwrap() ?:
|
||||
onlyResolvedCall?.candidate?.lastCall?.descriptorWithFreshTypes?.returnType?.unwrap() ?:
|
||||
onlyResolvedCall?.resultCallAtom?.freshReturnType ?:
|
||||
return null
|
||||
|
||||
// we should use DFI after this argument, because there can be some useful smartcast. Popular case: if branches.
|
||||
val receiverToCast = transformToReceiverWithSmartCastInfo(
|
||||
ownerDescriptor, bindingContext,
|
||||
typeInfoForArgument.dataFlowInfo,
|
||||
typeInfoForArgument.dataFlowInfo, // dataFlowInfoBeforeThisArgument cannot be used here, because of if() { if (x != null) return; x }
|
||||
ExpressionReceiver.create(ktExpression, baseType, bindingContext)
|
||||
).prepareReceiverRegardingCaptureTypes()
|
||||
).let {
|
||||
if (onlyResolvedCall == null) it.prepareReceiverRegardingCaptureTypes() else it
|
||||
}
|
||||
|
||||
return if (onlyResolvedCall == null) {
|
||||
ExpressionKotlinCallArgumentImpl(valueArgument, dataFlowInfoBeforeThisArgument, typeInfoForArgument.dataFlowInfo, receiverToCast)
|
||||
@@ -211,5 +234,4 @@ internal fun createSimplePSICallArgument(
|
||||
else {
|
||||
SubKotlinCallArgumentImpl(valueArgument, dataFlowInfoBeforeThisArgument, typeInfoForArgument.dataFlowInfo, receiverToCast, onlyResolvedCall)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,6 @@ 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
|
||||
@@ -38,9 +37,7 @@ import org.jetbrains.kotlin.resolve.calls.callResolverUtil.isInfixCall
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.createLookupLocation
|
||||
import org.jetbrains.kotlin.resolve.calls.context.*
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.CoroutineInferenceSupport
|
||||
import org.jetbrains.kotlin.resolve.calls.model.MutableResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCallImpl
|
||||
import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCallImpl
|
||||
import org.jetbrains.kotlin.resolve.calls.model.*
|
||||
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResultsImpl
|
||||
import org.jetbrains.kotlin.resolve.calls.results.ResolutionResultsHandler
|
||||
import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus
|
||||
@@ -108,7 +105,7 @@ class NewResolutionOldInference(
|
||||
): ScopeTowerProcessor<MyCandidate> {
|
||||
val functionFactory = outer.CandidateFactoryImpl(name, context, tracing)
|
||||
val variableFactory = outer.CandidateFactoryImpl(name, context, tracing)
|
||||
return CompositeScopeTowerProcessor(
|
||||
return PrioritizedCompositeScopeTowerProcessor(
|
||||
createSimpleFunctionProcessor(scopeTower, name, functionFactory, explicitReceiver, classValueReceiver = false),
|
||||
createVariableProcessor(scopeTower, name, variableFactory, explicitReceiver, classValueReceiver = false)
|
||||
)
|
||||
@@ -176,7 +173,7 @@ class NewResolutionOldInference(
|
||||
|
||||
// Temporary hack to resolve 'rem' as 'mod' if the first is do not present
|
||||
val emptyOrInapplicableCandidates = candidates.isEmpty() ||
|
||||
candidates.all { it.candidateStatus.resultingApplicability.isInapplicable }
|
||||
candidates.all { it.resultingApplicability.isInapplicable }
|
||||
if (isBinaryRemOperator && shouldUseOperatorRem && emptyOrInapplicableCandidates) {
|
||||
val deprecatedName = OperatorConventions.REM_TO_MOD_OPERATION_NAMES[name]
|
||||
val processorForDeprecatedName = kind.createTowerProcessor(this, deprecatedName!!, tracing, scopeTower, detailedReceiver, context)
|
||||
@@ -204,7 +201,7 @@ class NewResolutionOldInference(
|
||||
val resolvedCall = ResolvedCallImpl.create(candidate, candidateTrace, tracing, basicCallContext.dataFlowInfoForArguments)
|
||||
|
||||
if (candidate.descriptor.isHiddenInResolution(languageVersionSettings, basicCallContext.isSuperCall)) {
|
||||
return@map MyCandidate(ResolutionCandidateStatus(listOf(HiddenDescriptor)), resolvedCall)
|
||||
return@map MyCandidate(listOf(HiddenDescriptor), resolvedCall)
|
||||
}
|
||||
|
||||
val callCandidateResolutionContext = CallCandidateResolutionContext.create(
|
||||
@@ -214,16 +211,16 @@ class NewResolutionOldInference(
|
||||
candidateResolver.performResolutionForCandidateCall(callCandidateResolutionContext, basicCallContext.checkArguments) // todo
|
||||
|
||||
val diagnostics = listOfNotNull(createPreviousResolveError(resolvedCall.status))
|
||||
MyCandidate(ResolutionCandidateStatus(diagnostics), resolvedCall)
|
||||
MyCandidate(diagnostics, resolvedCall)
|
||||
}
|
||||
if (basicCallContext.collectAllCandidates) {
|
||||
val allCandidates = towerResolver.runWithEmptyTowerData(KnownResultProcessor(resolvedCandidates),
|
||||
TowerResolver.AllCandidatesCollector { it.candidateStatus }, useOrder = false)
|
||||
TowerResolver.AllCandidatesCollector(), useOrder = false)
|
||||
return allCandidatesResult(allCandidates)
|
||||
}
|
||||
|
||||
val processedCandidates = towerResolver.runWithEmptyTowerData(KnownResultProcessor(resolvedCandidates),
|
||||
TowerResolver.SuccessfulResultCollector { it.candidateStatus }, useOrder = true)
|
||||
TowerResolver.SuccessfulResultCollector(), useOrder = true)
|
||||
|
||||
return convertToOverloadResults(processedCandidates, tracing, basicCallContext, languageVersionSettings)
|
||||
}
|
||||
@@ -240,7 +237,7 @@ class NewResolutionOldInference(
|
||||
languageVersionSettings: LanguageVersionSettings
|
||||
): OverloadResolutionResultsImpl<D> {
|
||||
val resolvedCalls = candidates.map {
|
||||
val (status, resolvedCall) = it
|
||||
val (diagnostics, resolvedCall) = it
|
||||
if (resolvedCall is VariableAsFunctionResolvedCallImpl) {
|
||||
// todo hacks
|
||||
tracing.bindReference(resolvedCall.variableCall.trace, resolvedCall.variableCall)
|
||||
@@ -256,7 +253,7 @@ class NewResolutionOldInference(
|
||||
}
|
||||
|
||||
if (resolvedCall.status.possibleTransformToSuccess()) {
|
||||
for (error in status.diagnostics) {
|
||||
for (error in diagnostics) {
|
||||
when (error) {
|
||||
is UnsupportedInnerClassCall -> resolvedCall.trace.report(Errors.UNSUPPORTED.on(resolvedCall.call.callElement, error.message))
|
||||
is NestedClassViaInstanceReference -> tracing.nestedClassAccessViaInstanceReference(resolvedCall.trace, error.classDescriptor, resolvedCall.explicitReceiverKind)
|
||||
@@ -317,13 +314,11 @@ class NewResolutionOldInference(
|
||||
}
|
||||
|
||||
internal data class MyCandidate(
|
||||
val candidateStatus: ResolutionCandidateStatus,
|
||||
val diagnostics: List<KotlinCallDiagnostic>,
|
||||
val resolvedCall: MutableResolvedCall<*>
|
||||
) : Candidate {
|
||||
override val isSuccessful: Boolean
|
||||
get() = candidateStatus.resultingApplicability.isSuccess
|
||||
override val status: ResolutionCandidateStatus
|
||||
get() = candidateStatus
|
||||
override val resultingApplicability: ResolutionCandidateApplicability = getResultApplicability(diagnostics)
|
||||
override val isSuccessful get() = resultingApplicability.isSuccess
|
||||
}
|
||||
|
||||
private inner class CandidateFactoryImpl(
|
||||
@@ -358,12 +353,12 @@ class NewResolutionOldInference(
|
||||
if (parameterIsDynamic != argumentIsDynamic ||
|
||||
(parameterIsDynamic && !towerCandidate.descriptor.hasDynamicExtensionAnnotation())
|
||||
) {
|
||||
return MyCandidate(ResolutionCandidateStatus(listOf(HiddenExtensionRelatedToDynamicTypes)), candidateCall)
|
||||
return MyCandidate(listOf(HiddenExtensionRelatedToDynamicTypes), candidateCall)
|
||||
}
|
||||
}
|
||||
|
||||
if (towerCandidate.descriptor.isHiddenInResolution(languageVersionSettings, basicCallContext.isSuperCall)) {
|
||||
return MyCandidate(ResolutionCandidateStatus(listOf(HiddenDescriptor)), candidateCall)
|
||||
return MyCandidate(listOf(HiddenDescriptor), candidateCall)
|
||||
}
|
||||
|
||||
val callCandidateResolutionContext = CallCandidateResolutionContext.create(
|
||||
@@ -375,7 +370,7 @@ class NewResolutionOldInference(
|
||||
val diagnostics = (towerCandidate.diagnostics +
|
||||
checkInfixAndOperator(basicCallContext.call, towerCandidate.descriptor) +
|
||||
createPreviousResolveError(candidateCall.status)).filterNotNull() // todo
|
||||
return MyCandidate(ResolutionCandidateStatus(diagnostics), candidateCall)
|
||||
return MyCandidate(diagnostics, candidateCall)
|
||||
}
|
||||
|
||||
private fun checkInfixAndOperator(call: Call, descriptor: CallableDescriptor): List<ResolutionDiagnostic> {
|
||||
@@ -403,11 +398,11 @@ class NewResolutionOldInference(
|
||||
invoke.resolvedCall as MutableResolvedCall<FunctionDescriptor>,
|
||||
variable.resolvedCall as MutableResolvedCall<VariableDescriptor>
|
||||
)
|
||||
assert(variable.candidateStatus.resultingApplicability.isSuccess) {
|
||||
assert(variable.resultingApplicability.isSuccess) {
|
||||
"Variable call must be success: $variable"
|
||||
}
|
||||
|
||||
return MyCandidate(ResolutionCandidateStatus(variable.candidateStatus.diagnostics + invoke.candidateStatus.diagnostics), resolvedCallImpl)
|
||||
return MyCandidate(variable.diagnostics + invoke.diagnostics, resolvedCallImpl)
|
||||
}
|
||||
|
||||
override fun factoryForVariable(stripExplicitReceiver: Boolean): CandidateFactory<MyCandidate> {
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package org.jetbrains.kotlin.resolve.calls.tower
|
||||
|
||||
import org.jetbrains.kotlin.builtins.ReflectionTypes
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
@@ -27,6 +26,7 @@ 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.psi.psiUtil.getParentOfType
|
||||
import org.jetbrains.kotlin.psi.psiUtil.referenceExpression
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.ModifierCheckerCore
|
||||
@@ -39,13 +39,11 @@ import org.jetbrains.kotlin.resolve.calls.callUtil.createLookupLocation
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getCall
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getCalleeExpressionIfAny
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.isSafeCall
|
||||
import org.jetbrains.kotlin.resolve.calls.components.*
|
||||
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.model.*
|
||||
import org.jetbrains.kotlin.resolve.calls.results.*
|
||||
import org.jetbrains.kotlin.resolve.calls.results.ManyCandidates
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
|
||||
import org.jetbrains.kotlin.resolve.calls.tasks.DynamicCallableDescriptors
|
||||
@@ -60,6 +58,7 @@ 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.*
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
|
||||
import java.util.*
|
||||
|
||||
@@ -70,13 +69,7 @@ class PSICallResolver(
|
||||
private val languageVersionSettings: LanguageVersionSettings,
|
||||
private val dynamicCallableDescriptors: DynamicCallableDescriptors,
|
||||
private val syntheticScopes: SyntheticScopes,
|
||||
private val argumentsToParametersMapper: ArgumentsToParametersMapper,
|
||||
private val externalPredicates: KotlinResolutionExternalPredicates,
|
||||
private val typeArgumentsToParametersMapper: TypeArgumentsToParametersMapper,
|
||||
private val resultTypeResolver: ResultTypeResolver,
|
||||
private val callableReferenceResolver: CallableReferenceResolver,
|
||||
private val constraintInjector: ConstraintInjector,
|
||||
private val reflectionTypes: ReflectionTypes,
|
||||
private val callComponents: KotlinCallComponents,
|
||||
private val kotlinToResolvedCallTransformer: KotlinToResolvedCallTransformer,
|
||||
private val kotlinCallResolver: KotlinCallResolver,
|
||||
private val typeApproximator: TypeApproximator,
|
||||
@@ -95,17 +88,16 @@ class PSICallResolver(
|
||||
|
||||
val kotlinCall = toKotlinCall(context, resolutionKind.kotlinCallKind, context.call, refinedName, tracingStrategy)
|
||||
val scopeTower = ASTScopeTower(context)
|
||||
val lambdaAnalyzer = createLambdaAnalyzer(context)
|
||||
val resolutionCallbacks = createResolutionCallbacks(context)
|
||||
|
||||
val callContext = createCallContext(scopeTower, lambdaAnalyzer)
|
||||
val factoryProviderForInvoke = FactoryProviderForInvoke(context, callContext, kotlinCall)
|
||||
val factoryProviderForInvoke = FactoryProviderForInvoke(context, scopeTower, kotlinCall)
|
||||
|
||||
val expectedType = calculateExpectedType(context)
|
||||
var result = kotlinCallResolver.resolveCall(callContext, kotlinCall, expectedType, factoryProviderForInvoke)
|
||||
var result = kotlinCallResolver.resolveCall(scopeTower, resolutionCallbacks, kotlinCall, expectedType, factoryProviderForInvoke)
|
||||
|
||||
val shouldUseOperatorRem = languageVersionSettings.supportsFeature(LanguageFeature.OperatorRem)
|
||||
if (isBinaryRemOperator && shouldUseOperatorRem && (result.isEmpty() || result.areAllCompletedAndInapplicable())) {
|
||||
result = resolveToDeprecatedMod(name, context, resolutionKind, tracingStrategy, callContext, expectedType)
|
||||
if (isBinaryRemOperator && shouldUseOperatorRem && (result.isEmpty() || result.areAllInapplicable())) {
|
||||
result = resolveToDeprecatedMod(name, context, resolutionKind, tracingStrategy, scopeTower, resolutionCallbacks, expectedType)
|
||||
}
|
||||
|
||||
if (result.isEmpty() && reportAdditionalDiagnosticIfNoCandidates(context, scopeTower, resolutionKind.kotlinCallKind, kotlinCall)) {
|
||||
@@ -125,8 +117,7 @@ class PSICallResolver(
|
||||
|
||||
val kotlinCall = toKotlinCall(context, KotlinCallKind.FUNCTION, context.call, GIVEN_CANDIDATES_NAME, tracingStrategy, dispatchReceiver)
|
||||
val scopeTower = ASTScopeTower(context)
|
||||
val lambdaAnalyzer = createLambdaAnalyzer(context)
|
||||
val callContext = createCallContext(scopeTower, lambdaAnalyzer)
|
||||
val resolutionCallbacks = createResolutionCallbacks(context)
|
||||
|
||||
val givenCandidates = resolutionCandidates.map {
|
||||
GivenCandidate(it.descriptor as FunctionDescriptor,
|
||||
@@ -134,7 +125,7 @@ class PSICallResolver(
|
||||
it.knownTypeParametersResultingSubstitutor)
|
||||
}
|
||||
|
||||
val result = kotlinCallResolver.resolveGivenCandidates(callContext, kotlinCall, calculateExpectedType(context), givenCandidates)
|
||||
val result = kotlinCallResolver.resolveGivenCandidates(scopeTower, resolutionCallbacks, kotlinCall, calculateExpectedType(context), givenCandidates)
|
||||
return convertToOverloadResolutionResults(context, result, tracingStrategy)
|
||||
|
||||
}
|
||||
@@ -143,13 +134,15 @@ class PSICallResolver(
|
||||
remOperatorName: Name,
|
||||
context: BasicCallResolutionContext,
|
||||
resolutionKind: NewResolutionOldInference.ResolutionKind<D>,
|
||||
tracingStrategy: TracingStrategy, callContext: KotlinCallContext,
|
||||
tracingStrategy: TracingStrategy,
|
||||
scopeTower: ImplicitScopeTower,
|
||||
resolutionCallbacks: KotlinResolutionCallbacksImpl,
|
||||
expectedType: UnwrappedType?
|
||||
): Collection<ResolvedKotlinCall> {
|
||||
): CallResolutionResult {
|
||||
val deprecatedName = OperatorConventions.REM_TO_MOD_OPERATION_NAMES[remOperatorName]!!
|
||||
val callWithDeprecatedName = toKotlinCall(context, resolutionKind.kotlinCallKind, context.call, deprecatedName, tracingStrategy)
|
||||
val refinedProviderForInvokeFactory = FactoryProviderForInvoke(context, callContext, callWithDeprecatedName)
|
||||
return kotlinCallResolver.resolveCall(callContext, callWithDeprecatedName, expectedType, refinedProviderForInvokeFactory)
|
||||
val refinedProviderForInvokeFactory = FactoryProviderForInvoke(context, scopeTower, callWithDeprecatedName)
|
||||
return kotlinCallResolver.resolveCall(scopeTower, resolutionCallbacks, callWithDeprecatedName, expectedType, refinedProviderForInvokeFactory)
|
||||
}
|
||||
|
||||
private fun refineNameForRemOperator(isBinaryRemOperator: Boolean, name: Name): Name {
|
||||
@@ -157,9 +150,9 @@ class PSICallResolver(
|
||||
return if (isBinaryRemOperator && !shouldUseOperatorRem) OperatorConventions.REM_TO_MOD_OPERATION_NAMES[name]!! else name
|
||||
}
|
||||
|
||||
private fun createLambdaAnalyzer(context: BasicCallResolutionContext) =
|
||||
KotlinResolutionCallbacksImpl(context, expressionTypingServices, typeApproximator, kotlinToResolvedCallTransformer,
|
||||
argumentTypeResolver, doubleColonExpressionResolver, languageVersionSettings)
|
||||
private fun createResolutionCallbacks(context: BasicCallResolutionContext) =
|
||||
KotlinResolutionCallbacksImpl(context, expressionTypingServices, typeApproximator,
|
||||
argumentTypeResolver, languageVersionSettings, kotlinToResolvedCallTransformer)
|
||||
|
||||
private fun calculateExpectedType(context: BasicCallResolutionContext): UnwrappedType? {
|
||||
val expectedType = context.expectedType.unwrap()
|
||||
@@ -175,67 +168,69 @@ class PSICallResolver(
|
||||
}
|
||||
}
|
||||
|
||||
private fun createCallContext(scopeTower: ASTScopeTower, resolutionCallbacks: KotlinResolutionCallbacks) =
|
||||
KotlinCallContext(scopeTower, resolutionCallbacks, externalPredicates, argumentsToParametersMapper,
|
||||
typeArgumentsToParametersMapper, resultTypeResolver,
|
||||
callableReferenceResolver, constraintInjector, reflectionTypes)
|
||||
|
||||
private fun <D : CallableDescriptor> convertToOverloadResolutionResults(
|
||||
context: BasicCallResolutionContext,
|
||||
result: Collection<ResolvedKotlinCall>,
|
||||
result: CallResolutionResult,
|
||||
tracingStrategy: TracingStrategy
|
||||
): OverloadResolutionResults<D> {
|
||||
val trace = context.trace
|
||||
when (result.size) {
|
||||
0 -> {
|
||||
tracingStrategy.unresolvedReference(trace)
|
||||
return OverloadResolutionResultsImpl.nameNotFound()
|
||||
|
||||
result.diagnostics.firstIsInstanceOrNull<NoneCandidatesCallDiagnostic>()?.let {
|
||||
tracingStrategy.unresolvedReference(trace)
|
||||
return OverloadResolutionResultsImpl.nameNotFound()
|
||||
}
|
||||
|
||||
result.diagnostics.firstIsInstanceOrNull<ManyCandidatesCallDiagnostic>()?.let {
|
||||
val resolvedCalls = it.candidates.map { kotlinToResolvedCallTransformer.onlyTransform<D>(it.resolvedCall) }
|
||||
if (it.candidates.areAllFailed()) {
|
||||
tracingStrategy.noneApplicable(trace, resolvedCalls)
|
||||
tracingStrategy.recordAmbiguity(trace, resolvedCalls)
|
||||
}
|
||||
1 -> {
|
||||
val singleCandidate = result.single()
|
||||
|
||||
val isInapplicableReceiver = singleCandidate.currentStatus.resultingApplicability == ResolutionCandidateApplicability.INAPPLICABLE_WRONG_RECEIVER
|
||||
|
||||
val resolvedCall = kotlinToResolvedCallTransformer.transformAndReport<D>(singleCandidate, context, trace.takeUnless { isInapplicableReceiver })
|
||||
|
||||
if (isInapplicableReceiver) {
|
||||
tracingStrategy.unresolvedReferenceWrongReceiver(trace, listOf(resolvedCall))
|
||||
}
|
||||
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.recordAmbiguity(trace, resolvedCalls)
|
||||
if (resolvedCalls.first().status == ResolutionStatus.INCOMPLETE_TYPE_INFERENCE) {
|
||||
tracingStrategy.cannotCompleteResolve(trace, resolvedCalls)
|
||||
}
|
||||
else {
|
||||
tracingStrategy.ambiguity(trace, resolvedCalls)
|
||||
}
|
||||
tracingStrategy.ambiguity(trace, resolvedCalls)
|
||||
}
|
||||
return ManyCandidates(resolvedCalls)
|
||||
}
|
||||
return ManyCandidates(resolvedCalls)
|
||||
}
|
||||
|
||||
val singleCandidate = result.resultCallAtom ?: error("Should be not null for result: $result")
|
||||
val isInapplicableReceiver = getResultApplicability(singleCandidate.diagnostics) == ResolutionCandidateApplicability.INAPPLICABLE_WRONG_RECEIVER
|
||||
|
||||
val resolvedCall = if (isInapplicableReceiver) {
|
||||
kotlinToResolvedCallTransformer.onlyTransform<D>(singleCandidate).also {
|
||||
tracingStrategy.unresolvedReferenceWrongReceiver(trace, listOf(it))
|
||||
}
|
||||
}
|
||||
else {
|
||||
kotlinToResolvedCallTransformer.transformAndReport<D>(result, context)
|
||||
}
|
||||
return SingleOverloadResolutionResult(resolvedCall)
|
||||
}
|
||||
|
||||
private fun Collection<ResolvedKotlinCall>.areAllCompletedAndFailed() =
|
||||
private fun CallResolutionResult.isEmpty(): Boolean =
|
||||
diagnostics.firstIsInstanceOrNull<NoneCandidatesCallDiagnostic>() != null
|
||||
|
||||
private fun Collection<KotlinResolutionCandidate>.areAllFailed() =
|
||||
all {
|
||||
it is ResolvedKotlinCall.CompletedResolvedKotlinCall &&
|
||||
!it.completedCall.resolutionStatus.resultingApplicability.isSuccess
|
||||
!it.resultingApplicability.isSuccess
|
||||
}
|
||||
|
||||
private fun Collection<ResolvedKotlinCall>.areAllCompletedAndInapplicable() =
|
||||
all {
|
||||
val applicability = it.currentStatus.resultingApplicability
|
||||
applicability == ResolutionCandidateApplicability.INAPPLICABLE ||
|
||||
applicability == ResolutionCandidateApplicability.INAPPLICABLE_WRONG_RECEIVER ||
|
||||
applicability == ResolutionCandidateApplicability.HIDDEN
|
||||
}
|
||||
private fun CallResolutionResult.areAllInapplicable(): Boolean {
|
||||
val candidates = diagnostics.firstIsInstanceOrNull<ManyCandidatesCallDiagnostic>()?.candidates?.map { it.resolvedCall }
|
||||
?: listOfNotNull(resultCallAtom)
|
||||
|
||||
return candidates.all {
|
||||
val applicability = getResultApplicability(it.diagnostics)
|
||||
applicability == ResolutionCandidateApplicability.INAPPLICABLE ||
|
||||
applicability == ResolutionCandidateApplicability.INAPPLICABLE_WRONG_RECEIVER ||
|
||||
applicability == ResolutionCandidateApplicability.HIDDEN
|
||||
}
|
||||
}
|
||||
|
||||
// true if we found something
|
||||
private fun reportAdditionalDiagnosticIfNoCandidates(
|
||||
@@ -289,7 +284,7 @@ class PSICallResolver(
|
||||
|
||||
private inner class FactoryProviderForInvoke(
|
||||
val context: BasicCallResolutionContext,
|
||||
val callContext: KotlinCallContext,
|
||||
val scopeTower: ImplicitScopeTower,
|
||||
val kotlinCall: PSIKotlinCallImpl
|
||||
) : CandidateFactoryProviderForInvoke<KotlinResolutionCandidate> {
|
||||
|
||||
@@ -300,77 +295,69 @@ class PSICallResolver(
|
||||
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"
|
||||
}
|
||||
) = invoke
|
||||
|
||||
return VariableAsFunctionKotlinResolutionCandidate(kotlinCall, variable as SimpleKotlinResolutionCandidate, invoke as SimpleKotlinResolutionCandidate)
|
||||
}
|
||||
|
||||
override fun factoryForVariable(stripExplicitReceiver: Boolean): CandidateFactory<SimpleKotlinResolutionCandidate> {
|
||||
override fun factoryForVariable(stripExplicitReceiver: Boolean): CandidateFactory<KotlinResolutionCandidate> {
|
||||
val explicitReceiver = if (stripExplicitReceiver) null else kotlinCall.explicitReceiver
|
||||
val variableCall = PSIKotlinCallForVariable(kotlinCall, explicitReceiver, kotlinCall.name)
|
||||
return SimpleCandidateFactory(callContext, variableCall)
|
||||
return SimpleCandidateFactory(callComponents, scopeTower, 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
|
||||
if (isRecursiveVariableResolution(variable)) return null
|
||||
|
||||
assert(variable.isSuccessful) {
|
||||
"Variable call should be successful: $variable " +
|
||||
"Descriptor: ${variable.descriptorWithFreshTypes}"
|
||||
"Descriptor: ${variable.resolvedCall.candidateDescriptor}"
|
||||
}
|
||||
val variableCallArgument = createReceiverCallArgument(variable)
|
||||
|
||||
val explicitReceiver = kotlinCall.explicitReceiver
|
||||
val callForInvoke = if (useExplicitReceiver && explicitReceiver is SimpleKotlinCallArgument) {
|
||||
PSIKotlinCallForInvoke(kotlinCall, explicitReceiver, variableCallArgument)
|
||||
val callForInvoke = if (useExplicitReceiver && explicitReceiver != null) {
|
||||
PSIKotlinCallForInvoke(kotlinCall, variable, explicitReceiver, variableCallArgument)
|
||||
}
|
||||
else {
|
||||
PSIKotlinCallForInvoke(kotlinCall, variableCallArgument, null)
|
||||
PSIKotlinCallForInvoke(kotlinCall, variable, variableCallArgument, null)
|
||||
}
|
||||
|
||||
return variableCallArgument.receiver to SimpleCandidateFactory(callContext, callForInvoke)
|
||||
return variableCallArgument.receiver to SimpleCandidateFactory(callComponents, scopeTower, callForInvoke)
|
||||
}
|
||||
|
||||
// todo: create special check that there is no invoke on variable
|
||||
private fun isRecursiveVariableResolution(variable: SimpleKotlinResolutionCandidate): Boolean {
|
||||
val variableType = variable.candidateDescriptor.returnType
|
||||
private fun isRecursiveVariableResolution(variable: KotlinResolutionCandidate): Boolean {
|
||||
val variableType = variable.resolvedCall.candidateDescriptor.returnType
|
||||
return variableType is DeferredType && variableType.isComputing
|
||||
}
|
||||
|
||||
// todo: review
|
||||
private fun createReceiverCallArgument(variable: SimpleKotlinResolutionCandidate): SimpleKotlinCallArgument {
|
||||
private fun createReceiverCallArgument(variable: KotlinResolutionCandidate): SimpleKotlinCallArgument {
|
||||
variable.forceResolution()
|
||||
val variableReceiver = createReceiverValueWithSmartCastInfo(variable)
|
||||
if (variableReceiver.possibleTypes.isNotEmpty()) {
|
||||
return ReceiverExpressionKotlinCallArgument(createReceiverValueWithSmartCastInfo(variable), isVariableReceiverForInvoke = true)
|
||||
}
|
||||
|
||||
val psiKotlinCall = variable.kotlinCall.psiKotlinCall
|
||||
val psiKotlinCall = variable.resolvedCall.atom.psiKotlinCall
|
||||
|
||||
val variableResult = CallResolutionResult(CallResolutionResult.Type.PARTIAL, variable.resolvedCall, listOf(), variable.getSystem().asReadOnlyStorage())
|
||||
return SubKotlinCallArgumentImpl(CallMaker.makeExternalValueArgument((variableReceiver.receiverValue as ExpressionReceiver).expression),
|
||||
psiKotlinCall.resultDataFlowInfo, psiKotlinCall.resultDataFlowInfo, variableReceiver,
|
||||
ResolvedKotlinCall.OnlyResolvedKotlinCall(variable))
|
||||
variableResult)
|
||||
}
|
||||
|
||||
// todo: decrease hacks count
|
||||
private fun createReceiverValueWithSmartCastInfo(variable: SimpleKotlinResolutionCandidate): ReceiverValueWithSmartCastInfo {
|
||||
val callForVariable = variable.kotlinCall as PSIKotlinCallForVariable
|
||||
private fun createReceiverValueWithSmartCastInfo(variable: KotlinResolutionCandidate): ReceiverValueWithSmartCastInfo {
|
||||
val callForVariable = variable.resolvedCall.atom 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 type = variable.resolvedCall.freshReturnType!!
|
||||
val variableReceiver = ExpressionReceiver.create(calleeExpression, type, temporaryTrace.bindingContext)
|
||||
|
||||
temporaryTrace.record(BindingContext.REFERENCE_TARGET, calleeExpression, variable.descriptorWithFreshTypes)
|
||||
temporaryTrace.record(BindingContext.REFERENCE_TARGET, calleeExpression, variable.resolvedCall.candidateDescriptor)
|
||||
val dataFlowValue = DataFlowValueFactory.createDataFlowValue(variableReceiver, temporaryTrace.bindingContext, context.scope.ownerDescriptor)
|
||||
return ReceiverValueWithSmartCastInfo(variableReceiver, context.dataFlowInfo.getCollectedTypes(dataFlowValue), dataFlowValue.isStable)
|
||||
}
|
||||
@@ -423,6 +410,9 @@ class PSICallResolver(
|
||||
val astExternalArgument = externalArgument?.let { resolveValueArgument(context, dataFlowInfoAfterArgumentsInParenthesis, it) }
|
||||
val resultDataFlowInfo = astExternalArgument?.dataFlowInfoAfterThisArgument ?: dataFlowInfoAfterArgumentsInParenthesis
|
||||
|
||||
resolvedArgumentsInParenthesis.forEach { it.setResultDataFlowInfoIfRelevant(resultDataFlowInfo) }
|
||||
astExternalArgument?.setResultDataFlowInfoIfRelevant(resultDataFlowInfo)
|
||||
|
||||
return PSIKotlinCallImpl(kotlinCallKind, oldCall, tracingStrategy, resolvedExplicitReceiver, name, resolvedTypeArguments, resolvedArgumentsInParenthesis,
|
||||
astExternalArgument, context.dataFlowInfo, resultDataFlowInfo, context.dataFlowInfoForArguments)
|
||||
}
|
||||
@@ -494,22 +484,22 @@ class PSICallResolver(
|
||||
): PSIKotlinCallArgument {
|
||||
val builtIns = outerCallContext.scope.ownerDescriptor.builtIns
|
||||
val parseErrorArgument = ParseErrorKotlinCallArgument(valueArgument, startDataFlowInfo, builtIns)
|
||||
val ktExpression = KtPsiUtil.deparenthesize(valueArgument.getArgumentExpression()) ?:
|
||||
return parseErrorArgument
|
||||
val ktExpression = extractArgumentExpression(outerCallContext, valueArgument) ?: parseErrorArgument
|
||||
|
||||
val argumentName = valueArgument.getArgumentName()?.asName
|
||||
|
||||
val lambdaArgument: PSIKotlinCallArgument? = when (ktExpression) {
|
||||
is KtLambdaExpression ->
|
||||
LambdaKotlinCallArgumentImpl(outerCallContext, valueArgument, startDataFlowInfo, ktExpression, argumentName,
|
||||
LambdaKotlinCallArgumentImpl(outerCallContext, valueArgument, startDataFlowInfo, argumentName, ktExpression,
|
||||
resolveParametersTypes(outerCallContext, ktExpression.functionLiteral))
|
||||
is KtNamedFunction -> {
|
||||
val receiverType = resolveType(outerCallContext, ktExpression.receiverTypeReference)
|
||||
val parametersTypes = resolveParametersTypes(outerCallContext, ktExpression) ?: emptyArray()
|
||||
val returnType = resolveType(outerCallContext, ktExpression.typeReference) ?:
|
||||
if (ktExpression.hasBlockBody()) builtIns.unitType else null
|
||||
FunctionExpressionImpl(outerCallContext, valueArgument, startDataFlowInfo, ktExpression, argumentName, receiverType, parametersTypes, returnType)
|
||||
FunctionExpressionImpl(outerCallContext, valueArgument, startDataFlowInfo, argumentName, ktExpression, receiverType, parametersTypes, returnType)
|
||||
}
|
||||
|
||||
else -> null
|
||||
}
|
||||
if (lambdaArgument != null) {
|
||||
@@ -543,28 +533,29 @@ class PSICallResolver(
|
||||
LHSResult.Object(ClassQualifier(calleeExpression, classifier))
|
||||
}
|
||||
else {
|
||||
LHSResult.Empty // this is error case actually
|
||||
LHSResult.Error
|
||||
}
|
||||
}
|
||||
else {
|
||||
val fakeArgument = FakeValueArgumentForLeftCallableReference(ktExpression)
|
||||
|
||||
val kotlinCallArgument = createSimplePSICallArgument(context, fakeArgument, lhsResult.typeInfo)
|
||||
kotlinCallArgument?.let { LHSResult.Expression(it as SimpleKotlinCallArgument) } ?: LHSResult.Empty
|
||||
kotlinCallArgument?.let { LHSResult.Expression(it as SimpleKotlinCallArgument) } ?: LHSResult.Error
|
||||
}
|
||||
}
|
||||
is DoubleColonLHS.Type -> {
|
||||
val qualifier = expressionTypingContext.trace.get(BindingContext.QUALIFIER, ktExpression.receiverExpression!!.referenceExpression())
|
||||
val qualifiedExpression = ktExpression.receiverExpression!!.let { it.referenceExpression() ?: it }
|
||||
val qualifier = expressionTypingContext.trace.get(BindingContext.QUALIFIER, qualifiedExpression)
|
||||
if (qualifier is ClassQualifier) {
|
||||
LHSResult.Type(qualifier, lhsResult.type.unwrap())
|
||||
}
|
||||
else {
|
||||
LHSResult.Empty // this is error case actually
|
||||
LHSResult.Error
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return CallableReferenceKotlinCallArgumentImpl(valueArgument, startDataFlowInfo, newDataFlowInfo,
|
||||
return CallableReferenceKotlinCallArgumentImpl(ASTScopeTower(context), valueArgument, startDataFlowInfo, newDataFlowInfo,
|
||||
ktExpression, argumentName, lhsNewResult, name)
|
||||
}
|
||||
|
||||
@@ -573,6 +564,19 @@ class PSICallResolver(
|
||||
return createSimplePSICallArgument(context, valueArgument, typeInfo) ?: parseErrorArgument
|
||||
}
|
||||
|
||||
private fun extractArgumentExpression(outerCallContext: BasicCallResolutionContext, valueArgument: ValueArgument): KtExpression? {
|
||||
val argumentExpression = valueArgument.getArgumentExpression() ?: return null
|
||||
|
||||
val ktExpression = ArgumentTypeResolver.getFunctionLiteralArgumentIfAny(argumentExpression, outerCallContext) ?:
|
||||
ArgumentTypeResolver.getCallableReferenceExpressionIfAny(argumentExpression, outerCallContext) ?:
|
||||
KtPsiUtil.deparenthesize(argumentExpression)
|
||||
|
||||
return when (ktExpression) {
|
||||
is KtFunctionLiteral -> ktExpression.getParentOfType<KtLambdaExpression>(true)
|
||||
else -> ktExpression
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkNoSpread(context: BasicCallResolutionContext, valueArgument: ValueArgument) {
|
||||
valueArgument.getSpreadElement()?.let {
|
||||
context.trace.report(Errors.SPREAD_OF_LAMBDA_OR_CALLABLE_REFERENCE.on(it))
|
||||
|
||||
@@ -24,6 +24,7 @@ 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.resolve.scopes.receivers.ReceiverValue
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
|
||||
val KotlinCall.psiKotlinCall: PSIKotlinCall get() {
|
||||
@@ -79,7 +80,8 @@ class PSIKotlinCallForVariable(
|
||||
|
||||
class PSIKotlinCallForInvoke(
|
||||
val baseCall: PSIKotlinCallImpl,
|
||||
override val explicitReceiver: SimpleKotlinCallArgument,
|
||||
val variableCall: KotlinResolutionCandidate,
|
||||
override val explicitReceiver: ReceiverKotlinCallArgument,
|
||||
override val dispatchReceiverForInvokeExtension: SimpleKotlinCallArgument?
|
||||
) : PSIKotlinCall() {
|
||||
override val callKind: KotlinCallKind get() = KotlinCallKind.FUNCTION
|
||||
@@ -100,8 +102,15 @@ class PSIKotlinCallForInvoke(
|
||||
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)
|
||||
explicitExtensionReceiver?.receiverValue,
|
||||
variableReceiver.receiverValue as ExpressionReceiver, baseCall.psiCall, true)
|
||||
tracingStrategy = TracingStrategyForInvoke(calleeExpression, psiCall, variableReceiver.receiverValue!!.type) // check for type parameters
|
||||
}
|
||||
}
|
||||
|
||||
val ReceiverKotlinCallArgument.receiverValue: ReceiverValue?
|
||||
get() = when (this) {
|
||||
is SimpleKotlinCallArgument -> this.receiver.receiverValue
|
||||
is QualifierReceiverKotlinCallArgument -> this.receiver.classValueReceiver
|
||||
else -> null
|
||||
}
|
||||
@@ -0,0 +1,201 @@
|
||||
/*
|
||||
* 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.replaceReturnType
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.impl.FunctionDescriptorImpl
|
||||
import org.jetbrains.kotlin.psi.KtElement
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.BindingTrace
|
||||
import org.jetbrains.kotlin.resolve.TemporaryBindingTrace
|
||||
import org.jetbrains.kotlin.resolve.calls.ArgumentTypeResolver
|
||||
import org.jetbrains.kotlin.resolve.calls.checkers.CallCheckerContext
|
||||
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext
|
||||
import org.jetbrains.kotlin.resolve.calls.context.ContextDependency
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.components.NewTypeSubstitutor
|
||||
import org.jetbrains.kotlin.resolve.calls.model.*
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
|
||||
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
|
||||
import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategyImpl
|
||||
import org.jetbrains.kotlin.resolve.calls.util.CallMaker
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.expressions.DoubleColonExpressionResolver
|
||||
import org.jetbrains.kotlin.types.expressions.ExpressionTypingServices
|
||||
import org.jetbrains.kotlin.types.typeUtil.asTypeProjection
|
||||
|
||||
class ResolvedAtomCompleter(
|
||||
private val resultSubstitutor: NewTypeSubstitutor,
|
||||
private val trace: BindingTrace,
|
||||
private val topLevelCallContext: BasicCallResolutionContext,
|
||||
|
||||
private val kotlinToResolvedCallTransformer: KotlinToResolvedCallTransformer,
|
||||
private val expressionTypingServices: ExpressionTypingServices,
|
||||
private val argumentTypeResolver: ArgumentTypeResolver,
|
||||
private val doubleColonExpressionResolver: DoubleColonExpressionResolver,
|
||||
languageVersionSettings: LanguageVersionSettings
|
||||
) {
|
||||
private val callCheckerContext = CallCheckerContext(topLevelCallContext, languageVersionSettings)
|
||||
|
||||
fun completeAndReport(resolvedAtom: ResolvedAtom) {
|
||||
when (resolvedAtom) {
|
||||
is ResolvedCollectionLiteralAtom -> completeCollectionLiteralCalls(resolvedAtom)
|
||||
is ResolvedCallableReferenceAtom -> completeCallableReference(resolvedAtom)
|
||||
is ResolvedLambdaAtom -> completeLambda(resolvedAtom)
|
||||
is ResolvedCallAtom -> completeResolvedCall(resolvedAtom)
|
||||
}
|
||||
}
|
||||
|
||||
fun completeAll(resolvedAtom: ResolvedAtom) {
|
||||
for (subKtPrimitive in resolvedAtom.subResolvedAtoms) {
|
||||
completeAll(subKtPrimitive)
|
||||
}
|
||||
completeAndReport(resolvedAtom)
|
||||
}
|
||||
|
||||
fun completeResolvedCall(resolvedCallAtom: ResolvedCallAtom): ResolvedCall<*>? {
|
||||
if (resolvedCallAtom.atom.psiKotlinCall is PSIKotlinCallForVariable) return null
|
||||
|
||||
val resolvedCall = kotlinToResolvedCallTransformer.transformToResolvedCall<CallableDescriptor>(resolvedCallAtom, true, resultSubstitutor)
|
||||
kotlinToResolvedCallTransformer.bindAndReport(topLevelCallContext, trace, resolvedCall)
|
||||
kotlinToResolvedCallTransformer.runCallCheckers(resolvedCall, callCheckerContext)
|
||||
|
||||
val lastCall = if (resolvedCall is VariableAsFunctionResolvedCall) resolvedCall.functionCall else resolvedCall
|
||||
kotlinToResolvedCallTransformer.runArgumentsChecks(topLevelCallContext, trace, lastCall as NewResolvedCallImpl<*>)
|
||||
|
||||
return resolvedCall
|
||||
}
|
||||
|
||||
private fun completeLambda(lambda: ResolvedLambdaAtom) {
|
||||
val returnType = resultSubstitutor.safeSubstitute(lambda.returnType)
|
||||
|
||||
updateTraceForLambdaReturnType(lambda, trace, returnType)
|
||||
|
||||
for (lambdaResult in lambda.resultArguments) {
|
||||
val resultValueArgument = lambdaResult as? PSIKotlinCallArgument ?: continue
|
||||
val newContext =
|
||||
topLevelCallContext.replaceDataFlowInfo(resultValueArgument.dataFlowInfoAfterThisArgument)
|
||||
.replaceExpectedType(returnType)
|
||||
.replaceBindingTrace(trace)
|
||||
|
||||
val argumentExpression = resultValueArgument.valueArgument.getArgumentExpression() ?: continue
|
||||
kotlinToResolvedCallTransformer.updateRecordedType(argumentExpression, newContext)
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateTraceForLambdaReturnType(lambda: ResolvedLambdaAtom, trace: BindingTrace, returnType: UnwrappedType) {
|
||||
val psiCallArgument = lambda.atom.psiCallArgument
|
||||
|
||||
val ktArgumentExpression: KtExpression
|
||||
val ktFunction: KtElement
|
||||
when (psiCallArgument) {
|
||||
is LambdaKotlinCallArgumentImpl -> {
|
||||
ktArgumentExpression = psiCallArgument.ktLambdaExpression
|
||||
ktFunction = ktArgumentExpression.functionLiteral
|
||||
}
|
||||
is FunctionExpressionImpl -> {
|
||||
ktArgumentExpression = psiCallArgument.ktFunction
|
||||
ktFunction = ktArgumentExpression
|
||||
}
|
||||
else -> throw AssertionError("Unexpected psiCallArgument for resolved lambda argument: $psiCallArgument")
|
||||
}
|
||||
|
||||
val functionDescriptor = trace.bindingContext.get(BindingContext.FUNCTION, ktFunction) as? FunctionDescriptorImpl ?:
|
||||
throw AssertionError("No function descriptor for resolved lambda argument")
|
||||
functionDescriptor.setReturnType(returnType)
|
||||
|
||||
val existingLambdaType = trace.getType(ktArgumentExpression) ?: throw AssertionError("No type for resolved lambda argument")
|
||||
trace.recordType(ktArgumentExpression, existingLambdaType.replaceReturnType(returnType))
|
||||
}
|
||||
|
||||
private fun completeCallableReference(
|
||||
resolvedAtom: ResolvedCallableReferenceAtom
|
||||
) {
|
||||
val callableCandidate = resolvedAtom.candidate
|
||||
if (callableCandidate == null) {
|
||||
// todo report meanfull diagnostic here
|
||||
return
|
||||
}
|
||||
val resultTypeParameters = callableCandidate.freshSubstitutor!!.freshVariables.map { resultSubstitutor.safeSubstitute(it.defaultType) }
|
||||
|
||||
|
||||
val psiCallArgument = resolvedAtom.atom.psiCallArgument as CallableReferenceKotlinCallArgumentImpl
|
||||
val callableReferenceExpression = psiCallArgument.ktCallableReferenceExpression
|
||||
val resultSubstitutor = IndexedParametersSubstitution(callableCandidate.candidate.typeParameters, resultTypeParameters.map { it.asTypeProjection() }).buildSubstitutor()
|
||||
|
||||
|
||||
// write down type for callable reference expression
|
||||
val resultType = resultSubstitutor.safeSubstitute(callableCandidate.reflectionCandidateType, Variance.INVARIANT)
|
||||
argumentTypeResolver.updateResultArgumentTypeIfNotDenotable(trace, expressionTypingServices.statementFilter,
|
||||
resultType,
|
||||
callableReferenceExpression)
|
||||
val reference = callableReferenceExpression.callableReference
|
||||
|
||||
val explicitCallableReceiver = when (callableCandidate.explicitReceiverKind) {
|
||||
ExplicitReceiverKind.DISPATCH_RECEIVER -> callableCandidate.dispatchReceiver
|
||||
ExplicitReceiverKind.EXTENSION_RECEIVER -> callableCandidate.extensionReceiver
|
||||
else -> null
|
||||
}
|
||||
|
||||
val explicitReceiver = explicitCallableReceiver?.receiver
|
||||
val psiCall = CallMaker.makeCall(reference, explicitReceiver?.receiverValue, null, reference, emptyList())
|
||||
|
||||
val tracing = TracingStrategyImpl.create(reference, psiCall)
|
||||
val temporaryTrace = TemporaryBindingTrace.create(trace, "callable reference fake call")
|
||||
|
||||
val resolvedCall = ResolvedCallImpl(psiCall, callableCandidate.candidate, callableCandidate.dispatchReceiver?.receiver?.receiverValue,
|
||||
callableCandidate.extensionReceiver?.receiver?.receiverValue, callableCandidate.explicitReceiverKind,
|
||||
null, temporaryTrace, tracing, MutableDataFlowInfoForArguments.WithoutArgumentsCheck(DataFlowInfo.EMPTY))
|
||||
resolvedCall.setResultingSubstitutor(resultSubstitutor)
|
||||
|
||||
tracing.bindCall(trace, psiCall)
|
||||
tracing.bindReference(trace, resolvedCall)
|
||||
tracing.bindResolvedCall(trace, resolvedCall)
|
||||
|
||||
resolvedCall.setStatusToSuccess()
|
||||
resolvedCall.markCallAsCompleted()
|
||||
|
||||
when (callableCandidate.candidate) {
|
||||
is FunctionDescriptor -> doubleColonExpressionResolver.bindFunctionReference(callableReferenceExpression, resultType, topLevelCallContext)
|
||||
is PropertyDescriptor -> doubleColonExpressionResolver.bindPropertyReference(callableReferenceExpression, resultType, topLevelCallContext)
|
||||
}
|
||||
|
||||
// TODO: probably we should also record key 'DATA_FLOW_INFO_BEFORE', see ExpressionTypingVisitorDispatcher.getTypeInfo
|
||||
trace.recordType(callableReferenceExpression, resultType)
|
||||
trace.record(BindingContext.PROCESSED, callableReferenceExpression)
|
||||
|
||||
doubleColonExpressionResolver.checkReferenceIsToAllowedMember(callableCandidate.candidate, topLevelCallContext.trace, callableReferenceExpression)
|
||||
}
|
||||
|
||||
private fun completeCollectionLiteralCalls(collectionLiteralArgument: ResolvedCollectionLiteralAtom) {
|
||||
val psiCallArgument = collectionLiteralArgument.atom.psiCallArgument as CollectionLiteralKotlinCallArgumentImpl
|
||||
val context = psiCallArgument.outerCallContext
|
||||
|
||||
val expectedType = collectionLiteralArgument.expectedType?.let { resultSubstitutor.safeSubstitute(it) } ?: TypeUtils.NO_EXPECTED_TYPE
|
||||
|
||||
val actualContext = context
|
||||
.replaceBindingTrace(trace)
|
||||
.replaceExpectedType(expectedType)
|
||||
.replaceContextDependency(ContextDependency.INDEPENDENT)
|
||||
|
||||
expressionTypingServices.getTypeInfo(psiCallArgument.collectionLiteralExpression, actualContext)
|
||||
}
|
||||
}
|
||||
@@ -318,7 +318,6 @@ public class ExpressionTypingServices {
|
||||
ContextDependency dependency = context.contextDependency;
|
||||
if (KotlinResolutionConfigurationKt.getUSE_NEW_INFERENCE()) {
|
||||
dependency = ContextDependency.INDEPENDENT;
|
||||
|
||||
}
|
||||
|
||||
return blockLevelVisitor.getTypeInfo(statementExpression, context.replaceExpectedType(expectedType).replaceContextDependency(dependency), true);
|
||||
|
||||
@@ -17,10 +17,10 @@
|
||||
package org.jetbrains.kotlin.resolve.calls
|
||||
|
||||
import org.jetbrains.kotlin.resolve.calls.components.KotlinCallCompleter
|
||||
import org.jetbrains.kotlin.resolve.calls.components.KotlinResolutionCallbacks
|
||||
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
|
||||
@@ -29,20 +29,20 @@ import java.lang.UnsupportedOperationException
|
||||
class KotlinCallResolver(
|
||||
private val towerResolver: TowerResolver,
|
||||
private val kotlinCallCompleter: KotlinCallCompleter,
|
||||
private val overloadingConflictResolver: NewOverloadingConflictResolver
|
||||
private val overloadingConflictResolver: NewOverloadingConflictResolver,
|
||||
private val callComponents: KotlinCallComponents
|
||||
) {
|
||||
|
||||
fun resolveCall(
|
||||
callContext: KotlinCallContext,
|
||||
scopeTower: ImplicitScopeTower,
|
||||
resolutionCallbacks: KotlinResolutionCallbacks,
|
||||
kotlinCall: KotlinCall,
|
||||
expectedType: UnwrappedType?,
|
||||
factoryProviderForInvoke: CandidateFactoryProviderForInvoke<KotlinResolutionCandidate>
|
||||
): Collection<ResolvedKotlinCall> {
|
||||
val scopeTower = callContext.scopeTower
|
||||
|
||||
): CallResolutionResult {
|
||||
kotlinCall.checkCallInvariants()
|
||||
|
||||
val candidateFactory = SimpleCandidateFactory(callContext, kotlinCall)
|
||||
val candidateFactory = SimpleCandidateFactory(callComponents, scopeTower, kotlinCall)
|
||||
val processor = when(kotlinCall.callKind) {
|
||||
KotlinCallKind.VARIABLE -> {
|
||||
createVariableAndObjectProcessor(scopeTower, kotlinCall.name, candidateFactory, kotlinCall.explicitReceiver?.receiver)
|
||||
@@ -55,58 +55,41 @@ class KotlinCallResolver(
|
||||
|
||||
val candidates = towerResolver.runResolve(scopeTower, processor, useOrder = kotlinCall.callKind != KotlinCallKind.UNSUPPORTED)
|
||||
|
||||
return choseMostSpecific(callContext, expectedType, candidates)
|
||||
return choseMostSpecific(candidateFactory, resolutionCallbacks, expectedType, candidates)
|
||||
}
|
||||
|
||||
fun resolveGivenCandidates(
|
||||
callContext: KotlinCallContext,
|
||||
scopeTower: ImplicitScopeTower,
|
||||
resolutionCallbacks: KotlinResolutionCallbacks,
|
||||
kotlinCall: KotlinCall,
|
||||
expectedType: UnwrappedType?,
|
||||
givenCandidates: Collection<GivenCandidate>
|
||||
): Collection<ResolvedKotlinCall> {
|
||||
): CallResolutionResult {
|
||||
kotlinCall.checkCallInvariants()
|
||||
val candidateFactory = SimpleCandidateFactory(callComponents, scopeTower, kotlinCall)
|
||||
|
||||
val isSafeCall = (kotlinCall.explicitReceiver as? SimpleKotlinCallArgument)?.isSafeCall ?: false
|
||||
|
||||
val resolutionCandidates = givenCandidates.map {
|
||||
SimpleKotlinResolutionCandidate(callContext,
|
||||
kotlinCall,
|
||||
if (it.dispatchReceiver == null) ExplicitReceiverKind.NO_EXPLICIT_RECEIVER else ExplicitReceiverKind.DISPATCH_RECEIVER,
|
||||
it.dispatchReceiver?.let { ReceiverExpressionKotlinCallArgument(it, isSafeCall) },
|
||||
null,
|
||||
it.descriptor,
|
||||
it.knownTypeParametersResultingSubstitutor,
|
||||
listOf()
|
||||
)
|
||||
}
|
||||
val resolutionCandidates = givenCandidates.map { candidateFactory.createCandidate(it).forceResolution() }
|
||||
val candidates = towerResolver.runWithEmptyTowerData(KnownResultProcessor(resolutionCandidates),
|
||||
TowerResolver.SuccessfulResultCollector { it.status },
|
||||
TowerResolver.SuccessfulResultCollector(),
|
||||
useOrder = true)
|
||||
return choseMostSpecific(callContext, expectedType, candidates)
|
||||
return choseMostSpecific(candidateFactory, resolutionCallbacks, expectedType, candidates)
|
||||
}
|
||||
|
||||
private fun choseMostSpecific(
|
||||
callContext: KotlinCallContext,
|
||||
candidateFactory: SimpleCandidateFactory,
|
||||
resolutionCallbacks: KotlinResolutionCallbacks,
|
||||
expectedType: UnwrappedType?,
|
||||
candidates: Collection<KotlinResolutionCandidate>
|
||||
): Collection<ResolvedKotlinCall> {
|
||||
): CallResolutionResult {
|
||||
val isDebuggerContext = candidateFactory.scopeTower.isDebuggerContext
|
||||
|
||||
val maximallySpecificCandidates = overloadingConflictResolver.chooseMaximallySpecificCandidates(
|
||||
candidates,
|
||||
CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS,
|
||||
discriminateGenerics = true, // todo
|
||||
isDebuggerContext = callContext.scopeTower.isDebuggerContext)
|
||||
isDebuggerContext = isDebuggerContext)
|
||||
|
||||
val singleResult = maximallySpecificCandidates.singleOrNull()?.let {
|
||||
kotlinCallCompleter.completeCallIfNecessary(it, expectedType, callContext.resolutionCallbacks)
|
||||
}
|
||||
if (singleResult != null) {
|
||||
return listOf(singleResult)
|
||||
}
|
||||
|
||||
return maximallySpecificCandidates.map {
|
||||
kotlinCallCompleter.transformWhenAmbiguity(it, callContext.resolutionCallbacks)
|
||||
}
|
||||
return kotlinCallCompleter.runCompletion(candidateFactory, maximallySpecificCandidates, expectedType, resolutionCallbacks)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package org.jetbrains.kotlin.resolve.calls
|
||||
|
||||
val USE_NEW_INFERENCE = false
|
||||
val USE_NEW_INFERENCE
|
||||
get() = false
|
||||
|
||||
val REPORT_MISSING_NEW_INFERENCE_DIAGNOSTIC = false
|
||||
val REPORT_MISSING_NEW_INFERENCE_DIAGNOSTIC
|
||||
get() = false
|
||||
|
||||
@@ -21,65 +21,74 @@ import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor
|
||||
import org.jetbrains.kotlin.resolve.calls.model.*
|
||||
import org.jetbrains.kotlin.types.UnwrappedType
|
||||
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
|
||||
import org.jetbrains.kotlin.utils.SmartList
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
|
||||
// very initial state of component
|
||||
// todo: handle all diagnostic inside DiagnosticReporterByTrackingStrategy
|
||||
// move it to frontend module
|
||||
class AdditionalDiagnosticReporter {
|
||||
|
||||
fun createAdditionalDiagnostics(
|
||||
candidate: SimpleKotlinResolutionCandidate,
|
||||
resultingDescriptor: CallableDescriptor
|
||||
): List<KotlinCallDiagnostic> = reportSmartCasts(candidate, resultingDescriptor)
|
||||
fun reportAdditionalDiagnostics(
|
||||
candidate: ResolvedCallAtom,
|
||||
resultingDescriptor: CallableDescriptor,
|
||||
kotlinDiagnosticsHolder: KotlinDiagnosticsHolder
|
||||
) {
|
||||
reportSmartCasts(candidate, resultingDescriptor, kotlinDiagnosticsHolder)
|
||||
}
|
||||
|
||||
private fun createSmartCastDiagnostic(argument: KotlinCallArgument, expectedResultType: UnwrappedType): SmartCastDiagnostic? {
|
||||
private fun createSmartCastDiagnostic(
|
||||
candidate: ResolvedCallAtom,
|
||||
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 SmartCastDiagnostic(argument, expectedResultType.unwrap(), candidate.atom)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
private fun reportSmartCastOnReceiver(
|
||||
candidate: KotlinResolutionCandidate,
|
||||
candidate: ResolvedCallAtom,
|
||||
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
|
||||
val smartCastDiagnostic = createSmartCastDiagnostic(candidate, receiver, expectedType) ?: return null
|
||||
|
||||
// todo may be we have smart cast to Int?
|
||||
return smartCastDiagnostic.takeIf {
|
||||
candidate.status.diagnostics.filterIsInstance<UnsafeCallError>().none {
|
||||
candidate.diagnostics.filterIsInstance<UnsafeCallError>().none {
|
||||
it.receiver == receiver
|
||||
}
|
||||
&&
|
||||
candidate.status.diagnostics.filterIsInstance<UnstableSmartCast>().none {
|
||||
candidate.diagnostics.filterIsInstance<UnstableSmartCast>().none {
|
||||
it.argument == receiver
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun reportSmartCasts(candidate: SimpleKotlinResolutionCandidate, resultingDescriptor: CallableDescriptor) =
|
||||
SmartList<KotlinCallDiagnostic>().apply {
|
||||
addIfNotNull(reportSmartCastOnReceiver(candidate, candidate.extensionReceiver, resultingDescriptor.extensionReceiverParameter))
|
||||
addIfNotNull(reportSmartCastOnReceiver(candidate, candidate.dispatchReceiverArgument, resultingDescriptor.dispatchReceiverParameter))
|
||||
private fun reportSmartCasts(
|
||||
candidate: ResolvedCallAtom,
|
||||
resultingDescriptor: CallableDescriptor,
|
||||
kotlinDiagnosticsHolder: KotlinDiagnosticsHolder
|
||||
) {
|
||||
kotlinDiagnosticsHolder.addDiagnosticIfNotNull(reportSmartCastOnReceiver(candidate, candidate.extensionReceiverArgument, resultingDescriptor.extensionReceiverParameter))
|
||||
kotlinDiagnosticsHolder.addDiagnosticIfNotNull(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
|
||||
for (parameter in resultingDescriptor.valueParameters) {
|
||||
for (argument in candidate.argumentMappingByOriginal[parameter.original]?.arguments ?: continue) {
|
||||
val smartCastDiagnostic = createSmartCastDiagnostic(candidate, argument, argument.getExpectedType(parameter)) ?: continue
|
||||
|
||||
val thereIsUnstableSmartCastError = candidate.status.diagnostics.filterIsInstance<UnstableSmartCast>().any {
|
||||
it.argument == argument
|
||||
}
|
||||
val thereIsUnstableSmartCastError = candidate.diagnostics.filterIsInstance<UnstableSmartCast>().any {
|
||||
it.argument == argument
|
||||
}
|
||||
|
||||
if (!thereIsUnstableSmartCastError) {
|
||||
add(smartCastDiagnostic)
|
||||
}
|
||||
}
|
||||
if (!thereIsUnstableSmartCastError) {
|
||||
kotlinDiagnosticsHolder.addDiagnostic(smartCastDiagnostic)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,11 +16,13 @@
|
||||
|
||||
package org.jetbrains.kotlin.resolve.calls.components
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ParameterDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
||||
import org.jetbrains.kotlin.resolve.calls.model.KotlinCallArgument
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValueWithSmartCastInfo
|
||||
import org.jetbrains.kotlin.types.UnwrappedType
|
||||
import org.jetbrains.kotlin.types.checker.intersectWrappedTypes
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
|
||||
internal fun unexpectedArgument(argument: KotlinCallArgument): Nothing =
|
||||
@@ -40,12 +42,12 @@ internal val ReceiverValueWithSmartCastInfo.stableType: UnwrappedType
|
||||
return intersectWrappedTypes(possibleTypes + receiverValue.type)
|
||||
}
|
||||
|
||||
internal fun KotlinCallArgument.getExpectedType(parameter: ValueParameterDescriptor) =
|
||||
internal fun KotlinCallArgument.getExpectedType(parameter: ParameterDescriptor) =
|
||||
if (this.isSpread) {
|
||||
parameter.type.unwrap()
|
||||
}
|
||||
else {
|
||||
parameter.varargElementType?.unwrap() ?: parameter.type.unwrap()
|
||||
parameter.safeAs<ValueParameterDescriptor>()?.varargElementType?.unwrap() ?: parameter.type.unwrap()
|
||||
}
|
||||
|
||||
val ValueParameterDescriptor.isVararg: Boolean get() = varargElementType != null
|
||||
|
||||
@@ -21,7 +21,7 @@ import org.jetbrains.kotlin.builtins.getReturnTypeFromFunctionType
|
||||
import org.jetbrains.kotlin.builtins.isFunctionType
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.resolve.calls.components.CreateDescriptorWithFreshTypeVariables.createToFreshVariableSubstitutorAndAddInitialConstraints
|
||||
import org.jetbrains.kotlin.resolve.calls.components.CreateFreshVariablesSubstitutor.createToFreshVariableSubstitutorAndAddInitialConstraints
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemOperation
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.components.FreshVariableNewTypeSubstitutor
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.ArgumentConstraintPosition
|
||||
@@ -35,13 +35,10 @@ import org.jetbrains.kotlin.resolve.scopes.receivers.DetailedReceiver
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.QualifierReceiver
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValueWithSmartCastInfo
|
||||
import org.jetbrains.kotlin.types.ErrorUtils
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.UnwrappedType
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.expressions.CoercionStrategy
|
||||
import org.jetbrains.kotlin.types.typeUtil.immediateSupertypes
|
||||
import org.jetbrains.kotlin.types.typeUtil.isUnit
|
||||
import org.jetbrains.kotlin.types.upperIfFlexible
|
||||
import org.jetbrains.kotlin.utils.SmartList
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
|
||||
@@ -71,9 +68,13 @@ class CallableReferenceCandidate(
|
||||
val explicitReceiverKind: ExplicitReceiverKind,
|
||||
val reflectionCandidateType: UnwrappedType,
|
||||
val numDefaults: Int,
|
||||
override val status: ResolutionCandidateStatus
|
||||
val diagnostics: List<KotlinCallDiagnostic>
|
||||
) : Candidate {
|
||||
override val isSuccessful get() = status.resultingApplicability.isSuccess
|
||||
override val resultingApplicability = getResultApplicability(diagnostics)
|
||||
override val isSuccessful get() = resultingApplicability.isSuccess
|
||||
|
||||
var freshSubstitutor: FreshVariableNewTypeSubstitutor? = null
|
||||
internal set
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -87,7 +88,7 @@ class CallableReferenceCandidate(
|
||||
fun createCallableReferenceProcessor(factory: CallableReferencesCandidateFactory): ScopeTowerProcessor<CallableReferenceCandidate> {
|
||||
val lhsResult = factory.argument.lhsResult
|
||||
when (lhsResult) {
|
||||
LHSResult.Empty, is LHSResult.Expression -> {
|
||||
LHSResult.Empty, LHSResult.Error, is LHSResult.Expression -> {
|
||||
val explicitReceiver = (lhsResult as? LHSResult.Expression)?.lshCallArgument?.receiver
|
||||
return factory.createCallableProcessor(explicitReceiver)
|
||||
}
|
||||
@@ -95,18 +96,18 @@ fun createCallableReferenceProcessor(factory: CallableReferencesCandidateFactory
|
||||
val static = factory.createCallableProcessor(lhsResult.qualifier)
|
||||
val unbound = factory.createCallableProcessor(lhsResult.unboundDetailedReceiver)
|
||||
|
||||
// note that if we use CompositeScopeTowerProcessor then static will win over unbound members
|
||||
val staticOrUnbound = CompositeSimpleScopeTowerProcessor(static, unbound)
|
||||
// note that if we use PrioritizedCompositeScopeTowerProcessor then static will win over unbound members
|
||||
val staticOrUnbound = SamePriorityCompositeScopeTowerProcessor(static, unbound)
|
||||
|
||||
val asValue = lhsResult.qualifier.classValueReceiverWithSmartCastInfo ?: return staticOrUnbound
|
||||
return CompositeScopeTowerProcessor(staticOrUnbound, factory.createCallableProcessor(asValue))
|
||||
return PrioritizedCompositeScopeTowerProcessor(staticOrUnbound, factory.createCallableProcessor(asValue))
|
||||
}
|
||||
is LHSResult.Object -> {
|
||||
// callable reference to nested class constructor
|
||||
val static = factory.createCallableProcessor(lhsResult.qualifier)
|
||||
val boundObjectReference = factory.createCallableProcessor(lhsResult.objectValueReceiver)
|
||||
|
||||
return CompositeSimpleScopeTowerProcessor(static, boundObjectReference)
|
||||
return SamePriorityCompositeScopeTowerProcessor(static, boundObjectReference)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -120,46 +121,50 @@ fun ConstraintSystemOperation.checkCallableReference(
|
||||
expectedType: UnwrappedType?,
|
||||
ownerDescriptor: DeclarationDescriptor
|
||||
): Pair<FreshVariableNewTypeSubstitutor, KotlinCallDiagnostic?> {
|
||||
val invisibleMember = Visibilities.findInvisibleMember(dispatchReceiver?.asReceiverValueForVisibilityChecks,
|
||||
candidateDescriptor, ownerDescriptor)
|
||||
|
||||
val position = ArgumentConstraintPosition(argument)
|
||||
|
||||
val toFreshSubstitutor = createToFreshVariableSubstitutorAndAddInitialConstraints(candidateDescriptor, this, kotlinCall = null)
|
||||
val reflectionType = toFreshSubstitutor.safeSubstitute(reflectionCandidateType)
|
||||
val toFreshSubstitutor = createToFreshVariableSubstitutorAndAddInitialConstraints(candidateDescriptor, this)
|
||||
|
||||
if (expectedType != null) {
|
||||
addSubtypeConstraint(reflectionType, expectedType, position)
|
||||
addSubtypeConstraint(toFreshSubstitutor.safeSubstitute(reflectionCandidateType), expectedType, position)
|
||||
}
|
||||
|
||||
addReceiverConstraint(toFreshSubstitutor, dispatchReceiver, candidateDescriptor.dispatchReceiverParameter, position)
|
||||
addReceiverConstraint(toFreshSubstitutor, extensionReceiver, candidateDescriptor.extensionReceiverParameter, position)
|
||||
|
||||
val invisibleMember = Visibilities.findInvisibleMember(dispatchReceiver?.asReceiverValueForVisibilityChecks,
|
||||
candidateDescriptor, ownerDescriptor)
|
||||
return toFreshSubstitutor to invisibleMember?.let(::VisibilityError)
|
||||
}
|
||||
|
||||
|
||||
private fun ConstraintSystemOperation.addReceiverConstraint(
|
||||
toFreshSubstitutor: FreshVariableNewTypeSubstitutor,
|
||||
receiver: CallableReceiver?,
|
||||
candidateReceiver: ReceiverParameterDescriptor?,
|
||||
receiverArgument: CallableReceiver?,
|
||||
receiverParameter: ReceiverParameterDescriptor?,
|
||||
position: ArgumentConstraintPosition
|
||||
) {
|
||||
val expectedType = toFreshSubstitutor.safeSubstitute(candidateReceiver?.value?.type?.unwrap() ?: return)
|
||||
val receiverType = receiver?.receiver?.stableType ?: return
|
||||
if (receiverArgument == null || receiverParameter == null) {
|
||||
assert(receiverArgument == null) { "Receiver argument should be null if parameter is: $receiverArgument" }
|
||||
assert(receiverParameter == null) { "Receiver parameter should be null if argument is: $receiverParameter" }
|
||||
return
|
||||
}
|
||||
|
||||
val expectedType = toFreshSubstitutor.safeSubstitute(receiverParameter.value.type.unwrap())
|
||||
val receiverType = receiverArgument.receiver.stableType
|
||||
addSubtypeConstraint(receiverType, expectedType, position)
|
||||
}
|
||||
|
||||
class CallableReferencesCandidateFactory(
|
||||
val argument: CallableReferenceKotlinCallArgument,
|
||||
val outerCallContext: KotlinCallContext,
|
||||
val callComponents: KotlinCallComponents,
|
||||
val scopeTower: ImplicitScopeTower,
|
||||
val compatibilityChecker: ((ConstraintSystemOperation) -> Unit) -> Unit,
|
||||
val expectedType: UnwrappedType?
|
||||
) : CandidateFactory<CallableReferenceCandidate> {
|
||||
private val position = ArgumentConstraintPosition(argument)
|
||||
|
||||
fun createCallableProcessor(explicitReceiver: DetailedReceiver?) =
|
||||
createCallableReferenceProcessor(outerCallContext.scopeTower, argument.rhsName, this, explicitReceiver)
|
||||
createCallableReferenceProcessor(scopeTower, argument.rhsName, this, explicitReceiver)
|
||||
|
||||
override fun createCandidate(
|
||||
towerCandidate: CandidateWithBoundDispatchReceiver,
|
||||
@@ -170,27 +175,33 @@ class CallableReferencesCandidateFactory(
|
||||
val dispatchCallableReceiver = towerCandidate.dispatchReceiver?.let { toCallableReceiver(it, explicitReceiverKind == DISPATCH_RECEIVER) }
|
||||
val extensionCallableReceiver = extensionReceiver?.let { toCallableReceiver(it, explicitReceiverKind == EXTENSION_RECEIVER) }
|
||||
val candidateDescriptor = towerCandidate.descriptor
|
||||
val diagnostics = SmartList<KotlinCallDiagnostic>()
|
||||
|
||||
val (reflectionCandidateType, defaults) = buildReflectionType(candidateDescriptor,
|
||||
dispatchCallableReceiver,
|
||||
extensionCallableReceiver,
|
||||
expectedType)
|
||||
val (reflectionCandidateType, defaults) = buildReflectionType(
|
||||
candidateDescriptor,
|
||||
dispatchCallableReceiver,
|
||||
extensionCallableReceiver,
|
||||
expectedType)
|
||||
|
||||
if (candidateDescriptor !is CallableMemberDescriptor) {
|
||||
val status = ResolutionCandidateStatus(listOf(NotCallableMemberReference(argument, candidateDescriptor)))
|
||||
return CallableReferenceCandidate(candidateDescriptor, dispatchCallableReceiver, extensionCallableReceiver,
|
||||
explicitReceiverKind, reflectionCandidateType, defaults, status)
|
||||
if (defaults != 0) {
|
||||
diagnostics.add(CallableReferencesDefaultArgumentUsed(argument, candidateDescriptor, defaults))
|
||||
}
|
||||
|
||||
if (candidateDescriptor !is CallableMemberDescriptor) {
|
||||
return CallableReferenceCandidate(candidateDescriptor, dispatchCallableReceiver, extensionCallableReceiver,
|
||||
explicitReceiverKind, reflectionCandidateType, defaults,
|
||||
listOf(NotCallableMemberReference(argument, candidateDescriptor)))
|
||||
}
|
||||
|
||||
val diagnostics = SmartList<KotlinCallDiagnostic>()
|
||||
diagnostics.addAll(towerCandidate.diagnostics)
|
||||
// todo smartcast on receiver diagnostic and CheckInstantiationOfAbstractClass
|
||||
|
||||
compatibilityChecker {
|
||||
if (it.hasContradiction) return@compatibilityChecker
|
||||
|
||||
val (_, visibilityError) = it.checkCallableReference(argument, dispatchCallableReceiver, extensionCallableReceiver, candidateDescriptor,
|
||||
reflectionCandidateType, expectedType, outerCallContext.scopeTower.lexicalScope.ownerDescriptor)
|
||||
val (_, visibilityError) = it.checkCallableReference(
|
||||
argument, dispatchCallableReceiver, extensionCallableReceiver, candidateDescriptor,
|
||||
reflectionCandidateType, expectedType, scopeTower.lexicalScope.ownerDescriptor)
|
||||
|
||||
diagnostics.addIfNotNull(visibilityError)
|
||||
|
||||
@@ -198,7 +209,7 @@ class CallableReferencesCandidateFactory(
|
||||
}
|
||||
|
||||
return CallableReferenceCandidate(candidateDescriptor, dispatchCallableReceiver, extensionCallableReceiver,
|
||||
explicitReceiverKind, reflectionCandidateType, defaults, ResolutionCandidateStatus(diagnostics))
|
||||
explicitReceiverKind, reflectionCandidateType, defaults, diagnostics)
|
||||
}
|
||||
|
||||
private fun getArgumentAndReturnTypeUseMappingByExpectedType(
|
||||
@@ -206,25 +217,13 @@ class CallableReferencesCandidateFactory(
|
||||
expectedType: UnwrappedType?,
|
||||
unboundReceiverCount: Int
|
||||
): Triple<Array<KotlinType>, CoercionStrategy, Int>? {
|
||||
if (expectedType == null) return null
|
||||
|
||||
val functionType =
|
||||
if (expectedType.isFunctionType) {
|
||||
expectedType
|
||||
}
|
||||
else if (ReflectionTypes.isNumberedKFunction(expectedType)) {
|
||||
expectedType.immediateSupertypes().first { it.isFunctionType }
|
||||
}
|
||||
else {
|
||||
return null
|
||||
}
|
||||
|
||||
val functionType = getFunctionTypeFromCallableReferenceExpectedType(expectedType) ?: return null
|
||||
|
||||
val expectedArgumentCount = functionType.arguments.size - unboundReceiverCount - 1 // 1 -- return type
|
||||
if (expectedArgumentCount < 0) return null
|
||||
|
||||
val fakeArguments = (0..(expectedArgumentCount - 1)).map { FakeKotlinCallArgumentForCallableReference(it) }
|
||||
val argumentMapping = outerCallContext.argumentsToParametersMapper.mapArguments(fakeArguments, externalArgument = null, descriptor = descriptor)
|
||||
val argumentMapping = callComponents.argumentsToParametersMapper.mapArguments(fakeArguments, externalArgument = null, descriptor = descriptor)
|
||||
if (argumentMapping.diagnostics.any { !it.candidateApplicability.isSuccess }) return null
|
||||
|
||||
/**
|
||||
@@ -244,8 +243,10 @@ class CallableReferencesCandidateFactory(
|
||||
}
|
||||
if (mappedArguments.any { it == null }) return null
|
||||
|
||||
val unitExpectedType = functionType.let(KotlinType::getReturnTypeFromFunctionType).takeIf { it.upperIfFlexible().isUnit() }
|
||||
val coercion = if (unitExpectedType != null) CoercionStrategy.COERCION_TO_UNIT else CoercionStrategy.NO_COERCION
|
||||
// lower(Unit!) = Unit
|
||||
val returnExpectedType = functionType.getReturnTypeFromFunctionType().lowerIfFlexible()
|
||||
|
||||
val coercion = if (returnExpectedType.isUnit()) CoercionStrategy.COERCION_TO_UNIT else CoercionStrategy.NO_COERCION
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return Triple(mappedArguments as Array<KotlinType>, coercion, defaults)
|
||||
@@ -274,10 +275,10 @@ class CallableReferencesCandidateFactory(
|
||||
val mutable = descriptor.isVar && run {
|
||||
val setter = descriptor.setter
|
||||
setter == null || Visibilities.isVisible(dispatchReceiver?.asReceiverValueForVisibilityChecks, setter,
|
||||
outerCallContext.scopeTower.lexicalScope.ownerDescriptor)
|
||||
scopeTower.lexicalScope.ownerDescriptor)
|
||||
}
|
||||
|
||||
return outerCallContext.reflectionTypes.getKPropertyType(Annotations.EMPTY, argumentsAndReceivers, descriptorReturnType, mutable) to 0
|
||||
return callComponents.reflectionTypes.getKPropertyType(Annotations.EMPTY, argumentsAndReceivers, descriptorReturnType, mutable) to 0
|
||||
}
|
||||
is FunctionDescriptor -> {
|
||||
val returnType: KotlinType
|
||||
@@ -298,8 +299,8 @@ class CallableReferencesCandidateFactory(
|
||||
returnType = if (coercion == CoercionStrategy.COERCION_TO_UNIT) descriptor.builtIns.unitType else descriptorReturnType
|
||||
}
|
||||
|
||||
return outerCallContext.reflectionTypes.getKFunctionType(Annotations.EMPTY, null, argumentsAndReceivers, null,
|
||||
returnType, descriptor.builtIns) to defaults
|
||||
return callComponents.reflectionTypes.getKFunctionType(Annotations.EMPTY, null, argumentsAndReceivers, null,
|
||||
returnType, descriptor.builtIns) to defaults
|
||||
}
|
||||
else -> error("Unsupported descriptor type: $descriptor")
|
||||
}
|
||||
@@ -324,3 +325,17 @@ class CallableReferencesCandidateFactory(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getFunctionTypeFromCallableReferenceExpectedType(expectedType: UnwrappedType?): UnwrappedType? {
|
||||
if (expectedType == null) return null
|
||||
|
||||
return if (expectedType.isFunctionType) {
|
||||
expectedType
|
||||
}
|
||||
else if (ReflectionTypes.isNumberedKFunction(expectedType)) {
|
||||
expectedType.immediateSupertypes().first { it.isFunctionType }.unwrap()
|
||||
}
|
||||
else {
|
||||
null
|
||||
}
|
||||
}
|
||||
@@ -21,30 +21,31 @@ import org.jetbrains.kotlin.resolve.calls.context.CheckArgumentTypesMode
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemOperation
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.components.ConstraintInjector
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.components.ResultTypeResolver
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.components.SimpleConstraintSystemImpl
|
||||
import org.jetbrains.kotlin.resolve.calls.model.*
|
||||
import org.jetbrains.kotlin.resolve.calls.results.FlatSignature
|
||||
import org.jetbrains.kotlin.resolve.calls.results.OverloadingConflictResolver
|
||||
import org.jetbrains.kotlin.resolve.calls.results.TypeSpecificityComparator
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.ImplicitScopeTower
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.TowerResolver
|
||||
import org.jetbrains.kotlin.types.UnwrappedType
|
||||
import org.jetbrains.kotlin.utils.SmartList
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
|
||||
|
||||
class CallableReferenceOverloadConflictResolver(
|
||||
builtIns: KotlinBuiltIns,
|
||||
specificityComparator: TypeSpecificityComparator,
|
||||
externalPredicates: KotlinResolutionExternalPredicates,
|
||||
constraintInjector: ConstraintInjector,
|
||||
typeResolver: ResultTypeResolver
|
||||
statelessCallbacks: KotlinResolutionStatelessCallbacks,
|
||||
constraintInjector: ConstraintInjector
|
||||
) : OverloadingConflictResolver<CallableReferenceCandidate>(
|
||||
builtIns,
|
||||
specificityComparator,
|
||||
{ it.candidate },
|
||||
{ SimpleConstraintSystemImpl(constraintInjector, typeResolver) },
|
||||
{ SimpleConstraintSystemImpl(constraintInjector, builtIns) },
|
||||
Companion::createFlatSignature,
|
||||
{ null },
|
||||
{ externalPredicates.isDescriptorFromSource(it) }
|
||||
{ statelessCallbacks.isDescriptorFromSource(it) }
|
||||
) {
|
||||
companion object {
|
||||
private fun createFlatSignature(candidate: CallableReferenceCandidate) =
|
||||
@@ -52,56 +53,74 @@ class CallableReferenceOverloadConflictResolver(
|
||||
}
|
||||
}
|
||||
|
||||
fun processCallableReferenceArgument(
|
||||
callContext: KotlinCallContext,
|
||||
csBuilder: ConstraintSystemBuilder,
|
||||
postponedArgument: PostponedCallableReferenceArgument
|
||||
): KotlinCallDiagnostic? {
|
||||
val argument = postponedArgument.argument
|
||||
val expectedType = postponedArgument.expectedType
|
||||
|
||||
val subLHSCall = ((argument.lhsResult as? LHSResult.Expression)?.lshCallArgument as? SubKotlinCallArgument)
|
||||
if (subLHSCall != null) {
|
||||
csBuilder.addInnerCall(subLHSCall.resolvedCall)
|
||||
}
|
||||
val candidates = callContext.callableReferenceResolver.runRLSResolution(callContext, argument, expectedType) { checkCallableReference ->
|
||||
csBuilder.runTransaction { checkCallableReference(this); false }
|
||||
}
|
||||
val chosenCandidate = when (candidates.size) {
|
||||
0 -> return NoneCallableReferenceCandidates(argument)
|
||||
1 -> candidates.single()
|
||||
else -> return CallableReferenceCandidatesAmbiguity(argument, candidates)
|
||||
}
|
||||
val (toFreshSubstitutor, diagnostic) = with(chosenCandidate) {
|
||||
csBuilder.checkCallableReference(argument, dispatchReceiver, extensionReceiver, candidate,
|
||||
reflectionCandidateType, expectedType, callContext.scopeTower.lexicalScope.ownerDescriptor)
|
||||
}
|
||||
|
||||
postponedArgument.analyzedAndThereIsResult = true
|
||||
postponedArgument.myTypeVariables = toFreshSubstitutor.freshVariables
|
||||
postponedArgument.callableResolutionCandidate = chosenCandidate
|
||||
|
||||
return diagnostic
|
||||
}
|
||||
|
||||
|
||||
class CallableReferenceResolver(
|
||||
val towerResolver: TowerResolver,
|
||||
val callableReferenceOverloadConflictResolver: CallableReferenceOverloadConflictResolver
|
||||
private val towerResolver: TowerResolver,
|
||||
private val callableReferenceOverloadConflictResolver: CallableReferenceOverloadConflictResolver,
|
||||
private val callComponents: KotlinCallComponents
|
||||
) {
|
||||
|
||||
fun runRLSResolution(
|
||||
outerCallContext: KotlinCallContext,
|
||||
fun processCallableReferenceArgument(
|
||||
csBuilder: ConstraintSystemBuilder,
|
||||
resolvedAtom: ResolvedCallableReferenceAtom
|
||||
) {
|
||||
val argument = resolvedAtom.atom
|
||||
val expectedType = resolvedAtom.expectedType?.let { csBuilder.buildCurrentSubstitutor().safeSubstitute(it) }
|
||||
|
||||
val scopeTower = callComponents.statelessCallbacks.getScopeTowerForCallableReferenceArgument(argument)
|
||||
val candidates = runRHSResolution(scopeTower, argument, expectedType) { checkCallableReference ->
|
||||
csBuilder.runTransaction { checkCallableReference(this); false }
|
||||
}
|
||||
val diagnostics = SmartList<KotlinCallDiagnostic>()
|
||||
|
||||
val chosenCandidate = candidates.singleOrNull()
|
||||
if (chosenCandidate != null) {
|
||||
val (toFreshSubstitutor, diagnostic) = with(chosenCandidate) {
|
||||
csBuilder.checkCallableReference(argument, dispatchReceiver, extensionReceiver, candidate,
|
||||
reflectionCandidateType, expectedType, scopeTower.lexicalScope.ownerDescriptor)
|
||||
}
|
||||
diagnostics.addIfNotNull(diagnostic)
|
||||
chosenCandidate.freshSubstitutor = toFreshSubstitutor
|
||||
}
|
||||
else {
|
||||
if (candidates.isEmpty()) {
|
||||
diagnostics.add(NoneCallableReferenceCandidates(argument))
|
||||
}
|
||||
else {
|
||||
diagnostics.add(CallableReferenceCandidatesAmbiguity(argument, candidates))
|
||||
}
|
||||
}
|
||||
|
||||
// todo -- create this inside CallableReferencesCandidateFactory
|
||||
val subKtArguments = listOfNotNull(buildResolvedKtArgument(argument.lhsResult))
|
||||
|
||||
resolvedAtom.setAnalyzedResults(chosenCandidate, subKtArguments, diagnostics)
|
||||
}
|
||||
|
||||
private fun buildResolvedKtArgument(lhsResult: LHSResult): ResolvedAtom? {
|
||||
if (lhsResult !is LHSResult.Expression) return null
|
||||
val lshCallArgument = lhsResult.lshCallArgument
|
||||
return when(lshCallArgument) {
|
||||
is SubKotlinCallArgument -> lshCallArgument.callResult
|
||||
is ExpressionKotlinCallArgument -> ResolvedExpressionAtom(lshCallArgument)
|
||||
else -> unexpectedArgument(lshCallArgument)
|
||||
}
|
||||
}
|
||||
|
||||
private fun runRHSResolution(
|
||||
scopeTower: ImplicitScopeTower,
|
||||
callableReference: CallableReferenceKotlinCallArgument,
|
||||
expectedType: UnwrappedType?, // this type can have not fixed type variable inside
|
||||
compatibilityChecker: ((ConstraintSystemOperation) -> Unit) -> Unit // you can run anything throw this operation and all this operation will be roll backed
|
||||
compatibilityChecker: ((ConstraintSystemOperation) -> Unit) -> Unit // you can run anything throw this operation and all this operation will be rolled back
|
||||
): Set<CallableReferenceCandidate> {
|
||||
val factory = CallableReferencesCandidateFactory(callableReference, outerCallContext, compatibilityChecker, expectedType)
|
||||
val factory = CallableReferencesCandidateFactory(callableReference, callComponents, scopeTower, compatibilityChecker, expectedType)
|
||||
val processor = createCallableReferenceProcessor(factory)
|
||||
val candidates = towerResolver.runResolve(outerCallContext.scopeTower, processor, useOrder = true)
|
||||
return callableReferenceOverloadConflictResolver.chooseMaximallySpecificCandidates(candidates, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS,
|
||||
discriminateGenerics = false,
|
||||
isDebuggerContext = outerCallContext.scopeTower.isDebuggerContext)
|
||||
val candidates = towerResolver.runResolve(scopeTower, processor, useOrder = true)
|
||||
return callableReferenceOverloadConflictResolver.chooseMaximallySpecificCandidates(
|
||||
candidates,
|
||||
CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS,
|
||||
discriminateGenerics = false, // we can't specify generics explicitly for callable references
|
||||
isDebuggerContext = scopeTower.isDebuggerContext)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,22 +19,24 @@ package org.jetbrains.kotlin.resolve.calls.components
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.resolve.calls.model.*
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.ImplicitScopeTower
|
||||
import org.jetbrains.kotlin.types.UnwrappedType
|
||||
|
||||
// stateless component
|
||||
interface KotlinResolutionExternalPredicates {
|
||||
interface KotlinResolutionStatelessCallbacks {
|
||||
fun isDescriptorFromSource(descriptor: CallableDescriptor): Boolean
|
||||
fun isInfixCall(kotlinCall: KotlinCall): Boolean
|
||||
fun isOperatorCall(kotlinCall: KotlinCall): Boolean
|
||||
fun isSuperOrDelegatingConstructorCall(kotlinCall: KotlinCall): Boolean
|
||||
fun isHiddenInResolution(descriptor: DeclarationDescriptor, kotlinCall: KotlinCall): Boolean
|
||||
fun isSuperExpression(receiver: SimpleKotlinCallArgument?): Boolean
|
||||
fun getScopeTowerForCallableReferenceArgument(argument: CallableReferenceKotlinCallArgument): ImplicitScopeTower
|
||||
fun getVariableCandidateIfInvoke(functionCall: KotlinCall): KotlinResolutionCandidate?
|
||||
}
|
||||
|
||||
// This components hold state (trace). Work with this carefully.
|
||||
interface KotlinResolutionCallbacks {
|
||||
fun analyzeAndGetLambdaResultArguments(
|
||||
outerCall: KotlinCall,
|
||||
lambdaArgument: LambdaKotlinCallArgument,
|
||||
isSuspend: Boolean,
|
||||
receiverType: UnwrappedType?,
|
||||
@@ -42,11 +44,5 @@ interface KotlinResolutionCallbacks {
|
||||
expectedReturnType: UnwrappedType? // null means, that return type is not proper i.e. it depends on some type variables
|
||||
): List<SimpleKotlinCallArgument>
|
||||
|
||||
// todo this is hack for some client which try to read ResolvedCall from trace before all calls completed
|
||||
fun bindStubResolvedCallForCandidate(candidate: KotlinResolutionCandidate)
|
||||
|
||||
fun completeCallableReference(callableReferenceArgument: PostponedCallableReferenceArgument,
|
||||
resultTypeParameters: List<UnwrappedType>)
|
||||
|
||||
fun completeCollectionLiteralCalls(collectionLiteralArgument: PostponedCollectionLiteralArgument)
|
||||
fun bindStubResolvedCallForCandidate(candidate: ResolvedCallAtom)
|
||||
}
|
||||
@@ -16,209 +16,89 @@
|
||||
|
||||
package org.jetbrains.kotlin.resolve.calls.components
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.components.*
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.NewConstraintSystem
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.components.KotlinConstraintSystemCompleter
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.components.KotlinConstraintSystemCompleter.ConstraintSystemCompletionMode
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.ExpectedTypeConstraintPosition
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.LambdaArgumentConstraintPosition
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.NewTypeVariable
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.returnTypeOrNothing
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.substituteAndApproximateCapturedTypes
|
||||
import org.jetbrains.kotlin.resolve.calls.model.*
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.ResolutionCandidateStatus
|
||||
import org.jetbrains.kotlin.types.TypeApproximator
|
||||
import org.jetbrains.kotlin.types.TypeApproximatorConfiguration
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.forceResolution
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import org.jetbrains.kotlin.types.UnwrappedType
|
||||
import org.jetbrains.kotlin.types.checker.NewCapturedType
|
||||
import org.jetbrains.kotlin.types.typeUtil.builtIns
|
||||
import org.jetbrains.kotlin.types.typeUtil.contains
|
||||
|
||||
class KotlinCallCompleter(
|
||||
private val fixationOrderCalculator: FixationOrderCalculator,
|
||||
private val additionalDiagnosticReporter: AdditionalDiagnosticReporter,
|
||||
private val inferenceStepResolver: InferenceStepResolver
|
||||
private val postponedArgumentsAnalyzer: PostponedArgumentsAnalyzer,
|
||||
private val kotlinConstraintSystemCompleter: KotlinConstraintSystemCompleter
|
||||
) {
|
||||
interface Context {
|
||||
val innerCalls: List<ResolvedKotlinCall.OnlyResolvedKotlinCall>
|
||||
val hasContradiction: Boolean
|
||||
fun buildCurrentSubstitutor(): NewTypeSubstitutor
|
||||
fun buildResultingSubstitutor(): NewTypeSubstitutor
|
||||
val postponedArguments: List<PostponedKotlinCallArgument>
|
||||
val lambdaArguments: List<PostponedLambdaArgument>
|
||||
|
||||
// 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, resolutionCallbacks: KotlinResolutionCallbacks): ResolvedKotlinCall =
|
||||
toCompletedBaseResolvedCall(candidate.lastCall.constraintSystem.asCallCompleterContext(), candidate, resolutionCallbacks)
|
||||
|
||||
// todo investigate variable+function calls
|
||||
fun completeCallIfNecessary(
|
||||
candidate: KotlinResolutionCandidate,
|
||||
fun runCompletion(
|
||||
factory: SimpleCandidateFactory,
|
||||
candidates: Collection<KotlinResolutionCandidate>,
|
||||
expectedType: UnwrappedType?,
|
||||
resolutionCallbacks: KotlinResolutionCallbacks
|
||||
): ResolvedKotlinCall {
|
||||
resolutionCallbacks.bindStubResolvedCallForCandidate(candidate)
|
||||
val topLevelCall =
|
||||
when (candidate) {
|
||||
is VariableAsFunctionKotlinResolutionCandidate -> candidate.invokeCandidate
|
||||
else -> candidate as SimpleKotlinResolutionCandidate
|
||||
}
|
||||
): CallResolutionResult {
|
||||
val diagnosticHolder = KotlinDiagnosticsHolder.SimpleHolder()
|
||||
if (candidates.isEmpty()) {
|
||||
diagnosticHolder.addDiagnostic(NoneCandidatesCallDiagnostic(factory.kotlinCall))
|
||||
}
|
||||
if (candidates.size > 1) {
|
||||
diagnosticHolder.addDiagnostic(ManyCandidatesCallDiagnostic(factory.kotlinCall, candidates))
|
||||
}
|
||||
val candidate = candidates.singleOrNull()
|
||||
|
||||
if (topLevelCall.prepareForCompletion(expectedType)) {
|
||||
val c = candidate.lastCall.constraintSystem.asCallCompleterContext()
|
||||
// this is needed at least for non-local return checker, because when we analyze lambda we should already bind descriptor for outer call
|
||||
candidate?.resolvedCall?.let { resolutionCallbacks.bindStubResolvedCallForCandidate(it) }
|
||||
|
||||
resolveCallableReferenceArguments(c, candidate.lastCall)
|
||||
if (candidate == null || candidate.csBuilder.hasContradiction) {
|
||||
val candidateForCompletion = candidate ?: factory.createErrorCandidate().forceResolution()
|
||||
candidateForCompletion.prepareForCompletion(expectedType)
|
||||
runCompletion(candidateForCompletion.resolvedCall, ConstraintSystemCompletionMode.FULL, diagnosticHolder, candidateForCompletion.getSystem(), resolutionCallbacks)
|
||||
|
||||
topLevelCall.competeCall(c, resolutionCallbacks)
|
||||
return toCompletedBaseResolvedCall(c, candidate, resolutionCallbacks)
|
||||
return CallResolutionResult(CallResolutionResult.Type.ERROR, candidate?.resolvedCall, diagnosticHolder.getDiagnostics(), ConstraintStorage.Empty)
|
||||
}
|
||||
|
||||
return ResolvedKotlinCall.OnlyResolvedKotlinCall(candidate)
|
||||
}
|
||||
val completionType = candidate.prepareForCompletion(expectedType)
|
||||
val constraintSystem = candidate.getSystem()
|
||||
runCompletion(candidate.resolvedCall, completionType, diagnosticHolder, constraintSystem, resolutionCallbacks)
|
||||
|
||||
// todo do not use topLevelCall
|
||||
private fun resolveCallableReferenceArguments(c: Context, topLevelCall: SimpleKotlinResolutionCandidate) {
|
||||
for (callableReferenceArgument in c.postponedArguments) {
|
||||
if (callableReferenceArgument !is PostponedCallableReferenceArgument) continue
|
||||
processCallableReferenceArgument(topLevelCall.callContext, c.getBuilder(), callableReferenceArgument)
|
||||
return if (completionType == ConstraintSystemCompletionMode.FULL) {
|
||||
CallResolutionResult(CallResolutionResult.Type.COMPLETED, candidate.resolvedCall, diagnosticHolder.getDiagnostics(), constraintSystem.asReadOnlyStorage())
|
||||
}
|
||||
else {
|
||||
CallResolutionResult(CallResolutionResult.Type.PARTIAL, candidate.resolvedCall, diagnosticHolder.getDiagnostics(), constraintSystem.asReadOnlyStorage())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun toCompletedBaseResolvedCall(
|
||||
c: Context,
|
||||
candidate: KotlinResolutionCandidate,
|
||||
private fun runCompletion(
|
||||
resolvedCallAtom: ResolvedCallAtom,
|
||||
completionMode: ConstraintSystemCompletionMode,
|
||||
diagnosticsHolder: KotlinDiagnosticsHolder,
|
||||
constraintSystem: NewConstraintSystem,
|
||||
resolutionCallbacks: KotlinResolutionCallbacks
|
||||
): ResolvedKotlinCall.CompletedResolvedKotlinCall {
|
||||
val currentSubstitutor = c.buildResultingSubstitutor()
|
||||
val completedCall = candidate.toCompletedCall(currentSubstitutor)
|
||||
val competedCalls = c.innerCalls.map {
|
||||
it.candidate.toCompletedCall(currentSubstitutor)
|
||||
) {
|
||||
val returnType = resolvedCallAtom.freshReturnType ?: constraintSystem.builtIns.unitType
|
||||
kotlinConstraintSystemCompleter.runCompletion(constraintSystem.asConstraintSystemCompleterContext(), completionMode, resolvedCallAtom, returnType) {
|
||||
postponedArgumentsAnalyzer.analyze(constraintSystem.asPostponedArgumentsAnalyzerContext(), resolutionCallbacks, it)
|
||||
}
|
||||
for (postponedArgument in c.postponedArguments) {
|
||||
when (postponedArgument) {
|
||||
is PostponedLambdaArgument -> {
|
||||
postponedArgument.finalReturnType = currentSubstitutor.safeSubstitute(postponedArgument.returnType)
|
||||
}
|
||||
is PostponedCallableReferenceArgument -> {
|
||||
val resultTypeParameters = postponedArgument.myTypeVariables.map { currentSubstitutor.safeSubstitute(it.defaultType) }
|
||||
resolutionCallbacks.completeCallableReference(postponedArgument, resultTypeParameters)
|
||||
}
|
||||
is PostponedCollectionLiteralArgument -> {
|
||||
resolutionCallbacks.completeCollectionLiteralCalls(postponedArgument)
|
||||
}
|
||||
}
|
||||
}
|
||||
return ResolvedKotlinCall.CompletedResolvedKotlinCall(completedCall, competedCalls, c.lambdaArguments)
|
||||
|
||||
constraintSystem.diagnostics.forEach(diagnosticsHolder::addDiagnostic)
|
||||
}
|
||||
|
||||
private fun KotlinResolutionCandidate.toCompletedCall(substitutor: NewTypeSubstitutor): 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: NewTypeSubstitutor): CompletedKotlinCall.Simple {
|
||||
val containsCapturedTypes = descriptorWithFreshTypes.returnType?.contains { it is NewCapturedType } ?: false
|
||||
val resultingDescriptor = when {
|
||||
descriptorWithFreshTypes is FunctionDescriptor ||
|
||||
(descriptorWithFreshTypes is PropertyDescriptor && (descriptorWithFreshTypes.typeParameters.isNotEmpty() || containsCapturedTypes)) ->
|
||||
// this code is very suspicious. Now it is very useful for BE, because they cannot do nothing with captured types,
|
||||
// but it seems like temporary solution.
|
||||
descriptorWithFreshTypes.substituteAndApproximateCapturedTypes(substitutor)
|
||||
else ->
|
||||
descriptorWithFreshTypes
|
||||
}
|
||||
|
||||
val typeArguments = descriptorWithFreshTypes.typeParameters.map {
|
||||
val substituted = substitutor.safeSubstitute(typeVariablesForFreshTypeParameters[it.index].defaultType)
|
||||
TypeApproximator().approximateToSuperType(substituted, TypeApproximatorConfiguration.CapturedTypesApproximation) ?: substituted
|
||||
}
|
||||
|
||||
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 = additionalDiagnosticReporter.createAdditionalDiagnostics(candidate, resultingDescriptor).takeIf { it.isNotEmpty() } ?:
|
||||
return candidate.status
|
||||
return ResolutionCandidateStatus(candidate.status.diagnostics + smartCasts)
|
||||
}
|
||||
|
||||
// true if we should complete this call
|
||||
private fun SimpleKotlinResolutionCandidate.prepareForCompletion(expectedType: UnwrappedType?): Boolean {
|
||||
val returnType = descriptorWithFreshTypes.returnType?.unwrap() ?: return false
|
||||
private fun KotlinResolutionCandidate.prepareForCompletion(expectedType: UnwrappedType?): ConstraintSystemCompletionMode {
|
||||
val unsubstitutedReturnType = resolvedCall.candidateDescriptor.returnType?.unwrap() ?: return ConstraintSystemCompletionMode.PARTIAL
|
||||
val returnType = resolvedCall.substitutor.safeSubstitute(unsubstitutedReturnType)
|
||||
if (expectedType != null && !TypeUtils.noExpectedType(expectedType)) {
|
||||
csBuilder.addSubtypeConstraint(returnType, expectedType, ExpectedTypeConstraintPosition(kotlinCall))
|
||||
csBuilder.addSubtypeConstraint(returnType, expectedType, ExpectedTypeConstraintPosition(resolvedCall.atom))
|
||||
}
|
||||
|
||||
return expectedType != null || csBuilder.isProperType(returnType)
|
||||
}
|
||||
|
||||
private fun SimpleKotlinResolutionCandidate.competeCall(c: Context, resolutionCallbacks: KotlinResolutionCallbacks) {
|
||||
while (!oneStepToEndOrLambda(c, resolutionCallbacks)) {
|
||||
// do nothing -- be happy
|
||||
return if (expectedType != null || csBuilder.isProperType(returnType)) {
|
||||
ConstraintSystemCompletionMode.FULL
|
||||
}
|
||||
}
|
||||
|
||||
// true if it is the end (happy or not)
|
||||
// every step we fix type variable or analyzeLambda
|
||||
private fun SimpleKotlinResolutionCandidate.oneStepToEndOrLambda(c: Context, resolutionCallbacks: KotlinResolutionCallbacks): Boolean {
|
||||
val lambda = c.lambdaArguments.find { canWeAnalyzeIt(c, it) }
|
||||
if (lambda != null) {
|
||||
analyzeLambda(c, resolutionCallbacks, lambda)
|
||||
return false
|
||||
else {
|
||||
ConstraintSystemCompletionMode.PARTIAL
|
||||
}
|
||||
|
||||
val completionOrder = fixationOrderCalculator.computeCompletionOrder(c.asFixationOrderCalculatorContext(), descriptorWithFreshTypes.returnTypeOrNothing)
|
||||
return inferenceStepResolver.resolveVariables(c, completionOrder)
|
||||
}
|
||||
|
||||
private fun analyzeLambda(c: Context, resolutionCallbacks: KotlinResolutionCallbacks, lambda: PostponedLambdaArgument) {
|
||||
val currentSubstitutor = c.buildCurrentSubstitutor()
|
||||
fun substitute(type: UnwrappedType) = currentSubstitutor.safeSubstitute(type)
|
||||
|
||||
val receiver = lambda.receiver?.let(::substitute)
|
||||
val parameters = lambda.parameters.map(::substitute)
|
||||
val expectedType = lambda.returnType.takeIf { c.canBeProper(it) }?.let(::substitute)
|
||||
lambda.analyzed = true
|
||||
lambda.resultArguments = resolutionCallbacks.analyzeAndGetLambdaResultArguments(lambda.outerCall, lambda.argument, lambda.isSuspend, receiver, parameters, expectedType)
|
||||
|
||||
for (resultLambdaArgument in lambda.resultArguments) {
|
||||
checkSimpleArgument(c.getBuilder(), resultLambdaArgument, lambda.returnType.let(::substitute))
|
||||
}
|
||||
|
||||
if (lambda.resultArguments.isEmpty()) {
|
||||
val unitType = lambda.returnType.builtIns.unitType
|
||||
c.getBuilder().addSubtypeConstraint(lambda.returnType.let(::substitute), unitType, LambdaArgumentConstraintPosition(lambda))
|
||||
}
|
||||
}
|
||||
|
||||
private fun canWeAnalyzeIt(c: Context, lambda: PostponedLambdaArgument): Boolean {
|
||||
if (lambda.analyzed) return false
|
||||
|
||||
if (c.hasContradiction) return true // to record info about lambda and avoid exceptions
|
||||
|
||||
lambda.receiver?.let {
|
||||
if (!c.canBeProper(it)) return false
|
||||
}
|
||||
return lambda.parameters.all { c.canBeProper(it) }
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,6 @@ 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
|
||||
@@ -31,33 +30,31 @@ import java.util.*
|
||||
class NewOverloadingConflictResolver(
|
||||
builtIns: KotlinBuiltIns,
|
||||
specificityComparator: TypeSpecificityComparator,
|
||||
externalPredicates: KotlinResolutionExternalPredicates,
|
||||
constraintInjector: ConstraintInjector,
|
||||
typeResolver: ResultTypeResolver
|
||||
statelessCallbacks: KotlinResolutionStatelessCallbacks,
|
||||
constraintInjector: ConstraintInjector
|
||||
) : OverloadingConflictResolver<KotlinResolutionCandidate>(
|
||||
builtIns,
|
||||
specificityComparator,
|
||||
{
|
||||
// todo investigate
|
||||
(it as? VariableAsFunctionKotlinResolutionCandidate)?.invokeCandidate?.candidateDescriptor ?:
|
||||
(it as SimpleKotlinResolutionCandidate).candidateDescriptor
|
||||
it.resolvedCall.candidateDescriptor
|
||||
},
|
||||
{ SimpleConstraintSystemImpl(constraintInjector, typeResolver) },
|
||||
{ SimpleConstraintSystemImpl(constraintInjector, builtIns) },
|
||||
Companion::createFlatSignature,
|
||||
{ (it as? VariableAsFunctionKotlinResolutionCandidate)?.resolvedVariable },
|
||||
{ externalPredicates.isDescriptorFromSource(it) }
|
||||
{ it.variableCandidateIfInvoke },
|
||||
{ statelessCallbacks.isDescriptorFromSource(it) }
|
||||
) {
|
||||
|
||||
companion object {
|
||||
private fun createFlatSignature(candidate: KotlinResolutionCandidate): FlatSignature<KotlinResolutionCandidate> {
|
||||
val simpleCandidate = (candidate as? VariableAsFunctionKotlinResolutionCandidate)?.invokeCandidate ?: (candidate as SimpleKotlinResolutionCandidate)
|
||||
|
||||
val originalDescriptor = simpleCandidate.descriptorWithFreshTypes.original
|
||||
val resolvedCall = candidate.resolvedCall
|
||||
val originalDescriptor = resolvedCall.candidateDescriptor.original
|
||||
val originalValueParameters = originalDescriptor.valueParameters
|
||||
|
||||
var numDefaults = 0
|
||||
val valueArgumentToParameterType = HashMap<KotlinCallArgument, KotlinType>()
|
||||
for ((valueParameter, resolvedValueArgument) in simpleCandidate.argumentMappingByOriginal) {
|
||||
for ((valueParameter, resolvedValueArgument) in resolvedCall.argumentMappingByOriginal) {
|
||||
if (resolvedValueArgument is ResolvedCallArgument.DefaultArgument) {
|
||||
numDefaults++
|
||||
}
|
||||
@@ -73,8 +70,8 @@ class NewOverloadingConflictResolver(
|
||||
return FlatSignature.create(candidate,
|
||||
originalDescriptor,
|
||||
numDefaults,
|
||||
simpleCandidate.kotlinCall.argumentsInParenthesis.map { valueArgumentToParameterType[it] } +
|
||||
listOfNotNull(simpleCandidate.kotlinCall.externalArgument?.let { valueArgumentToParameterType[it] })
|
||||
resolvedCall.atom.argumentsInParenthesis.map { valueArgumentToParameterType[it] } +
|
||||
listOfNotNull(resolvedCall.atom.externalArgument?.let { valueArgumentToParameterType[it] })
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
@@ -17,105 +17,119 @@
|
||||
package org.jetbrains.kotlin.resolve.calls.components
|
||||
|
||||
import org.jetbrains.kotlin.builtins.*
|
||||
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
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.TypeVariableForLambdaReturnType
|
||||
import org.jetbrains.kotlin.resolve.calls.model.*
|
||||
import org.jetbrains.kotlin.types.UnwrappedType
|
||||
import org.jetbrains.kotlin.types.typeUtil.builtIns
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
fun createPostponedArgumentAndPerformInitialChecks(
|
||||
kotlinCall: KotlinCall,
|
||||
fun resolveKtPrimitive(
|
||||
csBuilder: ConstraintSystemBuilder,
|
||||
argument: PostponableKotlinCallArgument,
|
||||
parameterDescriptor: ValueParameterDescriptor
|
||||
): KotlinCallDiagnostic? {
|
||||
val expectedType = argument.getExpectedType(parameterDescriptor)
|
||||
val (postponedArgument, diagnostic) = when (argument) {
|
||||
is LambdaKotlinCallArgument -> preprocessLambdaArgument(kotlinCall, csBuilder, argument, expectedType)
|
||||
is CallableReferenceKotlinCallArgument -> preprocessCallableReference(csBuilder, argument, expectedType)
|
||||
is CollectionLiteralKotlinCallArgument -> preprocessCollectionLiteralArgument(csBuilder, argument, expectedType)
|
||||
else -> unexpectedArgument(argument)
|
||||
}
|
||||
csBuilder.addPostponedArgument(postponedArgument)
|
||||
|
||||
return diagnostic
|
||||
argument: KotlinCallArgument,
|
||||
expectedType: UnwrappedType?,
|
||||
diagnosticsHolder: KotlinDiagnosticsHolder,
|
||||
isReceiver: Boolean
|
||||
): ResolvedAtom = when (argument) {
|
||||
is SimpleKotlinCallArgument -> checkSimpleArgument(csBuilder, argument, expectedType, diagnosticsHolder, isReceiver)
|
||||
is LambdaKotlinCallArgument -> preprocessLambdaArgument(csBuilder, argument, expectedType)
|
||||
is CallableReferenceKotlinCallArgument -> preprocessCallableReference(csBuilder, argument, expectedType, diagnosticsHolder)
|
||||
is CollectionLiteralKotlinCallArgument -> preprocessCollectionLiteralArgument(argument, expectedType)
|
||||
else -> unexpectedArgument(argument)
|
||||
}
|
||||
|
||||
|
||||
// if expected type isn't function type, then may be it is Function<R>, Any or just `T`
|
||||
private fun preprocessLambdaArgument(
|
||||
kotlinCall: KotlinCall,
|
||||
csBuilder: ConstraintSystemBuilder,
|
||||
argument: LambdaKotlinCallArgument,
|
||||
expectedType: UnwrappedType
|
||||
): Pair<PostponedLambdaArgument, KotlinCallDiagnostic?> {
|
||||
val builtIns = expectedType.builtIns
|
||||
val isSuspend = expectedType.isSuspendFunctionType
|
||||
expectedType: UnwrappedType?
|
||||
): ResolvedAtom {
|
||||
val newExpectedType = expectedType?.let { csBuilder.getProperSubTypeBounds(expectedType).singleOrNull() } ?: expectedType
|
||||
|
||||
val receiverType: UnwrappedType? // null means that there is no receiver
|
||||
val parameters: List<UnwrappedType>
|
||||
val returnType: UnwrappedType
|
||||
val resolvedArgument = extractLambdaInfoFromFunctionalType(newExpectedType, argument) ?: extraLambdaInfo(newExpectedType, argument, csBuilder)
|
||||
|
||||
if (expectedType.isBuiltinFunctionalType) {
|
||||
receiverType = if (argument is FunctionExpression) argument.receiverType else expectedType.getReceiverTypeFromFunctionType()?.unwrap()
|
||||
|
||||
val expectedParameters = expectedType.getValueParameterTypesFromFunctionType()
|
||||
if (argument.parametersTypes != null) {
|
||||
parameters = argument.parametersTypes!!.mapIndexed {
|
||||
index, type ->
|
||||
type ?: expectedParameters.getOrNull(index)?.type?.unwrap() ?: builtIns.anyType
|
||||
}
|
||||
}
|
||||
else {
|
||||
// lambda without explicit parameters: { }
|
||||
parameters = expectedParameters.map { it.type.unwrap() }
|
||||
}
|
||||
returnType = (argument as? FunctionExpression)?.returnType ?: expectedType.getReturnTypeFromFunctionType().unwrap()
|
||||
}
|
||||
else {
|
||||
val isFunctionSupertype = KotlinBuiltIns.isNotNullOrNullableFunctionSupertype(expectedType)
|
||||
receiverType = (argument as? FunctionExpression)?.receiverType
|
||||
parameters = argument.parametersTypes?.map { it ?: builtIns.nothingType } ?: emptyList()
|
||||
returnType = (argument as? FunctionExpression)?.returnType ?:
|
||||
expectedType.arguments.singleOrNull()?.type?.unwrap()?.takeIf { isFunctionSupertype } ?:
|
||||
createFreshTypeVariableForLambdaReturnType(csBuilder, argument, builtIns)
|
||||
|
||||
// what about case where expected type is type variable? In old TY such cases was not supported. => do nothing for now. todo design
|
||||
if (expectedType != null) {
|
||||
val lambdaType = createFunctionType(csBuilder.builtIns, Annotations.EMPTY, resolvedArgument.receiver,
|
||||
resolvedArgument.parameters, null, resolvedArgument.returnType, resolvedArgument.isSuspend)
|
||||
csBuilder.addSubtypeConstraint(lambdaType, expectedType, ArgumentConstraintPosition(argument))
|
||||
}
|
||||
|
||||
val resolvedArgument = PostponedLambdaArgument(kotlinCall, argument, isSuspend, receiverType, parameters, returnType)
|
||||
|
||||
csBuilder.addSubtypeConstraint(resolvedArgument.type, expectedType, ArgumentConstraintPosition(argument))
|
||||
|
||||
return resolvedArgument to null
|
||||
return resolvedArgument
|
||||
}
|
||||
|
||||
private fun createFreshTypeVariableForLambdaReturnType(
|
||||
csBuilder: ConstraintSystemBuilder,
|
||||
private fun extraLambdaInfo(
|
||||
expectedType: UnwrappedType?,
|
||||
argument: LambdaKotlinCallArgument,
|
||||
builtIns: KotlinBuiltIns
|
||||
): UnwrappedType {
|
||||
csBuilder: ConstraintSystemBuilder
|
||||
): ResolvedLambdaAtom {
|
||||
val builtIns = csBuilder.builtIns
|
||||
val isSuspend = expectedType?.isSuspendFunctionType ?: false
|
||||
|
||||
val isFunctionSupertype = expectedType != null && KotlinBuiltIns.isNotNullOrNullableFunctionSupertype(expectedType)
|
||||
val argumentAsFunctionExpression = argument.safeAs<FunctionExpression>()
|
||||
|
||||
val typeVariable = TypeVariableForLambdaReturnType(argument, builtIns, "_L")
|
||||
csBuilder.registerVariable(typeVariable)
|
||||
return typeVariable.defaultType
|
||||
|
||||
val receiverType = argumentAsFunctionExpression?.receiverType
|
||||
val returnType = argumentAsFunctionExpression?.returnType ?:
|
||||
expectedType?.arguments?.singleOrNull()?.type?.unwrap()?.takeIf { isFunctionSupertype } ?:
|
||||
typeVariable.defaultType
|
||||
|
||||
val parameters = argument.parametersTypes?.map { it ?: builtIns.nothingType } ?: emptyList()
|
||||
|
||||
|
||||
val newTypeVariableUsed = returnType == typeVariable.defaultType
|
||||
if (newTypeVariableUsed) csBuilder.registerVariable(typeVariable)
|
||||
|
||||
return ResolvedLambdaAtom(argument, isSuspend, receiverType, parameters, returnType, typeVariable.takeIf { newTypeVariableUsed })
|
||||
}
|
||||
|
||||
private fun extractLambdaInfoFromFunctionalType(expectedType: UnwrappedType?, argument: LambdaKotlinCallArgument): ResolvedLambdaAtom? {
|
||||
if (expectedType == null || !expectedType.isBuiltinFunctionalType) return null
|
||||
val parameters = extractLambdaParameters(expectedType, argument)
|
||||
|
||||
val argumentAsFunctionExpression = argument.safeAs<FunctionExpression>()
|
||||
val receiverType = argumentAsFunctionExpression?.receiverType ?: expectedType.getReceiverTypeFromFunctionType()?.unwrap()
|
||||
val returnType = argumentAsFunctionExpression?.returnType ?: expectedType.getReturnTypeFromFunctionType().unwrap()
|
||||
|
||||
return ResolvedLambdaAtom(argument, expectedType.isSuspendFunctionType, receiverType, parameters, returnType, typeVariableForLambdaReturnType = null)
|
||||
}
|
||||
|
||||
private fun extractLambdaParameters(expectedType: UnwrappedType, argument: LambdaKotlinCallArgument): List<UnwrappedType> {
|
||||
val parametersTypes = argument.parametersTypes
|
||||
val expectedParameters = expectedType.getValueParameterTypesFromFunctionType()
|
||||
if (parametersTypes == null) {
|
||||
return expectedParameters.map { it.type.unwrap() }
|
||||
}
|
||||
|
||||
return parametersTypes.mapIndexed { index, type ->
|
||||
type ?: expectedParameters.getOrNull(index)?.type?.unwrap() ?: expectedType.builtIns.nullableAnyType
|
||||
}
|
||||
}
|
||||
|
||||
private fun preprocessCallableReference(
|
||||
csBuilder: ConstraintSystemBuilder,
|
||||
argument: CallableReferenceKotlinCallArgument,
|
||||
expectedType: UnwrappedType
|
||||
): Pair<PostponedCallableReferenceArgument, KotlinCallDiagnostic?> {
|
||||
expectedType: UnwrappedType?,
|
||||
diagnosticsHolder: KotlinDiagnosticsHolder
|
||||
): ResolvedAtom {
|
||||
val result = ResolvedCallableReferenceAtom(argument, expectedType)
|
||||
if (expectedType == null) return result
|
||||
|
||||
val notCallableTypeConstructor = csBuilder.getProperSuperTypeConstructors(expectedType).firstOrNull { !ReflectionTypes.isPossibleExpectedCallableType(it) }
|
||||
val diagnostic = notCallableTypeConstructor?.let { NotCallableExpectedType(argument, expectedType, notCallableTypeConstructor) }
|
||||
return PostponedCallableReferenceArgument(argument, expectedType) to diagnostic
|
||||
if (notCallableTypeConstructor != null) {
|
||||
diagnosticsHolder.addDiagnostic(NotCallableExpectedType(argument, expectedType, notCallableTypeConstructor))
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
private fun preprocessCollectionLiteralArgument(
|
||||
csBuilder: ConstraintSystemBuilder,
|
||||
collectionLiteralArgument: CollectionLiteralKotlinCallArgument,
|
||||
expectedType: UnwrappedType
|
||||
): Pair<PostponedCollectionLiteralArgument, KotlinCallDiagnostic?> {
|
||||
expectedType: UnwrappedType?
|
||||
): ResolvedAtom {
|
||||
// todo add some checks about expected type
|
||||
return PostponedCollectionLiteralArgument(collectionLiteralArgument, expectedType) to null
|
||||
return ResolvedCollectionLiteralAtom(collectionLiteralArgument, expectedType)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* 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.resolve.calls.inference.ConstraintSystemBuilder
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.addSubsystemForArgument
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.components.NewTypeSubstitutor
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.LambdaArgumentConstraintPosition
|
||||
import org.jetbrains.kotlin.resolve.calls.model.*
|
||||
import org.jetbrains.kotlin.types.UnwrappedType
|
||||
import org.jetbrains.kotlin.types.typeUtil.builtIns
|
||||
|
||||
class PostponedArgumentsAnalyzer(
|
||||
private val callableReferenceResolver: CallableReferenceResolver
|
||||
) {
|
||||
interface Context {
|
||||
fun buildCurrentSubstitutor(): NewTypeSubstitutor
|
||||
|
||||
// type can be proper if it not contains not fixed type variables
|
||||
fun canBeProper(type: UnwrappedType): Boolean
|
||||
|
||||
// mutable operations
|
||||
fun addOtherSystem(otherSystem: ConstraintStorage)
|
||||
fun getBuilder(): ConstraintSystemBuilder
|
||||
}
|
||||
|
||||
fun analyze(c: Context, resolutionCallbacks: KotlinResolutionCallbacks, argument: ResolvedAtom) {
|
||||
when (argument) {
|
||||
is ResolvedLambdaAtom -> analyzeLambda(c, resolutionCallbacks, argument)
|
||||
is ResolvedCallableReferenceAtom -> callableReferenceResolver.processCallableReferenceArgument(c.getBuilder(), argument)
|
||||
is ResolvedCollectionLiteralAtom -> TODO("Not supported")
|
||||
else -> error("Unexpected resolved primitive: ${argument.javaClass.canonicalName}")
|
||||
}
|
||||
}
|
||||
|
||||
private fun analyzeLambda(c: Context, resolutionCallbacks: KotlinResolutionCallbacks, lambda: ResolvedLambdaAtom) {
|
||||
val currentSubstitutor = c.buildCurrentSubstitutor()
|
||||
fun substitute(type: UnwrappedType) = currentSubstitutor.safeSubstitute(type)
|
||||
|
||||
val receiver = lambda.receiver?.let(::substitute)
|
||||
val parameters = lambda.parameters.map(::substitute)
|
||||
val expectedType = lambda.returnType.takeIf { c.canBeProper(it) }?.let(::substitute)
|
||||
|
||||
val resultArguments = resolutionCallbacks.analyzeAndGetLambdaResultArguments(lambda.atom, lambda.isSuspend, receiver, parameters, expectedType)
|
||||
|
||||
resultArguments.forEach { c.addSubsystemForArgument(it) }
|
||||
|
||||
val diagnosticHolder = KotlinDiagnosticsHolder.SimpleHolder()
|
||||
|
||||
val subResolvedKtPrimitives = resultArguments.map {
|
||||
checkSimpleArgument(c.getBuilder(), it, lambda.returnType.let(::substitute), diagnosticHolder, isReceiver = false)
|
||||
}
|
||||
|
||||
if (resultArguments.isEmpty()) {
|
||||
val unitType = lambda.returnType.builtIns.unitType
|
||||
c.getBuilder().addSubtypeConstraint(lambda.returnType.let(::substitute), unitType, LambdaArgumentConstraintPosition(lambda))
|
||||
}
|
||||
|
||||
lambda.setAnalyzedResults(resultArguments, subResolvedKtPrimitives, diagnosticHolder.getDiagnostics())
|
||||
}
|
||||
}
|
||||
@@ -31,114 +31,129 @@ import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind.*
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.InfixCallNoInfixModifier
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.InvokeConventionCallNoOperatorModifier
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.VisibilityError
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.isSuccess
|
||||
import org.jetbrains.kotlin.utils.SmartList
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
import org.jetbrains.kotlin.types.ErrorUtils
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
internal object CheckInstantiationOfAbstractClass : ResolutionPart {
|
||||
override fun SimpleKotlinResolutionCandidate.process(): List<KotlinCallDiagnostic> {
|
||||
if (candidateDescriptor is ConstructorDescriptor && !callContext.externalPredicates.isSuperOrDelegatingConstructorCall(kotlinCall)) {
|
||||
internal object CheckInstantiationOfAbstractClass : ResolutionPart() {
|
||||
override fun KotlinResolutionCandidate.process(workIndex: Int) {
|
||||
val candidateDescriptor = resolvedCall.candidateDescriptor
|
||||
|
||||
if (candidateDescriptor is ConstructorDescriptor &&
|
||||
!callComponents.statelessCallbacks.isSuperOrDelegatingConstructorCall(resolvedCall.atom)) {
|
||||
if (candidateDescriptor.constructedClass.modality == Modality.ABSTRACT) {
|
||||
return listOf(InstantiationOfAbstractClass)
|
||||
addDiagnostic(InstantiationOfAbstractClass)
|
||||
}
|
||||
}
|
||||
|
||||
return emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
internal object CheckVisibility : ResolutionPart {
|
||||
override fun SimpleKotlinResolutionCandidate.process(): List<KotlinCallDiagnostic> {
|
||||
internal object CheckVisibility : ResolutionPart() {
|
||||
override fun KotlinResolutionCandidate.process(workIndex: Int) {
|
||||
val containingDescriptor = scopeTower.lexicalScope.ownerDescriptor
|
||||
val dispatchReceiverArgument = resolvedCall.dispatchReceiverArgument
|
||||
|
||||
if (scopeTower.isDebuggerContext) return
|
||||
|
||||
val receiverValue = dispatchReceiverArgument?.receiver?.receiverValue ?: Visibilities.ALWAYS_SUITABLE_RECEIVER
|
||||
val invisibleMember = Visibilities.findInvisibleMember(receiverValue, candidateDescriptor, containingDescriptor) ?: return emptyList()
|
||||
val invisibleMember = Visibilities.findInvisibleMember(receiverValue, resolvedCall.candidateDescriptor, containingDescriptor) ?: return
|
||||
|
||||
if (dispatchReceiverArgument is ExpressionKotlinCallArgument) {
|
||||
val smartCastReceiver = getReceiverValueWithSmartCast(receiverValue, dispatchReceiverArgument.receiver.stableType)
|
||||
if (Visibilities.findInvisibleMember(smartCastReceiver, candidateDescriptor, containingDescriptor) == null) {
|
||||
return listOf(SmartCastDiagnostic(dispatchReceiverArgument, dispatchReceiverArgument.receiver.stableType))
|
||||
addDiagnostic(SmartCastDiagnostic(dispatchReceiverArgument, dispatchReceiverArgument.receiver.stableType, resolvedCall.atom))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
addDiagnostic(VisibilityError(invisibleMember))
|
||||
}
|
||||
}
|
||||
|
||||
internal object NoTypeArguments : ResolutionPart {
|
||||
override fun SimpleKotlinResolutionCandidate.process(): List<KotlinCallDiagnostic> {
|
||||
internal object MapTypeArguments : ResolutionPart() {
|
||||
override fun KotlinResolutionCandidate.process(workIndex: Int) {
|
||||
resolvedCall.typeArgumentMappingByOriginal =
|
||||
callComponents.typeArgumentsToParametersMapper.mapTypeArguments(kotlinCall, candidateDescriptor.original).also {
|
||||
it.diagnostics.forEach(this@process::addDiagnostic)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal object NoTypeArguments : ResolutionPart() {
|
||||
override fun KotlinResolutionCandidate.process(workIndex: Int) {
|
||||
assert(kotlinCall.typeArguments.isEmpty()) {
|
||||
"Variable call cannot has explicit type arguments: ${kotlinCall.typeArguments}. Call: $kotlinCall"
|
||||
}
|
||||
typeArgumentMappingByOriginal = NoExplicitArguments
|
||||
return typeArgumentMappingByOriginal.diagnostics
|
||||
resolvedCall.typeArgumentMappingByOriginal = NoExplicitArguments
|
||||
}
|
||||
}
|
||||
|
||||
internal object MapArguments : ResolutionPart {
|
||||
override fun SimpleKotlinResolutionCandidate.process(): List<KotlinCallDiagnostic> {
|
||||
val mapping = callContext.argumentsToParametersMapper.mapArguments(kotlinCall, candidateDescriptor)
|
||||
argumentMappingByOriginal = mapping.parameterToCallArgumentMap
|
||||
return mapping.diagnostics
|
||||
internal object MapArguments : ResolutionPart() {
|
||||
override fun KotlinResolutionCandidate.process(workIndex: Int) {
|
||||
val mapping = callComponents.argumentsToParametersMapper.mapArguments(kotlinCall, candidateDescriptor)
|
||||
mapping.diagnostics.forEach(this::addDiagnostic)
|
||||
|
||||
resolvedCall.argumentMappingByOriginal = mapping.parameterToCallArgumentMap
|
||||
}
|
||||
}
|
||||
|
||||
internal object NoArguments : ResolutionPart {
|
||||
override fun SimpleKotlinResolutionCandidate.process(): List<KotlinCallDiagnostic> {
|
||||
internal object ArgumentsToCandidateParameterDescriptor : ResolutionPart() {
|
||||
override fun KotlinResolutionCandidate.process(workIndex: Int) {
|
||||
val map = hashMapOf<KotlinCallArgument, ValueParameterDescriptor>()
|
||||
for ((originalValueParameter, resolvedCallArgument) in resolvedCall.argumentMappingByOriginal) {
|
||||
val valueParameter = candidateDescriptor.valueParameters.getOrNull(originalValueParameter.index) ?: continue
|
||||
for (argument in resolvedCallArgument.arguments) {
|
||||
map[argument] = valueParameter
|
||||
}
|
||||
}
|
||||
resolvedCall.argumentToCandidateParameter = map
|
||||
}
|
||||
}
|
||||
|
||||
internal object NoArguments : ResolutionPart() {
|
||||
override fun KotlinResolutionCandidate.process(workIndex: Int) {
|
||||
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()
|
||||
resolvedCall.argumentMappingByOriginal = emptyMap()
|
||||
resolvedCall.argumentToCandidateParameter = emptyMap()
|
||||
}
|
||||
}
|
||||
|
||||
internal object CreateDescriptorWithFreshTypeVariables : ResolutionPart {
|
||||
override fun SimpleKotlinResolutionCandidate.process(): List<KotlinCallDiagnostic> {
|
||||
|
||||
internal object CreateFreshVariablesSubstitutor : ResolutionPart() {
|
||||
override fun KotlinResolutionCandidate.process(workIndex: Int) {
|
||||
if (candidateDescriptor.typeParameters.isEmpty()) {
|
||||
descriptorWithFreshTypes = candidateDescriptor
|
||||
return emptyList()
|
||||
resolvedCall.substitutor = FreshVariableNewTypeSubstitutor.Empty
|
||||
return
|
||||
}
|
||||
val toFreshVariables = createToFreshVariableSubstitutorAndAddInitialConstraints(candidateDescriptor, csBuilder, kotlinCall)
|
||||
typeVariablesForFreshTypeParameters = toFreshVariables.freshVariables
|
||||
val toFreshVariables = createToFreshVariableSubstitutorAndAddInitialConstraints(candidateDescriptor, csBuilder)
|
||||
resolvedCall.substitutor = toFreshVariables
|
||||
|
||||
// bad function -- error on declaration side
|
||||
if (csBuilder.hasContradiction) {
|
||||
descriptorWithFreshTypes = candidateDescriptor
|
||||
return emptyList()
|
||||
}
|
||||
if (csBuilder.hasContradiction) return
|
||||
|
||||
// optimization
|
||||
if (typeArgumentMappingByOriginal == NoExplicitArguments && knownTypeParametersResultingSubstitutor == null) {
|
||||
descriptorWithFreshTypes = candidateDescriptor.substitute(toFreshVariables)
|
||||
csBuilder.simplify().let { assert(it.isEmpty) { "Substitutor should be empty: $it, call: $kotlinCall" } }
|
||||
return emptyList()
|
||||
if (resolvedCall.typeArgumentMappingByOriginal == NoExplicitArguments && knownTypeParametersResultingSubstitutor == null) {
|
||||
return
|
||||
}
|
||||
|
||||
val typeParameters = candidateDescriptor.typeParameters
|
||||
for (index in typeParameters.indices) {
|
||||
val typeParameter = typeParameters[index]
|
||||
val freshVariable = toFreshVariables.freshVariables[index]
|
||||
|
||||
val knownTypeArgument = knownTypeParametersResultingSubstitutor?.substitute(typeParameter.defaultType)
|
||||
if (knownTypeArgument != null) {
|
||||
val freshVariable = toFreshVariables.freshVariables[index]
|
||||
csBuilder.addEqualityConstraint(freshVariable.defaultType, knownTypeArgument.unwrap(), KnownTypeParameterConstraintPosition(knownTypeArgument))
|
||||
continue
|
||||
}
|
||||
|
||||
val typeArgument = typeArgumentMappingByOriginal.getTypeArgument(typeParameter)
|
||||
val typeArgument = resolvedCall.typeArgumentMappingByOriginal.getTypeArgument(typeParameter)
|
||||
|
||||
if (typeArgument is SimpleTypeArgument) {
|
||||
val freshVariable = toFreshVariables.freshVariables[index]
|
||||
csBuilder.addEqualityConstraint(freshVariable.defaultType, typeArgument.type, ExplicitTypeParameterConstraintPosition(typeArgument))
|
||||
}
|
||||
else {
|
||||
@@ -147,29 +162,15 @@ internal object CreateDescriptorWithFreshTypeVariables : ResolutionPart {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.substitute(toFreshVariables).substitute(toFixedTypeParameters)
|
||||
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
fun createToFreshVariableSubstitutorAndAddInitialConstraints(
|
||||
candidateDescriptor: CallableDescriptor,
|
||||
csBuilder: ConstraintSystemOperation,
|
||||
kotlinCall: KotlinCall?
|
||||
csBuilder: ConstraintSystemOperation
|
||||
): FreshVariableNewTypeSubstitutor {
|
||||
val typeParameters = candidateDescriptor.typeParameters
|
||||
|
||||
val freshTypeVariables = typeParameters.map { TypeVariableFromCallableDescriptor(it, kotlinCall) }
|
||||
val freshTypeVariables = typeParameters.map { TypeVariableFromCallableDescriptor(it) }
|
||||
|
||||
val toFreshVariables = FreshVariableNewTypeSubstitutor(freshTypeVariables)
|
||||
|
||||
@@ -190,97 +191,124 @@ internal object CreateDescriptorWithFreshTypeVariables : ResolutionPart {
|
||||
}
|
||||
}
|
||||
|
||||
internal object CheckExplicitReceiverKindConsistency : ResolutionPart {
|
||||
private fun SimpleKotlinResolutionCandidate.hasError(): Nothing =
|
||||
internal object CheckExplicitReceiverKindConsistency : ResolutionPart() {
|
||||
private fun KotlinResolutionCandidate.hasError(): Nothing =
|
||||
error("Inconsistent call: $kotlinCall. \n" +
|
||||
"Candidate: $candidateDescriptor, explicitReceiverKind: $explicitReceiverKind.\n" +
|
||||
"Candidate: $candidateDescriptor, explicitReceiverKind: ${resolvedCall.explicitReceiverKind}.\n" +
|
||||
"Explicit receiver: ${kotlinCall.explicitReceiver}, dispatchReceiverForInvokeExtension: ${kotlinCall.dispatchReceiverForInvokeExtension}")
|
||||
|
||||
override fun SimpleKotlinResolutionCandidate.process(): List<KotlinCallDiagnostic> {
|
||||
when (explicitReceiverKind) {
|
||||
override fun KotlinResolutionCandidate.process(workIndex: Int) {
|
||||
when (resolvedCall.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(
|
||||
private fun KotlinResolutionCandidate.resolveKotlinArgument(
|
||||
argument: KotlinCallArgument,
|
||||
candidateParameter: ParameterDescriptor?,
|
||||
isReceiver: Boolean
|
||||
) {
|
||||
val expectedType = candidateParameter?.let {
|
||||
resolvedCall.substitutor.safeSubstitute(argument.getExpectedType(candidateParameter))
|
||||
}
|
||||
addResolvedKtPrimitive(resolveKtPrimitive(csBuilder, argument, expectedType, this, isReceiver))
|
||||
}
|
||||
|
||||
internal object CheckReceivers : ResolutionPart() {
|
||||
private fun KotlinResolutionCandidate.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
|
||||
if (receiverArgument == null || receiverParameter == null) return
|
||||
|
||||
val expectedType = receiverParameter.type.unwrap()
|
||||
|
||||
return checkSimpleArgument(csBuilder, receiverArgument, expectedType, isReceiver = true)
|
||||
resolveKotlinArgument(receiverArgument, receiverParameter, isReceiver = true)
|
||||
}
|
||||
|
||||
override fun SimpleKotlinResolutionCandidate.process() =
|
||||
listOfNotNull(checkReceiver(dispatchReceiverArgument, descriptorWithFreshTypes.dispatchReceiverParameter),
|
||||
checkReceiver(extensionReceiver, descriptorWithFreshTypes.extensionReceiverParameter))
|
||||
}
|
||||
|
||||
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 = when (argument) {
|
||||
is SimpleKotlinCallArgument ->
|
||||
checkSimpleArgument(csBuilder, argument, argument.getExpectedType(parameterDescriptor))
|
||||
is PostponableKotlinCallArgument ->
|
||||
createPostponedArgumentAndPerformInitialChecks(kotlinCall, csBuilder, argument, parameterDescriptor)
|
||||
else -> unexpectedArgument(argument)
|
||||
}
|
||||
diagnostics.addIfNotNull(diagnostic)
|
||||
|
||||
if (diagnostic != null && !diagnostic.candidateApplicability.isSuccess) break
|
||||
}
|
||||
override fun KotlinResolutionCandidate.process(workIndex: Int) {
|
||||
if (workIndex == 0) {
|
||||
checkReceiver(resolvedCall.dispatchReceiverArgument, candidateDescriptor.dispatchReceiverParameter)
|
||||
} else {
|
||||
checkReceiver(resolvedCall.extensionReceiverArgument, candidateDescriptor.extensionReceiverParameter)
|
||||
}
|
||||
return diagnostics
|
||||
}
|
||||
|
||||
override fun KotlinResolutionCandidate.workCount() = 2
|
||||
}
|
||||
|
||||
internal object CheckArguments : ResolutionPart() {
|
||||
override fun KotlinResolutionCandidate.process(workIndex: Int) {
|
||||
val argument = kotlinCall.argumentsInParenthesis[workIndex]
|
||||
resolveKotlinArgument(argument, resolvedCall.argumentToCandidateParameter[argument], isReceiver = false)
|
||||
}
|
||||
|
||||
override fun KotlinResolutionCandidate.workCount() = kotlinCall.argumentsInParenthesis.size
|
||||
}
|
||||
|
||||
internal object CheckExternalArgument : ResolutionPart() {
|
||||
override fun KotlinResolutionCandidate.process(workIndex: Int) {
|
||||
val argument = kotlinCall.externalArgument ?: return
|
||||
|
||||
resolveKotlinArgument(argument, resolvedCall.argumentToCandidateParameter[argument], isReceiver = false)
|
||||
}
|
||||
}
|
||||
|
||||
internal object CheckInfixResolutionPart : ResolutionPart {
|
||||
override fun SimpleKotlinResolutionCandidate.process(): List<KotlinCallDiagnostic> {
|
||||
if (callContext.externalPredicates.isInfixCall(kotlinCall) &&
|
||||
internal object CheckInfixResolutionPart : ResolutionPart() {
|
||||
override fun KotlinResolutionCandidate.process(workIndex: Int) {
|
||||
val candidateDescriptor = resolvedCall.candidateDescriptor
|
||||
if (callComponents.statelessCallbacks.isInfixCall(kotlinCall) &&
|
||||
(candidateDescriptor !is FunctionDescriptor || !candidateDescriptor.isInfix)) {
|
||||
return listOf(InfixCallNoInfixModifier)
|
||||
addDiagnostic(InfixCallNoInfixModifier)
|
||||
}
|
||||
|
||||
return emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
internal object CheckOperatorResolutionPart : ResolutionPart {
|
||||
override fun SimpleKotlinResolutionCandidate.process(): List<KotlinCallDiagnostic> {
|
||||
if (callContext.externalPredicates.isOperatorCall(kotlinCall) &&
|
||||
internal object CheckOperatorResolutionPart : ResolutionPart() {
|
||||
override fun KotlinResolutionCandidate.process(workIndex: Int) {
|
||||
val candidateDescriptor = resolvedCall.candidateDescriptor
|
||||
if (callComponents.statelessCallbacks.isOperatorCall(kotlinCall) &&
|
||||
(candidateDescriptor !is FunctionDescriptor || !candidateDescriptor.isOperator)) {
|
||||
return listOf(InvokeConventionCallNoOperatorModifier)
|
||||
addDiagnostic(InvokeConventionCallNoOperatorModifier)
|
||||
}
|
||||
|
||||
return emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
internal object CheckAbstractSuperCallPart : ResolutionPart {
|
||||
override fun SimpleKotlinResolutionCandidate.process(): List<KotlinCallDiagnostic> {
|
||||
if (callContext.externalPredicates.isSuperExpression(dispatchReceiverArgument)) {
|
||||
internal object CheckAbstractSuperCallPart : ResolutionPart() {
|
||||
override fun KotlinResolutionCandidate.process(workIndex: Int) {
|
||||
val candidateDescriptor = resolvedCall.candidateDescriptor
|
||||
|
||||
if (callComponents.statelessCallbacks.isSuperExpression(resolvedCall.dispatchReceiverArgument)) {
|
||||
if (candidateDescriptor is MemberDescriptor && candidateDescriptor.modality == Modality.ABSTRACT) {
|
||||
return listOf(AbstractSuperCall)
|
||||
addDiagnostic(AbstractSuperCall)
|
||||
}
|
||||
}
|
||||
|
||||
return emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
internal object ErrorDescriptorResolutionPart : ResolutionPart() {
|
||||
override fun KotlinResolutionCandidate.process(workIndex: Int) {
|
||||
assert(ErrorUtils.isError(candidateDescriptor)) {
|
||||
"Should be error descriptor: $candidateDescriptor"
|
||||
}
|
||||
resolvedCall.typeArgumentMappingByOriginal = TypeArgumentsToParametersMapper.TypeArgumentsMapping.NoExplicitArguments
|
||||
resolvedCall.argumentMappingByOriginal = emptyMap()
|
||||
resolvedCall.substitutor = FreshVariableNewTypeSubstitutor.Empty
|
||||
resolvedCall.argumentToCandidateParameter = emptyMap()
|
||||
|
||||
kotlinCall.explicitReceiver?.safeAs<SimpleKotlinCallArgument>()?.let {
|
||||
resolveKotlinArgument(it, null, isReceiver = true)
|
||||
}
|
||||
for (argument in kotlinCall.argumentsInParenthesis) {
|
||||
resolveKotlinArgument(argument, null, isReceiver = true)
|
||||
}
|
||||
|
||||
kotlinCall.externalArgument?.let {
|
||||
resolveKotlinArgument(it, null, isReceiver = true)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -35,22 +35,25 @@ import org.jetbrains.kotlin.types.upperIfFlexible
|
||||
fun checkSimpleArgument(
|
||||
csBuilder: ConstraintSystemBuilder,
|
||||
argument: SimpleKotlinCallArgument,
|
||||
expectedType: UnwrappedType,
|
||||
isReceiver: Boolean = false
|
||||
): KotlinCallDiagnostic? {
|
||||
return when (argument) {
|
||||
is ExpressionKotlinCallArgument -> checkExpressionArgument(csBuilder, argument, expectedType, isReceiver)
|
||||
is SubKotlinCallArgument -> checkSubCallArgument(csBuilder, argument, expectedType, isReceiver)
|
||||
else -> unexpectedArgument(argument)
|
||||
}
|
||||
expectedType: UnwrappedType?,
|
||||
diagnosticsHolder: KotlinDiagnosticsHolder,
|
||||
isReceiver: Boolean
|
||||
): ResolvedAtom = when (argument) {
|
||||
is ExpressionKotlinCallArgument -> checkExpressionArgument(csBuilder, argument, expectedType, diagnosticsHolder, isReceiver)
|
||||
is SubKotlinCallArgument -> checkSubCallArgument(csBuilder, argument, expectedType, diagnosticsHolder, isReceiver)
|
||||
else -> unexpectedArgument(argument)
|
||||
}
|
||||
|
||||
private fun checkExpressionArgument(
|
||||
csBuilder: ConstraintSystemBuilder,
|
||||
expressionArgument: ExpressionKotlinCallArgument,
|
||||
expectedType: UnwrappedType,
|
||||
expectedType: UnwrappedType?,
|
||||
diagnosticsHolder: KotlinDiagnosticsHolder,
|
||||
isReceiver: Boolean
|
||||
): KotlinCallDiagnostic? {
|
||||
): ResolvedAtom {
|
||||
val resolvedKtExpression = ResolvedExpressionAtom(expressionArgument)
|
||||
if (expectedType == null) return resolvedKtExpression
|
||||
|
||||
// todo run this approximation only once for call
|
||||
val argumentType = captureFromTypeParameterUpperBoundIfNeeded(expressionArgument.receiver.stableType, expectedType)
|
||||
|
||||
@@ -70,30 +73,31 @@ private fun checkExpressionArgument(
|
||||
val position = if (isReceiver) ReceiverConstraintPosition(expressionArgument) else ArgumentConstraintPosition(expressionArgument)
|
||||
if (expressionArgument.isSafeCall) {
|
||||
if (!csBuilder.addSubtypeConstraintIfCompatible(argumentType, expectedNullableType, position)) {
|
||||
return unstableSmartCastOrSubtypeError(expressionArgument.receiver.unstableType, expectedNullableType, position)?.let { return it }
|
||||
diagnosticsHolder.addDiagnosticIfNotNull(
|
||||
unstableSmartCastOrSubtypeError(expressionArgument.receiver.unstableType, expectedNullableType, position))
|
||||
}
|
||||
return null
|
||||
return resolvedKtExpression
|
||||
}
|
||||
|
||||
if (!csBuilder.addSubtypeConstraintIfCompatible(argumentType, expectedType, position)) {
|
||||
if (!isReceiver) {
|
||||
return unstableSmartCastOrSubtypeError(expressionArgument.receiver.unstableType, expectedType, position)?.let { return it }
|
||||
diagnosticsHolder.addDiagnosticIfNotNull(unstableSmartCastOrSubtypeError(expressionArgument.receiver.unstableType, expectedType, position))
|
||||
return resolvedKtExpression
|
||||
}
|
||||
|
||||
val unstableType = expressionArgument.receiver.unstableType
|
||||
if (unstableType != null && csBuilder.addSubtypeConstraintIfCompatible(unstableType, expectedType, position)) {
|
||||
return UnstableSmartCast(expressionArgument, unstableType)
|
||||
diagnosticsHolder.addDiagnostic(UnstableSmartCast(expressionArgument, unstableType))
|
||||
}
|
||||
else if (csBuilder.addSubtypeConstraintIfCompatible(argumentType, expectedNullableType, position)) {
|
||||
return UnsafeCallError(expressionArgument)
|
||||
diagnosticsHolder.addDiagnostic(UnsafeCallError(expressionArgument))
|
||||
}
|
||||
else {
|
||||
csBuilder.addSubtypeConstraint(argumentType, expectedType, position)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
return resolvedKtExpression
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -131,29 +135,33 @@ private fun captureFromTypeParameterUpperBoundIfNeeded(argumentType: UnwrappedTy
|
||||
private fun checkSubCallArgument(
|
||||
csBuilder: ConstraintSystemBuilder,
|
||||
subCallArgument: SubKotlinCallArgument,
|
||||
expectedType: UnwrappedType,
|
||||
expectedType: UnwrappedType?,
|
||||
diagnosticsHolder: KotlinDiagnosticsHolder,
|
||||
isReceiver: Boolean
|
||||
): KotlinCallDiagnostic? {
|
||||
val resolvedCall = subCallArgument.resolvedCall
|
||||
val expectedNullableType = expectedType.makeNullableAsSpecified(true)
|
||||
val position = ArgumentConstraintPosition(subCallArgument)
|
||||
): ResolvedAtom {
|
||||
val subCallResult = subCallArgument.callResult
|
||||
|
||||
csBuilder.addInnerCall(resolvedCall)
|
||||
if (expectedType == null) return subCallResult
|
||||
|
||||
val expectedNullableType = expectedType.makeNullableAsSpecified(true)
|
||||
val position = if (isReceiver) ReceiverConstraintPosition(subCallArgument) else ArgumentConstraintPosition(subCallArgument)
|
||||
|
||||
// subArgument cannot has stable smartcast
|
||||
val currentReturnType = subCallArgument.receiver.receiverValue.type.unwrap()
|
||||
// return type can contains fixed type variables
|
||||
val currentReturnType = csBuilder.buildCurrentSubstitutor().safeSubstitute(subCallArgument.receiver.receiverValue.type.unwrap())
|
||||
if (subCallArgument.isSafeCall) {
|
||||
csBuilder.addSubtypeConstraint(currentReturnType, expectedNullableType, position)
|
||||
return null
|
||||
return subCallResult
|
||||
}
|
||||
|
||||
if (isReceiver && !csBuilder.addSubtypeConstraintIfCompatible(currentReturnType, expectedType, position) &&
|
||||
csBuilder.addSubtypeConstraintIfCompatible(currentReturnType, expectedNullableType, position)
|
||||
) {
|
||||
return UnsafeCallError(subCallArgument)
|
||||
diagnosticsHolder.addDiagnostic(UnsafeCallError(subCallArgument))
|
||||
return subCallResult
|
||||
}
|
||||
|
||||
csBuilder.addSubtypeConstraint(currentReturnType, expectedType, position)
|
||||
return null
|
||||
return subCallResult
|
||||
}
|
||||
|
||||
|
||||
@@ -16,12 +16,18 @@
|
||||
|
||||
package org.jetbrains.kotlin.resolve.calls.inference
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.resolve.calls.components.PostponedArgumentsAnalyzer
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.components.NewTypeSubstitutor
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintPosition
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.NewTypeVariable
|
||||
import org.jetbrains.kotlin.resolve.calls.model.*
|
||||
import org.jetbrains.kotlin.resolve.calls.model.CallableReferenceKotlinCallArgument
|
||||
import org.jetbrains.kotlin.resolve.calls.model.KotlinCallArgument
|
||||
import org.jetbrains.kotlin.resolve.calls.model.LHSResult
|
||||
import org.jetbrains.kotlin.resolve.calls.model.SubKotlinCallArgument
|
||||
import org.jetbrains.kotlin.types.TypeConstructor
|
||||
import org.jetbrains.kotlin.types.UnwrappedType
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
interface ConstraintSystemOperation {
|
||||
val hasContradiction: Boolean
|
||||
@@ -31,26 +37,32 @@ interface ConstraintSystemOperation {
|
||||
fun addEqualityConstraint(a: UnwrappedType, b: UnwrappedType, position: ConstraintPosition)
|
||||
|
||||
fun isProperType(type: UnwrappedType): Boolean
|
||||
fun isTypeVariable(type: UnwrappedType): Boolean
|
||||
|
||||
fun getProperSuperTypeConstructors(type: UnwrappedType): List<TypeConstructor>
|
||||
fun getProperSubTypeBounds(type: UnwrappedType): List<UnwrappedType>
|
||||
}
|
||||
|
||||
interface ConstraintSystemBuilder : ConstraintSystemOperation {
|
||||
fun addInnerCall(innerCall: ResolvedKotlinCall.OnlyResolvedKotlinCall)
|
||||
fun addPostponedArgument(postponedArgument: PostponedKotlinCallArgument)
|
||||
|
||||
val builtIns: KotlinBuiltIns
|
||||
// if runOperations return true, then this operation will be applied, and function return true
|
||||
fun runTransaction(runOperations: ConstraintSystemOperation.() -> Boolean): Boolean
|
||||
|
||||
/**
|
||||
* This function removes variables for which we know exact type.
|
||||
* @return substitutor from typeVariable to result
|
||||
*/
|
||||
fun simplify(): NewTypeSubstitutor
|
||||
fun buildCurrentSubstitutor(): NewTypeSubstitutor
|
||||
}
|
||||
|
||||
fun ConstraintSystemBuilder.addSubtypeConstraintIfCompatible(lowerType: UnwrappedType, upperType: UnwrappedType, position: ConstraintPosition) =
|
||||
runTransaction {
|
||||
if (!hasContradiction) addSubtypeConstraint(lowerType, upperType, position)
|
||||
!hasContradiction
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun PostponedArgumentsAnalyzer.Context.addSubsystemForArgument(argument: KotlinCallArgument?) {
|
||||
when (argument) {
|
||||
is SubKotlinCallArgument -> addOtherSystem(argument.callResult.constraintSystem)
|
||||
is CallableReferenceKotlinCallArgument -> {
|
||||
addSubsystemForArgument(argument.lhsResult.safeAs<LHSResult.Expression>()?.lshCallArgument)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.components.NewTypeSubstitutor
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.components.NewTypeSubstitutorByConstructorMap
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.NewConstraintSystemImpl
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
||||
import org.jetbrains.kotlin.types.*
|
||||
|
||||
@@ -27,6 +28,17 @@ fun ConstraintStorage.buildCurrentSubstitutor() = NewTypeSubstitutorByConstructo
|
||||
it.key to it.value
|
||||
})
|
||||
|
||||
fun ConstraintStorage.buildResultingSubstitutor(): NewTypeSubstitutor {
|
||||
val currentSubstitutorMap = fixedTypeVariables.entries.associate {
|
||||
it.key to it.value
|
||||
}
|
||||
val uninferredSubstitutorMap = notFixedTypeVariables.entries.associate { (freshTypeConstructor, typeVariable) ->
|
||||
freshTypeConstructor to ErrorUtils.createErrorTypeWithCustomConstructor("Uninferred type", typeVariable.typeVariable.freshTypeConstructor)
|
||||
}
|
||||
|
||||
return NewTypeSubstitutorByConstructorMap(currentSubstitutorMap + uninferredSubstitutorMap)
|
||||
}
|
||||
|
||||
val CallableDescriptor.returnTypeOrNothing: UnwrappedType
|
||||
get() {
|
||||
returnType?.let { return it.unwrap() }
|
||||
|
||||
@@ -16,16 +16,22 @@
|
||||
|
||||
package org.jetbrains.kotlin.resolve.calls.inference
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.resolve.calls.components.KotlinCallCompleter
|
||||
import org.jetbrains.kotlin.resolve.calls.components.PostponedArgumentsAnalyzer
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.components.KotlinConstraintSystemCompleter
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage
|
||||
import org.jetbrains.kotlin.resolve.calls.model.KotlinCallDiagnostic
|
||||
|
||||
interface NewConstraintSystem {
|
||||
val builtIns: KotlinBuiltIns
|
||||
val hasContradiction: Boolean
|
||||
val diagnostics: List<KotlinCallDiagnostic>
|
||||
|
||||
fun getBuilder(): ConstraintSystemBuilder
|
||||
|
||||
// after this method we shouldn't mutate system via ConstraintSystemBuilder
|
||||
fun asReadOnlyStorage(): ConstraintStorage
|
||||
fun asCallCompleterContext(): KotlinCallCompleter.Context
|
||||
fun asConstraintSystemCompleterContext(): KotlinConstraintSystemCompleter.Context
|
||||
fun asPostponedArgumentsAnalyzerContext(): PostponedArgumentsAnalyzer.Context
|
||||
}
|
||||
@@ -1,258 +0,0 @@
|
||||
/*
|
||||
* 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.VariableWithConstraints
|
||||
import org.jetbrains.kotlin.resolve.calls.model.PostponedKotlinCallArgument
|
||||
import org.jetbrains.kotlin.resolve.calls.model.PostponedLambdaArgument
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.checker.NewKotlinTypeChecker
|
||||
import org.jetbrains.kotlin.types.checker.isIntersectionType
|
||||
import org.jetbrains.kotlin.types.typeUtil.contains
|
||||
import org.jetbrains.kotlin.utils.DFS
|
||||
import org.jetbrains.kotlin.utils.SmartList
|
||||
|
||||
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<PostponedLambdaArgument>
|
||||
val postponedArguments: List<PostponedKotlinCallArgument>
|
||||
}
|
||||
|
||||
fun computeCompletionOrder(
|
||||
c: Context,
|
||||
topReturnType: UnwrappedType
|
||||
): List<NodeWithDirection> = DependencyGraph(c).getCompletionOrder(topReturnType)
|
||||
|
||||
/**
|
||||
* U depends-on V if one of the following conditions is met:
|
||||
*
|
||||
* LAMBDA
|
||||
* result type U depends-on all parameters types V of the corresponding lambda
|
||||
*
|
||||
* LAMBDA-RESULT
|
||||
* Since there is no separate type variables for lambda such edges removed for now
|
||||
*
|
||||
* V is a lambda result type variable,
|
||||
* V <: T constraint exists for V,
|
||||
* U is a constituent type of T in position matching approximation direction for U
|
||||
*
|
||||
* STRONG-CONSTRAINT
|
||||
* 'U <op> T' constraint exists for U,
|
||||
* <op> is a constraint operator relevant to U approximation direction,
|
||||
* V is a proper constituent type of T
|
||||
*
|
||||
* WEAK-CONSTRAINT
|
||||
* 'U <op> V' constraint exists for U,
|
||||
* <op> is a constraint operator relevant to U approximation direction
|
||||
*/
|
||||
private class DependencyGraph(val c: Context) {
|
||||
private val directions = HashMap<Variable, ResolveDirection>()
|
||||
|
||||
private val lambdaEdges = HashMap<Variable, MutableSet<Variable>>()
|
||||
|
||||
// first in the list -- first fix
|
||||
fun getCompletionOrder(topReturnType: UnwrappedType): List<NodeWithDirection> {
|
||||
setupDirections(topReturnType)
|
||||
|
||||
buildLambdaEdges()
|
||||
|
||||
return topologicalOrderWith0Priority().map { NodeWithDirection(it, directions[it] ?: ResolveDirection.UNKNOWN) }
|
||||
}
|
||||
|
||||
private fun buildLambdaEdges() {
|
||||
for (lambdaArgument in c.lambdaArguments) {
|
||||
if (lambdaArgument.analyzed) continue // optimization
|
||||
|
||||
val typeVariablesInReturnType = SmartList<Variable>()
|
||||
lambdaArgument.outputType.findTypeVariables(typeVariablesInReturnType)
|
||||
|
||||
if (typeVariablesInReturnType.isEmpty()) continue // optimization
|
||||
|
||||
val typeVariablesInParameters = SmartList<Variable>()
|
||||
lambdaArgument.inputTypes.forEach { it.findTypeVariables(typeVariablesInParameters) }
|
||||
|
||||
for (returnTypeVariable in typeVariablesInReturnType) {
|
||||
lambdaEdges.getOrPut(returnTypeVariable) { LinkedHashSet() }.addAll(typeVariablesInParameters)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun UnwrappedType.findTypeVariables(to: MutableCollection<Variable>) =
|
||||
contains {
|
||||
c.notFixedTypeVariables[it.constructor]?.let { variable -> to.add(variable) }
|
||||
false
|
||||
}
|
||||
|
||||
private fun topologicalOrderWith0Priority(): List<Variable> {
|
||||
val handler = object : DFS.CollectingNodeHandler<Variable, Variable, LinkedHashSet<Variable>>(LinkedHashSet()) {
|
||||
override fun afterChildren(current: Variable) {
|
||||
// LAMBDA dependency edges should always be satisfied
|
||||
// Note that cyclic by lambda edges are possible
|
||||
result.addAll(getLambdaDependencies(current))
|
||||
|
||||
result.add(current)
|
||||
}
|
||||
}
|
||||
|
||||
for (typeVariable in c.notFixedTypeVariables.values.sortByTypeVariable()) {
|
||||
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 (inputType in resolvedLambdaArgument.inputTypes) {
|
||||
inputType.visitType(ResolveDirection.TO_SUBTYPE) { variableWithConstraints, direction ->
|
||||
enterToNode(variableWithConstraints, direction)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 getConstraintDependencies(variable, direction)) {
|
||||
enterToNode(otherVariable, otherDirection)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getEdges(variable: Variable): List<Variable> {
|
||||
val direction = directions[variable] ?: ResolveDirection.UNKNOWN
|
||||
val constraintEdges =
|
||||
LinkedHashSet<Variable>().also { set ->
|
||||
getConstraintDependencies(variable, direction).mapTo(set) { it.variableWithConstraints }
|
||||
}.toList().sortByTypeVariable()
|
||||
val lambdaEdges = getLambdaDependencies(variable).sortByTypeVariable()
|
||||
return constraintEdges + lambdaEdges
|
||||
}
|
||||
|
||||
private fun Collection<Variable>.sortByTypeVariable() =
|
||||
// TODO hack, provide some reasonable stable order
|
||||
sortedBy { it.typeVariable.toString() }
|
||||
|
||||
private enum class ConstraintDependencyKind { STRONG, WEAK }
|
||||
|
||||
private fun getConstraintDependencies(
|
||||
variableWithConstraints: Variable,
|
||||
direction: ResolveDirection,
|
||||
filterByDependencyKind: ConstraintDependencyKind? = null
|
||||
): List<NodeWithDirection> =
|
||||
SmartList<NodeWithDirection>().also { result ->
|
||||
for (constraint in variableWithConstraints.constraints) {
|
||||
if (!isInterestingConstraint(direction, constraint)) continue
|
||||
|
||||
if (filterByDependencyKind == null || filterByDependencyKind == getConstraintDependencyKind(constraint)) {
|
||||
constraint.type.visitType(direction) { nodeVariable, nodeDirection ->
|
||||
result.add(NodeWithDirection(nodeVariable, nodeDirection))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getConstraintDependencyKind(constraint: Constraint): ConstraintDependencyKind =
|
||||
if (c.notFixedTypeVariables.containsKey(constraint.type.constructor))
|
||||
ConstraintDependencyKind.WEAK
|
||||
else
|
||||
ConstraintDependencyKind.STRONG
|
||||
|
||||
private fun isInterestingConstraint(direction: ResolveDirection, constraint: Constraint): Boolean =
|
||||
!(direction == ResolveDirection.TO_SUBTYPE && constraint.kind == ConstraintKind.UPPER) &&
|
||||
!(direction == ResolveDirection.TO_SUPERTYPE && constraint.kind == ConstraintKind.LOWER)
|
||||
|
||||
|
||||
private fun getLambdaDependencies(variable: Variable): List<Variable> = lambdaEdges[variable]?.toList() ?: emptyList()
|
||||
|
||||
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
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
private fun ResolveDirection.opposite() = when (this) {
|
||||
ResolveDirection.UNKNOWN -> ResolveDirection.UNKNOWN
|
||||
ResolveDirection.TO_SUPERTYPE -> ResolveDirection.TO_SUBTYPE
|
||||
ResolveDirection.TO_SUBTYPE -> ResolveDirection.TO_SUPERTYPE
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
/*
|
||||
* 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.inference.components
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.resolve.calls.components.KotlinCallCompleter
|
||||
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.NotEnoughInformationForTypeParameter
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.VariableWithConstraints
|
||||
|
||||
typealias VariableResolutionNode = FixationOrderCalculator.NodeWithDirection
|
||||
|
||||
class InferenceStepResolver(
|
||||
private val resultTypeResolver: ResultTypeResolver
|
||||
) {
|
||||
/**
|
||||
* Resolves one or more of the `variables`.
|
||||
* Returns `true` if type variable resolution should stop.
|
||||
*/
|
||||
fun resolveVariables(c: KotlinCallCompleter.Context, variables: List<VariableResolutionNode>): Boolean {
|
||||
if (variables.isEmpty()) return true
|
||||
if (c.hasContradiction) return true
|
||||
|
||||
val nodeToResolve = variables.firstOrNull { it.variableWithConstraints.hasProperConstraint(c) } ?:
|
||||
variables.first()
|
||||
val (variableWithConstraints, direction) = nodeToResolve
|
||||
val variable = variableWithConstraints.typeVariable
|
||||
|
||||
val resultType = resultTypeResolver.findResultType(c.asResultTypeResolverContext(), variableWithConstraints, direction)
|
||||
if (resultType == null) {
|
||||
c.addError(NotEnoughInformationForTypeParameter(variable))
|
||||
return true
|
||||
}
|
||||
c.fixVariable(variable, resultType)
|
||||
return false
|
||||
}
|
||||
|
||||
private fun VariableWithConstraints.hasProperConstraint(c: KotlinCallCompleter.Context) =
|
||||
constraints.any { !it.isTrivial() && c.canBeProper(it.type) }
|
||||
|
||||
private fun Constraint.isTrivial() =
|
||||
kind == ConstraintKind.LOWER && KotlinBuiltIns.isNothing(type) ||
|
||||
kind == ConstraintKind.UPPER && KotlinBuiltIns.isNullableAny(type)
|
||||
}
|
||||
@@ -0,0 +1,176 @@
|
||||
/*
|
||||
* 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.inference.components
|
||||
|
||||
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.model.VariableWithConstraints
|
||||
import org.jetbrains.kotlin.resolve.calls.model.*
|
||||
import org.jetbrains.kotlin.types.TypeConstructor
|
||||
import org.jetbrains.kotlin.types.UnwrappedType
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
class KotlinConstraintSystemCompleter(
|
||||
private val resultTypeResolver: ResultTypeResolver,
|
||||
private val variableFixationFinder: VariableFixationFinder
|
||||
) {
|
||||
enum class ConstraintSystemCompletionMode {
|
||||
FULL,
|
||||
PARTIAL
|
||||
}
|
||||
|
||||
interface Context : VariableFixationFinder.Context, ResultTypeResolver.Context {
|
||||
override val notFixedTypeVariables: Map<TypeConstructor, VariableWithConstraints>
|
||||
|
||||
// type can be proper if it not contains not fixed type variables
|
||||
fun canBeProper(type: UnwrappedType): Boolean
|
||||
|
||||
// mutable operations
|
||||
fun addError(error: KotlinCallDiagnostic)
|
||||
fun fixVariable(variable: NewTypeVariable, resultType: UnwrappedType)
|
||||
}
|
||||
|
||||
fun runCompletion(
|
||||
c: Context,
|
||||
completionMode: ConstraintSystemCompletionMode,
|
||||
topLevelPrimitive: ResolvedAtom,
|
||||
topLevelType: UnwrappedType,
|
||||
analyze: (PostponedResolvedAtom) -> Unit
|
||||
) {
|
||||
while (true) {
|
||||
if (analyzePostponeArgumentIfPossible(c, topLevelPrimitive, analyze)) continue
|
||||
|
||||
val allTypeVariables = getOrderedAllTypeVariables(c, topLevelPrimitive)
|
||||
val postponedKtPrimitives = getOrderedNotAnalyzedPostponedArguments(topLevelPrimitive)
|
||||
val variableForFixation = variableFixationFinder.findFirstVariableForFixation(
|
||||
c, allTypeVariables, postponedKtPrimitives, completionMode, topLevelType)
|
||||
|
||||
if (shouldWeForceCallableReferenceResolution(completionMode, variableForFixation)) {
|
||||
if (forceCallableReferenceResolution(topLevelPrimitive, analyze)) continue
|
||||
}
|
||||
|
||||
if (variableForFixation != null) {
|
||||
if (variableForFixation.hasProperConstraint || completionMode == ConstraintSystemCompletionMode.FULL) {
|
||||
val variableWithConstraints = c.notFixedTypeVariables[variableForFixation.variable]!!
|
||||
|
||||
fixVariable(c, topLevelType, variableWithConstraints, postponedKtPrimitives)
|
||||
|
||||
if (!variableForFixation.hasProperConstraint) {
|
||||
c.addError(NotEnoughInformationForTypeParameter(variableWithConstraints.typeVariable))
|
||||
}
|
||||
continue
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
if (completionMode == ConstraintSystemCompletionMode.FULL) {
|
||||
// force resolution for all not-analyzed argument's
|
||||
getOrderedNotAnalyzedPostponedArguments(topLevelPrimitive).forEach(analyze)
|
||||
}
|
||||
}
|
||||
|
||||
private fun shouldWeForceCallableReferenceResolution(
|
||||
completionMode: ConstraintSystemCompletionMode,
|
||||
variableForFixation: VariableFixationFinder.VariableForFixation?
|
||||
): Boolean {
|
||||
if (completionMode == ConstraintSystemCompletionMode.PARTIAL) return false
|
||||
if (variableForFixation != null && variableForFixation.hasProperConstraint) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// true if we do analyze
|
||||
private fun analyzePostponeArgumentIfPossible(c: Context, topLevelPrimitive: ResolvedAtom, analyze: (PostponedResolvedAtom) -> Unit): Boolean {
|
||||
for (argument in getOrderedNotAnalyzedPostponedArguments(topLevelPrimitive)) {
|
||||
if (canWeAnalyzeIt(c, argument)) {
|
||||
analyze(argument)
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// true if we find some callable reference and run resolution for it. Note that such resolution can be unsuccessful
|
||||
private fun forceCallableReferenceResolution(topLevelPrimitive: ResolvedAtom, analyze: (PostponedResolvedAtom) -> Unit): Boolean {
|
||||
val callableReferenceArgument = getOrderedNotAnalyzedPostponedArguments(topLevelPrimitive).
|
||||
firstIsInstanceOrNull<ResolvedCallableReferenceAtom>() ?: return false
|
||||
|
||||
analyze(callableReferenceArgument)
|
||||
return true
|
||||
}
|
||||
|
||||
private fun getOrderedNotAnalyzedPostponedArguments(topLevelPrimitive: ResolvedAtom): List<PostponedResolvedAtom> {
|
||||
fun ResolvedAtom.process(to: MutableList<PostponedResolvedAtom>) {
|
||||
to.addIfNotNull(this.safeAs<PostponedResolvedAtom>()?.takeUnless { it.analyzed })
|
||||
|
||||
if (analyzed) {
|
||||
subResolvedAtoms.forEach { it.process(to) }
|
||||
}
|
||||
}
|
||||
return arrayListOf<PostponedResolvedAtom>().apply { topLevelPrimitive.process(this) }
|
||||
}
|
||||
|
||||
private fun getOrderedAllTypeVariables(c: Context, topLevelPrimitive: ResolvedAtom) : List<TypeConstructor> {
|
||||
fun ResolvedAtom.process(to: MutableList<TypeConstructor>) {
|
||||
val typeVariables = when (this) {
|
||||
is ResolvedCallAtom -> substitutor.freshVariables
|
||||
is ResolvedCallableReferenceAtom -> candidate?.freshSubstitutor?.freshVariables.orEmpty()
|
||||
is ResolvedLambdaAtom -> listOfNotNull(typeVariableForLambdaReturnType)
|
||||
else -> emptyList()
|
||||
}
|
||||
typeVariables.mapNotNullTo(to) {
|
||||
val typeConstructor = it.freshTypeConstructor
|
||||
typeConstructor.takeIf { c.notFixedTypeVariables.containsKey(typeConstructor) }
|
||||
}
|
||||
|
||||
if (analyzed) {
|
||||
subResolvedAtoms.forEach { it.process(to) }
|
||||
}
|
||||
}
|
||||
val result = arrayListOf<TypeConstructor>().apply { topLevelPrimitive.process(this) }
|
||||
|
||||
assert(result.size == c.notFixedTypeVariables.size) {
|
||||
val notFoundTypeVariables = c.notFixedTypeVariables.keys.toMutableSet().removeAll(result)
|
||||
"Not all type variables found: $notFoundTypeVariables"
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
|
||||
private fun canWeAnalyzeIt(c: Context, argument: PostponedResolvedAtom): Boolean {
|
||||
if (argument.analyzed) return false
|
||||
|
||||
return argument.inputTypes.all { c.canBeProper(it) }
|
||||
}
|
||||
|
||||
private fun fixVariable(
|
||||
c: Context,
|
||||
topLevelType: UnwrappedType,
|
||||
variableWithConstraints: VariableWithConstraints,
|
||||
postponedResolveKtPrimitives: List<PostponedResolvedAtom>
|
||||
) {
|
||||
val direction = TypeVariableDirectionCalculator(c, postponedResolveKtPrimitives, topLevelType).getDirection(variableWithConstraints)
|
||||
|
||||
val resultType = resultTypeResolver.findResultType(c, variableWithConstraints, direction)
|
||||
|
||||
c.fixVariable(variableWithConstraints.typeVariable, resultType)
|
||||
}
|
||||
}
|
||||
@@ -150,4 +150,8 @@ class FreshVariableNewTypeSubstitutor(val freshVariables: List<TypeVariableFromC
|
||||
|
||||
return typeVariable.defaultType
|
||||
}
|
||||
|
||||
companion object {
|
||||
val Empty = FreshVariableNewTypeSubstitutor(emptyList())
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,7 @@
|
||||
package org.jetbrains.kotlin.resolve.calls.inference.components
|
||||
|
||||
import org.jetbrains.kotlin.resolve.calls.NewCommonSuperTypeCalculator
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.components.FixationOrderCalculator.ResolveDirection
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.components.TypeVariableDirectionCalculator.ResolveDirection
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintKind
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.VariableWithConstraints
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.checkConstraint
|
||||
@@ -33,7 +33,16 @@ class ResultTypeResolver(
|
||||
fun isProperType(type: UnwrappedType): Boolean
|
||||
}
|
||||
|
||||
fun findResultType(c: Context, variableWithConstraints: VariableWithConstraints, direction: ResolveDirection): UnwrappedType? {
|
||||
fun findResultType(c: Context, variableWithConstraints: VariableWithConstraints, direction: ResolveDirection): UnwrappedType {
|
||||
findResultTypeOrNull(c, variableWithConstraints, direction)?.let { return it }
|
||||
|
||||
// no proper constraints
|
||||
return variableWithConstraints.typeVariable.freshTypeConstructor.builtIns.run {
|
||||
if (direction == ResolveDirection.TO_SUBTYPE) nothingType else nullableAnyType
|
||||
}
|
||||
}
|
||||
|
||||
fun findResultTypeOrNull(c: Context, variableWithConstraints: VariableWithConstraints, direction: ResolveDirection): UnwrappedType? {
|
||||
findResultIfThereIsEqualsConstraint(c, variableWithConstraints, allowedFixToNotProperType = false)?.let { return it }
|
||||
|
||||
val subType = findSubType(c, variableWithConstraints)
|
||||
@@ -45,12 +54,7 @@ class ResultTypeResolver(
|
||||
c.resultType(superType, subType, variableWithConstraints)
|
||||
}
|
||||
|
||||
if (result != null) return result
|
||||
|
||||
// no proper constraints
|
||||
return variableWithConstraints.typeVariable.freshTypeConstructor.builtIns.run {
|
||||
if (direction == ResolveDirection.TO_SUBTYPE) nothingType else nullableAnyType
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
private fun Context.resultType(
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.resolve.calls.inference.components
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.NewConstraintSystemImpl
|
||||
@@ -29,8 +30,8 @@ import org.jetbrains.kotlin.types.UnwrappedType
|
||||
import org.jetbrains.kotlin.types.typeUtil.asTypeProjection
|
||||
|
||||
|
||||
class SimpleConstraintSystemImpl(constraintInjector: ConstraintInjector, resultTypeResolver: ResultTypeResolver) : SimpleConstraintSystem {
|
||||
val csBuilder: ConstraintSystemBuilder = NewConstraintSystemImpl(constraintInjector, resultTypeResolver).getBuilder()
|
||||
class SimpleConstraintSystemImpl(constraintInjector: ConstraintInjector, builtIns: KotlinBuiltIns) : SimpleConstraintSystem {
|
||||
val csBuilder: ConstraintSystemBuilder = NewConstraintSystemImpl(constraintInjector, builtIns).getBuilder()
|
||||
|
||||
override fun registerTypeVariables(typeParameters: Collection<TypeParameterDescriptor>): TypeSubstitutor {
|
||||
val substitutionMap = typeParameters.associate {
|
||||
|
||||
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.checker.*
|
||||
import org.jetbrains.kotlin.types.typeUtil.builtIns
|
||||
import org.jetbrains.kotlin.types.typeUtil.contains
|
||||
import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
|
||||
|
||||
abstract class TypeCheckerContextForConstraintSystem : TypeCheckerContext(errorTypeEqualsToAnything = true, allowedTypeVariable = false) {
|
||||
|
||||
@@ -59,21 +60,28 @@ abstract class TypeCheckerContextForConstraintSystem : TypeCheckerContext(errorT
|
||||
}
|
||||
|
||||
/**
|
||||
* Previous idea was to replace flexible types with intersection types:
|
||||
* 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.isFlexible()) {
|
||||
val subtypeAsFlexible = typeVariable.getCustomTypeVariable()?.substitutionResult(subType)?.unwrap()
|
||||
if (subtypeAsFlexible != null) {
|
||||
addLowerConstraint(typeVariable.constructor, subtypeAsFlexible)
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
if (typeVariable.isMarkedNullable) {
|
||||
addLowerConstraint(typeVariable.constructor, intersectTypes(listOf(subType, subType.builtIns.anyType)))
|
||||
}
|
||||
else {
|
||||
addLowerConstraint(typeVariable.constructor, subType)
|
||||
val notNullSubType = subType.makeNotNullable().unwrap()
|
||||
addLowerConstraint(typeVariable.constructor, notNullSubType)
|
||||
return true
|
||||
}
|
||||
|
||||
addLowerConstraint(typeVariable.constructor, subType)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* 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.inference.components
|
||||
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.VariableWithConstraints
|
||||
import org.jetbrains.kotlin.resolve.calls.model.PostponedResolvedAtom
|
||||
import org.jetbrains.kotlin.types.TypeConstructor
|
||||
import org.jetbrains.kotlin.types.UnwrappedType
|
||||
import org.jetbrains.kotlin.types.typeUtil.contains
|
||||
import org.jetbrains.kotlin.utils.SmartSet
|
||||
|
||||
class TypeVariableDependencyInformationProvider(
|
||||
private val notFixedTypeVariables: Map<TypeConstructor, VariableWithConstraints>,
|
||||
private val postponedKtPrimitives: List<PostponedResolvedAtom>,
|
||||
private val topLevelType: UnwrappedType?
|
||||
) {
|
||||
// not oriented edges
|
||||
private val constrainEdges: MutableMap<TypeConstructor, MutableSet<TypeConstructor>> = hashMapOf()
|
||||
|
||||
// oriented edges
|
||||
private val postponeArgumentsEdges: MutableMap<TypeConstructor, MutableSet<TypeConstructor>> = hashMapOf()
|
||||
|
||||
private val relatedToAllOutputTypes: MutableSet<TypeConstructor> = hashSetOf()
|
||||
private val relatedToTopLevelType: MutableSet<TypeConstructor> = hashSetOf()
|
||||
|
||||
init {
|
||||
computeConstraintEdges()
|
||||
computePostponeArgumentsEdges()
|
||||
computeRelatedToAllOutputTypes()
|
||||
computeRelatedToTopLevelType()
|
||||
}
|
||||
|
||||
fun isVariableRelatedToTopLevelType(variable: TypeConstructor) = relatedToTopLevelType.contains(variable)
|
||||
fun isVariableRelatedToAnyOutputType(variable: TypeConstructor) = relatedToAllOutputTypes.contains(variable)
|
||||
|
||||
private fun computeConstraintEdges() {
|
||||
fun addConstraintEdge(from: TypeConstructor, to: TypeConstructor) {
|
||||
constrainEdges.getOrPut(from) { hashSetOf() }.add(to)
|
||||
constrainEdges.getOrPut(to) { hashSetOf() }.add(from)
|
||||
}
|
||||
|
||||
for (variableWithConstraints in notFixedTypeVariables.values) {
|
||||
val from = variableWithConstraints.typeVariable.freshTypeConstructor
|
||||
|
||||
for (constraint in variableWithConstraints.constraints) {
|
||||
constraint.type.forAllMyTypeVariables {
|
||||
if (isMyTypeVariable(it)) {
|
||||
addConstraintEdge(from, it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun computePostponeArgumentsEdges() {
|
||||
fun addPostponeArgumentsEdges(from: TypeConstructor, to: TypeConstructor) {
|
||||
postponeArgumentsEdges.getOrPut(from) { hashSetOf() }.add(to)
|
||||
}
|
||||
|
||||
for (argument in postponedKtPrimitives) {
|
||||
if (argument.analyzed) continue
|
||||
|
||||
val typeVariablesInOutputType = SmartSet.create<TypeConstructor>()
|
||||
(argument.outputType ?: continue).forAllMyTypeVariables { typeVariablesInOutputType.add(it) }
|
||||
if (typeVariablesInOutputType.isEmpty()) continue
|
||||
|
||||
for (inputType in argument.inputTypes) {
|
||||
inputType.forAllMyTypeVariables { from ->
|
||||
for (to in typeVariablesInOutputType) {
|
||||
addPostponeArgumentsEdges(from, to)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun computeRelatedToAllOutputTypes() {
|
||||
for (argument in postponedKtPrimitives) {
|
||||
if (argument.analyzed) continue
|
||||
(argument.outputType ?: continue).forAllMyTypeVariables {
|
||||
addAllRelatedNodes(relatedToAllOutputTypes, it, includePostponedEdges = false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun computeRelatedToTopLevelType() {
|
||||
if (topLevelType == null) return
|
||||
topLevelType.forAllMyTypeVariables {
|
||||
addAllRelatedNodes(relatedToTopLevelType, it, includePostponedEdges = true)
|
||||
}
|
||||
}
|
||||
|
||||
private fun isMyTypeVariable(typeConstructor: TypeConstructor) = notFixedTypeVariables.containsKey(typeConstructor)
|
||||
|
||||
private fun UnwrappedType.forAllMyTypeVariables(action: (TypeConstructor) -> Unit) = this.contains {
|
||||
if (isMyTypeVariable(it.constructor)) action(it.constructor)
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
private fun getConstraintEdges(from: TypeConstructor): Set<TypeConstructor> = constrainEdges[from] ?: emptySet()
|
||||
private fun getPostponeEdges(from: TypeConstructor): Set<TypeConstructor> = postponeArgumentsEdges[from] ?: emptySet()
|
||||
|
||||
private fun addAllRelatedNodes(to: MutableSet<TypeConstructor>, node: TypeConstructor, includePostponedEdges: Boolean) {
|
||||
if (to.add(node)) {
|
||||
for (relatedNode in getConstraintEdges(node)) {
|
||||
addAllRelatedNodes(to, relatedNode, includePostponedEdges)
|
||||
}
|
||||
if (includePostponedEdges) {
|
||||
for (relatedNode in getPostponeEdges(node)) {
|
||||
addAllRelatedNodes(to, relatedNode, includePostponedEdges)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
* 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.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.VariableWithConstraints
|
||||
import org.jetbrains.kotlin.resolve.calls.model.PostponedResolvedAtom
|
||||
import org.jetbrains.kotlin.types.FlexibleType
|
||||
import org.jetbrains.kotlin.types.SimpleType
|
||||
import org.jetbrains.kotlin.types.UnwrappedType
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import org.jetbrains.kotlin.types.checker.NewKotlinTypeChecker
|
||||
import org.jetbrains.kotlin.types.checker.isIntersectionType
|
||||
import org.jetbrains.kotlin.utils.SmartList
|
||||
|
||||
|
||||
private typealias Variable = VariableWithConstraints
|
||||
|
||||
class TypeVariableDirectionCalculator(
|
||||
private val c: VariableFixationFinder.Context,
|
||||
private val postponedKtPrimitives: List<PostponedResolvedAtom>,
|
||||
topLevelType: UnwrappedType
|
||||
) {
|
||||
enum class ResolveDirection {
|
||||
TO_SUBTYPE,
|
||||
TO_SUPERTYPE,
|
||||
UNKNOWN
|
||||
}
|
||||
|
||||
data class NodeWithDirection(val variableWithConstraints: VariableWithConstraints, val direction: ResolveDirection) {
|
||||
override fun toString() = "$variableWithConstraints to $direction"
|
||||
}
|
||||
|
||||
private val directions = HashMap<Variable, ResolveDirection>()
|
||||
|
||||
init {
|
||||
setupDirections(topLevelType)
|
||||
}
|
||||
|
||||
fun getDirection(typeVariable: Variable): ResolveDirection =
|
||||
directions.getOrDefault(typeVariable, ResolveDirection.UNKNOWN)
|
||||
|
||||
private fun setupDirections(topReturnType: UnwrappedType) {
|
||||
topReturnType.visitType(ResolveDirection.TO_SUBTYPE) { variableWithConstraints, direction ->
|
||||
enterToNode(variableWithConstraints, direction)
|
||||
}
|
||||
for (postponedArgument in postponedKtPrimitives) {
|
||||
for (inputType in postponedArgument.inputTypes) {
|
||||
inputType.visitType(ResolveDirection.TO_SUBTYPE) { variableWithConstraints, direction ->
|
||||
enterToNode(variableWithConstraints, direction)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 getConstraintDependencies(variable, direction)) {
|
||||
enterToNode(otherVariable, otherDirection)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getConstraintDependencies(
|
||||
variable: Variable,
|
||||
direction: ResolveDirection
|
||||
): List<NodeWithDirection> =
|
||||
SmartList<NodeWithDirection>().also { result ->
|
||||
for (constraint in variable.constraints) {
|
||||
if (!isInterestingConstraint(direction, constraint)) continue
|
||||
|
||||
constraint.type.visitType(direction) { nodeVariable, nodeDirection ->
|
||||
result.add(NodeWithDirection(nodeVariable, nodeDirection))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun isInterestingConstraint(direction: ResolveDirection, constraint: Constraint): Boolean =
|
||||
!(direction == ResolveDirection.TO_SUBTYPE && constraint.kind == ConstraintKind.UPPER) &&
|
||||
!(direction == ResolveDirection.TO_SUPERTYPE && constraint.kind == ConstraintKind.LOWER)
|
||||
|
||||
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
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
private fun ResolveDirection.opposite() = when (this) {
|
||||
ResolveDirection.UNKNOWN -> ResolveDirection.UNKNOWN
|
||||
ResolveDirection.TO_SUPERTYPE -> ResolveDirection.TO_SUBTYPE
|
||||
ResolveDirection.TO_SUBTYPE -> ResolveDirection.TO_SUPERTYPE
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* 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.inference.components
|
||||
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.components.KotlinConstraintSystemCompleter.ConstraintSystemCompletionMode
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.components.KotlinConstraintSystemCompleter.ConstraintSystemCompletionMode.PARTIAL
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.Constraint
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.DeclaredUpperBoundConstraintPosition
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.VariableWithConstraints
|
||||
import org.jetbrains.kotlin.resolve.calls.model.PostponedResolvedAtom
|
||||
import org.jetbrains.kotlin.types.TypeConstructor
|
||||
import org.jetbrains.kotlin.types.UnwrappedType
|
||||
import org.jetbrains.kotlin.types.typeUtil.contains
|
||||
|
||||
class VariableFixationFinder {
|
||||
interface Context {
|
||||
val notFixedTypeVariables: Map<TypeConstructor, VariableWithConstraints>
|
||||
}
|
||||
|
||||
data class VariableForFixation(val variable: TypeConstructor, val hasProperConstraint: Boolean)
|
||||
|
||||
fun findFirstVariableForFixation(
|
||||
c: Context,
|
||||
allTypeVariables: List<TypeConstructor>,
|
||||
postponedKtPrimitives: List<PostponedResolvedAtom>,
|
||||
completionMode: ConstraintSystemCompletionMode,
|
||||
topLevelType: UnwrappedType
|
||||
): VariableForFixation? = c.findTypeVariableForFixation(allTypeVariables, postponedKtPrimitives, completionMode, topLevelType)
|
||||
|
||||
private enum class TypeVariableFixationReadiness {
|
||||
FORBIDDEN,
|
||||
WITHOUT_PROPER_ARGUMENT_CONSTRAINT, // proper constraint from arguments -- not from upper bound for type parameters
|
||||
RELATED_TO_ANY_OUTPUT_TYPE,
|
||||
WITH_COMPLEX_DEPENDENCY, // if type variable T has constraint with non fixed type variable inside (non-top-level): T <: Foo<S>
|
||||
READY_FOR_FIXATION,
|
||||
}
|
||||
|
||||
private fun Context.getTypeVariableReadiness(
|
||||
variable: TypeConstructor,
|
||||
dependencyProvider: TypeVariableDependencyInformationProvider
|
||||
): TypeVariableFixationReadiness = when {
|
||||
!notFixedTypeVariables.contains(variable) ||
|
||||
dependencyProvider.isVariableRelatedToTopLevelType(variable) -> TypeVariableFixationReadiness.FORBIDDEN
|
||||
!variableHasProperArgumentConstraints(variable) -> TypeVariableFixationReadiness.WITHOUT_PROPER_ARGUMENT_CONSTRAINT
|
||||
dependencyProvider.isVariableRelatedToAnyOutputType(variable) -> TypeVariableFixationReadiness.RELATED_TO_ANY_OUTPUT_TYPE
|
||||
hasDependencyToOtherTypeVariables(variable) -> TypeVariableFixationReadiness.WITH_COMPLEX_DEPENDENCY
|
||||
else -> TypeVariableFixationReadiness.READY_FOR_FIXATION
|
||||
}
|
||||
|
||||
private fun Context.findTypeVariableForFixation(
|
||||
allTypeVariables: List<TypeConstructor>,
|
||||
postponedKtPrimitives: List<PostponedResolvedAtom>,
|
||||
completionMode: ConstraintSystemCompletionMode,
|
||||
topLevelType: UnwrappedType
|
||||
): VariableForFixation? {
|
||||
val dependencyProvider = TypeVariableDependencyInformationProvider(notFixedTypeVariables, postponedKtPrimitives,
|
||||
topLevelType.takeIf { completionMode == PARTIAL })
|
||||
|
||||
val candidate = allTypeVariables.maxBy { getTypeVariableReadiness(it, dependencyProvider) } ?: return null
|
||||
val candidateReadiness = getTypeVariableReadiness(candidate, dependencyProvider)
|
||||
return when (candidateReadiness) {
|
||||
TypeVariableFixationReadiness.FORBIDDEN -> null
|
||||
TypeVariableFixationReadiness.WITHOUT_PROPER_ARGUMENT_CONSTRAINT -> VariableForFixation(candidate, false)
|
||||
else -> VariableForFixation(candidate, true)
|
||||
}
|
||||
}
|
||||
|
||||
private fun Context.hasDependencyToOtherTypeVariables(typeVariable: TypeConstructor): Boolean {
|
||||
for (constraint in notFixedTypeVariables[typeVariable]?.constraints ?: return false) {
|
||||
if (constraint.type.arguments.isNotEmpty() && constraint.type.contains { notFixedTypeVariables.containsKey(it.constructor) }) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private fun Context.variableHasProperArgumentConstraints(variable: TypeConstructor): Boolean =
|
||||
notFixedTypeVariables[variable]?.constraints?.any { isProperArgumentConstraint(it) } ?: false
|
||||
|
||||
private fun Context.isProperArgumentConstraint(c: Constraint) =
|
||||
isProperType(c.type) && c.position.initialConstraint.position !is DeclaredUpperBoundConstraintPosition
|
||||
|
||||
private fun Context.isProperType(type: UnwrappedType): Boolean =
|
||||
!type.contains { notFixedTypeVariables.containsKey(it.constructor) }
|
||||
|
||||
}
|
||||
@@ -50,9 +50,9 @@ class FixVariableConstraintPosition(val variable: NewTypeVariable) : ConstraintP
|
||||
class KnownTypeParameterConstraintPosition(val typeArgument: KotlinType) : ConstraintPosition() {
|
||||
override fun toString() = "TypeArgument $typeArgument"
|
||||
}
|
||||
class LambdaArgumentConstraintPosition(val lambdaArgument: PostponedLambdaArgument) : ConstraintPosition() {
|
||||
class LambdaArgumentConstraintPosition(val lambda: ResolvedLambdaAtom) : ConstraintPosition() {
|
||||
override fun toString(): String {
|
||||
return "LambdaArgument $lambdaArgument"
|
||||
return "LambdaArgument $lambda"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -52,8 +52,6 @@ interface ConstraintStorage {
|
||||
val maxTypeDepthFromInitialConstraints: Int
|
||||
val errors: List<KotlinCallDiagnostic>
|
||||
val fixedTypeVariables: Map<TypeConstructor, UnwrappedType>
|
||||
val postponedArguments: List<PostponedKotlinCallArgument>
|
||||
val innerCalls: List<ResolvedKotlinCall.OnlyResolvedKotlinCall>
|
||||
|
||||
object Empty : ConstraintStorage {
|
||||
override val allTypeVariables: Map<TypeConstructor, NewTypeVariable> get() = emptyMap()
|
||||
@@ -62,8 +60,6 @@ interface ConstraintStorage {
|
||||
override val maxTypeDepthFromInitialConstraints: Int get() = 1
|
||||
override val errors: List<KotlinCallDiagnostic> get() = emptyList()
|
||||
override val fixedTypeVariables: Map<TypeConstructor, UnwrappedType> get() = emptyMap()
|
||||
override val postponedArguments: List<PostponedKotlinCallArgument> get() = emptyList()
|
||||
override val innerCalls: List<ResolvedKotlinCall.OnlyResolvedKotlinCall> get() = emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,8 +18,6 @@ package org.jetbrains.kotlin.resolve.calls.inference.model
|
||||
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.trimToSize
|
||||
import org.jetbrains.kotlin.resolve.calls.model.KotlinCallDiagnostic
|
||||
import org.jetbrains.kotlin.resolve.calls.model.PostponedKotlinCallArgument
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedKotlinCall
|
||||
import org.jetbrains.kotlin.types.TypeConstructor
|
||||
import org.jetbrains.kotlin.types.UnwrappedType
|
||||
import java.util.*
|
||||
@@ -105,6 +103,4 @@ internal class MutableConstraintStorage : ConstraintStorage {
|
||||
override var maxTypeDepthFromInitialConstraints: Int = 1
|
||||
override val errors: MutableList<KotlinCallDiagnostic> = ArrayList()
|
||||
override val fixedTypeVariables: MutableMap<TypeConstructor, UnwrappedType> = LinkedHashMap()
|
||||
override val postponedArguments: MutableList<PostponedKotlinCallArgument> = ArrayList()
|
||||
override val innerCalls: MutableList<ResolvedKotlinCall.OnlyResolvedKotlinCall> = ArrayList()
|
||||
}
|
||||
@@ -16,25 +16,30 @@
|
||||
|
||||
package org.jetbrains.kotlin.resolve.calls.inference.model
|
||||
|
||||
import org.jetbrains.kotlin.resolve.calls.components.KotlinCallCompleter
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.resolve.calls.components.PostponedArgumentsAnalyzer
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.*
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.components.*
|
||||
import org.jetbrains.kotlin.resolve.calls.model.*
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.components.ConstraintInjector
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.components.KotlinConstraintSystemCompleter
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.components.NewTypeSubstitutor
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.components.ResultTypeResolver
|
||||
import org.jetbrains.kotlin.resolve.calls.model.KotlinCallDiagnostic
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.isSuccess
|
||||
import org.jetbrains.kotlin.types.ErrorUtils
|
||||
import org.jetbrains.kotlin.types.TypeConstructor
|
||||
import org.jetbrains.kotlin.types.UnwrappedType
|
||||
import org.jetbrains.kotlin.types.typeUtil.contains
|
||||
import org.jetbrains.kotlin.utils.SmartList
|
||||
import java.util.*
|
||||
|
||||
class NewConstraintSystemImpl(val constraintInjector: ConstraintInjector, val resultTypeResolver: ResultTypeResolver):
|
||||
class NewConstraintSystemImpl(
|
||||
private val constraintInjector: ConstraintInjector,
|
||||
override val builtIns: KotlinBuiltIns
|
||||
):
|
||||
NewConstraintSystem,
|
||||
ConstraintSystemBuilder,
|
||||
ConstraintInjector.Context,
|
||||
ResultTypeResolver.Context,
|
||||
KotlinCallCompleter.Context,
|
||||
FixationOrderCalculator.Context
|
||||
KotlinConstraintSystemCompleter.Context,
|
||||
PostponedArgumentsAnalyzer.Context
|
||||
{
|
||||
private val storage = MutableConstraintStorage()
|
||||
private var state = State.BUILDING
|
||||
@@ -58,19 +63,15 @@ class NewConstraintSystemImpl(val constraintInjector: ConstraintInjector, val re
|
||||
|
||||
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
|
||||
}
|
||||
override fun asConstraintSystemCompleterContext() = apply { checkState(State.BUILDING) }
|
||||
|
||||
override fun asPostponedArgumentsAnalyzerContext() = apply { checkState(State.BUILDING) }
|
||||
|
||||
// ConstraintSystemOperation
|
||||
override fun registerVariable(variable: NewTypeVariable) {
|
||||
@@ -97,6 +98,16 @@ class NewConstraintSystemImpl(val constraintInjector: ConstraintInjector, val re
|
||||
}
|
||||
}
|
||||
|
||||
override fun getProperSubTypeBounds(type: UnwrappedType): List<UnwrappedType> {
|
||||
checkState(State.BUILDING, State.COMPLETION, State.TRANSACTION)
|
||||
val variableWithConstraints = notFixedTypeVariables[type.constructor] ?: return emptyList()
|
||||
|
||||
return variableWithConstraints.constraints.mapNotNull { constraint ->
|
||||
if (constraint.kind == ConstraintKind.UPPER) return@mapNotNull null
|
||||
constraint.type.takeUnless { !canBeProper(it) }
|
||||
}
|
||||
}
|
||||
|
||||
// ConstraintSystemBuilder
|
||||
private fun transactionRegisterVariable(variable: NewTypeVariable) {
|
||||
if (state != State.TRANSACTION) return
|
||||
@@ -143,50 +154,11 @@ class NewConstraintSystemImpl(val constraintInjector: ConstraintInjector, val re
|
||||
return false
|
||||
}
|
||||
|
||||
override fun addPostponedArgument(postponedArgument: PostponedKotlinCallArgument) {
|
||||
checkState(State.BUILDING, State.COMPLETION)
|
||||
storage.postponedArguments.add(postponedArgument)
|
||||
}
|
||||
|
||||
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(): NewTypeSubstitutor {
|
||||
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
|
||||
// ConstraintSystemBuilder, KotlinConstraintSystemCompleter.Context
|
||||
override val hasContradiction: Boolean
|
||||
get() = diagnostics.any { !it.candidateApplicability.isSuccess }.apply { checkState(State.BUILDING, State.COMPLETION, State.TRANSACTION) }
|
||||
get() = diagnostics.any { !it.candidateApplicability.isSuccess }.apply { checkState(State.FREEZED, State.BUILDING, State.COMPLETION, State.TRANSACTION) }
|
||||
|
||||
override fun addInnerCall(innerCall: ResolvedKotlinCall.OnlyResolvedKotlinCall) {
|
||||
checkState(State.BUILDING, State.COMPLETION)
|
||||
storage.innerCalls.add(innerCall)
|
||||
|
||||
val otherSystem = innerCall.candidate.lastCall.constraintSystem.asReadOnlyStorage()
|
||||
override fun addOtherSystem(otherSystem: ConstraintStorage) {
|
||||
storage.allTypeVariables.putAll(otherSystem.allTypeVariables)
|
||||
for ((variable, constraints) in otherSystem.notFixedTypeVariables) {
|
||||
notFixedTypeVariables[variable] = MutableVariableWithConstraints(constraints.typeVariable, constraints.constraints)
|
||||
@@ -195,11 +167,8 @@ class NewConstraintSystemImpl(val constraintInjector: ConstraintInjector, val re
|
||||
storage.maxTypeDepthFromInitialConstraints = Math.max(storage.maxTypeDepthFromInitialConstraints, otherSystem.maxTypeDepthFromInitialConstraints)
|
||||
storage.errors.addAll(otherSystem.errors)
|
||||
storage.fixedTypeVariables.putAll(otherSystem.fixedTypeVariables)
|
||||
storage.postponedArguments.addAll(otherSystem.postponedArguments)
|
||||
storage.innerCalls.addAll(otherSystem.innerCalls)
|
||||
}
|
||||
|
||||
|
||||
// ResultTypeResolver.Context, ConstraintSystemBuilder
|
||||
override fun isProperType(type: UnwrappedType): Boolean {
|
||||
checkState(State.BUILDING, State.COMPLETION, State.TRANSACTION)
|
||||
@@ -208,6 +177,11 @@ class NewConstraintSystemImpl(val constraintInjector: ConstraintInjector, val re
|
||||
}
|
||||
}
|
||||
|
||||
override fun isTypeVariable(type: UnwrappedType): Boolean {
|
||||
checkState(State.BUILDING, State.COMPLETION, State.TRANSACTION)
|
||||
return notFixedTypeVariables.containsKey(type.constructor)
|
||||
}
|
||||
|
||||
// ConstraintInjector.Context
|
||||
override val allTypeVariables: Map<TypeConstructor, NewTypeVariable> get() {
|
||||
checkState(State.BUILDING, State.COMPLETION, State.TRANSACTION)
|
||||
@@ -232,27 +206,13 @@ class NewConstraintSystemImpl(val constraintInjector: ConstraintInjector, val re
|
||||
return storage.notFixedTypeVariables
|
||||
}
|
||||
|
||||
// ConstraintInjector.Context, KotlinCallCompleter.Context
|
||||
// ConstraintInjector.Context, KotlinConstraintSystemCompleter.Context
|
||||
override fun addError(error: KotlinCallDiagnostic) {
|
||||
checkState(State.BUILDING, State.COMPLETION, State.TRANSACTION)
|
||||
storage.errors.add(error)
|
||||
}
|
||||
|
||||
// KotlinCallCompleter.Context, FixationOrderCalculator.Context
|
||||
override val lambdaArguments: List<PostponedLambdaArgument> get() {
|
||||
checkState(State.COMPLETION)
|
||||
return storage.postponedArguments.filterIsInstance<PostponedLambdaArgument>()
|
||||
}
|
||||
|
||||
// FixationOrderCalculator.Context
|
||||
override val postponedArguments: List<PostponedKotlinCallArgument>
|
||||
get() = storage.postponedArguments
|
||||
|
||||
// KotlinCallCompleter.Context
|
||||
override fun asResultTypeResolverContext() = apply { checkState(State.COMPLETION) }
|
||||
|
||||
override fun asFixationOrderCalculatorContext() = apply { checkState(State.COMPLETION) }
|
||||
|
||||
// KotlinConstraintSystemCompleter.Context
|
||||
override fun fixVariable(variable: NewTypeVariable, resultType: UnwrappedType) {
|
||||
checkState(State.BUILDING, State.COMPLETION)
|
||||
|
||||
@@ -268,30 +228,15 @@ class NewConstraintSystemImpl(val constraintInjector: ConstraintInjector, val re
|
||||
storage.fixedTypeVariables[variable.freshTypeConstructor] = resultType
|
||||
}
|
||||
|
||||
override val innerCalls: List<ResolvedKotlinCall.OnlyResolvedKotlinCall> get() {
|
||||
checkState(State.COMPLETION)
|
||||
return storage.innerCalls
|
||||
}
|
||||
|
||||
// KotlinConstraintSystemCompleter.Context, PostponedArgumentsAnalyzer.Context
|
||||
override fun canBeProper(type: UnwrappedType): Boolean {
|
||||
checkState(State.COMPLETION)
|
||||
checkState(State.BUILDING, State.COMPLETION)
|
||||
return !type.contains { storage.notFixedTypeVariables.containsKey(it.constructor) }
|
||||
}
|
||||
|
||||
// PostponedArgumentsAnalyzer.Context
|
||||
override fun buildCurrentSubstitutor(): NewTypeSubstitutor {
|
||||
checkState(State.COMPLETION)
|
||||
checkState(State.BUILDING, State.COMPLETION)
|
||||
return storage.buildCurrentSubstitutor()
|
||||
}
|
||||
|
||||
override fun buildResultingSubstitutor(): NewTypeSubstitutor {
|
||||
checkState(State.COMPLETION)
|
||||
val currentSubstitutorMap = storage.fixedTypeVariables.entries.associate {
|
||||
it.key to it.value
|
||||
}
|
||||
val uninferredSubstitutorMap = storage.notFixedTypeVariables.entries.associate { (freshTypeConstructor, typeVariable) ->
|
||||
freshTypeConstructor to ErrorUtils.createErrorTypeWithCustomConstructor("Uninferred type", typeVariable.typeVariable.freshTypeConstructor)
|
||||
}
|
||||
|
||||
return NewTypeSubstitutorByConstructorMap(currentSubstitutorMap + uninferredSubstitutorMap)
|
||||
}
|
||||
}
|
||||
@@ -20,11 +20,12 @@ 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.resolve.scopes.MemberScope
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.KotlinTypeFactory
|
||||
import org.jetbrains.kotlin.types.SimpleType
|
||||
import org.jetbrains.kotlin.types.TypeConstructor
|
||||
import org.jetbrains.kotlin.types.checker.NewTypeVariableConstructor
|
||||
|
||||
|
||||
@@ -53,8 +54,7 @@ sealed class NewTypeVariable(builtIns: KotlinBuiltIns, name: String) {
|
||||
}
|
||||
|
||||
class TypeVariableFromCallableDescriptor(
|
||||
val originalTypeParameter: TypeParameterDescriptor,
|
||||
val call: KotlinCall? = null
|
||||
val originalTypeParameter: TypeParameterDescriptor
|
||||
) : NewTypeVariable(originalTypeParameter.builtIns, originalTypeParameter.name.identifier)
|
||||
|
||||
class TypeVariableForLambdaReturnType(
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
* 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.
|
||||
@@ -17,15 +17,16 @@
|
||||
package org.jetbrains.kotlin.resolve.calls.model
|
||||
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
|
||||
interface KotlinCall {
|
||||
interface KotlinCall : ResolutionAtom {
|
||||
val callKind: KotlinCallKind
|
||||
|
||||
val explicitReceiver: ReceiverKotlinCallArgument?
|
||||
|
||||
// a.(foo)() -- (foo) is dispatchReceiverForInvoke
|
||||
val dispatchReceiverForInvokeExtension: SimpleKotlinCallArgument? get() = null
|
||||
val dispatchReceiverForInvokeExtension: ReceiverKotlinCallArgument? get() = null
|
||||
|
||||
val name: Name
|
||||
|
||||
@@ -43,6 +44,18 @@ private fun SimpleKotlinCallArgument.checkReceiverInvariants() {
|
||||
assert(argumentName == null) {
|
||||
"Argument name should be null for receiver: $this, but it is $argumentName"
|
||||
}
|
||||
checkArgumentInvariants()
|
||||
}
|
||||
|
||||
private fun KotlinCallArgument.checkArgumentInvariants() {
|
||||
if (this is SubKotlinCallArgument) {
|
||||
assert(callResult.type == CallResolutionResult.Type.PARTIAL) {
|
||||
"SubCall should has type PARTIAL: $callResult"
|
||||
}
|
||||
assert(callResult.resultCallAtom != null) {
|
||||
"SubCall should has resultCallAtom: $callResult"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun KotlinCall.checkCallInvariants() {
|
||||
@@ -50,8 +63,10 @@ fun KotlinCall.checkCallInvariants() {
|
||||
"Lambda argument or callable reference is not allowed as explicit receiver: $explicitReceiver"
|
||||
}
|
||||
|
||||
(explicitReceiver as? SimpleKotlinCallArgument)?.checkReceiverInvariants()
|
||||
dispatchReceiverForInvokeExtension?.checkReceiverInvariants()
|
||||
explicitReceiver.safeAs<SimpleKotlinCallArgument>()?.checkReceiverInvariants()
|
||||
dispatchReceiverForInvokeExtension.safeAs<SimpleKotlinCallArgument>()?.checkReceiverInvariants()
|
||||
argumentsInParenthesis.forEach(KotlinCallArgument::checkArgumentInvariants)
|
||||
externalArgument?.checkArgumentInvariants()
|
||||
|
||||
if (callKind != KotlinCallKind.FUNCTION) {
|
||||
assert(externalArgument == null) {
|
||||
|
||||
@@ -26,12 +26,19 @@ import org.jetbrains.kotlin.resolve.scopes.receivers.TransientReceiver
|
||||
import org.jetbrains.kotlin.types.UnwrappedType
|
||||
|
||||
|
||||
interface ReceiverKotlinCallArgument {
|
||||
interface ReceiverKotlinCallArgument : KotlinCallArgument {
|
||||
val receiver: DetailedReceiver
|
||||
val isSafeCall: Boolean
|
||||
}
|
||||
|
||||
class QualifierReceiverKotlinCallArgument(override val receiver: QualifierReceiver) : ReceiverKotlinCallArgument {
|
||||
override val isSafeCall: Boolean
|
||||
get() = false // TODO: add warning
|
||||
|
||||
override fun toString() = "$receiver"
|
||||
|
||||
override val isSpread get() = false
|
||||
override val argumentName: Name? get() = null
|
||||
}
|
||||
|
||||
interface KotlinCallArgument {
|
||||
@@ -39,18 +46,16 @@ interface KotlinCallArgument {
|
||||
val argumentName: Name?
|
||||
}
|
||||
|
||||
interface PostponableKotlinCallArgument : KotlinCallArgument
|
||||
interface PostponableKotlinCallArgument : KotlinCallArgument, ResolutionAtom
|
||||
|
||||
interface SimpleKotlinCallArgument : KotlinCallArgument, ReceiverKotlinCallArgument {
|
||||
override val receiver: ReceiverValueWithSmartCastInfo
|
||||
|
||||
val isSafeCall: Boolean
|
||||
}
|
||||
|
||||
interface ExpressionKotlinCallArgument : SimpleKotlinCallArgument
|
||||
interface ExpressionKotlinCallArgument : SimpleKotlinCallArgument, ResolutionAtom
|
||||
|
||||
interface SubKotlinCallArgument : SimpleKotlinCallArgument {
|
||||
val resolvedCall: ResolvedKotlinCall.OnlyResolvedKotlinCall
|
||||
val callResult: CallResolutionResult
|
||||
}
|
||||
|
||||
interface LambdaKotlinCallArgument : PostponableKotlinCallArgument {
|
||||
@@ -110,6 +115,8 @@ sealed class LHSResult {
|
||||
|
||||
// todo this case is forbid for now
|
||||
object Empty: LHSResult()
|
||||
|
||||
object Error: LHSResult()
|
||||
}
|
||||
|
||||
interface CallableReferenceKotlinCallArgument : PostponableKotlinCallArgument {
|
||||
|
||||
@@ -98,6 +98,15 @@ class CallableReferenceNotCompatible(
|
||||
val callableReverenceType: UnwrappedType
|
||||
) : InapplicableArgumentDiagnostic()
|
||||
|
||||
// supported by FE but not supported by BE now
|
||||
class CallableReferencesDefaultArgumentUsed(
|
||||
val argument: CallableReferenceKotlinCallArgument,
|
||||
val candidate: CallableDescriptor,
|
||||
val defaultsCount: Int
|
||||
) : KotlinCallDiagnostic(IMPOSSIBLE_TO_GENERATE) {
|
||||
override fun report(reporter: DiagnosticReporter) = reporter.onCallArgument(argument, this)
|
||||
}
|
||||
|
||||
class NotCallableMemberReference(
|
||||
override val argument: CallableReferenceKotlinCallArgument,
|
||||
val candidate: CallableDescriptor
|
||||
@@ -119,7 +128,8 @@ class NotCallableExpectedType(
|
||||
// SmartCasts
|
||||
class SmartCastDiagnostic(
|
||||
val argument: ExpressionKotlinCallArgument,
|
||||
val smartCastType: UnwrappedType
|
||||
val smartCastType: UnwrappedType,
|
||||
val kotlinCall: KotlinCall?
|
||||
): KotlinCallDiagnostic(RESOLVED) {
|
||||
override fun report(reporter: DiagnosticReporter) = reporter.onCallArgument(argument, this)
|
||||
}
|
||||
@@ -145,3 +155,19 @@ object AbstractSuperCall : KotlinCallDiagnostic(RUNTIME_ERROR) {
|
||||
reporter.onCall(this)
|
||||
}
|
||||
}
|
||||
|
||||
// candidates result
|
||||
class NoneCandidatesCallDiagnostic(val kotlinCall: KotlinCall) : KotlinCallDiagnostic(INAPPLICABLE) {
|
||||
override fun report(reporter: DiagnosticReporter) {
|
||||
reporter.onCall(this)
|
||||
}
|
||||
}
|
||||
|
||||
class ManyCandidatesCallDiagnostic(
|
||||
val kotlinCall: KotlinCall,
|
||||
val candidates: Collection<KotlinResolutionCandidate>
|
||||
) : KotlinCallDiagnostic(INAPPLICABLE) {
|
||||
override fun report(reporter: DiagnosticReporter) {
|
||||
reporter.onCall(this)
|
||||
}
|
||||
}
|
||||
@@ -16,11 +16,15 @@
|
||||
|
||||
package org.jetbrains.kotlin.resolve.calls.model
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.builtins.ReflectionTypes
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.resolve.calls.components.*
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.addSubsystemForArgument
|
||||
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.inference.model.NewConstraintSystemImpl
|
||||
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.*
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.hasDynamicExtensionAnnotation
|
||||
@@ -30,19 +34,33 @@ import org.jetbrains.kotlin.types.TypeSubstitutor
|
||||
import org.jetbrains.kotlin.types.isDynamic
|
||||
|
||||
|
||||
class KotlinCallContext(
|
||||
val scopeTower: ImplicitScopeTower,
|
||||
val resolutionCallbacks: KotlinResolutionCallbacks,
|
||||
val externalPredicates: KotlinResolutionExternalPredicates,
|
||||
class KotlinCallComponents(
|
||||
val statelessCallbacks: KotlinResolutionStatelessCallbacks,
|
||||
val argumentsToParametersMapper: ArgumentsToParametersMapper,
|
||||
val typeArgumentsToParametersMapper: TypeArgumentsToParametersMapper,
|
||||
val resultTypeResolver: ResultTypeResolver,
|
||||
val callableReferenceResolver: CallableReferenceResolver,
|
||||
val constraintInjector: ConstraintInjector,
|
||||
val reflectionTypes: ReflectionTypes
|
||||
val reflectionTypes: ReflectionTypes,
|
||||
val builtIns: KotlinBuiltIns
|
||||
)
|
||||
|
||||
class SimpleCandidateFactory(val callContext: KotlinCallContext, val kotlinCall: KotlinCall): CandidateFactory<SimpleKotlinResolutionCandidate> {
|
||||
class SimpleCandidateFactory(
|
||||
val callComponents: KotlinCallComponents,
|
||||
val scopeTower: ImplicitScopeTower,
|
||||
val kotlinCall: KotlinCall
|
||||
): CandidateFactory<KotlinResolutionCandidate> {
|
||||
val baseSystem: ConstraintStorage
|
||||
|
||||
init {
|
||||
val baseSystem = NewConstraintSystemImpl(callComponents.constraintInjector, callComponents.builtIns)
|
||||
baseSystem.addSubsystemForArgument(kotlinCall.explicitReceiver)
|
||||
baseSystem.addSubsystemForArgument(kotlinCall.dispatchReceiverForInvokeExtension)
|
||||
for (argument in kotlinCall.argumentsInParenthesis) {
|
||||
baseSystem.addSubsystemForArgument(argument)
|
||||
}
|
||||
baseSystem.addSubsystemForArgument(kotlinCall.externalArgument)
|
||||
|
||||
this.baseSystem = baseSystem.asReadOnlyStorage()
|
||||
}
|
||||
|
||||
// todo: try something else, because current method is ugly and unstable
|
||||
private fun createReceiverArgument(
|
||||
@@ -63,37 +81,80 @@ class SimpleCandidateFactory(val callContext: KotlinCallContext, val kotlinCall:
|
||||
else -> null
|
||||
}
|
||||
|
||||
fun createCandidate(givenCandidate: GivenCandidate): KotlinResolutionCandidate {
|
||||
val isSafeCall = (kotlinCall.explicitReceiver as? SimpleKotlinCallArgument)?.isSafeCall ?: false
|
||||
|
||||
val explicitReceiverKind = if (givenCandidate.dispatchReceiver == null) ExplicitReceiverKind.NO_EXPLICIT_RECEIVER else ExplicitReceiverKind.DISPATCH_RECEIVER
|
||||
val dispatchArgumentReceiver = givenCandidate.dispatchReceiver?.let { ReceiverExpressionKotlinCallArgument(it, isSafeCall) }
|
||||
return createCandidate(givenCandidate.descriptor, explicitReceiverKind, dispatchArgumentReceiver, null,
|
||||
listOf(), givenCandidate.knownTypeParametersResultingSubstitutor)
|
||||
}
|
||||
|
||||
override fun createCandidate(
|
||||
towerCandidate: CandidateWithBoundDispatchReceiver,
|
||||
explicitReceiverKind: ExplicitReceiverKind,
|
||||
extensionReceiver: ReceiverValueWithSmartCastInfo?
|
||||
): SimpleKotlinResolutionCandidate {
|
||||
): KotlinResolutionCandidate {
|
||||
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 createCandidate(towerCandidate.descriptor, explicitReceiverKind, dispatchArgumentReceiver,
|
||||
extensionArgumentReceiver, towerCandidate.diagnostics, knownSubstitutor = null)
|
||||
}
|
||||
|
||||
private fun createCandidate(
|
||||
descriptor: CallableDescriptor,
|
||||
explicitReceiverKind: ExplicitReceiverKind,
|
||||
dispatchArgumentReceiver: SimpleKotlinCallArgument?,
|
||||
extensionArgumentReceiver: SimpleKotlinCallArgument?,
|
||||
initialDiagnostics: Collection<KotlinCallDiagnostic>,
|
||||
knownSubstitutor: TypeSubstitutor?
|
||||
): KotlinResolutionCandidate {
|
||||
val resolvedKtCall = MutableResolvedCallAtom(kotlinCall, descriptor, explicitReceiverKind,
|
||||
dispatchArgumentReceiver, extensionArgumentReceiver)
|
||||
|
||||
if (ErrorUtils.isError(descriptor)) {
|
||||
return KotlinResolutionCandidate(callComponents, scopeTower, baseSystem, resolvedKtCall, knownSubstitutor, listOf(ErrorDescriptorResolutionPart))
|
||||
}
|
||||
|
||||
val candidateDiagnostics = towerCandidate.diagnostics.toMutableList()
|
||||
if (callContext.externalPredicates.isHiddenInResolution(towerCandidate.descriptor, kotlinCall)) {
|
||||
candidateDiagnostics.add(HiddenDescriptor)
|
||||
val candidate = KotlinResolutionCandidate(callComponents, scopeTower, baseSystem, resolvedKtCall, knownSubstitutor)
|
||||
|
||||
initialDiagnostics.forEach(candidate::addDiagnostic)
|
||||
|
||||
if (callComponents.statelessCallbacks.isHiddenInResolution(descriptor, kotlinCall)) {
|
||||
candidate.addDiagnostic(HiddenDescriptor)
|
||||
}
|
||||
|
||||
if (extensionReceiver != null) {
|
||||
val parameterIsDynamic = towerCandidate.descriptor.extensionReceiverParameter!!.value.type.isDynamic()
|
||||
val argumentIsDynamic = extensionReceiver.receiverValue.type.isDynamic()
|
||||
if (extensionArgumentReceiver != null) {
|
||||
val parameterIsDynamic = descriptor.extensionReceiverParameter!!.value.type.isDynamic()
|
||||
val argumentIsDynamic = extensionArgumentReceiver.receiver.receiverValue.type.isDynamic()
|
||||
|
||||
if (parameterIsDynamic != argumentIsDynamic ||
|
||||
(parameterIsDynamic && !towerCandidate.descriptor.hasDynamicExtensionAnnotation())) {
|
||||
candidateDiagnostics.add(HiddenExtensionRelatedToDynamicTypes)
|
||||
(parameterIsDynamic && !descriptor.hasDynamicExtensionAnnotation())) {
|
||||
candidate.addDiagnostic(HiddenExtensionRelatedToDynamicTypes)
|
||||
}
|
||||
}
|
||||
|
||||
return SimpleKotlinResolutionCandidate(callContext, kotlinCall, explicitReceiverKind, dispatchArgumentReceiver, extensionArgumentReceiver,
|
||||
towerCandidate.descriptor, null, candidateDiagnostics)
|
||||
return candidate
|
||||
}
|
||||
|
||||
fun createErrorCandidate(): KotlinResolutionCandidate {
|
||||
val errorScope = ErrorUtils.createErrorScope("Error resolution candidate for call $kotlinCall")
|
||||
val errorDescriptor = if (kotlinCall.callKind == KotlinCallKind.VARIABLE) {
|
||||
errorScope.getContributedVariables(kotlinCall.name, scopeTower.location)
|
||||
}
|
||||
else {
|
||||
errorScope.getContributedFunctions(kotlinCall.name, scopeTower.location)
|
||||
}.first()
|
||||
|
||||
val dispatchReceiver = createReceiverArgument(kotlinCall.explicitReceiver, fromResolution = null)
|
||||
val explicitReceiverKind = if (dispatchReceiver == null) ExplicitReceiverKind.NO_EXPLICIT_RECEIVER else ExplicitReceiverKind.DISPATCH_RECEIVER
|
||||
|
||||
return createCandidate(errorDescriptor, explicitReceiverKind, dispatchReceiver, extensionArgumentReceiver = null,
|
||||
initialDiagnostics = listOf(), knownSubstitutor = null)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
enum class KotlinCallKind(vararg resolutionPart: ResolutionPart) {
|
||||
@@ -104,7 +165,7 @@ enum class KotlinCallKind(vararg resolutionPart: ResolutionPart) {
|
||||
CheckAbstractSuperCallPart,
|
||||
NoTypeArguments,
|
||||
NoArguments,
|
||||
CreateDescriptorWithFreshTypeVariables,
|
||||
CreateFreshVariablesSubstitutor,
|
||||
CheckExplicitReceiverKindConsistency,
|
||||
CheckReceivers
|
||||
),
|
||||
@@ -115,10 +176,12 @@ enum class KotlinCallKind(vararg resolutionPart: ResolutionPart) {
|
||||
CheckAbstractSuperCallPart,
|
||||
MapTypeArguments,
|
||||
MapArguments,
|
||||
CreateDescriptorWithFreshTypeVariables,
|
||||
ArgumentsToCandidateParameterDescriptor,
|
||||
CreateFreshVariablesSubstitutor,
|
||||
CheckExplicitReceiverKindConsistency,
|
||||
CheckReceivers,
|
||||
CheckArguments
|
||||
CheckArguments,
|
||||
CheckExternalArgument
|
||||
),
|
||||
UNSUPPORTED();
|
||||
|
||||
|
||||
@@ -1,64 +0,0 @@
|
||||
/*
|
||||
* 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.createFunctionType
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.resolve.calls.components.CallableReferenceCandidate
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.NewTypeVariable
|
||||
import org.jetbrains.kotlin.types.SimpleType
|
||||
import org.jetbrains.kotlin.types.UnwrappedType
|
||||
import org.jetbrains.kotlin.types.typeUtil.builtIns
|
||||
|
||||
|
||||
sealed class PostponedKotlinCallArgument {
|
||||
abstract val argument: PostponableKotlinCallArgument
|
||||
}
|
||||
|
||||
class PostponedLambdaArgument(
|
||||
val outerCall: KotlinCall,
|
||||
override val argument: LambdaKotlinCallArgument,
|
||||
val isSuspend: Boolean,
|
||||
val receiver: UnwrappedType?,
|
||||
val parameters: List<UnwrappedType>,
|
||||
val returnType: UnwrappedType
|
||||
) : PostponedKotlinCallArgument() {
|
||||
var analyzed: Boolean = false
|
||||
|
||||
val type: SimpleType = createFunctionType(returnType.builtIns, Annotations.EMPTY, receiver, parameters, null, returnType, isSuspend) // todo support annotations
|
||||
|
||||
val inputTypes: Collection<UnwrappedType> get() = receiver?.let { parameters + it } ?: parameters
|
||||
val outputType: UnwrappedType get() = returnType
|
||||
|
||||
lateinit var resultArguments: List<SimpleKotlinCallArgument>
|
||||
lateinit var finalReturnType: UnwrappedType
|
||||
}
|
||||
|
||||
class PostponedCallableReferenceArgument(
|
||||
override val argument: CallableReferenceKotlinCallArgument,
|
||||
val expectedType: UnwrappedType
|
||||
) : PostponedKotlinCallArgument() {
|
||||
var analyzedAndThereIsResult: Boolean = false
|
||||
|
||||
lateinit var myTypeVariables: List<NewTypeVariable>
|
||||
lateinit var callableResolutionCandidate: CallableReferenceCandidate
|
||||
}
|
||||
|
||||
class PostponedCollectionLiteralArgument(
|
||||
override val argument: CollectionLiteralKotlinCallArgument,
|
||||
val expectedType: UnwrappedType
|
||||
) : PostponedKotlinCallArgument()
|
||||
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
* 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.getReceiverTypeFromFunctionType
|
||||
import org.jetbrains.kotlin.builtins.getReturnTypeFromFunctionType
|
||||
import org.jetbrains.kotlin.builtins.getValueParameterTypesFromFunctionType
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
||||
import org.jetbrains.kotlin.resolve.calls.components.CallableReferenceCandidate
|
||||
import org.jetbrains.kotlin.resolve.calls.components.TypeArgumentsToParametersMapper
|
||||
import org.jetbrains.kotlin.resolve.calls.components.getFunctionTypeFromCallableReferenceExpectedType
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.components.FreshVariableNewTypeSubstitutor
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.TypeVariableForLambdaReturnType
|
||||
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
|
||||
import org.jetbrains.kotlin.types.UnwrappedType
|
||||
|
||||
/**
|
||||
* Call, Callable reference, lambda & function expression, collection literal.
|
||||
* In future we should add literals here, because they have similar lifecycle.
|
||||
*
|
||||
* Expression with type is also primitive. This is done for simplification. todo
|
||||
*/
|
||||
interface ResolutionAtom
|
||||
|
||||
sealed class ResolvedAtom {
|
||||
abstract val atom: ResolutionAtom? // CallResolutionResult has no ResolutionAtom
|
||||
|
||||
var analyzed: Boolean = false
|
||||
private set
|
||||
|
||||
lateinit var subResolvedAtoms: List<ResolvedAtom>
|
||||
private set
|
||||
lateinit var diagnostics: Collection<KotlinCallDiagnostic>
|
||||
private set
|
||||
|
||||
protected open fun setAnalyzedResults(subResolvedAtoms: List<ResolvedAtom>, diagnostics: Collection<KotlinCallDiagnostic>) {
|
||||
assert(!analyzed) {
|
||||
"Already analyzed: $this"
|
||||
}
|
||||
|
||||
analyzed = true
|
||||
|
||||
this.subResolvedAtoms = subResolvedAtoms
|
||||
this.diagnostics = diagnostics
|
||||
}
|
||||
}
|
||||
|
||||
abstract class ResolvedCallAtom : ResolvedAtom() {
|
||||
abstract override val atom: KotlinCall
|
||||
abstract val candidateDescriptor: CallableDescriptor
|
||||
abstract val explicitReceiverKind: ExplicitReceiverKind
|
||||
abstract val dispatchReceiverArgument: SimpleKotlinCallArgument?
|
||||
abstract val extensionReceiverArgument: SimpleKotlinCallArgument?
|
||||
abstract val typeArgumentMappingByOriginal: TypeArgumentsToParametersMapper.TypeArgumentsMapping
|
||||
abstract val argumentMappingByOriginal: Map<ValueParameterDescriptor, ResolvedCallArgument>
|
||||
abstract val substitutor: FreshVariableNewTypeSubstitutor
|
||||
}
|
||||
|
||||
class ResolvedExpressionAtom(override val atom: ExpressionKotlinCallArgument) : ResolvedAtom() {
|
||||
init {
|
||||
setAnalyzedResults(listOf(), listOf())
|
||||
}
|
||||
}
|
||||
sealed class PostponedResolvedAtom : ResolvedAtom() {
|
||||
abstract val inputTypes: Collection<UnwrappedType>
|
||||
abstract val outputType: UnwrappedType?
|
||||
}
|
||||
|
||||
class ResolvedLambdaAtom(
|
||||
override val atom: LambdaKotlinCallArgument,
|
||||
val isSuspend: Boolean,
|
||||
val receiver: UnwrappedType?,
|
||||
val parameters: List<UnwrappedType>,
|
||||
val returnType: UnwrappedType,
|
||||
val typeVariableForLambdaReturnType: TypeVariableForLambdaReturnType?
|
||||
) : PostponedResolvedAtom() {
|
||||
lateinit var resultArguments: List<KotlinCallArgument>
|
||||
private set
|
||||
|
||||
fun setAnalyzedResults(
|
||||
resultArguments: List<KotlinCallArgument>,
|
||||
subResolvedAtoms: List<ResolvedAtom>,
|
||||
diagnostics: Collection<KotlinCallDiagnostic>
|
||||
) {
|
||||
this.resultArguments = resultArguments
|
||||
setAnalyzedResults(subResolvedAtoms, diagnostics)
|
||||
}
|
||||
|
||||
override val inputTypes: Collection<UnwrappedType> get() = receiver?.let { parameters + it } ?: parameters
|
||||
override val outputType: UnwrappedType get() = returnType
|
||||
}
|
||||
|
||||
class ResolvedCallableReferenceAtom(
|
||||
override val atom: CallableReferenceKotlinCallArgument,
|
||||
val expectedType: UnwrappedType?
|
||||
) : PostponedResolvedAtom() {
|
||||
var candidate: CallableReferenceCandidate? = null
|
||||
private set
|
||||
|
||||
fun setAnalyzedResults(
|
||||
candidate: CallableReferenceCandidate?,
|
||||
subResolvedAtoms: List<ResolvedAtom>,
|
||||
diagnostics: Collection<KotlinCallDiagnostic>
|
||||
) {
|
||||
this.candidate = candidate
|
||||
setAnalyzedResults(subResolvedAtoms, diagnostics)
|
||||
}
|
||||
|
||||
override val inputTypes: Collection<UnwrappedType>
|
||||
get() {
|
||||
val functionType = getFunctionTypeFromCallableReferenceExpectedType(expectedType) ?: return emptyList()
|
||||
val parameters = functionType.getValueParameterTypesFromFunctionType().map { it.type.unwrap() }
|
||||
val receiver = functionType.getReceiverTypeFromFunctionType()?.unwrap()
|
||||
return receiver?.let { parameters + it } ?: parameters
|
||||
}
|
||||
|
||||
override val outputType: UnwrappedType?
|
||||
get() {
|
||||
val functionType = getFunctionTypeFromCallableReferenceExpectedType(expectedType) ?: return null
|
||||
return functionType.getReturnTypeFromFunctionType().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
class ResolvedCollectionLiteralAtom(
|
||||
override val atom: CollectionLiteralKotlinCallArgument,
|
||||
val expectedType: UnwrappedType?
|
||||
) : ResolvedAtom() {
|
||||
init {
|
||||
setAnalyzedResults(listOf(), listOf())
|
||||
}
|
||||
}
|
||||
|
||||
class CallResolutionResult(
|
||||
val type: Type,
|
||||
val resultCallAtom: ResolvedCallAtom?,
|
||||
diagnostics: List<KotlinCallDiagnostic>,
|
||||
val constraintSystem: ConstraintStorage
|
||||
) : ResolvedAtom() {
|
||||
override val atom: ResolutionAtom? get() = null
|
||||
|
||||
enum class Type {
|
||||
COMPLETED, // resultSubstitutor possible create use constraintSystem
|
||||
PARTIAL,
|
||||
ERROR // if resultCallAtom == null it means that there is errors NoneCandidates or ManyCandidates
|
||||
}
|
||||
|
||||
init {
|
||||
setAnalyzedResults(listOfNotNull(resultCallAtom), diagnostics)
|
||||
}
|
||||
|
||||
override fun toString() = "$type, resultCallAtom = $resultCallAtom, (${diagnostics.joinToString()})"
|
||||
}
|
||||
|
||||
val ResolvedCallAtom.freshReturnType: UnwrappedType? get() {
|
||||
val returnType = candidateDescriptor.returnType ?: return null
|
||||
return substitutor.safeSubstitute(returnType.unwrap())
|
||||
}
|
||||
@@ -20,130 +20,163 @@ 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.components.FreshVariableNewTypeSubstitutor
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.NewConstraintSystemImpl
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.NewTypeVariable
|
||||
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.Candidate
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.ResolutionCandidateStatus
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.isSuccess
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.*
|
||||
import org.jetbrains.kotlin.types.TypeSubstitutor
|
||||
import java.util.*
|
||||
|
||||
|
||||
interface ResolutionPart {
|
||||
fun SimpleKotlinResolutionCandidate.process(): List<KotlinCallDiagnostic>
|
||||
abstract class ResolutionPart {
|
||||
abstract fun KotlinResolutionCandidate.process(workIndex: Int)
|
||||
|
||||
open fun KotlinResolutionCandidate.workCount(): Int = 1
|
||||
|
||||
// helper functions
|
||||
protected inline val KotlinResolutionCandidate.candidateDescriptor get() = resolvedCall.candidateDescriptor
|
||||
protected inline val KotlinResolutionCandidate.kotlinCall get() = resolvedCall.atom
|
||||
}
|
||||
|
||||
sealed class KotlinResolutionCandidate : Candidate {
|
||||
abstract val kotlinCall: KotlinCall
|
||||
interface KotlinDiagnosticsHolder {
|
||||
fun addDiagnostic(diagnostic: KotlinCallDiagnostic)
|
||||
|
||||
abstract val lastCall: SimpleKotlinResolutionCandidate
|
||||
}
|
||||
class SimpleHolder : KotlinDiagnosticsHolder {
|
||||
private val diagnostics = arrayListOf<KotlinCallDiagnostic>()
|
||||
|
||||
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
|
||||
override fun addDiagnostic(diagnostic: KotlinCallDiagnostic) {
|
||||
diagnostics.add(diagnostic)
|
||||
}
|
||||
|
||||
private var _status: ResolutionCandidateStatus? = null
|
||||
fun getDiagnostics(): List<KotlinCallDiagnostic> = diagnostics
|
||||
}
|
||||
}
|
||||
|
||||
override val status: ResolutionCandidateStatus
|
||||
get() {
|
||||
if (_status == null) {
|
||||
process(stopOnFirstError = false)
|
||||
_status = ResolutionCandidateStatus(diagnostics + constraintSystem.diagnostics)
|
||||
fun KotlinDiagnosticsHolder.addDiagnosticIfNotNull(diagnostic: KotlinCallDiagnostic?) {
|
||||
diagnostic?.let { addDiagnostic(it) }
|
||||
}
|
||||
/**
|
||||
* baseSystem contains all information from arguments, i.e. it is union of all system of arguments
|
||||
* Also by convention we suppose that baseSystem has no contradiction
|
||||
*/
|
||||
class KotlinResolutionCandidate(
|
||||
val callComponents: KotlinCallComponents,
|
||||
val scopeTower: ImplicitScopeTower,
|
||||
private val baseSystem: ConstraintStorage,
|
||||
val resolvedCall: MutableResolvedCallAtom,
|
||||
val knownTypeParametersResultingSubstitutor: TypeSubstitutor? = null,
|
||||
private val resolutionSequence: List<ResolutionPart> = resolvedCall.atom.callKind.resolutionSequence
|
||||
) : Candidate, KotlinDiagnosticsHolder {
|
||||
private var newSystem: NewConstraintSystemImpl? = null
|
||||
private val diagnostics = arrayListOf<KotlinCallDiagnostic>()
|
||||
private var currentApplicability = ResolutionCandidateApplicability.RESOLVED
|
||||
private var subResolvedAtoms: MutableList<ResolvedAtom> = arrayListOf()
|
||||
|
||||
private val stepCount = resolutionSequence.sumBy { it.run { workCount() } }
|
||||
private var step = 0
|
||||
|
||||
fun getSystem(): NewConstraintSystem {
|
||||
if (newSystem == null) {
|
||||
newSystem = NewConstraintSystemImpl(callComponents.constraintInjector, callComponents.builtIns)
|
||||
newSystem!!.addOtherSystem(baseSystem)
|
||||
}
|
||||
return newSystem!!
|
||||
}
|
||||
|
||||
internal val csBuilder get() = getSystem().getBuilder()
|
||||
|
||||
override fun addDiagnostic(diagnostic: KotlinCallDiagnostic) {
|
||||
diagnostics.add(diagnostic)
|
||||
currentApplicability = maxOf(diagnostic.candidateApplicability, currentApplicability)
|
||||
}
|
||||
|
||||
fun addResolvedKtPrimitive(resolvedAtom: ResolvedAtom) {
|
||||
subResolvedAtoms.add(resolvedAtom)
|
||||
}
|
||||
|
||||
private fun processParts(stopOnFirstError: Boolean) {
|
||||
if (stopOnFirstError && step > 0) return // error already happened
|
||||
if (step == stepCount) return
|
||||
|
||||
var partIndex = 0
|
||||
var workStep = step
|
||||
while (workStep > 0) {
|
||||
val workCount = resolutionSequence[partIndex].run { workCount() }
|
||||
if (workStep >= workCount) {
|
||||
partIndex++
|
||||
workStep -= workCount
|
||||
}
|
||||
return _status!!
|
||||
}
|
||||
if (partIndex < resolutionSequence.size) {
|
||||
if (processPart(resolutionSequence[partIndex], stopOnFirstError, workStep)) return
|
||||
partIndex++
|
||||
}
|
||||
|
||||
private val diagnostics = ArrayList<KotlinCallDiagnostic>()
|
||||
protected var step = 0
|
||||
private set
|
||||
while (partIndex < resolutionSequence.size) {
|
||||
if (processPart(resolutionSequence[partIndex], stopOnFirstError)) return
|
||||
partIndex++
|
||||
}
|
||||
if (step == stepCount) {
|
||||
resolvedCall.setAnalyzedResults(subResolvedAtoms, diagnostics + getSystem().diagnostics)
|
||||
}
|
||||
}
|
||||
|
||||
protected var hasErrors = false
|
||||
private set
|
||||
// true if part was interrupted
|
||||
private fun processPart(part: ResolutionPart, stopOnFirstError: Boolean, startWorkIndex: Int = 0): Boolean {
|
||||
for (workIndex in startWorkIndex until (part.run { workCount() })) {
|
||||
if (stopOnFirstError && !currentApplicability.isSuccess) return true
|
||||
|
||||
private fun process(stopOnFirstError: Boolean) {
|
||||
while (step < resolutionSequence.size && (!stopOnFirstError || !hasErrors)) {
|
||||
addDiagnostics(resolutionSequence[step].run { lastCall.process() })
|
||||
part.run { process(workIndex) }
|
||||
step++
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private fun addDiagnostics(diagnostics: Collection<KotlinCallDiagnostic>) {
|
||||
hasErrors = hasErrors || diagnostics.any { !it.candidateApplicability.isSuccess } ||
|
||||
constraintSystem.diagnostics.any { !it.candidateApplicability.isSuccess }
|
||||
this.diagnostics.addAll(diagnostics)
|
||||
}
|
||||
val variableCandidateIfInvoke: KotlinResolutionCandidate?
|
||||
get() = callComponents.statelessCallbacks.getVariableCandidateIfInvoke(resolvedCall.atom)
|
||||
|
||||
init {
|
||||
addDiagnostics(initialDiagnostics)
|
||||
}
|
||||
private val variableApplicability
|
||||
get() = variableCandidateIfInvoke?.resultingApplicability ?: ResolutionCandidateApplicability.RESOLVED
|
||||
|
||||
override val isSuccessful: Boolean
|
||||
get() {
|
||||
processParts(stopOnFirstError = true)
|
||||
return currentApplicability.isSuccess && variableApplicability.isSuccess
|
||||
}
|
||||
|
||||
abstract val resolutionSequence: List<ResolutionPart>
|
||||
}
|
||||
override val resultingApplicability: ResolutionCandidateApplicability
|
||||
get() {
|
||||
processParts(stopOnFirstError = false)
|
||||
|
||||
open class SimpleKotlinResolutionCandidate(
|
||||
val callContext: KotlinCallContext,
|
||||
override val kotlinCall: KotlinCall,
|
||||
val explicitReceiverKind: ExplicitReceiverKind,
|
||||
val dispatchReceiverArgument: SimpleKotlinCallArgument?,
|
||||
val extensionReceiver: SimpleKotlinCallArgument?,
|
||||
val candidateDescriptor: CallableDescriptor,
|
||||
val knownTypeParametersResultingSubstitutor: TypeSubstitutor?,
|
||||
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
|
||||
lateinit var typeVariablesForFreshTypeParameters: List<NewTypeVariable>
|
||||
|
||||
override val lastCall: SimpleKotlinResolutionCandidate get() = this
|
||||
override val resolutionSequence: List<ResolutionPart> get() = kotlinCall.callKind.resolutionSequence
|
||||
val systemApplicability = getResultApplicability(getSystem().diagnostics)
|
||||
return maxOf(currentApplicability, systemApplicability, variableApplicability)
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
val descriptor = DescriptorRenderer.COMPACT.render(candidateDescriptor)
|
||||
val okOrFail = if (hasErrors) "FAIL" else "OK"
|
||||
val step = "$step/${resolutionSequence.size}"
|
||||
val descriptor = DescriptorRenderer.COMPACT.render(resolvedCall.candidateDescriptor)
|
||||
val okOrFail = if (currentApplicability.isSuccess) "OK" else "FAIL"
|
||||
val step = "$step/$stepCount"
|
||||
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, null, listOf()) {
|
||||
override val resolutionSequence: List<ResolutionPart> get() = emptyList()
|
||||
class MutableResolvedCallAtom(
|
||||
override val atom: KotlinCall,
|
||||
override val candidateDescriptor: CallableDescriptor, // original candidate descriptor
|
||||
override val explicitReceiverKind: ExplicitReceiverKind,
|
||||
override val dispatchReceiverArgument: SimpleKotlinCallArgument?,
|
||||
override val extensionReceiverArgument: SimpleKotlinCallArgument?
|
||||
) : ResolvedCallAtom() {
|
||||
override lateinit var typeArgumentMappingByOriginal: TypeArgumentsToParametersMapper.TypeArgumentsMapping
|
||||
override lateinit var argumentMappingByOriginal: Map<ValueParameterDescriptor, ResolvedCallArgument>
|
||||
override lateinit var substitutor: FreshVariableNewTypeSubstitutor
|
||||
lateinit var argumentToCandidateParameter: Map<KotlinCallArgument, ValueParameterDescriptor>
|
||||
|
||||
init {
|
||||
typeArgumentMappingByOriginal = TypeArgumentsToParametersMapper.TypeArgumentsMapping.NoExplicitArguments
|
||||
argumentMappingByOriginal = emptyMap()
|
||||
descriptorWithFreshTypes = candidateDescriptor
|
||||
override public fun setAnalyzedResults(subResolvedAtoms: List<ResolvedAtom>, diagnostics: Collection<KotlinCallDiagnostic>) {
|
||||
super.setAnalyzedResults(subResolvedAtoms, diagnostics)
|
||||
}
|
||||
|
||||
override fun toString(): String = "$atom, candidate = $candidateDescriptor"
|
||||
}
|
||||
|
||||
|
||||
@@ -16,54 +16,6 @@
|
||||
|
||||
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.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 {
|
||||
abstract val currentStatus: ResolutionCandidateStatus
|
||||
|
||||
class CompletedResolvedKotlinCall(
|
||||
val completedCall: CompletedKotlinCall,
|
||||
val allInnerCalls: Collection<CompletedKotlinCall>,
|
||||
val lambdaArguments: List<PostponedLambdaArgument>
|
||||
): ResolvedKotlinCall() {
|
||||
override val currentStatus get() = completedCall.resolutionStatus
|
||||
}
|
||||
|
||||
class OnlyResolvedKotlinCall(val candidate: KotlinResolutionCandidate) : ResolvedKotlinCall() {
|
||||
override val currentStatus get() = candidate.status
|
||||
}
|
||||
}
|
||||
|
||||
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>
|
||||
|
||||
@@ -38,7 +38,7 @@ open class OverloadingConflictResolver<C : Any>(
|
||||
private val getResultingDescriptor: (C) -> CallableDescriptor,
|
||||
private val createEmptyConstraintSystem: () -> SimpleConstraintSystem,
|
||||
private val createFlatSignature: (C) -> FlatSignature<C>,
|
||||
private val getVariableCandidates: (C) -> C?, // vor variable WithInvoke
|
||||
private val getVariableCandidates: (C) -> C?, // for variable WithInvoke
|
||||
private val isFromSources: (CallableDescriptor) -> Boolean
|
||||
) {
|
||||
|
||||
|
||||
@@ -21,8 +21,8 @@ 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.model.KotlinCallDiagnostic
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.ResolutionCandidateApplicability.*
|
||||
import org.jetbrains.kotlin.resolve.scopes.LexicalScope
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||
@@ -60,10 +60,8 @@ interface CandidateWithBoundDispatchReceiver {
|
||||
val dispatchReceiver: ReceiverValueWithSmartCastInfo?
|
||||
}
|
||||
|
||||
data class ResolutionCandidateStatus(val diagnostics: List<KotlinCallDiagnostic>) {
|
||||
val resultingApplicability: ResolutionCandidateApplicability = diagnostics.asSequence().map { it.candidateApplicability }.max()
|
||||
?: RESOLVED
|
||||
}
|
||||
fun getResultApplicability(diagnostics: Collection<KotlinCallDiagnostic>) = diagnostics.maxBy { it.candidateApplicability }?.candidateApplicability
|
||||
?: RESOLVED
|
||||
|
||||
enum class ResolutionCandidateApplicability {
|
||||
RESOLVED, // call success or has uncompleted inference or in other words possible successful candidate
|
||||
|
||||
@@ -17,8 +17,6 @@
|
||||
package org.jetbrains.kotlin.resolve.calls.tower
|
||||
|
||||
import org.jetbrains.kotlin.builtins.isBuiltinExtensionFunctionalType
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.VariableDescriptor
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
|
||||
import org.jetbrains.kotlin.resolve.calls.tasks.createSynthesizedInvokes
|
||||
@@ -182,7 +180,7 @@ fun <C : Candidate> createCallTowerProcessorForExplicitInvoke(
|
||||
usualInvoke
|
||||
}
|
||||
else {
|
||||
CompositeScopeTowerProcessor(
|
||||
PrioritizedCompositeScopeTowerProcessor(
|
||||
usualInvoke,
|
||||
InvokeExtensionScopeTowerProcessor(functionContext, invokeExtensionDescriptor, explicitReceiver = null)
|
||||
)
|
||||
|
||||
@@ -32,14 +32,14 @@ class KnownResultProcessor<out C>(
|
||||
}
|
||||
|
||||
// use this if processors priority is important
|
||||
class CompositeScopeTowerProcessor<out C>(
|
||||
class PrioritizedCompositeScopeTowerProcessor<out C>(
|
||||
vararg val processors: ScopeTowerProcessor<C>
|
||||
) : ScopeTowerProcessor<C> {
|
||||
override fun process(data: TowerData): List<Collection<C>> = processors.flatMap { it.process(data) }
|
||||
}
|
||||
|
||||
// use this if all processors has same priority
|
||||
class CompositeSimpleScopeTowerProcessor<C : Candidate>(
|
||||
class SamePriorityCompositeScopeTowerProcessor<out C>(
|
||||
private vararg val processors: SimpleScopeTowerProcessor<C>
|
||||
): SimpleScopeTowerProcessor<C> {
|
||||
override fun simpleProcess(data: TowerData): Collection<C> = processors.flatMap { it.simpleProcess(data) }
|
||||
@@ -192,7 +192,7 @@ private fun <C : Candidate> createSimpleProcessor(
|
||||
|
||||
if (classValueReceiver && explicitReceiver is QualifierReceiver) {
|
||||
val classValue = explicitReceiver.classValueReceiverWithSmartCastInfo ?: return withoutClassValueProcessor
|
||||
return CompositeScopeTowerProcessor(
|
||||
return PrioritizedCompositeScopeTowerProcessor(
|
||||
withoutClassValueProcessor,
|
||||
ExplicitReceiverScopeTowerProcessor(scopeTower, context, classValue, collectCandidates)
|
||||
)
|
||||
@@ -200,11 +200,14 @@ private fun <C : Candidate> createSimpleProcessor(
|
||||
return withoutClassValueProcessor
|
||||
}
|
||||
|
||||
fun <C : Candidate> createCallableReferenceProcessor(scopeTower: ImplicitScopeTower, name: Name, context: CandidateFactory<C>,
|
||||
explicitReceiver: DetailedReceiver?): SimpleScopeTowerProcessor<C> {
|
||||
fun <C : Candidate> createCallableReferenceProcessor(
|
||||
scopeTower: ImplicitScopeTower,
|
||||
name: Name, context: CandidateFactory<C>,
|
||||
explicitReceiver: DetailedReceiver?
|
||||
): SimpleScopeTowerProcessor<C> {
|
||||
val variable = createSimpleProcessorWithoutClassValueReceiver(scopeTower, context, explicitReceiver) { getVariables(name, it) }
|
||||
val function = createSimpleProcessorWithoutClassValueReceiver(scopeTower, context, explicitReceiver) { getFunctions(name, it) }
|
||||
return CompositeSimpleScopeTowerProcessor(variable, function)
|
||||
return SamePriorityCompositeScopeTowerProcessor(variable, function)
|
||||
}
|
||||
|
||||
fun <C : Candidate> createVariableProcessor(scopeTower: ImplicitScopeTower, name: Name,
|
||||
@@ -213,7 +216,7 @@ fun <C : Candidate> createVariableProcessor(scopeTower: ImplicitScopeTower, name
|
||||
|
||||
fun <C : Candidate> createVariableAndObjectProcessor(scopeTower: ImplicitScopeTower, name: Name,
|
||||
context: CandidateFactory<C>, explicitReceiver: DetailedReceiver?, classValueReceiver: Boolean = true
|
||||
) = CompositeScopeTowerProcessor(
|
||||
) = PrioritizedCompositeScopeTowerProcessor(
|
||||
createVariableProcessor(scopeTower, name, context, explicitReceiver),
|
||||
createSimpleProcessor(scopeTower, context, explicitReceiver, classValueReceiver) { getObjects(name, it) }
|
||||
)
|
||||
@@ -229,7 +232,7 @@ fun <С: Candidate> createFunctionProcessor(
|
||||
simpleContext: CandidateFactory<С>,
|
||||
factoryProviderForInvoke: CandidateFactoryProviderForInvoke<С>,
|
||||
explicitReceiver: DetailedReceiver?
|
||||
): CompositeScopeTowerProcessor<С> {
|
||||
): PrioritizedCompositeScopeTowerProcessor<С> {
|
||||
|
||||
// a.foo() -- simple function call
|
||||
val simpleFunction = createSimpleFunctionProcessor(scopeTower, name, simpleContext, explicitReceiver)
|
||||
@@ -242,7 +245,7 @@ fun <С: Candidate> createFunctionProcessor(
|
||||
InvokeExtensionTowerProcessor(scopeTower, name, factoryProviderForInvoke, it)
|
||||
}
|
||||
|
||||
return CompositeScopeTowerProcessor(simpleFunction, invokeProcessor, invokeExtensionProcessor)
|
||||
return PrioritizedCompositeScopeTowerProcessor(simpleFunction, invokeProcessor, invokeExtensionProcessor)
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ interface Candidate {
|
||||
// this operation should be very fast
|
||||
val isSuccessful: Boolean
|
||||
|
||||
val status: ResolutionCandidateStatus
|
||||
val resultingApplicability: ResolutionCandidateApplicability
|
||||
}
|
||||
|
||||
interface CandidateFactory<out C: Candidate> {
|
||||
@@ -75,13 +75,13 @@ class TowerResolver {
|
||||
scopeTower: ImplicitScopeTower,
|
||||
processor: ScopeTowerProcessor<C>,
|
||||
useOrder: Boolean
|
||||
): Collection<C> = scopeTower.run(processor, SuccessfulResultCollector { it.status }, useOrder)
|
||||
): Collection<C> = scopeTower.run(processor, SuccessfulResultCollector(), useOrder)
|
||||
|
||||
fun <C: Candidate> collectAllCandidates(
|
||||
scopeTower: ImplicitScopeTower,
|
||||
processor: ScopeTowerProcessor<C>
|
||||
): Collection<C>
|
||||
= scopeTower.run(processor, AllCandidatesCollector { it.status }, false)
|
||||
= scopeTower.run(processor, AllCandidatesCollector(), false)
|
||||
|
||||
private fun ImplicitScopeTower.createNonLocalLevels(): List<ScopeTowerLevel> {
|
||||
val result = ArrayList<ScopeTowerLevel>()
|
||||
@@ -100,7 +100,7 @@ class TowerResolver {
|
||||
return result
|
||||
}
|
||||
|
||||
private fun <C> ImplicitScopeTower.run(
|
||||
private fun <C : Candidate> ImplicitScopeTower.run(
|
||||
processor: ScopeTowerProcessor<C>,
|
||||
resultCollector: ResultCollector<C>,
|
||||
useOrder: Boolean
|
||||
@@ -173,13 +173,13 @@ class TowerResolver {
|
||||
return resultCollector.getFinalCandidates()
|
||||
}
|
||||
|
||||
fun <C> runWithEmptyTowerData(
|
||||
fun <C : Candidate> runWithEmptyTowerData(
|
||||
processor: ScopeTowerProcessor<C>,
|
||||
resultCollector: ResultCollector<C>,
|
||||
useOrder: Boolean
|
||||
): Collection<C> = processTowerData(processor, resultCollector, useOrder, TowerData.Empty) ?: resultCollector.getFinalCandidates()
|
||||
|
||||
private fun <C> processTowerData(
|
||||
private fun <C : Candidate> processTowerData(
|
||||
processor: ScopeTowerProcessor<C>,
|
||||
resultCollector: ResultCollector<C>,
|
||||
useOrder: Boolean,
|
||||
@@ -203,55 +203,66 @@ class TowerResolver {
|
||||
}
|
||||
|
||||
|
||||
abstract class ResultCollector<C>(protected val getStatus: (C) -> ResolutionCandidateStatus) {
|
||||
abstract class ResultCollector<C : Candidate> {
|
||||
abstract fun getSuccessfulCandidates(): Collection<C>?
|
||||
|
||||
abstract fun getFinalCandidates(): Collection<C>
|
||||
|
||||
fun pushCandidates(candidates: Collection<C>) {
|
||||
val filteredCandidates = candidates.filter {
|
||||
getStatus(it).resultingApplicability != ResolutionCandidateApplicability.HIDDEN
|
||||
}
|
||||
if (filteredCandidates.isNotEmpty()) addCandidates(filteredCandidates)
|
||||
}
|
||||
|
||||
protected abstract fun addCandidates(candidates: Collection<C>)
|
||||
abstract fun pushCandidates(candidates: Collection<C>)
|
||||
}
|
||||
|
||||
class AllCandidatesCollector<C>(getStatus: (C) -> ResolutionCandidateStatus): ResultCollector<C>(getStatus) {
|
||||
class AllCandidatesCollector<C : Candidate>: ResultCollector<C>() {
|
||||
private val allCandidates = ArrayList<C>()
|
||||
|
||||
override fun getSuccessfulCandidates(): Collection<C>? = null
|
||||
|
||||
override fun getFinalCandidates(): Collection<C> = allCandidates
|
||||
|
||||
override fun addCandidates(candidates: Collection<C>) {
|
||||
allCandidates.addAll(candidates)
|
||||
}
|
||||
}
|
||||
|
||||
class SuccessfulResultCollector<C>(getStatus: (C) -> ResolutionCandidateStatus): ResultCollector<C>(getStatus) {
|
||||
private var currentCandidates: Collection<C> = emptyList()
|
||||
private var currentLevel: ResolutionCandidateApplicability? = null
|
||||
|
||||
override fun getSuccessfulCandidates(): Collection<C>? = getResolved()
|
||||
|
||||
fun getResolved() = currentCandidates.takeIf { currentLevel == ResolutionCandidateApplicability.RESOLVED }
|
||||
|
||||
fun getResolvedLowPriority() = currentCandidates.takeIf { currentLevel == ResolutionCandidateApplicability.RESOLVED_LOW_PRIORITY }
|
||||
|
||||
fun getErrors() = currentCandidates.takeIf {
|
||||
currentLevel == null || currentLevel!! > ResolutionCandidateApplicability.RESOLVED_LOW_PRIORITY
|
||||
}
|
||||
|
||||
override fun getFinalCandidates() = getResolved() ?: getResolvedLowPriority() ?: getErrors() ?: emptyList()
|
||||
|
||||
override fun addCandidates(candidates: Collection<C>) {
|
||||
val minimalLevel = candidates.map { getStatus(it).resultingApplicability }.min()!!
|
||||
if (currentLevel == null || currentLevel!! > minimalLevel) {
|
||||
currentLevel = minimalLevel
|
||||
currentCandidates = candidates.filter { getStatus(it).resultingApplicability == minimalLevel }
|
||||
override fun pushCandidates(candidates: Collection<C>) {
|
||||
candidates.filterNotTo(allCandidates) {
|
||||
it.resultingApplicability == ResolutionCandidateApplicability.HIDDEN
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class SuccessfulResultCollector<C : Candidate> : ResultCollector<C>() {
|
||||
private var candidateGroups = arrayListOf<Collection<C>>()
|
||||
private var isSuccessful = false
|
||||
|
||||
override fun getSuccessfulCandidates(): Collection<C>? {
|
||||
if (!isSuccessful) return null
|
||||
val firstGroupWithResolved = candidateGroups.firstOrNull {
|
||||
it.any { it.resultingApplicability == ResolutionCandidateApplicability.RESOLVED }
|
||||
} ?: return null
|
||||
|
||||
return firstGroupWithResolved.filter { it.resultingApplicability == ResolutionCandidateApplicability.RESOLVED }
|
||||
}
|
||||
|
||||
override fun pushCandidates(candidates: Collection<C>) {
|
||||
val thereIsSuccessful = candidates.any { it.isSuccessful }
|
||||
if (!isSuccessful && !thereIsSuccessful) {
|
||||
candidateGroups.add(candidates)
|
||||
return
|
||||
}
|
||||
|
||||
if (!isSuccessful) {
|
||||
candidateGroups.clear()
|
||||
isSuccessful = true
|
||||
}
|
||||
if (thereIsSuccessful) {
|
||||
candidateGroups.add(candidates.filter { it.isSuccessful })
|
||||
}
|
||||
}
|
||||
|
||||
override fun getFinalCandidates(): Collection<C> {
|
||||
val moreSuitableGroup = candidateGroups.minBy { it.groupApplicability } ?: return emptyList()
|
||||
val groupApplicability = moreSuitableGroup.groupApplicability
|
||||
if (groupApplicability == ResolutionCandidateApplicability.HIDDEN) return emptyList()
|
||||
|
||||
return moreSuitableGroup.filter { it.resultingApplicability == groupApplicability }
|
||||
}
|
||||
|
||||
private val Collection<C>.groupApplicability get() =
|
||||
minBy { it.resultingApplicability }?.resultingApplicability ?: ResolutionCandidateApplicability.HIDDEN
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,4 +41,9 @@ internal class CandidateWithBoundDispatchReceiverImpl(
|
||||
override val dispatchReceiver: ReceiverValueWithSmartCastInfo?,
|
||||
override val descriptor: CallableDescriptor,
|
||||
override val diagnostics: List<ResolutionDiagnostic>
|
||||
) : CandidateWithBoundDispatchReceiver
|
||||
) : CandidateWithBoundDispatchReceiver
|
||||
|
||||
fun <C : Candidate> C.forceResolution(): C {
|
||||
resultingApplicability
|
||||
return this
|
||||
}
|
||||
@@ -132,9 +132,9 @@ class TypeApproximator {
|
||||
|
||||
if (conf.flexible) {
|
||||
/**
|
||||
* Let inputTypes = L_1..U_1; resultType = L_2..U_2
|
||||
* We should create resultType such as inputTypes <: resultType.
|
||||
* It means that if A <: inputTypes, then A <: U_1. And, because inputTypes <: resultType,
|
||||
* 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.
|
||||
@@ -147,7 +147,7 @@ class TypeApproximator {
|
||||
|
||||
/**
|
||||
* If C <: L..U then C <: L.
|
||||
* inputTypes.lower <: lowerResult => inputTypes.lower <: lowerResult?.lowerIfFlexible()
|
||||
* 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.
|
||||
|
||||
32
compiler/testData/codegen/box/regressions/approximateGenericTypeWithIntersectionType.kt
vendored
Normal file
32
compiler/testData/codegen/box/regressions/approximateGenericTypeWithIntersectionType.kt
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
// WITH_RUNTIME
|
||||
|
||||
// FILE: First.java
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Iterator;
|
||||
|
||||
public class First {
|
||||
public static <A> List<A> from(List<A> var0) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// FILE: second.kt
|
||||
|
||||
fun <T> List<T>.listFromJava() = First.from(this)
|
||||
fun <T> List<T>.listFromKotlin() = fromKotlin(this)
|
||||
|
||||
fun <T> fromKotlin(var0: List<T?>): List<T?> = var0
|
||||
|
||||
fun test(a: List<Int>) {
|
||||
val b: List<Int>? = a.listFromJava()
|
||||
val c: List<Int?> = a.listFromKotlin()
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
test(listOf(1))
|
||||
return "OK"
|
||||
}
|
||||
|
||||
|
||||
|
||||
14
compiler/testData/codegen/box/regressions/dontCaptureTypesWithTypeVariables.kt
vendored
Normal file
14
compiler/testData/codegen/box/regressions/dontCaptureTypesWithTypeVariables.kt
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
fun test(i: Inv<out Any?>) {
|
||||
foo(i.superclass())
|
||||
}
|
||||
|
||||
fun <T> foo(x: T) {}
|
||||
|
||||
class Inv<T>
|
||||
|
||||
fun <T> Inv<T>.superclass(): Inv<in T> = Inv()
|
||||
|
||||
fun box(): String {
|
||||
test(Inv())
|
||||
return "OK"
|
||||
}
|
||||
8
compiler/testData/codegen/box/regressions/functionLiteralAsLastExpressionInBlock.kt
vendored
Normal file
8
compiler/testData/codegen/box/regressions/functionLiteralAsLastExpressionInBlock.kt
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
fun box(): String {
|
||||
val p: (String) -> Boolean = if (true) {
|
||||
{ true }
|
||||
} else {
|
||||
{ true }
|
||||
}
|
||||
return "OK"
|
||||
}
|
||||
14
compiler/testData/codegen/box/regressions/itInsideComplexLambda.kt
vendored
Normal file
14
compiler/testData/codegen/box/regressions/itInsideComplexLambda.kt
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
class MyList<T>
|
||||
|
||||
operator fun <T> MyList<T>.plusAssign(element: T) {}
|
||||
|
||||
val listOfFunctions = MyList<(Int) -> Int>()
|
||||
|
||||
fun foo() {
|
||||
listOfFunctions.plusAssign({ it -> it })
|
||||
listOfFunctions += { it -> it }
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
return "OK"
|
||||
}
|
||||
5
compiler/testData/codegen/box/regressions/lambdaAsLastExpressionInLambda.kt
vendored
Normal file
5
compiler/testData/codegen/box/regressions/lambdaAsLastExpressionInLambda.kt
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
val foo: ((String) -> String) = run {
|
||||
{ it }
|
||||
}
|
||||
|
||||
fun box() = foo("OK")
|
||||
10
compiler/testData/codegen/box/regressions/noCapturingForTypesWithTypeVariables.kt
vendored
Normal file
10
compiler/testData/codegen/box/regressions/noCapturingForTypesWithTypeVariables.kt
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
fun foo(useScriptArgs: Array<out Any?>?) {
|
||||
val constructorArgs: Array<out Any?> = arrayOf(useScriptArgs.orEmpty())
|
||||
}
|
||||
|
||||
inline fun <reified T> Array<out T>?.orEmpty(): Array<out T> = this ?: emptyArray<T>()
|
||||
|
||||
fun box(): String {
|
||||
foo(arrayOf(1))
|
||||
return "OK"
|
||||
}
|
||||
5
compiler/testData/codegen/box/regressions/noResolutionRecursion.kt
vendored
Normal file
5
compiler/testData/codegen/box/regressions/noResolutionRecursion.kt
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
fun <T> T.at(element: Int) = this.at()
|
||||
|
||||
fun <T> T.at(): T = this
|
||||
|
||||
fun box(): String = "OK".at()
|
||||
10
compiler/testData/codegen/box/regressions/useBoundWhenThereIsNoFixedVariables.kt
vendored
Normal file
10
compiler/testData/codegen/box/regressions/useBoundWhenThereIsNoFixedVariables.kt
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
fun <X : Y, Y> X.foo(y: Y) {}
|
||||
|
||||
fun test(x: (Int) -> Unit) {
|
||||
x.foo { it.toByte() }
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
test { it -> }
|
||||
return "OK"
|
||||
}
|
||||
10
compiler/testData/diagnostics/tests/regressions/delegationWithReceiver.kt
vendored
Normal file
10
compiler/testData/diagnostics/tests/regressions/delegationWithReceiver.kt
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
class MyMetadata<in T, R>(val default: R) {
|
||||
operator fun getValue(thisRef: T, desc: KProperty<*>): R = TODO()
|
||||
operator fun setValue(thisRef: T, desc: KProperty<*>, value: R) {}
|
||||
}
|
||||
|
||||
interface Something
|
||||
class MyReceiver
|
||||
var MyReceiver.something: Something? by MyMetadata(default = null)
|
||||
26
compiler/testData/diagnostics/tests/regressions/delegationWithReceiver.txt
vendored
Normal file
26
compiler/testData/diagnostics/tests/regressions/delegationWithReceiver.txt
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
package
|
||||
|
||||
public var MyReceiver.something: Something?
|
||||
|
||||
public final class MyMetadata</*0*/ in T, /*1*/ R> {
|
||||
public constructor MyMetadata</*0*/ in T, /*1*/ R>(/*0*/ default: R)
|
||||
public final val default: R
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public final operator fun getValue(/*0*/ thisRef: T, /*1*/ desc: kotlin.reflect.KProperty<*>): R
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public final operator fun setValue(/*0*/ thisRef: T, /*1*/ desc: kotlin.reflect.KProperty<*>, /*2*/ value: R): kotlin.Unit
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public final class MyReceiver {
|
||||
public constructor MyReceiver()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public interface Something {
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
7
compiler/testData/diagnostics/tests/regressions/propertyWithExtensionTypeInvoke.kt
vendored
Normal file
7
compiler/testData/diagnostics/tests/regressions/propertyWithExtensionTypeInvoke.kt
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
object X
|
||||
|
||||
class Y {
|
||||
fun f(op: X.() -> Unit) {
|
||||
X.op()
|
||||
}
|
||||
}
|
||||
16
compiler/testData/diagnostics/tests/regressions/propertyWithExtensionTypeInvoke.txt
vendored
Normal file
16
compiler/testData/diagnostics/tests/regressions/propertyWithExtensionTypeInvoke.txt
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
package
|
||||
|
||||
public object X {
|
||||
private constructor X()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public final class Y {
|
||||
public constructor Y()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public final fun f(/*0*/ op: X.() -> kotlin.Unit): kotlin.Unit
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
@@ -16556,6 +16556,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/regressions"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
|
||||
}
|
||||
|
||||
@TestMetadata("approximateGenericTypeWithIntersectionType.kt")
|
||||
public void testApproximateGenericTypeWithIntersectionType() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/approximateGenericTypeWithIntersectionType.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("arrayLengthNPE.kt")
|
||||
public void testArrayLengthNPE() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/arrayLengthNPE.kt");
|
||||
@@ -16580,6 +16586,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("dontCaptureTypesWithTypeVariables.kt")
|
||||
public void testDontCaptureTypesWithTypeVariables() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/dontCaptureTypesWithTypeVariables.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("doubleMerge.kt")
|
||||
public void testDoubleMerge() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/doubleMerge.kt");
|
||||
@@ -16592,6 +16604,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("functionLiteralAsLastExpressionInBlock.kt")
|
||||
public void testFunctionLiteralAsLastExpressionInBlock() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/functionLiteralAsLastExpressionInBlock.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("generic.kt")
|
||||
public void testGeneric() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/generic.kt");
|
||||
@@ -16622,6 +16640,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("itInsideComplexLambda.kt")
|
||||
public void testItInsideComplexLambda() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/itInsideComplexLambda.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("kt10143.kt")
|
||||
public void testKt10143() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/kt10143.kt");
|
||||
@@ -16964,12 +16988,30 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("lambdaAsLastExpressionInLambda.kt")
|
||||
public void testLambdaAsLastExpressionInLambda() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/lambdaAsLastExpressionInLambda.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("nestedIntersection.kt")
|
||||
public void testNestedIntersection() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/nestedIntersection.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("noCapturingForTypesWithTypeVariables.kt")
|
||||
public void testNoCapturingForTypesWithTypeVariables() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/noCapturingForTypesWithTypeVariables.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("noResolutionRecursion.kt")
|
||||
public void testNoResolutionRecursion() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/noResolutionRecursion.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("nullabilityForCommonCapturedSupertypes.kt")
|
||||
public void testNullabilityForCommonCapturedSupertypes() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/nullabilityForCommonCapturedSupertypes.kt");
|
||||
@@ -16999,6 +17041,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/typeCastException.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("useBoundWhenThereIsNoFixedVariables.kt")
|
||||
public void testUseBoundWhenThereIsNoFixedVariables() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/useBoundWhenThereIsNoFixedVariables.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/reified")
|
||||
|
||||
@@ -16702,6 +16702,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("delegationWithReceiver.kt")
|
||||
public void testDelegationWithReceiver() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/regressions/delegationWithReceiver.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("DoubleDefine.kt")
|
||||
public void testDoubleDefine() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/regressions/DoubleDefine.kt");
|
||||
@@ -17470,6 +17476,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("propertyWithExtensionTypeInvoke.kt")
|
||||
public void testPropertyWithExtensionTypeInvoke() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/regressions/propertyWithExtensionTypeInvoke.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("resolveSubclassOfList.kt")
|
||||
public void testResolveSubclassOfList() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/regressions/resolveSubclassOfList.kt");
|
||||
|
||||
@@ -16556,6 +16556,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/regressions"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
|
||||
}
|
||||
|
||||
@TestMetadata("approximateGenericTypeWithIntersectionType.kt")
|
||||
public void testApproximateGenericTypeWithIntersectionType() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/approximateGenericTypeWithIntersectionType.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("arrayLengthNPE.kt")
|
||||
public void testArrayLengthNPE() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/arrayLengthNPE.kt");
|
||||
@@ -16580,6 +16586,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("dontCaptureTypesWithTypeVariables.kt")
|
||||
public void testDontCaptureTypesWithTypeVariables() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/dontCaptureTypesWithTypeVariables.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("doubleMerge.kt")
|
||||
public void testDoubleMerge() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/doubleMerge.kt");
|
||||
@@ -16592,6 +16604,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("functionLiteralAsLastExpressionInBlock.kt")
|
||||
public void testFunctionLiteralAsLastExpressionInBlock() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/functionLiteralAsLastExpressionInBlock.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("generic.kt")
|
||||
public void testGeneric() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/generic.kt");
|
||||
@@ -16622,6 +16640,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("itInsideComplexLambda.kt")
|
||||
public void testItInsideComplexLambda() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/itInsideComplexLambda.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("kt10143.kt")
|
||||
public void testKt10143() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/kt10143.kt");
|
||||
@@ -16964,12 +16988,30 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("lambdaAsLastExpressionInLambda.kt")
|
||||
public void testLambdaAsLastExpressionInLambda() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/lambdaAsLastExpressionInLambda.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("nestedIntersection.kt")
|
||||
public void testNestedIntersection() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/nestedIntersection.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("noCapturingForTypesWithTypeVariables.kt")
|
||||
public void testNoCapturingForTypesWithTypeVariables() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/noCapturingForTypesWithTypeVariables.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("noResolutionRecursion.kt")
|
||||
public void testNoResolutionRecursion() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/noResolutionRecursion.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("nullabilityForCommonCapturedSupertypes.kt")
|
||||
public void testNullabilityForCommonCapturedSupertypes() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/nullabilityForCommonCapturedSupertypes.kt");
|
||||
@@ -16999,6 +17041,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/typeCastException.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("useBoundWhenThereIsNoFixedVariables.kt")
|
||||
public void testUseBoundWhenThereIsNoFixedVariables() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/useBoundWhenThereIsNoFixedVariables.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/reified")
|
||||
|
||||
@@ -16556,6 +16556,12 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/regressions"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
|
||||
}
|
||||
|
||||
@TestMetadata("approximateGenericTypeWithIntersectionType.kt")
|
||||
public void testApproximateGenericTypeWithIntersectionType() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/approximateGenericTypeWithIntersectionType.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("arrayLengthNPE.kt")
|
||||
public void testArrayLengthNPE() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/arrayLengthNPE.kt");
|
||||
@@ -16580,6 +16586,12 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("dontCaptureTypesWithTypeVariables.kt")
|
||||
public void testDontCaptureTypesWithTypeVariables() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/dontCaptureTypesWithTypeVariables.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("doubleMerge.kt")
|
||||
public void testDoubleMerge() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/doubleMerge.kt");
|
||||
@@ -16592,6 +16604,12 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("functionLiteralAsLastExpressionInBlock.kt")
|
||||
public void testFunctionLiteralAsLastExpressionInBlock() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/functionLiteralAsLastExpressionInBlock.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("generic.kt")
|
||||
public void testGeneric() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/generic.kt");
|
||||
@@ -16622,6 +16640,12 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("itInsideComplexLambda.kt")
|
||||
public void testItInsideComplexLambda() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/itInsideComplexLambda.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("kt10143.kt")
|
||||
public void testKt10143() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/kt10143.kt");
|
||||
@@ -16964,12 +16988,30 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("lambdaAsLastExpressionInLambda.kt")
|
||||
public void testLambdaAsLastExpressionInLambda() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/lambdaAsLastExpressionInLambda.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("nestedIntersection.kt")
|
||||
public void testNestedIntersection() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/nestedIntersection.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("noCapturingForTypesWithTypeVariables.kt")
|
||||
public void testNoCapturingForTypesWithTypeVariables() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/noCapturingForTypesWithTypeVariables.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("noResolutionRecursion.kt")
|
||||
public void testNoResolutionRecursion() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/noResolutionRecursion.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("nullabilityForCommonCapturedSupertypes.kt")
|
||||
public void testNullabilityForCommonCapturedSupertypes() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/nullabilityForCommonCapturedSupertypes.kt");
|
||||
@@ -16999,6 +17041,12 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/typeCastException.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("useBoundWhenThereIsNoFixedVariables.kt")
|
||||
public void testUseBoundWhenThereIsNoFixedVariables() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/useBoundWhenThereIsNoFixedVariables.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/reified")
|
||||
|
||||
@@ -277,8 +277,6 @@ public abstract class KotlinBuiltIns {
|
||||
|
||||
public final FqNameUnsafe functionSupertype = fqNameUnsafe("Function");
|
||||
|
||||
|
||||
|
||||
public final FqName throwable = fqName("Throwable");
|
||||
public final FqName comparable = fqName("Comparable");
|
||||
|
||||
|
||||
@@ -20198,6 +20198,12 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/regressions"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS, true);
|
||||
}
|
||||
|
||||
@TestMetadata("approximateGenericTypeWithIntersectionType.kt")
|
||||
public void testApproximateGenericTypeWithIntersectionType() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/approximateGenericTypeWithIntersectionType.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("arrayLengthNPE.kt")
|
||||
public void testArrayLengthNPE() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/arrayLengthNPE.kt");
|
||||
@@ -20228,6 +20234,12 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("dontCaptureTypesWithTypeVariables.kt")
|
||||
public void testDontCaptureTypesWithTypeVariables() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/dontCaptureTypesWithTypeVariables.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("doubleMerge.kt")
|
||||
public void testDoubleMerge() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/doubleMerge.kt");
|
||||
@@ -20240,6 +20252,12 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("functionLiteralAsLastExpressionInBlock.kt")
|
||||
public void testFunctionLiteralAsLastExpressionInBlock() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/functionLiteralAsLastExpressionInBlock.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("generic.kt")
|
||||
public void testGeneric() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/generic.kt");
|
||||
@@ -20276,6 +20294,12 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("itInsideComplexLambda.kt")
|
||||
public void testItInsideComplexLambda() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/itInsideComplexLambda.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("kt10143.kt")
|
||||
public void testKt10143() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/kt10143.kt");
|
||||
@@ -20732,6 +20756,12 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("lambdaAsLastExpressionInLambda.kt")
|
||||
public void testLambdaAsLastExpressionInLambda() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/lambdaAsLastExpressionInLambda.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("nestedIntersection.kt")
|
||||
public void testNestedIntersection() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/nestedIntersection.kt");
|
||||
@@ -20744,6 +20774,18 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
||||
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
|
||||
}
|
||||
|
||||
@TestMetadata("noCapturingForTypesWithTypeVariables.kt")
|
||||
public void testNoCapturingForTypesWithTypeVariables() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/noCapturingForTypesWithTypeVariables.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("noResolutionRecursion.kt")
|
||||
public void testNoResolutionRecursion() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/noResolutionRecursion.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("nullabilityForCommonCapturedSupertypes.kt")
|
||||
public void testNullabilityForCommonCapturedSupertypes() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/nullabilityForCommonCapturedSupertypes.kt");
|
||||
@@ -20785,6 +20827,12 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
||||
}
|
||||
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
|
||||
}
|
||||
|
||||
@TestMetadata("useBoundWhenThereIsNoFixedVariables.kt")
|
||||
public void testUseBoundWhenThereIsNoFixedVariables() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/useBoundWhenThereIsNoFixedVariables.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/reified")
|
||||
|
||||
Reference in New Issue
Block a user