From 88c537942489ed2dc6644c7b1bf1e14ffcb8d31e Mon Sep 17 00:00:00 2001 From: "Pavel V. Talanov" Date: Tue, 17 Feb 2015 16:39:39 +0300 Subject: [PATCH] Change importing rules for objects: Allow importing classes from object, prohibit import-on-demand from objects It's unclear what import-on-demand from object should mean so we prohibit it for now --- .../jetbrains/kotlin/diagnostics/Errors.java | 1 + .../rendering/DefaultErrorMessages.java | 1 + .../org/jetbrains/kotlin/resolve/Importer.kt | 2 +- .../resolve/QualifiedExpressionResolver.java | 25 +++- .../diagnostics/tests/imports/Imports.kt | 2 +- .../tests/imports/StarImportFromObject.kt | 47 +++++++ .../tests/imports/StarImportFromObject.txt | 122 ++++++++++++++++++ .../diagnostics/tests/scopes/kt900-1.kt | 2 +- .../diagnostics/tests/scopes/kt900-2.kt | 16 +-- .../diagnostics/tests/scopes/kt900.kt | 4 +- .../checkers/JetDiagnosticsTestGenerated.java | 6 + 11 files changed, 214 insertions(+), 14 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/imports/StarImportFromObject.kt create mode 100644 compiler/testData/diagnostics/tests/imports/StarImportFromObject.txt diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java index 090f9b2d006..afa0addce27 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java @@ -100,6 +100,7 @@ public interface Errors { // Imports DiagnosticFactory1 CANNOT_IMPORT_FROM_ELEMENT = DiagnosticFactory1.create(ERROR); + DiagnosticFactory1 CANNOT_IMPORT_ON_DEMAND_FROM_SINGLETON = DiagnosticFactory1.create(ERROR); DiagnosticFactory1 CANNOT_BE_IMPORTED = DiagnosticFactory1.create(ERROR); DiagnosticFactory1 CONFLICTING_IMPORT = DiagnosticFactory1.create(ERROR); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java index b1fa4769a19..bb3923af581 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java @@ -166,6 +166,7 @@ public class DefaultErrorMessages { MAP.put(EXPRESSION_EXPECTED_PACKAGE_FOUND, "Expression expected, but a package name found"); MAP.put(CANNOT_IMPORT_FROM_ELEMENT, "Cannot import from ''{0}''", NAME); + MAP.put(CANNOT_IMPORT_ON_DEMAND_FROM_SINGLETON, "Cannot import-on-demand from object ''{0}''", NAME); MAP.put(CANNOT_BE_IMPORTED, "Cannot import ''{0}'', functions and properties can be imported only from packages", NAME); MAP.put(CONFLICTING_IMPORT, "Conflicting import, imported name ''{0}'' is ambiguous", STRING); MAP.put(PLATFORM_CLASS_MAPPED_TO_KOTLIN, "This class shouldn''t be used in Kotlin. Use {0} instead.", CLASSES_OR_SEPARATED); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/Importer.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/Importer.kt index b5721da7ffc..10ac2e71673 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/Importer.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/Importer.kt @@ -34,7 +34,7 @@ public class Importer { if (descriptor is PackageViewDescriptor) { allUnderImportScopes.add(NoSubpackagesInPackageScope(descriptor)) } - else if (descriptor is ClassDescriptor && descriptor.getKind() != ClassKind.OBJECT) { + else if (descriptor is ClassDescriptor && QualifiedExpressionResolver.canAllUnderImportFromClass(descriptor)) { allUnderImportScopes.add(descriptor.getStaticScope()) allUnderImportScopes.add(descriptor.getUnsubstitutedInnerClassesScope()) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/QualifiedExpressionResolver.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/QualifiedExpressionResolver.java index 9c947e3c3db..a14158702f3 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/QualifiedExpressionResolver.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/QualifiedExpressionResolver.java @@ -54,6 +54,25 @@ public class QualifiedExpressionResolver { EVERYTHING } + public static boolean canAllUnderImportFrom(@NotNull Collection descriptors) { + if (descriptors.isEmpty()) { + return true; + } + for (DeclarationDescriptor descriptor : descriptors) { + if (!(descriptor instanceof ClassDescriptor)) { + return true; + } + if (canAllUnderImportFromClass((ClassDescriptor) descriptor)) { + return true; + } + } + return false; + } + + public static boolean canAllUnderImportFromClass(@NotNull ClassDescriptor descriptor) { + return !descriptor.getKind().isSingleton(); + } + @NotNull public Collection processImportReference( @NotNull JetImportDirective importDirective, @@ -88,6 +107,10 @@ public class QualifiedExpressionResolver { JetSimpleNameExpression referenceExpression = JetPsiUtil.getLastReference(importedReference); if (importDirective.isAllUnder()) { + if (!canAllUnderImportFrom(descriptors) && referenceExpression != null) { + trace.report(CANNOT_IMPORT_ON_DEMAND_FROM_SINGLETON.on(referenceExpression, (ClassDescriptor) descriptors.iterator().next())); + } + if (referenceExpression == null || !canImportMembersFrom(descriptors, referenceExpression, trace, lookupMode)) { return Collections.emptyList(); } @@ -150,7 +173,7 @@ public class QualifiedExpressionResolver { if (descriptor instanceof PackageViewDescriptor) { return true; } - if (descriptor instanceof ClassDescriptor && !((ClassDescriptor) descriptor).getKind().isSingleton()) { + if (descriptor instanceof ClassDescriptor) { return true; } trace.report(CANNOT_IMPORT_FROM_ELEMENT.on(reference, descriptor)); diff --git a/compiler/testData/diagnostics/tests/imports/Imports.kt b/compiler/testData/diagnostics/tests/imports/Imports.kt index 14b10059db3..cec1771aa49 100644 --- a/compiler/testData/diagnostics/tests/imports/Imports.kt +++ b/compiler/testData/diagnostics/tests/imports/Imports.kt @@ -70,7 +70,7 @@ fun bar() {} //FILE:c.kt package c -import c.C.* +import c.C.* object C { fun f() { diff --git a/compiler/testData/diagnostics/tests/imports/StarImportFromObject.kt b/compiler/testData/diagnostics/tests/imports/StarImportFromObject.kt new file mode 100644 index 00000000000..1de1a401604 --- /dev/null +++ b/compiler/testData/diagnostics/tests/imports/StarImportFromObject.kt @@ -0,0 +1,47 @@ +package a + +import a.A.* +import a.A.C +import a.A.C.* +import a.A.D.* +import a.A.C.* +import a.A.C.G +import a.A.E.J.* +import a.A.CO.* +import a.A.CO + +import a.B.C.* +import a.B.C.A.* +import a.B.C.D.* + +import a.E.* +import a.E.E1 +import a.E.E2.* + +class A { + object C { + object G + } + object D { + + } + + class E { + object J + } + + class object CO { + object H + } +} + +enum class E { + E1 E2 +} + +object B { + class C { + object A + object D + } +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/imports/StarImportFromObject.txt b/compiler/testData/diagnostics/tests/imports/StarImportFromObject.txt new file mode 100644 index 00000000000..33f69c6447d --- /dev/null +++ b/compiler/testData/diagnostics/tests/imports/StarImportFromObject.txt @@ -0,0 +1,122 @@ +package + +package a { + + internal final class A { + public constructor A() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + internal object C { + private constructor C() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + internal object G { + private constructor G() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } + } + + internal class object CO { + private constructor CO() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + internal object H { + private constructor H() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } + } + + internal object D { + private constructor D() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } + + internal final class E { + public constructor E() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + internal object J { + private constructor J() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } + } + } + + internal object B { + private constructor B() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + internal final class C { + public constructor C() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + internal object A { + private constructor A() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } + + internal object D { + private constructor D() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } + } + } + + internal final enum class E : kotlin.Enum { + public enum entry E1 : a.E { + private constructor E1() + public final override /*1*/ /*fake_override*/ fun compareTo(/*0*/ other: a.E): kotlin.Int + public final override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public final override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public final override /*1*/ /*fake_override*/ fun name(): kotlin.String + public final override /*1*/ /*fake_override*/ fun ordinal(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } + + public enum entry E2 : a.E { + private constructor E2() + public final override /*1*/ /*fake_override*/ fun compareTo(/*0*/ other: a.E): kotlin.Int + public final override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public final override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public final override /*1*/ /*fake_override*/ fun name(): kotlin.String + public final override /*1*/ /*fake_override*/ fun ordinal(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } + + private constructor E() + public final override /*1*/ /*fake_override*/ fun compareTo(/*0*/ other: a.E): kotlin.Int + public final override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public final override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public final override /*1*/ /*fake_override*/ fun name(): kotlin.String + public final override /*1*/ /*fake_override*/ fun ordinal(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + // Static members + public final /*synthesized*/ fun valueOf(/*0*/ value: kotlin.String): a.E + public final /*synthesized*/ fun values(): kotlin.Array + } +} diff --git a/compiler/testData/diagnostics/tests/scopes/kt900-1.kt b/compiler/testData/diagnostics/tests/scopes/kt900-1.kt index abd2dab3cd9..ee78487073d 100644 --- a/compiler/testData/diagnostics/tests/scopes/kt900-1.kt +++ b/compiler/testData/diagnostics/tests/scopes/kt900-1.kt @@ -2,7 +2,7 @@ package c import c.A.* -import c.M.* +import c.M.* fun foo() { val b: B = B() diff --git a/compiler/testData/diagnostics/tests/scopes/kt900-2.kt b/compiler/testData/diagnostics/tests/scopes/kt900-2.kt index 9267abd625e..a59f7ba4e1a 100644 --- a/compiler/testData/diagnostics/tests/scopes/kt900-2.kt +++ b/compiler/testData/diagnostics/tests/scopes/kt900-2.kt @@ -2,18 +2,18 @@ package d //import from objects before properties resolve -import d.A.* -import d.M.R -import d.M.R.bar -import d.M.T -import d.M.Y +import d.A.* +import d.M.R +import d.M.R.bar +import d.M.T +import d.M.Y -var r: T = T() -val y: T = Y +var r: T = T() +val y: T = Y fun f() { bar() - R.bar() + R.bar() B.foo() } diff --git a/compiler/testData/diagnostics/tests/scopes/kt900.kt b/compiler/testData/diagnostics/tests/scopes/kt900.kt index 924df791112..253c28fe66b 100644 --- a/compiler/testData/diagnostics/tests/scopes/kt900.kt +++ b/compiler/testData/diagnostics/tests/scopes/kt900.kt @@ -35,7 +35,7 @@ object N { //FILE:b.kt package b -import b.N.M +import b.N.M import b.A.P import b.A.B @@ -45,7 +45,7 @@ fun foo() { P.foo() - M.bar() + M.bar() } class A() { diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java index 3d0b438281a..8b29bc78445 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java @@ -5209,6 +5209,12 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest { String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/imports/RenameOnImport.kt"); doTest(fileName); } + + @TestMetadata("StarImportFromObject.kt") + public void testStarImportFromObject() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/imports/StarImportFromObject.kt"); + doTest(fileName); + } } @TestMetadata("compiler/testData/diagnostics/tests/incompleteCode")