Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1065)

Unified Diff: pkg/compiler/lib/src/tree_ir/optimization/logical_rewriter.dart

Issue 1185333002: dart2js cps: Use JS semantics for logical operators in the tree IR. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Renamed method Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | tests/language/conditional_rewrite_test.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/compiler/lib/src/tree_ir/optimization/logical_rewriter.dart
diff --git a/pkg/compiler/lib/src/tree_ir/optimization/logical_rewriter.dart b/pkg/compiler/lib/src/tree_ir/optimization/logical_rewriter.dart
index aba10f4fc9967a4bee301471a4a6d7d3d50a6999..189171739d1a263dcc06ce072051579a34aa3157 100644
--- a/pkg/compiler/lib/src/tree_ir/optimization/logical_rewriter.dart
+++ b/pkg/compiler/lib/src/tree_ir/optimization/logical_rewriter.dart
@@ -8,8 +8,6 @@ import '../tree_ir_nodes.dart';
import 'optimization.dart' show Pass;
import '../../constants/values.dart' as values;
-// TODO(asgerf): Update this class to use JS semantics for && and ||.
-
/// Rewrites logical expressions to be more compact in the Tree IR.
///
/// In this class an expression is said to occur in "boolean context" if
@@ -49,16 +47,10 @@ import '../../constants/values.dart' as values;
///
/// x ? true : false ==> !!x
///
-/// If an operand is known to be a boolean, we can introduce a logical operator:
-///
-/// x ? y : false ==> x && y (if y is known to be a boolean)
+/// If the possible falsy values of the condition are known, we can sometimes
+/// introduce a logical operator:
///
-/// The following sequence of rewrites demonstrates the merit of these rules:
-///
-/// x ? (y ? true : false) : false
-/// x ? !!y : false (double negation introduced by [toBoolean])
-/// x && !!y (!!y validated by [isBooleanValued])
-/// x && y (double negation removed by [putInBooleanContext])
+/// !x ? y : false ==> !x && y
///
class LogicalRewriter extends RecursiveTransformer
implements Pass {
@@ -94,7 +86,7 @@ class LogicalRewriter extends RecursiveTransformer
Statement visitIf(If node) {
// If one of the branches is empty (i.e. just a fallthrough), then that
- // branch should preferrably be the 'else' so we won't have to print it.
+ // branch should preferably be the 'else' so we won't have to print it.
// In other words, we wish to perform this rewrite:
// if (E) {} else {S}
// ==>
@@ -143,6 +135,31 @@ class LogicalRewriter extends RecursiveTransformer
return toBoolean(makeCondition(node.operand, false, liftNots: false));
}
+ /// True if the only possible falsy return value of [condition] is [value].
+ ///
+ /// If [value] is `null` or a truthy value, false is returned. This is to make
+ /// pattern matching more convenient.
+ bool matchesFalsyValue(Expression condition, values.ConstantValue value) {
+ if (value == null) return false;
+ // TODO(asgerf): Here we could really use some more type information,
+ // this is just the best we can do at the moment.
+ return isBooleanValued(condition) && value.isFalse;
+ }
+
+ /// True if the only possible truthy return value of [condition] is [value].
+ ///
+ /// If [value] is `null` or a falsy value, false is returned. This is to make
+ /// pattern matching more convenient.
+ bool matchesTruthyValue(Expression condition, values.ConstantValue value) {
+ if (value == null) return false;
+ // TODO(asgerf): Again, more type information could really beef this up.
+ return isBooleanValued(condition) && value.isTrue;
+ }
+
+ values.ConstantValue getConstant(Expression exp) {
+ return exp is Constant ? exp.value : null;
+ }
+
Expression visitConditional(Conditional node) {
// node.condition will be visited after the then and else parts, because its
// polarity depends on what rewrite we use.
@@ -161,29 +178,32 @@ class LogicalRewriter extends RecursiveTransformer
return toBoolean(makeCondition(node.condition, false, liftNots: false));
}
- // x ? y : false ==> x && y (if y is known to be a boolean)
- if (isBooleanValued(node.thenExpression) && isFalse(node.elseExpression)) {
+ // x ? y : false ==> x && y (if x is truthy or false)
+ // x ? y : null ==> x && y (if x is truthy or null)
+ // x ? y : 0 ==> x && y (if x is truthy or zero) (and so on...)
+ if (matchesFalsyValue(node.condition, getConstant(node.elseExpression))) {
return new LogicalOperator.and(
- makeCondition(node.condition, true, liftNots:false),
- putInBooleanContext(node.thenExpression));
+ visitExpression(node.condition),
+ node.thenExpression);
}
- // x ? y : true ==> !x || y (if y is known to be a boolean)
- if (isBooleanValued(node.thenExpression) && isTrue(node.elseExpression)) {
+ // x ? true : y ==> x || y (if x is falsy or true)
+ // x ? 1 : y ==> x || y (if x is falsy or one) (and so on...)
+ if (matchesTruthyValue(node.condition, getConstant(node.thenExpression))) {
return new LogicalOperator.or(
- makeCondition(node.condition, false, liftNots: false),
- putInBooleanContext(node.thenExpression));
+ visitExpression(node.condition),
+ node.elseExpression);
}
- // x ? true : y ==> x || y (if y if known to be boolean)
- if (isBooleanValued(node.elseExpression) && isTrue(node.thenExpression)) {
+ // x ? y : true ==> !x || y
+ if (isTrue(node.elseExpression)) {
return new LogicalOperator.or(
- makeCondition(node.condition, true, liftNots: false),
- putInBooleanContext(node.elseExpression));
+ toBoolean(makeCondition(node.condition, false, liftNots: false)),
+ node.thenExpression);
}
- // x ? false : y ==> !x && y (if y is known to be a boolean)
- if (isBooleanValued(node.elseExpression) && isFalse(node.thenExpression)) {
+ // x ? false : y ==> !x && y
+ if (isFalse(node.thenExpression)) {
return new LogicalOperator.and(
- makeCondition(node.condition, false, liftNots: false),
- putInBooleanContext(node.elseExpression));
+ toBoolean(makeCondition(node.condition, false, liftNots: false)),
+ node.elseExpression);
}
node.condition = makeCondition(node.condition, true);
@@ -200,8 +220,8 @@ class LogicalRewriter extends RecursiveTransformer
}
Expression visitLogicalOperator(LogicalOperator node) {
- node.left = makeCondition(node.left, true);
- node.right = makeCondition(node.right, true);
+ node.left = visitExpression(node.left);
+ node.right = visitExpression(node.right);
return node;
}
@@ -253,16 +273,6 @@ class LogicalRewriter extends RecursiveTransformer
}
}
- /// Rewrite an expression that was originally processed in a non-boolean
- /// context.
- Expression putInBooleanContext(Expression e) {
- if (e is Not && e.operand is Not) {
- return (e.operand as Not).operand;
- } else {
- return e;
- }
- }
-
/// Forces a boolean conversion of the given expression.
Expression toBoolean(Expression e) {
if (isBooleanValued(e))
@@ -275,7 +285,7 @@ class LogicalRewriter extends RecursiveTransformer
/// context where its result is immediately subject to boolean conversion.
/// If [polarity] if false, the negated condition will be created instead.
/// If [liftNots] is true (default) then Not expressions will be lifted toward
- /// the root the condition so they can be eliminated by the caller.
+ /// the root of the condition so they can be eliminated by the caller.
Expression makeCondition(Expression e, bool polarity, {bool liftNots:true}) {
if (e is Not) {
// !!E ==> E
« no previous file with comments | « no previous file | tests/language/conditional_rewrite_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698