JS: fix referencing outer class from secondary constructor

See KT-21041
This commit is contained in:
Alexey Andreev
2017-11-08 20:42:19 +03:00
parent 88441da131
commit ec8adfe7c4
7 changed files with 100 additions and 30 deletions
@@ -11075,6 +11075,12 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
doTest(fileName);
}
@TestMetadata("passingOuterRef.kt")
public void testPassingOuterRef() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/innerNested/passingOuterRef.kt");
doTest(fileName);
}
@TestMetadata("protectedNestedClass.kt")
public void testProtectedNestedClass() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/innerNested/protectedNestedClass.kt");
@@ -476,11 +476,6 @@ public class TranslationContext {
return tempVar;
}
public void associateExpressionToLazyValue(JsExpression expression, TemporaryConstVariable temporaryConstVariable) {
assert expression == temporaryConstVariable.assignmentExpression();
expressionToTempConstVariableCache.put(expression, temporaryConstVariable);
}
@NotNull
public Namer namer() {
return staticContext.getNamer();
@@ -586,14 +581,8 @@ public class TranslationContext {
assert classifier instanceof ClassDescriptor;
ClassDescriptor cls = (ClassDescriptor) classifier;
assert classDescriptor != null : "Can't get ReceiverParameterDescriptor in top level";
JsExpression receiver = getAliasForDescriptor(classDescriptor.getThisAsReceiverParameter());
if (receiver == null) {
receiver = new JsThisRef();
}
return getDispatchReceiverPath(cls, receiver);
assert classDescriptor != null;
return getDispatchReceiverPath(classDescriptor, cls, new JsThisRef());
}
private boolean isConstructorOrDirectScope(DeclarationDescriptor descriptor) {
@@ -601,24 +590,25 @@ public class TranslationContext {
}
@NotNull
private JsExpression getDispatchReceiverPath(@Nullable ClassDescriptor cls, JsExpression thisExpression) {
if (cls != null) {
JsExpression alias = getAliasForDescriptor(cls);
private JsExpression getDispatchReceiverPath(
@NotNull ClassDescriptor from, @NotNull ClassDescriptor to,
@NotNull JsExpression qualifier
) {
while (true) {
JsExpression alias = getAliasForDescriptor(from.getThisAsReceiverParameter());
if (alias != null) {
return alias;
qualifier = alias;
}
if (from == to || !from.isInner() || !(from.getContainingDeclaration() instanceof ClassDescriptor)) {
break;
}
qualifier = new JsNameRef(Namer.OUTER_FIELD_NAME, qualifier);
from = (ClassDescriptor) from.getContainingDeclaration();
}
if (classDescriptor == cls || parent == null) {
return thisExpression;
}
if (classDescriptor != parent.classDescriptor) {
return new JsNameRef(Namer.OUTER_FIELD_NAME, parent.getDispatchReceiverPath(cls, thisExpression));
}
else {
return parent.getDispatchReceiverPath(cls, thisExpression);
}
return qualifier;
}
@Nullable
@@ -268,14 +268,16 @@ class ClassTranslator private constructor(
superCallGenerators += { it += instanceVar }
// Add parameter for outer instance
val leadingArgs = mutableListOf<JsExpression>()
val commonLeadingArgs = mutableListOf<JsExpression>()
if (descriptor.kind == ClassKind.ENUM_CLASS) {
val nameParamName = JsScope.declareTemporaryName("name")
val ordinalParamName = JsScope.declareTemporaryName("ordinal")
constructorInitializer.parameters.addAll(0, listOf(JsParameter(nameParamName), JsParameter(ordinalParamName)))
leadingArgs += listOf(nameParamName.makeRef().withDefaultLocation(), ordinalParamName.makeRef().withDefaultLocation())
commonLeadingArgs += listOf(nameParamName.makeRef().withDefaultLocation(), ordinalParamName.makeRef().withDefaultLocation())
}
val leadingArgs = commonLeadingArgs.toMutableList()
if (outerClassName != null) {
constructorInitializer.parameters.add(0, JsParameter(outerClassName))
leadingArgs += outerClassName.makeRef()
@@ -301,8 +303,15 @@ class ClassTranslator private constructor(
superCallGenerators += {
val delegationConstructor = resolvedCall.resultingDescriptor
val innerContext = context.innerBlock()
val delegatedLeadingArgs = commonLeadingArgs.toMutableList()
val delegateClass = resolvedCall.resultingDescriptor.constructedClass
if (delegateClass.isInner) {
val delegatedOuterDescriptor = (delegateClass.containingDeclaration as ClassDescriptor).thisAsReceiverParameter
delegatedLeadingArgs += context.getDispatchReceiver(delegatedOuterDescriptor)
}
val statement = CallTranslator.translate(innerContext, resolvedCall).toInvocationWith(
leadingArgs, delegationConstructor.valueParameters.size, thisNameRef.deepCopy())
delegatedLeadingArgs, delegationConstructor.valueParameters.size, thisNameRef.deepCopy())
.source(resolvedCall.call.callElement)
.makeStmt()
it += innerContext.currentBlock.statements