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:
-11
@@ -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();
|
||||
}
|
||||
|
||||
+41
-20
@@ -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();
|
||||
|
||||
|
||||
+14
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user