[JS Legacy] Fix Unit materialization in overridden methods
^KT-51878 Fixed
This commit is contained in:
@@ -895,6 +895,24 @@ public abstract class KotlinBuiltIns {
|
|||||||
return isNotNullConstructedFromGivenClass(type, FqNames.unit);
|
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) {
|
public static boolean isUnitOrNullableUnit(@NotNull KotlinType type) {
|
||||||
return isConstructedFromGivenClass(type, FqNames.unit);
|
return isConstructedFromGivenClass(type, FqNames.unit);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -750,6 +750,12 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest {
|
|||||||
runTest("js/js.translator/testData/box/coercion/unitIsAs.kt");
|
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
|
@Test
|
||||||
@TestMetadata("unitNullCheck.kt")
|
@TestMetadata("unitNullCheck.kt")
|
||||||
public void testUnitNullCheck() throws Exception {
|
public void testUnitNullCheck() throws Exception {
|
||||||
|
|||||||
+6
@@ -750,6 +750,12 @@ public class IrBoxJsTestGenerated extends AbstractIrBoxJsTest {
|
|||||||
runTest("js/js.translator/testData/box/coercion/unitIsAs.kt");
|
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
|
@Test
|
||||||
@TestMetadata("unitNullCheck.kt")
|
@TestMetadata("unitNullCheck.kt")
|
||||||
public void testUnitNullCheck() throws Exception {
|
public void testUnitNullCheck() throws Exception {
|
||||||
|
|||||||
+6
-1
@@ -160,7 +160,12 @@ public final class ExpressionVisitor extends TranslatorVisitor<JsNode> {
|
|||||||
|
|
||||||
JsReturn jsReturn;
|
JsReturn jsReturn;
|
||||||
if (returned == null) {
|
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 {
|
else {
|
||||||
JsExpression jsReturnExpression = translateAsExpression(returned, context);
|
JsExpression jsReturnExpression = translateAsExpression(returned, context);
|
||||||
|
|||||||
+1
-3
@@ -161,9 +161,7 @@ public final class FunctionBodyTranslator extends AbstractTranslator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean mustAddReturnToGeneratedFunctionBody() {
|
private boolean mustAddReturnToGeneratedFunctionBody() {
|
||||||
KotlinType functionReturnType = descriptor.getReturnType();
|
return !declaration.hasBlockBody() && (KotlinBuiltIns.mayReturnNonUnitValue(descriptor) || descriptor.isSuspend());
|
||||||
assert functionReturnType != null : "Function return typed type must be resolved.";
|
|
||||||
return (!declaration.hasBlockBody()) && !(KotlinBuiltIns.isUnit(functionReturnType) && !descriptor.isSuspend());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
|
|||||||
+24
@@ -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"
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user