KT-11030 Implements closures in classes. Represent local object literals as classes
This commit is contained in:
@@ -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 {
|
||||||
|
|||||||
+11
-6
@@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+48
-4
@@ -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>()
|
||||||
|
|||||||
+58
-29
@@ -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()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+7
-4
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -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
@@ -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"
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user