Compare commits

...

26 Commits

Author SHA1 Message Date
zarechenskiy
f6081fd9dd [NI] Use proper bound for lambda if expected type is type variable 2017-08-18 20:43:30 +03:00
Mikhail Zarechenskiy
a5222b0558 [NI] Resolve function literals in block as lambda expression 2017-08-18 18:47:40 +03:00
Mikhail Zarechenskiy
e07a135ee8 [NI] Get rid of intersection types from constraint system 2017-08-18 18:39:30 +03:00
Mikhail Zarechenskiy
d872621edc [NI] Avoid type capturing for types that can contain type variables 2017-08-18 18:39:25 +03:00
Mikhail Zarechenskiy
a67e578a28 [NI] Store setValue with fresh type variables before substitution 2017-08-18 18:31:55 +03:00
Mikhail Zarechenskiy
ba3a1d5d83 [NI] Add getters to avoid inspections about useless boolean expressions 2017-08-18 18:31:51 +03:00
Mikhail Zarechenskiy
4b0890d9f8 [NI] Pass candidates with wrong visibility in debugger context
See test 'privateMembersPriority' (KT-10634)
2017-08-18 18:30:39 +03:00
Mikhail Zarechenskiy
2d8a56dbd9 [NI] Fix KNPE, exception occurred when element is synthetic 2017-08-18 18:28:27 +03:00
Mikhail Zarechenskiy
ba61919795 [NI] Fix exception explicit qualified receiver and dispatch receiver 2017-08-18 18:28:22 +03:00
Stanislav Erokhin
b4149b0b5b Add test for lambda as last expression in lambda 2017-08-18 18:06:40 +03:00
Stanislav Erokhin
4a367f3b56 Add regression test for no resolution recursion 2017-08-18 18:06:39 +03:00
Stanislav Erokhin
04636a5497 [NI] Support smartcast info in ResolvedCall on receivers 2017-08-18 18:06:37 +03:00
Stanislav Erokhin
d1af799f97 [NI] Introduced ResolutionAtom's
Introduced new model for resolution result: tree of ResolvedAtoms.
Moved all postprocessing for arguments to front-end module.
Do not create freshDescriptor -- use freshTypeSubstitutor directly.
Removed Candidates for variables+invoke.
Add lazy way for argument analysis -- do not analyze all arguments
if we have subtyping error in first argument, but if we want report
all errors, then all arguments checks will be performed.

Future improvements:
  - optimize constraint system usage inside ResolutionCandidate
  - improve constraint system API
  - improve diagnostic handlers
2017-08-18 18:06:36 +03:00
Stanislav Erokhin
c6aeb954c8 Minor. rename ConstraintSystemCompleter
In front-end we have other ConstraintSystemCompleter and because of this
in dist we have ambiguity(because there all src folders compiles inside
same module.
2017-08-18 18:06:35 +03:00
Stanislav Erokhin
fc3479405a ++ fixation order refactoring 2017-08-18 18:06:34 +03:00
Stanislav Erokhin
8a085f8219 [NI] Implement next call completer.
Type inference completer features:
  - type variables depended from result type will be fixed in the end
  - type variables with proper constraints will be fixed first
  - fixation via groups "accessible" via constraints is supported

 TODO:
  - stable order via PSI order
  - argument constraint should rewrite position if constraint is the
      same as upper bound for type parameter
2017-08-18 18:06:33 +03:00
Stanislav Erokhin
f51f5576c8 [NI] Extract logic about fixation order to separated component 2017-08-18 18:06:31 +03:00
Stanislav Erokhin
5c0833fb47 [NI] Use right scope for callable reference resolution
Previously was used scope for top-level call. It isn't correct because
if we have callable reference inside lambda -> scope is different.
2017-08-18 18:06:30 +03:00
Stanislav Erokhin
7d8820fc82 Support isSuccessful in SuccessfulResultCollector
Since now SuccessfulResultCollector do not run computation of
resultingApplicability for error candidate before
getFinalCandidates(). It is very useful because we can do not run
all checks for error candidates if we have not-error candidate.
2017-08-18 18:06:29 +03:00
Stanislav Erokhin
ab5088c4b2 Refactoring. Remove ResolutionCandidateStatus.
Use diagnostics directly.
Also TowerCandidate since now know only about applicability
and not about diagnostics itself.
2017-08-18 18:06:28 +03:00
Stanislav Erokhin
b9be1b306b [NI] Fix resolution for callable references to nested class members 2017-08-18 18:06:27 +03:00
Stanislav Erokhin
e245b7edf0 [NI] Do not take type advice for delegation if type is not fixed 2017-08-18 18:06:26 +03:00
Stanislav Erokhin
5f4ca7a341 [NI] Fixes after review 2017-08-18 18:06:24 +03:00
Stanislav Erokhin
b4e79424f6 [NI] Refactoring: KotlinCallContext to stateless component (2) 2017-08-18 18:06:23 +03:00
Stanislav Erokhin
6839efe48e [NI] Refactoring: KotlinCallContext to stateless component (1) 2017-08-18 18:06:22 +03:00
Stanislav Erokhin
61992aeefd [NI] Add common supertype for PSI lambda arguments
Also move initial dataFlowInfo to lambda arguments.
As result, we can not store outer call for postpone call arguments
2017-08-18 18:06:21 +03:00
78 changed files with 2804 additions and 1798 deletions

View File

@@ -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(

View File

@@ -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);

View File

@@ -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 } }
}
}
}

