From 92eb4a5f1fc144d03af9cbbfee0a850967c9c64a Mon Sep 17 00:00:00 2001 From: develar Date: Wed, 3 Oct 2012 17:44:49 +0400 Subject: [PATCH] JS backend: fixed wrong behavior when using nullable type in string template. (cherry picked from commit 3a16e95) --- .../expression/StringTemplateTranslator.java | 50 ++++++++++++------- .../functions/factories/TopLevelFIF.java | 5 +- .../functions/patterns/NamePredicate.java | 3 ++ .../stringTemplates/cases/stringValues.kt | 3 ++ 4 files changed, 41 insertions(+), 20 deletions(-) diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/expression/StringTemplateTranslator.java b/js/js.translator/src/org/jetbrains/k2js/translate/expression/StringTemplateTranslator.java index baa7fed8e0f..7a2cc67cc78 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/expression/StringTemplateTranslator.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/expression/StringTemplateTranslator.java @@ -23,16 +23,23 @@ import com.google.dart.compiler.backend.js.ast.JsNumberLiteral; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.psi.*; +import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.name.Name; +import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.k2js.translate.context.TranslationContext; import org.jetbrains.k2js.translate.general.AbstractTranslator; import org.jetbrains.k2js.translate.general.Translation; +import org.jetbrains.k2js.translate.intrinsic.functions.factories.TopLevelFIF; +import org.jetbrains.k2js.translate.intrinsic.functions.patterns.NamePredicate; + +import java.util.Collections; import static org.jetbrains.k2js.translate.utils.JsAstUtils.sum; import static org.jetbrains.k2js.translate.utils.JsDescriptorUtils.getNameIfStandardType; public final class StringTemplateTranslator extends AbstractTranslator { + private final JetStringTemplateEntry[] expressionEntries; @NotNull public static JsExpression translate(@NotNull JetStringTemplateExpression expression, @@ -40,20 +47,20 @@ public final class StringTemplateTranslator extends AbstractTranslator { return (new StringTemplateTranslator(expression, context).translate()); } - @NotNull - private final JetStringTemplateExpression expression; + private StringTemplateTranslator(@NotNull JetStringTemplateExpression expression, @NotNull TranslationContext context) { super(context); - this.expression = expression; + + expressionEntries = expression.getEntries(); + assert expressionEntries.length != 0 : "String template must have one or more entries."; } @NotNull private JsExpression translate() { - assert expression.getEntries().length != 0 : "String template must have one or more entries."; EntryVisitor entryVisitor = new EntryVisitor(); - for (JetStringTemplateEntry entry : expression.getEntries()) { + for (JetStringTemplateEntry entry : expressionEntries) { entry.accept(entryVisitor); } return entryVisitor.getResultingExpression(); @@ -83,26 +90,31 @@ public final class StringTemplateTranslator extends AbstractTranslator { append(context().program().getStringLiteral(translatedExpression.toString())); return; } - if (mustCallToString(entryExpression)) { + + JetType type = context().bindingContext().get(BindingContext.EXPRESSION_TYPE, entryExpression); + if (type == null || type.isNullable()) { + append(TopLevelFIF.TO_STRING.apply((JsExpression) null, Collections.singletonList(translatedExpression), context())); + } + else if (mustCallToString(type)) { append(new JsInvocation(new JsNameRef("toString", translatedExpression))); - } else { + } + else { append(translatedExpression); } } - private boolean mustCallToString(@NotNull JetExpression entryExpression) { - Name typeName = getNameIfStandardType(entryExpression, context()); - if (typeName == null) { - return true; + private boolean mustCallToString(@NotNull JetType type) { + Name typeName = getNameIfStandardType(type); + if (typeName != null) { + //TODO: this is a hacky optimization, should use some generic approach + if (NamePredicate.STRING.apply(typeName)) { + return false; + } + else if (NamePredicate.PRIMITIVE_NUMBERS.apply(typeName)) { + return resultingExpression == null; + } } - //TODO: this is a hacky optimization, should use some generic approach - if (typeName.asString().equals("String")) { - return false; - } - if (typeName.asString().equals("Int") && resultingExpression != null) { - return false; - } - return true; + return expressionEntries.length == 1; } @Override diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/functions/factories/TopLevelFIF.java b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/functions/factories/TopLevelFIF.java index 8e8bc7eb1bb..d7a8d33ee88 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/functions/factories/TopLevelFIF.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/functions/factories/TopLevelFIF.java @@ -123,11 +123,14 @@ public final class TopLevelFIF extends CompositeFIF { } }; + @NotNull + public static final KotlinFunctionIntrinsic TO_STRING = new KotlinFunctionIntrinsic("toString"); + @NotNull public static final FunctionIntrinsicFactory INSTANCE = new TopLevelFIF(); private TopLevelFIF() { - add(pattern("jet", "toString").receiverExists(), new KotlinFunctionIntrinsic("toString")); + add(pattern("jet", "toString").receiverExists(), TO_STRING); add(pattern("jet", "equals").receiverExists(), EQUALS); add(pattern("jet", "identityEquals").receiverExists(), IDENTITY_EQUALS); add(pattern(NamePredicate.PRIMITIVE_NUMBERS, "equals"), EQUALS); diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/functions/patterns/NamePredicate.java b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/functions/patterns/NamePredicate.java index d309fcffe41..6d7a6637b23 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/functions/patterns/NamePredicate.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/functions/patterns/NamePredicate.java @@ -40,6 +40,9 @@ public final class NamePredicate implements Predicate { } })); + @NotNull + public static final NamePredicate STRING = new NamePredicate("String"); + @NotNull private final List validNames = Lists.newArrayList(); diff --git a/js/js.translator/testFiles/expression/stringTemplates/cases/stringValues.kt b/js/js.translator/testFiles/expression/stringTemplates/cases/stringValues.kt index b69f8fc95f3..24f364c9d2b 100644 --- a/js/js.translator/testFiles/expression/stringTemplates/cases/stringValues.kt +++ b/js/js.translator/testFiles/expression/stringTemplates/cases/stringValues.kt @@ -7,5 +7,8 @@ fun box(): Boolean { if (message != "a = abc, b = def") return false + val v1 = null + if ("returns null null" != "returns $v1 ${null}") return false + return true } \ No newline at end of file