JS: fix referencing outer class from secondary constructor
See KT-21041
This commit is contained in:
@@ -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");
|
||||
|
||||
+17
-27
@@ -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
|
||||
|
||||
+12
-3
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user