From 9378bff65cd866b3a6dc34326dc56d9cc0940887 Mon Sep 17 00:00:00 2001 From: Stanislav Erokhin Date: Fri, 23 Jun 2017 06:00:12 +0300 Subject: [PATCH] [NI] Move irrelevant code from KotlinCallCompleter Extract code about smart cast diagnostic to new component AdditionalDiagnosticReporter --- .../AdditionalDiagnosticReporter.kt | 85 +++++++++++++++++++ .../calls/components/KotlinCallCompleter.kt | 66 ++------------ .../calls/components/ResolutionParts.kt | 4 + 3 files changed, 94 insertions(+), 61 deletions(-) create mode 100644 compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/AdditionalDiagnosticReporter.kt 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 new file mode 100644 index 00000000000..f01c225c03f --- /dev/null +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/AdditionalDiagnosticReporter.kt @@ -0,0 +1,85 @@ +/* + * Copyright 2010-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.resolve.calls.components + +import org.jetbrains.kotlin.descriptors.CallableDescriptor +import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor +import org.jetbrains.kotlin.resolve.calls.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 +class AdditionalDiagnosticReporter { + + fun createAdditionalDiagnostics( + candidate: SimpleKotlinResolutionCandidate, + resultingDescriptor: CallableDescriptor + ): List = reportSmartCasts(candidate, resultingDescriptor) + + private fun createSmartCastDiagnostic(argument: KotlinCallArgument, expectedResultType: UnwrappedType): SmartCastDiagnostic? { + if (argument !is ExpressionKotlinCallArgument) return null + if (!KotlinTypeChecker.DEFAULT.isSubtypeOf(argument.receiver.receiverValue.type, expectedResultType)) { + return SmartCastDiagnostic(argument, expectedResultType.unwrap()) + } + return null + } + + private fun reportSmartCastOnReceiver( + candidate: KotlinResolutionCandidate, + receiver: SimpleKotlinCallArgument?, + parameter: ReceiverParameterDescriptor? + ): SmartCastDiagnostic? { + if (receiver == null || parameter == null) return null + val expectedType = parameter.type.unwrap().let { if (receiver.isSafeCall) it.makeNullableAsSpecified(true) else it } + + val smartCastDiagnostic = createSmartCastDiagnostic(receiver, expectedType) ?: return null + + // todo may be we have smart cast to Int? + return smartCastDiagnostic.takeIf { + candidate.status.diagnostics.filterIsInstance().none { + it.receiver == receiver + } + && + candidate.status.diagnostics.filterIsInstance().none { + it.expressionArgument == receiver + } + } + } + + private fun reportSmartCasts(candidate: SimpleKotlinResolutionCandidate, resultingDescriptor: CallableDescriptor) = + SmartList().apply { + addIfNotNull(reportSmartCastOnReceiver(candidate, candidate.extensionReceiver, resultingDescriptor.extensionReceiverParameter)) + addIfNotNull(reportSmartCastOnReceiver(candidate, candidate.dispatchReceiverArgument, resultingDescriptor.dispatchReceiverParameter)) + + for (parameter in resultingDescriptor.valueParameters) { + for (argument in candidate.argumentMappingByOriginal[parameter.original]?.arguments ?: continue) { + val smartCastDiagnostic = createSmartCastDiagnostic(argument, argument.getExpectedType(parameter)) ?: continue + + val thereIsUnstableSmartCastError = candidate.status.diagnostics.filterIsInstance().any { + it.expressionArgument == argument + } + + if (!thereIsUnstableSmartCastError) { + add(smartCastDiagnostic) + } + } + } + } +} \ No newline at end of file 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 4505948042b..ba4bc5bf067 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 @@ -19,7 +19,6 @@ 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.descriptors.ReceiverParameterDescriptor import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder import org.jetbrains.kotlin.resolve.calls.inference.components.ConstraintInjector import org.jetbrains.kotlin.resolve.calls.inference.components.FixationOrderCalculator @@ -38,16 +37,14 @@ 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.checker.KotlinTypeChecker import org.jetbrains.kotlin.types.checker.NewCapturedType import org.jetbrains.kotlin.types.typeUtil.builtIns import org.jetbrains.kotlin.types.typeUtil.contains -import org.jetbrains.kotlin.utils.SmartList -import org.jetbrains.kotlin.utils.addIfNotNull class KotlinCallCompleter( - val resultTypeResolver: ResultTypeResolver, - val fixationOrderCalculator: FixationOrderCalculator + private val resultTypeResolver: ResultTypeResolver, + private val fixationOrderCalculator: FixationOrderCalculator, + private val additionalDiagnosticReporter: AdditionalDiagnosticReporter ) { interface Context { val innerCalls: List @@ -165,60 +162,11 @@ class KotlinCallCompleter( } private fun computeStatus(candidate: SimpleKotlinResolutionCandidate, resultingDescriptor: CallableDescriptor): ResolutionCandidateStatus { - val smartCasts = reportSmartCasts(candidate, resultingDescriptor).takeIf { it.isNotEmpty() } ?: return candidate.status + val smartCasts = additionalDiagnosticReporter.createAdditionalDiagnostics(candidate, resultingDescriptor).takeIf { it.isNotEmpty() } ?: + return candidate.status return ResolutionCandidateStatus(candidate.status.diagnostics + smartCasts) } - private fun createSmartCastDiagnostic(argument: KotlinCallArgument, expectedResultType: UnwrappedType): SmartCastDiagnostic? { - if (argument !is ExpressionKotlinCallArgument) return null - if (!KotlinTypeChecker.DEFAULT.isSubtypeOf(argument.receiver.receiverValue.type, expectedResultType)) { - return SmartCastDiagnostic(argument, expectedResultType.unwrap()) - } - return null - } - - private fun reportSmartCastOnReceiver( - candidate: KotlinResolutionCandidate, - receiver: SimpleKotlinCallArgument?, - parameter: ReceiverParameterDescriptor? - ): SmartCastDiagnostic? { - if (receiver == null || parameter == null) return null - val expectedType = parameter.type.unwrap().let { if (receiver.isSafeCall) it.makeNullableAsSpecified(true) else it } - - val smartCastDiagnostic = createSmartCastDiagnostic(receiver, expectedType) ?: return null - - // todo may be we have smart cast to Int? - return smartCastDiagnostic.takeIf { - candidate.status.diagnostics.filterIsInstance().none { - it.receiver == receiver - } - && - candidate.status.diagnostics.filterIsInstance().none { - it.expressionArgument == receiver - } - } - } - - - private fun reportSmartCasts(candidate: SimpleKotlinResolutionCandidate, resultingDescriptor: CallableDescriptor): List = SmartList().apply { - addIfNotNull(reportSmartCastOnReceiver(candidate, candidate.extensionReceiver, resultingDescriptor.extensionReceiverParameter)) - addIfNotNull(reportSmartCastOnReceiver(candidate, candidate.dispatchReceiverArgument, resultingDescriptor.dispatchReceiverParameter)) - - for (parameter in resultingDescriptor.valueParameters) { - for (argument in candidate.argumentMappingByOriginal[parameter.original]?.arguments ?: continue) { - val smartCastDiagnostic = createSmartCastDiagnostic(argument, argument.getExpectedType(parameter)) ?: continue - - val thereIsUnstableSmartCastError = candidate.status.diagnostics.filterIsInstance().any { - it.expressionArgument == argument - } - - if (!thereIsUnstableSmartCastError) { - add(smartCastDiagnostic) - } - } - } - } - // true if we should complete this call private fun SimpleKotlinResolutionCandidate.prepareForCompletion(expectedType: UnwrappedType?): Boolean { val returnType = descriptorWithFreshTypes.returnType?.unwrap() ?: return false @@ -289,8 +237,4 @@ class KotlinCallCompleter( } return lambda.parameters.all { c.canBeProper(it) } } -} - -class SmartCastDiagnostic(val expressionArgument: ExpressionKotlinCallArgument, val smartCastType: UnwrappedType): KotlinCallDiagnostic(ResolutionCandidateApplicability.RESOLVED) { - override fun report(reporter: DiagnosticReporter) = reporter.onCallArgument(expressionArgument, this) } \ No newline at end of file diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ResolutionParts.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ResolutionParts.kt index 8e9da0ea9a4..320f3d6836d 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ResolutionParts.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ResolutionParts.kt @@ -256,6 +256,10 @@ object InstantiationOfAbstractClass : KotlinCallDiagnostic(RUNTIME_ERROR) { override fun report(reporter: DiagnosticReporter) = reporter.onCall(this) } +class SmartCastDiagnostic(val expressionArgument: ExpressionKotlinCallArgument, val smartCastType: UnwrappedType): KotlinCallDiagnostic(ResolutionCandidateApplicability.RESOLVED) { + override fun report(reporter: DiagnosticReporter) = reporter.onCallArgument(expressionArgument, this) +} + class UnstableSmartCast(val expressionArgument: ExpressionKotlinCallArgument, val targetType: UnwrappedType) : KotlinCallDiagnostic(ResolutionCandidateApplicability.MAY_THROW_RUNTIME_ERROR) { override fun report(reporter: DiagnosticReporter) = reporter.onCallArgument(expressionArgument, this)