diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPsiUtil.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPsiUtil.java index 7c9730f6397..8f753b3929a 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPsiUtil.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPsiUtil.java @@ -431,6 +431,13 @@ public class JetPsiUtil { return selectorParent instanceof JetQualifiedExpression && (((JetQualifiedExpression) selectorParent).getSelectorExpression() == selector); } + public static boolean isLHSOfDot(@NotNull JetExpression expression) { + PsiElement parent = expression.getParent(); + if (!(parent instanceof JetQualifiedExpression)) return false; + JetQualifiedExpression qualifiedParent = (JetQualifiedExpression) parent; + return qualifiedParent.getReceiverExpression() == expression || isLHSOfDot(qualifiedParent); + } + public static boolean isVoidType(@Nullable JetTypeReference typeReference) { if (typeReference == null) { return 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 cba60b6f806..bd0cb4c74fc 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 @@ -53,6 +53,7 @@ import static org.jetbrains.jet.lang.diagnostics.Errors.*; import static org.jetbrains.jet.lang.resolve.BindingContext.*; import static org.jetbrains.jet.lang.resolve.DescriptorUtils.getStaticNestedClassesScope; import static org.jetbrains.jet.lang.types.TypeUtils.NO_EXPECTED_TYPE; +import static org.jetbrains.jet.lang.psi.JetPsiUtil.isLHSOfDot; public class CallExpressionResolver { @NotNull @@ -71,7 +72,7 @@ public class CallExpressionResolver { JetType classObjectType = classifier.getClassObjectType(); if (classObjectType != null) { context.trace.record(REFERENCE_TARGET, expression, classifier); - JetType result = getExtendedClassObjectType(classObjectType, referencedName, classifier, context); + JetType result = getExtendedClassObjectType(expression, classObjectType, classifier, context); checkClassObjectVisibility(classifier, expression, context); return DataFlowUtils.checkType(result, expression, context); } @@ -86,14 +87,14 @@ public class CallExpressionResolver { // To report NO_CLASS_OBJECT when no namespace found if (classifier != null) { if (classifier instanceof TypeParameterDescriptor) { - if (context.expressionPosition == ExpressionPosition.FREE) { - context.trace.report(TYPE_PARAMETER_IS_NOT_AN_EXPRESSION.on(expression, (TypeParameterDescriptor) classifier)); - } - else { + 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 (context.expressionPosition == ExpressionPosition.FREE) { + else if (!isLHSOfDot(expression)) { context.trace.report(NO_CLASS_OBJECT.on(expression, classifier)); } context.trace.record(REFERENCE_TARGET, expression, classifier); @@ -134,17 +135,18 @@ public class CallExpressionResolver { @NotNull private static JetType getExtendedClassObjectType( + @NotNull JetSimpleNameExpression expression, @NotNull JetType classObjectType, - @NotNull Name referencedName, @NotNull ClassifierDescriptor classifier, @NotNull ResolutionContext context ) { - if (context.expressionPosition == ExpressionPosition.LHS_OF_DOT && classifier instanceof ClassDescriptor) { + if (isLHSOfDot(expression) && classifier instanceof ClassDescriptor) { List scopes = new ArrayList(3); scopes.add(classObjectType.getMemberScope()); scopes.add(getStaticNestedClassesScope((ClassDescriptor) classifier)); + Name referencedName = expression.getReferencedNameAsName(); NamespaceDescriptor namespace = context.scope.getNamespace(referencedName); if (namespace != null) { //for enums loaded from java binaries @@ -166,7 +168,7 @@ public class CallExpressionResolver { if (namespaceType == null) { return false; } - if (context.expressionPosition == ExpressionPosition.LHS_OF_DOT) { + if (isLHSOfDot(expression)) { result[0] = namespaceType; return true; } @@ -266,7 +268,7 @@ public class CallExpressionResolver { JetType type = getVariableType(nameExpression, receiver, callOperationNode, context.replaceTraceAndCache(temporaryForVariable), result); if (result[0]) { temporaryForVariable.commit(); - if (type instanceof NamespaceType && context.expressionPosition == ExpressionPosition.FREE) { + if (type instanceof NamespaceType && !isLHSOfDot(nameExpression)) { type = null; } return JetTypeInfo.create(type, context.dataFlowInfo); 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 0406a2cf0a0..fd262ce2064 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 @@ -36,7 +36,6 @@ import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowValue; import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowValueFactory; import org.jetbrains.jet.lang.resolve.calls.autocasts.Nullability; import org.jetbrains.jet.lang.resolve.calls.context.CheckValueArgumentsMode; -import org.jetbrains.jet.lang.resolve.calls.context.ExpressionPosition; import org.jetbrains.jet.lang.resolve.calls.context.TemporaryTraceAndCache; import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall; import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCallWithTrace; @@ -281,10 +280,11 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { public JetTypeInfo visitSuperExpression(@NotNull JetSuperExpression expression, ExpressionTypingContext context) { LabelResolver.LabeledReceiverResolutionResult resolutionResult = resolveToReceiver(expression, context, true); - if (context.expressionPosition == ExpressionPosition.FREE) { + if (!JetPsiUtil.isLHSOfDot(expression)) { context.trace.report(SUPER_IS_NOT_AN_EXPRESSION.on(expression, expression.getText())); return errorInSuper(expression, context); } + switch (resolutionResult.getCode()) { case LABEL_RESOLUTION_ERROR: // The error is already reported @@ -1124,7 +1124,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { @Override public JetTypeInfo visitRootNamespaceExpression(@NotNull JetRootNamespaceExpression expression, ExpressionTypingContext context) { - if (context.expressionPosition == ExpressionPosition.LHS_OF_DOT) { + if (JetPsiUtil.isLHSOfDot(expression)) { return DataFlowUtils.checkType(JetModuleUtil.getRootNamespaceType(expression), expression, context, context.dataFlowInfo); } context.trace.report(NAMESPACE_IS_NOT_AN_EXPRESSION.on(expression)); diff --git a/compiler/testData/diagnostics/tests/classObjects/kt3866.kt b/compiler/testData/diagnostics/tests/classObjects/kt3866.kt new file mode 100644 index 00000000000..22a3a34a9e0 --- /dev/null +++ b/compiler/testData/diagnostics/tests/classObjects/kt3866.kt @@ -0,0 +1,21 @@ +open class C { +} + +fun C.foo() {} + +open class X { + class object : C() {} +} + +open class Y { + class object : C() {} +} + +fun bar() { + val x = X + x.foo() + X.foo() + (X : C).foo() + (X as C).foo() + ((if (1<2) X else Y) : C).foo() +} diff --git a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java index 9cf96836b25..62b71a4fd3e 100644 --- a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java @@ -1374,6 +1374,11 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage doTest("compiler/testData/diagnostics/tests/classObjects/invisibleClassObjects.kt"); } + @TestMetadata("kt3866.kt") + public void testKt3866() throws Exception { + doTest("compiler/testData/diagnostics/tests/classObjects/kt3866.kt"); + } + @TestMetadata("nestedClassInPrivateClassObject.kt") public void testNestedClassInPrivateClassObject() throws Exception { doTest("compiler/testData/diagnostics/tests/classObjects/nestedClassInPrivateClassObject.kt");