JS: allow to inherit external classes with overloaded functions in case we don't override them (see KT-13910).

This commit is contained in:
Alexey Andreev
2016-11-28 18:00:32 +03:00
parent ecb498717a
commit fff1af4ff6
7 changed files with 88 additions and 2 deletions
@@ -0,0 +1,9 @@
external open class A {
open fun f(x: Int): Unit
<!JS_NAME_CLASH!>open fun f(x: String): Unit<!>
}
class InheritClass : A() {
<!JS_NAME_CLASH!>override fun f(x: Int): Unit<!> { }
}
@@ -0,0 +1,19 @@
package
public external open class A {
public constructor A()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open fun f(/*0*/ x: kotlin.Int): kotlin.Unit
public open fun f(/*0*/ x: kotlin.String): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public final class InheritClass : A {
public constructor InheritClass()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ fun f(/*0*/ x: kotlin.Int): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun f(/*0*/ x: kotlin.String): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -476,6 +476,12 @@ public class DiagnosticsTestWithJsStdLibGenerated extends AbstractDiagnosticsTes
doTest(fileName);
}
@TestMetadata("overrideOverloadedNativeFunction.kt")
public void testOverrideOverloadedNativeFunction() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithJsStdLib/name/overrideOverloadedNativeFunction.kt");
doTest(fileName);
}
@TestMetadata("packageAndMethod.kt")
public void testPackageAndMethod() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithJsStdLib/name/packageAndMethod.kt");
@@ -73,8 +73,8 @@ class JsNameClashChecker : SimpleDeclarationChecker {
val overrideFqn = nameSuggestion.suggest(override)!!
val scope = getScope(overrideFqn.scope)
val name = overrideFqn.names.last()
val existing = scope[name]
if (existing != null && existing != overrideFqn.descriptor) {
val existing = scope[name] as? CallableMemberDescriptor
if (existing != null && existing != overrideFqn.descriptor && !isFakeOverridingNative(existing)) {
diagnosticHolder.report(ErrorsJs.JS_FAKE_NAME_CLASH.on(declaration, name, override, existing))
break
}
@@ -89,6 +89,11 @@ class JsNameClashChecker : SimpleDeclarationChecker {
}
}
private fun isFakeOverridingNative(descriptor: CallableMemberDescriptor): Boolean {
return descriptor.kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE &&
descriptor.overriddenDescriptors.all { !presentsInGeneratedCode(it) }
}
private fun getScope(descriptor: DeclarationDescriptor) = scopes.getOrPut(descriptor) {
val scope = mutableMapOf<String, DeclarationDescriptor>()
when (descriptor) {
@@ -5681,6 +5681,12 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest {
doTest(fileName);
}
@TestMetadata("overrideNativeOverloadedFunction.kt")
public void testOverrideNativeOverloadedFunction() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/native/overrideNativeOverloadedFunction.kt");
doTest(fileName);
}
@TestMetadata("passExtLambdaFromNative.kt")
public void testPassExtLambdaFromNative() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/native/passExtLambdaFromNative.kt");
@@ -0,0 +1,5 @@
function A() {
}
A.prototype.f = function(x) {
return typeof x;
};
@@ -0,0 +1,36 @@
external open class A {
open fun f(x: Int) = "number"
open fun f(x: String) = "string"
}
class B : A() {
fun g(x: Int) = "[${f(x)}]"
fun g(x: String) = "[${f(x)}]"
}
interface I {
fun f(x: Int): String
}
class C : A(), I
external interface J {
fun f(x: Int): String
}
class D : A(), J
fun box(): String {
var result = B().g(23) + B().g("foo")
if (result != "[number][string]") return "fail1: $result"
result = C().f(42)
if (result != "number") return "fail2: $result"
result = D().f("bar")
if (result != "string") return "fail3: $result"
return "OK"
}