From 192a81591bd1f8b40c05d8ca7b689b7acb3a9266 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Wed, 26 Dec 2012 17:00:48 +0400 Subject: [PATCH] Resolve qualified nested class expressions lookupNamespaceType now returns NamespaceType of a scope not only of the namespace found by name, but also of the classifier static classes scope found by the same name. This allows correct resolution of expressions "Class.Nested.member()", where Class comes from Java (previously it was resolved into a NamespaceDescriptor with a NamespaceType). NamespaceDescriptor.getNamespaceType() is deleted since there are no sense in namespace's NamespaceType alone anymore. Also some minor refactoring (referencedName param is useless) #KT-1174 In Progress --- .../AbstractNamespaceDescriptorImpl.java | 11 --- .../lang/descriptors/NamespaceDescriptor.java | 3 - .../BasicExpressionTypingVisitor.java | 61 +++++++++++------ .../classObjectOfNestedClass.kt | 14 ++++ .../constructNestedClass.kt | 17 +++++ .../qualifiedExpression/dataLocalVariable.kt | 5 ++ .../inner/qualifiedExpression/enumConstant.kt | 7 ++ .../qualifiedExpression/genericNestedClass.kt | 8 +++ .../qualifiedExpression/importNestedClass.kt | 17 +++++ .../nestedClassInPackage.kt | 8 +++ .../qualifiedExpression/nestedEnumConstant.kt | 9 +++ .../qualifiedExpression/nestedObjects.kt | 7 ++ .../inner/qualifiedExpression/typePosition.kt | 11 +++ compiler/testData/renderer/KeywordsInNames.kt | 6 +- .../checkers/JetDiagnosticsTestGenerated.java | 67 ++++++++++++++++++- 15 files changed, 213 insertions(+), 38 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/inner/qualifiedExpression/classObjectOfNestedClass.kt create mode 100644 compiler/testData/diagnostics/tests/inner/qualifiedExpression/constructNestedClass.kt create mode 100644 compiler/testData/diagnostics/tests/inner/qualifiedExpression/dataLocalVariable.kt create mode 100644 compiler/testData/diagnostics/tests/inner/qualifiedExpression/enumConstant.kt create mode 100644 compiler/testData/diagnostics/tests/inner/qualifiedExpression/genericNestedClass.kt create mode 100644 compiler/testData/diagnostics/tests/inner/qualifiedExpression/importNestedClass.kt create mode 100644 compiler/testData/diagnostics/tests/inner/qualifiedExpression/nestedClassInPackage.kt create mode 100644 compiler/testData/diagnostics/tests/inner/qualifiedExpression/nestedEnumConstant.kt create mode 100644 compiler/testData/diagnostics/tests/inner/qualifiedExpression/nestedObjects.kt create mode 100644 compiler/testData/diagnostics/tests/inner/qualifiedExpression/typePosition.kt 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);