Prohibit constructors declarations for object

This commit is contained in:
Denis Zharkov
2015-02-13 14:55:44 +03:00
parent 3fef4ad742
commit 28fbdb7c53
9 changed files with 103 additions and 3 deletions
@@ -156,6 +156,7 @@ public interface Errors {
// Secondary constructors // Secondary constructors
DiagnosticFactory0<JetConstructorDelegationCall> CYCLIC_CONSTRUCTOR_DELEGATION_CALL = DiagnosticFactory0.create(ERROR); DiagnosticFactory0<JetConstructorDelegationCall> CYCLIC_CONSTRUCTOR_DELEGATION_CALL = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<JetSecondaryConstructor> SECONDARY_CONSTRUCTOR_IN_OBJECT = DiagnosticFactory0.create(ERROR);
// Trait-specific // Trait-specific
@@ -414,6 +414,7 @@ public class DefaultErrorMessages {
MAP.put(SINGLETON_IN_SUPERTYPE, "Cannot inherit from a singleton"); MAP.put(SINGLETON_IN_SUPERTYPE, "Cannot inherit from a singleton");
MAP.put(CYCLIC_CONSTRUCTOR_DELEGATION_CALL, "There's a cycle in the delegation calls chain"); MAP.put(CYCLIC_CONSTRUCTOR_DELEGATION_CALL, "There's a cycle in the delegation calls chain");
MAP.put(SECONDARY_CONSTRUCTOR_IN_OBJECT, "Constructors are not allowed for objects");
MAP.put(ILLEGAL_SELECTOR, "Expression ''{0}'' cannot be a selector (occur after a dot)", STRING); MAP.put(ILLEGAL_SELECTOR, "Expression ''{0}'' cannot be a selector (occur after a dot)", STRING);
@@ -175,4 +175,9 @@ public class JetSecondaryConstructor extends JetDeclarationStub<KotlinPlaceHolde
public JetConstructorDelegationCall getDelegationCall() { public JetConstructorDelegationCall getDelegationCall() {
return getStubOrPsiChild(JetStubElementTypes.CONSTRUCTOR_DELEGATION_CALL); return getStubOrPsiChild(JetStubElementTypes.CONSTRUCTOR_DELEGATION_CALL);
} }
@NotNull
public JetClassOrObject getClassOrObject() {
return (JetClassOrObject) getParent().getParent();
}
} }
@@ -37,6 +37,7 @@ import java.util.Collection;
import java.util.List; import java.util.List;
import static org.jetbrains.kotlin.diagnostics.Errors.MANY_DEFAULT_OBJECTS; import static org.jetbrains.kotlin.diagnostics.Errors.MANY_DEFAULT_OBJECTS;
import static org.jetbrains.kotlin.diagnostics.Errors.SECONDARY_CONSTRUCTOR_IN_OBJECT;
import static org.jetbrains.kotlin.diagnostics.Errors.UNSUPPORTED; import static org.jetbrains.kotlin.diagnostics.Errors.UNSUPPORTED;
public class LazyTopDownAnalyzer { public class LazyTopDownAnalyzer {
@@ -189,10 +190,10 @@ public class LazyTopDownAnalyzer {
registerDeclarations(classOrObject.getDeclarations()); registerDeclarations(classOrObject.getDeclarations());
registerTopLevelFqName(topLevelFqNames, classOrObject, descriptor); registerTopLevelFqName(topLevelFqNames, classOrObject, descriptor);
checkManyDefaultObjects(classOrObject); checkClassOrObjectDeclarations(classOrObject, descriptor);
} }
private void checkManyDefaultObjects(JetClassOrObject classOrObject) { private void checkClassOrObjectDeclarations(JetClassOrObject classOrObject, ClassDescriptor classDescriptor) {
boolean defaultObjectAlreadyFound = false; boolean defaultObjectAlreadyFound = false;
for (JetDeclaration jetDeclaration : classOrObject.getDeclarations()) { for (JetDeclaration jetDeclaration : classOrObject.getDeclarations()) {
if (jetDeclaration instanceof JetObjectDeclaration && ((JetObjectDeclaration) jetDeclaration).isDefault()) { if (jetDeclaration instanceof JetObjectDeclaration && ((JetObjectDeclaration) jetDeclaration).isDefault()) {
@@ -201,6 +202,11 @@ public class LazyTopDownAnalyzer {
} }
defaultObjectAlreadyFound = true; defaultObjectAlreadyFound = true;
} }
else if (jetDeclaration instanceof JetSecondaryConstructor) {
if (DescriptorUtils.isSingletonOrAnonymousObject(classDescriptor)) {
trace.report(SECONDARY_CONSTRUCTOR_IN_OBJECT.on((JetSecondaryConstructor) jetDeclaration));
}
}
} }
} }
@@ -223,6 +229,11 @@ public class LazyTopDownAnalyzer {
@Override @Override
public void visitSecondaryConstructor(@NotNull JetSecondaryConstructor constructor) { public void visitSecondaryConstructor(@NotNull JetSecondaryConstructor constructor) {
ClassDescriptor classDescriptor =
(ClassDescriptor) lazyDeclarationResolver.resolveToDescriptor(constructor.getClassOrObject());
if (!DescriptorUtils.canHaveSecondaryConstructors(classDescriptor)) {
return;
}
c.getSecondaryConstructors().put( c.getSecondaryConstructors().put(
constructor, constructor,
(ConstructorDescriptor) lazyDeclarationResolver.resolveToDescriptor(constructor) (ConstructorDescriptor) lazyDeclarationResolver.resolveToDescriptor(constructor)
@@ -297,8 +297,9 @@ public open class LazyClassMemberScope(
private fun resolveSecondaryConstructors(): Collection<ConstructorDescriptor> { private fun resolveSecondaryConstructors(): Collection<ConstructorDescriptor> {
val classOrObject = declarationProvider.getOwnerInfo().getCorrespondingClassOrObject() val classOrObject = declarationProvider.getOwnerInfo().getCorrespondingClassOrObject()
if (!DescriptorUtils.canHaveSecondaryConstructors(thisDescriptor)) return emptyList()
// Script classes have usual class descriptors but do not have conventional class body
if (classOrObject !is JetClass) return emptyList() if (classOrObject !is JetClass) return emptyList()
if (thisDescriptor.getKind().isSingleton()) return emptyList()
return classOrObject.getSecondaryConstructors().map { constructor -> return classOrObject.getSecondaryConstructors().map { constructor ->
val descriptor = c.descriptorResolver.resolveSecondaryConstructorDescriptor( val descriptor = c.descriptorResolver.resolveSecondaryConstructorDescriptor(
@@ -0,0 +1,20 @@
object A {
<!SECONDARY_CONSTRUCTOR_IN_OBJECT!>constructor() {}<!>
init {}
}
enum class B {
X : B() {
<!SECONDARY_CONSTRUCTOR_IN_OBJECT!>constructor() {}<!>
}
}
class C {
default object {
<!SECONDARY_CONSTRUCTOR_IN_OBJECT!>constructor() {}<!>
}
}
val anonObject = object {
<!SECONDARY_CONSTRUCTOR_IN_OBJECT!>constructor() {}<!>
}
@@ -0,0 +1,48 @@
package
internal val anonObject: kotlin.Any
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 final enum class B : kotlin.Enum<B> {
public enum entry X : B {
private constructor X()
public final override /*1*/ /*fake_override*/ fun compareTo(/*0*/ other: B): 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 B()
public final override /*1*/ /*fake_override*/ fun compareTo(/*0*/ other: B): 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): B
public final /*synthesized*/ fun values(): kotlin.Array<B>
}
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 default object Default {
private constructor Default()
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
}
}
@@ -10415,6 +10415,12 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
doTest(fileName); doTest(fileName);
} }
@TestMetadata("constructorInObject.kt")
public void testConstructorInObject() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/secondaryConstructors/constructorInObject.kt");
doTest(fileName);
}
@TestMetadata("cyclicDelegationCalls.kt") @TestMetadata("cyclicDelegationCalls.kt")
public void testCyclicDelegationCalls() throws Exception { public void testCyclicDelegationCalls() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/secondaryConstructors/cyclicDelegationCalls.kt"); String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/secondaryConstructors/cyclicDelegationCalls.kt");
@@ -480,4 +480,11 @@ public class DescriptorUtils {
return false; return false;
} }
public static boolean isSingletonOrAnonymousObject(@NotNull ClassDescriptor classDescriptor) {
return classDescriptor.getKind().isSingleton() || isAnonymousObject(classDescriptor);
}
public static boolean canHaveSecondaryConstructors(@NotNull ClassDescriptor classDescriptor) {
return !isSingletonOrAnonymousObject(classDescriptor) && !isTrait(classDescriptor);
}
} }