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 ClassConstructorDescriptor descriptor
) {
if (descriptor.isHeader()) {
// For header classes, we do not resolve constructor delegation calls because they are prohibited
if (descriptor.isHeader() || DescriptorUtils.isEffectivelyExternal(descriptor)) {
// For header and external classes, we do not resolve constructor delegation calls because they are prohibited
return DataFlowInfo.Companion.getEMPTY();
}
@@ -367,7 +367,7 @@ public class BodyResolver {
descriptor.getUnsubstitutedPrimaryConstructor() != null &&
superClass.getKind() != ClassKind.INTERFACE &&
!superClass.getConstructors().isEmpty() &&
!descriptor.isHeader() &&
!descriptor.isHeader() && !DescriptorUtils.isEffectivelyExternal(descriptor) &&
!ErrorUtils.isError(superClass)
) {
trace.report(SUPERTYPE_NOT_INITIALIZED.on(specifier));
@@ -39,4 +39,5 @@ fun box() {
<!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 {
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 {
@@ -33,4 +33,5 @@ fun box() {
<!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 {
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 {
@@ -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 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()
@@ -6,7 +6,7 @@ class B : A() {
<!OVERRIDING_EXTERNAL_FUN_WITH_OPTIONAL_PARAMS!>override fun f(x: Int)<!> {}
}
external class C : A() {
external class C : A {
override fun f(x: Int)
}
@@ -31,7 +31,7 @@ class F : D(), I {
<!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)
}
@@ -45,6 +45,6 @@ open external class XE {
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
@@ -575,6 +575,18 @@ public class DiagnosticsTestWithJsStdLibGenerated extends AbstractDiagnosticsTes
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")
public void testExtensionFunctionAndProperty() throws Exception {
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.NON_ABSTRACT_MEMBER_OF_EXTERNAL_INTERFACE,
"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_INITIALIZER_OF_EXTERNAL_DECLARATION, "Wrong initializer of external declaration. Must be ' = noImpl'")
put(ErrorsJs.WRONG_DEFAULT_VALUE_FOR_EXTERNAL_FUN_PARAMETER,
"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
}
@@ -80,9 +80,13 @@ public interface ErrorsJs {
ERROR, PositioningStrategies.DECLARATION_SIGNATURE_OR_DEFAULT);
DiagnosticFactory0<KtExpression> NON_ABSTRACT_MEMBER_OF_EXTERNAL_INTERFACE = DiagnosticFactory0.create(
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_INITIALIZER_OF_EXTERNAL_DECLARATION = 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")
Object _initializer = new Object() {
@@ -91,6 +91,7 @@ object JsExternalChecker : SimpleDeclarationChecker {
}
checkBody(declaration, descriptor, diagnosticHolder, bindingContext)
checkDelegation(declaration, descriptor, diagnosticHolder)
}
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 {
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 external class MouseClickEvent() : MouseEvent() {
public external class MouseClickEvent() : MouseEvent {
public val which: Int
}
@@ -7,7 +7,7 @@ class A(val x: Int) {
}
external class B(x: Int) {
constructor(a: Int, b: Int) : this(0) { noImpl }
constructor(a: Int, b: Int)
val x: Int
}
@@ -6,7 +6,7 @@ external open class A {
fun foo(): String
}
external open class B : A() {
external open class B : A {
fun bar(): String
}