diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/KotlinResolutionCallbacksImpl.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/KotlinResolutionCallbacksImpl.kt index 54b52c1718e..f14664501f8 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/KotlinResolutionCallbacksImpl.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/KotlinResolutionCallbacksImpl.kt @@ -30,7 +30,6 @@ 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.KotlinCall import org.jetbrains.kotlin.resolve.calls.model.LambdaKotlinCallArgument import org.jetbrains.kotlin.resolve.calls.model.ResolvedCallAtom import org.jetbrains.kotlin.resolve.calls.model.SimpleKotlinCallArgument @@ -145,7 +144,7 @@ class KotlinResolutionCallbacksImpl( } override fun bindStubResolvedCallForCandidate(candidate: ResolvedCallAtom) { - kotlinToResolvedCallTransformer.createStubResolvedCallAndWriteItToTrace(candidate, trace) + kotlinToResolvedCallTransformer.createStubResolvedCallAndWriteItToTrace(candidate, trace, emptyList()) } override fun createReceiverWithSmartCastInfo(resolvedAtom: ResolvedCallAtom): ReceiverValueWithSmartCastInfo? { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/KotlinToResolvedCallTransformer.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/KotlinToResolvedCallTransformer.kt index bdef9894c2e..b76ace907c2 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/KotlinToResolvedCallTransformer.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/KotlinToResolvedCallTransformer.kt @@ -77,8 +77,9 @@ class KotlinToResolvedCallTransformer( } fun onlyTransform( - resolvedCallAtom: ResolvedCallAtom - ): ResolvedCall = transformToResolvedCall(resolvedCallAtom, null) + resolvedCallAtom: ResolvedCallAtom, + diagnostics: Collection + ): ResolvedCall = transformToResolvedCall(resolvedCallAtom, null, null, diagnostics) fun transformAndReport( baseResolvedCall: CallResolutionResult, @@ -95,7 +96,7 @@ class KotlinToResolvedCallTransformer( context.trace.record(BindingContext.ONLY_RESOLVED_CALL, psiCall, baseResolvedCall) - return createStubResolvedCallAndWriteItToTrace(candidate, context.trace) + return createStubResolvedCallAndWriteItToTrace(candidate, context.trace, baseResolvedCall.diagnostics) } CallResolutionResult.Type.ERROR, CallResolutionResult.Type.COMPLETED -> { val resultSubstitutor = baseResolvedCall.constraintSystem.buildResultingSubstitutor() @@ -107,14 +108,18 @@ class KotlinToResolvedCallTransformer( ktPrimitiveCompleter.completeAll(subKtPrimitive) } - return ktPrimitiveCompleter.completeResolvedCall(candidate) as ResolvedCall + return ktPrimitiveCompleter.completeResolvedCall(candidate, baseResolvedCall.diagnostics) as ResolvedCall } CallResolutionResult.Type.ALL_CANDIDATES -> error("Cannot transform result for ALL_CANDIDATES mode") } } - fun createStubResolvedCallAndWriteItToTrace(candidate: ResolvedCallAtom, trace: BindingTrace): ResolvedCall { - val result = transformToResolvedCall(candidate, trace) + fun createStubResolvedCallAndWriteItToTrace( + candidate: ResolvedCallAtom, + trace: BindingTrace, + diagnostics: Collection + ): ResolvedCall { + val result = transformToResolvedCall(candidate, trace, null, diagnostics) val psiKotlinCall = candidate.atom.psiKotlinCall val tracing = psiKotlinCall.safeAs()?.baseCall?.tracingStrategy ?: psiKotlinCall.tracingStrategy @@ -126,35 +131,38 @@ class KotlinToResolvedCallTransformer( fun transformToResolvedCall( completedCallAtom: ResolvedCallAtom, trace: BindingTrace?, - resultSubstitutor: NewTypeSubstitutor? = null // if substitutor is not null, it means that this call is completed + resultSubstitutor: NewTypeSubstitutor? = null, // if substitutor is not null, it means that this call is completed + diagnostics: Collection ): ResolvedCall { val psiKotlinCall = completedCallAtom.atom.psiKotlinCall return if (psiKotlinCall is PSIKotlinCallForInvoke) { @Suppress("UNCHECKED_CAST") NewVariableAsFunctionResolvedCallImpl( - createOrGet(psiKotlinCall.variableCall.resolvedCall, trace, resultSubstitutor), - createOrGet(completedCallAtom, trace, resultSubstitutor) + createOrGet(psiKotlinCall.variableCall.resolvedCall, trace, resultSubstitutor, diagnostics), + createOrGet(completedCallAtom, trace, resultSubstitutor, diagnostics) ) as ResolvedCall } else { - createOrGet(completedCallAtom, trace, resultSubstitutor) + createOrGet(completedCallAtom, trace, resultSubstitutor, diagnostics) } } private fun createOrGet( completedSimpleAtom: ResolvedCallAtom, trace: BindingTrace?, - resultSubstitutor: NewTypeSubstitutor? + resultSubstitutor: NewTypeSubstitutor?, + diagnostics: Collection ): NewResolvedCallImpl { if (trace != null) { val storedResolvedCall = completedSimpleAtom.atom.psiKotlinCall.psiCall.getResolvedCall(trace.bindingContext)?. safeAs>() if (storedResolvedCall != null) { storedResolvedCall.setResultingSubstitutor(resultSubstitutor) + storedResolvedCall.updateDiagnostics(diagnostics) return storedResolvedCall } } - return NewResolvedCallImpl(completedSimpleAtom, resultSubstitutor) + return NewResolvedCallImpl(completedSimpleAtom, resultSubstitutor, diagnostics) } fun runCallCheckers(resolvedCall: ResolvedCall<*>, callCheckerContext: CallCheckerContext) { @@ -289,44 +297,63 @@ class KotlinToResolvedCallTransformer( return expressionType != null && TypeUtils.isNullableType(expressionType) } - internal fun bindAndReport(context: BasicCallResolutionContext, trace: BindingTrace, resolvedCall: ResolvedCall<*>) { - resolvedCall.safeAs>()?.let { bindAndReport(context, trace, it) } - resolvedCall.safeAs()?.let { bindAndReport(context, trace, it) } + internal fun bindAndReport( + context: BasicCallResolutionContext, + trace: BindingTrace, + resolvedCall: ResolvedCall<*>, + diagnostics: Collection + ) { + resolvedCall.safeAs>()?.let { bindAndReport(context, trace, it, diagnostics) } + resolvedCall.safeAs()?.let { bindAndReport(context, trace, it, diagnostics) } } - private fun bindAndReport(context: BasicCallResolutionContext, trace: BindingTrace, simpleResolvedCall: NewResolvedCallImpl<*>) { + private fun bindAndReport( + context: BasicCallResolutionContext, + trace: BindingTrace, + simpleResolvedCall: NewResolvedCallImpl<*>, + diagnostics: Collection + ) { val tracing = simpleResolvedCall.resolvedCallAtom.atom.psiKotlinCall.tracingStrategy tracing.bindReference(trace, simpleResolvedCall) tracing.bindResolvedCall(trace, simpleResolvedCall) - reportCallDiagnostic(context, trace, simpleResolvedCall.resolvedCallAtom, simpleResolvedCall.resultingDescriptor) + reportCallDiagnostic(context, trace, simpleResolvedCall.resolvedCallAtom, simpleResolvedCall.resultingDescriptor, diagnostics) } - private fun bindAndReport(context: BasicCallResolutionContext, trace: BindingTrace, variableAsFunction: NewVariableAsFunctionResolvedCallImpl) { + private fun bindAndReport( + context: BasicCallResolutionContext, + trace: BindingTrace, + variableAsFunction: NewVariableAsFunctionResolvedCallImpl, + diagnostics: Collection + ) { val outerTracingStrategy = variableAsFunction.baseCall.tracingStrategy - outerTracingStrategy.bindReference(trace, variableAsFunction.variableCall) - outerTracingStrategy.bindResolvedCall(trace, variableAsFunction) - variableAsFunction.functionCall.kotlinCall.psiKotlinCall.tracingStrategy.bindReference(trace, variableAsFunction.functionCall) + val variableCall = variableAsFunction.variableCall + val functionCall = variableAsFunction.functionCall - reportCallDiagnostic(context, trace, variableAsFunction.variableCall.resolvedCallAtom, variableAsFunction.variableCall.resultingDescriptor) - reportCallDiagnostic(context, trace, variableAsFunction.functionCall.resolvedCallAtom, variableAsFunction.functionCall.resultingDescriptor) + outerTracingStrategy.bindReference(trace, variableCall) + outerTracingStrategy.bindResolvedCall(trace, variableAsFunction) + functionCall.kotlinCall.psiKotlinCall.tracingStrategy.bindReference(trace, functionCall) + + reportCallDiagnostic(context, trace, variableCall.resolvedCallAtom, variableCall.resultingDescriptor, diagnostics) + reportCallDiagnostic(context, trace, functionCall.resolvedCallAtom, functionCall.resultingDescriptor, emptyList()) } private fun reportCallDiagnostic( context: BasicCallResolutionContext, trace: BindingTrace, completedCallAtom: ResolvedCallAtom, - resultingDescriptor: CallableDescriptor + resultingDescriptor: CallableDescriptor, + diagnostics: Collection ) { val trackingTrace = TrackingBindingTrace(trace) val newContext = context.replaceBindingTrace(trackingTrace) val diagnosticReporter = DiagnosticReporterByTrackingStrategy(constantExpressionEvaluator, newContext, completedCallAtom.atom.psiKotlinCall) val diagnosticHolder = KotlinDiagnosticsHolder.SimpleHolder() - additionalDiagnosticReporter.reportAdditionalDiagnostics(completedCallAtom, resultingDescriptor, diagnosticHolder) + additionalDiagnosticReporter.reportAdditionalDiagnostics(completedCallAtom, resultingDescriptor, diagnosticHolder, diagnostics) - for (diagnostic in completedCallAtom.diagnostics + diagnosticHolder.getDiagnostics()) { + for (diagnostic in diagnostics + diagnosticHolder.getDiagnostics()) { trackingTrace.reported = false diagnostic.report(diagnosticReporter) @@ -445,7 +472,8 @@ sealed class NewAbstractResolvedCall(): ResolvedCall class NewResolvedCallImpl( val resolvedCallAtom: ResolvedCallAtom, - substitutor: NewTypeSubstitutor? + substitutor: NewTypeSubstitutor?, + private var diagnostics: Collection ): NewAbstractResolvedCall() { var isCompleted = false private set @@ -458,7 +486,7 @@ class NewResolvedCallImpl( override val kotlinCall: KotlinCall get() = resolvedCallAtom.atom - override fun getStatus(): ResolutionStatus = getResultApplicability(resolvedCallAtom.diagnostics).toResolutionStatus() + override fun getStatus(): ResolutionStatus = getResultApplicability(diagnostics).toResolutionStatus() override val argumentMappingByOriginal: Map get() = resolvedCallAtom.argumentMappingByOriginal @@ -489,6 +517,10 @@ class NewResolvedCallImpl( this.smartCastDispatchReceiverType = smartCastDispatchReceiverType } + fun updateDiagnostics(completedDiagnostics: Collection) { + diagnostics = completedDiagnostics + } + fun setResultingSubstitutor(substitutor: NewTypeSubstitutor?) { //clear cached values argumentToParameterMap = null diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/PSICallResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/PSICallResolver.kt index 4b79c28a735..b4e086d9bd1 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/PSICallResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/PSICallResolver.kt @@ -179,7 +179,7 @@ class PSICallResolver( if (result.type == CallResolutionResult.Type.ALL_CANDIDATES) { val resolvedCalls = result.allCandidates?.map { val resultingSubstitutor = it.getSystem().asReadOnlyStorage().buildResultingSubstitutor() - kotlinToResolvedCallTransformer.transformToResolvedCall(it.resolvedCall, null, resultingSubstitutor) + kotlinToResolvedCallTransformer.transformToResolvedCall(it.resolvedCall, null, resultingSubstitutor, result.diagnostics) } return AllCandidates(resolvedCalls ?: emptyList()) @@ -193,7 +193,7 @@ class PSICallResolver( } result.diagnostics.firstIsInstanceOrNull()?.let { - val resolvedCalls = it.candidates.map { kotlinToResolvedCallTransformer.onlyTransform(it.resolvedCall) } + val resolvedCalls = it.candidates.map { kotlinToResolvedCallTransformer.onlyTransform(it.resolvedCall, emptyList()) } if (it.candidates.areAllFailed()) { tracingStrategy.noneApplicable(trace, resolvedCalls) tracingStrategy.recordAmbiguity(trace, resolvedCalls) @@ -210,11 +210,11 @@ class PSICallResolver( 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 isInapplicableReceiver = getResultApplicability(result.diagnostics) == ResolutionCandidateApplicability.INAPPLICABLE_WRONG_RECEIVER val resolvedCall = if (isInapplicableReceiver) { - kotlinToResolvedCallTransformer.onlyTransform(singleCandidate).also { + val singleCandidate = result.resultCallAtom ?: error("Should be not null for result: $result") + kotlinToResolvedCallTransformer.onlyTransform(singleCandidate, result.diagnostics).also { tracingStrategy.unresolvedReferenceWrongReceiver(trace, listOf(it)) } } @@ -233,15 +233,15 @@ class PSICallResolver( } private fun CallResolutionResult.areAllInapplicable(): Boolean { - val candidates = diagnostics.firstIsInstanceOrNull()?.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 + val manyCandidates = diagnostics.firstIsInstanceOrNull()?.candidates + if (manyCandidates != null) { + return manyCandidates.areAllFailed() } + + val applicability = getResultApplicability(diagnostics) + return applicability == ResolutionCandidateApplicability.INAPPLICABLE || + applicability == ResolutionCandidateApplicability.INAPPLICABLE_WRONG_RECEIVER || + applicability == ResolutionCandidateApplicability.HIDDEN } // true if we found something diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/ResolvedAtomCompleter.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/ResolvedAtomCompleter.kt index ca9214f81f5..4754c603e4a 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/ResolvedAtomCompleter.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/ResolvedAtomCompleter.kt @@ -60,12 +60,12 @@ class ResolvedAtomCompleter( ) { private val callCheckerContext = CallCheckerContext(topLevelCallContext, languageVersionSettings, deprecationResolver) - fun completeAndReport(resolvedAtom: ResolvedAtom) { + private fun complete(resolvedAtom: ResolvedAtom) { when (resolvedAtom) { is ResolvedCollectionLiteralAtom -> completeCollectionLiteralCalls(resolvedAtom) is ResolvedCallableReferenceAtom -> completeCallableReference(resolvedAtom) is ResolvedLambdaAtom -> completeLambda(resolvedAtom) - is ResolvedCallAtom -> completeResolvedCall(resolvedAtom) + is ResolvedCallAtom -> completeResolvedCall(resolvedAtom, emptyList()) } } @@ -73,14 +73,14 @@ class ResolvedAtomCompleter( for (subKtPrimitive in resolvedAtom.subResolvedAtoms) { completeAll(subKtPrimitive) } - completeAndReport(resolvedAtom) + complete(resolvedAtom) } - fun completeResolvedCall(resolvedCallAtom: ResolvedCallAtom): ResolvedCall<*>? { + fun completeResolvedCall(resolvedCallAtom: ResolvedCallAtom, diagnostics: Collection): ResolvedCall<*>? { if (resolvedCallAtom.atom.psiKotlinCall is PSIKotlinCallForVariable) return null - val resolvedCall = kotlinToResolvedCallTransformer.transformToResolvedCall(resolvedCallAtom, trace, resultSubstitutor) - kotlinToResolvedCallTransformer.bindAndReport(topLevelCallContext, trace, resolvedCall) + val resolvedCall = kotlinToResolvedCallTransformer.transformToResolvedCall(resolvedCallAtom, trace, resultSubstitutor, diagnostics) + kotlinToResolvedCallTransformer.bindAndReport(topLevelCallContext, trace, resolvedCall, diagnostics) kotlinToResolvedCallTransformer.runCallCheckers(resolvedCall, callCheckerContext) val lastCall = if (resolvedCall is VariableAsFunctionResolvedCall) resolvedCall.functionCall else resolvedCall diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/AdditionalDiagnosticReporter.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/AdditionalDiagnosticReporter.kt index a152c9e2942..b07ceaf93f5 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/AdditionalDiagnosticReporter.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/AdditionalDiagnosticReporter.kt @@ -31,9 +31,10 @@ class AdditionalDiagnosticReporter(private val languageVersionSettings: Language fun reportAdditionalDiagnostics( candidate: ResolvedCallAtom, resultingDescriptor: CallableDescriptor, - kotlinDiagnosticsHolder: KotlinDiagnosticsHolder + kotlinDiagnosticsHolder: KotlinDiagnosticsHolder, + diagnostics: Collection ) { - reportSmartCasts(candidate, resultingDescriptor, kotlinDiagnosticsHolder) + reportSmartCasts(candidate, resultingDescriptor, kotlinDiagnosticsHolder, diagnostics) } private fun createSmartCastDiagnostic( @@ -51,7 +52,8 @@ class AdditionalDiagnosticReporter(private val languageVersionSettings: Language private fun reportSmartCastOnReceiver( candidate: ResolvedCallAtom, receiver: SimpleKotlinCallArgument?, - parameter: ReceiverParameterDescriptor? + parameter: ReceiverParameterDescriptor?, + diagnostics: Collection ): SmartCastDiagnostic? { if (receiver == null || parameter == null) return null val expectedType = parameter.type.unwrap().let { if (receiver.isSafeCall) it.makeNullableAsSpecified(true) else it } @@ -60,11 +62,11 @@ class AdditionalDiagnosticReporter(private val languageVersionSettings: Language // todo may be we have smart cast to Int? return smartCastDiagnostic.takeIf { - candidate.diagnostics.filterIsInstance().none { + diagnostics.filterIsInstance().none { it.receiver == receiver } && - candidate.diagnostics.filterIsInstance().none { + diagnostics.filterIsInstance().none { it.argument == receiver } } @@ -73,17 +75,22 @@ class AdditionalDiagnosticReporter(private val languageVersionSettings: Language private fun reportSmartCasts( candidate: ResolvedCallAtom, resultingDescriptor: CallableDescriptor, - kotlinDiagnosticsHolder: KotlinDiagnosticsHolder + kotlinDiagnosticsHolder: KotlinDiagnosticsHolder, + diagnostics: Collection ) { - kotlinDiagnosticsHolder.addDiagnosticIfNotNull(reportSmartCastOnReceiver(candidate, candidate.extensionReceiverArgument, resultingDescriptor.extensionReceiverParameter)) - kotlinDiagnosticsHolder.addDiagnosticIfNotNull(reportSmartCastOnReceiver(candidate, candidate.dispatchReceiverArgument, resultingDescriptor.dispatchReceiverParameter)) + kotlinDiagnosticsHolder.addDiagnosticIfNotNull( + reportSmartCastOnReceiver(candidate, candidate.extensionReceiverArgument, resultingDescriptor.extensionReceiverParameter, diagnostics) + ) + kotlinDiagnosticsHolder.addDiagnosticIfNotNull( + reportSmartCastOnReceiver(candidate, candidate.dispatchReceiverArgument, resultingDescriptor.dispatchReceiverParameter, diagnostics) + ) for (parameter in resultingDescriptor.valueParameters) { for (argument in candidate.argumentMappingByOriginal[parameter.original]?.arguments ?: continue) { val effectiveExpectedType = argument.getExpectedType(parameter, languageVersionSettings) val smartCastDiagnostic = createSmartCastDiagnostic(candidate, argument, effectiveExpectedType) ?: continue - val thereIsUnstableSmartCastError = candidate.diagnostics.filterIsInstance().any { + val thereIsUnstableSmartCastError = diagnostics.filterIsInstance().any { it.argument == argument } diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/CallableReferenceResolver.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/CallableReferenceResolver.kt index 35e5496f9d3..1cbabcbd2ca 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/CallableReferenceResolver.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/CallableReferenceResolver.kt @@ -29,8 +29,6 @@ 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( @@ -62,7 +60,8 @@ class CallableReferenceResolver( fun processCallableReferenceArgument( csBuilder: ConstraintSystemBuilder, - resolvedAtom: ResolvedCallableReferenceAtom + resolvedAtom: ResolvedCallableReferenceAtom, + diagnosticsHolder: KotlinDiagnosticsHolder ) { val argument = resolvedAtom.atom val expectedType = resolvedAtom.expectedType?.let { csBuilder.buildCurrentSubstitutor().safeSubstitute(it) } @@ -71,30 +70,28 @@ class CallableReferenceResolver( val candidates = runRHSResolution(scopeTower, argument, expectedType) { checkCallableReference -> csBuilder.runTransaction { checkCallableReference(this); false } } - val diagnostics = SmartList() - 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) + diagnosticsHolder.addDiagnosticIfNotNull(diagnostic) chosenCandidate.freshSubstitutor = toFreshSubstitutor } else { if (candidates.isEmpty()) { - diagnostics.add(NoneCallableReferenceCandidates(argument)) + diagnosticsHolder.addDiagnostic(NoneCallableReferenceCandidates(argument)) } else { - diagnostics.add(CallableReferenceCandidatesAmbiguity(argument, candidates)) + diagnosticsHolder.addDiagnostic(CallableReferenceCandidatesAmbiguity(argument, candidates)) } } // todo -- create this inside CallableReferencesCandidateFactory val subKtArguments = listOfNotNull(buildResolvedKtArgument(argument.lhsResult)) - resolvedAtom.setAnalyzedResults(chosenCandidate, subKtArguments, diagnostics) + resolvedAtom.setAnalyzedResults(chosenCandidate, subKtArguments) } private fun buildResolvedKtArgument(lhsResult: LHSResult): ResolvedAtom? { diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/KotlinCallCompleter.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/KotlinCallCompleter.kt index 41aebf98e19..7cb1e4c03ed 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/KotlinCallCompleter.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/KotlinCallCompleter.kt @@ -49,13 +49,20 @@ class KotlinCallCompleter( // 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) } + val diagnosticsFromResolutionParts = candidate?.diagnosticsFromResolutionParts ?: emptyList() + if (candidate == null || candidate.csBuilder.hasContradiction) { val candidateForCompletion = candidate ?: factory.createErrorCandidate().forceResolution() candidateForCompletion.prepareForCompletion(expectedType, resolutionCallbacks) runCompletion(candidateForCompletion.resolvedCall, ConstraintSystemCompletionMode.FULL, diagnosticHolder, candidateForCompletion.getSystem(), resolutionCallbacks) val systemStorage = candidate?.getSystem()?.asReadOnlyStorage() ?: ConstraintStorage.Empty - return CallResolutionResult(CallResolutionResult.Type.ERROR, candidate?.resolvedCall, diagnosticHolder.getDiagnostics(), systemStorage) + return CallResolutionResult( + CallResolutionResult.Type.ERROR, + candidate?.resolvedCall, + diagnosticHolder.getDiagnostics() + diagnosticsFromResolutionParts, + systemStorage + ) } val completionType = candidate.prepareForCompletion(expectedType, resolutionCallbacks) @@ -63,10 +70,20 @@ class KotlinCallCompleter( runCompletion(candidate.resolvedCall, completionType, diagnosticHolder, constraintSystem, resolutionCallbacks) return if (completionType == ConstraintSystemCompletionMode.FULL) { - CallResolutionResult(CallResolutionResult.Type.COMPLETED, candidate.resolvedCall, diagnosticHolder.getDiagnostics(), constraintSystem.asReadOnlyStorage()) + CallResolutionResult( + CallResolutionResult.Type.COMPLETED, + candidate.resolvedCall, + diagnosticHolder.getDiagnostics() + diagnosticsFromResolutionParts, + constraintSystem.asReadOnlyStorage() + ) } else { - CallResolutionResult(CallResolutionResult.Type.PARTIAL, candidate.resolvedCall, diagnosticHolder.getDiagnostics(), constraintSystem.asReadOnlyStorage()) + CallResolutionResult( + CallResolutionResult.Type.PARTIAL, + candidate.resolvedCall, + diagnosticHolder.getDiagnostics() + diagnosticsFromResolutionParts, + constraintSystem.asReadOnlyStorage() + ) } } @@ -100,7 +117,12 @@ class KotlinCallCompleter( val returnType = resolvedCallAtom.freshReturnType ?: constraintSystem.builtIns.unitType kotlinConstraintSystemCompleter.runCompletion(constraintSystem.asConstraintSystemCompleterContext(), completionMode, resolvedCallAtom, returnType) { if (!skipPostponedArguments) { - postponedArgumentsAnalyzer.analyze(constraintSystem.asPostponedArgumentsAnalyzerContext(), resolutionCallbacks, it) + postponedArgumentsAnalyzer.analyze( + constraintSystem.asPostponedArgumentsAnalyzerContext(), + resolutionCallbacks, + it, + diagnosticsHolder + ) } } diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/PostponedArgumentsAnalyzer.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/PostponedArgumentsAnalyzer.kt index 19c2fca3a3b..e71265233b3 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/PostponedArgumentsAnalyzer.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/PostponedArgumentsAnalyzer.kt @@ -39,17 +39,24 @@ class PostponedArgumentsAnalyzer( fun getBuilder(): ConstraintSystemBuilder } - fun analyze(c: Context, resolutionCallbacks: KotlinResolutionCallbacks, argument: ResolvedAtom) { + fun analyze(c: Context, resolutionCallbacks: KotlinResolutionCallbacks, argument: ResolvedAtom, diagnosticsHolder: KotlinDiagnosticsHolder) { when (argument) { - is ResolvedLambdaAtom -> analyzeLambda(c, resolutionCallbacks, argument) - is LambdaWithTypeVariableAsExpectedTypeAtom -> analyzeLambda(c, resolutionCallbacks, argument.transformToResolvedLambda(c.getBuilder())) - is ResolvedCallableReferenceAtom -> callableReferenceResolver.processCallableReferenceArgument(c.getBuilder(), argument) + is ResolvedLambdaAtom -> + analyzeLambda(c, resolutionCallbacks, argument, diagnosticsHolder) + + is LambdaWithTypeVariableAsExpectedTypeAtom -> + analyzeLambda(c, resolutionCallbacks, argument.transformToResolvedLambda(c.getBuilder()), diagnosticsHolder) + + is ResolvedCallableReferenceAtom -> + callableReferenceResolver.processCallableReferenceArgument(c.getBuilder(), argument, diagnosticsHolder) + is ResolvedCollectionLiteralAtom -> TODO("Not supported") + else -> error("Unexpected resolved primitive: ${argument.javaClass.canonicalName}") } } - private fun analyzeLambda(c: Context, resolutionCallbacks: KotlinResolutionCallbacks, lambda: ResolvedLambdaAtom) { + private fun analyzeLambda(c: Context, resolutionCallbacks: KotlinResolutionCallbacks, lambda: ResolvedLambdaAtom, diagnosticHolder: KotlinDiagnosticsHolder) { val currentSubstitutor = c.buildCurrentSubstitutor() fun substitute(type: UnwrappedType) = currentSubstitutor.safeSubstitute(type) @@ -61,8 +68,6 @@ class PostponedArgumentsAnalyzer( resultArguments.forEach { c.addSubsystemForArgument(it) } - val diagnosticHolder = KotlinDiagnosticsHolder.SimpleHolder() - val subResolvedKtPrimitives = resultArguments.map { checkSimpleArgument(c.getBuilder(), it, lambda.returnType.let(::substitute), diagnosticHolder, isReceiver = false) } @@ -72,6 +77,6 @@ class PostponedArgumentsAnalyzer( c.getBuilder().addSubtypeConstraint(lambda.returnType.let(::substitute), unitType, LambdaArgumentConstraintPosition(lambda)) } - lambda.setAnalyzedResults(resultArguments, subResolvedKtPrimitives, diagnosticHolder.getDiagnostics()) + lambda.setAnalyzedResults(resultArguments, subResolvedKtPrimitives) } } \ No newline at end of file diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/ResolutionAtoms.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/ResolutionAtoms.kt index c32be7a0d60..7107d98777a 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/ResolutionAtoms.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/ResolutionAtoms.kt @@ -46,10 +46,8 @@ sealed class ResolvedAtom { lateinit var subResolvedAtoms: List private set - lateinit var diagnostics: Collection - private set - protected open fun setAnalyzedResults(subResolvedAtoms: List, diagnostics: Collection) { + protected open fun setAnalyzedResults(subResolvedAtoms: List) { assert(!analyzed) { "Already analyzed: $this" } @@ -57,7 +55,6 @@ sealed class ResolvedAtom { analyzed = true this.subResolvedAtoms = subResolvedAtoms - this.diagnostics = diagnostics } } @@ -74,7 +71,7 @@ abstract class ResolvedCallAtom : ResolvedAtom() { class ResolvedExpressionAtom(override val atom: ExpressionKotlinCallArgument) : ResolvedAtom() { init { - setAnalyzedResults(listOf(), listOf()) + setAnalyzedResults(listOf()) } } sealed class PostponedResolvedAtom : ResolvedAtom() { @@ -90,7 +87,7 @@ class LambdaWithTypeVariableAsExpectedTypeAtom( override val outputType: UnwrappedType? get() = null fun setAnalyzed(resolvedLambdaAtom: ResolvedLambdaAtom) { - setAnalyzedResults(listOf(resolvedLambdaAtom), listOf()) + setAnalyzedResults(listOf(resolvedLambdaAtom)) } } @@ -107,11 +104,10 @@ class ResolvedLambdaAtom( fun setAnalyzedResults( resultArguments: List, - subResolvedAtoms: List, - diagnostics: Collection + subResolvedAtoms: List ) { this.resultArguments = resultArguments - setAnalyzedResults(subResolvedAtoms, diagnostics) + setAnalyzedResults(subResolvedAtoms) } override val inputTypes: Collection get() = receiver?.let { parameters + it } ?: parameters @@ -127,11 +123,10 @@ class ResolvedCallableReferenceAtom( fun setAnalyzedResults( candidate: CallableReferenceCandidate?, - subResolvedAtoms: List, - diagnostics: Collection + subResolvedAtoms: List ) { this.candidate = candidate - setAnalyzedResults(subResolvedAtoms, diagnostics) + setAnalyzedResults(subResolvedAtoms) } override val inputTypes: Collection @@ -154,14 +149,14 @@ class ResolvedCollectionLiteralAtom( val expectedType: UnwrappedType? ) : ResolvedAtom() { init { - setAnalyzedResults(listOf(), listOf()) + setAnalyzedResults(listOf()) } } class CallResolutionResult( val type: Type, val resultCallAtom: ResolvedCallAtom?, - diagnostics: List, + val diagnostics: List, val constraintSystem: ConstraintStorage, val allCandidates: Collection? = null ) : ResolvedAtom() { @@ -175,7 +170,7 @@ class CallResolutionResult( } init { - setAnalyzedResults(listOfNotNull(resultCallAtom), diagnostics) + setAnalyzedResults(listOfNotNull(resultCallAtom)) } override fun toString() = "$type, resultCallAtom = $resultCallAtom, (${diagnostics.joinToString()})" diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/ResolutionCandidate.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/ResolutionCandidate.kt index f8e8579626e..5499e110ef9 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/ResolutionCandidate.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/ResolutionCandidate.kt @@ -68,8 +68,8 @@ class KotlinResolutionCandidate( val knownTypeParametersResultingSubstitutor: TypeSubstitutor? = null, private val resolutionSequence: List = resolvedCall.atom.callKind.resolutionSequence ) : Candidate, KotlinDiagnosticsHolder { + val diagnosticsFromResolutionParts = arrayListOf() // TODO: this is mutable list, take diagnostics only once! private var newSystem: NewConstraintSystemImpl? = null - private val diagnostics = arrayListOf() private var currentApplicability = ResolutionCandidateApplicability.RESOLVED private var subResolvedAtoms: MutableList = arrayListOf() @@ -87,7 +87,7 @@ class KotlinResolutionCandidate( internal val csBuilder get() = getSystem().getBuilder() override fun addDiagnostic(diagnostic: KotlinCallDiagnostic) { - diagnostics.add(diagnostic) + diagnosticsFromResolutionParts.add(diagnostic) currentApplicability = maxOf(diagnostic.candidateApplicability, currentApplicability) } @@ -121,7 +121,7 @@ class KotlinResolutionCandidate( partIndex++ } if (step == stepCount) { - resolvedCall.setAnalyzedResults(subResolvedAtoms, diagnostics + getSystem().diagnostics) + resolvedCall.setAnalyzedResults(subResolvedAtoms) } } @@ -176,8 +176,8 @@ class MutableResolvedCallAtom( override lateinit var substitutor: FreshVariableNewTypeSubstitutor lateinit var argumentToCandidateParameter: Map - override public fun setAnalyzedResults(subResolvedAtoms: List, diagnostics: Collection) { - super.setAnalyzedResults(subResolvedAtoms, diagnostics) + override public fun setAnalyzedResults(subResolvedAtoms: List) { + super.setAnalyzedResults(subResolvedAtoms) } override fun toString(): String = "$atom, candidate = $candidateDescriptor"