diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/psiUtil/jetPsiUtil.kt b/compiler/frontend/src/org/jetbrains/jet/lang/psi/psiUtil/jetPsiUtil.kt index 10bb92791b7..70d89f65276 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/psiUtil/jetPsiUtil.kt +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/psiUtil/jetPsiUtil.kt @@ -229,6 +229,13 @@ public fun JetSimpleNameExpression.getQualifiedElement(): JetElement { } } +public fun JetSimpleNameExpression.getTopmostParentQualifiedExpressionForSelector(): JetQualifiedExpression? { + return stream(this) { + val parentQualified = it.getParent() as? JetQualifiedExpression + if (parentQualified?.getSelectorExpression() == it) parentQualified else null + }.last() as? JetQualifiedExpression +} + /** * Returns rightmost selector of the qualified element (null if there is no such selector) */ diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContext.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContext.java index 54708064425..07bb0a1794d 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContext.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContext.java @@ -34,6 +34,7 @@ import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant; import org.jetbrains.jet.lang.resolve.name.FqName; import org.jetbrains.jet.lang.resolve.name.FqNameUnsafe; import org.jetbrains.jet.lang.resolve.scopes.JetScope; +import org.jetbrains.jet.lang.resolve.scopes.receivers.QualifierReceiver; import org.jetbrains.jet.lang.types.DeferredType; import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.expressions.CaptureKind; @@ -84,6 +85,8 @@ public interface BindingContext { WritableSlice EXPRESSION_DATA_FLOW_INFO = new BasicWritableSlice(DO_NOTHING); WritableSlice DATAFLOW_INFO_AFTER_CONDITION = Slices.createSimpleSlice(); + WritableSlice QUALIFIER_RECEIVER = new BasicWritableSlice(DO_NOTHING); + WritableSlice REFERENCE_TARGET = new BasicWritableSlice(DO_NOTHING); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/JetModuleUtil.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/JetModuleUtil.java index a12782b0646..4b2d8389957 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/JetModuleUtil.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/JetModuleUtil.java @@ -20,19 +20,10 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.descriptors.ModuleDescriptor; import org.jetbrains.jet.lang.descriptors.PackageViewDescriptor; import org.jetbrains.jet.lang.descriptors.impl.SubpackagesScope; -import org.jetbrains.jet.lang.psi.JetElement; import org.jetbrains.jet.lang.resolve.name.FqName; -import org.jetbrains.jet.lang.resolve.name.SpecialNames; import org.jetbrains.jet.lang.resolve.scopes.JetScope; -import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue; -import org.jetbrains.jet.lang.types.PackageType; public class JetModuleUtil { - public static PackageType getRootPackageType(JetElement expression) { - // TODO: this is a stub: at least the modules' root packages must be indexed here - return new PackageType(SpecialNames.ROOT_PACKAGE, JetScope.EMPTY, ReceiverValue.NO_RECEIVER); - } - public static JetScope getSubpackagesOfRootScope(@NotNull ModuleDescriptor module) { return getRootPackageScope(module, /* scopeIncludingMembers = */ false); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallExpressionResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallExpressionResolver.java index cee060dd5b8..bd96f19da77 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallExpressionResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallExpressionResolver.java @@ -24,8 +24,10 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.evaluate.ConstantExpressionEvaluator; import org.jetbrains.jet.lang.psi.*; -import org.jetbrains.jet.lang.psi.codeFragmentUtil.CodeFragmentUtilPackage; -import org.jetbrains.jet.lang.resolve.*; +import org.jetbrains.jet.lang.resolve.BindingContext; +import org.jetbrains.jet.lang.resolve.BindingTrace; +import org.jetbrains.jet.lang.resolve.DescriptorUtils; +import org.jetbrains.jet.lang.resolve.calls.callUtil.CallUtilPackage; import org.jetbrains.jet.lang.resolve.calls.context.BasicCallResolutionContext; import org.jetbrains.jet.lang.resolve.calls.context.CheckValueArgumentsMode; import org.jetbrains.jet.lang.resolve.calls.context.ResolutionContext; @@ -37,32 +39,27 @@ import org.jetbrains.jet.lang.resolve.calls.util.CallMaker; import org.jetbrains.jet.lang.resolve.calls.util.FakeCallableDescriptorForObject; import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant; import org.jetbrains.jet.lang.resolve.constants.IntegerValueConstant; -import org.jetbrains.jet.lang.resolve.name.Name; -import org.jetbrains.jet.lang.resolve.scopes.ChainedScope; -import org.jetbrains.jet.lang.resolve.scopes.JetScope; -import org.jetbrains.jet.lang.resolve.scopes.JetScopeImpl; import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver; +import org.jetbrains.jet.lang.resolve.scopes.receivers.QualifierReceiver; import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue; -import org.jetbrains.jet.lang.types.*; +import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiversPackage; +import org.jetbrains.jet.lang.types.ErrorUtils; +import org.jetbrains.jet.lang.types.JetType; +import org.jetbrains.jet.lang.types.JetTypeInfo; +import org.jetbrains.jet.lang.types.TypeUtils; import org.jetbrains.jet.lang.types.expressions.BasicExpressionTypingVisitor; import org.jetbrains.jet.lang.types.expressions.DataFlowUtils; import org.jetbrains.jet.lang.types.expressions.ExpressionTypingContext; import org.jetbrains.jet.lang.types.expressions.ExpressionTypingServices; import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; import org.jetbrains.jet.lexer.JetTokens; -import org.jetbrains.jet.utils.Printer; import javax.inject.Inject; -import java.util.ArrayList; import java.util.Collections; -import java.util.List; import static org.jetbrains.jet.lang.diagnostics.Errors.*; -import static org.jetbrains.jet.lang.psi.JetPsiUtil.isLHSOfDot; -import static org.jetbrains.jet.lang.resolve.BindingContext.*; -import static org.jetbrains.jet.lang.resolve.DescriptorUtils.getStaticNestedClassesScope; import static org.jetbrains.jet.lang.resolve.calls.context.ContextDependency.INDEPENDENT; -import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue.NO_RECEIVER; +import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiversPackage.*; import static org.jetbrains.jet.lang.types.TypeUtils.NO_EXPECTED_TYPE; public class CallExpressionResolver { @@ -74,156 +71,6 @@ public class CallExpressionResolver { this.expressionTypingServices = expressionTypingServices; } - @Nullable - private JetType lookupPackageOrClassObject(@NotNull JetSimpleNameExpression expression, @NotNull ExpressionTypingContext context) { - Name referencedName = expression.getReferencedNameAsName(); - final ClassifierDescriptor classifier = context.scope.getClassifier(referencedName); - if (classifier != null) { - JetType classObjectType = classifier.getClassObjectType(); - if (classObjectType != null) { - context.trace.record(REFERENCE_TARGET, expression, classifier); - JetType result = getExtendedClassObjectType(expression, classObjectType, classifier, context.scope); - checkClassObjectVisibility(classifier, expression, context); - return result; - } - } - JetType[] result = new JetType[1]; - TemporaryBindingTrace temporaryTrace = TemporaryBindingTrace.create( - context.trace, "trace for package/class object lookup of name", referencedName); - if (furtherNameLookup(expression, result, context.replaceBindingTrace(temporaryTrace))) { - temporaryTrace.commit(); - return DataFlowUtils.checkType(result[0], expression, context); - } - // To report NO_CLASS_OBJECT when no package found - if (classifier != null) { - if (classifier instanceof TypeParameterDescriptor) { - if (isLHSOfDot(expression)) { - context.trace.report(TYPE_PARAMETER_ON_LHS_OF_DOT.on(expression, (TypeParameterDescriptor) classifier)); - } - else { - context.trace.report(TYPE_PARAMETER_IS_NOT_AN_EXPRESSION.on(expression, (TypeParameterDescriptor) classifier)); - } - } - else if (!isLHSOfDot(expression)) { - context.trace.report(NO_CLASS_OBJECT.on(expression, classifier)); - } - context.trace.record(REFERENCE_TARGET, expression, classifier); - JetScope scopeForStaticMembersResolution = - classifier instanceof ClassDescriptor - ? getStaticNestedClassesScope((ClassDescriptor) classifier) - : new JetScopeImpl() { - @NotNull - @Override - public DeclarationDescriptor getContainingDeclaration() { - return classifier; - } - - @Override - public String toString() { - return "Scope for the type parameter on the left hand side of dot"; - } - - @Override - public void printScopeStructure(@NotNull Printer p) { - p.println(toString(), " for ", classifier); - } - }; - return new PackageType(referencedName, scopeForStaticMembersResolution, NO_RECEIVER); - } - temporaryTrace.commit(); - return result[0]; - } - - private static void checkClassObjectVisibility( - @NotNull ClassifierDescriptor classifier, - @NotNull JetSimpleNameExpression expression, - @NotNull ExpressionTypingContext context - ) { - if (!(classifier instanceof ClassDescriptor)) return; - - ClassDescriptor classObject = ((ClassDescriptor) classifier).getClassObjectDescriptor(); - assert classObject != null : "This check should be done only for classes with class objects: " + classifier; - DeclarationDescriptor from = context.scope.getContainingDeclaration(); - if (!Visibilities.isVisible(classObject, from)) { - context.trace.report(INVISIBLE_MEMBER.on(expression, classObject, classObject.getVisibility(), from)); - } - } - - @NotNull - private static JetType getExtendedClassObjectType( - @NotNull JetSimpleNameExpression expression, - @NotNull JetType classObjectType, - @NotNull ClassifierDescriptor classifier, - @NotNull JetScope receiverScope - ) { - if (!isLHSOfDot(expression) || !(classifier instanceof ClassDescriptor)) { - return classObjectType; - } - ClassDescriptor classDescriptor = (ClassDescriptor) classifier; - - if (classDescriptor.getKind() == ClassKind.ENUM_ENTRY) { - return classObjectType; - } - - List scopes = new ArrayList(3); - - scopes.add(classObjectType.getMemberScope()); - scopes.add(getStaticNestedClassesScope(classDescriptor)); - - Name referencedName = expression.getReferencedNameAsName(); - PackageViewDescriptor packageView = receiverScope.getPackage(referencedName); - if (packageView != null) { - //for enums loaded from java binaries - scopes.add(packageView.getMemberScope()); - } - - JetScope scope = new ChainedScope( - classifier, "Member scope for extended class object type " + classifier, scopes.toArray(new JetScope[scopes.size()]) - ); - return new PackageType(referencedName, scope, new ExpressionReceiver(expression, classObjectType)); - } - - private boolean furtherNameLookup( - @NotNull JetSimpleNameExpression expression, - @NotNull JetType[] result, - @NotNull ResolutionContext context - ) { - PackageType packageType = lookupPackageType(expression, context); - if (packageType == null) { - return false; - } - if (isLHSOfDot(expression)) { - result[0] = packageType; - return true; - } - context.trace.report(EXPRESSION_EXPECTED_PACKAGE_FOUND.on(expression)); - result[0] = ErrorUtils.createErrorType("Type for " + expression.getReferencedNameAsName()); - return false; - } - - @Nullable - private PackageType lookupPackageType(@NotNull JetSimpleNameExpression expression, @NotNull ResolutionContext context) { - Name name = expression.getReferencedNameAsName(); - PackageViewDescriptor packageView = context.scope.getPackage(name); - if (packageView == null) { - return null; - } - context.trace.record(REFERENCE_TARGET, expression, packageView); - - // Construct a PackageType with everything from the package and with nested classes of the corresponding class (if any) - JetScope scope; - ClassifierDescriptor classifier = context.scope.getClassifier(name); - if (classifier instanceof ClassDescriptor) { - scope = new ChainedScope( - packageView, "Package type member scope for " + expression.getText(), packageView.getMemberScope(), getStaticNestedClassesScope((ClassDescriptor) classifier) - ); - } - else { - scope = packageView.getMemberScope(); - } - return new PackageType(name, scope, NO_RECEIVER); - } - @Nullable public ResolvedCall getResolvedCallForFunction( @NotNull Call call, @NotNull JetExpression callExpression, @@ -254,36 +101,27 @@ public class CallExpressionResolver { context.replaceTraceAndCache(temporaryForVariable), call, CheckValueArgumentsMode.ENABLED); OverloadResolutionResults resolutionResult = callResolver.resolveSimpleProperty(contextForVariable); - JetScope receiverScope = receiver.exists() ? receiver.getType().getMemberScope() : context.scope; - if (resolutionResult.isSuccess()) { - result[0] = true; - if (resolutionResult.getResultingDescriptor() instanceof FakeCallableDescriptorForObject) { - FakeCallableDescriptorForObject fakeCallableDescriptorForObject = - (FakeCallableDescriptorForObject) resolutionResult.getResultingDescriptor(); - ClassDescriptor classDescriptor = fakeCallableDescriptorForObject.getClassDescriptor(); - context.trace.record(REFERENCE_TARGET, nameExpression, classDescriptor); - checkClassObjectVisibility(classDescriptor, nameExpression, context); - return getExtendedClassObjectType(nameExpression, fakeCallableDescriptorForObject.getType(), classDescriptor, receiverScope); + + // if the expression is a receiver in a qualified expression, it should be resolved after the selector is resolved + boolean isLHSOfDot = JetPsiUtil.isLHSOfDot(nameExpression); + if (!resolutionResult.isNothing()) { + boolean isQualifier = isLHSOfDot && resolutionResult.isSingleResult() + && resolutionResult.getResultingDescriptor() instanceof FakeCallableDescriptorForObject; + if (!isQualifier) { + result[0] = true; + temporaryForVariable.commit(); + checkSuper(receiver, resolutionResult, context.trace, nameExpression); + return resolutionResult.isSingleResult() ? resolutionResult.getResultingDescriptor().getReturnType() : null; } - temporaryForVariable.commit(); - checkSuper(receiver, resolutionResult, context.trace, nameExpression); - return resolutionResult.getResultingDescriptor().getReturnType(); } - ExpressionTypingContext newContext = context.replaceScope(receiverScope); - TemporaryTraceAndCache temporaryForPackageOrClassObject = TemporaryTraceAndCache.create( - context, "trace to resolve as package or class object", nameExpression); - JetType jetType = lookupPackageOrClassObject(nameExpression, newContext.replaceTraceAndCache(temporaryForPackageOrClassObject)); - if (jetType != null) { - temporaryForPackageOrClassObject.commit(); - - // Uncommitted changes in temp context - context.trace.record(RESOLUTION_SCOPE, nameExpression, context.scope); - if (context.dataFlowInfo.hasTypeInfoConstraints()) { - context.trace.record(NON_DEFAULT_EXPRESSION_DATA_FLOW, nameExpression, context.dataFlowInfo); - } + QualifierReceiver qualifierReceiver = createQualifierReceiver(nameExpression, receiver, context); + if (qualifierReceiver != null) { result[0] = true; - return jetType; + if (!isLHSOfDot) { + resolveAsStandaloneExpression(qualifierReceiver, context); + } + return null; } temporaryForVariable.commit(); result[0] = !resolutionResult.isNothing(); @@ -301,9 +139,6 @@ public class CallExpressionResolver { JetType type = getVariableType(nameExpression, receiver, callOperationNode, context.replaceTraceAndCache(temporaryForVariable), result); if (result[0]) { temporaryForVariable.commit(); - if (type instanceof PackageType && !isLHSOfDot(nameExpression)) { - type = null; - } return JetTypeInfo.create(type, context.dataFlowInfo); } @@ -425,7 +260,7 @@ public class CallExpressionResolver { private JetTypeInfo getSelectorReturnTypeInfo( @NotNull ReceiverValue receiver, @Nullable ASTNode callOperationNode, - @NotNull JetExpression selectorExpression, + @Nullable JetExpression selectorExpression, @NotNull ExpressionTypingContext context ) { if (selectorExpression instanceof JetCallExpression) { @@ -435,7 +270,7 @@ public class CallExpressionResolver { else if (selectorExpression instanceof JetSimpleNameExpression) { return getSimpleNameExpressionTypeInfo((JetSimpleNameExpression) selectorExpression, receiver, callOperationNode, context); } - else { + else if (selectorExpression != null) { context.trace.report(ILLEGAL_SELECTOR.on(selectorExpression, selectorExpression.getText())); } return JetTypeInfo.create(null, context.dataFlowInfo); @@ -451,18 +286,21 @@ public class CallExpressionResolver { ResolutionContext contextForReceiver = context.replaceExpectedType(NO_EXPECTED_TYPE).replaceContextDependency(INDEPENDENT); JetTypeInfo receiverTypeInfo = expressionTypingServices.getTypeInfo(receiverExpression, contextForReceiver); JetType receiverType = receiverTypeInfo.getType(); - if (selectorExpression == null) return JetTypeInfo.create(null, context.dataFlowInfo); + QualifierReceiver qualifierReceiver = context.trace.get(BindingContext.QUALIFIER_RECEIVER, receiverExpression); + if (receiverType == null) receiverType = ErrorUtils.createErrorType("Type for " + expression.getText()); context = context.replaceDataFlowInfo(receiverTypeInfo.getDataFlowInfo()); + ReceiverValue receiver = qualifierReceiver == null ? new ExpressionReceiver(receiverExpression, receiverType) : qualifierReceiver; JetTypeInfo selectorReturnTypeInfo = getSelectorReturnTypeInfo( - new ExpressionReceiver(receiverExpression, receiverType), - expression.getOperationTokenNode(), selectorExpression, context); + receiver, expression.getOperationTokenNode(), selectorExpression, context); JetType selectorReturnType = selectorReturnTypeInfo.getType(); + resolveDeferredReceiverInQualifiedExpression(qualifierReceiver, expression, context); + //TODO move further - if (!(receiverType instanceof PackageType) && expression.getOperationSign() == JetTokens.SAFE_ACCESS) { + if (expression.getOperationSign() == JetTokens.SAFE_ACCESS) { if (selectorReturnType != null && !KotlinBuiltIns.getInstance().isUnit(selectorReturnType)) { if (receiverType.isNullable()) { selectorReturnType = TypeUtils.makeNullable(selectorReturnType); @@ -486,4 +324,18 @@ public class CallExpressionResolver { } return typeInfo; } + + private static void resolveDeferredReceiverInQualifiedExpression( + @Nullable QualifierReceiver qualifierReceiver, + @NotNull JetQualifiedExpression qualifiedExpression, + @NotNull ExpressionTypingContext context + ) { + if (qualifierReceiver == null) return; + JetExpression calleeExpression = + JetPsiUtil.deparenthesize(CallUtilPackage.getCalleeExpressionIfAny(qualifiedExpression.getSelectorExpression()), false); + DeclarationDescriptor selectorDescriptor = + calleeExpression instanceof JetReferenceExpression + ? context.trace.get(BindingContext.REFERENCE_TARGET, (JetReferenceExpression) calleeExpression) : null; + ReceiversPackage.resolveAsReceiverInQualifiedExpression(qualifierReceiver, context, selectorDescriptor); + } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/autocasts/DataFlowValueFactory.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/autocasts/DataFlowValueFactory.java index 03acfb883e0..b34f7ca9833 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/autocasts/DataFlowValueFactory.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/autocasts/DataFlowValueFactory.java @@ -154,7 +154,7 @@ public class DataFlowValueFactory { return getIdForThisReceiver(declarationDescriptor); } else if (expression instanceof JetRootPackageExpression) { - return createPackageInfo(JetModuleUtil.getRootPackageType(expression)); + //todo return createPackageInfo()); } return NO_IDENTIFIER_INFO; } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/tasks/TaskPrioritizer.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/tasks/TaskPrioritizer.java index 1a26fe4c306..520b28bb8fa 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/tasks/TaskPrioritizer.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/tasks/TaskPrioritizer.java @@ -19,7 +19,6 @@ package org.jetbrains.jet.lang.resolve.calls.tasks; import com.google.common.collect.Lists; import com.google.common.collect.Sets; import com.intellij.openapi.progress.ProgressIndicatorProvider; -import com.intellij.openapi.util.Pair; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.*; @@ -32,14 +31,13 @@ import org.jetbrains.jet.lang.resolve.name.Name; import org.jetbrains.jet.lang.resolve.scopes.JetScope; import org.jetbrains.jet.lang.resolve.scopes.JetScopeUtils; import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver; +import org.jetbrains.jet.lang.resolve.scopes.receivers.QualifierReceiver; import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue; import org.jetbrains.jet.lang.types.ErrorUtils; import org.jetbrains.jet.lang.types.JetType; -import org.jetbrains.jet.lang.types.PackageType; import org.jetbrains.jet.lang.types.checker.JetTypeChecker; import org.jetbrains.jet.lang.types.expressions.ExpressionTypingUtils; -import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -84,25 +82,22 @@ public class TaskPrioritizer { @NotNull TracingStrategy tracing, @NotNull CallableDescriptorCollectors callableDescriptorCollectors ) { - List> variants = new ArrayList>(2); - ReceiverValue explicitReceiver = context.call.getExplicitReceiver(); - if (explicitReceiver.exists() && explicitReceiver.getType() instanceof PackageType) { - JetType receiverType = explicitReceiver.getType(); - variants.add(Pair.create(receiverType.getMemberScope(), NO_RECEIVER)); - ReceiverValue value = ((PackageType) receiverType).getReceiverValue(); - if (value.exists()) { - variants.add(Pair.create(context.scope, value)); + ResolutionTaskHolder result = + new ResolutionTaskHolder(context, new MyPriorityProvider(context), tracing); + TaskPrioritizerContext taskPrioritizerContext = + new TaskPrioritizerContext(name, result, context, context.scope, callableDescriptorCollectors); + + if (explicitReceiver instanceof QualifierReceiver) { + QualifierReceiver qualifierReceiver = (QualifierReceiver) explicitReceiver; + doComputeTasks(NO_RECEIVER, taskPrioritizerContext.replaceScope(qualifierReceiver.getNestedClassesAndPackageMembersScope())); + ReceiverValue classObjectReceiver = qualifierReceiver.getClassObjectReceiver(); + if (classObjectReceiver.exists()) { + doComputeTasks(classObjectReceiver, taskPrioritizerContext); } } else { - variants.add(Pair.create(context.scope, explicitReceiver)); - } - - ResolutionTaskHolder result = - new ResolutionTaskHolder(context, new MyPriorityProvider(context), tracing); - for (Pair pair : variants) { - doComputeTasks(pair.second, new TaskPrioritizerContext(name, result, context, pair.first, callableDescriptorCollectors)); + doComputeTasks(explicitReceiver, taskPrioritizerContext); } return result.getTasks(); @@ -401,5 +396,9 @@ public class TaskPrioritizer { this.scope = scope; this.callableDescriptorCollectors = callableDescriptorCollectors; } + + private TaskPrioritizerContext replaceScope(JetScope newScope) { + return new TaskPrioritizerContext(name, result, context, newScope, callableDescriptorCollectors); + } } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/util/callUtil.kt b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/util/callUtil.kt index edbcccf7efa..8af22f09083 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/util/callUtil.kt +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/util/callUtil.kt @@ -114,12 +114,12 @@ public fun Call.getValueArgumentForExpression(expression: JetExpression): ValueA // Get call / resolved call from binding context -public fun JetElement.getCalleeExpressionIfAny(): JetExpression? { +public fun JetElement?.getCalleeExpressionIfAny(): JetExpression? { val element = if (this is JetExpression) JetPsiUtil.safeDeparenthesize(this, false) else this return when (element) { is JetSimpleNameExpression -> element is JetCallElement -> element.getCalleeExpression() - is JetQualifiedExpression -> element.getSelectorExpression()?.getCalleeExpressionIfAny() + is JetQualifiedExpression -> element.getSelectorExpression().getCalleeExpressionIfAny() is JetOperationExpression -> element.getOperationReference() else -> null } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/receivers/QualifierReceiver.kt b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/receivers/QualifierReceiver.kt new file mode 100644 index 00000000000..91b12eb5264 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/receivers/QualifierReceiver.kt @@ -0,0 +1,163 @@ +/* + * Copyright 2010-2014 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.jet.lang.resolve.scopes.receivers + +import org.jetbrains.jet.lang.types.JetType +import org.jetbrains.jet.lang.descriptors.PackageViewDescriptor +import org.jetbrains.jet.lang.resolve.scopes.JetScope +import org.jetbrains.jet.lang.descriptors.ClassifierDescriptor +import org.jetbrains.jet.lang.psi.JetSimpleNameExpression +import org.jetbrains.jet.lang.descriptors.ClassDescriptor +import org.jetbrains.jet.lang.descriptors.ClassKind +import org.jetbrains.jet.lang.resolve.DescriptorUtils +import org.jetbrains.jet.lang.resolve.DescriptorUtils.getFqName +import org.jetbrains.jet.lang.resolve.name.Name +import org.jetbrains.jet.lang.resolve.scopes.ChainedScope +import java.util.ArrayList +import org.jetbrains.jet.utils.addIfNotNull +import org.jetbrains.jet.lang.resolve.BindingContext.* +import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor +import org.jetbrains.jet.lang.diagnostics.Errors.* +import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor +import org.jetbrains.jet.lang.descriptors.ConstructorDescriptor +import org.jetbrains.jet.lang.descriptors.impl.PackageFragmentDescriptorImpl +import org.jetbrains.jet.lang.types.expressions.ExpressionTypingContext +import org.jetbrains.jet.lang.psi.psiUtil.getTopmostParentQualifiedExpressionForSelector + +public class QualifierReceiver( + val expression: JetSimpleNameExpression, + val packageView: PackageViewDescriptor?, + val classifier: ClassifierDescriptor? +) : ReceiverValue { + + val name: Name + get() = classifier?.getName() ?: packageView!!.getName() + + fun getClassObjectReceiver(): ReceiverValue = + classifier?.getClassObjectType()?.let { ExpressionReceiver(expression, it) } ?: ReceiverValue.NO_RECEIVER + + val descriptor: DeclarationDescriptor + get() = classifier ?: packageView ?: throw AssertionError("PackageView and classifier both are null") + + fun getScope(): JetScope { + val scopes = listOf(classifier?.getClassObjectType()?.getMemberScope(), getNestedClassesAndPackageMembersScope()).filterNotNull().copyToArray() + return ChainedScope(descriptor, "Member scope for " + name + " as package or class or object", *scopes as Array) + } + + fun getNestedClassesAndPackageMembersScope(): JetScope { + val scopes = ArrayList(3) + + scopes.addIfNotNull(classifier?.getClassObjectType()?.getMemberScope()) + + scopes.addIfNotNull(packageView?.getMemberScope()) + + if (classifier is ClassDescriptor && classifier.getKind() != ClassKind.ENUM_ENTRY) { + scopes.add(DescriptorUtils.getStaticNestedClassesScope(classifier)) + } + + return ChainedScope(descriptor, "Static scope for " + name + " as package or class or object", *scopes.copyToArray()) + } + + override fun getType(): JetType = throw IllegalStateException("No type corresponds to QualifierReceiver '$this'") + + override fun exists() = true + + override fun toString() = "Package{$packageView} OR Class{$classifier}" +} + +fun createQualifierReceiver( + expression: JetSimpleNameExpression, + receiver: ReceiverValue, + context: ExpressionTypingContext +): QualifierReceiver? { + val receiverScope = when { + !receiver.exists() -> context.scope + receiver is QualifierReceiver -> receiver.getScope() + else -> receiver.getType().getMemberScope() + } + + val name = expression.getReferencedNameAsName() + val packageViewDescriptor = receiverScope.getPackage(name) + val classifierDescriptor = receiverScope.getClassifier(name) + + if (packageViewDescriptor == null && classifierDescriptor == null) return null + + context.trace.record(RESOLUTION_SCOPE, expression, context.scope) + if (context.dataFlowInfo.hasTypeInfoConstraints()) { + context.trace.record(NON_DEFAULT_EXPRESSION_DATA_FLOW, expression, context.dataFlowInfo) + } + + val qualifierReceiver = QualifierReceiver(expression, packageViewDescriptor, classifierDescriptor) + context.trace.record(QUALIFIER_RECEIVER, expression.getTopmostParentQualifiedExpressionForSelector() ?: expression, qualifierReceiver) + return qualifierReceiver +} + +private fun QualifierReceiver.resolveAsStandaloneExpression(context: ExpressionTypingContext): JetType? { + context.trace.record(REFERENCE_TARGET, expression, resolveReferenceTarget(selector = null)) + if (classifier is TypeParameterDescriptor) { + context.trace.report(TYPE_PARAMETER_IS_NOT_AN_EXPRESSION.on(expression, classifier)) + } + else if (classifier is ClassDescriptor && classifier.getClassObjectType() == null) { + context.trace.report(NO_CLASS_OBJECT.on(expression, classifier)) + } + else if (packageView != null) { + context.trace.report(EXPRESSION_EXPECTED_PACKAGE_FOUND.on(expression)) + } + return null +} + +private fun QualifierReceiver.resolveAsReceiverInQualifiedExpression(context: ExpressionTypingContext, selector: DeclarationDescriptor?) { + context.trace.record(REFERENCE_TARGET, expression, resolveReferenceTarget(selector)) + if (classifier is TypeParameterDescriptor) { + context.trace.report(TYPE_PARAMETER_ON_LHS_OF_DOT.on(expression, classifier as TypeParameterDescriptor)) + } + else if (classifier is ClassDescriptor && classifier.getClassObjectDescriptor() != null) { + checkClassObjectVisibility(context) + context.trace.record(EXPRESSION_TYPE, expression, classifier.getClassObjectType()) + } +} + +private fun QualifierReceiver.resolveReferenceTarget(selector: DeclarationDescriptor?): DeclarationDescriptor { + if (classifier is TypeParameterDescriptor) { + return classifier + } + + val containingDeclaration = when { + selector is ConstructorDescriptor -> selector.getContainingDeclaration().getContainingDeclaration() + else -> selector?.getContainingDeclaration() + } + + if (packageView != null && (containingDeclaration is PackageFragmentDescriptorImpl || containingDeclaration is PackageViewDescriptor) + && getFqName(packageView) == getFqName(containingDeclaration)) { + return packageView + } + + return descriptor +} + +private fun QualifierReceiver.checkClassObjectVisibility(context: ExpressionTypingContext) { + if (classifier !is ClassDescriptor) return + + val scopeContainer = context.scope.getContainingDeclaration() + val classObject = classifier.getClassObjectDescriptor() + assert(classObject != null) { "This check should be done only for classes with class objects: " + classifier } + if (!Visibilities.isVisible(classObject!!, scopeContainer)) { + context.trace.report(INVISIBLE_MEMBER.on(expression, classObject, classObject.getVisibility(), scopeContainer)) + } +} + + diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java index 740970b533f..9c1b1f97b36 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java @@ -1221,10 +1221,9 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { @Override public JetTypeInfo visitRootPackageExpression(@NotNull JetRootPackageExpression expression, ExpressionTypingContext context) { - if (JetPsiUtil.isLHSOfDot(expression)) { - return DataFlowUtils.checkType(JetModuleUtil.getRootPackageType(expression), expression, context, context.dataFlowInfo); + if (!JetPsiUtil.isLHSOfDot(expression)) { + context.trace.report(PACKAGE_IS_NOT_AN_EXPRESSION.on(expression)); } - context.trace.report(PACKAGE_IS_NOT_AN_EXPRESSION.on(expression)); return JetTypeInfo.create(null, context.dataFlowInfo); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingUtils.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingUtils.java index 39b0a78413a..e1df0aefd4c 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingUtils.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingUtils.java @@ -231,11 +231,6 @@ public class ExpressionTypingUtils { ) { JetType type = receiverArgument.getType(); - if (type instanceof PackageType) { - // This fake class ruins standard algorithms - return false; - } - if (checkReceiverResolution(receiverArgument, type, callableDescriptor)) return true; if (type.isNullable()) { JetType notNullableType = TypeUtils.makeNotNullable(type); diff --git a/compiler/testData/codegen/box/classes/classObjectAsExtensionReceiver.kt b/compiler/testData/codegen/box/classes/classObjectAsExtensionReceiver.kt new file mode 100644 index 00000000000..153e9e4a640 --- /dev/null +++ b/compiler/testData/codegen/box/classes/classObjectAsExtensionReceiver.kt @@ -0,0 +1,7 @@ +fun Any.foo() = 1 + +class A { + class object +} + +fun box() = if (A.foo() == 1) "OK" else "fail" diff --git a/compiler/testData/diagnostics/tests/PackageInExpressionPosition.kt b/compiler/testData/diagnostics/tests/PackageInExpressionPosition.kt index 6288201f899..f9160f181a8 100644 --- a/compiler/testData/diagnostics/tests/PackageInExpressionPosition.kt +++ b/compiler/testData/diagnostics/tests/PackageInExpressionPosition.kt @@ -13,7 +13,7 @@ val xssss = foo val f = { System } fun main(args : Array) { - java = null + java = null System = null System!! java.lang.System = null diff --git a/compiler/testData/diagnostics/tests/incompleteCode/diagnosticWithSyntaxError/incompleteEnumReference.kt b/compiler/testData/diagnostics/tests/incompleteCode/diagnosticWithSyntaxError/incompleteEnumReference.kt new file mode 100644 index 00000000000..d95209adbd0 --- /dev/null +++ b/compiler/testData/diagnostics/tests/incompleteCode/diagnosticWithSyntaxError/incompleteEnumReference.kt @@ -0,0 +1,11 @@ +enum class E { + A + B + C +} + +fun foo() { + val e = E. +} + + diff --git a/compiler/testData/diagnostics/tests/resolve/ambiguityOnPropertiesWithTheSamePackageName.kt b/compiler/testData/diagnostics/tests/resolve/ambiguityOnPropertiesWithTheSamePackageName.kt new file mode 100644 index 00000000000..c8ca6a8de53 --- /dev/null +++ b/compiler/testData/diagnostics/tests/resolve/ambiguityOnPropertiesWithTheSamePackageName.kt @@ -0,0 +1,30 @@ +// FILE: a.kt +package a + +class A + +// FILE: b.kt +package b + +import a.A + +val A.d: Int get() = 1 + +// FILE: c.kt +package c + +import a.A + +val A.d: Int get() = 2 + +// FILE: d.kt + +package d + +import a.A +import b.d +import c.d + +fun A.test() { + d +} diff --git a/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/callableRefrenceOnNestedObject.kt b/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/callableRefrenceOnNestedObject.kt new file mode 100644 index 00000000000..6e62db4637a --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/callableReference/function/callableRefrenceOnNestedObject.kt @@ -0,0 +1,9 @@ +open class A { + fun foo() = 42 + + object B: A() +} + +fun test() { + A.B.(A::foo)() +} \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java index ff37f0c52db..12f8e82fc01 100644 --- a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java @@ -3882,6 +3882,11 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest { doTest("compiler/testData/diagnostics/tests/incompleteCode/diagnosticWithSyntaxError/funcitonTypes.kt"); } + @TestMetadata("incompleteEnumReference.kt") + public void testIncompleteEnumReference() throws Exception { + doTest("compiler/testData/diagnostics/tests/incompleteCode/diagnosticWithSyntaxError/incompleteEnumReference.kt"); + } + @TestMetadata("incompleteVal.kt") public void testIncompleteVal() throws Exception { doTest("compiler/testData/diagnostics/tests/incompleteCode/diagnosticWithSyntaxError/incompleteVal.kt"); @@ -6973,6 +6978,11 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest { JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/tests/resolve"), Pattern.compile("^(.+)\\.kt$"), true); } + @TestMetadata("ambiguityOnPropertiesWithTheSamePackageName.kt") + public void testAmbiguityOnPropertiesWithTheSamePackageName() throws Exception { + doTest("compiler/testData/diagnostics/tests/resolve/ambiguityOnPropertiesWithTheSamePackageName.kt"); + } + @TestMetadata("incompleteConstructorInvocation.kt") public void testIncompleteConstructorInvocation() throws Exception { doTest("compiler/testData/diagnostics/tests/resolve/incompleteConstructorInvocation.kt"); diff --git a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestWithStdLibGenerated.java b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestWithStdLibGenerated.java index 3df804b1f02..205a0a7c1f3 100644 --- a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestWithStdLibGenerated.java +++ b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestWithStdLibGenerated.java @@ -129,6 +129,11 @@ public class JetDiagnosticsTestWithStdLibGenerated extends AbstractJetDiagnostic doTest("compiler/testData/diagnostics/testsWithStdLib/callableReference/function/ambiguityTopLevelVsTopLevel.kt"); } + @TestMetadata("callableRefrenceOnNestedObject.kt") + public void testCallableRefrenceOnNestedObject() throws Exception { + doTest("compiler/testData/diagnostics/testsWithStdLib/callableReference/function/callableRefrenceOnNestedObject.kt"); + } + @TestMetadata("constructorFromClass.kt") public void testConstructorFromClass() throws Exception { doTest("compiler/testData/diagnostics/testsWithStdLib/callableReference/function/constructorFromClass.kt"); diff --git a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java index c9b44291f98..dab8433f233 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java @@ -685,6 +685,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { doTest("compiler/testData/codegen/box/classes/classObject.kt"); } + @TestMetadata("classObjectAsExtensionReceiver.kt") + public void testClassObjectAsExtensionReceiver() throws Exception { + doTest("compiler/testData/codegen/box/classes/classObjectAsExtensionReceiver.kt"); + } + @TestMetadata("classObjectAsStaticInitializer.kt") public void testClassObjectAsStaticInitializer() throws Exception { doTest("compiler/testData/codegen/box/classes/classObjectAsStaticInitializer.kt"); diff --git a/core/descriptors/src/org/jetbrains/jet/lang/types/ErrorUtils.java b/core/descriptors/src/org/jetbrains/jet/lang/types/ErrorUtils.java index b0f426294ff..f70b09625b2 100644 --- a/core/descriptors/src/org/jetbrains/jet/lang/types/ErrorUtils.java +++ b/core/descriptors/src/org/jetbrains/jet/lang/types/ErrorUtils.java @@ -351,7 +351,6 @@ public class ErrorUtils { public static boolean containsErrorType(@Nullable JetType type) { if (type == null) return false; - if (type instanceof PackageType) return false; if (type.isError()) return true; for (TypeProjection projection : type.getArguments()) { if (containsErrorType(projection.getType())) return true; diff --git a/core/descriptors/src/org/jetbrains/jet/lang/types/PackageType.java b/core/descriptors/src/org/jetbrains/jet/lang/types/PackageType.java deleted file mode 100644 index 0962c0d2804..00000000000 --- a/core/descriptors/src/org/jetbrains/jet/lang/types/PackageType.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright 2010-2013 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.jet.lang.types; - -import org.jetbrains.annotations.NotNull; -import org.jetbrains.jet.lang.descriptors.annotations.Annotations; -import org.jetbrains.jet.lang.resolve.name.Name; -import org.jetbrains.jet.lang.resolve.scopes.JetScope; -import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue; - -import java.util.List; - -/** - * This is a fake type assigned to package expressions. Only member lookup is - * supposed to be done on these types. - */ -public class PackageType implements JetType { - private final Name name; - private final JetScope memberScope; - private final ReceiverValue receiver; - - public PackageType(@NotNull Name name, @NotNull JetScope memberScope, @NotNull ReceiverValue receiver) { - this.name = name; - this.memberScope = memberScope; - this.receiver = receiver; - } - - @NotNull - @Override - public JetScope getMemberScope() { - return memberScope; - } - - @Override - public boolean isError() { - return false; - } - - @NotNull - public ReceiverValue getReceiverValue() { - return receiver; - } - - @NotNull - @Override - public TypeConstructor getConstructor() { - return throwException(); - } - - private TypeConstructor throwException() { - throw new UnsupportedOperationException("Only member lookup is allowed on a package type " + name); - } - - @NotNull - @Override - public List getArguments() { - throwException(); - return null; - } - - @Override - public boolean isNullable() { - throwException(); - return false; - } - - @NotNull - @Override - public Annotations getAnnotations() { - throwException(); - return null; - } - - @Override - public String toString() { - return "[Package-type " + name + "]"; - } -} diff --git a/core/descriptors/src/org/jetbrains/jet/lang/types/TypeUtils.java b/core/descriptors/src/org/jetbrains/jet/lang/types/TypeUtils.java index d4d0f404405..28bb00a17f2 100644 --- a/core/descriptors/src/org/jetbrains/jet/lang/types/TypeUtils.java +++ b/core/descriptors/src/org/jetbrains/jet/lang/types/TypeUtils.java @@ -519,7 +519,6 @@ public class TypeUtils { ) { if (type == null) return false; if (isSpecialType.invoke(type)) return true; - if (type instanceof PackageType) return false; for (TypeProjection projection : type.getArguments()) { if (containsSpecialType(projection.getType(), isSpecialType)) return true; } diff --git a/core/descriptors/src/org/jetbrains/jet/lang/types/lang/KotlinBuiltIns.java b/core/descriptors/src/org/jetbrains/jet/lang/types/lang/KotlinBuiltIns.java index f2df1fbd048..6297b116a6a 100644 --- a/core/descriptors/src/org/jetbrains/jet/lang/types/lang/KotlinBuiltIns.java +++ b/core/descriptors/src/org/jetbrains/jet/lang/types/lang/KotlinBuiltIns.java @@ -724,7 +724,6 @@ public class KotlinBuiltIns { } public boolean isFunctionType(@NotNull JetType type) { - if (type instanceof PackageType) return false; if (isExactFunctionType(type)) return true; for (JetType superType : type.getConstructor().getSupertypes()) { @@ -735,7 +734,6 @@ public class KotlinBuiltIns { } public boolean isExtensionFunctionType(@NotNull JetType type) { - if (type instanceof PackageType) return false; if (isExactExtensionFunctionType(type)) return true; for (JetType superType : type.getConstructor().getSupertypes()) { @@ -833,21 +831,19 @@ public class KotlinBuiltIns { } public boolean isNothingOrNullableNothing(@NotNull JetType type) { - return !(type instanceof PackageType) - && type.getConstructor() == getNothing().getTypeConstructor(); + return type.getConstructor() == getNothing().getTypeConstructor(); } public boolean isAnyOrNullableAny(@NotNull JetType type) { - return !(type instanceof PackageType) && - type.getConstructor() == getAny().getTypeConstructor(); + return type.getConstructor() == getAny().getTypeConstructor(); } public boolean isUnit(@NotNull JetType type) { - return !(type instanceof PackageType) && type.equals(getUnitType()); + return type.equals(getUnitType()); } public boolean isString(@Nullable JetType type) { - return !(type instanceof PackageType) && getStringType().equals(type); + return getStringType().equals(type); } public boolean isCloneable(@NotNull ClassDescriptor descriptor) { diff --git a/core/descriptors/src/org/jetbrains/jet/renderer/DescriptorRendererImpl.java b/core/descriptors/src/org/jetbrains/jet/renderer/DescriptorRendererImpl.java index 494e0c2692b..30e3d1d6d16 100644 --- a/core/descriptors/src/org/jetbrains/jet/renderer/DescriptorRendererImpl.java +++ b/core/descriptors/src/org/jetbrains/jet/renderer/DescriptorRendererImpl.java @@ -279,9 +279,6 @@ public class DescriptorRendererImpl implements DescriptorRenderer { } return "???"; } - if (type instanceof PackageType) { - return type.toString(); - } if (type instanceof LazyType && debugMode) { return type.toString(); } diff --git a/idea/src/org/jetbrains/jet/plugin/codeInsight/TipsManager.java b/idea/src/org/jetbrains/jet/plugin/codeInsight/TipsManager.java index 2a78d3e0691..ed42c6f94e3 100644 --- a/idea/src/org/jetbrains/jet/plugin/codeInsight/TipsManager.java +++ b/idea/src/org/jetbrains/jet/plugin/codeInsight/TipsManager.java @@ -35,9 +35,9 @@ import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo; import org.jetbrains.jet.lang.resolve.scopes.JetScope; import org.jetbrains.jet.lang.resolve.scopes.JetScopeUtils; import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver; +import org.jetbrains.jet.lang.resolve.scopes.receivers.QualifierReceiver; import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue; import org.jetbrains.jet.lang.types.JetType; -import org.jetbrains.jet.lang.types.PackageType; import org.jetbrains.jet.lang.types.expressions.ExpressionTypingUtils; import java.util.*; @@ -58,32 +58,32 @@ public final class TipsManager { if (receiverExpression != null && inPositionForCompletionWithReceiver) { // Process as call expression JetScope resolutionScope = context.get(BindingContext.RESOLUTION_SCOPE, expression); + QualifierReceiver qualifierReceiver = context.get(BindingContext.QUALIFIER_RECEIVER, receiverExpression); + if (qualifierReceiver != null && resolutionScope != null) { + return includeExternalCallableExtensions( + excludePrivateDescriptors(qualifierReceiver.getScope().getAllDescriptors()), + resolutionScope, qualifierReceiver); + } + JetType expressionType = context.get(BindingContext.EXPRESSION_TYPE, receiverExpression); - if (expressionType != null && resolutionScope != null && !expressionType.isError()) { - if (!(expressionType instanceof PackageType)) { - ExpressionReceiver receiverValue = new ExpressionReceiver(receiverExpression, expressionType); - Set descriptors = new HashSet(); + ExpressionReceiver receiverValue = new ExpressionReceiver(receiverExpression, expressionType); + Set descriptors = new HashSet(); - DataFlowInfo info = context.get(BindingContext.NON_DEFAULT_EXPRESSION_DATA_FLOW, expression); - if (info == null) { - info = DataFlowInfo.EMPTY; - } - - List variantsForExplicitReceiver = AutoCastUtils.getAutoCastVariants(receiverValue, context, info); - - for (JetType variant : variantsForExplicitReceiver) { - descriptors.addAll(includeExternalCallableExtensions( - excludePrivateDescriptors(variant.getMemberScope().getAllDescriptors()), - resolutionScope, receiverValue)); - } - - return descriptors; + DataFlowInfo info = context.get(BindingContext.NON_DEFAULT_EXPRESSION_DATA_FLOW, expression); + if (info == null) { + info = DataFlowInfo.EMPTY; } - return includeExternalCallableExtensions( - excludePrivateDescriptors(expressionType.getMemberScope().getAllDescriptors()), - resolutionScope, new ExpressionReceiver(receiverExpression, expressionType)); + List variantsForExplicitReceiver = AutoCastUtils.getAutoCastVariants(receiverValue, context, info); + + for (JetType variant : variantsForExplicitReceiver) { + descriptors.addAll(includeExternalCallableExtensions( + excludePrivateDescriptors(variant.getMemberScope().getAllDescriptors()), + resolutionScope, receiverValue)); + } + + return descriptors; } return Collections.emptyList(); } @@ -197,11 +197,9 @@ public final class TipsManager { @NotNull final ReceiverValue receiverValue ) { // It's impossible to add extension function for package - JetType receiverType = receiverValue.getType(); - if (receiverType instanceof PackageType) { + if (receiverValue instanceof QualifierReceiver) { return new HashSet(descriptors); } - Set descriptorsSet = Sets.newHashSet(descriptors); descriptorsSet.addAll( diff --git a/idea/src/org/jetbrains/jet/plugin/intentions/ReplaceWithInfixFunctionCallIntention.kt b/idea/src/org/jetbrains/jet/plugin/intentions/ReplaceWithInfixFunctionCallIntention.kt index 8a1c29aa5bd..04f05943721 100644 --- a/idea/src/org/jetbrains/jet/plugin/intentions/ReplaceWithInfixFunctionCallIntention.kt +++ b/idea/src/org/jetbrains/jet/plugin/intentions/ReplaceWithInfixFunctionCallIntention.kt @@ -24,7 +24,6 @@ import org.jetbrains.jet.lang.resolve.BindingContext import org.jetbrains.jet.plugin.JetBundle import org.jetbrains.jet.lang.psi.JetValueArgument import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache -import org.jetbrains.jet.lang.types.PackageType import org.jetbrains.jet.lang.psi.JetPsiUnparsingUtils import org.jetbrains.jet.lang.psi.JetPsiFactory import com.intellij.codeInsight.hint.HintManager @@ -91,15 +90,13 @@ public open class ReplaceWithInfixFunctionCallIntention : JetSelfTargetingIntent val functionLiteralArguments = element.getFunctionLiteralArguments() val bindingContext = AnalyzerFacadeWithCache.getContextForElement(parent) val receiverType = bindingContext[BindingContext.EXPRESSION_TYPE, receiver] - when { - receiverType == null -> { - intentionFailed(editor, "resolution.failed") - return - } - receiverType is PackageType -> { + if (receiverType == null) { + if (bindingContext[BindingContext.QUALIFIER_RECEIVER, receiver] != null) { intentionFailed(editor, "package.call") return } + intentionFailed(editor, "resolution.failed") + return } rightHandTextStringBuilder.append( diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/JetRefactoringUtil.java b/idea/src/org/jetbrains/jet/plugin/refactoring/JetRefactoringUtil.java index 0345cdbc5b3..a7fccf5dcec 100644 --- a/idea/src/org/jetbrains/jet/plugin/refactoring/JetRefactoringUtil.java +++ b/idea/src/org/jetbrains/jet/plugin/refactoring/JetRefactoringUtil.java @@ -48,8 +48,6 @@ import org.jetbrains.jet.lang.resolve.DescriptorToSourceUtils; import org.jetbrains.jet.lang.resolve.OverrideResolver; import org.jetbrains.jet.lang.resolve.java.jetAsJava.KotlinLightMethod; import org.jetbrains.jet.lang.types.JetType; -import org.jetbrains.jet.lang.types.PackageType; -import org.jetbrains.jet.lang.types.checker.JetTypeChecker; import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; import org.jetbrains.jet.lexer.JetKeywordToken; import org.jetbrains.jet.lexer.JetTokens; @@ -432,9 +430,7 @@ public class JetRefactoringUtil { JetExpression expression = (JetExpression)element; BindingContext bindingContext = AnalyzerFacadeWithCache.getContextForElement(expression); JetType expressionType = bindingContext.get(BindingContext.EXPRESSION_TYPE, expression); - if (expressionType == null || !(expressionType instanceof PackageType) && - !JetTypeChecker.DEFAULT.equalTypes(KotlinBuiltIns. - getInstance().getUnitType(), expressionType)) { + if (expressionType == null || !KotlinBuiltIns.getInstance().isUnit(expressionType)) { expressions.add(expression); } } diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/introduce/introduceVariable/KotlinIntroduceVariableHandler.java b/idea/src/org/jetbrains/jet/plugin/refactoring/introduce/introduceVariable/KotlinIntroduceVariableHandler.java index 3f04d3317b3..2b4a0dcdf0c 100644 --- a/idea/src/org/jetbrains/jet/plugin/refactoring/introduce/introduceVariable/KotlinIntroduceVariableHandler.java +++ b/idea/src/org/jetbrains/jet/plugin/refactoring/introduce/introduceVariable/KotlinIntroduceVariableHandler.java @@ -44,7 +44,6 @@ import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo; import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall; import org.jetbrains.jet.lang.resolve.scopes.JetScope; import org.jetbrains.jet.lang.types.JetType; -import org.jetbrains.jet.lang.types.PackageType; import org.jetbrains.jet.lang.types.TypeUtils; import org.jetbrains.jet.lang.types.checker.JetTypeChecker; import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; @@ -139,7 +138,8 @@ public class KotlinIntroduceVariableHandler extends KotlinIntroduceHandlerBase { noTypeInference = true; } } - if (expressionType instanceof PackageType) { + + if (expressionType == null && bindingContext.get(BindingContext.QUALIFIER_RECEIVER, expression) != null) { showErrorHint(project, editor, JetRefactoringBundle.message("cannot.refactor.package.expression")); return; } diff --git a/idea/testData/completion/handlers/ClassFromClassObjectInPackage.kt b/idea/testData/completion/handlers/ClassFromClassObjectInPackage.kt new file mode 100644 index 00000000000..221cd69f48e --- /dev/null +++ b/idea/testData/completion/handlers/ClassFromClassObjectInPackage.kt @@ -0,0 +1,11 @@ +package a + +class Test { + class object { + class Some + } +} + +fun test() { + a.Test.S +} \ No newline at end of file diff --git a/idea/testData/completion/handlers/ClassFromClassObjectInPackage.kt.after b/idea/testData/completion/handlers/ClassFromClassObjectInPackage.kt.after new file mode 100644 index 00000000000..5ed84907089 --- /dev/null +++ b/idea/testData/completion/handlers/ClassFromClassObjectInPackage.kt.after @@ -0,0 +1,11 @@ +package a + +class Test { + class object { + class Some + } +} + +fun test() { + a.Test.Some +} \ No newline at end of file diff --git a/idea/testData/parameterInfo/functionParameterInfo/ExtensionOnClassObject.kt b/idea/testData/parameterInfo/functionParameterInfo/ExtensionOnClassObject.kt new file mode 100644 index 00000000000..b0518380e04 --- /dev/null +++ b/idea/testData/parameterInfo/functionParameterInfo/ExtensionOnClassObject.kt @@ -0,0 +1,15 @@ +trait A + +fun A.foo(i: Int) = i + +class B { + class object : A +} + +fun test() { + B.foo() +} + +/* +Text: (i: Int), Disabled: false, Strikeout: false, Green: true +*/ \ No newline at end of file diff --git a/idea/tests/org/jetbrains/jet/completion/handlers/BasicCompletionHandlerTest.kt b/idea/tests/org/jetbrains/jet/completion/handlers/BasicCompletionHandlerTest.kt index 4d3894f6bb9..dd4f9447bcd 100644 --- a/idea/tests/org/jetbrains/jet/completion/handlers/BasicCompletionHandlerTest.kt +++ b/idea/tests/org/jetbrains/jet/completion/handlers/BasicCompletionHandlerTest.kt @@ -137,6 +137,7 @@ public class BasicCompletionHandlerTest : CompletionHandlerTestBase(){ fun testEnumMember() = doTest(1, "A", null, '\n') fun testEnumMember1() = doTest(1, "A", null, '\n') fun testClassFromClassObject() = doTest(1, "Some", null, '\n') + fun testClassFromClassObjectInPackage() = doTest(1, "Some", null, '\n') fun testParameterType() = doTest(1, "StringBuilder", " (java.lang)", '\n') diff --git a/idea/tests/org/jetbrains/jet/plugin/parameterInfo/FunctionParameterInfoTestGenerated.java b/idea/tests/org/jetbrains/jet/plugin/parameterInfo/FunctionParameterInfoTestGenerated.java index 458a06ebff6..5f8e8113953 100644 --- a/idea/tests/org/jetbrains/jet/plugin/parameterInfo/FunctionParameterInfoTestGenerated.java +++ b/idea/tests/org/jetbrains/jet/plugin/parameterInfo/FunctionParameterInfoTestGenerated.java @@ -38,6 +38,11 @@ public class FunctionParameterInfoTestGenerated extends AbstractFunctionParamete doTest("idea/testData/parameterInfo/functionParameterInfo/Deprecated.kt"); } + @TestMetadata("ExtensionOnClassObject.kt") + public void testExtensionOnClassObject() throws Exception { + doTest("idea/testData/parameterInfo/functionParameterInfo/ExtensionOnClassObject.kt"); + } + @TestMetadata("InheritedFunctions.kt") public void testInheritedFunctions() throws Exception { doTest("idea/testData/parameterInfo/functionParameterInfo/InheritedFunctions.kt");