From 8e7d949dd462df863615d3dc225505f9665aea4b Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Thu, 3 Mar 2016 19:44:44 +0300 Subject: [PATCH] KT-11030 Implements closures in classes. Represent local object literals as classes --- .../kotlin/resolve/DescriptorUtils.java | 4 +- .../kotlin/js/test/semantics/ObjectTest.java | 4 +- .../callTranslator/FunctionCallCases.kt | 17 ++-- .../kotlin/js/translate/context/Namer.java | 6 +- .../js/translate/context/StaticContext.java | 43 +++++++-- .../translate/context/TranslationContext.java | 52 ++++++++++- .../js/translate/context/UsageTracker.kt | 6 +- .../translate/declaration/ClassTranslator.kt | 87 ++++++++++++------- .../expression/ExpressionVisitor.java | 11 ++- .../initializer/InitializerUtils.java | 4 +- .../testData/object/cases/objectInObject.kt | 15 +++- 11 files changed, 181 insertions(+), 68 deletions(-) diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorUtils.java b/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorUtils.java index b66af0ff790..f4e88e98af2 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorUtils.java +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2010-2015 JetBrains s.r.o. + * Copyright 2010-2016 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. @@ -78,7 +78,7 @@ public class DescriptorUtils { return false; } - private static boolean isDescriptorWithLocalVisibility(DeclarationDescriptor current) { + public static boolean isDescriptorWithLocalVisibility(DeclarationDescriptor current) { return current instanceof DeclarationDescriptorWithVisibility && ((DeclarationDescriptorWithVisibility) current).getVisibility() == Visibilities.LOCAL; } diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/ObjectTest.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/ObjectTest.java index 2b5e4b88d6f..d929c74ecf7 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/ObjectTest.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/ObjectTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2010-2015 JetBrains s.r.o. + * Copyright 2010-2016 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. @@ -41,7 +41,7 @@ public final class ObjectTest extends SingleFileTranslationTest { } public void testObjectInObject() throws Exception { - fooBoxTest(); + checkFooBoxIsOk(); } public void testObjectInheritingFromATrait() throws Exception { diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/callTranslator/FunctionCallCases.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/callTranslator/FunctionCallCases.kt index 42b095fdb17..0aacc9e7c43 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/callTranslator/FunctionCallCases.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/callTranslator/FunctionCallCases.kt @@ -1,5 +1,5 @@ /* - * Copyright 2010-2015 JetBrains s.r.o. + * Copyright 2010-2016 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. @@ -17,9 +17,7 @@ package org.jetbrains.kotlin.js.translate.callTranslator import com.google.dart.compiler.backend.js.ast.* -import org.jetbrains.kotlin.descriptors.CallableDescriptor -import org.jetbrains.kotlin.descriptors.ConstructorDescriptor -import org.jetbrains.kotlin.descriptors.Visibilities +import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.js.PredefinedAnnotation import org.jetbrains.kotlin.js.translate.context.Namer import org.jetbrains.kotlin.js.translate.context.TranslationContext @@ -212,11 +210,18 @@ object ConstructorCallCase : FunctionCallCase() { val arguments = argumentsInfo.getArguments() val constructorDescriptor = callableDescriptor as ConstructorDescriptor + val classDescriptor = constructorDescriptor.containingDeclaration + val closure = context.getLocalClassClosure(classDescriptor) + var closureArgs = emptyList() + if (closure != null) { + closureArgs = closure.asSequence().map { context.getParameterNameRefForInvocation(it) }.toList() + } + if (constructorDescriptor.isPrimary || AnnotationsUtils.isNativeObject(constructorDescriptor)) { - return JsNew(functionRef, arguments) + return JsNew(functionRef, closureArgs + arguments) } else { - return JsInvocation(functionRef, arguments) + return JsInvocation(functionRef, closureArgs + arguments) } } } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/Namer.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/Namer.java index d1acbdad814..bfaf548efde 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/Namer.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/Namer.java @@ -1,5 +1,5 @@ /* - * Copyright 2010-2015 JetBrains s.r.o. + * Copyright 2010-2016 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. @@ -438,9 +438,7 @@ public final class Namer { return objectCreationMethodReference(); case ANNOTATION_CLASS: case CLASS: - return DescriptorUtils.isAnonymousObject(descriptor) - ? objectCreationMethodReference() - : classCreationMethodReference(); + return classCreationMethodReference(); default: throw new UnsupportedOperationException("Unsupported class kind: " + descriptor); } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/StaticContext.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/StaticContext.java index 75d7a709cf0..6cbfa456d11 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/StaticContext.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/StaticContext.java @@ -1,5 +1,5 @@ /* - * Copyright 2010-2015 JetBrains s.r.o. + * Copyright 2010-2016 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. @@ -16,6 +16,7 @@ package org.jetbrains.kotlin.js.translate.context; +import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.dart.compiler.backend.js.ast.*; import com.google.dart.compiler.backend.js.ast.metadata.HasMetadata; @@ -98,6 +99,9 @@ public final class StaticContext { @NotNull private final Map scopeToFunction = Maps.newHashMap(); + @NotNull + private final Map> localClassesClosure = Maps.newHashMap(); + @NotNull private final Config config; @@ -262,13 +266,17 @@ public final class StaticContext { @Nullable @Override public JsName apply(@NotNull DeclarationDescriptor descriptor) { - if (!DescriptorUtils.isLocal(descriptor) || !DescriptorUtils.isClass(descriptor)) return null; + if (!DescriptorUtils.isDescriptorWithLocalVisibility(descriptor) || + !DescriptorUtils.isClass(descriptor)) { + return null; + } List parts = new ArrayList(); do { - parts.add(descriptor.getName().asString()); + parts.add(descriptor.getName().isSpecial() ? "f" : descriptor.getName().getIdentifier()); descriptor = descriptor.getContainingDeclaration(); - } while (!(descriptor instanceof ClassOrPackageFragmentDescriptor)); + } while (descriptor != null && !(descriptor instanceof ClassOrPackageFragmentDescriptor)); + assert descriptor != null; Collections.reverse(parts); StringBuilder suggestedName = new StringBuilder(parts.get(0)); @@ -580,10 +588,7 @@ public final class StaticContext { if (!(descriptor instanceof ClassDescriptor)) { return null; } - DeclarationDescriptor container = descriptor.getContainingDeclaration(); - if (container != null && !(container instanceof ClassDescriptor)) { - container = DescriptorUtils.getContainingClass(container); - } + DeclarationDescriptor container = getEnclosingNonSingleton(descriptor.getContainingDeclaration()); if (container == null) { return null; } @@ -608,7 +613,9 @@ public final class StaticContext { @Nullable @Override public JsExpression apply(@NotNull DeclarationDescriptor descriptor) { - if (!DescriptorUtils.isLocal(descriptor) || !(descriptor instanceof ClassDescriptor)) return null; + if (!DescriptorUtils.isDescriptorWithLocalVisibility(descriptor) || !(descriptor instanceof ClassDescriptor)) { + return null; + } descriptor = descriptor.getContainingDeclaration(); while (descriptor != null && !(descriptor instanceof ClassOrPackageFragmentDescriptor)) { @@ -631,6 +638,14 @@ public final class StaticContext { } } + @Nullable + private static ClassDescriptor getEnclosingNonSingleton(@NotNull DeclarationDescriptor descriptor) { + while (descriptor != null && (!(descriptor instanceof ClassDescriptor) || DescriptorUtils.isObject(descriptor))) { + descriptor = descriptor.getContainingDeclaration(); + } + return (ClassDescriptor) descriptor; + } + private static JsExpression applySideEffects(JsExpression expression, DeclarationDescriptor descriptor) { if (expression instanceof HasMetadata) { if (descriptor instanceof FunctionDescriptor || @@ -658,4 +673,14 @@ public final class StaticContext { addRule(propertiesInClassHaveNoQualifiers); } } + + public void putLocalClassClosure(@NotNull ClassDescriptor localClass, @NotNull List closure) { + localClassesClosure.put(localClass, Lists.newArrayList(closure)); + } + + @Nullable + public List getLocalClassClosure(@NotNull ClassDescriptor localClass) { + List result = localClassesClosure.get(localClass); + return result != null ? Lists.newArrayList(result) : null; + } } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/TranslationContext.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/TranslationContext.java index 172275c7a9b..f65e6377c0b 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/TranslationContext.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/TranslationContext.java @@ -1,5 +1,5 @@ /* - * Copyright 2010-2015 JetBrains s.r.o. + * Copyright 2010-2016 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. @@ -32,6 +32,7 @@ import org.jetbrains.kotlin.resolve.BindingTrace; import org.jetbrains.kotlin.resolve.DescriptorUtils; import java.util.HashMap; +import java.util.List; import java.util.Map; import static org.jetbrains.kotlin.js.translate.context.UsageTrackerKt.getNameForCapturedDescriptor; @@ -135,6 +136,13 @@ public class TranslationContext { this.definitionPlace, descriptor); } + @NotNull + public TranslationContext innerWithUsageTracker(@NotNull JsScope scope, @NotNull MemberDescriptor descriptor) { + UsageTracker usageTracker = new UsageTracker(this.usageTracker, descriptor, scope); + return new TranslationContext(this, staticContext, dynamicContext, aliasingContext.inner(), usageTracker, definitionPlace, + descriptor); + } + @NotNull public TranslationContext innerBlock(@NotNull JsBlock block) { return new TranslationContext(this, staticContext, dynamicContext.innerBlock(block), aliasingContext, usageTracker, null, @@ -154,8 +162,7 @@ public class TranslationContext { @NotNull private TranslationContext innerWithAliasingContext(AliasingContext aliasingContext) { - return new TranslationContext(this, this.staticContext, this.dynamicContext, aliasingContext, this.usageTracker, null, - this.declarationDescriptor); + return new TranslationContext(this, staticContext, dynamicContext, aliasingContext, usageTracker, null, declarationDescriptor); } @NotNull @@ -414,12 +421,27 @@ public class TranslationContext { usageTracker.used(descriptor); JsName name = getNameForCapturedDescriptor(usageTracker, descriptor); - if (name != null) return name.makeRef(); + if (name != null) { + JsNameRef result = name.makeRef(); + if (shouldCaptureViaThis()) { + result.setQualifier(JsLiteral.THIS); + } + return result; + } } return null; } + private boolean shouldCaptureViaThis() { + if (declarationDescriptor == null) return false; + + if (DescriptorUtils.isDescriptorWithLocalVisibility(declarationDescriptor)) { + return !(declarationDescriptor instanceof FunctionDescriptor); + } + return true; + } + @Nullable private static ClassDescriptor getNearestClass(@NotNull DeclarationDescriptor declaration) { DeclarationDescriptor decl = declaration; @@ -438,4 +460,26 @@ public class TranslationContext { public DeclarationDescriptor getDeclarationDescriptor() { return declarationDescriptor; } + + public void putLocalClassClosure(@NotNull ClassDescriptor localClass, @NotNull List closure) { + staticContext.putLocalClassClosure(localClass, closure); + } + + @Nullable + public List getLocalClassClosure(@NotNull ClassDescriptor localClass) { + return staticContext.getLocalClassClosure(localClass); + } + + @NotNull + public JsExpression getParameterNameRefForInvocation(@NotNull DeclarationDescriptor descriptor) { + JsExpression alias = getAliasForDescriptor(descriptor); + if (alias != null) return alias; + if (descriptor instanceof ReceiverParameterDescriptor) return JsLiteral.THIS; + return getNameForDescriptor(descriptor).makeRef(); + } + + @NotNull + public JsScope getRootScope() { + return staticContext.getRootScope(); + } } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/UsageTracker.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/UsageTracker.kt index 09aad7cfef4..38511972535 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/UsageTracker.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/UsageTracker.kt @@ -1,5 +1,5 @@ /* - * Copyright 2010-2015 JetBrains s.r.o. + * Copyright 2010-2016 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. @@ -20,7 +20,7 @@ import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.resolve.DescriptorUtils.isAncestor import com.google.dart.compiler.backend.js.ast.JsName import org.jetbrains.kotlin.js.translate.utils.ManglingUtils.getSuggestedName -import com.google.dart.compiler.backend.js.ast.JsFunctionScope +import com.google.dart.compiler.backend.js.ast.JsScope import org.jetbrains.kotlin.resolve.DescriptorUtils private val CAPTURED_RECEIVER_NAME_PREFIX : String = "this$" @@ -28,7 +28,7 @@ private val CAPTURED_RECEIVER_NAME_PREFIX : String = "this$" class UsageTracker( private val parent: UsageTracker?, val containingDescriptor: MemberDescriptor, - private val scope: JsFunctionScope + private val scope: JsScope ) { private val captured = linkedMapOf() diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/ClassTranslator.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/ClassTranslator.kt index bb37de48268..447d82cd3e9 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/ClassTranslator.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/ClassTranslator.kt @@ -1,5 +1,5 @@ /* - * Copyright 2010-2015 JetBrains s.r.o. + * Copyright 2010-2016 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. @@ -28,8 +28,8 @@ import org.jetbrains.kotlin.js.translate.callTranslator.CallTranslator import org.jetbrains.kotlin.js.translate.context.DefinitionPlace import org.jetbrains.kotlin.js.translate.context.Namer import org.jetbrains.kotlin.js.translate.context.TranslationContext +import org.jetbrains.kotlin.js.translate.context.* import org.jetbrains.kotlin.js.translate.expression.FunctionTranslator -import org.jetbrains.kotlin.js.translate.expression.withCapturedParameters import org.jetbrains.kotlin.js.translate.general.AbstractTranslator import org.jetbrains.kotlin.js.translate.initializer.ClassInitializerTranslator import org.jetbrains.kotlin.js.translate.reference.ReferenceTranslator.translateAsFQReference @@ -46,6 +46,7 @@ import org.jetbrains.kotlin.psi.KtClassOrObject import org.jetbrains.kotlin.psi.KtObjectDeclaration import org.jetbrains.kotlin.psi.KtSecondaryConstructor import org.jetbrains.kotlin.resolve.BindingContextUtils +import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.DescriptorUtils.* import org.jetbrains.kotlin.types.CommonSupertypes.topologicallySortSuperclassesAndRecordAllInstances import org.jetbrains.kotlin.types.KotlinType @@ -64,9 +65,10 @@ class ClassTranslator private constructor( private val descriptor = getClassDescriptor(context.bindingContext(), classDeclaration) private fun translateObjectLiteralExpression(): JsExpression { - getContainingClass(descriptor) ?: return translate(context()) - - return translateObjectInsideClass(context()) + return if (descriptor.containingDeclaration is ClassDescriptor && descriptor.kind == ClassKind.OBJECT) + translateObjectInsideClass(context()) + else + translate(context()) } private fun translate(declarationContext: TranslationContext = context()): JsInvocation { @@ -82,28 +84,19 @@ class ClassTranslator private constructor( val properties = SmartList() val staticProperties = SmartList() - val isTopLevelDeclaration = context() == context - - var qualifiedReference: JsNameRef? = null - if (isTopLevelDeclaration) { - var definitionPlace: DefinitionPlace? = null - - if (!descriptor.kind.isSingleton && !isAnonymousObject(descriptor)) { - qualifiedReference = context.getQualifiedReference(descriptor) - val scope = context().getScopeForDescriptor(descriptor) - definitionPlace = DefinitionPlace(scope as JsObjectScope, qualifiedReference, staticProperties) - } - - context = context.newDeclaration(descriptor, definitionPlace) - } + val qualifiedReference = context.getQualifiedReference(descriptor) + val scope = context().getScopeForDescriptor(descriptor) + val definitionPlace = DefinitionPlace(scope as JsObjectScope, qualifiedReference, staticProperties) + context = context.newDeclaration(descriptor, definitionPlace) context = fixContextForCompanionObjectAccessing(context) invocationArguments.add(getSuperclassReferences(context)) val delegationTranslator = DelegationTranslator(classDeclaration, context()) + var initializer: JsFunction? = null if (!isTrait()) { - val initializer = ClassInitializerTranslator(classDeclaration, context).generateInitializeMethod(delegationTranslator) - invocationArguments.add(if (initializer.body.statements.isEmpty()) JsLiteral.NULL else initializer) + initializer = ClassInitializerTranslator(classDeclaration, context).generateInitializeMethod(delegationTranslator) + invocationArguments.add(initializer) } translatePropertiesAsConstructorParameters(context, properties) @@ -129,10 +122,8 @@ class ClassTranslator private constructor( invocationArguments.add(JsLiteral.NULL) } else { - if (qualifiedReference != null) { - // about "prototype" - see http://code.google.com/p/jsdoc-toolkit/wiki/TagLends - invocationArguments.add(JsDocComment(JsAstUtils.LENDS_JS_DOC_TAG, JsNameRef("prototype", qualifiedReference))) - } + // about "prototype" - see http://code.google.com/p/jsdoc-toolkit/wiki/TagLends + invocationArguments.add(JsDocComment(JsAstUtils.LENDS_JS_DOC_TAG, JsNameRef("prototype", qualifiedReference))) invocationArguments.add(JsObjectLiteral(properties, true)) } } @@ -141,6 +132,22 @@ class ClassTranslator private constructor( invocationArguments.add(JsObjectLiteral(staticProperties, true)) } + val tracker = context.usageTracker() + if (tracker != null && initializer != null && tracker.hasCapturedExceptContaining()) { + val captured = tracker.capturedDescriptorToJsName + val keysAsList = captured.keys.toList() + for ((i, key) in keysAsList.withIndex()) { + val name = captured[key]!! + initializer.parameters.add(i, JsParameter(name)) + initializer.body.statements.add(i, JsAstUtils.defineSimpleProperty(name.ident, name.makeRef())) + } + context.putLocalClassClosure(descriptor, keysAsList) + } + + if (initializer != null && initializer.body.isEmpty) { + invocationArguments.replaceAll { if (it == initializer) JsLiteral.NULL else it } + } + return invocationArguments } @@ -214,12 +221,30 @@ class ClassTranslator private constructor( } private fun translateObjectInsideClass(outerClassContext: TranslationContext): JsExpression { - val function = JsFunction(outerClassContext.scope(), JsBlock(), "initializer for " + descriptor.name.asString()) - val funContext = outerClassContext.newFunctionBodyWithUsageTracker(function, descriptor) + var outerDeclaration = descriptor.containingDeclaration.containingDeclaration + if (outerDeclaration != null && outerDeclaration !is ClassDescriptor) { + outerDeclaration = DescriptorUtils.getContainingClass(outerDeclaration) + } + val scope = if (outerDeclaration != null) + outerClassContext.getScopeForDescriptor(outerDeclaration) + else + outerClassContext.rootScope - function.body.statements.add(JsReturn(translate(funContext))) + val classContext = outerClassContext.innerWithUsageTracker(scope, descriptor) - return function.withCapturedParameters(funContext, outerClassContext, descriptor) + var declarationArgs = getClassCreateInvocationArguments(classContext) + val jsClass = JsInvocation(context().namer().classCreationMethodReference(), declarationArgs) + + val name = outerClassContext.getNameForDescriptor(descriptor) + val constructor = outerClassContext.define(name, jsClass) + + val closure = outerClassContext.getLocalClassClosure(descriptor) + var closureArgs = emptyList() + if (closure != null) { + closureArgs = closure.map { context().getParameterNameRefForInvocation(it) }.toList() + } + + return JsNew(constructor, closureArgs) } private fun generatedBridgeMethods(properties: MutableList) { @@ -289,6 +314,10 @@ class ClassTranslator private constructor( } @JvmStatic fun generateObjectLiteral(objectDeclaration: KtObjectDeclaration, context: TranslationContext): JsExpression { + return ClassTranslator(objectDeclaration, context).translateObjectInsideClass(context) + } + + @JvmStatic fun generateObjectDeclaration(objectDeclaration: KtObjectDeclaration, context: TranslationContext): JsExpression { return ClassTranslator(objectDeclaration, context).translateObjectLiteralExpression() } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/ExpressionVisitor.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/ExpressionVisitor.java index ebbd8ba7c1d..6d0e68205fd 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/ExpressionVisitor.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/ExpressionVisitor.java @@ -518,8 +518,7 @@ public final class ExpressionVisitor extends TranslatorVisitor { @Override @NotNull - public JsNode visitObjectLiteralExpression(@NotNull KtObjectLiteralExpression expression, - @NotNull TranslationContext context) { + public JsNode visitObjectLiteralExpression(@NotNull KtObjectLiteralExpression expression, @NotNull TranslationContext context) { return ClassTranslator.generateObjectLiteral(expression.getObjectDeclaration(), context); } @@ -569,8 +568,12 @@ public final class ExpressionVisitor extends TranslatorVisitor { @Override public JsNode visitClass(@NotNull KtClass klass, TranslationContext context) { - JsInvocation jsClass = ClassTranslator.generateClassCreation(klass, context); - DeclarationDescriptor descriptor = BindingUtils.getClassDescriptor(context.bindingContext(), klass); + ClassDescriptor descriptor = BindingUtils.getClassDescriptor(context.bindingContext(), klass); + JsObjectScope scope = new JsObjectScope(context.scope(), descriptor.toString(), ""); + TranslationContext classContext = context.innerWithUsageTracker(scope, descriptor); + + JsInvocation jsClass = ClassTranslator.generateClassCreation(klass, classContext); + JsName name = context.getNameForDescriptor(descriptor); return context.define(name, jsClass); } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/initializer/InitializerUtils.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/initializer/InitializerUtils.java index 186b79426ad..c3af93863a6 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/initializer/InitializerUtils.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/initializer/InitializerUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2010-2015 JetBrains s.r.o. + * Copyright 2010-2016 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. @@ -64,7 +64,7 @@ public final class InitializerUtils { @NotNull List initializers, @NotNull TranslationContext context ) { - JsExpression value = ClassTranslator.generateObjectLiteral(declaration, context); + JsExpression value = ClassTranslator.generateObjectDeclaration(declaration, context); ClassDescriptor descriptor = getClassDescriptor(context.bindingContext(), declaration); JsExpression expression = assignment(new JsNameRef(descriptor.getName().asString(), JsLiteral.THIS), value); initializers.add(expression.makeStmt()); diff --git a/js/js.translator/testData/object/cases/objectInObject.kt b/js/js.translator/testData/object/cases/objectInObject.kt index 5d1bc8a743a..1856ac76d5a 100644 --- a/js/js.translator/testData/object/cases/objectInObject.kt +++ b/js/js.translator/testData/object/cases/objectInObject.kt @@ -22,7 +22,16 @@ class C { } } -fun box() = A.query.status == "complete" && B.query.status == "completed" -// todo fix after KT-3868 will be fixed -// && C.query.status == "completed" +fun box(): String { + var result = A.query.status + if (result != "complete") return "fail1: $result" + + result = B.query.status + if (result != "completed") return "fail2: $result" + + result = C.query.status + if (result != "completed") return "fail3: $result" + + return "OK" +}