[NI] Use context for relevant nested call to run call checkers
#KT-24808 Fixed
This commit is contained in:
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor;
|
|||||||
import org.jetbrains.kotlin.name.FqName;
|
import org.jetbrains.kotlin.name.FqName;
|
||||||
import org.jetbrains.kotlin.name.FqNameUnsafe;
|
import org.jetbrains.kotlin.name.FqNameUnsafe;
|
||||||
import org.jetbrains.kotlin.psi.*;
|
import org.jetbrains.kotlin.psi.*;
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext;
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemCompleter;
|
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemCompleter;
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.PartialCallResolutionResult;
|
import org.jetbrains.kotlin.resolve.calls.model.PartialCallResolutionResult;
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
|
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
|
||||||
@@ -118,6 +119,7 @@ public interface BindingContext {
|
|||||||
|
|
||||||
WritableSlice<Call, ResolvedCall<?>> RESOLVED_CALL = new BasicWritableSlice<>(DO_NOTHING);
|
WritableSlice<Call, ResolvedCall<?>> RESOLVED_CALL = new BasicWritableSlice<>(DO_NOTHING);
|
||||||
WritableSlice<Call, PartialCallResolutionResult> ONLY_RESOLVED_CALL = new BasicWritableSlice<>(DO_NOTHING);
|
WritableSlice<Call, PartialCallResolutionResult> ONLY_RESOLVED_CALL = new BasicWritableSlice<>(DO_NOTHING);
|
||||||
|
WritableSlice<Call, BasicCallResolutionContext> PARTIAL_CALL_RESOLUTION_CONTEXT = new BasicWritableSlice<>(DO_NOTHING);
|
||||||
WritableSlice<KtExpression, Call> DELEGATE_EXPRESSION_TO_PROVIDE_DELEGATE_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<Call, TailRecursionKind> TAIL_RECURSION_CALL = Slices.createSimpleSlice();
|
||||||
WritableSlice<KtElement, ConstraintSystemCompleter> CONSTRAINT_SYSTEM_COMPLETER = new BasicWritableSlice<>(DO_NOTHING);
|
WritableSlice<KtElement, ConstraintSystemCompleter> CONSTRAINT_SYSTEM_COMPLETER = new BasicWritableSlice<>(DO_NOTHING);
|
||||||
|
|||||||
+1
-1
@@ -198,7 +198,7 @@ class CoroutineInferenceSession(
|
|||||||
context: BasicCallResolutionContext
|
context: BasicCallResolutionContext
|
||||||
): ResolvedAtomCompleter {
|
): ResolvedAtomCompleter {
|
||||||
return ResolvedAtomCompleter(
|
return ResolvedAtomCompleter(
|
||||||
resultSubstitutor, context.trace, context, kotlinToResolvedCallTransformer,
|
resultSubstitutor, context, kotlinToResolvedCallTransformer,
|
||||||
expressionTypingServices, argumentTypeResolver, doubleColonExpressionResolver, builtIns,
|
expressionTypingServices, argumentTypeResolver, doubleColonExpressionResolver, builtIns,
|
||||||
deprecationResolver, moduleDescriptor, context.dataFlowValueFactory
|
deprecationResolver, moduleDescriptor, context.dataFlowValueFactory
|
||||||
)
|
)
|
||||||
|
|||||||
+3
-1
@@ -89,6 +89,8 @@ class KotlinToResolvedCallTransformer(
|
|||||||
psiKotlinCall.psiCall
|
psiKotlinCall.psiCall
|
||||||
|
|
||||||
context.trace.record(BindingContext.ONLY_RESOLVED_CALL, psiCall, baseResolvedCall)
|
context.trace.record(BindingContext.ONLY_RESOLVED_CALL, psiCall, baseResolvedCall)
|
||||||
|
context.trace.record(BindingContext.PARTIAL_CALL_RESOLUTION_CONTEXT, psiCall, context)
|
||||||
|
|
||||||
context.inferenceSession.addPartialCallInfo(
|
context.inferenceSession.addPartialCallInfo(
|
||||||
PSIPartialCallInfo(baseResolvedCall, context, tracingStrategy)
|
PSIPartialCallInfo(baseResolvedCall, context, tracingStrategy)
|
||||||
)
|
)
|
||||||
@@ -114,7 +116,7 @@ class KotlinToResolvedCallTransformer(
|
|||||||
|
|
||||||
val resultSubstitutor = baseResolvedCall.constraintSystem.buildResultingSubstitutor()
|
val resultSubstitutor = baseResolvedCall.constraintSystem.buildResultingSubstitutor()
|
||||||
val ktPrimitiveCompleter = ResolvedAtomCompleter(
|
val ktPrimitiveCompleter = ResolvedAtomCompleter(
|
||||||
resultSubstitutor, context.trace, context, this, expressionTypingServices, argumentTypeResolver,
|
resultSubstitutor, context, this, expressionTypingServices, argumentTypeResolver,
|
||||||
doubleColonExpressionResolver, builtIns, deprecationResolver, moduleDescriptor, dataFlowValueFactory
|
doubleColonExpressionResolver, builtIns, deprecationResolver, moduleDescriptor, dataFlowValueFactory
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
+30
-17
@@ -40,18 +40,18 @@ import org.jetbrains.kotlin.types.typeUtil.asTypeProjection
|
|||||||
|
|
||||||
class ResolvedAtomCompleter(
|
class ResolvedAtomCompleter(
|
||||||
private val resultSubstitutor: NewTypeSubstitutor,
|
private val resultSubstitutor: NewTypeSubstitutor,
|
||||||
private val trace: BindingTrace,
|
|
||||||
private val topLevelCallContext: BasicCallResolutionContext,
|
private val topLevelCallContext: BasicCallResolutionContext,
|
||||||
private val kotlinToResolvedCallTransformer: KotlinToResolvedCallTransformer,
|
private val kotlinToResolvedCallTransformer: KotlinToResolvedCallTransformer,
|
||||||
private val expressionTypingServices: ExpressionTypingServices,
|
private val expressionTypingServices: ExpressionTypingServices,
|
||||||
private val argumentTypeResolver: ArgumentTypeResolver,
|
private val argumentTypeResolver: ArgumentTypeResolver,
|
||||||
private val doubleColonExpressionResolver: DoubleColonExpressionResolver,
|
private val doubleColonExpressionResolver: DoubleColonExpressionResolver,
|
||||||
private val builtIns: KotlinBuiltIns,
|
private val builtIns: KotlinBuiltIns,
|
||||||
deprecationResolver: DeprecationResolver,
|
private val deprecationResolver: DeprecationResolver,
|
||||||
moduleDescriptor: ModuleDescriptor,
|
private val moduleDescriptor: ModuleDescriptor,
|
||||||
private val dataFlowValueFactory: DataFlowValueFactory
|
private val dataFlowValueFactory: DataFlowValueFactory
|
||||||
) {
|
) {
|
||||||
private val callCheckerContext = CallCheckerContext(topLevelCallContext, deprecationResolver, moduleDescriptor)
|
private val topLevelCallCheckerContext = CallCheckerContext(topLevelCallContext, deprecationResolver, moduleDescriptor)
|
||||||
|
private val topLevelTrace = topLevelCallCheckerContext.trace
|
||||||
|
|
||||||
private fun complete(resolvedAtom: ResolvedAtom) {
|
private fun complete(resolvedAtom: ResolvedAtom) {
|
||||||
when (resolvedAtom) {
|
when (resolvedAtom) {
|
||||||
@@ -75,15 +75,28 @@ class ResolvedAtomCompleter(
|
|||||||
|
|
||||||
val resolvedCall = kotlinToResolvedCallTransformer.transformToResolvedCall<CallableDescriptor>(
|
val resolvedCall = kotlinToResolvedCallTransformer.transformToResolvedCall<CallableDescriptor>(
|
||||||
resolvedCallAtom,
|
resolvedCallAtom,
|
||||||
trace,
|
topLevelTrace,
|
||||||
resultSubstitutor,
|
resultSubstitutor,
|
||||||
diagnostics
|
diagnostics
|
||||||
)
|
)
|
||||||
kotlinToResolvedCallTransformer.bindAndReport(topLevelCallContext, trace, resolvedCall, diagnostics)
|
|
||||||
|
val resolutionContextForPartialCall =
|
||||||
|
topLevelCallContext.trace[BindingContext.PARTIAL_CALL_RESOLUTION_CONTEXT, resolvedCallAtom.atom.psiKotlinCall.psiCall]
|
||||||
|
|
||||||
|
val callCheckerContext = if (resolutionContextForPartialCall != null)
|
||||||
|
CallCheckerContext(
|
||||||
|
resolutionContextForPartialCall.replaceBindingTrace(topLevelTrace),
|
||||||
|
deprecationResolver,
|
||||||
|
moduleDescriptor
|
||||||
|
)
|
||||||
|
else
|
||||||
|
topLevelCallCheckerContext
|
||||||
|
|
||||||
|
kotlinToResolvedCallTransformer.bindAndReport(topLevelCallContext, topLevelTrace, resolvedCall, diagnostics)
|
||||||
kotlinToResolvedCallTransformer.runCallCheckers(resolvedCall, callCheckerContext)
|
kotlinToResolvedCallTransformer.runCallCheckers(resolvedCall, callCheckerContext)
|
||||||
|
|
||||||
val lastCall = if (resolvedCall is VariableAsFunctionResolvedCall) resolvedCall.functionCall else resolvedCall
|
val lastCall = if (resolvedCall is VariableAsFunctionResolvedCall) resolvedCall.functionCall else resolvedCall
|
||||||
kotlinToResolvedCallTransformer.runArgumentsChecks(topLevelCallContext, trace, lastCall as NewResolvedCallImpl<*>)
|
kotlinToResolvedCallTransformer.runArgumentsChecks(topLevelCallContext, topLevelTrace, lastCall as NewResolvedCallImpl<*>)
|
||||||
|
|
||||||
return resolvedCall
|
return resolvedCall
|
||||||
}
|
}
|
||||||
@@ -91,14 +104,14 @@ class ResolvedAtomCompleter(
|
|||||||
private fun completeLambda(lambda: ResolvedLambdaAtom) {
|
private fun completeLambda(lambda: ResolvedLambdaAtom) {
|
||||||
val returnType = resultSubstitutor.safeSubstitute(lambda.returnType)
|
val returnType = resultSubstitutor.safeSubstitute(lambda.returnType)
|
||||||
|
|
||||||
updateTraceForLambda(lambda, trace, returnType)
|
updateTraceForLambda(lambda, topLevelTrace, returnType)
|
||||||
|
|
||||||
for (lambdaResult in lambda.resultArguments) {
|
for (lambdaResult in lambda.resultArguments) {
|
||||||
val resultValueArgument = lambdaResult as? PSIKotlinCallArgument ?: continue
|
val resultValueArgument = lambdaResult as? PSIKotlinCallArgument ?: continue
|
||||||
val newContext =
|
val newContext =
|
||||||
topLevelCallContext.replaceDataFlowInfo(resultValueArgument.dataFlowInfoAfterThisArgument)
|
topLevelCallContext.replaceDataFlowInfo(resultValueArgument.dataFlowInfoAfterThisArgument)
|
||||||
.replaceExpectedType(returnType)
|
.replaceExpectedType(returnType)
|
||||||
.replaceBindingTrace(trace)
|
.replaceBindingTrace(topLevelTrace)
|
||||||
|
|
||||||
val argumentExpression = resultValueArgument.valueArgument.getArgumentExpression() ?: continue
|
val argumentExpression = resultValueArgument.valueArgument.getArgumentExpression() ?: continue
|
||||||
kotlinToResolvedCallTransformer.updateRecordedType(argumentExpression, newContext, true)
|
kotlinToResolvedCallTransformer.updateRecordedType(argumentExpression, newContext, true)
|
||||||
@@ -179,7 +192,7 @@ class ResolvedAtomCompleter(
|
|||||||
// write down type for callable reference expression
|
// write down type for callable reference expression
|
||||||
val resultType = resultSubstitutor.safeSubstitute(callableCandidate.reflectionCandidateType, Variance.INVARIANT)
|
val resultType = resultSubstitutor.safeSubstitute(callableCandidate.reflectionCandidateType, Variance.INVARIANT)
|
||||||
argumentTypeResolver.updateResultArgumentTypeIfNotDenotable(
|
argumentTypeResolver.updateResultArgumentTypeIfNotDenotable(
|
||||||
trace, expressionTypingServices.statementFilter,
|
topLevelTrace, expressionTypingServices.statementFilter,
|
||||||
resultType,
|
resultType,
|
||||||
callableReferenceExpression
|
callableReferenceExpression
|
||||||
)
|
)
|
||||||
@@ -195,7 +208,7 @@ class ResolvedAtomCompleter(
|
|||||||
val psiCall = CallMaker.makeCall(reference, explicitReceiver?.receiverValue, null, reference, emptyList())
|
val psiCall = CallMaker.makeCall(reference, explicitReceiver?.receiverValue, null, reference, emptyList())
|
||||||
|
|
||||||
val tracing = TracingStrategyImpl.create(reference, psiCall)
|
val tracing = TracingStrategyImpl.create(reference, psiCall)
|
||||||
val temporaryTrace = TemporaryBindingTrace.create(trace, "callable reference fake call")
|
val temporaryTrace = TemporaryBindingTrace.create(topLevelTrace, "callable reference fake call")
|
||||||
|
|
||||||
val resolvedCall = ResolvedCallImpl(
|
val resolvedCall = ResolvedCallImpl(
|
||||||
psiCall, callableCandidate.candidate, callableCandidate.dispatchReceiver?.receiver?.receiverValue,
|
psiCall, callableCandidate.candidate, callableCandidate.dispatchReceiver?.receiver?.receiverValue,
|
||||||
@@ -204,9 +217,9 @@ class ResolvedAtomCompleter(
|
|||||||
)
|
)
|
||||||
resolvedCall.setResultingSubstitutor(resultSubstitutor)
|
resolvedCall.setResultingSubstitutor(resultSubstitutor)
|
||||||
|
|
||||||
tracing.bindCall(trace, psiCall)
|
tracing.bindCall(topLevelTrace, psiCall)
|
||||||
tracing.bindReference(trace, resolvedCall)
|
tracing.bindReference(topLevelTrace, resolvedCall)
|
||||||
tracing.bindResolvedCall(trace, resolvedCall)
|
tracing.bindResolvedCall(topLevelTrace, resolvedCall)
|
||||||
|
|
||||||
resolvedCall.setStatusToSuccess()
|
resolvedCall.setStatusToSuccess()
|
||||||
resolvedCall.markCallAsCompleted()
|
resolvedCall.markCallAsCompleted()
|
||||||
@@ -225,8 +238,8 @@ class ResolvedAtomCompleter(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: probably we should also record key 'DATA_FLOW_INFO_BEFORE', see ExpressionTypingVisitorDispatcher.getTypeInfo
|
// TODO: probably we should also record key 'DATA_FLOW_INFO_BEFORE', see ExpressionTypingVisitorDispatcher.getTypeInfo
|
||||||
trace.recordType(callableReferenceExpression, resultType)
|
topLevelTrace.recordType(callableReferenceExpression, resultType)
|
||||||
trace.record(BindingContext.PROCESSED, callableReferenceExpression)
|
topLevelTrace.record(BindingContext.PROCESSED, callableReferenceExpression)
|
||||||
|
|
||||||
doubleColonExpressionResolver.checkReferenceIsToAllowedMember(
|
doubleColonExpressionResolver.checkReferenceIsToAllowedMember(
|
||||||
callableCandidate.candidate,
|
callableCandidate.candidate,
|
||||||
@@ -243,7 +256,7 @@ class ResolvedAtomCompleter(
|
|||||||
collectionLiteralArgument.expectedType?.let { resultSubstitutor.safeSubstitute(it) } ?: TypeUtils.NO_EXPECTED_TYPE
|
collectionLiteralArgument.expectedType?.let { resultSubstitutor.safeSubstitute(it) } ?: TypeUtils.NO_EXPECTED_TYPE
|
||||||
|
|
||||||
val actualContext = context
|
val actualContext = context
|
||||||
.replaceBindingTrace(trace)
|
.replaceBindingTrace(topLevelTrace)
|
||||||
.replaceExpectedType(expectedType)
|
.replaceExpectedType(expectedType)
|
||||||
.replaceContextDependency(ContextDependency.INDEPENDENT)
|
.replaceContextDependency(ContextDependency.INDEPENDENT)
|
||||||
|
|
||||||
|
|||||||
Vendored
+9
@@ -0,0 +1,9 @@
|
|||||||
|
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||||
|
|
||||||
|
suspend fun wrapUp2() {
|
||||||
|
withContext<Unit> {
|
||||||
|
other()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
suspend fun <T> withContext(block: suspend () -> T) {}
|
||||||
|
suspend fun <R> other(): R = TODO()
|
||||||
compiler/testData/diagnostics/testsWithStdLib/coroutines/inference/nestedSuspendCallInsideLambda.txt
Vendored
+5
@@ -0,0 +1,5 @@
|
|||||||
|
package
|
||||||
|
|
||||||
|
public suspend fun </*0*/ R> other(): R
|
||||||
|
public suspend fun </*0*/ T> withContext(/*0*/ block: suspend () -> T): kotlin.Unit
|
||||||
|
public suspend fun wrapUp2(): kotlin.Unit
|
||||||
+5
@@ -1586,6 +1586,11 @@ public class DiagnosticsTestWithStdLibGenerated extends AbstractDiagnosticsTestW
|
|||||||
runTest("compiler/testData/diagnostics/testsWithStdLib/coroutines/inference/kt15516.kt");
|
runTest("compiler/testData/diagnostics/testsWithStdLib/coroutines/inference/kt15516.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("nestedSuspendCallInsideLambda.kt")
|
||||||
|
public void testNestedSuspendCallInsideLambda() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/testsWithStdLib/coroutines/inference/nestedSuspendCallInsideLambda.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("recursiveGenerators.kt")
|
@TestMetadata("recursiveGenerators.kt")
|
||||||
public void testRecursiveGenerators() throws Exception {
|
public void testRecursiveGenerators() throws Exception {
|
||||||
runTest("compiler/testData/diagnostics/testsWithStdLib/coroutines/inference/recursiveGenerators.kt");
|
runTest("compiler/testData/diagnostics/testsWithStdLib/coroutines/inference/recursiveGenerators.kt");
|
||||||
|
|||||||
compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsTestWithStdLibUsingJavacGenerated.java
Generated
+5
@@ -1586,6 +1586,11 @@ public class DiagnosticsTestWithStdLibUsingJavacGenerated extends AbstractDiagno
|
|||||||
runTest("compiler/testData/diagnostics/testsWithStdLib/coroutines/inference/kt15516.kt");
|
runTest("compiler/testData/diagnostics/testsWithStdLib/coroutines/inference/kt15516.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("nestedSuspendCallInsideLambda.kt")
|
||||||
|
public void testNestedSuspendCallInsideLambda() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/testsWithStdLib/coroutines/inference/nestedSuspendCallInsideLambda.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("recursiveGenerators.kt")
|
@TestMetadata("recursiveGenerators.kt")
|
||||||
public void testRecursiveGenerators() throws Exception {
|
public void testRecursiveGenerators() throws Exception {
|
||||||
runTest("compiler/testData/diagnostics/testsWithStdLib/coroutines/inference/recursiveGenerators.kt");
|
runTest("compiler/testData/diagnostics/testsWithStdLib/coroutines/inference/recursiveGenerators.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user