diff --git a/.idea/workspace.xml b/.idea/workspace.xml
index 5318e951e73..e35a91b9c12 100644
--- a/.idea/workspace.xml
+++ b/.idea/workspace.xml
@@ -6,12 +6,14 @@
-
+
+
+
+
+
-
-
-
+
@@ -49,7 +51,20 @@
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
@@ -132,26 +129,17 @@
-
-
+
+
-
+
-
-
-
-
-
-
-
-
-
-
-
+
+
@@ -159,37 +147,64 @@
-
-
+
+
-
+
-
-
+
+
-
+
-
-
+
+
-
+
-
-
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -199,82 +214,82 @@
-
-
+
+
-
+
-
-
+
+
-
+
-
-
+
+
-
+
-
-
+
+
-
+
-
-
+
+
-
+
-
-
+
+
-
+
-
-
+
+
-
+
-
-
+
+
-
+
-
-
+
+
-
+
@@ -310,22 +325,22 @@
@@ -400,6 +415,50 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -571,10 +630,6 @@
-
-
-
-
@@ -634,6 +689,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -678,7 +755,6 @@
-
@@ -694,6 +770,7 @@
+
@@ -726,32 +803,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -852,6 +903,32 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -927,11 +1004,11 @@
-
-
-
-
-
+
+
+
+
+
localhost
@@ -981,9 +1058,9 @@
-
+
-
+
@@ -1021,7 +1098,7 @@
-
+
@@ -1034,8 +1111,6 @@
-
-
@@ -1056,6 +1131,11 @@
+
+
+
+
+
@@ -1065,116 +1145,114 @@
-
+
+
+
+
+
+
+
+
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
+
-
+
-
+
-
+
-
-
-
-
-
-
-
-
-
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
diff --git a/translator/src/org/jetbrains/k2js/translate/BindingUtils.java b/translator/src/org/jetbrains/k2js/translate/BindingUtils.java
index 5e936dca416..ead6477d4e1 100644
--- a/translator/src/org/jetbrains/k2js/translate/BindingUtils.java
+++ b/translator/src/org/jetbrains/k2js/translate/BindingUtils.java
@@ -101,12 +101,20 @@ public final class BindingUtils {
return superClassDescriptors;
}
- static public boolean hasAncestor(@NotNull BindingContext context, @NotNull JetClass classDeclaration) {
- return !getSuperclassDescriptors(context, classDeclaration).isEmpty();
+ 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;
}
static public boolean isStatement(@NotNull BindingContext context, @NotNull JetExpression expression) {
- return context.get(BindingContext.STATEMENT, expression);
+ Boolean isStatement = context.get(BindingContext.STATEMENT, expression);
+ assert isStatement != null : "Invalid behaviour of get(BindingContext.STATEMENT)";
+ return isStatement;
}
//TODO better implementation?
diff --git a/translator/src/org/jetbrains/k2js/translate/ClassTranslator.java b/translator/src/org/jetbrains/k2js/translate/ClassTranslator.java
index 0695a0e8577..c9e9901d099 100644
--- a/translator/src/org/jetbrains/k2js/translate/ClassTranslator.java
+++ b/translator/src/org/jetbrains/k2js/translate/ClassTranslator.java
@@ -30,13 +30,43 @@ public final class ClassTranslator extends AbstractTranslator {
@NotNull
public JsStatement translateClass(@NotNull JetClass classDeclaration) {
+ if (!classDeclaration.isTrait()) {
+ return translateAsClassWithState(classDeclaration);
+ } else {
+ return translateAsStatelessTrait(classDeclaration);
+ }
+ }
+
+ private JsStatement translateAsStatelessTrait(@NotNull JetClass classDeclaration) {
+ JsObjectLiteral traitLiteral = translateClassDeclarations(classDeclaration);
+ return AstUtil.convertToStatement
+ (AstUtil.newAssignment(namespaceQualifiedClassNameReference(classDeclaration), traitLiteral));
+ }
+
+ private JsStatement translateAsClassWithState(JetClass jetClassDeclaration) {
+ JsInvocation jsClassDeclaration = createMethodInvocation();
+ addSuperclassReferences(jetClassDeclaration, jsClassDeclaration);
+ addClassOwnDeclarations(jetClassDeclaration, jsClassDeclaration);
+ return classDeclarationStatement(jetClassDeclaration, jsClassDeclaration);
+ }
+
+ @NotNull
+ private JsInvocation createMethodInvocation() {
JsInvocation jsClassDeclaration = new JsInvocation();
jsClassDeclaration.setQualifier(Namer.creationMethodReference());
- addSuperclassReferences(classDeclaration, jsClassDeclaration);
- addClassOwnDeclarations(classDeclaration, jsClassDeclaration);
- JsName jsClassName = translationContext().getNameForElement(classDeclaration);
- return AstUtil.convertToStatement(
- AstUtil.newAssignment(translationContext().getNamespaceQualifiedReference(jsClassName), jsClassDeclaration));
+ return jsClassDeclaration;
+ }
+
+ @NotNull
+ private JsStatement classDeclarationStatement(@NotNull JetClass classDeclaration,
+ @NotNull JsInvocation jsClassDeclaration) {
+ return AstUtil.convertToStatement(AstUtil.newAssignment
+ (namespaceQualifiedClassNameReference(classDeclaration), jsClassDeclaration));
+ }
+
+ private JsNameRef namespaceQualifiedClassNameReference(JetClass classDeclaration) {
+ return translationContext().getNamespaceQualifiedReference
+ (translationContext().getNameForElement(classDeclaration));
}
private void addClassOwnDeclarations(@NotNull JetClass classDeclaration,
@@ -67,7 +97,9 @@ public final class ClassTranslator extends AbstractTranslator {
@NotNull
private JsObjectLiteral translateClassDeclarations(@NotNull JetClass classDeclaration) {
List propertyList = new ArrayList();
- propertyList.add(generateInitializeMethod(classDeclaration));
+ if (!classDeclaration.isTrait()) {
+ propertyList.add(generateInitializeMethod(classDeclaration));
+ }
propertyList.addAll(classDeclaration.accept(classBodyVisitor,
translationContext().newClass(classDeclaration)));
return new JsObjectLiteral(propertyList);
@@ -88,4 +120,5 @@ public final class ClassTranslator extends AbstractTranslator {
translationContext().newClass(classDeclaration));
return initializerVisitor.generateInitializeMethod();
}
+
}
diff --git a/translator/src/org/jetbrains/k2js/translate/ExpressionVisitor.java b/translator/src/org/jetbrains/k2js/translate/ExpressionVisitor.java
index b9e58407427..4c84e827a89 100644
--- a/translator/src/org/jetbrains/k2js/translate/ExpressionVisitor.java
+++ b/translator/src/org/jetbrains/k2js/translate/ExpressionVisitor.java
@@ -93,11 +93,11 @@ public final class ExpressionVisitor extends TranslatorVisitor {
// by name
JsName referencedName = getReferencedName(expression, context);
if (referencedName != null) {
- if (context.namespaceScope().ownsName(referencedName)) {
+ if (requiresNamespaceQualifier(context, referencedName)) {
return context.getNamespaceQualifiedReference(referencedName);
}
JsNameRef nameRef = referencedName.makeRef();
- if (expression.getReferencedNameElementType() == JetTokens.FIELD_IDENTIFIER) {
+ if (requiresThisQualifier(expression, context)) {
nameRef.setQualifier(new JsThisRef());
}
return nameRef;
@@ -110,6 +110,17 @@ public final class ExpressionVisitor extends TranslatorVisitor {
throw new AssertionError("Undefined name in this scope: " + expression.getReferencedName());
}
+ private boolean requiresNamespaceQualifier(TranslationContext context, JsName referencedName) {
+ return context.namespaceScope().ownsName(referencedName);
+ }
+
+ private boolean requiresThisQualifier(@NotNull JetSimpleNameExpression expression,
+ @NotNull TranslationContext context) {
+ boolean isClassMember = context.classScope().ownsName(getReferencedName(expression, context));
+ boolean isBackingFieldAccess = expression.getReferencedNameElementType() == JetTokens.FIELD_IDENTIFIER;
+ return isClassMember || isBackingFieldAccess;
+ }
+
@Nullable
private JsName getReferencedName(@NotNull JetSimpleNameExpression expression, @NotNull TranslationContext context) {
String referencedName = expression.getReferencedName();
diff --git a/translator/src/org/jetbrains/k2js/translate/InitializerVisitor.java b/translator/src/org/jetbrains/k2js/translate/InitializerVisitor.java
index b4c69297a3c..b244dc5cec3 100644
--- a/translator/src/org/jetbrains/k2js/translate/InitializerVisitor.java
+++ b/translator/src/org/jetbrains/k2js/translate/InitializerVisitor.java
@@ -53,7 +53,7 @@ public class InitializerVisitor extends TranslatorVisitor> {
private List generateCallToSuperMethod(@NotNull JetClass classDeclaration,
@NotNull TranslationContext context) {
List result = new ArrayList();
- if (BindingUtils.hasAncestor(context.bindingContext(), classDeclaration)) {
+ if (BindingUtils.hasAncestorClass(context.bindingContext(), classDeclaration)) {
JsName superMethodName = initializerMethodScope.declareName(Namer.SUPER_METHOD_NAME);
List arguments = translateArguments(classDeclaration, context);
result.add(AstUtil.convertToStatement
diff --git a/translator/test/org/jetbrains/k2js/test/TraitTest.java b/translator/test/org/jetbrains/k2js/test/TraitTest.java
new file mode 100644
index 00000000000..4fb3576c8d1
--- /dev/null
+++ b/translator/test/org/jetbrains/k2js/test/TraitTest.java
@@ -0,0 +1,26 @@
+package org.jetbrains.k2js.test;
+
+import org.junit.Test;
+
+/**
+ * @author Talanov Pavel
+ */
+public final class TraitTest extends AbstractClassTest {
+
+ final private static String MAIN = "trait/";
+
+ @Override
+ protected String mainDirectory() {
+ return MAIN;
+ }
+
+ @Test
+ public void traitCompiles() throws Exception {
+ testFooBoxIsTrue("traitCompiles.kt");
+ }
+
+ @Test
+ public void traitAddsFunctionsToClass() throws Exception {
+ testFooBoxIsTrue("traitAddsFunctionsToClass.kt");
+ }
+}
diff --git a/translator/testFiles/trait/cases/traitAddsFunctionsToClass.kt b/translator/testFiles/trait/cases/traitAddsFunctionsToClass.kt
new file mode 100644
index 00000000000..bba3fe75695
--- /dev/null
+++ b/translator/testFiles/trait/cases/traitAddsFunctionsToClass.kt
@@ -0,0 +1,21 @@
+namespace foo
+
+trait Test {
+ fun addFoo(s:String) : String {
+ return s + "FOO"
+ }
+
+ fun addBar(s:String) : String {
+ return s + "BAR"
+ }
+}
+
+
+class A() : Test {
+ val string = "TEST"
+ fun value() : String {
+ return addBar(addFoo(string))
+ }
+}
+
+fun box() = A().value() == "TESTFOOBAR"
\ No newline at end of file
diff --git a/translator/testFiles/trait/cases/traitCompiles.kt b/translator/testFiles/trait/cases/traitCompiles.kt
new file mode 100644
index 00000000000..93f090310d2
--- /dev/null
+++ b/translator/testFiles/trait/cases/traitCompiles.kt
@@ -0,0 +1,9 @@
+namespace foo
+
+trait Test {
+ fun addFoo(s:String) : String {
+ return s + "FOO"
+ }
+}
+
+fun box() = true
\ No newline at end of file