From 28d15e776aed4e996df5ecde6dc09a447f04d670 Mon Sep 17 00:00:00 2001 From: Dmitry Petrov Date: Wed, 11 Nov 2015 16:43:29 +0300 Subject: [PATCH] Drop createQualifier. NB: some regression in diagnostics for special cases, such as class or package used in expression position or in safe access; see next commit. --- .../resolve/QualifiedExpressionResolveUtil.kt | 87 +++++++++---------- .../resolve/QualifiedExpressionResolver.kt | 52 ++++++++--- .../resolve/calls/CallExpressionResolver.java | 35 +++++--- .../tasks/CallableDescriptorCollectors.kt | 19 +++- .../resolve/scopes/receivers/Qualifier.kt | 33 ------- 5 files changed, 116 insertions(+), 110 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/QualifiedExpressionResolveUtil.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/QualifiedExpressionResolveUtil.kt index 78615d6066f..95c6a188ec5 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/QualifiedExpressionResolveUtil.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/QualifiedExpressionResolveUtil.kt @@ -23,65 +23,54 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.hasClassObjectType import org.jetbrains.kotlin.resolve.scopes.receivers.ClassQualifier import org.jetbrains.kotlin.resolve.scopes.receivers.ClassifierQualifier import org.jetbrains.kotlin.resolve.scopes.receivers.PackageQualifier -import org.jetbrains.kotlin.resolve.scopes.receivers.QualifierReceiver +import org.jetbrains.kotlin.resolve.scopes.receivers.Qualifier import org.jetbrains.kotlin.resolve.validation.SymbolUsageValidator import org.jetbrains.kotlin.types.expressions.ExpressionTypingContext -public fun resolveAsReceiverInQualifiedExpression( - qualifier: QualifierReceiver, - context: ExpressionTypingContext, +public fun resolveQualifierAsReceiverInExpression( + qualifier: Qualifier, selector: DeclarationDescriptor?, - symbolUsageValidator: SymbolUsageValidator -) { - resolveAndRecordReferenceTarget(qualifier, context, selector, symbolUsageValidator) - - if (qualifier is ClassifierQualifier) { - val classifier = qualifier.classifier - if (classifier is TypeParameterDescriptor) { - context.trace.report(Errors.TYPE_PARAMETER_ON_LHS_OF_DOT.on(qualifier.referenceExpression, classifier)) - } - else if (classifier is ClassDescriptor && classifier.hasClassObjectType) { - context.trace.recordType(qualifier.expression, classifier.classObjectType) - } - } -} - -public fun resolveAsStandaloneExpression( - qualifier: QualifierReceiver, context: ExpressionTypingContext, symbolUsageValidator: SymbolUsageValidator -) { - resolveAndRecordReferenceTarget(qualifier, context, selector = null, symbolUsageValidator = symbolUsageValidator) +): DeclarationDescriptor { + val referenceTarget = resolveQualifierReferenceTarget(qualifier, selector, context, symbolUsageValidator) - if (qualifier is ClassifierQualifier) { - val classifier = qualifier.classifier - if (classifier is TypeParameterDescriptor) { - context.trace.report(Errors.TYPE_PARAMETER_IS_NOT_AN_EXPRESSION.on(qualifier.referenceExpression, classifier)) - } - else if (classifier is ClassDescriptor && !classifier.hasClassObjectType) { - context.trace.report(Errors.NO_COMPANION_OBJECT.on(qualifier.referenceExpression, classifier)) - } - } - else if (qualifier is PackageQualifier) { - context.trace.report(Errors.EXPRESSION_EXPECTED_PACKAGE_FOUND.on(qualifier.referenceExpression)) + if (referenceTarget is TypeParameterDescriptor) { + context.trace.report(Errors.TYPE_PARAMETER_ON_LHS_OF_DOT.on(qualifier.referenceExpression, referenceTarget)) } + + return referenceTarget } -private fun resolveAndRecordReferenceTarget( - qualifier: QualifierReceiver, +public fun resolveQualifierAsStandaloneExpression( + qualifier: Qualifier, context: ExpressionTypingContext, - selector: DeclarationDescriptor?, symbolUsageValidator: SymbolUsageValidator -) { - val resultingDescriptor = resolveReferenceTarget(qualifier, context, selector, symbolUsageValidator) - context.trace.record(BindingContext.REFERENCE_TARGET, qualifier.referenceExpression, resultingDescriptor) +): DeclarationDescriptor { + val referenceTarget = resolveQualifierReferenceTarget(qualifier, null, context, symbolUsageValidator) + + when (referenceTarget) { + is TypeParameterDescriptor -> { + context.trace.report(Errors.TYPE_PARAMETER_IS_NOT_AN_EXPRESSION.on(qualifier.referenceExpression, referenceTarget)) + } + is ClassDescriptor -> { + if (!referenceTarget.kind.isSingleton) { + context.trace.report(Errors.NO_COMPANION_OBJECT.on(qualifier.referenceExpression, referenceTarget)) + } + } + is PackageViewDescriptor -> { + context.trace.report(Errors.EXPRESSION_EXPECTED_PACKAGE_FOUND.on(qualifier.referenceExpression)) + } + } + + return referenceTarget } -private fun resolveReferenceTarget( - qualifier: QualifierReceiver, - context: ExpressionTypingContext, +private fun resolveQualifierReferenceTarget( + qualifier: Qualifier, selector: DeclarationDescriptor?, + context: ExpressionTypingContext, symbolUsageValidator: SymbolUsageValidator ): DeclarationDescriptor { if (qualifier is ClassifierQualifier && qualifier.classifier is TypeParameterDescriptor) { @@ -102,15 +91,19 @@ private fun resolveReferenceTarget( return qualifier.packageView } + // TODO make decisions about short reference to companion object somewhere else if (qualifier is ClassQualifier) { + val classifier = qualifier.classifier if (selector is CallableDescriptor && (selector.dispatchReceiverParameter != null || selector.extensionReceiverParameter != null) && - qualifier.classifier is ClassDescriptor && - qualifier.classifier.hasClassObjectType + classifier is ClassDescriptor && + classifier.hasClassObjectType ) { - val companionObjectDescriptor = qualifier.classifier.companionObjectDescriptor + val companionObjectDescriptor = classifier.companionObjectDescriptor if (companionObjectDescriptor != null) { - context.trace.record(BindingContext.SHORT_REFERENCE_TO_COMPANION_OBJECT, qualifier.referenceExpression, qualifier.classifier) + context.trace.record(BindingContext.REFERENCE_TARGET, qualifier.referenceExpression, companionObjectDescriptor) + context.trace.record(BindingContext.SHORT_REFERENCE_TO_COMPANION_OBJECT, qualifier.referenceExpression, classifier) + context.trace.recordType(qualifier.expression, classifier.classObjectType) symbolUsageValidator.validateTypeUsage(companionObjectDescriptor, context.trace, qualifier.referenceExpression) return companionObjectDescriptor } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/QualifiedExpressionResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/QualifiedExpressionResolver.kt index 29483eab7a7..bf43a40996d 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/QualifiedExpressionResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/QualifiedExpressionResolver.kt @@ -28,14 +28,11 @@ import org.jetbrains.kotlin.resolve.calls.unrollToLeftMostQualifiedExpression import org.jetbrains.kotlin.resolve.descriptorUtil.module import org.jetbrains.kotlin.resolve.scopes.ImportingScope import org.jetbrains.kotlin.resolve.scopes.LexicalScope -import org.jetbrains.kotlin.resolve.scopes.receivers.PackageQualifier -import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue -import org.jetbrains.kotlin.resolve.scopes.receivers.createClassifierQualifier -import org.jetbrains.kotlin.resolve.scopes.utils.findClassifier +import org.jetbrains.kotlin.resolve.scopes.receivers.* +import org.jetbrains.kotlin.resolve.scopes.utils.* import org.jetbrains.kotlin.resolve.source.KotlinSourceElement import org.jetbrains.kotlin.resolve.validation.SymbolUsageValidator import org.jetbrains.kotlin.types.expressions.ExpressionTypingContext -import org.jetbrains.kotlin.types.expressions.ExpressionTypingServices import org.jetbrains.kotlin.utils.addIfNotNull import org.jetbrains.kotlin.utils.addToStdlib.check @@ -392,6 +389,33 @@ public class QualifiedExpressionResolver(val symbolUsageValidator: SymbolUsageVa return Pair(currentDescriptor, path.size) } + public fun resolveNameExpressionAsQualifierForDiagnostics( + expression: KtSimpleNameExpression, + receiver: Receiver, + context: ExpressionTypingContext + ): Qualifier? { + val name = expression.getReferencedNameAsName() + + val qualifierDescriptor = when { + receiver is PackageQualifier -> { + val childPackageFQN = receiver.packageView.fqName.child(name) + val childPackageDescriptor = receiver.packageView.module.getPackage(childPackageFQN).check { !it.isEmpty() } + childPackageDescriptor ?: receiver.packageView.memberScope.getContributedClassifier(name, KotlinLookupLocation(expression)) + } + receiver is ClassQualifier -> + receiver.scope.getContributedClassifier(name, KotlinLookupLocation(expression)) + !receiver.exists() -> + context.scope.findClassifier(name, KotlinLookupLocation(expression)) ?: + context.scope.ownerDescriptor.module.getPackage(FqName.ROOT.child(name)).check { !it.isEmpty() } + else -> null + } + + if (qualifierDescriptor != null) { + return storeResult(context.trace, expression, qualifierDescriptor, context.scope.ownerDescriptor, QualifierPosition.EXPRESSION) + } + + return null + } public fun resolveQualifierInExpressionAndUnroll( expression: KtQualifiedExpression, @@ -411,11 +435,11 @@ public class QualifiedExpressionResolver(val symbolUsageValidator: SymbolUsageVa isValue = isValue ).second - val firstExpressionAfterQualifierIndex = + val nextExpressionIndexAfterQualifier = if (nextIndexAfterPrefix == 0) 0 else nextIndexAfterPrefix - 1 return qualifiedExpressions - .subList(firstExpressionAfterQualifierIndex, qualifiedExpressions.size) + .subList(nextExpressionIndexAfterQualifier, qualifiedExpressions.size) .map { CallExpressionElement(it) } } @@ -520,10 +544,10 @@ public class QualifiedExpressionResolver(val symbolUsageValidator: SymbolUsageVa shouldBeVisibleFrom: DeclarationDescriptor?, position: QualifierPosition, isQualifier: Boolean = true - ) { + ): Qualifier? { if (descriptor == null) { trace.report(Errors.UNRESOLVED_REFERENCE.on(referenceExpression, referenceExpression)) - return + return null } trace.record(BindingContext.REFERENCE_TARGET, referenceExpression, descriptor) @@ -545,20 +569,20 @@ public class QualifiedExpressionResolver(val symbolUsageValidator: SymbolUsageVa } } - if (isQualifier) { - storeQualifier(trace, referenceExpression, descriptor) - } + return if (isQualifier) storeQualifier(trace, referenceExpression, descriptor) else null } - private fun storeQualifier(trace: BindingTrace, referenceExpression: KtSimpleNameExpression, descriptor: DeclarationDescriptor) { + private fun storeQualifier(trace: BindingTrace, referenceExpression: KtSimpleNameExpression, descriptor: DeclarationDescriptor): Qualifier? { val qualifier = when (descriptor) { is PackageViewDescriptor -> PackageQualifier(referenceExpression, descriptor) is ClassifierDescriptor -> createClassifierQualifier(referenceExpression, descriptor, trace.bindingContext) - else -> return + else -> return null } trace.record(BindingContext.QUALIFIER, qualifier.expression, qualifier) + + return qualifier } private fun isVisible( diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallExpressionResolver.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallExpressionResolver.java index 13a7f425305..57f42fd430c 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallExpressionResolver.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallExpressionResolver.java @@ -127,8 +127,9 @@ public class CallExpressionResolver { // if the expression is a receiver in a qualified expression, it should be resolved after the selector is resolved boolean isLHSOfDot = KtPsiUtil.isLHSOfDot(nameExpression); if (!resolutionResult.isNothing() && resolutionResult.getResultCode() != OverloadResolutionResults.Code.CANDIDATES_WITH_WRONG_RECEIVER) { - boolean isQualifier = isLHSOfDot && resolutionResult.isSingleResult() - && resolutionResult.getResultingDescriptor() instanceof FakeCallableDescriptorForObject; + boolean isQualifier = isLHSOfDot && + resolutionResult.isSingleResult() && + resolutionResult.getResultingDescriptor() instanceof FakeCallableDescriptorForObject; if (!isQualifier) { result[0] = true; temporaryForVariable.commit(); @@ -136,14 +137,13 @@ public class CallExpressionResolver { } } - QualifierReceiver qualifier = QualifierKt.createQualifier(nameExpression, receiver, context); - if (qualifier != null) { - result[0] = true; - if (!isLHSOfDot) { - QualifiedExpressionResolveUtilKt.resolveAsStandaloneExpression(qualifier, context, symbolUsageValidator); - } - return null; - } + //// Generate some diagnostics for qualifier in unexpected position + //DeclarationDescriptor qualifierDescriptor = + // QualifiedExpressionResolveUtilKt.getQualifierDescriptorOrNull(nameExpression, receiver, context); + //if (qualifierDescriptor != null) { + // QualifiedExpressionResolveUtilKt.checkQualifierAsStandaloneExpression(qualifierDescriptor, nameExpression, context); + //} + temporaryForVariable.commit(); result[0] = !resolutionResult.isNothing(); return resolutionResult.isSingleResult() ? resolutionResult.getResultingDescriptor().getReturnType() : null; @@ -191,6 +191,15 @@ public class CallExpressionResolver { return TypeInfoFactoryKt.createTypeInfo(type, context); } + TemporaryTraceAndCache temporaryForQualifier = TemporaryTraceAndCache.create(context, "trace to resolve as qualifier", nameExpression); + ExpressionTypingContext contextForQualifier = context.replaceTraceAndCache(temporaryForQualifier); + Qualifier qualifier = qualifiedExpressionResolver.resolveNameExpressionAsQualifierForDiagnostics(nameExpression, receiver, contextForQualifier); + if (qualifier != null) { + QualifiedExpressionResolveUtilKt.resolveQualifierAsStandaloneExpression(qualifier, contextForQualifier, symbolUsageValidator); + temporaryForQualifier.commit(); + return TypeInfoFactoryKt.createTypeInfo(null, context); + } + temporaryForVariable.commit(); return TypeInfoFactoryKt.noTypeInfo(context); } @@ -350,7 +359,9 @@ public class CallExpressionResolver { return false; } - return !resolutionResult.isNothing(); + OverloadResolutionResults.Code resultCode = resolutionResult.getResultCode(); + return resultCode != OverloadResolutionResults.Code.NAME_NOT_FOUND && + resultCode != OverloadResolutionResults.Code.CANDIDATES_WITH_WRONG_RECEIVER; } }; List elementChain = @@ -462,7 +473,7 @@ public class CallExpressionResolver { calleeExpression instanceof KtReferenceExpression ? context.trace.get(BindingContext.REFERENCE_TARGET, (KtReferenceExpression) calleeExpression) : null; - QualifiedExpressionResolveUtilKt.resolveAsReceiverInQualifiedExpression(qualifierReceiver, context, selectorDescriptor, symbolUsageValidator); + QualifiedExpressionResolveUtilKt.resolveQualifierAsReceiverInExpression(qualifierReceiver, selectorDescriptor, context, symbolUsageValidator); } private static void checkNestedClassAccess( diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/CallableDescriptorCollectors.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/CallableDescriptorCollectors.kt index f25a6509725..2b0d1524d82 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/CallableDescriptorCollectors.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/CallableDescriptorCollectors.kt @@ -16,6 +16,7 @@ package org.jetbrains.kotlin.resolve.calls.tasks.collectors +import com.intellij.util.SmartList import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.functions.FunctionInvokeDescriptor import org.jetbrains.kotlin.descriptors.* @@ -33,6 +34,7 @@ import org.jetbrains.kotlin.resolve.scopes.utils.* import org.jetbrains.kotlin.types.ErrorUtils import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.util.OperatorNameConventions +import org.jetbrains.kotlin.utils.addIfNotNull public interface CallableDescriptorCollector { @@ -165,7 +167,10 @@ private object FunctionCollector : CallableDescriptorCollector { override fun getLocalNonExtensionsByName(lexicalScope: LexicalScope, name: Name, location: LookupLocation): Collection { - return listOfNotNull(lexicalScope.findLocalVariable(name)) + val result = SmartList() + result.addIfNotNull(lexicalScope.findLocalVariable(name)) + result.addIfNotNull(getContributedFakeDescriptorForObject(lexicalScope, name, location)) + return result } override fun getStaticInheritanceByName(lexicalScope: LexicalScope, name: Name, location: LookupLocation): Collection { @@ -179,7 +184,13 @@ private object VariableCollector : CallableDescriptorCollector { val properties = scope.collectVariables(name, location).filter { it.extensionReceiverParameter == null } - val fakeDescriptor = getFakeDescriptorForObject(scope, name, location) + val fakeDescriptor = findFakeDescriptorForObject(scope, name, location) return if (fakeDescriptor != null) properties + fakeDescriptor else properties } override fun getMembersByName(receiver: KotlinType, name: Name, location: LookupLocation): Collection { val memberScope = receiver.memberScope val properties = memberScope.getContributedVariables(name, location) - val fakeDescriptor = getFakeDescriptorForObject(memberScope.memberScopeAsImportingScope(), name, location) + val fakeDescriptor = findFakeDescriptorForObject(memberScope.memberScopeAsImportingScope(), name, location) return if (fakeDescriptor != null) properties + fakeDescriptor else properties } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/scopes/receivers/Qualifier.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/scopes/receivers/Qualifier.kt index b89acfd75c3..5dce7f2dd7c 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/scopes/receivers/Qualifier.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/scopes/receivers/Qualifier.kt @@ -149,39 +149,6 @@ class ClassQualifier( override fun toString() = "Class{$classifier}" } -fun createQualifier(expression: KtSimpleNameExpression, receiver: Receiver, context: ExpressionTypingContext): QualifierReceiver? { - val receiverScope = when { - !receiver.exists() -> context.scope - receiver is QualifierReceiver -> receiver.scope.memberScopeAsImportingScope() - receiver is ReceiverValue -> receiver.type.memberScope.memberScopeAsImportingScope() - else -> throw IllegalArgumentException("Unexpected receiver kind: $receiver") - } - - val name = expression.getReferencedNameAsName() - val packageViewDescriptor = receiverScope.findPackage(name) - val classifierDescriptor = receiverScope.findClassifier(name, KotlinLookupLocation(expression)) - - if (packageViewDescriptor == null && classifierDescriptor == null) return null - - context.trace.recordScope(context.scope, expression) - - val qualifier = - if (receiver is PackageQualifier) { - if (packageViewDescriptor != null) - PackageQualifier(expression, packageViewDescriptor) - else - createClassifierQualifier(expression, classifierDescriptor!!, context.trace.bindingContext) - else - if (classifierDescriptor != null) - createClassifierQualifier(expression, classifierDescriptor, context.trace.bindingContext) - else - PackageQualifier(expression, packageViewDescriptor!!) - } - - context.trace.record(QUALIFIER, qualifier.expression, qualifier) - return qualifier -} - fun createClassifierQualifier( referenceExpression: KtSimpleNameExpression, classifier: ClassifierDescriptor,