From 3e8c15c62aca3579e93b730af461730f8477d410 Mon Sep 17 00:00:00 2001 From: Pavel Kirpichenkov Date: Wed, 13 Nov 2019 18:27:06 +0300 Subject: [PATCH] Introduce component for caching missing supertypes Profiling has shown, that supertype hierarchy scan for all calls has considerable performance cost. However, missing supertypes may be calculated only once per descriptor which would help avoiding multiple supertype hierarchy scans for resolved calls from the same class. New memoizer is injected into call completers and checker contexts and then used for retrieving missing super classifiers. #KT-19234 Fixed --- .../resolve/MissingSupertypesResolver.kt | 47 +++++++++++ .../kotlin/resolve/ModifiersChecker.java | 8 +- .../kotlin/resolve/calls/CallCompleter.kt | 18 +++-- .../resolve/calls/checkers/CallChecker.kt | 2 + .../inference/CoroutineInferenceSession.kt | 6 +- .../tower/KotlinResolutionCallbacksImpl.kt | 8 +- .../tower/KotlinToResolvedCallTransformer.kt | 5 +- .../resolve/calls/tower/PSICallResolver.kt | 5 +- .../calls/tower/ResolvedAtomCompleter.kt | 17 ++-- .../resolve/checkers/DeclarationChecker.kt | 4 +- .../MissingDependencySupertypeChecker.kt | 79 +++++++++---------- .../BasicExpressionTypingVisitor.java | 15 +++- .../ExpressionTypingComponents.java | 6 ++ 13 files changed, 150 insertions(+), 70 deletions(-) create mode 100644 compiler/frontend/src/org/jetbrains/kotlin/resolve/MissingSupertypesResolver.kt diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/MissingSupertypesResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/MissingSupertypesResolver.kt new file mode 100644 index 00000000000..9d5ff5d8963 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/MissingSupertypesResolver.kt @@ -0,0 +1,47 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.resolve + +import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.resolve.descriptorUtil.classId +import org.jetbrains.kotlin.storage.StorageManager +import org.jetbrains.kotlin.types.typeUtil.supertypes + +class MissingSupertypesResolver( + storageManager: StorageManager, + private val moduleDescriptor: ModuleDescriptor +) { + fun getMissingSuperClassifiers(descriptor: ClassifierDescriptor) = missingClassifiers(descriptor) + + private val missingClassifiers = storageManager.createMemoizedFunction { classifier: ClassifierDescriptor -> + doGetMissingClassifiers(classifier) + } + + private fun doGetMissingClassifiers(descriptor: ClassifierDescriptor): Set { + val missingSuperClassifiers = mutableSetOf() + val type = descriptor.defaultType + + for (supertype in type.supertypes()) { + val supertypeDeclaration = supertype.constructor.declarationDescriptor + + /* + * TODO: expects are not checked, because findClassAcrossModuleDependencies does not work with actualization via type alias + * Type parameters are skipped here in favor to explicit checks for bounds, local declarations are ignored for optimization + */ + if (supertypeDeclaration !is ClassDescriptor || supertypeDeclaration.isExpect) continue + if (supertypeDeclaration.visibility == Visibilities.LOCAL) continue + + val superTypeClassId = supertypeDeclaration.classId ?: continue + val dependency = moduleDescriptor.findClassAcrossModuleDependencies(superTypeClassId) + + if (dependency == null || dependency is NotFoundClasses.MockClassDescriptor) { + missingSuperClassifiers.add(supertypeDeclaration) + } + } + + return missingSuperClassifiers.toSet() + } +} diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/ModifiersChecker.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/ModifiersChecker.java index 99dabe061a8..a41070940fd 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/ModifiersChecker.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/ModifiersChecker.java @@ -266,7 +266,8 @@ public class ModifiersChecker { public void runDeclarationCheckers(@NotNull KtDeclaration declaration, @NotNull DeclarationDescriptor descriptor) { DeclarationCheckerContext context = new DeclarationCheckerContext( - trace, languageVersionSettings, deprecationResolver, moduleDescriptor, expectActualTracker + trace, languageVersionSettings, deprecationResolver, moduleDescriptor, expectActualTracker, + missingSupertypesResolver ); for (DeclarationChecker checker : declarationCheckers) { checker.check(declaration, descriptor, context); @@ -291,6 +292,7 @@ public class ModifiersChecker { private final ExpectActualTracker expectActualTracker; private final DeprecationResolver deprecationResolver; private final ModuleDescriptor moduleDescriptor; + private final MissingSupertypesResolver missingSupertypesResolver; public ModifiersChecker( @NotNull AnnotationChecker annotationChecker, @@ -298,7 +300,8 @@ public class ModifiersChecker { @NotNull LanguageVersionSettings languageVersionSettings, @NotNull ExpectActualTracker expectActualTracker, @NotNull DeprecationResolver deprecationResolver, - @NotNull ModuleDescriptor moduleDescriptor + @NotNull ModuleDescriptor moduleDescriptor, + @NotNull MissingSupertypesResolver missingSupertypesResolver ) { this.annotationChecker = annotationChecker; this.declarationCheckers = declarationCheckers; @@ -306,6 +309,7 @@ public class ModifiersChecker { this.expectActualTracker = expectActualTracker; this.deprecationResolver = deprecationResolver; this.moduleDescriptor = moduleDescriptor; + this.missingSupertypesResolver = missingSupertypesResolver; } @NotNull diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallCompleter.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallCompleter.kt index ccf38c91ac7..554759a6af7 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallCompleter.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallCompleter.kt @@ -59,7 +59,8 @@ class CallCompleter( private val moduleDescriptor: ModuleDescriptor, private val deprecationResolver: DeprecationResolver, private val effectSystem: EffectSystem, - private val dataFlowValueFactory: DataFlowValueFactory + private val dataFlowValueFactory: DataFlowValueFactory, + private val missingSupertypesResolver: MissingSupertypesResolver ) { fun completeCall( context: BasicCallResolutionContext, @@ -78,7 +79,7 @@ class CallCompleter( if (context.trace.wantsDiagnostics()) { if (resolvedCall == null) { - checkMissingSupertypes(context, moduleDescriptor) + checkMissingSupertypes(context, missingSupertypesResolver) } else { val calleeExpression = if (resolvedCall is VariableAsFunctionResolvedCall) resolvedCall.variableCall.call.calleeExpression @@ -88,7 +89,7 @@ class CallCompleter( if (calleeExpression != null && !calleeExpression.isFakeElement) calleeExpression else resolvedCall.call.callElement - val callCheckerContext = CallCheckerContext(context, deprecationResolver, moduleDescriptor) + val callCheckerContext = CallCheckerContext(context, deprecationResolver, moduleDescriptor, missingSupertypesResolver) for (callChecker in callCheckers) { callChecker.check(resolvedCall, reportOn, callCheckerContext) @@ -105,12 +106,15 @@ class CallCompleter( return results } - private fun checkMissingSupertypes(context: BasicCallResolutionContext, moduleDescriptor: ModuleDescriptor) { + private fun checkMissingSupertypes( + context: BasicCallResolutionContext, + missingSupertypesResolver: MissingSupertypesResolver + ) { val call = context.call - val explicitReceiver = call.explicitReceiver.safeAs() - ?: return + val explicitReceiver = call.explicitReceiver.safeAs() ?: return + MissingDependencySupertypeChecker.checkSupertypes( - explicitReceiver.type, call.callElement, context.trace, moduleDescriptor + explicitReceiver.type, call.callElement, context.trace, missingSupertypesResolver ) } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/CallChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/CallChecker.kt index 90cbbd98ed9..60875e30575 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/CallChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/CallChecker.kt @@ -20,6 +20,7 @@ import com.intellij.psi.PsiElement import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.resolve.BindingTrace +import org.jetbrains.kotlin.resolve.MissingSupertypesResolver import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo @@ -42,6 +43,7 @@ class CallCheckerContext @JvmOverloads constructor( val resolutionContext: ResolutionContext<*>, override val deprecationResolver: DeprecationResolver, override val moduleDescriptor: ModuleDescriptor, + val missingSupertypesResolver: MissingSupertypesResolver, override val trace: BindingTrace = resolutionContext.trace ) : CheckerContext { val scope: LexicalScope diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/inference/CoroutineInferenceSession.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/inference/CoroutineInferenceSession.kt index 0c2f4ddce05..0602c5faf68 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/inference/CoroutineInferenceSession.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/inference/CoroutineInferenceSession.kt @@ -9,6 +9,7 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.resolve.BindingTrace +import org.jetbrains.kotlin.resolve.MissingSupertypesResolver import org.jetbrains.kotlin.resolve.TemporaryBindingTrace import org.jetbrains.kotlin.resolve.calls.ArgumentTypeResolver import org.jetbrains.kotlin.resolve.calls.components.CompletedCallInfo @@ -49,7 +50,8 @@ class CoroutineInferenceSession( private val doubleColonExpressionResolver: DoubleColonExpressionResolver, private val deprecationResolver: DeprecationResolver, private val moduleDescriptor: ModuleDescriptor, - private val typeApproximator: TypeApproximator + private val typeApproximator: TypeApproximator, + private val missingSupertypesResolver: MissingSupertypesResolver ) : ManyCandidatesResolver( psiCallResolver, postponedArgumentsAnalyzer, kotlinConstraintSystemCompleter, callComponents, builtIns ) { @@ -222,7 +224,7 @@ class CoroutineInferenceSession( return ResolvedAtomCompleter( resultSubstitutor, context, kotlinToResolvedCallTransformer, expressionTypingServices, argumentTypeResolver, doubleColonExpressionResolver, builtIns, - deprecationResolver, moduleDescriptor, context.dataFlowValueFactory, typeApproximator + deprecationResolver, moduleDescriptor, context.dataFlowValueFactory, typeApproximator, missingSupertypesResolver ) } } 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 6a1a8e42afa..253633c44b8 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 @@ -38,8 +38,6 @@ import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluat import org.jetbrains.kotlin.resolve.deprecation.DeprecationResolver import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns import org.jetbrains.kotlin.resolve.scopes.LexicalScope -import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver -import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValueWithSmartCastInfo import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.expressions.DoubleColonExpressionResolver import org.jetbrains.kotlin.types.expressions.ExpressionTypingServices @@ -75,7 +73,8 @@ class KotlinResolutionCallbacksImpl( val doubleColonExpressionResolver: DoubleColonExpressionResolver, val deprecationResolver: DeprecationResolver, val moduleDescriptor: ModuleDescriptor, - val topLevelCallContext: BasicCallResolutionContext? + val topLevelCallContext: BasicCallResolutionContext?, + val missingSupertypesResolver: MissingSupertypesResolver ) : KotlinResolutionCallbacks { class LambdaInfo(val expectedType: UnwrappedType, val contextDependency: ContextDependency) { val returnStatements = ArrayList>() @@ -161,7 +160,8 @@ class KotlinResolutionCallbacksImpl( psiCallResolver, postponedArgumentsAnalyzer, kotlinConstraintSystemCompleter, callComponents, builtIns, topLevelCallContext, stubsForPostponedVariables, trace, kotlinToResolvedCallTransformer, expressionTypingServices, argumentTypeResolver, - doubleColonExpressionResolver, deprecationResolver, moduleDescriptor, typeApproximator + doubleColonExpressionResolver, deprecationResolver, moduleDescriptor, typeApproximator, + missingSupertypesResolver ) } else { null 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 f483415e3f5..cb93c7805ff 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 @@ -72,7 +72,8 @@ class KotlinToResolvedCallTransformer( private val builtIns: KotlinBuiltIns, private val typeSystemContext: TypeSystemInferenceExtensionContextDelegate, private val smartCastManager: SmartCastManager, - private val typeApproximator: TypeApproximator + private val typeApproximator: TypeApproximator, + private val missingSupertypesResolver: MissingSupertypesResolver ) { companion object { private val REPORT_MISSING_NEW_INFERENCE_DIAGNOSTIC @@ -134,7 +135,7 @@ class KotlinToResolvedCallTransformer( val ktPrimitiveCompleter = ResolvedAtomCompleter( resultSubstitutor, context, this, expressionTypingServices, argumentTypeResolver, doubleColonExpressionResolver, builtIns, deprecationResolver, moduleDescriptor, dataFlowValueFactory, - typeApproximator + typeApproximator, missingSupertypesResolver ) if (!ErrorUtils.isError(candidate.candidateDescriptor)) { 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 330b52282d7..f47863dc005 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 @@ -69,7 +69,8 @@ class PSICallResolver( private val deprecationResolver: DeprecationResolver, private val moduleDescriptor: ModuleDescriptor, private val callableReferenceResolver: CallableReferenceResolver, - private val candidateInterceptor: CandidateInterceptor + private val candidateInterceptor: CandidateInterceptor, + private val missingSupertypesResolver: MissingSupertypesResolver ) { private val givenCandidatesName = Name.special("") @@ -182,7 +183,7 @@ class PSICallResolver( argumentTypeResolver, languageVersionSettings, kotlinToResolvedCallTransformer, dataFlowValueFactory, inferenceSession, constantExpressionEvaluator, typeResolver, this, postponedArgumentsAnalyzer, kotlinConstraintSystemCompleter, callComponents, - doubleColonExpressionResolver, deprecationResolver, moduleDescriptor, context + doubleColonExpressionResolver, deprecationResolver, moduleDescriptor, context, missingSupertypesResolver ) private fun calculateExpectedType(context: BasicCallResolutionContext): UnwrappedType? { 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 6078e5b7922..9a61285badb 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 @@ -15,6 +15,7 @@ import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.psi.KtNamedFunction import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingTrace +import org.jetbrains.kotlin.resolve.MissingSupertypesResolver import org.jetbrains.kotlin.resolve.TemporaryBindingTrace import org.jetbrains.kotlin.resolve.calls.ArgumentTypeResolver import org.jetbrains.kotlin.resolve.calls.NewCommonSuperTypeCalculator @@ -49,9 +50,12 @@ class ResolvedAtomCompleter( private val deprecationResolver: DeprecationResolver, private val moduleDescriptor: ModuleDescriptor, private val dataFlowValueFactory: DataFlowValueFactory, - private val typeApproximator: TypeApproximator + private val typeApproximator: TypeApproximator, + private val missingSupertypesResolver: MissingSupertypesResolver ) { - private val topLevelCallCheckerContext = CallCheckerContext(topLevelCallContext, deprecationResolver, moduleDescriptor) + private val topLevelCallCheckerContext = CallCheckerContext( + topLevelCallContext, deprecationResolver, moduleDescriptor, missingSupertypesResolver + ) private val topLevelTrace = topLevelCallCheckerContext.trace private fun complete(resolvedAtom: ResolvedAtom) { @@ -90,7 +94,7 @@ class ResolvedAtomCompleter( val lastCall = if (resolvedCall is VariableAsFunctionResolvedCall) resolvedCall.functionCall else resolvedCall if (ErrorUtils.isError(resolvedCall.candidateDescriptor)) { kotlinToResolvedCallTransformer.runArgumentsChecks(topLevelCallContext, topLevelTrace, lastCall as NewResolvedCallImpl<*>) - checkMissingReceiverSupertypes(resolvedCall, moduleDescriptor, topLevelTrace) + checkMissingReceiverSupertypes(resolvedCall, missingSupertypesResolver, topLevelTrace) return resolvedCall } @@ -101,7 +105,8 @@ class ResolvedAtomCompleter( CallCheckerContext( resolutionContextForPartialCall.replaceBindingTrace(topLevelTrace), deprecationResolver, - moduleDescriptor + moduleDescriptor, + missingSupertypesResolver ) else topLevelCallCheckerContext @@ -119,7 +124,7 @@ class ResolvedAtomCompleter( private fun checkMissingReceiverSupertypes( resolvedCall: ResolvedCall, - moduleDescriptor: ModuleDescriptor, + missingSupertypesResolver: MissingSupertypesResolver, trace: BindingTrace ) { val receiverValue = resolvedCall.dispatchReceiver ?: resolvedCall.extensionReceiver @@ -128,7 +133,7 @@ class ResolvedAtomCompleter( receiverType, resolvedCall.call.callElement, trace, - moduleDescriptor + missingSupertypesResolver ) } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/DeclarationChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/DeclarationChecker.kt index b0790dda1ee..8426b205c5c 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/DeclarationChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/DeclarationChecker.kt @@ -22,6 +22,7 @@ import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.incremental.components.ExpectActualTracker import org.jetbrains.kotlin.psi.KtDeclaration import org.jetbrains.kotlin.resolve.BindingTrace +import org.jetbrains.kotlin.resolve.MissingSupertypesResolver import org.jetbrains.kotlin.resolve.deprecation.DeprecationResolver interface DeclarationChecker { @@ -33,5 +34,6 @@ class DeclarationCheckerContext( override val languageVersionSettings: LanguageVersionSettings, override val deprecationResolver: DeprecationResolver, override val moduleDescriptor: ModuleDescriptor, - val expectActualTracker: ExpectActualTracker + val expectActualTracker: ExpectActualTracker, + val missingSupertypesResolver: MissingSupertypesResolver ) : CheckerContext diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/MissingDependencySupertypeChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/MissingDependencySupertypeChecker.kt index 03c35b38ad3..c85695a0ac5 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/MissingDependencySupertypeChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/MissingDependencySupertypeChecker.kt @@ -12,29 +12,27 @@ import org.jetbrains.kotlin.psi.KtDeclaration import org.jetbrains.kotlin.psi.KtTypeParameterListOwner import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingTrace +import org.jetbrains.kotlin.resolve.MissingSupertypesResolver import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker import org.jetbrains.kotlin.resolve.calls.checkers.CallCheckerContext import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall -import org.jetbrains.kotlin.resolve.descriptorUtil.classId import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe import org.jetbrains.kotlin.types.KotlinType -import org.jetbrains.kotlin.types.typeUtil.supertypes object MissingDependencySupertypeChecker { object ForDeclarations : DeclarationChecker { override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) { val trace = context.trace - val module = context.moduleDescriptor if (descriptor is ClassDescriptor) { - checkSupertypes(descriptor.defaultType, declaration, trace, module) + checkSupertypes(descriptor, declaration, trace, context.missingSupertypesResolver) } if (declaration is KtTypeParameterListOwner) { for (ktTypeParameter in declaration.typeParameters) { val typeParameterDescriptor = trace.bindingContext.get(BindingContext.TYPE_PARAMETER, ktTypeParameter) ?: continue for (upperBound in typeParameterDescriptor.upperBounds) { - checkSupertypes(upperBound, ktTypeParameter, trace, module) + checkSupertypes(upperBound, ktTypeParameter, trace, context.missingSupertypesResolver) } } } @@ -45,57 +43,54 @@ object MissingDependencySupertypeChecker { override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) { val descriptor = resolvedCall.resultingDescriptor - // Constructor call leads to resolution of supertypes of enclosing class if it's an inner class constructor - checkHierarchy(descriptor.dispatchReceiverParameter?.declaration, reportOn, context) - // The constructed class' own supertypes are not resolved after constructor call, - // so its containing declaration should not be checked. - if (descriptor !is ConstructorDescriptor) { - checkHierarchy(descriptor.containingDeclaration, reportOn, context) - checkHierarchy(descriptor.extensionReceiverParameter?.declaration, reportOn, context) + val errorReported = checkSupertypes( + descriptor.dispatchReceiverParameter?.declaration, reportOn, + context.trace, context.missingSupertypesResolver + ) + if (descriptor !is ConstructorDescriptor && !errorReported) { + // The constructed class' own supertypes are not resolved after constructor call, + // so its containing declaration should not be checked. + // Dispatch receiver is checked before for case of inner class constructor call. + checkSupertypes(descriptor.containingDeclaration, reportOn, context.trace, context.missingSupertypesResolver) + checkSupertypes( + descriptor.extensionReceiverParameter?.declaration, reportOn, + context.trace, context.missingSupertypesResolver + ) } } private val ReceiverParameterDescriptor.declaration get() = value.type.constructor.declarationDescriptor - - private fun checkHierarchy(declaration: DeclarationDescriptor?, reportOn: PsiElement, context: CallCheckerContext) { - if (declaration !is ClassifierDescriptor) return - - checkSupertypes(declaration.defaultType, reportOn, context.trace, context.moduleDescriptor) - } } + // true for reported error fun checkSupertypes( classifierType: KotlinType, reportOn: PsiElement, trace: BindingTrace, - moduleDescriptor: ModuleDescriptor - ) { - val classifierDescriptor = classifierType.constructor.declarationDescriptor ?: return + missingSupertypesResolver: MissingSupertypesResolver + ) = checkSupertypes(classifierType.constructor.declarationDescriptor, reportOn, trace, missingSupertypesResolver) - for (supertype in classifierType.supertypes()) { - val supertypeDeclaration = supertype.constructor.declarationDescriptor + // true for reported error + fun checkSupertypes( + declaration: DeclarationDescriptor?, + reportOn: PsiElement, + trace: BindingTrace, + missingSupertypesResolver: MissingSupertypesResolver + ): Boolean { + if (declaration !is ClassifierDescriptor) + return false - /* - * TODO: expects are not checked, because findClassAcrossModuleDependencies does not work with actualization via type alias - * Type parameters are skipped here, bounds of type parameters are checked in declaration checker separately - * Local declarations are ignored for optimization - */ - if (supertypeDeclaration !is ClassDescriptor || supertypeDeclaration.isExpect) continue - if (supertypeDeclaration.visibility == Visibilities.LOCAL) continue - - val superTypeClassId = supertypeDeclaration.classId ?: continue - val dependency = moduleDescriptor.findClassAcrossModuleDependencies(superTypeClassId) - - if (dependency == null || dependency is NotFoundClasses.MockClassDescriptor) { - trace.report( - Errors.MISSING_DEPENDENCY_SUPERCLASS.on( - reportOn, - supertypeDeclaration.fqNameSafe, - classifierDescriptor.fqNameSafe - ) + val missingSupertypes = missingSupertypesResolver.getMissingSuperClassifiers(declaration) + for (missingClassifier in missingSupertypes) { + trace.report( + Errors.MISSING_DEPENDENCY_SUPERCLASS.on( + reportOn, + missingClassifier.fqNameSafe, + declaration.fqNameSafe ) - } + ) } + return missingSupertypes.isNotEmpty() } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java index 4d9a156e249..b59ec9ca5ac 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java @@ -961,7 +961,13 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { // Call must be validated with the actual, not temporary trace in order to report operator diagnostic // Only unary assignment expressions (++, --) and +=/... must be checked, normal assignments have the proper trace CallCheckerContext callCheckerContext = - new CallCheckerContext(context, components.deprecationResolver, components.moduleDescriptor, trace); + new CallCheckerContext( + context, + components.deprecationResolver, + components.moduleDescriptor, + components.missingSupertypesResolver, + trace + ); for (CallChecker checker : components.callCheckers) { checker.check(resolvedCall, expression, callCheckerContext); } @@ -1038,7 +1044,12 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { @NotNull private CallCheckerContext createCallCheckerContext(@NotNull ExpressionTypingContext context) { - return new CallCheckerContext(context, components.deprecationResolver, components.moduleDescriptor); + return new CallCheckerContext( + context, + components.deprecationResolver, + components.moduleDescriptor, + components.missingSupertypesResolver + ); } @Override diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingComponents.java b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingComponents.java index 208513313de..77e4303401a 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingComponents.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingComponents.java @@ -66,6 +66,7 @@ public class ExpressionTypingComponents { /*package*/ DataFlowValueFactory dataFlowValueFactory; /*package*/ NewKotlinTypeChecker kotlinTypeChecker; /*package*/ TypeResolutionInterceptor typeResolutionInterceptor; + /*package*/ MissingSupertypesResolver missingSupertypesResolver; @Inject @@ -252,4 +253,9 @@ public class ExpressionTypingComponents { public void setTypeResolutionInterceptor(@NotNull TypeResolutionInterceptor typeResolutionInterceptor) { this.typeResolutionInterceptor = typeResolutionInterceptor; } + + @Inject + public void setMissingSupertypesResolver(@NotNull MissingSupertypesResolver missingSupertypesResolver) { + this.missingSupertypesResolver = missingSupertypesResolver; + } }