KT-11030 Minor code improvements
This commit is contained in:
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
+2
-5
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
+12
-6
@@ -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
|
||||
|
||||
+40
-66
@@ -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 {
|
||||
|
||||
+1
-7
@@ -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);
|
||||
|
||||
+2
-14
@@ -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
|
||||
|
||||
|
||||
+13
-10
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
+6
-5
@@ -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"
|
||||
}
|
||||
+23
@@ -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"
|
||||
}
|
||||
+17
@@ -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"
|
||||
}
|
||||
Reference in New Issue
Block a user