From 8fd38e261f2cf99b9cb910a9f9c3075e4bc25fa2 Mon Sep 17 00:00:00 2001 From: Zalim Bashorov Date: Mon, 17 Mar 2014 21:00:23 +0400 Subject: [PATCH] JS backend: fix access to enum entries by implicit receiver and explicit `this`. --- .../k2js/test/semantics/EnumTest.java | 3 ++ .../expression/ExpressionVisitor.java | 2 +- .../QualifiedExpressionTranslator.java | 7 +--- .../reference/ReferenceTranslator.java | 33 +++++++++++++-- .../testData/enum/cases/accessing.kt | 41 +++++++++++++++++++ 5 files changed, 75 insertions(+), 11 deletions(-) create mode 100644 js/js.translator/testData/enum/cases/accessing.kt diff --git a/js/js.tests/test/org/jetbrains/k2js/test/semantics/EnumTest.java b/js/js.tests/test/org/jetbrains/k2js/test/semantics/EnumTest.java index 305918762c9..88ed3d92d22 100644 --- a/js/js.tests/test/org/jetbrains/k2js/test/semantics/EnumTest.java +++ b/js/js.tests/test/org/jetbrains/k2js/test/semantics/EnumTest.java @@ -35,4 +35,7 @@ public class EnumTest extends SingleFileTranslationTest { checkFooBoxIsOk(); } + public void testAccessing() throws Exception { + checkFooBoxIsOk(); + } } diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/expression/ExpressionVisitor.java b/js/js.translator/src/org/jetbrains/k2js/translate/expression/ExpressionVisitor.java index a1afebc969e..672eb3035a0 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/expression/ExpressionVisitor.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/expression/ExpressionVisitor.java @@ -219,7 +219,7 @@ public final class ExpressionVisitor extends TranslatorVisitor { @NotNull public JsExpression visitSimpleNameExpression(@NotNull JetSimpleNameExpression expression, @NotNull TranslationContext context) { - return ReferenceTranslator.translateSimpleName(expression, context).source(expression); + return ReferenceTranslator.translateSimpleNameWithQualifier(expression, null, context).source(expression); } @NotNull diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/reference/QualifiedExpressionTranslator.java b/js/js.translator/src/org/jetbrains/k2js/translate/reference/QualifiedExpressionTranslator.java index 906d55d3417..59ecbce3d5e 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/reference/QualifiedExpressionTranslator.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/reference/QualifiedExpressionTranslator.java @@ -27,7 +27,6 @@ import org.jetbrains.k2js.translate.utils.ErrorReportingUtils; import static org.jetbrains.k2js.translate.general.Translation.translateAsExpression; import static org.jetbrains.k2js.translate.utils.BindingUtils.getDescriptorForReferenceExpression; -import static org.jetbrains.k2js.translate.utils.JsAstUtils.setQualifier; import static org.jetbrains.k2js.translate.utils.PsiUtils.getNotNullSimpleNameSelector; import static org.jetbrains.k2js.translate.utils.PsiUtils.getSelector; @@ -66,11 +65,7 @@ public final class QualifiedExpressionTranslator { } //TODO: never get there if (selector instanceof JetSimpleNameExpression) { - JsExpression simpleName = ReferenceTranslator.translateSimpleName((JetSimpleNameExpression) selector, context); - if (receiver != null) { // TODO: hack for nested Object - setQualifier(simpleName, receiver); - } - return simpleName; + return ReferenceTranslator.translateSimpleNameWithQualifier((JetSimpleNameExpression) selector, receiver, context); } throw new AssertionError("Unexpected qualified expression: " + selector.getText()); } diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/reference/ReferenceTranslator.java b/js/js.translator/src/org/jetbrains/k2js/translate/reference/ReferenceTranslator.java index 43dbabac7cc..b7a8ab9b544 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/reference/ReferenceTranslator.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/reference/ReferenceTranslator.java @@ -19,17 +19,17 @@ package org.jetbrains.k2js.translate.reference; import com.google.dart.compiler.backend.js.ast.JsExpression; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; -import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; -import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor; -import org.jetbrains.jet.lang.descriptors.VariableDescriptor; +import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.psi.JetExpression; import org.jetbrains.jet.lang.psi.JetQualifiedExpression; import org.jetbrains.jet.lang.psi.JetSimpleNameExpression; +import org.jetbrains.k2js.translate.context.Namer; import org.jetbrains.k2js.translate.context.TranslationContext; +import org.jetbrains.k2js.translate.utils.BindingUtils; import static org.jetbrains.jet.lang.psi.JetPsiUtil.isBackingFieldReference; import static org.jetbrains.k2js.translate.utils.BindingUtils.getDescriptorForReferenceExpression; +import static org.jetbrains.k2js.translate.utils.JsAstUtils.setQualifier; import static org.jetbrains.k2js.translate.utils.PsiUtils.getSelectorAsSimpleName; public final class ReferenceTranslator { @@ -43,6 +43,31 @@ public final class ReferenceTranslator { return getAccessTranslator(expression, context).translateAsGet(); } + @NotNull + public static JsExpression translateSimpleNameWithQualifier( + @NotNull JetSimpleNameExpression expression, + @Nullable JsExpression qualifier, + @NotNull TranslationContext context + ) { + JsExpression simpleName = translateSimpleName(expression, context); + + // Ignore qualifier if expression is EnumEntry and use always use FQ name. + DeclarationDescriptor descriptor = BindingUtils.getDescriptorForReferenceExpression(context.bindingContext(), expression); + if (descriptor instanceof ClassDescriptor) { + ClassDescriptor entryClass = (ClassDescriptor) descriptor; + if (entryClass.getKind() == ClassKind.ENUM_ENTRY) { + DeclarationDescriptor enumClass = entryClass.getContainingDeclaration(); + qualifier = Namer.getClassObjectAccessor(translateAsFQReference(enumClass, context)); + } + } + + if (qualifier != null) { // TODO: hack for nested Object + setQualifier(simpleName, qualifier); + } + + return simpleName; + } + @NotNull public static JsExpression translateAsFQReference(@NotNull DeclarationDescriptor referencedDescriptor, @NotNull TranslationContext context) { diff --git a/js/js.translator/testData/enum/cases/accessing.kt b/js/js.translator/testData/enum/cases/accessing.kt new file mode 100644 index 00000000000..e29d589ca69 --- /dev/null +++ b/js/js.translator/testData/enum/cases/accessing.kt @@ -0,0 +1,41 @@ +package foo + +enum class A { + FOO + + BAR : A() { + fun explicitFromEntry() = A.FOO + //fun byThisFromEntry() = this.FOO + fun implicitFromEntry() = FOO + } + + fun explicit() = A.FOO + fun byThis() = this.FOO + fun implicit() = FOO +} + +fun A.extExplicit() = A.FOO +fun A.extByThis() = this.FOO +//fun A.extImplicit() = FOO + +fun assertEquals(expected: T, actual: T, id: String) { + if (expected != actual) throw Exception("Failed on $id, expected = '$expected', actual = '$actual'") +} + +fun box(): String { + assertEquals(A.FOO, A.FOO.explicit(), "explicit access") + assertEquals(A.FOO, A.FOO.byThis(), "access by this") + assertEquals(A.FOO, A.FOO.implicit(), "implicit access") + + assertEquals(A.FOO, A.FOO.explicit(), "explicit access from BAR") + // TODO uncoment when KT-4692 will be fixed + //assertEquals(A.FOO, A.FOO.byThis(), "access by this from BAR") + assertEquals(A.FOO, A.FOO.implicit(), "implicit access from BAR") + + assertEquals(A.FOO, A.FOO.extExplicit(), "explicit access from ext fun") + assertEquals(A.FOO, A.FOO.extByThis(), "access by this from ext fun") + // TODO uncoment when KT-4692 will be fixed + //assertEquals(A.FOO, A.FOO.extImplicit(), "implicit access from ext fun") + + return "OK" +}