JS: allow to omit delegated constructor call for external classes in common FE. Prohibit delegated constructor call for external classes in JS FE.

This commit is contained in:
Alexey Andreev
2016-12-20 15:01:33 +03:00
parent 02ea1a4d64
commit 1a7e8b0690
18 changed files with 160 additions and 29 deletions
@@ -169,8 +169,8 @@ public class BodyResolver {
@NotNull KtSecondaryConstructor constructor, @NotNull KtSecondaryConstructor constructor,
@NotNull ClassConstructorDescriptor descriptor @NotNull ClassConstructorDescriptor descriptor
) { ) {
if (descriptor.isHeader()) { if (descriptor.isHeader() || DescriptorUtils.isEffectivelyExternal(descriptor)) {
// For header classes, we do not resolve constructor delegation calls because they are prohibited // For header and external classes, we do not resolve constructor delegation calls because they are prohibited
return DataFlowInfo.Companion.getEMPTY(); return DataFlowInfo.Companion.getEMPTY();
} }
@@ -367,7 +367,7 @@ public class BodyResolver {
descriptor.getUnsubstitutedPrimaryConstructor() != null && descriptor.getUnsubstitutedPrimaryConstructor() != null &&
superClass.getKind() != ClassKind.INTERFACE && superClass.getKind() != ClassKind.INTERFACE &&
!superClass.getConstructors().isEmpty() && !superClass.getConstructors().isEmpty() &&
!descriptor.isHeader() && !descriptor.isHeader() && !DescriptorUtils.isEffectivelyExternal(descriptor) &&
!ErrorUtils.isError(superClass) !ErrorUtils.isError(superClass)
) { ) {
trace.report(SUPERTYPE_NOT_INITIALIZED.on(specifier)); trace.report(SUPERTYPE_NOT_INITIALIZED.on(specifier));
@@ -39,4 +39,5 @@ fun box() {
<!CALL_TO_JS_MODULE_WITHOUT_MODULE_SYSTEM!>baz<!>() <!CALL_TO_JS_MODULE_WITHOUT_MODULE_SYSTEM!>baz<!>()
} }
external class DerivedB : <!CALL_TO_JS_MODULE_WITHOUT_MODULE_SYSTEM!>B<!>() // TODO: fix and uncomment
// external class DerivedB : <! CALL_TO_JS_MODULE_WITHOUT_MODULE_SYSTEM!>B< !>
@@ -28,14 +28,6 @@ package
package bar { package bar {
public fun box(): kotlin.Unit public fun box(): kotlin.Unit
public external final class DerivedB : foo.B {
public constructor DerivedB()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public final override /*1*/ /*fake_override*/ fun foo(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
} }
package foo { package foo {
@@ -33,4 +33,5 @@ fun box() {
<!CALL_TO_JS_NON_MODULE_WITH_MODULE_SYSTEM!>bar<!>() <!CALL_TO_JS_NON_MODULE_WITH_MODULE_SYSTEM!>bar<!>()
} }
external class DerivedB : <!CALL_TO_JS_NON_MODULE_WITH_MODULE_SYSTEM!>B<!>() // TODO: fix and uncomment
// external class DerivedB : <! CALL_TO_JS_NON_MODULE_WITH_MODULE_SYSTEM!>B< !>
@@ -2,14 +2,6 @@ package
package bar { package bar {
public fun box(): kotlin.Unit public fun box(): kotlin.Unit
public external final class DerivedB : foo.B {
public constructor DerivedB()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public final override /*1*/ /*fake_override*/ fun foo(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
} }
package foo { package foo {
@@ -0,0 +1,18 @@
// !DIAGNOSTICS: -DEBUG_INFO_MISSING_UNRESOLVED
external open class Base(x: Int) {
constructor(x: String) : <!EXTERNAL_DELEGATED_CONSTRUCTOR_CALL!>this<!>(23)
constructor(x: String, y: String) : <!EXTERNAL_DELEGATED_CONSTRUCTOR_CALL!>this<!>("")
}
external open class Derived1() : Base<!EXTERNAL_DELEGATED_CONSTRUCTOR_CALL!>(23)<!> {
constructor(x: Byte) : <!EXTERNAL_DELEGATED_CONSTRUCTOR_CALL!>super<!>(23)
constructor(x: String) : <!EXTERNAL_DELEGATED_CONSTRUCTOR_CALL!>super<!>("")
constructor(x: String, y: String) : <!EXTERNAL_DELEGATED_CONSTRUCTOR_CALL!>super<!>("")
}
external open class Derived2() : Base<!EXTERNAL_DELEGATED_CONSTRUCTOR_CALL!>("")<!>
@@ -0,0 +1,27 @@
package
public external open class Base {
public constructor Base(/*0*/ x: kotlin.Int)
public constructor Base(/*0*/ x: kotlin.String)
public constructor Base(/*0*/ x: kotlin.String, /*1*/ y: kotlin.String)
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
}
public external open class Derived1 : Base {
public constructor Derived1()
public constructor Derived1(/*0*/ x: kotlin.Byte)
public constructor Derived1(/*0*/ x: kotlin.String)
public constructor Derived1(/*0*/ x: kotlin.String, /*1*/ y: kotlin.String)
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
}
public external open class Derived2 : Base {
public constructor Derived2()
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
}
@@ -0,0 +1,18 @@
external interface I
external object O : I
class Delegate {
operator fun getValue(thisRef: Any?, property: Any): String = ""
operator fun setValue(thisRef: Any?, property: Any, value: String) {}
}
external class A : <!EXTERNAL_DELEGATION!>I by O<!> {
val prop <!EXTERNAL_DELEGATION!>by Delegate()<!>
var mutableProp <!EXTERNAL_DELEGATION!>by Delegate()<!>
}
external val topLevelProp <!EXTERNAL_DELEGATION!>by Delegate()<!>
@@ -0,0 +1,34 @@
package
public external val topLevelProp: kotlin.String
public external final class A : I {
public constructor A()
public final var mutableProp: kotlin.String
public final val prop: kotlin.String
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
}
public final class Delegate {
public constructor Delegate()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public final operator fun getValue(/*0*/ thisRef: kotlin.Any?, /*1*/ property: kotlin.Any): kotlin.String
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public final operator fun setValue(/*0*/ thisRef: kotlin.Any?, /*1*/ property: kotlin.Any, /*2*/ value: kotlin.String): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public external interface I {
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
}
public external object O : I {
private constructor O()
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,9 +6,9 @@ interface I
external open class B external open class B
external class <!EXTERNAL_TYPE_EXTENDS_NON_EXTERNAL_TYPE!>C<!> : A() external class <!EXTERNAL_TYPE_EXTENDS_NON_EXTERNAL_TYPE!>C<!> : A
external class <!EXTERNAL_TYPE_EXTENDS_NON_EXTERNAL_TYPE!>D<!> : B(), I external class <!EXTERNAL_TYPE_EXTENDS_NON_EXTERNAL_TYPE!>D<!> : B, I
@native class <!EXTERNAL_TYPE_EXTENDS_NON_EXTERNAL_TYPE!>N<!> : A() @native class <!EXTERNAL_TYPE_EXTENDS_NON_EXTERNAL_TYPE!>N<!> : A()
@@ -6,7 +6,7 @@ class B : A() {
<!OVERRIDING_EXTERNAL_FUN_WITH_OPTIONAL_PARAMS!>override fun f(x: Int)<!> {} <!OVERRIDING_EXTERNAL_FUN_WITH_OPTIONAL_PARAMS!>override fun f(x: Int)<!> {}
} }
external class C : A() { external class C : A {
override fun f(x: Int) override fun f(x: Int)
} }
@@ -31,7 +31,7 @@ class F : D(), I {
<!OVERRIDING_EXTERNAL_FUN_WITH_OPTIONAL_PARAMS!>override fun f(x: Int)<!> {} <!OVERRIDING_EXTERNAL_FUN_WITH_OPTIONAL_PARAMS!>override fun f(x: Int)<!> {}
} }
external class G : D(), I { external class G : D, I {
override fun f(x: Int) override fun f(x: Int)
} }
@@ -45,6 +45,6 @@ open external class XE {
class <!OVERRIDING_EXTERNAL_FUN_WITH_OPTIONAL_PARAMS_WITH_FAKE!>Y<!> : X(), I class <!OVERRIDING_EXTERNAL_FUN_WITH_OPTIONAL_PARAMS_WITH_FAKE!>Y<!> : X(), I
external class YE: XE(), I external class YE: XE, I
class Z : X(), J class Z : X(), J
@@ -575,6 +575,18 @@ public class DiagnosticsTestWithJsStdLibGenerated extends AbstractDiagnosticsTes
doTest(fileName); doTest(fileName);
} }
@TestMetadata("delegatedConstructorCall.kt")
public void testDelegatedConstructorCall() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithJsStdLib/native/delegatedConstructorCall.kt");
doTest(fileName);
}
@TestMetadata("delegation.kt")
public void testDelegation() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithJsStdLib/native/delegation.kt");
doTest(fileName);
}
@TestMetadata("extensionFunctionAndProperty.kt") @TestMetadata("extensionFunctionAndProperty.kt")
public void testExtensionFunctionAndProperty() throws Exception { public void testExtensionFunctionAndProperty() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithJsStdLib/native/extensionFunctionAndProperty.kt"); String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithJsStdLib/native/extensionFunctionAndProperty.kt");
@@ -75,10 +75,13 @@ private val DIAGNOSTIC_FACTORY_TO_RENDERER by lazy {
put(ErrorsJs.INLINE_EXTERNAL_DECLARATION, "Inline external declaration") put(ErrorsJs.INLINE_EXTERNAL_DECLARATION, "Inline external declaration")
put(ErrorsJs.NON_ABSTRACT_MEMBER_OF_EXTERNAL_INTERFACE, put(ErrorsJs.NON_ABSTRACT_MEMBER_OF_EXTERNAL_INTERFACE,
"Only nullable properties of external interfaces are allowed to be non-abstract") "Only nullable properties of external interfaces are allowed to be non-abstract")
put(ErrorsJs.WRONG_BODY_OF_EXTERNAL_DECLARATION, "Wrong body of external declaration. Must be either ' = noImpl' or { noImpl }") put(ErrorsJs.WRONG_BODY_OF_EXTERNAL_DECLARATION, "Wrong body of external declaration. Must be either ' = noImpl' or { noImpl }")
put(ErrorsJs.WRONG_INITIALIZER_OF_EXTERNAL_DECLARATION, "Wrong initializer of external declaration. Must be ' = noImpl'") put(ErrorsJs.WRONG_INITIALIZER_OF_EXTERNAL_DECLARATION, "Wrong initializer of external declaration. Must be ' = noImpl'")
put(ErrorsJs.WRONG_DEFAULT_VALUE_FOR_EXTERNAL_FUN_PARAMETER, put(ErrorsJs.WRONG_DEFAULT_VALUE_FOR_EXTERNAL_FUN_PARAMETER,
"Wrong default value for parameter of external function. Must be ' = noImpl'") "Wrong default value for parameter of external function. Must be ' = noImpl'")
put(ErrorsJs.EXTERNAL_DELEGATED_CONSTRUCTOR_CALL, "Delegated constructor call in external class")
put(ErrorsJs.EXTERNAL_DELEGATION, "Using delegate on external declaration")
this this
} }
@@ -80,9 +80,13 @@ public interface ErrorsJs {
ERROR, PositioningStrategies.DECLARATION_SIGNATURE_OR_DEFAULT); ERROR, PositioningStrategies.DECLARATION_SIGNATURE_OR_DEFAULT);
DiagnosticFactory0<KtExpression> NON_ABSTRACT_MEMBER_OF_EXTERNAL_INTERFACE = DiagnosticFactory0.create( DiagnosticFactory0<KtExpression> NON_ABSTRACT_MEMBER_OF_EXTERNAL_INTERFACE = DiagnosticFactory0.create(
ERROR, PositioningStrategies.DECLARATION_SIGNATURE_OR_DEFAULT); ERROR, PositioningStrategies.DECLARATION_SIGNATURE_OR_DEFAULT);
// Diagnostics about exposing implementation detail in external declarations
DiagnosticFactory0<KtExpression> WRONG_BODY_OF_EXTERNAL_DECLARATION = DiagnosticFactory0.create(ERROR); DiagnosticFactory0<KtExpression> WRONG_BODY_OF_EXTERNAL_DECLARATION = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<KtExpression> WRONG_INITIALIZER_OF_EXTERNAL_DECLARATION = DiagnosticFactory0.create(ERROR); DiagnosticFactory0<KtExpression> WRONG_INITIALIZER_OF_EXTERNAL_DECLARATION = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<KtExpression> WRONG_DEFAULT_VALUE_FOR_EXTERNAL_FUN_PARAMETER = DiagnosticFactory0.create(ERROR); DiagnosticFactory0<KtExpression> WRONG_DEFAULT_VALUE_FOR_EXTERNAL_FUN_PARAMETER = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<KtElement> EXTERNAL_DELEGATED_CONSTRUCTOR_CALL = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<KtElement> EXTERNAL_DELEGATION = DiagnosticFactory0.create(ERROR);
@SuppressWarnings("UnusedDeclaration") @SuppressWarnings("UnusedDeclaration")
Object _initializer = new Object() { Object _initializer = new Object() {
@@ -91,6 +91,7 @@ object JsExternalChecker : SimpleDeclarationChecker {
} }
checkBody(declaration, descriptor, diagnosticHolder, bindingContext) checkBody(declaration, descriptor, diagnosticHolder, bindingContext)
checkDelegation(declaration, descriptor, diagnosticHolder)
} }
private fun checkBody( private fun checkBody(
@@ -114,6 +115,34 @@ object JsExternalChecker : SimpleDeclarationChecker {
} }
} }
private fun checkDelegation(declaration: KtDeclaration, descriptor: DeclarationDescriptor, diagnosticHolder: DiagnosticSink) {
if (descriptor !is MemberDescriptor || !DescriptorUtils.isEffectivelyExternal(descriptor)) return
if (declaration is KtClassOrObject) {
for (superTypeEntry in declaration.superTypeListEntries) {
when (superTypeEntry) {
is KtSuperTypeCallEntry -> {
diagnosticHolder.report(ErrorsJs.EXTERNAL_DELEGATED_CONSTRUCTOR_CALL.on(superTypeEntry.valueArgumentList!!))
}
is KtDelegatedSuperTypeEntry -> {
diagnosticHolder.report(ErrorsJs.EXTERNAL_DELEGATION.on(superTypeEntry))
}
}
}
}
else if (declaration is KtSecondaryConstructor) {
val delegationCall = declaration.getDelegationCall()
if (!delegationCall.isImplicit) {
diagnosticHolder.report(ErrorsJs.EXTERNAL_DELEGATED_CONSTRUCTOR_CALL.on(delegationCall))
}
}
else if (declaration is KtProperty && descriptor !is PropertyAccessorDescriptor) {
declaration.delegate?.let { delegate ->
diagnosticHolder.report(ErrorsJs.EXTERNAL_DELEGATION.on(delegate))
}
}
}
private fun isDirectlyExternal(declaration: KtDeclaration, descriptor: DeclarationDescriptor): Boolean { private fun isDirectlyExternal(declaration: KtDeclaration, descriptor: DeclarationDescriptor): Boolean {
if (declaration is KtProperty && descriptor is PropertyAccessorDescriptor) return false if (declaration is KtProperty && descriptor is PropertyAccessorDescriptor) return false
+1 -1
View File
@@ -49,7 +49,7 @@ open public external class MouseEvent() {
public fun isDefaultPrevented(): Boolean public fun isDefaultPrevented(): Boolean
} }
public external class MouseClickEvent() : MouseEvent() { public external class MouseClickEvent() : MouseEvent {
public val which: Int public val which: Int
} }
@@ -7,7 +7,7 @@ class A(val x: Int) {
} }
external class B(x: Int) { external class B(x: Int) {
constructor(a: Int, b: Int) : this(0) { noImpl } constructor(a: Int, b: Int)
val x: Int val x: Int
} }
@@ -6,7 +6,7 @@ external open class A {
fun foo(): String fun foo(): String
} }
external open class B : A() { external open class B : A {
fun bar(): String fun bar(): String
} }