KT-2752: remove diagnostic that reports about overridden method having several names from different sources. Generate proxies instead. Fix reporting name clash when two distinct fake overrides require same name.

This commit is contained in:
Alexey Andreev
2016-06-15 18:07:28 +03:00
parent c5087779e4
commit 1dcb037aee
12 changed files with 120 additions and 80 deletions
+59
View File
@@ -0,0 +1,59 @@
// TARGET_BACKEND: JS
package foo
interface A {
@JsName("foo") fun foo(value: Int): String
}
interface B {
@JsName("bar") fun foo(value: Int): String
}
open class C : A, B {
override fun foo(value: Int) = "C.foo($value)"
}
class CDerived : C() {
override fun foo(value: Int) = "CDerived.foo($value)"
}
open class D {
open fun foo(value: Int) = "D.foo($value)"
}
class E : D(), A, B
fun box(): String {
val a: A = C()
assertEquals("C.foo(55)", a.foo(55))
val b: B = C()
assertEquals("C.foo(23)", b.foo(23))
val a2: A = CDerived()
assertEquals("CDerived.foo(55)", a2.foo(55))
val b2: B = CDerived()
assertEquals("CDerived.foo(23)", b2.foo(23))
val d: dynamic = C()
assertEquals("C.foo(42)", d.foo(42))
assertEquals("C.foo(99)", d.bar(99))
val d2: dynamic = CDerived()
assertEquals("CDerived.foo(42)", d2.foo(42))
assertEquals("CDerived.foo(99)", d2.bar(99))
val da: A = E()
assertEquals("D.foo(55)", da.foo(55))
val db: B = E()
assertEquals("D.foo(23)", db.foo(23))
val dd: dynamic = E()
assertEquals("D.foo(42)", dd.foo(42))
assertEquals("D.foo(99)", dd.bar(99))
assertEquals("D.foo(88)", dd.`foo_za3lpa$`(88))
return "OK"
}
+16
View File
@@ -13,6 +13,12 @@ class C : A, B {
override fun foo(value: Int) = "C.foo($value)"
}
open class D {
open fun foo(value: Int) = "D.foo($value)"
}
class E : D(), A, B
fun box(): String {
val a: A = C()
assertEquals("C.foo(55)", a.foo(55))
@@ -24,5 +30,15 @@ fun box(): String {
assertEquals("C.foo(42)", d.foo(42))
assertEquals("C.foo(99)", d.`foo_za3lpa$`(99))
val da: A = E()
assertEquals("D.foo(55)", da.foo(55))
val db: B = E()
assertEquals("D.foo(23)", db.foo(23))
val dd: dynamic = E()
assertEquals("D.foo(42)", dd.foo(42))
assertEquals("D.foo(99)", dd.`foo_za3lpa$`(99))
return "OK"
}
@@ -20,4 +20,4 @@ open class E {
open fun g() {}
}
<!JS_NAME_OVERRIDE_CLASH!>class F : E(), A, B<!>
<!JS_NAME_CLASH_SYNTHETIC!>class F : E(), A, B<!>
@@ -1,23 +0,0 @@
interface A {
@JsName("f") fun foo(value: Int)
}
interface B {
@JsName("g") fun foo(value: Int)
}
class C : A, B {
<!JS_NAME_OVERRIDE_CLASH!>override fun foo(value: Int) { }<!>
}
@native interface NA {
@JsName("f") fun foo(value: Int)
}
@native interface NB {
@JsName("g") fun foo(value: Int)
}
class NC : NA, NB {
<!JS_NAME_OVERRIDE_CLASH!>override fun foo(value: Int) { }<!>
}
@@ -1,45 +0,0 @@
package
public interface A {
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
@kotlin.js.JsName(name = "f") public abstract fun foo(/*0*/ value: kotlin.Int): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public interface B {
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
@kotlin.js.JsName(name = "g") public abstract fun foo(/*0*/ value: kotlin.Int): 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 C : A, B {
public constructor C()
public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*2*/ fun foo(/*0*/ value: kotlin.Int): kotlin.Unit
public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String
}
@kotlin.js.native() public interface NA {
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
@kotlin.js.JsName(name = "f") public abstract fun foo(/*0*/ value: kotlin.Int): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@kotlin.js.native() public interface NB {
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
@kotlin.js.JsName(name = "g") public abstract fun foo(/*0*/ value: kotlin.Int): 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 NC : NA, NB {
public constructor NC()
public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*2*/ fun foo(/*0*/ value: kotlin.Int): kotlin.Unit
public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -373,12 +373,6 @@ public class DiagnosticsTestWithJsStdLibGenerated extends AbstractDiagnosticsTes
doTest(fileName);
}
@TestMetadata("overriddenJsNameClash.kt")
public void testOverriddenJsNameClash() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithJsStdLib/name/overriddenJsNameClash.kt");
doTest(fileName);
}
@TestMetadata("packageAndMethod.kt")
public void testPackageAndMethod() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithJsStdLib/name/packageAndMethod.kt");
@@ -906,6 +906,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Bridges extends AbstractBlackBoxCodegenTest {
@TestMetadata("jsName.kt")
public void ignoredJsName() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/bridges/jsName.kt");
doTest(fileName);
}
@TestMetadata("jsNative.kt")
public void ignoredJsNative() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/bridges/jsNative.kt");
@@ -45,8 +45,6 @@ private val DIAGNOSTIC_FACTORY_TO_RENDERER by lazy {
put(ErrorsJs.JS_NAME_ON_ACCESSOR_AND_PROPERTY, "@JsName can be either on a property or its accessors, not both of them")
put(ErrorsJs.JS_NAME_IS_NOT_ON_ALL_ACCESSORS, "@JsName should be on all of the property accessors")
put(ErrorsJs.JS_NAME_PROHIBITED_FOR_OVERRIDE, "@JsName is prohibited for overridden members")
put(ErrorsJs.JS_NAME_OVERRIDE_CLASH, "Conflicting names got from overridden declarations {0} and {1}", Renderers.COMPACT,
Renderers.COMPACT)
this
}
@@ -49,7 +49,6 @@ public interface ErrorsJs {
DiagnosticFactory0<KtElement> JS_NAME_ON_ACCESSOR_AND_PROPERTY = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<PsiElement> JS_NAME_IS_NOT_ON_ALL_ACCESSORS = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<PsiElement> JS_NAME_PROHIBITED_FOR_OVERRIDE = DiagnosticFactory0.create(ERROR);
DiagnosticFactory2<PsiElement, DeclarationDescriptor, DeclarationDescriptor> JS_NAME_OVERRIDE_CLASH = DiagnosticFactory2.create(ERROR);
@SuppressWarnings("UnusedDeclaration")
Object _initializer = new Object() {
@@ -33,6 +33,7 @@ import org.jetbrains.kotlin.resolve.scopes.MemberScope
class JsNameClashChecker : SimpleDeclarationChecker {
private val fqnGenerator = FQNGenerator()
private val scopes = mutableMapOf<DeclarationDescriptor, MutableMap<String, DeclarationDescriptor>>()
private val clashedFakeOverrides = mutableMapOf<DeclarationDescriptor, Pair<DeclarationDescriptor, DeclarationDescriptor>>()
private val clashedDescriptors = mutableSetOf<DeclarationDescriptor>()
override fun check(
@@ -74,6 +75,14 @@ class JsNameClashChecker : SimpleDeclarationChecker {
val existing = scope[name]
if (existing != null && existing != overrideFqn.descriptor) {
diagnosticHolder.report(ErrorsJs.JS_NAME_CLASH_SYNTHETIC.on(declaration, name, override, existing))
break
}
val clashedOverrides = clashedFakeOverrides[override]
if (clashedOverrides != null) {
val (firstExample, secondExample) = clashedOverrides
diagnosticHolder.report(ErrorsJs.JS_NAME_CLASH_SYNTHETIC.on(declaration, name, firstExample, secondExample))
break
}
}
}
@@ -111,6 +120,28 @@ class JsNameClashChecker : SimpleDeclarationChecker {
val fqn = fqnGenerator.generate(descriptor)
if (fqn.shared && isOpaque(fqn.descriptor)) {
target[fqn.names.last()] = fqn.descriptor
(fqn.descriptor as? CallableMemberDescriptor)?.let { checkOverrideClashes(it, target) }
}
}
private fun checkOverrideClashes(descriptor: CallableMemberDescriptor, target: MutableMap<String, DeclarationDescriptor>) {
var overridden = descriptor.overriddenDescriptors
while (overridden.isNotEmpty()) {
for (overridenDescriptor in overridden) {
val overriddenFqn = fqnGenerator.generate(overridenDescriptor)
if (overriddenFqn.shared) {
val existing = target[overriddenFqn.names.last()]
if (existing != null) {
if (existing != descriptor && descriptor.kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) {
clashedFakeOverrides[descriptor] = Pair(existing, overridenDescriptor)
}
}
else {
target[overriddenFqn.names.last()] = descriptor
}
}
}
overridden = overridden.flatMap { it.overriddenDescriptors }
}
}
@@ -16,7 +16,6 @@
package org.jetbrains.kotlin.js.resolve.diagnostics
import org.jetbrains.kotlin.config.LanguageFeatureSettings
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
@@ -31,7 +30,7 @@ class OverriddenJsNameChecker : DeclarationChecker {
private val fqnGenerator = FQNGenerator()
override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, diagnosticHolder: DiagnosticSink,
bindingContext: BindingContext, languageFeatureSettings: LanguageFeatureSettings) {
bindingContext: BindingContext) {
doCheck(descriptor) { first, second ->
val psi = descriptor.findPsi() ?: declaration
diagnosticHolder.report(ErrorsJs.JS_NAME_OVERRIDE_CLASH.on(psi, first, second))
@@ -125,6 +125,12 @@ public class BridgeTestGenerated extends AbstractBridgeTest {
doTest(fileName);
}
@TestMetadata("jsName.kt")
public void testJsName() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/bridges/jsName.kt");
doTest(fileName);
}
@TestMetadata("kt12416.kt")
public void testKt12416() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/bridges/kt12416.kt");