diff --git a/js/js.tests/test/org/jetbrains/k2js/test/semantics/ClassInheritanceTest.java b/js/js.tests/test/org/jetbrains/k2js/test/semantics/ClassInheritanceTest.java index dca0fb3f4ae..ae3027c2e1a 100644 --- a/js/js.tests/test/org/jetbrains/k2js/test/semantics/ClassInheritanceTest.java +++ b/js/js.tests/test/org/jetbrains/k2js/test/semantics/ClassInheritanceTest.java @@ -75,6 +75,9 @@ public final class ClassInheritanceTest extends SingleFileTranslationTest { public void testKt3499() throws Exception { fooBoxTest(); } + public void testFromFakeClasses() throws Exception { + checkFooBoxIsOk(); + } } diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/declaration/ClassTranslator.java b/js/js.translator/src/org/jetbrains/k2js/translate/declaration/ClassTranslator.java index 16bdda0e3af..a52f33c5a45 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/declaration/ClassTranslator.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/declaration/ClassTranslator.java @@ -44,6 +44,7 @@ import static org.jetbrains.k2js.translate.initializer.InitializerUtils.createCl import static org.jetbrains.k2js.translate.utils.BindingUtils.getClassDescriptor; import static org.jetbrains.k2js.translate.utils.BindingUtils.getPropertyDescriptorForConstructorParameter; import static org.jetbrains.k2js.translate.utils.JsDescriptorUtils.getContainingClass; +import static org.jetbrains.k2js.translate.utils.JsDescriptorUtils.getSupertypesWithoutFakes; import static org.jetbrains.k2js.translate.utils.PsiUtils.getPrimaryConstructorParameters; import static org.jetbrains.k2js.translate.utils.TranslationUtils.simpleReturnFunction; @@ -220,16 +221,13 @@ public final class ClassTranslator extends AbstractTranslator { @NotNull private List getSupertypesNameReferences() { - Collection supertypes = descriptor.getTypeConstructor().getSupertypes(); + List supertypes = getSupertypesWithoutFakes(descriptor); if (supertypes.isEmpty()) { return Collections.emptyList(); } if (supertypes.size() == 1) { - JetType type = supertypes.iterator().next(); + JetType type = supertypes.get(0); ClassDescriptor supertypeDescriptor = getClassDescriptorForType(type); - if (isAny(supertypeDescriptor)) { - return Collections.emptyList(); - } return Collections.singletonList(getClassReference(supertypeDescriptor)); } @@ -244,9 +242,7 @@ public final class ClassTranslator extends AbstractTranslator { for (TypeConstructor typeConstructor : sortedAllSuperTypes) { if (supertypeConstructors.contains(typeConstructor)) { ClassDescriptor supertypeDescriptor = getClassDescriptorForTypeConstructor(typeConstructor); - if (!isAny(supertypeDescriptor)) { - supertypesRefs.add(getClassReference(supertypeDescriptor)); - } + supertypesRefs.add(getClassReference(supertypeDescriptor)); } } return supertypesRefs; diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/declaration/DeclarationBodyVisitor.java b/js/js.translator/src/org/jetbrains/k2js/translate/declaration/DeclarationBodyVisitor.java index 96f261794b4..759378f5ddb 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/declaration/DeclarationBodyVisitor.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/declaration/DeclarationBodyVisitor.java @@ -35,12 +35,12 @@ import org.jetbrains.k2js.translate.initializer.ClassInitializerTranslator; import org.jetbrains.k2js.translate.utils.BindingUtils; import org.jetbrains.k2js.translate.utils.TranslationUtils; -import java.util.Collection; import java.util.List; import static org.jetbrains.k2js.translate.initializer.InitializerUtils.createClassObjectInitializer; import static org.jetbrains.k2js.translate.utils.BindingUtils.getClassDescriptor; import static org.jetbrains.k2js.translate.utils.BindingUtils.getFunctionDescriptor; +import static org.jetbrains.k2js.translate.utils.JsDescriptorUtils.getSupertypesWithoutFakes; public class DeclarationBodyVisitor extends TranslatorVisitor { @KotlinSignature("val result: MutableList") @@ -75,12 +75,12 @@ public class DeclarationBodyVisitor extends TranslatorVisitor { public Void visitEnumEntry(@NotNull JetEnumEntry enumEntry, TranslationContext data) { JsExpression jsEnumEntryCreation; ClassDescriptor descriptor = getClassDescriptor(data.bindingContext(), enumEntry); - Collection supertypes = descriptor.getTypeConstructor().getSupertypes(); + List supertypes = getSupertypesWithoutFakes(descriptor); if (enumEntry.getBody() != null || supertypes.size() > 1) { jsEnumEntryCreation = ClassTranslator.generateClassCreation(enumEntry, descriptor, data); } else { assert supertypes.size() == 1 : "Simple Enum entry must have one supertype"; - jsEnumEntryCreation = new ClassInitializerTranslator(enumEntry, data).generateEnumEntryInstanceCreation(supertypes.iterator().next()); + jsEnumEntryCreation = new ClassInitializerTranslator(enumEntry, data).generateEnumEntryInstanceCreation(supertypes.get(0)); } enumEntryList.add(new JsPropertyInitializer(data.getNameForDescriptor(descriptor).makeRef(), jsEnumEntryCreation)); return null; diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/utils/JsDescriptorUtils.java b/js/js.translator/src/org/jetbrains/k2js/translate/utils/JsDescriptorUtils.java index 9cb6da19221..f3fd0708c3b 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/utils/JsDescriptorUtils.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/utils/JsDescriptorUtils.java @@ -16,6 +16,8 @@ package org.jetbrains.k2js.translate.utils; +import com.intellij.openapi.util.Condition; +import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.*; @@ -29,13 +31,19 @@ import org.jetbrains.jet.lang.types.expressions.OperatorConventions; import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; import org.jetbrains.k2js.translate.context.TranslationContext; +import java.util.Collection; import java.util.List; import java.util.Set; -import static org.jetbrains.jet.lang.resolve.DescriptorUtils.getSuperclassDescriptors; -import static org.jetbrains.jet.lang.resolve.DescriptorUtils.isClassObject; +import static org.jetbrains.jet.lang.resolve.DescriptorUtils.*; +import static org.jetbrains.jet.lang.resolve.DescriptorUtils.getFQName; public final class JsDescriptorUtils { + // TODO: maybe we should use external annotations or something else. + private static final Set FAKE_CLASSES = ContainerUtil.immutableSet( + getFQName(KotlinBuiltIns.getInstance().getAny()).toSafe().asString(), + "jet.Iterable" + ); private JsDescriptorUtils() { } @@ -67,6 +75,18 @@ public final class JsDescriptorUtils { return findAncestorClass(getSuperclassDescriptors(classDescriptor)); } + @NotNull + public static List getSupertypesWithoutFakes(ClassDescriptor descriptor) { + Collection supertypes = descriptor.getTypeConstructor().getSupertypes(); + return ContainerUtil.filter(supertypes, new Condition() { + @Override + public boolean value(JetType type) { + ClassDescriptor classDescriptor = getClassDescriptorForType(type); + return !FAKE_CLASSES.contains(getFQName(classDescriptor).toSafe().asString()); + } + }); + } + @NotNull public static DeclarationDescriptor getContainingDeclaration(@NotNull DeclarationDescriptor descriptor) { DeclarationDescriptor containing = descriptor.getContainingDeclaration(); diff --git a/js/js.translator/testFiles/inheritance/cases/fromFakeClasses.kt b/js/js.translator/testFiles/inheritance/cases/fromFakeClasses.kt new file mode 100644 index 00000000000..6fe87617178 --- /dev/null +++ b/js/js.translator/testFiles/inheritance/cases/fromFakeClasses.kt @@ -0,0 +1,43 @@ +package foo + +class FromAny: Any() + +class FromItrable(val n: Int): Iterable { + override fun iterator() = object: Iterator { + var i = 0 + override fun next() = i++ + override fun hasNext() = i < n + } +} + +fun Iterable.stringify(): String { + var s = "" + for (i in this) s += i + return s +} + +fun box(): String { + val a = FromAny() + val it = FromItrable(3) + + val s = it.stringify() + if (s != "012") return "s /*$s*/ != 012" + + var ao = object : Any() {} + var ito = object : Iterable { + override public fun iterator() = object: Iterator { + var i = 0 + override fun next(): Int { + var r = i + i += 2 + return r + } + override fun hasNext() = i < 9 + } + } + + val so = ito.stringify() + if (so != "02468") return "so /*$so*/ != 02468" + + return "OK" +} \ No newline at end of file