diff --git a/.idea/workspace.xml b/.idea/workspace.xml index e35a91b9c12..585220fa7e4 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -6,14 +6,12 @@ - - - + + - - + @@ -117,47 +115,29 @@ - + - - - - - - - - - - - - - - - - - - - + - - + + - + - - + + @@ -165,10 +145,28 @@ - + + + + + + + + + + + + + + + + + + + - + @@ -214,19 +212,37 @@ - + - + - - + + - + + + + + + + + + + + + + + + + + + + @@ -235,7 +251,7 @@ - + @@ -277,28 +293,10 @@ - - - - - - - - - - - - - - - - - - - + @@ -325,7 +323,6 @@ @@ -795,11 +793,11 @@ + - @@ -1044,7 +1042,7 @@ - + @@ -1058,9 +1056,9 @@ - + - + @@ -1098,7 +1096,7 @@ @@ -1145,23 +1143,16 @@ - - - - - - - - - - - - - - - + + + + + + + + @@ -1173,6 +1164,13 @@ + + + + + + + @@ -1182,77 +1180,77 @@ - + - + + + + + + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - - - - - + diff --git a/translator/src/org/jetbrains/k2js/translate/BindingUtils.java b/translator/src/org/jetbrains/k2js/translate/BindingUtils.java index ead6477d4e1..42e183eb81b 100644 --- a/translator/src/org/jetbrains/k2js/translate/BindingUtils.java +++ b/translator/src/org/jetbrains/k2js/translate/BindingUtils.java @@ -2,6 +2,7 @@ package org.jetbrains.k2js.translate; import com.intellij.psi.PsiElement; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingContext; @@ -103,12 +104,7 @@ public final class BindingUtils { static public boolean hasAncestorClass(@NotNull BindingContext context, @NotNull JetClass classDeclaration) { List superclassDescriptors = getSuperclassDescriptors(context, classDeclaration); - for (ClassDescriptor descriptor : superclassDescriptors) { - if (descriptor.getKind() == ClassKind.CLASS) { - return true; - } - } - return false; + return (findAncestorClass(superclassDescriptors) != null); } static public boolean isStatement(@NotNull BindingContext context, @NotNull JetExpression expression) { @@ -122,4 +118,14 @@ public final class BindingUtils { return !superClassDescriptor.getName().equals("Any"); } + //TODO move unrelated utils to other class + @Nullable + public static ClassDescriptor findAncestorClass(@NotNull List superclassDescriptors) { + for (ClassDescriptor descriptor : superclassDescriptors) { + if (descriptor.getKind() == ClassKind.CLASS) { + return descriptor; + } + } + return null; + } } diff --git a/translator/src/org/jetbrains/k2js/translate/ClassTranslator.java b/translator/src/org/jetbrains/k2js/translate/ClassTranslator.java index c9e9901d099..3857087688e 100644 --- a/translator/src/org/jetbrains/k2js/translate/ClassTranslator.java +++ b/translator/src/org/jetbrains/k2js/translate/ClassTranslator.java @@ -3,7 +3,9 @@ package org.jetbrains.k2js.translate; import com.google.dart.compiler.backend.js.ast.*; import com.google.dart.compiler.util.AstUtil; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.ClassDescriptor; +import org.jetbrains.jet.lang.descriptors.ClassKind; import org.jetbrains.jet.lang.psi.JetClass; import java.util.ArrayList; @@ -37,13 +39,15 @@ public final class ClassTranslator extends AbstractTranslator { } } + @NotNull private JsStatement translateAsStatelessTrait(@NotNull JetClass classDeclaration) { JsObjectLiteral traitLiteral = translateClassDeclarations(classDeclaration); return AstUtil.convertToStatement (AstUtil.newAssignment(namespaceQualifiedClassNameReference(classDeclaration), traitLiteral)); } - private JsStatement translateAsClassWithState(JetClass jetClassDeclaration) { + @NotNull + private JsStatement translateAsClassWithState(@NotNull JetClass jetClassDeclaration) { JsInvocation jsClassDeclaration = createMethodInvocation(); addSuperclassReferences(jetClassDeclaration, jsClassDeclaration); addClassOwnDeclarations(jetClassDeclaration, jsClassDeclaration); @@ -64,7 +68,8 @@ public final class ClassTranslator extends AbstractTranslator { (namespaceQualifiedClassNameReference(classDeclaration), jsClassDeclaration)); } - private JsNameRef namespaceQualifiedClassNameReference(JetClass classDeclaration) { + @NotNull + private JsNameRef namespaceQualifiedClassNameReference(@NotNull JetClass classDeclaration) { return translationContext().getNamespaceQualifiedReference (translationContext().getNameForElement(classDeclaration)); } @@ -85,15 +90,45 @@ public final class ClassTranslator extends AbstractTranslator { @NotNull private List getSuperclassNameReferences(@NotNull JetClass classDeclaration) { List superclassReferences = new ArrayList(); - for (ClassDescriptor superClassDescriptor : - BindingUtils.getSuperclassDescriptors(translationContext().bindingContext(), classDeclaration)) { - //TODO should get a full class name here - superclassReferences.add(translationContext().getNamespaceQualifiedReference - (translationContext().getNameForDescriptor(superClassDescriptor))); - } + List superclassDescriptors = + BindingUtils.getSuperclassDescriptors(translationContext().bindingContext(), classDeclaration); + addAncestorClass(superclassReferences, superclassDescriptors); + addTraits(superclassReferences, superclassDescriptors); return superclassReferences; } + private void addTraits(@NotNull List superclassReferences, + @NotNull List superclassDescriptors) { + for (ClassDescriptor superClassDescriptor : + superclassDescriptors) { + assert (superClassDescriptor.getKind() == ClassKind.TRAIT) : "Only traits are expected here"; + superclassReferences.add(getClassReference(superClassDescriptor)); + } + } + + private void addAncestorClass(@NotNull List superclassReferences, + @NotNull List superclassDescriptors) { + //here we remove ancestor class from the list + ClassDescriptor ancestorClass = findAndRemoveAncestorClass(superclassDescriptors); + if (ancestorClass != null) { + superclassReferences.add(getClassReference(ancestorClass)); + } + } + + @NotNull + private JsNameRef getClassReference(@NotNull ClassDescriptor superClassDescriptor) { + //TODO should get a full class name here + return translationContext().getNamespaceQualifiedReference + (translationContext().getNameForDescriptor(superClassDescriptor)); + } + + @Nullable + private ClassDescriptor findAndRemoveAncestorClass(@NotNull List superclassDescriptors) { + ClassDescriptor ancestorClass = BindingUtils.findAncestorClass(superclassDescriptors); + superclassDescriptors.remove(ancestorClass); + return ancestorClass; + } + @NotNull private JsObjectLiteral translateClassDeclarations(@NotNull JetClass classDeclaration) { List propertyList = new ArrayList(); diff --git a/translator/test/org/jetbrains/k2js/test/TraitTest.java b/translator/test/org/jetbrains/k2js/test/TraitTest.java index 4fb3576c8d1..7ca25dc8305 100644 --- a/translator/test/org/jetbrains/k2js/test/TraitTest.java +++ b/translator/test/org/jetbrains/k2js/test/TraitTest.java @@ -23,4 +23,14 @@ public final class TraitTest extends AbstractClassTest { public void traitAddsFunctionsToClass() throws Exception { testFooBoxIsTrue("traitAddsFunctionsToClass.kt"); } + + @Test + public void classDerivesFromClassAndTrait() throws Exception { + testFooBoxIsTrue("classDerivesFromClassAndTrait.kt"); + } + + @Test + public void classDerivesFromTraitAndClass() throws Exception { + testFooBoxIsTrue("classDerivesFromTraitAndClass.kt"); + } } diff --git a/translator/testFiles/trait/cases/classDerivesFromClassAndTrait.kt b/translator/testFiles/trait/cases/classDerivesFromClassAndTrait.kt new file mode 100644 index 00000000000..1e02ef4f80e --- /dev/null +++ b/translator/testFiles/trait/cases/classDerivesFromClassAndTrait.kt @@ -0,0 +1,21 @@ +namespace foo + + +open class A() { + val value = "BAR" +} + +trait Test { + fun addFoo(s:String) : String { + return s + "FOO" + } +} + + +class B() : A(), Test { + fun eval() : String { + return addFoo(value); + } +} + +fun box() = B().eval() == "BARFOO" \ No newline at end of file diff --git a/translator/testFiles/trait/cases/classDerivesFromTraitAndClass.kt b/translator/testFiles/trait/cases/classDerivesFromTraitAndClass.kt new file mode 100644 index 00000000000..82a586cc491 --- /dev/null +++ b/translator/testFiles/trait/cases/classDerivesFromTraitAndClass.kt @@ -0,0 +1,21 @@ +namespace foo + + +open class A() { + val value = "BAR" +} + +trait Test { + fun addFoo(s:String) : String { + return s + "FOO" + } +} + + +class B() : Test, A() { + fun eval() : String { + return addFoo(value); + } +} + +fun box() = B().eval() == "BARFOO" \ No newline at end of file