diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/AbstractNamespaceDescriptorImpl.java b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/AbstractNamespaceDescriptorImpl.java index b0072063dbb..2d30a4eab00 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/AbstractNamespaceDescriptorImpl.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/AbstractNamespaceDescriptorImpl.java @@ -25,8 +25,6 @@ import org.jetbrains.jet.lang.types.TypeSubstitutor; import java.util.List; public abstract class AbstractNamespaceDescriptorImpl extends DeclarationDescriptorNonRootImpl implements NamespaceDescriptor { - private NamespaceType namespaceType; - public AbstractNamespaceDescriptorImpl( @NotNull NamespaceDescriptorParent containingDeclaration, List annotations, @@ -51,15 +49,6 @@ public abstract class AbstractNamespaceDescriptorImpl extends DeclarationDescrip throw new IllegalStateException("immutable"); } - @Override - @NotNull - public NamespaceType getNamespaceType() { - if (namespaceType == null) { - namespaceType = new NamespaceType(getName(), getMemberScope()); - } - return namespaceType; - } - @NotNull @Override public NamespaceDescriptor substitute(TypeSubstitutor substitutor) { diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/NamespaceDescriptor.java b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/NamespaceDescriptor.java index a4e22a67842..a7bcc83a84d 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/NamespaceDescriptor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/NamespaceDescriptor.java @@ -26,8 +26,5 @@ public interface NamespaceDescriptor extends Annotated, Named, FqNamed, ClassOrN JetScope getMemberScope(); @NotNull - NamespaceType getNamespaceType(); - - @Override NamespaceDescriptorParent getContainingDeclaration(); } 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 6715e8b1965..0012f0aee7b 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 @@ -40,6 +40,7 @@ import org.jetbrains.jet.lang.resolve.constants.*; import org.jetbrains.jet.lang.resolve.constants.StringValue; import org.jetbrains.jet.lang.resolve.name.LabelName; import org.jetbrains.jet.lang.resolve.name.Name; +import org.jetbrains.jet.lang.resolve.scopes.ChainedScope; import org.jetbrains.jet.lang.resolve.scopes.FilteringScope; import org.jetbrains.jet.lang.resolve.scopes.JetScope; import org.jetbrains.jet.lang.resolve.scopes.WritableScopeImpl; @@ -78,29 +79,33 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { } @Nullable - private JetType lookupNamespaceOrClassObject(JetSimpleNameExpression expression, Name referencedName, ExpressionTypingContext context) { + private JetType lookupNamespaceOrClassObject(@NotNull JetSimpleNameExpression expression, @NotNull ExpressionTypingContext context) { + Name referencedName = expression.getReferencedNameAsName(); ClassifierDescriptor classifier = context.scope.getClassifier(referencedName); if (classifier != null) { JetType classObjectType = classifier.getClassObjectType(); - JetType result = null; if (classObjectType != null) { - if (context.namespacesAllowed || classifier.isClassObjectAValue()) { + context.trace.record(REFERENCE_TARGET, expression, classifier); + JetType result; + if (context.namespacesAllowed && classifier instanceof ClassDescriptor) { + JetScope scope = new ChainedScope(classifier, classObjectType.getMemberScope(), + getStaticNestedClassesScope((ClassDescriptor) classifier)); + result = new NamespaceType(referencedName, scope); + } + else if (context.namespacesAllowed || classifier.isClassObjectAValue()) { result = classObjectType; } else { context.trace.report(NO_CLASS_OBJECT.on(expression, classifier)); + result = null; } - context.trace.record(REFERENCE_TARGET, expression, classifier); - //if (result == null) { - // return ErrorUtils.createErrorType("No class object in " + expression.getReferencedName()); - //} return DataFlowUtils.checkType(result, expression, context); } } JetType[] result = new JetType[1]; TemporaryBindingTrace temporaryTrace = TemporaryBindingTrace.create( context.trace, "trace for namespace/class object lookup of name", referencedName); - if (furtherNameLookup(expression, referencedName, result, context.replaceBindingTrace(temporaryTrace))) { + if (furtherNameLookup(expression, result, context.replaceBindingTrace(temporaryTrace))) { temporaryTrace.commit(); return DataFlowUtils.checkType(result[0], expression, context); } @@ -130,27 +135,43 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { }); } - protected boolean furtherNameLookup(@NotNull JetSimpleNameExpression expression, @NotNull Name referencedName, @NotNull JetType[] result, ExpressionTypingContext context) { + private boolean furtherNameLookup( + @NotNull JetSimpleNameExpression expression, + @NotNull JetType[] result, + @NotNull ExpressionTypingContext context + ) { + NamespaceType namespaceType = lookupNamespaceType(expression, context); + if (namespaceType == null) { + return false; + } if (context.namespacesAllowed) { - result[0] = lookupNamespaceType(expression, referencedName, context); - return result[0] != null; - } - NamespaceType namespaceType = lookupNamespaceType(expression, referencedName, context); - if (namespaceType != null) { - context.trace.report(EXPRESSION_EXPECTED_NAMESPACE_FOUND.on(expression)); - result[0] = ErrorUtils.createErrorType("Type for " + referencedName); + result[0] = namespaceType; + return true; } + context.trace.report(EXPRESSION_EXPECTED_NAMESPACE_FOUND.on(expression)); + result[0] = ErrorUtils.createErrorType("Type for " + expression.getReferencedNameAsName()); return false; } @Nullable - protected NamespaceType lookupNamespaceType(@NotNull JetSimpleNameExpression expression, @NotNull Name referencedName, ExpressionTypingContext context) { - NamespaceDescriptor namespace = context.scope.getNamespace(referencedName); + private NamespaceType lookupNamespaceType(@NotNull JetSimpleNameExpression expression, @NotNull ExpressionTypingContext context) { + Name name = expression.getReferencedNameAsName(); + NamespaceDescriptor namespace = context.scope.getNamespace(name); if (namespace == null) { return null; } context.trace.record(REFERENCE_TARGET, expression, namespace); - return namespace.getNamespaceType(); + + // Construct a NamespaceType with everything from the namespace and with static nested classes of the corresponding class (if any) + JetScope scope; + ClassifierDescriptor classifier = context.scope.getClassifier(name); + if (classifier instanceof ClassDescriptor) { + scope = new ChainedScope(namespace, namespace.getMemberScope(), getStaticNestedClassesScope((ClassDescriptor) classifier)); + } + else { + scope = namespace.getMemberScope(); + } + return new NamespaceType(name, scope); } @Override @@ -769,7 +790,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { : context; TemporaryBindingTrace traceForNamespaceOrClassObject = TemporaryBindingTrace.create( context.trace, "trace to resolve as namespace or class object", nameExpression); - JetType jetType = lookupNamespaceOrClassObject(nameExpression, nameExpression.getReferencedNameAsName(), newContext.replaceBindingTrace(traceForNamespaceOrClassObject)); + JetType jetType = lookupNamespaceOrClassObject(nameExpression, newContext.replaceBindingTrace(traceForNamespaceOrClassObject)); if (jetType != null) { traceForNamespaceOrClassObject.commit(); diff --git a/compiler/testData/diagnostics/tests/inner/qualifiedExpression/classObjectOfNestedClass.kt b/compiler/testData/diagnostics/tests/inner/qualifiedExpression/classObjectOfNestedClass.kt new file mode 100644 index 00000000000..514a0a3767d --- /dev/null +++ b/compiler/testData/diagnostics/tests/inner/qualifiedExpression/classObjectOfNestedClass.kt @@ -0,0 +1,14 @@ +class Outer { + class Nested { + class object { + fun foo() = 42 + } + } + + class object { + fun bar() = 239 + } +} + +fun foo() = Outer.Nested.foo() +fun bar() = Outer.bar() diff --git a/compiler/testData/diagnostics/tests/inner/qualifiedExpression/constructNestedClass.kt b/compiler/testData/diagnostics/tests/inner/qualifiedExpression/constructNestedClass.kt new file mode 100644 index 00000000000..fae9317986a --- /dev/null +++ b/compiler/testData/diagnostics/tests/inner/qualifiedExpression/constructNestedClass.kt @@ -0,0 +1,17 @@ +class Outer { + class Nested { + class NestedNested + } + + inner class Inner { + inner class InnerInner + } +} + +fun f1() = Outer() +fun f2() = Outer.Nested() +fun f3() = Outer.Nested.NestedNested() +fun f4() = Outer.Inner() +fun f5() = Outer.Inner.InnerInner() +fun f6() = Outer().Inner() +fun f7() = Outer().Inner().InnerInner() diff --git a/compiler/testData/diagnostics/tests/inner/qualifiedExpression/dataLocalVariable.kt b/compiler/testData/diagnostics/tests/inner/qualifiedExpression/dataLocalVariable.kt new file mode 100644 index 00000000000..07b6d50f09c --- /dev/null +++ b/compiler/testData/diagnostics/tests/inner/qualifiedExpression/dataLocalVariable.kt @@ -0,0 +1,5 @@ +fun bar(b: Boolean) = b + +fun foo(data: List) { + bar(data.contains("")) +} diff --git a/compiler/testData/diagnostics/tests/inner/qualifiedExpression/enumConstant.kt b/compiler/testData/diagnostics/tests/inner/qualifiedExpression/enumConstant.kt new file mode 100644 index 00000000000..bc777fe834c --- /dev/null +++ b/compiler/testData/diagnostics/tests/inner/qualifiedExpression/enumConstant.kt @@ -0,0 +1,7 @@ +enum class E { + E1 + E2 { } +} + +fun foo() = E.E1 +fun bar() = E.E2 diff --git a/compiler/testData/diagnostics/tests/inner/qualifiedExpression/genericNestedClass.kt b/compiler/testData/diagnostics/tests/inner/qualifiedExpression/genericNestedClass.kt new file mode 100644 index 00000000000..bc142a7e12c --- /dev/null +++ b/compiler/testData/diagnostics/tests/inner/qualifiedExpression/genericNestedClass.kt @@ -0,0 +1,8 @@ +class Outer { + class Nested +} + +fun nested() = Outer.Nested() +fun noArguments() = Outer.Nested() +fun noArgumentsExpectedType(): Outer.Nested = Outer.Nested() +fun manyArguments() = Outer.Nested() diff --git a/compiler/testData/diagnostics/tests/inner/qualifiedExpression/importNestedClass.kt b/compiler/testData/diagnostics/tests/inner/qualifiedExpression/importNestedClass.kt new file mode 100644 index 00000000000..128bdafcc08 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inner/qualifiedExpression/importNestedClass.kt @@ -0,0 +1,17 @@ +// FILE: a.kt +class A { + class B { + class C + } +} + +// FILE: b.kt +import A.B +import A.B.C + +val a = A() +val b = B() +val ab = A.B() +val c = C() +val bc = B.C() +val abc = A.B.C() diff --git a/compiler/testData/diagnostics/tests/inner/qualifiedExpression/nestedClassInPackage.kt b/compiler/testData/diagnostics/tests/inner/qualifiedExpression/nestedClassInPackage.kt new file mode 100644 index 00000000000..07623cb8350 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inner/qualifiedExpression/nestedClassInPackage.kt @@ -0,0 +1,8 @@ +package A + +class B { + class C { + } +} + +val a = A.B.C() diff --git a/compiler/testData/diagnostics/tests/inner/qualifiedExpression/nestedEnumConstant.kt b/compiler/testData/diagnostics/tests/inner/qualifiedExpression/nestedEnumConstant.kt new file mode 100644 index 00000000000..033826556c1 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inner/qualifiedExpression/nestedEnumConstant.kt @@ -0,0 +1,9 @@ +class A { + enum class E { + E1 + E2 { } + } +} + +fun foo() = A.E.E1 +fun bar() = A.E.E2 diff --git a/compiler/testData/diagnostics/tests/inner/qualifiedExpression/nestedObjects.kt b/compiler/testData/diagnostics/tests/inner/qualifiedExpression/nestedObjects.kt new file mode 100644 index 00000000000..c764ad234e1 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inner/qualifiedExpression/nestedObjects.kt @@ -0,0 +1,7 @@ +object A { + object B { + object C + } +} + +val a = A.B.C diff --git a/compiler/testData/diagnostics/tests/inner/qualifiedExpression/typePosition.kt b/compiler/testData/diagnostics/tests/inner/qualifiedExpression/typePosition.kt new file mode 100644 index 00000000000..067bc4df710 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inner/qualifiedExpression/typePosition.kt @@ -0,0 +1,11 @@ +abstract class Outer { + class Nested { + class NestedNested + } + + abstract val prop1: Nested + abstract val prop2: Nested.NestedNested +} + +fun foo(): Outer.Nested = null!! +val bar: Outer.Nested.NestedNested = null!! diff --git a/compiler/testData/renderer/KeywordsInNames.kt b/compiler/testData/renderer/KeywordsInNames.kt index 0b866190421..6337ac5c96d 100644 --- a/compiler/testData/renderer/KeywordsInNames.kt +++ b/compiler/testData/renderer/KeywordsInNames.kt @@ -5,10 +5,10 @@ val `val` = 5 `true` trait `trait` class `class`<`in`>(p: `in`?) { - class `class` + inner class `class` } -val `is` = `class`.`class`() +val `is` = `class`<`trait`>(null).`class`() val `in` = `class`<`trait`>(null) fun <`in`: `trait`> `trait`.`fun`(`false`: `trait`): `trait` where `in`: Number @@ -21,7 +21,7 @@ fun <`in`: `trait`> `trait`.`fun`(`false`: `trait`): `trait` where `in`: Number //public constructor `class`<`in`>(p : `in`?) defined in `class` //<`in`> defined in `class` //value-parameter val p : `in`? defined in `class`. -//internal final class `class` defined in `class` +//internal final inner class `class` defined in `class` //public constructor `class`() defined in `class`.`class` //internal val `is` : `class`.`class` defined in root package //internal val `in` : `class`<`trait`> defined in root package diff --git a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java index fec5bc2aade..d5c81e6650f 100644 --- a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java @@ -2399,6 +2399,7 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage } @TestMetadata("compiler/testData/diagnostics/tests/inner") + @InnerTestClasses({Inner.QualifiedExpression.class}) public static class Inner extends AbstractDiagnosticsTestWithEagerResolve { public void testAllFilesPresentInInner() throws Exception { JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("compiler/testData/diagnostics/tests/inner"), "kt", true); @@ -2479,6 +2480,70 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage doTest("compiler/testData/diagnostics/tests/inner/visibility.kt"); } + @TestMetadata("compiler/testData/diagnostics/tests/inner/qualifiedExpression") + public static class QualifiedExpression extends AbstractDiagnosticsTestWithEagerResolve { + public void testAllFilesPresentInQualifiedExpression() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("compiler/testData/diagnostics/tests/inner/qualifiedExpression"), "kt", true); + } + + @TestMetadata("classObjectOfNestedClass.kt") + public void testClassObjectOfNestedClass() throws Exception { + doTest("compiler/testData/diagnostics/tests/inner/qualifiedExpression/classObjectOfNestedClass.kt"); + } + + @TestMetadata("constructNestedClass.kt") + public void testConstructNestedClass() throws Exception { + doTest("compiler/testData/diagnostics/tests/inner/qualifiedExpression/constructNestedClass.kt"); + } + + @TestMetadata("dataLocalVariable.kt") + public void testDataLocalVariable() throws Exception { + doTest("compiler/testData/diagnostics/tests/inner/qualifiedExpression/dataLocalVariable.kt"); + } + + @TestMetadata("enumConstant.kt") + public void testEnumConstant() throws Exception { + doTest("compiler/testData/diagnostics/tests/inner/qualifiedExpression/enumConstant.kt"); + } + + @TestMetadata("genericNestedClass.kt") + public void testGenericNestedClass() throws Exception { + doTest("compiler/testData/diagnostics/tests/inner/qualifiedExpression/genericNestedClass.kt"); + } + + @TestMetadata("importNestedClass.kt") + public void testImportNestedClass() throws Exception { + doTest("compiler/testData/diagnostics/tests/inner/qualifiedExpression/importNestedClass.kt"); + } + + @TestMetadata("nestedClassInPackage.kt") + public void testNestedClassInPackage() throws Exception { + doTest("compiler/testData/diagnostics/tests/inner/qualifiedExpression/nestedClassInPackage.kt"); + } + + @TestMetadata("nestedEnumConstant.kt") + public void testNestedEnumConstant() throws Exception { + doTest("compiler/testData/diagnostics/tests/inner/qualifiedExpression/nestedEnumConstant.kt"); + } + + @TestMetadata("nestedObjects.kt") + public void testNestedObjects() throws Exception { + doTest("compiler/testData/diagnostics/tests/inner/qualifiedExpression/nestedObjects.kt"); + } + + @TestMetadata("typePosition.kt") + public void testTypePosition() throws Exception { + doTest("compiler/testData/diagnostics/tests/inner/qualifiedExpression/typePosition.kt"); + } + + } + + public static Test innerSuite() { + TestSuite suite = new TestSuite("Inner"); + suite.addTestSuite(Inner.class); + suite.addTestSuite(QualifiedExpression.class); + return suite; + } } @TestMetadata("compiler/testData/diagnostics/tests/j+k") @@ -4192,7 +4257,7 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage suite.addTest(IncompleteCode.innerSuite()); suite.addTest(Inference.innerSuite()); suite.addTestSuite(Infos.class); - suite.addTestSuite(Inner.class); + suite.addTest(Inner.innerSuite()); suite.addTestSuite(J_k.class); suite.addTest(Jdk_annotations.innerSuite()); suite.addTestSuite(Library.class);