From e331f274837f6f74df0f1bbe90f8d73f38703216 Mon Sep 17 00:00:00 2001 From: pTalanov Date: Tue, 13 Mar 2012 20:16:48 +0400 Subject: [PATCH] Introduce BackingFieldAccessTranslator. Refactor AccessTranslationUtils, ReferenceTranslator. Add test for namespace properties. --- .../test/semantics/MultiNamespaceTest.java | 4 + .../declaration/PropertyTranslator.java | 2 +- .../ClassInitializerTranslator.java | 2 +- .../initializer/InitializerVisitor.java | 8 +- .../reference/AccessTranslationUtils.java | 17 ++-- .../BackingFieldAccessTranslator.java | 81 +++++++++++++++++++ .../reference/CachedAccessTranslator.java | 2 + .../CachedArrayAccessTranslator.java | 1 + .../CachedPropertyAccessTranslator.java | 1 + .../reference/ReferenceAccessTranslator.java | 20 ++--- .../reference/ReferenceTranslator.java | 20 +++-- .../k2js/translate/utils/BindingUtils.java | 2 +- .../translate/utils/TranslationUtils.java | 25 +++--- .../a.kt | 5 ++ .../b.kt | 3 + 15 files changed, 145 insertions(+), 48 deletions(-) create mode 100644 js/js.translator/src/org/jetbrains/k2js/translate/reference/BackingFieldAccessTranslator.java create mode 100644 js/js.translator/testFiles/multiNamespace/cases/namespaceVariableVisibleFromOtherNamespace/a.kt create mode 100644 js/js.translator/testFiles/multiNamespace/cases/namespaceVariableVisibleFromOtherNamespace/b.kt diff --git a/js/js.tests/test/org/jetbrains/k2js/test/semantics/MultiNamespaceTest.java b/js/js.tests/test/org/jetbrains/k2js/test/semantics/MultiNamespaceTest.java index 01ea5bd6cfd..75be3de270b 100644 --- a/js/js.tests/test/org/jetbrains/k2js/test/semantics/MultiNamespaceTest.java +++ b/js/js.tests/test/org/jetbrains/k2js/test/semantics/MultiNamespaceTest.java @@ -36,5 +36,9 @@ public class MultiNamespaceTest extends MultipleFilesTranslationTest { checkFooBoxIsTrue("classesInheritedFromOtherNamespace"); } + public void testNamespaceVariableVisibleFromOtherNamespace() throws Exception { + checkFooBoxIsTrue("namespaceVariableVisibleFromOtherNamespace"); + } + } diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/declaration/PropertyTranslator.java b/js/js.translator/src/org/jetbrains/k2js/translate/declaration/PropertyTranslator.java index cb57c77f0fe..00ed05c5ea8 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/declaration/PropertyTranslator.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/declaration/PropertyTranslator.java @@ -142,7 +142,7 @@ public final class PropertyTranslator extends AbstractTranslator { JsFunction result = context().getFunctionObject(propertySetterDescriptor); JsParameter defaultParameter = new JsParameter(propertyAccessContext(propertySetterDescriptor).jsScope().declareTemporary()); - JsStatement assignment = assignmentToBackingField(context(), property, defaultParameter.getName().makeRef()); + JsStatement assignment = assignmentToBackingField(context(), property, defaultParameter.getName().makeRef()).makeStmt(); setParameters(result, defaultParameter); result.setBody(convertToBlock(assignment)); return result; diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/initializer/ClassInitializerTranslator.java b/js/js.translator/src/org/jetbrains/k2js/translate/initializer/ClassInitializerTranslator.java index ea87a3a8534..602c322a42b 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/initializer/ClassInitializerTranslator.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/initializer/ClassInitializerTranslator.java @@ -140,7 +140,7 @@ public final class ClassInitializerTranslator extends AbstractInitializerTransla getPropertyDescriptorForConstructorParameter(bindingContext(), jetParameter); if (propertyDescriptor != null) { JsStatement assignmentToBackingFieldExpression = assignmentToBackingField - (context(), propertyDescriptor, jsParameter.getName().makeRef()); + (context(), propertyDescriptor, jsParameter.getName().makeRef()).makeStmt(); initializerStatements.add(assignmentToBackingFieldExpression); } } diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/initializer/InitializerVisitor.java b/js/js.translator/src/org/jetbrains/k2js/translate/initializer/InitializerVisitor.java index 2f3dabc843b..47b128dd366 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/initializer/InitializerVisitor.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/initializer/InitializerVisitor.java @@ -16,6 +16,7 @@ package org.jetbrains.k2js.translate.initializer; +import com.google.dart.compiler.backend.js.ast.JsExprStmt; import com.google.dart.compiler.backend.js.ast.JsExpression; import com.google.dart.compiler.backend.js.ast.JsInvocation; import com.google.dart.compiler.backend.js.ast.JsStatement; @@ -33,7 +34,6 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; -import static java.util.Collections.singletonList; import static org.jetbrains.k2js.translate.general.Translation.translateAsStatement; import static org.jetbrains.k2js.translate.utils.BindingUtils.getDeclarationsForNamespace; import static org.jetbrains.k2js.translate.utils.BindingUtils.getPropertyDescriptorForObjectDeclaration; @@ -62,7 +62,7 @@ public final class InitializerVisitor extends TranslatorVisitorsingletonList(assignment); } @NotNull diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/reference/AccessTranslationUtils.java b/js/js.translator/src/org/jetbrains/k2js/translate/reference/AccessTranslationUtils.java index 47817d43a58..79983f64f94 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/reference/AccessTranslationUtils.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/reference/AccessTranslationUtils.java @@ -28,24 +28,19 @@ public final class AccessTranslationUtils { private AccessTranslationUtils() { } - //TODO: this piece of code represents dangerously convoluted logic, think of the ways it can be improved @NotNull public static AccessTranslator getAccessTranslator(@NotNull JetExpression referenceExpression, @NotNull TranslationContext context) { assert ((referenceExpression instanceof JetReferenceExpression) || (referenceExpression instanceof JetQualifiedExpression)); - if (PropertyAccessTranslator.canBePropertyAccess(referenceExpression, context)) { - if (referenceExpression instanceof JetQualifiedExpression) { - return QualifiedExpressionTranslator.getAccessTranslator((JetQualifiedExpression) referenceExpression, context); - } - assert referenceExpression instanceof JetSimpleNameExpression; - return PropertyAccessTranslator.newInstance((JetSimpleNameExpression) referenceExpression, - null, CallType.NORMAL, context); + if (referenceExpression instanceof JetQualifiedExpression) { + return QualifiedExpressionTranslator.getAccessTranslator((JetQualifiedExpression) referenceExpression, context); } - if (referenceExpression instanceof JetArrayAccessExpression) { - return ArrayAccessTranslator.newInstance((JetArrayAccessExpression) referenceExpression, context); + if (referenceExpression instanceof JetSimpleNameExpression) { + return ReferenceTranslator.getAccessTranslator((JetSimpleNameExpression) referenceExpression, context); } - return ReferenceAccessTranslator.newInstance((JetSimpleNameExpression) referenceExpression, context); + assert referenceExpression instanceof JetArrayAccessExpression; + return ArrayAccessTranslator.newInstance((JetArrayAccessExpression) referenceExpression, context); } @NotNull diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/reference/BackingFieldAccessTranslator.java b/js/js.translator/src/org/jetbrains/k2js/translate/reference/BackingFieldAccessTranslator.java new file mode 100644 index 00000000000..754807ca7e5 --- /dev/null +++ b/js/js.translator/src/org/jetbrains/k2js/translate/reference/BackingFieldAccessTranslator.java @@ -0,0 +1,81 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.k2js.translate.reference; + +import com.google.dart.compiler.backend.js.ast.JsExpression; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; +import org.jetbrains.jet.lang.descriptors.PropertyDescriptor; +import org.jetbrains.jet.lang.psi.JetSimpleNameExpression; +import org.jetbrains.k2js.translate.context.TemporaryVariable; +import org.jetbrains.k2js.translate.context.TranslationContext; +import org.jetbrains.k2js.translate.general.AbstractTranslator; +import org.jetbrains.k2js.translate.utils.PsiUtils; + +import java.util.Collections; +import java.util.List; + +import static org.jetbrains.k2js.translate.utils.BindingUtils.getDescriptorForReferenceExpression; +import static org.jetbrains.k2js.translate.utils.TranslationUtils.assignmentToBackingField; +import static org.jetbrains.k2js.translate.utils.TranslationUtils.backingFieldReference; + +/** + * @author Pavel Talanov + */ +public final class BackingFieldAccessTranslator extends AbstractTranslator implements CachedAccessTranslator { + + @NotNull + private final PropertyDescriptor descriptor; + + /*package*/ + static BackingFieldAccessTranslator newInstance(@NotNull JetSimpleNameExpression expression, + @NotNull TranslationContext context) { + assert PsiUtils.isBackingFieldReference(expression); + DeclarationDescriptor referencedProperty = getDescriptorForReferenceExpression(context.bindingContext(), expression); + assert referencedProperty instanceof PropertyDescriptor; + return new BackingFieldAccessTranslator((PropertyDescriptor) referencedProperty, context); + } + + private BackingFieldAccessTranslator(@NotNull PropertyDescriptor descriptor, @NotNull TranslationContext context) { + super(context); + this.descriptor = descriptor; + } + + @NotNull + @Override + public JsExpression translateAsGet() { + return backingFieldReference(context(), descriptor); + } + + @NotNull + @Override + public JsExpression translateAsSet(@NotNull JsExpression setTo) { + return assignmentToBackingField(context(), descriptor, setTo); + } + + @NotNull + @Override + public CachedAccessTranslator getCached() { + return this; + } + + @NotNull + @Override + public List declaredTemporaries() { + return Collections.emptyList(); + } +} diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/reference/CachedAccessTranslator.java b/js/js.translator/src/org/jetbrains/k2js/translate/reference/CachedAccessTranslator.java index 42d6f13cbef..9fd2e17805f 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/reference/CachedAccessTranslator.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/reference/CachedAccessTranslator.java @@ -16,6 +16,7 @@ package org.jetbrains.k2js.translate.reference; +import org.jetbrains.annotations.NotNull; import org.jetbrains.k2js.translate.context.TemporaryVariable; import java.util.List; @@ -26,5 +27,6 @@ import java.util.List; * Represents a translator which guaranties that all expression will be computed only once. */ public interface CachedAccessTranslator extends AccessTranslator { + @NotNull List declaredTemporaries(); } diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/reference/CachedArrayAccessTranslator.java b/js/js.translator/src/org/jetbrains/k2js/translate/reference/CachedArrayAccessTranslator.java index 2f22aa1c0a0..e09800619cb 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/reference/CachedArrayAccessTranslator.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/reference/CachedArrayAccessTranslator.java @@ -57,6 +57,7 @@ public final class CachedArrayAccessTranslator extends ArrayAccessTranslator imp return translateAsSet(arrayExpression.reference(), toExpressionList(indexExpressions), setTo); } + @NotNull @Override public List declaredTemporaries() { List result = Lists.newArrayList(); diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/reference/CachedPropertyAccessTranslator.java b/js/js.translator/src/org/jetbrains/k2js/translate/reference/CachedPropertyAccessTranslator.java index e9ffb3b1725..dc1a7a8babf 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/reference/CachedPropertyAccessTranslator.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/reference/CachedPropertyAccessTranslator.java @@ -68,6 +68,7 @@ public final class CachedPropertyAccessTranslator implements CachedAccessTransla return this; } + @NotNull @Override public List declaredTemporaries() { return cachedReceiver != null ? singletonList(cachedReceiver) : Collections.emptyList(); diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/reference/ReferenceAccessTranslator.java b/js/js.translator/src/org/jetbrains/k2js/translate/reference/ReferenceAccessTranslator.java index 40c93acad4a..29795609d6f 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/reference/ReferenceAccessTranslator.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/reference/ReferenceAccessTranslator.java @@ -20,6 +20,7 @@ import com.google.dart.compiler.backend.js.ast.JsExpression; import com.google.dart.compiler.backend.js.ast.JsNameRef; import com.google.dart.compiler.util.AstUtil; import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; import org.jetbrains.jet.lang.psi.JetSimpleNameExpression; import org.jetbrains.k2js.translate.context.TemporaryVariable; import org.jetbrains.k2js.translate.context.TranslationContext; @@ -28,6 +29,9 @@ import org.jetbrains.k2js.translate.general.AbstractTranslator; import java.util.Collections; import java.util.List; +import static org.jetbrains.k2js.translate.reference.ReferenceTranslator.translateAsLocalNameReference; +import static org.jetbrains.k2js.translate.utils.BindingUtils.getDescriptorForReferenceExpression; + /** * @author Pavel Talanov */ @@ -36,30 +40,27 @@ public final class ReferenceAccessTranslator extends AbstractTranslator implemen @NotNull /*package*/ static ReferenceAccessTranslator newInstance(@NotNull JetSimpleNameExpression expression, @NotNull TranslationContext context) { - return new ReferenceAccessTranslator(expression, context); + DeclarationDescriptor referenceDescriptor = getDescriptorForReferenceExpression(context.bindingContext(), expression); + return new ReferenceAccessTranslator(referenceDescriptor, context); } @NotNull - private final JetSimpleNameExpression expression; + private final JsExpression reference; - private ReferenceAccessTranslator(@NotNull JetSimpleNameExpression expression, - @NotNull TranslationContext context) { + private ReferenceAccessTranslator(@NotNull DeclarationDescriptor descriptor, @NotNull TranslationContext context) { super(context); - this.expression = expression; + this.reference = translateAsLocalNameReference(descriptor, context()); } @Override @NotNull public JsExpression translateAsGet() { - //TODO: consider evaluating only once - return ReferenceTranslator.translateSimpleName(expression, context()); + return reference; } @Override @NotNull public JsExpression translateAsSet(@NotNull JsExpression toSetTo) { - //TODO: consider evaluating only once - JsExpression reference = ReferenceTranslator.translateSimpleName(expression, context()); assert reference instanceof JsNameRef; return AstUtil.newAssignment((JsNameRef) reference, toSetTo); } @@ -70,6 +71,7 @@ public final class ReferenceAccessTranslator extends AbstractTranslator implemen return this; } + @NotNull @Override public List declaredTemporaries() { return Collections.emptyList(); 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 582baa8f9b7..e9d7f5e8d68 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 @@ -23,8 +23,8 @@ import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; import org.jetbrains.jet.lang.psi.JetSimpleNameExpression; import org.jetbrains.k2js.translate.context.TranslationContext; -import static org.jetbrains.k2js.translate.utils.BindingUtils.getDescriptorForReferenceExpression; import static org.jetbrains.k2js.translate.utils.JsAstUtils.qualified; +import static org.jetbrains.k2js.translate.utils.PsiUtils.isBackingFieldReference; /** * @author Pavel Talanov @@ -37,12 +37,7 @@ public final class ReferenceTranslator { @NotNull public static JsExpression translateSimpleName(@NotNull JetSimpleNameExpression expression, @NotNull TranslationContext context) { - if (PropertyAccessTranslator.canBePropertyGetterCall(expression, context)) { - return PropertyAccessTranslator.translateAsPropertyGetterCall(expression, null, CallType.NORMAL, context); - } - DeclarationDescriptor referencedDescriptor = - getDescriptorForReferenceExpression(context.bindingContext(), expression); - return translateAsLocalNameReference(referencedDescriptor, context); + return getAccessTranslator(expression, context).translateAsGet(); } @NotNull @@ -62,4 +57,15 @@ public final class ReferenceTranslator { JsName referencedName = context.getNameForDescriptor(referencedDescriptor); return referencedName.makeRef(); } + + public static AccessTranslator getAccessTranslator(JetSimpleNameExpression referenceExpression, TranslationContext context) { + if (isBackingFieldReference(referenceExpression)) { + return BackingFieldAccessTranslator.newInstance(referenceExpression, context); + } + if (PropertyAccessTranslator.canBePropertyAccess(referenceExpression, context)) { + return PropertyAccessTranslator.newInstance(referenceExpression, + null, CallType.NORMAL, context); + } + return ReferenceAccessTranslator.newInstance(referenceExpression, context); + } } diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/utils/BindingUtils.java b/js/js.translator/src/org/jetbrains/k2js/translate/utils/BindingUtils.java index 558e4b23081..157a9083822 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/utils/BindingUtils.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/utils/BindingUtils.java @@ -201,7 +201,7 @@ public final class BindingUtils { //TODO: refactor duplication - //TODO: check where we use there, suspicious + //TODO: check where we use these, suspicious public static boolean isOwnedByNamespace(@NotNull DeclarationDescriptor descriptor) { if (descriptor instanceof ConstructorDescriptor) { DeclarationDescriptor classDescriptor = descriptor.getContainingDeclaration(); diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/utils/TranslationUtils.java b/js/js.translator/src/org/jetbrains/k2js/translate/utils/TranslationUtils.java index a1e9dd27e7e..6cd815630d7 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/utils/TranslationUtils.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/utils/TranslationUtils.java @@ -30,7 +30,9 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import static org.jetbrains.k2js.translate.utils.BindingUtils.*; +import static com.google.dart.compiler.util.AstUtil.newAssignment; +import static org.jetbrains.k2js.translate.utils.BindingUtils.getFunctionDescriptorForOperationExpression; +import static org.jetbrains.k2js.translate.utils.BindingUtils.getPropertyDescriptor; import static org.jetbrains.k2js.translate.utils.DescriptorUtils.getExpectedReceiverDescriptor; import static org.jetbrains.k2js.translate.utils.JsAstUtils.*; @@ -77,21 +79,15 @@ public final class TranslationUtils { public static JsNameRef backingFieldReference(@NotNull TranslationContext context, @NotNull PropertyDescriptor descriptor) { JsName backingFieldName = context.getNameForDescriptor(descriptor); - if (isOwnedByClass(descriptor)) { - return qualified(backingFieldName, new JsThisRef()); - } - assert isOwnedByNamespace(descriptor) - : "Only classes and namespaces may own backing fields."; - JsNameRef qualifier = context.getQualifierForDescriptor(descriptor); - return qualified(backingFieldName, qualifier); + return qualified(backingFieldName, new JsThisRef()); } @NotNull - public static JsStatement assignmentToBackingField(@NotNull TranslationContext context, - @NotNull PropertyDescriptor descriptor, - @NotNull JsExpression assignTo) { + public static JsExpression assignmentToBackingField(@NotNull TranslationContext context, + @NotNull PropertyDescriptor descriptor, + @NotNull JsExpression assignTo) { JsNameRef backingFieldReference = backingFieldReference(context, descriptor); - return newAssignmentStatement(backingFieldReference, assignTo); + return newAssignment(backingFieldReference, assignTo); } @Nullable @@ -223,9 +219,8 @@ public final class TranslationUtils { } @NotNull - public static JsStatement assignmentToBackingField(@NotNull TranslationContext context, @NotNull JetProperty property, - @NotNull JsExpression initExpression) { - + public static JsExpression assignmentToBackingField(@NotNull TranslationContext context, @NotNull JetProperty property, + @NotNull JsExpression initExpression) { PropertyDescriptor propertyDescriptor = getPropertyDescriptor(context.bindingContext(), property); return assignmentToBackingField(context, propertyDescriptor, initExpression); } diff --git a/js/js.translator/testFiles/multiNamespace/cases/namespaceVariableVisibleFromOtherNamespace/a.kt b/js/js.translator/testFiles/multiNamespace/cases/namespaceVariableVisibleFromOtherNamespace/a.kt new file mode 100644 index 00000000000..7794224efc3 --- /dev/null +++ b/js/js.translator/testFiles/multiNamespace/cases/namespaceVariableVisibleFromOtherNamespace/a.kt @@ -0,0 +1,5 @@ +package foo + +val a = 2 + +fun box() = (a + bar.a) == 5 \ No newline at end of file diff --git a/js/js.translator/testFiles/multiNamespace/cases/namespaceVariableVisibleFromOtherNamespace/b.kt b/js/js.translator/testFiles/multiNamespace/cases/namespaceVariableVisibleFromOtherNamespace/b.kt new file mode 100644 index 00000000000..040e1d28d02 --- /dev/null +++ b/js/js.translator/testFiles/multiNamespace/cases/namespaceVariableVisibleFromOtherNamespace/b.kt @@ -0,0 +1,3 @@ +package bar + +val a = 3