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
This commit is contained in:
Alexander Udalov
2012-12-26 17:00:48 +04:00
parent c4b5577555
commit 192a81591b
15 changed files with 213 additions and 38 deletions
@@ -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<AnnotationDescriptor> 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) {
@@ -26,8 +26,5 @@ public interface NamespaceDescriptor extends Annotated, Named, FqNamed, ClassOrN
JetScope getMemberScope();
@NotNull
NamespaceType getNamespaceType();
@Override
NamespaceDescriptorParent getContainingDeclaration();
}
@@ -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();
@@ -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()
@@ -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.<!UNRESOLVED_REFERENCE!>Inner<!>()
fun f5() = Outer.<!UNRESOLVED_REFERENCE!>Inner<!>.<!DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>InnerInner<!>()
fun f6() = Outer().Inner()
fun f7() = Outer().Inner().InnerInner()
@@ -0,0 +1,5 @@
fun bar(b: Boolean) = b
fun foo(data: List<String>) {
bar(data.contains(""))
}
@@ -0,0 +1,7 @@
enum class E {
E1
E2 { }
}
fun foo() = E.E1
fun bar() = E.E2
@@ -0,0 +1,8 @@
class Outer {
class Nested<T>
}
fun nested() = Outer.Nested<Int>()
fun noArguments() = Outer.<!TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>Nested<!>()
fun noArgumentsExpectedType(): Outer.Nested<String> = Outer.Nested()
fun manyArguments() = Outer.Nested<!WRONG_NUMBER_OF_TYPE_ARGUMENTS!><String, Int><!>()
@@ -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()
@@ -0,0 +1,8 @@
package A
class B {
class C {
}
}
val a = A.B.C()
@@ -0,0 +1,9 @@
class A {
enum class E {
E1
E2 { }
}
}
fun foo() = A.E.E1
fun bar() = A.E.E2
@@ -0,0 +1,7 @@
object A {
object B {
object C
}
}
val a = A.B.C
@@ -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!!
@@ -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`.<init>
//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
@@ -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);