[JS Legacy] Fix Unit materialization in overridden methods

^KT-51878 Fixed
This commit is contained in:
Sergej Jaskiewicz
2022-04-06 16:23:08 +03:00
committed by Space
parent cfe76343d5
commit e1b0e27e62
6 changed files with 61 additions and 4 deletions
@@ -895,6 +895,24 @@ public abstract class KotlinBuiltIns {
return isNotNullConstructedFromGivenClass(type, FqNames.unit);
}
/**
* Returns <code>true</code> if the <code>descriptor</code>'s return type is not <code>Unit</code>,
* or it overrides a function with a non-<code>Unit</code> return type.
*/
public static boolean mayReturnNonUnitValue(@NotNull FunctionDescriptor descriptor) {
KotlinType functionReturnType = descriptor.getReturnType();
assert functionReturnType != null : "Function return typed type must be resolved.";
boolean mayReturnNonUnitValue = !isUnit(functionReturnType);
for (FunctionDescriptor overriddenDescriptor : descriptor.getOriginal().getOverriddenDescriptors()) {
if (mayReturnNonUnitValue)
break;
KotlinType overriddenFunctionReturnType = overriddenDescriptor.getReturnType();
assert overriddenFunctionReturnType != null : "Function return typed type must be resolved.";
mayReturnNonUnitValue = !isUnit(overriddenFunctionReturnType);
}
return mayReturnNonUnitValue;
}
public static boolean isUnitOrNullableUnit(@NotNull KotlinType type) {
return isConstructedFromGivenClass(type, FqNames.unit);
}
@@ -750,6 +750,12 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest {
runTest("js/js.translator/testData/box/coercion/unitIsAs.kt");
}
@Test
@TestMetadata("unitMaterializationInOverriddenMethod.kt")
public void testUnitMaterializationInOverriddenMethod() throws Exception {
runTest("js/js.translator/testData/box/coercion/unitMaterializationInOverriddenMethod.kt");
}
@Test
@TestMetadata("unitNullCheck.kt")
public void testUnitNullCheck() throws Exception {
@@ -750,6 +750,12 @@ public class IrBoxJsTestGenerated extends AbstractIrBoxJsTest {
runTest("js/js.translator/testData/box/coercion/unitIsAs.kt");
}
@Test
@TestMetadata("unitMaterializationInOverriddenMethod.kt")
public void testUnitMaterializationInOverriddenMethod() throws Exception {
runTest("js/js.translator/testData/box/coercion/unitMaterializationInOverriddenMethod.kt");
}
@Test
@TestMetadata("unitNullCheck.kt")
public void testUnitNullCheck() throws Exception {
@@ -160,7 +160,12 @@ public final class ExpressionVisitor extends TranslatorVisitor<JsNode> {
JsReturn jsReturn;
if (returned == null) {
jsReturn = new JsReturn(null);
JsExpression returnExpression = null;
if (returnTarget != null && KotlinBuiltIns.mayReturnNonUnitValue(returnTarget)) {
ClassDescriptor unit = context.getCurrentModule().getBuiltIns().getUnit();
returnExpression = ReferenceTranslator.translateAsValueReference(unit, context);
}
jsReturn = new JsReturn(returnExpression);
}
else {
JsExpression jsReturnExpression = translateAsExpression(returned, context);
@@ -161,9 +161,7 @@ public final class FunctionBodyTranslator extends AbstractTranslator {
}
private boolean mustAddReturnToGeneratedFunctionBody() {
KotlinType functionReturnType = descriptor.getReturnType();
assert functionReturnType != null : "Function return typed type must be resolved.";
return (!declaration.hasBlockBody()) && !(KotlinBuiltIns.isUnit(functionReturnType) && !descriptor.isSuspend());
return !declaration.hasBlockBody() && (KotlinBuiltIns.mayReturnNonUnitValue(descriptor) || descriptor.isSuspend());
}
@NotNull
@@ -0,0 +1,24 @@
// EXPECTED_REACHABLE_NODES: 1279
// KT-51878
open class A {
open fun foo(): Any = "string"
}
var condition = true
class B: A() {
override fun foo(): Unit {
if (condition) {
return
}
condition = !condition
}
}
fun box(): String {
val b: A = B()
if (b.foo() !is Unit) return "fail1"
if (b.foo() !is Unit) return "fail2"
return "OK"
}