Resolve constructors declared in traits and objects

It prevents exceptions and produces less red code

 #EA-68667 Fixed
This commit is contained in:
Denis Zharkov
2015-05-29 15:58:08 +03:00
parent 7f9d2e8a36
commit 70dbbd8fda
23 changed files with 179 additions and 31 deletions
@@ -1067,6 +1067,8 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
}
private void generateSecondaryConstructor(@NotNull ConstructorDescriptor constructorDescriptor) {
if (!canHaveDeclaredConstructors(descriptor)) return;
ConstructorContext constructorContext = context.intoConstructor(constructorDescriptor);
functionCodegen.generateMethod(OtherOrigin(descriptorToDeclaration(constructorDescriptor), constructorDescriptor),
@@ -371,6 +371,7 @@ public class BodyResolver {
}
if (descriptor.getKind() != ClassKind.INTERFACE &&
descriptor.getUnsubstitutedPrimaryConstructor() != null &&
superClass.getKind() != ClassKind.INTERFACE &&
!superClass.getConstructors().isEmpty() &&
!ErrorUtils.isError(superClass)
) {
@@ -500,8 +501,7 @@ public class BodyResolver {
private void resolvePrimaryConstructorParameters(@NotNull BodiesResolveContext c) {
for (Map.Entry<JetClassOrObject, ClassDescriptorWithResolutionScopes> entry : c.getDeclaredClasses().entrySet()) {
if (!(entry.getKey() instanceof JetClass)) continue;
JetClass klass = (JetClass) entry.getKey();
JetClassOrObject klass = entry.getKey();
ClassDescriptorWithResolutionScopes classDescriptor = entry.getValue();
ConstructorDescriptor unsubstitutedPrimaryConstructor = classDescriptor.getUnsubstitutedPrimaryConstructor();
@@ -87,6 +87,8 @@ public class DeclarationsChecker {
checkObject((JetObjectDeclaration) classOrObject, classDescriptor);
}
checkPrimaryConstructor(classOrObject, classDescriptor);
modifiersChecker.checkModifiersForDeclaration(classOrObject, classDescriptor);
}
@@ -244,7 +246,6 @@ public class DeclarationsChecker {
private void checkClass(BodiesResolveContext c, JetClass aClass, ClassDescriptorWithResolutionScopes classDescriptor) {
AnnotationResolver.reportDeprecatedAnnotationSyntax(aClass.getAnnotations(), trace);
checkOpenMembers(classDescriptor);
checkPrimaryConstructor(aClass, classDescriptor);
checkTypeParameters(aClass);
if (aClass.isInterface()) {
@@ -271,9 +272,9 @@ public class DeclarationsChecker {
}
}
private void checkPrimaryConstructor(JetClass aClass, ClassDescriptor classDescriptor) {
private void checkPrimaryConstructor(JetClassOrObject classOrObject, ClassDescriptor classDescriptor) {
ConstructorDescriptor primaryConstructor = classDescriptor.getUnsubstitutedPrimaryConstructor();
JetPrimaryConstructor declaration = aClass.getPrimaryConstructor();
JetPrimaryConstructor declaration = classOrObject.getPrimaryConstructor();
if (primaryConstructor == null || declaration == null) return;
for (JetParameter parameter : declaration.getValueParameters()) {
@@ -287,6 +288,10 @@ public class DeclarationsChecker {
trace.report(MISSING_CONSTRUCTOR_KEYWORD.on(declaration.getModifierList()));
}
if (!(classOrObject instanceof JetClass)) {
trace.report(CONSTRUCTOR_IN_OBJECT.on(declaration));
}
checkConstructorDeclaration(primaryConstructor, declaration);
}
@@ -210,7 +210,7 @@ class FunctionDescriptorResolver(
public fun resolvePrimaryConstructorDescriptor(
scope: JetScope,
classDescriptor: ClassDescriptor,
classElement: JetClass,
classElement: JetClassOrObject,
trace: BindingTrace
): ConstructorDescriptorImpl? {
if (classDescriptor.getKind() == ClassKind.ENUM_ENTRY || !classElement.hasPrimaryConstructor()) return null
@@ -199,10 +199,6 @@ public class LazyTopDownAnalyzer {
}
override fun visitSecondaryConstructor(constructor: JetSecondaryConstructor) {
val classDescriptor = lazyDeclarationResolver!!.resolveToDescriptor(constructor.getClassOrObject()) as ClassDescriptor
if (!DescriptorUtils.canHaveSecondaryConstructors(classDescriptor)) {
return
}
c.getSecondaryConstructors().put(constructor, lazyDeclarationResolver!!.resolveToDescriptor(constructor) as ConstructorDescriptor)
registerScope(c, constructor)
}
@@ -349,9 +349,12 @@ public class CallResolver {
Collection<ConstructorDescriptor> constructors = delegateClassDescriptor.getConstructors();
if (!isThisCall && currentClassDescriptor.getUnsubstitutedPrimaryConstructor() != null) {
context.trace.report(PRIMARY_CONSTRUCTOR_DELEGATION_CALL_EXPECTED.on(
(JetConstructorDelegationCall) calleeExpression.getParent()
));
if (DescriptorUtils.canHaveDeclaredConstructors(currentClassDescriptor)) {
// Diagnostic is meaningless when reporting on interfaces and object
context.trace.report(PRIMARY_CONSTRUCTOR_DELEGATION_CALL_EXPECTED.on(
(JetConstructorDelegationCall) calleeExpression.getParent()
));
}
if (call.isImplicit()) return OverloadResolutionResultsImpl.nameNotFound();
}
@@ -275,15 +275,12 @@ public open class LazyClassMemberScope(
protected open fun resolvePrimaryConstructor(): ConstructorDescriptor? {
val ownerInfo = declarationProvider.getOwnerInfo()
val classOrObject = ownerInfo.getCorrespondingClassOrObject()
if (!thisDescriptor.getKind().isSingleton() && !classOrObject.isObjectLiteral()) {
assert(classOrObject is JetClass) { "No JetClass for $thisDescriptor" }
classOrObject as JetClass
val classOrObject = ownerInfo.getCorrespondingClassOrObject() ?: return null
if (DescriptorUtils.isTrait(thisDescriptor) && declarationProvider.getOwnerInfo().getPrimaryConstructorParameters().isEmpty()) {
return null
}
val hasPrimaryConstructor = classOrObject.hasExplicitPrimaryConstructor()
if (DescriptorUtils.isTrait(thisDescriptor) && !hasPrimaryConstructor) return null
if (DescriptorUtils.canHaveDeclaredConstructors(thisDescriptor) || hasPrimaryConstructor) {
val constructor = c.functionDescriptorResolver.resolvePrimaryConstructorDescriptor(
thisDescriptor.getScopeForClassHeaderResolution(), thisDescriptor, classOrObject, trace)
constructor ?: return null
@@ -298,10 +295,7 @@ public open class LazyClassMemberScope(
}
private fun resolveSecondaryConstructors(): Collection<ConstructorDescriptor> {
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()
val classOrObject = declarationProvider.getOwnerInfo().getCorrespondingClassOrObject() ?: return emptyList()
return classOrObject.getSecondaryConstructors().map { constructor ->
val descriptor = c.functionDescriptorResolver.resolveSecondaryConstructorDescriptor(
@@ -0,0 +1,24 @@
object A1<!CONSTRUCTOR_IN_OBJECT!>()<!> {
<!CONSTRUCTOR_IN_OBJECT!>constructor(x: Int = <!TYPE_MISMATCH!>""<!>, y: Int)<!> : this() {
x + y
}
}
object A2 public <!CONSTRUCTOR_IN_OBJECT!>constructor(private val prop: Int)<!> {
<!CONSTRUCTOR_IN_OBJECT!>constructor(x: Int = <!TYPE_MISMATCH!>""<!>, y: Int)<!> : this(x * y) {
x + y
}
}
val x = object <!CONSTRUCTOR_IN_OBJECT!>(val prop: Int)<!> {
<!CONSTRUCTOR_IN_OBJECT!>constructor()<!> : this(1) {
val x = 1
x * x
}
}
class A3 {
companion object B<!CONSTRUCTOR_IN_OBJECT!>(val prop: Int)<!> {
<!CONSTRUCTOR_IN_OBJECT!>public constructor()<!> : this(2)
}
}
@@ -0,0 +1,36 @@
package
internal val x: kotlin.Any
internal object A1 {
private constructor A1()
private constructor A1(/*0*/ x: kotlin.Int = ..., /*1*/ y: kotlin.Int)
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 A2 {
public constructor A2(/*0*/ prop: kotlin.Int)
private constructor A2(/*0*/ x: kotlin.Int = ..., /*1*/ y: kotlin.Int)
private final val prop: kotlin.Int
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 A3 {
public constructor A3()
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 companion object B {
public constructor B()
private constructor B(/*0*/ prop: kotlin.Int)
internal final val prop: kotlin.Int
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
}
}
@@ -83,6 +83,7 @@ internal interface T2</*0*/ T> {
}
internal interface Test {
public constructor Test()
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
@@ -1,14 +1,16 @@
// !DIAGNOSTICS: -MISSING_CONSTRUCTOR_KEYWORD
class C(val a: String) {}
interface T1<!CONSTRUCTOR_IN_TRAIT!>(val x: String)<!> {}
interface T2<!CONSTRUCTOR_IN_TRAIT!>()<!> {}
interface T2 <!CONSTRUCTOR_IN_TRAIT!>constructor()<!> {}
interface T3 private <!CONSTRUCTOR_IN_TRAIT!>constructor(<!UNUSED_PARAMETER!>a<!>: Int)<!> {}
interface T4 {
<!CONSTRUCTOR_IN_TRAIT!>constructor(a: <!DEBUG_INFO_MISSING_UNRESOLVED!>Int<!>)<!> {
val b: <!DEBUG_INFO_MISSING_UNRESOLVED!>Int<!> = 1
<!CONSTRUCTOR_IN_TRAIT!>constructor(<!UNUSED_PARAMETER!>a<!>: Int)<!> {
val <!UNUSED_VARIABLE!>b<!>: Int = 1
}
}
@@ -17,6 +17,7 @@ internal interface T1 {
}
internal interface T2 {
public constructor T2()
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
@@ -30,18 +31,21 @@ internal interface T3 {
}
internal interface T4 {
public constructor T4(/*0*/ a: kotlin.Int)
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 interface T5 : T4 {
private constructor T5()
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 interface T6 : T5 {
private constructor T6()
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
@@ -3,6 +3,7 @@ package
internal val anonObject: kotlin.Any
internal object A {
private constructor 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
@@ -11,6 +12,7 @@ internal object A {
internal final enum class B : kotlin.Enum<B> {
public enum entry X : B {
private constructor X()
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
@@ -40,6 +42,7 @@ internal final class C {
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
internal companion object Companion {
private constructor Companion()
private constructor Companion()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
@@ -1,6 +1,7 @@
package
internal interface 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
@@ -6,5 +6,5 @@ interface Foo<!CONSTRUCTOR_IN_TRAIT!>()<!> : <!TRAIT_WITH_SUPERCLASS!>bar<!><!SU
interface Foo2 : <!TRAIT_WITH_SUPERCLASS!>bar<!>, Foo {
}
open class Foo1() : bar(), <!SUPERTYPE_NOT_INITIALIZED, MANY_CLASSES_IN_SUPERTYPE_LIST, SUPERTYPE_APPEARS_TWICE!>bar<!>, Foo, <!SUPERTYPE_APPEARS_TWICE!>Foo<!><!NO_CONSTRUCTOR!>()<!> {}
open class Foo1() : bar(), <!SUPERTYPE_NOT_INITIALIZED, MANY_CLASSES_IN_SUPERTYPE_LIST, SUPERTYPE_APPEARS_TWICE!>bar<!>, Foo, <!SUPERTYPE_APPEARS_TWICE!>Foo<!>() {}
open class Foo12 : bar(), <!SUPERTYPE_NOT_INITIALIZED, MANY_CLASSES_IN_SUPERTYPE_LIST, SUPERTYPE_APPEARS_TWICE!>bar<!> {}
@@ -1,6 +1,7 @@
package
internal interface Foo : bar, bar, bar {
public constructor Foo()
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
+35
View File
@@ -0,0 +1,35 @@
object A1() {
constructor(x: Int = "", y: Int) : this() {
x + y
}
}
object A2 public constructor(private val prop: Int) {
constructor(x: Int = "", y: Int) : this(x * y) {
x + y
}
}
class A3 {
companion object B(val prop: Int) {
public constructor() : this(2)
}
}
//internal object A1 defined in root package
//private constructor A1() defined in A1
//private constructor A1(x: kotlin.Int = ..., y: kotlin.Int) defined in A1
//value-parameter val x: kotlin.Int = ... defined in A1.<init>
//value-parameter val y: kotlin.Int defined in A1.<init>
//internal object A2 defined in root package
//public constructor A2(prop: kotlin.Int) defined in A2
//value-parameter val prop: kotlin.Int defined in A2.<init>
//private constructor A2(x: kotlin.Int = ..., y: kotlin.Int) defined in A2
//value-parameter val x: kotlin.Int = ... defined in A2.<init>
//value-parameter val y: kotlin.Int defined in A2.<init>
//internal final class A3 defined in root package
//public constructor A3() defined in A3
//internal companion object defined in A3
//private constructor B(prop: kotlin.Int) defined in A3.B
//value-parameter val prop: kotlin.Int defined in A3.B.<init>
//public constructor B() defined in A3.B
+23
View File
@@ -0,0 +1,23 @@
trait A1() {
constructor(x: Int = "", y: Int) : this() {
x + y
}
}
trait A2 private constructor(private val prop: Int) {
constructor(x: Int = "", y: Int) : this(x * y) {
x + y
}
}
//internal interface A1 defined in root package
//public constructor A1() defined in A1
//public constructor A1(x: kotlin.Int = ..., y: kotlin.Int) defined in A1
//value-parameter val x: kotlin.Int = ... defined in A1.<init>
//value-parameter val y: kotlin.Int defined in A1.<init>
//internal interface A2 defined in root package
//private constructor A2(prop: kotlin.Int) defined in A2
//value-parameter val prop: kotlin.Int defined in A2.<init>
//public constructor A2(x: kotlin.Int = ..., y: kotlin.Int) defined in A2
//value-parameter val x: kotlin.Int = ... defined in A2.<init>
//value-parameter val y: kotlin.Int defined in A2.<init>
@@ -325,6 +325,12 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
doTest(fileName);
}
@TestMetadata("ObjectWithConstructor.kt")
public void testObjectWithConstructor() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/ObjectWithConstructor.kt");
doTest(fileName);
}
@TestMetadata("OverrideFunctionWithParamDefaultValue.kt")
public void testOverrideFunctionWithParamDefaultValue() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/OverrideFunctionWithParamDefaultValue.kt");
@@ -105,7 +105,7 @@ public abstract class AbstractDescriptorRendererTest : KotlinTestWithEnvironment
descriptors.add(descriptor)
if (descriptor is ClassDescriptor) {
// if class has primary constructor then we visit it later, otherwise add it artificially
if (element !is JetClass || !element.hasExplicitPrimaryConstructor()) {
if (element !is JetClassOrObject || !element.hasExplicitPrimaryConstructor()) {
if (descriptor.getUnsubstitutedPrimaryConstructor() != null) {
descriptors.add(descriptor.getUnsubstitutedPrimaryConstructor())
}
@@ -89,12 +89,24 @@ public class DescriptorRendererTestGenerated extends AbstractDescriptorRendererT
doTest(fileName);
}
@TestMetadata("ObjectWithConstructor.kt")
public void testObjectWithConstructor() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/renderer/ObjectWithConstructor.kt");
doTest(fileName);
}
@TestMetadata("StarProjection.kt")
public void testStarProjection() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/renderer/StarProjection.kt");
doTest(fileName);
}
@TestMetadata("TraitWithConstructor.kt")
public void testTraitWithConstructor() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/renderer/TraitWithConstructor.kt");
doTest(fileName);
}
@TestMetadata("UnitType.kt")
public void testUnitType() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/renderer/UnitType.kt");
@@ -507,7 +507,7 @@ public class DescriptorUtils {
return classDescriptor.getKind().isSingleton() || isAnonymousObject(classDescriptor);
}
public static boolean canHaveSecondaryConstructors(@NotNull ClassDescriptor classDescriptor) {
public static boolean canHaveDeclaredConstructors(@NotNull ClassDescriptor classDescriptor) {
return !isSingletonOrAnonymousObject(classDescriptor) && !isTrait(classDescriptor);
}
+1 -1
View File
@@ -6,5 +6,5 @@ interface Foo<error>()</error> : <warning>bar</warning><error>()</error>, <error
interface Foo2 : <warning>bar</warning>, Foo {
}
open class Foo1() : bar(), <error>bar</error>, Foo, <error>Foo</error><error>()</error> {}
open class Foo1() : bar(), <error>bar</error>, Foo, <error>Foo</error>() {}
open class Foo12 : bar(), <error>bar</error> {}