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.
This commit is contained in:
Dmitry Petrov
2015-11-11 16:43:29 +03:00
parent b532fa2bbf
commit 28d15e776a
5 changed files with 116 additions and 110 deletions
@@ -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
}
@@ -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(
@@ -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<CallExpressionElement> 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(
@@ -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<D : CallableDescriptor> {
@@ -165,7 +167,10 @@ private object FunctionCollector : CallableDescriptorCollector<FunctionDescripto
private object VariableCollector : CallableDescriptorCollector<VariableDescriptor> {
override fun getLocalNonExtensionsByName(lexicalScope: LexicalScope, name: Name, location: LookupLocation): Collection<VariableDescriptor> {
return listOfNotNull(lexicalScope.findLocalVariable(name))
val result = SmartList<VariableDescriptor>()
result.addIfNotNull(lexicalScope.findLocalVariable(name))
result.addIfNotNull(getContributedFakeDescriptorForObject(lexicalScope, name, location))
return result
}
override fun getStaticInheritanceByName(lexicalScope: LexicalScope, name: Name, location: LookupLocation): Collection<VariableDescriptor> {
@@ -179,7 +184,13 @@ private object VariableCollector : CallableDescriptorCollector<VariableDescripto
}
}
private fun getFakeDescriptorForObject(scope: HierarchicalScope, name: Name, location: LookupLocation): VariableDescriptor? {
private fun getContributedFakeDescriptorForObject(scope: LexicalScope, name: Name, location: LookupLocation): VariableDescriptor? {
val classifier = scope.getContributedClassifier(name, location)
if (classifier !is ClassDescriptor || !classifier.hasClassObjectType) return null
return FakeCallableDescriptorForObject(classifier)
}
private fun findFakeDescriptorForObject(scope: HierarchicalScope, name: Name, location: LookupLocation): VariableDescriptor? {
val classifier = scope.findClassifier(name, location)
if (classifier !is ClassDescriptor || !classifier.hasCompanionObject) return null
@@ -188,14 +199,14 @@ private object VariableCollector : CallableDescriptorCollector<VariableDescripto
override fun getNonExtensionsByName(scope: HierarchicalScope, name: Name, location: LookupLocation): Collection<VariableDescriptor> {
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<VariableDescriptor> {
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
}
@@ -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,