Fix some Unit materialization bugs

This commit is contained in:
Anton Bannykh
2018-03-02 18:08:55 +03:00
parent 1f7d235fb5
commit 7cde03938a
6 changed files with 63 additions and 24 deletions
@@ -280,13 +280,13 @@ public final class PatternTranslator extends AbstractTranslator {
EqualityType matchEquality = equalityType(subjectType);
EqualityType patternEquality = equalityType(patternType);
JsExpression expressionToMatchAgainst = translateExpressionForExpressionPattern(patternExpression);
JsExpression expressionToMatchAgainst = TranslationUtils.coerce(context(), translateExpressionForExpressionPattern(patternExpression), subjectType);
if (matchEquality == EqualityType.PRIMITIVE && patternEquality == EqualityType.PRIMITIVE) {
return equality(expressionToMatch, expressionToMatchAgainst);
}
else if (expressionToMatchAgainst instanceof JsNullLiteral) {
return TranslationUtils.nullCheck(expressionToMatch, false);
return TranslationUtils.nullCheck(subjectExpression, expressionToMatch, context(), false);
}
else {
return TopLevelFIF.KOTLIN_EQUALS.apply(expressionToMatch, Collections.singletonList(expressionToMatchAgainst), context());
@@ -27,6 +27,7 @@ import org.jetbrains.kotlin.js.translate.context.TranslationContext
import org.jetbrains.kotlin.js.translate.intrinsic.functions.factories.TopLevelFIF
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils
import org.jetbrains.kotlin.js.translate.utils.PsiUtils.getOperationToken
import org.jetbrains.kotlin.js.translate.utils.PsiUtils.isNegatedOperation
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.KtBinaryExpression
@@ -36,7 +37,6 @@ import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.expressions.OperatorConventions
import org.jetbrains.kotlin.types.isDynamic
import org.jetbrains.kotlin.types.typeUtil.makeNullable
import java.util.*
object EqualsBOIF : BinaryOperationIntrinsicFactory {
@@ -49,9 +49,7 @@ object EqualsBOIF : BinaryOperationIntrinsicFactory {
val anyType = context.currentModule.builtIns.anyType
if (right is JsNullLiteral || left is JsNullLiteral) {
val (subject, ktSubject) = if (right is JsNullLiteral) Pair(left, expression.left!!) else Pair(right, expression.right!!)
val type = context.bindingContext().getType(ktSubject) ?: anyType
val coercedSubject = TranslationUtils.coerce(context, subject, type.makeNullable())
return TranslationUtils.nullCheck(coercedSubject, isNegated)
return TranslationUtils.nullCheck(ktSubject, subject, context, isNegatedOperation(expression))
}
val (leftKotlinType, rightKotlinType) = binaryOperationTypes(expression, context)
@@ -35,6 +35,7 @@ import org.jetbrains.kotlin.types.expressions.OperatorConventions;
import static org.jetbrains.kotlin.js.translate.utils.PsiUtils.getOperationToken;
import static org.jetbrains.kotlin.js.translate.utils.PsiUtils.isAssignment;
import static org.jetbrains.kotlin.js.translate.utils.TranslationUtils.coerce;
import static org.jetbrains.kotlin.js.translate.utils.TranslationUtils.isSimpleNameExpressionNotDelegatedLocalVar;
public final class IntrinsicAssignmentTranslator extends AssignmentTranslator {
@@ -62,6 +63,7 @@ public final class IntrinsicAssignmentTranslator extends AssignmentTranslator {
JsExpression result = TranslationUtils.translateRightExpression(context, expression, rightBlock);
KotlinType leftType = context.bindingContext().getType(expression.getLeft());
KotlinType rightType = context.bindingContext().getType(expression.getRight());
if (rightType != null && KotlinBuiltIns.isCharOrNullableChar(rightType)) {
if (leftType != null && KotlinBuiltIns.isStringOrNullableString(leftType)) {
result = JsAstUtils.charToString(result);
@@ -54,7 +54,7 @@ public final class UnaryOperationTranslator {
if (operationToken == KtTokens.EXCLEXCL) {
KtExpression baseExpression = getBaseExpression(expression);
JsExpression translatedExpression = translateAsExpression(baseExpression, context);
return sure(translatedExpression, context);
return sure(baseExpression, translatedExpression, context);
}
if (operationToken == KtTokens.MINUS) {
@@ -50,6 +50,7 @@ import org.jetbrains.kotlin.resolve.inline.InlineUtil;
import org.jetbrains.kotlin.resolve.source.KotlinSourceElementKt;
import org.jetbrains.kotlin.types.DynamicTypesKt;
import org.jetbrains.kotlin.types.KotlinType;
import org.jetbrains.kotlin.types.TypeUtils;
import java.util.*;
import java.util.stream.Collectors;
@@ -157,6 +158,30 @@ public final class TranslationUtils {
return new JsBinaryOperation(operator, expressionToCheck, new JsNullLiteral());
}
@NotNull
private static JsExpression prepareForNullCheck(
@NotNull KtExpression ktSubject,
@NotNull JsExpression expression,
@NotNull TranslationContext context
) {
KotlinType type = context.bindingContext().getType(ktSubject);
if (type == null) {
type = context.getCurrentModule().getBuiltIns().getAnyType();
}
return coerce(context, expression, TypeUtils.makeNullable(type));
}
@NotNull
public static JsBinaryOperation nullCheck(
@NotNull KtExpression ktSubject,
@NotNull JsExpression expressionToCheck,
@NotNull TranslationContext context,
boolean isNegated
) {
return nullCheck(prepareForNullCheck(ktSubject, expressionToCheck, context), isNegated);
}
@NotNull
public static JsConditional notNullConditional(
@NotNull JsExpression expression,
@@ -310,8 +335,9 @@ public final class TranslationUtils {
}
@NotNull
public static JsExpression sure(@NotNull JsExpression expression, @NotNull TranslationContext context) {
return new JsInvocation(context.getReferenceToIntrinsic(Namer.NULL_CHECK_INTRINSIC_NAME), expression);
public static JsExpression sure(@NotNull KtExpression ktExpression, @NotNull JsExpression expression, @NotNull TranslationContext context) {
return new JsInvocation(context.getReferenceToIntrinsic(Namer.NULL_CHECK_INTRINSIC_NAME),
prepareForNullCheck(ktExpression, expression, context));
}
public static boolean isSimpleNameExpressionNotDelegatedLocalVar(@Nullable KtExpression expression, @NotNull TranslationContext context) {
@@ -491,9 +517,7 @@ public final class TranslationUtils {
}
else if (KotlinBuiltIns.isUnit(from)) {
if (!KotlinBuiltIns.isUnit(to) && !MetadataProperties.isUnit(value)) {
ClassDescriptor unit = context.getCurrentModule().getBuiltIns().getUnit();
JsExpression unitRef = ReferenceTranslator.translateAsValueReference(unit, context);
value = JsAstUtils.newSequence(Arrays.asList(value, unitRef));
value = voidToUnit(context, value);
}
}
@@ -501,6 +525,13 @@ public final class TranslationUtils {
return value;
}
@NotNull
public static JsExpression voidToUnit(@NotNull TranslationContext context, @NotNull JsExpression expression) {
ClassDescriptor unit = context.getCurrentModule().getBuiltIns().getUnit();
JsExpression unitRef = ReferenceTranslator.translateAsValueReference(unit, context);
return JsAstUtils.newSequence(Arrays.asList(expression, unitRef));
}
@NotNull
private static JsExpression unitToVoid(@NotNull JsExpression expression) {
if (expression instanceof JsBinaryOperation) {
+20 -12
View File
@@ -1,18 +1,26 @@
// EXPECTED_REACHABLE_NODES: 1132
var log = ""
fun box(): String {
foo() ?: bar()
if (foo() == null) bar()
fun log(msg: String) {
log += "$msg;"
}
fun box(): String {
log("!!")!!
log("elvis-left") ?: log("elvis-right")
if (log("if") == null) log("then")
when (null) {
log("when-pattern") -> log("when-body-1")
}
when (log("when-subject")) {
null -> log("when-body-2")
}
if (log != "!!;elvis-left;if;when-pattern;when-subject;") return "fail: $log"
if (log != "foo;foo;") return "fail: $log"
return "OK"
}
fun foo() {
log += "foo;"
}
fun bar() {
log += "bar;"
}