JS: fix referencing outer class from secondary constructor
See KT-21041
This commit is contained in:
@@ -0,0 +1,47 @@
|
||||
open class A1(y: String) {
|
||||
val x = "A1.x,$y"
|
||||
}
|
||||
|
||||
open class A2(y: String) {
|
||||
val x = "A2.x,$y"
|
||||
|
||||
inner open class B1 : A1 {
|
||||
constructor(p: String) : super("B1.param,$p")
|
||||
}
|
||||
|
||||
inner open class B2 : A2 {
|
||||
constructor(p: String) : super("B2.param,$p")
|
||||
}
|
||||
|
||||
inner class B3 : B1 {
|
||||
constructor(p: String) : super("B3.param,$p")
|
||||
}
|
||||
|
||||
fun foo(): String {
|
||||
return B1("q").x + ";" + B2("w").x + ";" + B3("e").x + ";" + x
|
||||
}
|
||||
}
|
||||
|
||||
open class A3(y: String) {
|
||||
val x = "A3.x,$y"
|
||||
|
||||
inner open class B1(p: String) : A1("B1.param,$p")
|
||||
|
||||
inner open class B2(p: String) : A3("B2.param,$p")
|
||||
|
||||
inner class B3(p: String) : B1("B3.param,$p")
|
||||
|
||||
fun foo(): String {
|
||||
return B1("q").x + ";" + B2("w").x + ";" + B3("e").x + ";" + x
|
||||
}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val r1 = A2("c").foo()
|
||||
if (r1 != "A1.x,B1.param,q;A2.x,B2.param,w;A1.x,B1.param,B3.param,e;A2.x,c") return "fail1: $r1"
|
||||
|
||||
val r2 = A3("d").foo()
|
||||
if (r2 != "A1.x,B1.param,q;A3.x,B2.param,w;A1.x,B1.param,B3.param,e;A3.x,d") return "fail2: $r2"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
+6
@@ -10151,6 +10151,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
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");
|
||||
|
||||
@@ -10151,6 +10151,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
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");
|
||||
|
||||
@@ -10151,6 +10151,12 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
||||
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");
|
||||
|
||||
@@ -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