KT-11030 Minor code improvements

This commit is contained in:
Alexey Andreev
2016-04-13 11:08:33 +03:00
parent 166b985fca
commit 87ea0bd0cb
14 changed files with 185 additions and 152 deletions
@@ -171,4 +171,18 @@ public final class ClosureTest extends SingleFileTranslationTest {
public void testLocalConstructorAndMethod() throws Exception {
checkFooBoxIsOk();
}
// TODO: tests UsageTracker but encounters issue somewhere else. Uncomment when issue with `this` generation gets fixed
// Presumably, KT-11823
/*public void testDeepInnerClassInLocalClass() throws Exception {
checkFooBoxIsOk();
}
public void testDeepInnerClassInLocalClassFromExtension() throws Exception {
checkFooBoxIsOk();
}*/
public void testImplicitGenericReceiverInExtensionInLocalClass() throws Exception {
checkFooBoxIsOk();
}
}
@@ -210,11 +210,8 @@ object ConstructorCallCase : FunctionCallCase() {
val arguments = argumentsInfo.getArguments()
val constructorDescriptor = callableDescriptor as ConstructorDescriptor
val closure = context.getLocalClassClosure(constructorDescriptor)
var closureArgs = emptyList<JsExpression>()
if (closure != null) {
closureArgs = closure.asSequence().map { context.getParameterNameRefForInvocation(it) }.toList()
}
val closure = context.getClassOrConstructorClosure(constructorDescriptor)
val closureArgs = closure?.map { context.getParameterNameRefForInvocation(it) } ?: emptyList()
if (constructorDescriptor.isPrimary || AnnotationsUtils.isNativeObject(constructorDescriptor)) {
return JsNew(functionRef, closureArgs + arguments)
@@ -46,6 +46,7 @@ import static org.jetbrains.kotlin.js.translate.utils.JsAstUtils.fqnWithoutSideE
import static org.jetbrains.kotlin.js.translate.utils.JsDescriptorUtils.*;
import static org.jetbrains.kotlin.js.translate.utils.ManglingUtils.getMangledName;
import static org.jetbrains.kotlin.js.translate.utils.ManglingUtils.getSuggestedName;
import static org.jetbrains.kotlin.resolve.DescriptorUtils.getParentOfType;
import static org.jetbrains.kotlin.resolve.DescriptorUtils.isCompanionObject;
import static org.jetbrains.kotlin.resolve.DescriptorUtils.isExtension;
import static org.jetbrains.kotlin.resolve.calls.tasks.DynamicCallsKt.isDynamic;
@@ -252,7 +253,7 @@ public final class StaticContext {
}
};
Rule<JsName> localDeclarations = new Rule<JsName>() {
Rule<JsName> localClasses = new Rule<JsName>() {
@Nullable
@Override
public JsName apply(@NotNull DeclarationDescriptor descriptor) {
@@ -263,9 +264,7 @@ public final class StaticContext {
String suggested = getSuggestedName(descriptor);
do {
descriptor = descriptor.getContainingDeclaration();
} while (descriptor != null && !(descriptor instanceof ClassOrPackageFragmentDescriptor));
descriptor = getParentOfType(descriptor, ClassOrPackageFragmentDescriptor.class, true);
assert descriptor != null;
JsScope scope = getScopeForDescriptor(descriptor);
@@ -291,7 +290,7 @@ public final class StaticContext {
return scope.declareFreshName(getSuggestedName(descriptor));
}
};
Rule<JsName> constructorOrCompanionObjectHasTheSameNameAsTheClass = new Rule<JsName>() {
Rule<JsName> constructorOrNativeCompanionObjectHasTheSameNameAsTheClass = new Rule<JsName>() {
@Override
public JsName apply(@NotNull DeclarationDescriptor descriptor) {
if (descriptor instanceof ConstructorDescriptor && ((ConstructorDescriptor) descriptor).isPrimary() ||
@@ -385,9 +384,9 @@ public final class StaticContext {
};
addRule(namesForDynamic);
addRule(localDeclarations);
addRule(localClasses);
addRule(namesForStandardClasses);
addRule(constructorOrCompanionObjectHasTheSameNameAsTheClass);
addRule(constructorOrNativeCompanionObjectHasTheSameNameAsTheClass);
addRule(propertyOrPropertyAccessor);
addRule(predefinedObjectsHasUnobfuscatableNames);
addRule(overridingDescriptorsReferToOriginalName);
@@ -573,7 +572,7 @@ public final class StaticContext {
if (!(descriptor instanceof ClassDescriptor)) {
return null;
}
DeclarationDescriptor container = getEnclosing(descriptor.getContainingDeclaration());
DeclarationDescriptor container = getParentOfType(descriptor, ClassDescriptor.class);
if (container == null) {
return null;
}
@@ -593,12 +592,8 @@ public final class StaticContext {
return null;
}
descriptor = descriptor.getContainingDeclaration();
while (descriptor != null && !(descriptor instanceof ClassOrPackageFragmentDescriptor)) {
descriptor = descriptor.getContainingDeclaration();
}
if (!(descriptor instanceof PackageFragmentDescriptor)) return null;
descriptor = getParentOfType(descriptor, PackageFragmentDescriptor.class, true);
assert descriptor != null;
return getQualifiedReference(descriptor);
}
};
@@ -614,14 +609,6 @@ public final class StaticContext {
}
}
@Nullable
private static ClassDescriptor getEnclosing(@Nullable DeclarationDescriptor descriptor) {
while (descriptor != null && !(descriptor instanceof ClassDescriptor)) {
descriptor = descriptor.getContainingDeclaration();
}
return (ClassDescriptor) descriptor;
}
private static JsExpression applySideEffects(JsExpression expression, DeclarationDescriptor descriptor) {
if (expression instanceof HasMetadata) {
if (descriptor instanceof FunctionDescriptor ||
@@ -650,13 +637,13 @@ public final class StaticContext {
}
}
public void putLocalClassClosure(@NotNull MemberDescriptor localClass, @NotNull List<DeclarationDescriptor> closure) {
public void putClassOrConstructorClosure(@NotNull MemberDescriptor localClass, @NotNull List<DeclarationDescriptor> closure) {
localClassesClosure.put(localClass, Lists.newArrayList(closure));
}
@Nullable
public List<DeclarationDescriptor> getLocalClassClosure(@NotNull MemberDescriptor localClass) {
List<DeclarationDescriptor> result = localClassesClosure.get(localClass);
public List<DeclarationDescriptor> getClassOrConstructorClosure(@NotNull MemberDescriptor descriptor) {
List<DeclarationDescriptor> result = localClassesClosure.get(descriptor);
return result != null ? Lists.newArrayList(result) : null;
}
}
@@ -356,11 +356,17 @@ public class TranslationContext {
if (descriptor.getValue() instanceof ExtensionReceiver) return JsLiteral.THIS;
ClassifierDescriptor classifier = descriptor.getValue().getType().getConstructor().getDeclarationDescriptor();
if (!(classifier instanceof ClassDescriptor)) return JsLiteral.THIS;
// TODO: can't tell why this assertion is valid, revisit this code later
assert classifier instanceof ClassDescriptor;
ClassDescriptor cls = (ClassDescriptor) classifier;
JsExpression receiver = getAliasForDescriptor(cls.getThisAsReceiverParameter());
// I could reproduce situation when receiver == null, although there's no test to reproduce it. Have no time for investigation
// Hint: try generating field with getter/setter, see deepInnerClassInLocalClass.kt
// TODO: revisit this code later
if (receiver == null) {
receiver = JsLiteral.THIS;
}
@@ -447,15 +453,15 @@ public class TranslationContext {
return declarationDescriptor;
}
public void putLocalClassClosure(@NotNull MemberDescriptor localClass, @NotNull List<DeclarationDescriptor> closure) {
staticContext.putLocalClassClosure(localClass, closure);
public void putClassOrConstructorClosure(@NotNull MemberDescriptor descriptor, @NotNull List<DeclarationDescriptor> closure) {
staticContext.putClassOrConstructorClosure(descriptor, closure);
}
@Nullable
public List<DeclarationDescriptor> getLocalClassClosure(@NotNull MemberDescriptor localClass) {
List<DeclarationDescriptor> result = staticContext.getLocalClassClosure(localClass);
public List<DeclarationDescriptor> getClassOrConstructorClosure(@NotNull MemberDescriptor localClass) {
List<DeclarationDescriptor> result = staticContext.getClassOrConstructorClosure(localClass);
if (result == null && localClass instanceof ConstructorDescriptor && ((ConstructorDescriptor) localClass).isPrimary()) {
result = staticContext.getLocalClassClosure((ClassDescriptor) localClass.getContainingDeclaration());
result = staticContext.getClassOrConstructorClosure((ClassDescriptor) localClass.getContainingDeclaration());
}
return result;
}
@@ -17,13 +17,11 @@
package org.jetbrains.kotlin.js.translate.context
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.JsScope
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.DescriptorUtils.getParentOfType
import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitReceiver
import org.jetbrains.kotlin.resolve.DescriptorUtils.*
private val CAPTURED_RECEIVER_NAME_PREFIX : String = "this$"
@@ -64,14 +62,23 @@ class UsageTracker(
}
private fun captureIfNeed(descriptor: DeclarationDescriptor?) {
if (descriptor == null || isCaptured(descriptor) || isAncestor(containingDescriptor, descriptor, /* strict = */ true) ||
isReceiverAncestor(descriptor) || isSingletonReceiver(descriptor)) return
if (descriptor == null || isCaptured(descriptor) || !isInLocalDeclaration() ||
isAncestor(containingDescriptor, descriptor, /* strict = */ true) ||
isReceiverAncestor(descriptor) || isSingletonReceiver(descriptor)
) {
return
}
parent?.captureIfNeed(descriptor)
captured[descriptor] = descriptor.getJsNameForCapturedDescriptor()
}
private fun isInLocalDeclaration(): Boolean {
val container = containingDescriptor
return isDescriptorWithLocalVisibility(if (container is ConstructorDescriptor) container.containingDeclaration else container)
}
/**
* We shouldn't capture current `this` or outer `this`. Assuming `C` is current translating class,
* we have `descriptor == A::this` in the following cases:
@@ -92,10 +99,10 @@ class UsageTracker(
*/
private fun isReceiverAncestor(descriptor: DeclarationDescriptor): Boolean {
if (descriptor !is ReceiverParameterDescriptor) return false
if (containingDescriptor !is ClassDescriptor && DescriptorUtils.isDescriptorWithLocalVisibility(containingDescriptor)) return false
if (containingDescriptor !is ClassDescriptor && containingDescriptor !is ConstructorDescriptor) return false
val currentClass = DescriptorUtils.getClassDescriptorForType(descriptor.type)
val containingClass = getParentOfType(containingDescriptor, ClassDescriptor::class.java, false) ?: return false
val currentClass = descriptor.containingDeclaration as? ClassDescriptor ?: return false
for (outerDeclaration in generateSequence(containingClass) { it.containingDeclaration as? ClassDescriptor }) {
if (DescriptorUtils.isSubclass(outerDeclaration, currentClass)) return true
@@ -124,19 +131,17 @@ class UsageTracker(
private fun isSingletonReceiver(descriptor: DeclarationDescriptor): Boolean {
if (descriptor !is ReceiverParameterDescriptor) return false
val value = descriptor.value
if (value !is ImplicitReceiver) return false
if (!DescriptorUtils.isObject(value.declarationDescriptor)) return false
val container = descriptor.containingDeclaration
if (!DescriptorUtils.isObject(container)) return false
// This is workaround, since sometimes translator generates wrong expression for `this` expressions.
// Presumably, it's related to KT-11823
// TODO: remove when issue gets fixed.
if (containingDescriptor == value.declarationDescriptor) return false
if (containingDescriptor == container) return false
if (containingDescriptor !is ClassDescriptor) {
val containingClass = getParentOfType(containingDescriptor, ClassDescriptor::class.java, false);
if (containingClass == value.declarationDescriptor) return false
if (containingClass == container) return false
}
return true
@@ -46,6 +46,7 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils.*
import org.jetbrains.kotlin.types.CommonSupertypes.topologicallySortSuperclassesAndRecordAllInstances
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeConstructor
import org.jetbrains.kotlin.utils.DFS
import org.jetbrains.kotlin.utils.identity
/**
@@ -63,9 +64,8 @@ class ClassTranslator private constructor(
private var primaryConstructor: ConstructorInfo? = null
private lateinit var definitionPlace: DefinitionPlace
fun translate(): TranslationResult {
invocationArguments.clear()
getClassCreateInvocationArguments()
private fun translate(): TranslationResult {
generateClassCreateInvocationArguments()
val classNameRef = context().getNameForDescriptor(descriptor).makeRef()
val classCreation = JsInvocation(context().namer().classCreateInvocation(descriptor), invocationArguments)
@@ -76,16 +76,14 @@ class ClassTranslator private constructor(
private fun isTrait(): Boolean = descriptor.kind == ClassKind.INTERFACE
private fun getClassCreateInvocationArguments() {
var context = context()
private fun generateClassCreateInvocationArguments() {
val properties = SmartList<JsPropertyInitializer>()
val staticProperties = SmartList<JsPropertyInitializer>()
val qualifiedReference = context.getQualifiedReference(descriptor)
val qualifiedReference = context().getQualifiedReference(descriptor)
val scope = context().getScopeForDescriptor(descriptor)
val definitionPlace = DefinitionPlace(scope as JsObjectScope, qualifiedReference, staticProperties)
context = context.newDeclaration(descriptor, definitionPlace)
val context = context().newDeclaration(descriptor, definitionPlace)
invocationArguments += getSuperclassReferences(context)
@@ -96,16 +94,14 @@ class ClassTranslator private constructor(
bodyVisitor.traverseContainer(classDeclaration, nonConstructorContext)
delegationTranslator.generateDelegated(properties)
var enumFunction: JsFunction? = null
if (isEnumClass(descriptor)) {
val enumEntries = JsObjectLiteral(bodyVisitor.enumEntryList, true)
enumFunction = simpleReturnFunction(nonConstructorContext.getScopeForDescriptor(descriptor), enumEntries)
}
translatePrimaryConstructor(context, delegationTranslator)
classDeclaration.getSecondaryConstructors().forEach { generateSecondaryConstructor(context, it) }
generatedBridgeMethods(properties)
enumFunction?.let { invocationArguments += it }
if (isEnumClass(descriptor)) {
val enumEntries = JsObjectLiteral(bodyVisitor.enumEntryList, true)
invocationArguments += simpleReturnFunction(nonConstructorContext.getScopeForDescriptor(descriptor), enumEntries)
}
val dataClassGenerator = JsDataClassGenerator(classDeclaration, context, properties)
@@ -118,6 +114,12 @@ class ClassTranslator private constructor(
dataClassGenerator.generate()
}
// ExpressionVisitor.visitObjectLiteralExpression uses DefinitionPlace of the translated class to generate call to
// super constructor. Sometimes, when generating super call, we may translate another anonymous class passed as an
// argument. This class will be declared in the DefinitionPlace and put it static properties. See full explanation
// in ExpressionVisitor.visitObjectLiteralExpression
// TODO: It's a hack, we should think how to generate staticProperties lazily, whenever somebody tries to put
// definition into DefinitionPlace.
val hasStaticProperties = !staticProperties.isEmpty() || DescriptorUtils.isAnonymousObject(descriptor)
if (!properties.isEmpty() || hasStaticProperties) {
if (properties.isEmpty()) {
@@ -144,7 +146,7 @@ class ClassTranslator private constructor(
if (isTrait()) return
val scope = JsFunctionScope(classContext.scope(), "$descriptor: primary constructor")
var constructorContext = classContext.innerWithUsageTracker(scope, descriptor)
val constructorContext = classContext.innerWithUsageTracker(scope, descriptor)
val initializer = ClassInitializerTranslator(classDeclaration, constructorContext).generateInitializeMethod(delegationTranslator)
invocationArguments += initializer
@@ -157,21 +159,20 @@ class ClassTranslator private constructor(
val classDescriptor = constructorDescriptor.containingDeclaration
val constructorScope = classContext.getScopeForDescriptor(constructorDescriptor)
var context = classContext.innerWithUsageTracker(constructorScope, constructorDescriptor)
val thisName = constructorScope.declareName(Namer.ANOTHER_THIS_PARAMETER_NAME)
val thisNameRef = thisName.makeRef()
val receiverDescriptor = classDescriptor.thisAsReceiverParameter
context = context.newDeclaration(constructorDescriptor.containingDeclaration, context.definitionPlace)
context = context.newDeclaration(constructorDescriptor, context.definitionPlace)
context = context.innerContextWithAliased(receiverDescriptor, thisNameRef)
var context = classContext
.innerWithUsageTracker(constructorScope, constructorDescriptor)
.innerContextWithAliased(receiverDescriptor, thisNameRef)
val outerName = context.getOuterClassReference(classDescriptor);
val outerClassName = context.getOuterClassReference(classDescriptor);
val outerClass = DescriptorUtils.getContainingClass(classDescriptor)
if (outerClass != null && outerName != null) {
val outerClassRef = outerClass.thisAsReceiverParameter
context = context.innerContextWithAliased(outerClassRef, outerName.makeRef())
if (outerClassName != null) {
val outerClassReceiver = outerClass!!.thisAsReceiverParameter
context = context.innerContextWithAliased(outerClassReceiver, outerClassName.makeRef())
}
// Translate constructor body
@@ -191,9 +192,9 @@ class ClassTranslator private constructor(
// Add parameter for outer instance
val leadingArgs = mutableListOf<JsExpression>()
if (outerName != null) {
constructorFunction.parameters.add(0, JsParameter(outerName))
leadingArgs += outerName.makeRef()
if (outerClassName != null) {
constructorFunction.parameters.add(0, JsParameter(outerClassName))
leadingArgs += outerClassName.makeRef()
}
constructorFunction.parameters += JsParameter(thisName)
@@ -212,8 +213,8 @@ class ClassTranslator private constructor(
if (!delegationCtorInTheSameClass && !classDescriptor.hasPrimaryConstructor()) {
superCallGenerators += {
val usageTracker = context.usageTracker()!!
val closure = context.getLocalClassClosure(classDescriptor).orEmpty().map {
usageTracker.capturedDescriptorToJsName[it]?.makeRef() as? JsExpression ?: JsLiteral.NULL
val closure = context.getClassOrConstructorClosure(classDescriptor).orEmpty().map {
usageTracker.getNameForCapturedDescriptor(it)!!.makeRef()
}
it += JsInvocation(Namer.getFunctionCallRef(referenceToClass), listOf(thisNameRef) + closure + leadingArgs).makeStmt()
}
@@ -242,9 +243,8 @@ class ClassTranslator private constructor(
private fun emitConstructors(nonConstructorContext: TranslationContext) {
// Build map that maps constructor to all constructors called via this()
val constructorMap = allConstructors.map { it.descriptor to it }.toMap()
val primaryConstructor = this.primaryConstructor
val thisCalls = allConstructors.map {
val thisCalls = secondaryConstructors.map {
val set = mutableSetOf<ConstructorInfo>()
val descriptor = it.descriptor
if (descriptor is ConstructorDescriptor) {
@@ -256,72 +256,46 @@ class ClassTranslator private constructor(
}
}
}
if (primaryConstructor != null && primaryConstructor != it) {
set += primaryConstructor
}
Pair(it, set)
}.toMap()
// Sort graph of constructors
val sortedConstructors = mutableListOf<ConstructorInfo>()
val visitedConstructors = mutableSetOf<ConstructorInfo>()
fun sort(constructor: ConstructorInfo) {
if (!visitedConstructors.add(constructor)) return
sortedConstructors += constructor
for (thisCall in thisCalls[constructor].orEmpty()) {
sort(thisCall)
}
}
allConstructors.forEach(::sort)
// Emit constructors
val sortedConstructors = DFS.topologicalOrder(allConstructors.asIterable()) { thisCalls[it].orEmpty() }.reversed()
for (constructor in sortedConstructors) {
constructor.superCallGenerator()
val nonConstructorUsageTracker = nonConstructorContext.usageTracker()!!
val usageTracker = constructor.context.usageTracker() ?: continue
val usageTracker = constructor.context.usageTracker()!!
val nonConstructorCapturedVars = nonConstructorUsageTracker.capturedDescriptors
val constructorCapturedVars = usageTracker.capturedDescriptors
val capturedVars = (nonConstructorCapturedVars.asSequence() +
constructorCapturedVars.asSequence().filter { it !in nonConstructorCapturedVars }).toList()
val capturedVars = (nonConstructorCapturedVars + constructorCapturedVars).distinct()
val descriptor = constructor.descriptor
nonConstructorContext.putLocalClassClosure(descriptor, capturedVars)
if (descriptor is ClassDescriptor) {
if (primaryConstructor != null) {
nonConstructorContext.putLocalClassClosure(primaryConstructor.descriptor, capturedVars)
}
}
for (thisCall in thisCalls[constructor].orEmpty()) {
val callUsageTracker = thisCall.context.usageTracker() ?: continue
callUsageTracker.capturedDescriptors.forEach { usageTracker.used(it) }
}
nonConstructorContext.putClassOrConstructorClosure(descriptor, capturedVars)
}
}
private fun addClosureParameters(constructor: ConstructorInfo, nonConstructorContext: TranslationContext,
dataClassGenerator: JsDataClassGenerator) {
val usageTracker = constructor.context.usageTracker()!!
val capturedVars = context().getLocalClassClosure(constructor.descriptor) ?: return
val capturedVars = context().getClassOrConstructorClosure(constructor.descriptor) ?: return
val nonConstructorUsageTracker = nonConstructorContext.usageTracker()!!
val function = constructor.function
val additionalStatements = mutableListOf<JsStatement>()
for ((i, capturedVar) in capturedVars.withIndex()) {
val fieldName = nonConstructorUsageTracker.capturedDescriptorToJsName[capturedVar]
val name = usageTracker.capturedDescriptorToJsName[capturedVar] ?: fieldName!!
function.parameters.add(i, JsParameter(name))
if (fieldName != null && constructor == primaryConstructor) {
function.body.statements.add(i, JsAstUtils.defineSimpleProperty(fieldName.ident, name.makeRef()))
additionalStatements += JsAstUtils.defineSimpleProperty(fieldName.ident, name.makeRef())
dataClassGenerator.addClosureVariable(fieldName)
}
}
function.body.statements.addAll(0, additionalStatements);
}
private fun getSuperclassReferences(declarationContext: TranslationContext): JsExpression {
@@ -62,7 +62,7 @@ public class DeclarationBodyVisitor extends TranslatorVisitor<Void> {
}
@Override
public Void visitClass(@NotNull KtClass declaration, TranslationContext context) {
public Void visitClassOrObject(@NotNull KtClassOrObject declaration, TranslationContext context) {
staticResult.addAll(ClassTranslator.translate(declaration, context).getProperties());
return null;
}
@@ -82,12 +82,6 @@ public class DeclarationBodyVisitor extends TranslatorVisitor<Void> {
return null;
}
@Override
public Void visitObjectDeclaration(@NotNull KtObjectDeclaration declaration, TranslationContext context) {
staticResult.addAll(ClassTranslator.translate(declaration, context).getProperties());
return null;
}
@Override
public Void visitNamedFunction(@NotNull KtNamedFunction expression, TranslationContext context) {
FunctionDescriptor descriptor = getFunctionDescriptor(context.bindingContext(), expression);
@@ -26,10 +26,7 @@ import org.jetbrains.kotlin.js.translate.initializer.InitializerUtils.generateIn
import org.jetbrains.kotlin.js.translate.initializer.InitializerVisitor
import org.jetbrains.kotlin.js.translate.utils.BindingUtils.getPropertyDescriptor
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils
import org.jetbrains.kotlin.psi.KtClass
import org.jetbrains.kotlin.psi.KtAnonymousInitializer
import org.jetbrains.kotlin.psi.KtObjectDeclaration
import org.jetbrains.kotlin.psi.KtProperty
import org.jetbrains.kotlin.psi.*
class FileDeclarationVisitor(
val context: TranslationContext,
@@ -49,20 +46,11 @@ class FileDeclarationVisitor(
}
}
override fun visitClass(declaration: KtClass, context: TranslationContext?): Void? {
override fun visitClassOrObject(declaration: KtClassOrObject, context: TranslationContext?): Void? {
result += ClassTranslator.translate(declaration, context!!).properties
return null
}
override fun visitObjectDeclaration(declaration: KtObjectDeclaration, context: TranslationContext?): Void? {
context!!
// TODO: avoid duplication with superclass
result += ClassTranslator.translate(declaration, context).properties
return null
}
override fun visitProperty(expression: KtProperty, context: TranslationContext?): Void? {
context!! // hack
@@ -522,15 +522,12 @@ public final class ExpressionVisitor extends TranslatorVisitor<JsNode> {
@NotNull
public JsNode visitObjectLiteralExpression(@NotNull KtObjectLiteralExpression expression, @NotNull TranslationContext context) {
ClassDescriptor descriptor = BindingUtils.getClassDescriptor(context.bindingContext(), expression.getObjectDeclaration());
JsScope scope = context.getScopeForDescriptor(descriptor);
TranslationContext classContext = context.innerWithUsageTracker(scope, descriptor);
ClassTranslator.TranslationResult result = ClassTranslator.translate(expression.getObjectDeclaration(), classContext);
ClassTranslator.TranslationResult result = translateClassOrObject(expression.getObjectDeclaration(), descriptor, context);
List<JsPropertyInitializer> properties = result.getProperties();
context.getDefinitionPlace().getProperties().addAll(properties);
JsExpression constructor = context.getQualifiedReference(descriptor);
List<DeclarationDescriptor> closure = context.getLocalClassClosure(descriptor);
List<DeclarationDescriptor> closure = context.getClassOrConstructorClosure(descriptor);
List<JsExpression> closureArgs = new ArrayList<JsExpression>();
if (closure != null) {
for (DeclarationDescriptor capturedValue : closure) {
@@ -601,11 +598,17 @@ public final class ExpressionVisitor extends TranslatorVisitor<JsNode> {
@Override
public JsNode visitClass(@NotNull KtClass klass, TranslationContext context) {
ClassDescriptor descriptor = BindingUtils.getClassDescriptor(context.bindingContext(), klass);
JsScope scope = context.getScopeForDescriptor(descriptor);
TranslationContext classContext = context.innerWithUsageTracker(scope, descriptor);
context.getDefinitionPlace().getProperties().addAll(ClassTranslator.translate(klass, classContext).getProperties());
context.getDefinitionPlace().getProperties().addAll(translateClassOrObject(klass, descriptor, context).getProperties());
return JsEmpty.INSTANCE;
}
private static ClassTranslator.TranslationResult translateClassOrObject(
@NotNull KtClassOrObject declaration,
@NotNull ClassDescriptor descriptor,
@NotNull TranslationContext context
) {
JsScope scope = context.getScopeForDescriptor(descriptor);
TranslationContext classContext = context.innerWithUsageTracker(scope, descriptor);
return ClassTranslator.translate(declaration, classContext);
}
}
@@ -27,7 +27,6 @@ import org.jetbrains.kotlin.js.translate.context.UsageTracker;
import org.jetbrains.kotlin.js.translate.declaration.DelegationTranslator;
import org.jetbrains.kotlin.js.translate.general.AbstractTranslator;
import org.jetbrains.kotlin.js.translate.reference.CallArgumentTranslator;
import org.jetbrains.kotlin.js.translate.utils.BindingUtils;
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils;
import org.jetbrains.kotlin.js.translate.utils.jsAstUtils.AstUtilsKt;
import org.jetbrains.kotlin.lexer.KtTokens;
@@ -149,7 +148,7 @@ public final class ClassInitializerTranslator extends AbstractTranslator {
return;
}
if (hasAncestorClass(bindingContext(), classDeclaration)) {
ResolvedCall<FunctionDescriptor> superCall = BindingUtils.getSuperCall(bindingContext(), classDeclaration);
ResolvedCall<FunctionDescriptor> superCall = getSuperCall(bindingContext(), classDeclaration);
if (superCall == null) return;
if (classDeclaration instanceof KtEnumEntry) {
@@ -163,9 +162,11 @@ public final class ClassInitializerTranslator extends AbstractTranslator {
ConstructorDescriptor superDescriptor = (ConstructorDescriptor) superCall.getResultingDescriptor();
List<DeclarationDescriptor> superclassClosure = context.getLocalClassClosure(superDescriptor);
UsageTracker tracker = context.usageTracker();
if (superclassClosure != null && tracker != null) {
List<DeclarationDescriptor> superclassClosure = context.getClassOrConstructorClosure(superDescriptor);
if (superclassClosure != null) {
UsageTracker tracker = context.usageTracker();
assert tracker != null : "Closure exists, therefore UsageTracker must exist too. Translating constructor of " +
descriptor;
for (DeclarationDescriptor capturedValue : superclassClosure) {
tracker.used(capturedValue);
arguments.add(tracker.getCapturedDescriptorToJsName().get(capturedValue).makeRef());
@@ -85,7 +85,8 @@ public class ManglingUtils {
}
Collections.reverse(parts);
return StringUtil.join(parts, "$") + "$";
String result = StringUtil.join(parts, "$");
return !result.isEmpty() ? result + "$" : "";
}
@NotNull
@@ -0,0 +1,23 @@
package foo
class A() {
fun test(): Int {
open class B(open val x: Int) {
inner class C(override val x: Int) : B(x * 10) {
inner class D() {
var baz: () -> Int = { 0 }
constructor(b: Boolean) : this() {
baz = { x + this@B.x }
}
fun bar() = { x + this@B.x }
}
}
}
return B(3).C(2).D().bar()() + B(5).C(4).D(true).baz()
}
}
fun box(): String {
assertEquals(2345, A().test())
return "OK"
}
@@ -0,0 +1,23 @@
package foo
class A() {
fun test(): Int {
open class B(open val x: Int) {
inner class C(override val x: Int) : B(x * 10) {
inner class D() {
fun baz() = bar()
}
fun D.bar() = { x + this@B.x }
}
}
return B(3).C(2).D().baz()()
}
}
fun box(): String {
assertEquals(23, A().test())
return "OK"
}
@@ -0,0 +1,17 @@
package foo
class A {
fun test() = 23
}
fun <T : A> T.foo(): Int {
class B {
fun foo() = test()
}
return B().foo()
}
fun box(): String {
assertEquals(23, A().foo())
return "OK"
}