View File

@@ -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) {

View File

@@ -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;
}
}

View File

@@ -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)
}
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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)
}
}
}

View File

@@ -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> {

View File

@@ -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))

View File

@@ -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
}

View File

@@ -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)
}
}

View File

@@ -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);

View File

@@ -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)
}
}

View File

@@ -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

View File

@@ -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)
}
}
}
}
}

View File

@@ -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

View File

@@ -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
}
}

View File

@@ -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)
}
}

View File

@@ -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)
}

View File

@@ -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) }
}
}

View File

@@ -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] })
)
}

View File

@@ -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)
}

View File

@@ -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())
}
}

View File

@@ -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)
}
}
}

View File

@@ -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
}

View File

@@ -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)
}
}
}

View File

@@ -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() }

View File

@@ -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
}

View File

@@ -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
}
}
}

View File

@@ -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)
}

View File

@@ -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)
}
}

View File

@@ -150,4 +150,8 @@ class FreshVariableNewTypeSubstitutor(val freshVariables: List<TypeVariableFromC
return typeVariable.defaultType
}
companion object {
val Empty = FreshVariableNewTypeSubstitutor(emptyList())
}
}

View File

@@ -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(

View File

@@ -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 {

View File

@@ -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
}

View File

@@ -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)
}
}
}
}
}

View File

@@ -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
}
}

View File

@@ -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) }
}

View File

@@ -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"
}
}

View File

@@ -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()
}
}

View File

@@ -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()
}

View File

@@ -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)
}
}

View File

@@ -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(

View File

@@ -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) {

View File

@@ -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 {

View File

@@ -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)
}
}

View File

@@ -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();

View File

@@ -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()

View File

@@ -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())
}

View File

@@ -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"
}

View File

@@ -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>

View File

@@ -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
) {

View File

@@ -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

View File

@@ -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)
)

View File

@@ -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)
}

View File

@@ -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
}
}

View File

@@ -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
}

View File

@@ -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.

View 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"
}

View 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"
}

View File

@@ -0,0 +1,8 @@
fun box(): String {
val p: (String) -> Boolean = if (true) {
{ true }
} else {
{ true }
}
return "OK"
}

View 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"
}

View File

@@ -0,0 +1,5 @@
val foo: ((String) -> String) = run {
{ it }
}
fun box() = foo("OK")

View 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"
}

View File

@@ -0,0 +1,5 @@
fun <T> T.at(element: Int) = this.at()
fun <T> T.at(): T = this
fun box(): String = "OK".at()

View 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"
}

View 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)

View 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
}

View File

@@ -0,0 +1,7 @@
object X
class Y {
fun f(op: X.() -> Unit) {
X.op()
}
}

View 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
}

View File

@@ -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")

View File

@@ -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");

View File

@@ -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")

View File

@@ -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")

View File

@@ -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");

View File

@@ -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")