KT-11030 Implements closures in classes. Represent local object literals as classes

This commit is contained in:
Alexey Andreev
2016-03-03 19:44:44 +03:00
parent 1f8c3375fe
commit 8e7d949dd4
11 changed files with 181 additions and 68 deletions
@@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -78,7 +78,7 @@ public class DescriptorUtils {
return false; return false;
} }
private static boolean isDescriptorWithLocalVisibility(DeclarationDescriptor current) { public static boolean isDescriptorWithLocalVisibility(DeclarationDescriptor current) {
return current instanceof DeclarationDescriptorWithVisibility && return current instanceof DeclarationDescriptorWithVisibility &&
((DeclarationDescriptorWithVisibility) current).getVisibility() == Visibilities.LOCAL; ((DeclarationDescriptorWithVisibility) current).getVisibility() == Visibilities.LOCAL;
} }
@@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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 { public void testObjectInObject() throws Exception {
fooBoxTest(); checkFooBoxIsOk();
} }
public void testObjectInheritingFromATrait() throws Exception { public void testObjectInheritingFromATrait() throws Exception {
@@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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 package org.jetbrains.kotlin.js.translate.callTranslator
import com.google.dart.compiler.backend.js.ast.* import com.google.dart.compiler.backend.js.ast.*
import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.js.PredefinedAnnotation import org.jetbrains.kotlin.js.PredefinedAnnotation
import org.jetbrains.kotlin.js.translate.context.Namer import org.jetbrains.kotlin.js.translate.context.Namer
import org.jetbrains.kotlin.js.translate.context.TranslationContext import org.jetbrains.kotlin.js.translate.context.TranslationContext
@@ -212,11 +210,18 @@ object ConstructorCallCase : FunctionCallCase() {
val arguments = argumentsInfo.getArguments() val arguments = argumentsInfo.getArguments()
val constructorDescriptor = callableDescriptor as ConstructorDescriptor val constructorDescriptor = callableDescriptor as ConstructorDescriptor
val classDescriptor = constructorDescriptor.containingDeclaration
val closure = context.getLocalClassClosure(classDescriptor)
var closureArgs = emptyList<JsExpression>()
if (closure != null) {
closureArgs = closure.asSequence().map { context.getParameterNameRefForInvocation(it) }.toList()
}
if (constructorDescriptor.isPrimary || AnnotationsUtils.isNativeObject(constructorDescriptor)) { if (constructorDescriptor.isPrimary || AnnotationsUtils.isNativeObject(constructorDescriptor)) {
return JsNew(functionRef, arguments) return JsNew(functionRef, closureArgs + arguments)
} }
else { else {
return JsInvocation(functionRef, arguments) return JsInvocation(functionRef, closureArgs + arguments)
} }
} }
} }
@@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -438,9 +438,7 @@ public final class Namer {
return objectCreationMethodReference(); return objectCreationMethodReference();
case ANNOTATION_CLASS: case ANNOTATION_CLASS:
case CLASS: case CLASS:
return DescriptorUtils.isAnonymousObject(descriptor) return classCreationMethodReference();
? objectCreationMethodReference()
: classCreationMethodReference();
default: default:
throw new UnsupportedOperationException("Unsupported class kind: " + descriptor); throw new UnsupportedOperationException("Unsupported class kind: " + descriptor);
} }
@@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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; package org.jetbrains.kotlin.js.translate.context;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import com.google.dart.compiler.backend.js.ast.*; import com.google.dart.compiler.backend.js.ast.*;
import com.google.dart.compiler.backend.js.ast.metadata.HasMetadata; import com.google.dart.compiler.backend.js.ast.metadata.HasMetadata;
@@ -98,6 +99,9 @@ public final class StaticContext {
@NotNull @NotNull
private final Map<JsScope, JsFunction> scopeToFunction = Maps.newHashMap(); private final Map<JsScope, JsFunction> scopeToFunction = Maps.newHashMap();
@NotNull
private final Map<ClassDescriptor, List<DeclarationDescriptor>> localClassesClosure = Maps.newHashMap();
@NotNull @NotNull
private final Config config; private final Config config;
@@ -262,13 +266,17 @@ public final class StaticContext {
@Nullable @Nullable
@Override @Override
public JsName apply(@NotNull DeclarationDescriptor descriptor) { 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<String> parts = new ArrayList<String>(); List<String> parts = new ArrayList<String>();
do { do {
parts.add(descriptor.getName().asString()); parts.add(descriptor.getName().isSpecial() ? "f" : descriptor.getName().getIdentifier());
descriptor = descriptor.getContainingDeclaration(); descriptor = descriptor.getContainingDeclaration();
} while (!(descriptor instanceof ClassOrPackageFragmentDescriptor)); } while (descriptor != null && !(descriptor instanceof ClassOrPackageFragmentDescriptor));
assert descriptor != null;
Collections.reverse(parts); Collections.reverse(parts);
StringBuilder suggestedName = new StringBuilder(parts.get(0)); StringBuilder suggestedName = new StringBuilder(parts.get(0));
@@ -580,10 +588,7 @@ public final class StaticContext {
if (!(descriptor instanceof ClassDescriptor)) { if (!(descriptor instanceof ClassDescriptor)) {
return null; return null;
} }
DeclarationDescriptor container = descriptor.getContainingDeclaration(); DeclarationDescriptor container = getEnclosingNonSingleton(descriptor.getContainingDeclaration());
if (container != null && !(container instanceof ClassDescriptor)) {
container = DescriptorUtils.getContainingClass(container);
}
if (container == null) { if (container == null) {
return null; return null;
} }
@@ -608,7 +613,9 @@ public final class StaticContext {
@Nullable @Nullable
@Override @Override
public JsExpression apply(@NotNull DeclarationDescriptor descriptor) { 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(); descriptor = descriptor.getContainingDeclaration();
while (descriptor != null && !(descriptor instanceof ClassOrPackageFragmentDescriptor)) { 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) { private static JsExpression applySideEffects(JsExpression expression, DeclarationDescriptor descriptor) {
if (expression instanceof HasMetadata) { if (expression instanceof HasMetadata) {
if (descriptor instanceof FunctionDescriptor || if (descriptor instanceof FunctionDescriptor ||
@@ -658,4 +673,14 @@ public final class StaticContext {
addRule(propertiesInClassHaveNoQualifiers); addRule(propertiesInClassHaveNoQualifiers);
} }
} }
public void putLocalClassClosure(@NotNull ClassDescriptor localClass, @NotNull List<DeclarationDescriptor> closure) {
localClassesClosure.put(localClass, Lists.newArrayList(closure));
}
@Nullable
public List<DeclarationDescriptor> getLocalClassClosure(@NotNull ClassDescriptor localClass) {
List<DeclarationDescriptor> result = localClassesClosure.get(localClass);
return result != null ? Lists.newArrayList(result) : null;
}
} }
@@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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 org.jetbrains.kotlin.resolve.DescriptorUtils;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import static org.jetbrains.kotlin.js.translate.context.UsageTrackerKt.getNameForCapturedDescriptor; import static org.jetbrains.kotlin.js.translate.context.UsageTrackerKt.getNameForCapturedDescriptor;
@@ -135,6 +136,13 @@ public class TranslationContext {
this.definitionPlace, descriptor); 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 @NotNull
public TranslationContext innerBlock(@NotNull JsBlock block) { public TranslationContext innerBlock(@NotNull JsBlock block) {
return new TranslationContext(this, staticContext, dynamicContext.innerBlock(block), aliasingContext, usageTracker, null, return new TranslationContext(this, staticContext, dynamicContext.innerBlock(block), aliasingContext, usageTracker, null,
@@ -154,8 +162,7 @@ public class TranslationContext {
@NotNull @NotNull
private TranslationContext innerWithAliasingContext(AliasingContext aliasingContext) { private TranslationContext innerWithAliasingContext(AliasingContext aliasingContext) {
return new TranslationContext(this, this.staticContext, this.dynamicContext, aliasingContext, this.usageTracker, null, return new TranslationContext(this, staticContext, dynamicContext, aliasingContext, usageTracker, null, declarationDescriptor);
this.declarationDescriptor);
} }
@NotNull @NotNull
@@ -414,12 +421,27 @@ public class TranslationContext {
usageTracker.used(descriptor); usageTracker.used(descriptor);
JsName name = getNameForCapturedDescriptor(usageTracker, 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; return null;
} }
private boolean shouldCaptureViaThis() {
if (declarationDescriptor == null) return false;
if (DescriptorUtils.isDescriptorWithLocalVisibility(declarationDescriptor)) {
return !(declarationDescriptor instanceof FunctionDescriptor);
}
return true;
}
@Nullable @Nullable
private static ClassDescriptor getNearestClass(@NotNull DeclarationDescriptor declaration) { private static ClassDescriptor getNearestClass(@NotNull DeclarationDescriptor declaration) {
DeclarationDescriptor decl = declaration; DeclarationDescriptor decl = declaration;
@@ -438,4 +460,26 @@ public class TranslationContext {
public DeclarationDescriptor getDeclarationDescriptor() { public DeclarationDescriptor getDeclarationDescriptor() {
return declarationDescriptor; return declarationDescriptor;
} }
public void putLocalClassClosure(@NotNull ClassDescriptor localClass, @NotNull List<DeclarationDescriptor> closure) {
staticContext.putLocalClassClosure(localClass, closure);
}
@Nullable
public List<DeclarationDescriptor> 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();
}
} }
@@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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 org.jetbrains.kotlin.resolve.DescriptorUtils.isAncestor
import com.google.dart.compiler.backend.js.ast.JsName import com.google.dart.compiler.backend.js.ast.JsName
import org.jetbrains.kotlin.js.translate.utils.ManglingUtils.getSuggestedName 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 import org.jetbrains.kotlin.resolve.DescriptorUtils
private val CAPTURED_RECEIVER_NAME_PREFIX : String = "this$" private val CAPTURED_RECEIVER_NAME_PREFIX : String = "this$"
@@ -28,7 +28,7 @@ private val CAPTURED_RECEIVER_NAME_PREFIX : String = "this$"
class UsageTracker( class UsageTracker(
private val parent: UsageTracker?, private val parent: UsageTracker?,
val containingDescriptor: MemberDescriptor, val containingDescriptor: MemberDescriptor,
private val scope: JsFunctionScope private val scope: JsScope
) { ) {
private val captured = linkedMapOf<DeclarationDescriptor, JsName>() private val captured = linkedMapOf<DeclarationDescriptor, JsName>()
@@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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.DefinitionPlace
import org.jetbrains.kotlin.js.translate.context.Namer import org.jetbrains.kotlin.js.translate.context.Namer
import org.jetbrains.kotlin.js.translate.context.TranslationContext 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.FunctionTranslator
import org.jetbrains.kotlin.js.translate.expression.withCapturedParameters
import org.jetbrains.kotlin.js.translate.general.AbstractTranslator import org.jetbrains.kotlin.js.translate.general.AbstractTranslator
import org.jetbrains.kotlin.js.translate.initializer.ClassInitializerTranslator import org.jetbrains.kotlin.js.translate.initializer.ClassInitializerTranslator
import org.jetbrains.kotlin.js.translate.reference.ReferenceTranslator.translateAsFQReference 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.KtObjectDeclaration
import org.jetbrains.kotlin.psi.KtSecondaryConstructor import org.jetbrains.kotlin.psi.KtSecondaryConstructor
import org.jetbrains.kotlin.resolve.BindingContextUtils import org.jetbrains.kotlin.resolve.BindingContextUtils
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.DescriptorUtils.* import org.jetbrains.kotlin.resolve.DescriptorUtils.*
import org.jetbrains.kotlin.types.CommonSupertypes.topologicallySortSuperclassesAndRecordAllInstances import org.jetbrains.kotlin.types.CommonSupertypes.topologicallySortSuperclassesAndRecordAllInstances
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
@@ -64,9 +65,10 @@ class ClassTranslator private constructor(
private val descriptor = getClassDescriptor(context.bindingContext(), classDeclaration) private val descriptor = getClassDescriptor(context.bindingContext(), classDeclaration)
private fun translateObjectLiteralExpression(): JsExpression { private fun translateObjectLiteralExpression(): JsExpression {
getContainingClass(descriptor) ?: return translate(context()) return if (descriptor.containingDeclaration is ClassDescriptor && descriptor.kind == ClassKind.OBJECT)
translateObjectInsideClass(context())
return translateObjectInsideClass(context()) else
translate(context())
} }
private fun translate(declarationContext: TranslationContext = context()): JsInvocation { private fun translate(declarationContext: TranslationContext = context()): JsInvocation {
@@ -82,28 +84,19 @@ class ClassTranslator private constructor(
val properties = SmartList<JsPropertyInitializer>() val properties = SmartList<JsPropertyInitializer>()
val staticProperties = SmartList<JsPropertyInitializer>() val staticProperties = SmartList<JsPropertyInitializer>()
val isTopLevelDeclaration = context() == context val qualifiedReference = context.getQualifiedReference(descriptor)
val scope = context().getScopeForDescriptor(descriptor)
var qualifiedReference: JsNameRef? = null val definitionPlace = DefinitionPlace(scope as JsObjectScope, qualifiedReference, staticProperties)
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)
}
context = context.newDeclaration(descriptor, definitionPlace)
context = fixContextForCompanionObjectAccessing(context) context = fixContextForCompanionObjectAccessing(context)
invocationArguments.add(getSuperclassReferences(context)) invocationArguments.add(getSuperclassReferences(context))
val delegationTranslator = DelegationTranslator(classDeclaration, context()) val delegationTranslator = DelegationTranslator(classDeclaration, context())
var initializer: JsFunction? = null
if (!isTrait()) { if (!isTrait()) {
val initializer = ClassInitializerTranslator(classDeclaration, context).generateInitializeMethod(delegationTranslator) initializer = ClassInitializerTranslator(classDeclaration, context).generateInitializeMethod(delegationTranslator)
invocationArguments.add(if (initializer.body.statements.isEmpty()) JsLiteral.NULL else initializer) invocationArguments.add(initializer)
} }
translatePropertiesAsConstructorParameters(context, properties) translatePropertiesAsConstructorParameters(context, properties)
@@ -129,10 +122,8 @@ class ClassTranslator private constructor(
invocationArguments.add(JsLiteral.NULL) invocationArguments.add(JsLiteral.NULL)
} }
else { else {
if (qualifiedReference != null) { // about "prototype" - see http://code.google.com/p/jsdoc-toolkit/wiki/TagLends
// 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(JsDocComment(JsAstUtils.LENDS_JS_DOC_TAG, JsNameRef("prototype", qualifiedReference)))
}
invocationArguments.add(JsObjectLiteral(properties, true)) invocationArguments.add(JsObjectLiteral(properties, true))
} }
} }
@@ -141,6 +132,22 @@ class ClassTranslator private constructor(
invocationArguments.add(JsObjectLiteral(staticProperties, true)) 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 return invocationArguments
} }
@@ -214,12 +221,30 @@ class ClassTranslator private constructor(
} }
private fun translateObjectInsideClass(outerClassContext: TranslationContext): JsExpression { private fun translateObjectInsideClass(outerClassContext: TranslationContext): JsExpression {
val function = JsFunction(outerClassContext.scope(), JsBlock(), "initializer for " + descriptor.name.asString()) var outerDeclaration = descriptor.containingDeclaration.containingDeclaration
val funContext = outerClassContext.newFunctionBodyWithUsageTracker(function, descriptor) 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<JsExpression>()
if (closure != null) {
closureArgs = closure.map { context().getParameterNameRefForInvocation(it) }.toList()
}
return JsNew(constructor, closureArgs)
} }
private fun generatedBridgeMethods(properties: MutableList<JsPropertyInitializer>) { private fun generatedBridgeMethods(properties: MutableList<JsPropertyInitializer>) {
@@ -289,6 +314,10 @@ class ClassTranslator private constructor(
} }
@JvmStatic fun generateObjectLiteral(objectDeclaration: KtObjectDeclaration, context: TranslationContext): JsExpression { @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() return ClassTranslator(objectDeclaration, context).translateObjectLiteralExpression()
} }
@@ -518,8 +518,7 @@ public final class ExpressionVisitor extends TranslatorVisitor<JsNode> {
@Override @Override
@NotNull @NotNull
public JsNode visitObjectLiteralExpression(@NotNull KtObjectLiteralExpression expression, public JsNode visitObjectLiteralExpression(@NotNull KtObjectLiteralExpression expression, @NotNull TranslationContext context) {
@NotNull TranslationContext context) {
return ClassTranslator.generateObjectLiteral(expression.getObjectDeclaration(), context); return ClassTranslator.generateObjectLiteral(expression.getObjectDeclaration(), context);
} }
@@ -569,8 +568,12 @@ public final class ExpressionVisitor extends TranslatorVisitor<JsNode> {
@Override @Override
public JsNode visitClass(@NotNull KtClass klass, TranslationContext context) { public JsNode visitClass(@NotNull KtClass klass, TranslationContext context) {
JsInvocation jsClass = ClassTranslator.generateClassCreation(klass, context); ClassDescriptor descriptor = BindingUtils.getClassDescriptor(context.bindingContext(), klass);
DeclarationDescriptor 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); JsName name = context.getNameForDescriptor(descriptor);
return context.define(name, jsClass); return context.define(name, jsClass);
} }
@@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -64,7 +64,7 @@ public final class InitializerUtils {
@NotNull List<JsStatement> initializers, @NotNull List<JsStatement> initializers,
@NotNull TranslationContext context @NotNull TranslationContext context
) { ) {
JsExpression value = ClassTranslator.generateObjectLiteral(declaration, context); JsExpression value = ClassTranslator.generateObjectDeclaration(declaration, context);
ClassDescriptor descriptor = getClassDescriptor(context.bindingContext(), declaration); ClassDescriptor descriptor = getClassDescriptor(context.bindingContext(), declaration);
JsExpression expression = assignment(new JsNameRef(descriptor.getName().asString(), JsLiteral.THIS), value); JsExpression expression = assignment(new JsNameRef(descriptor.getName().asString(), JsLiteral.THIS), value);
initializers.add(expression.makeStmt()); initializers.add(expression.makeStmt());
+12 -3
View File
@@ -22,7 +22,16 @@ class C {
} }
} }
fun box() = A.query.status == "complete" && B.query.status == "completed" fun box(): String {
// todo fix after KT-3868 will be fixed var result = A.query.status
// && C.query.status == "completed" 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"
}