@@ -372,6 +372,7 @@ class ConstantsTransformer extends Transformer {
372
372
373
373
class ConstantEvaluator extends RecursiveVisitor {
374
374
final ConstantsBackend backend;
375
+ final NumberSemantics numberSemantics;
375
376
Map <String , String > environmentDefines;
376
377
final CoreTypes coreTypes;
377
378
final TypeEnvironment typeEnvironment;
@@ -396,9 +397,12 @@ class ConstantEvaluator extends RecursiveVisitor {
396
397
Set <TreeNode > unevaluatedNodes;
397
398
Set <Expression > replacementNodes;
398
399
400
+ bool get targetingJavaScript => numberSemantics == NumberSemantics .js;
401
+
399
402
ConstantEvaluator (this .backend, this .environmentDefines, this .typeEnvironment,
400
403
this .enableAsserts, this .errorReporter)
401
- : coreTypes = typeEnvironment.coreTypes,
404
+ : numberSemantics = backend.numberSemantics,
405
+ coreTypes = typeEnvironment.coreTypes,
402
406
canonicalizationCache = < Constant , Constant > {},
403
407
nodeCache = < Node , Constant > {},
404
408
env = new EvaluationEnvironment ();
@@ -517,7 +521,7 @@ class ConstantEvaluator extends RecursiveVisitor {
517
521
}
518
522
519
523
visitDoubleLiteral (DoubleLiteral node) {
520
- return canonicalize (new DoubleConstant (node.value));
524
+ return canonicalize (makeDoubleConstant (node.value));
521
525
}
522
526
523
527
visitStringLiteral (StringLiteral node) {
@@ -557,7 +561,8 @@ class ConstantEvaluator extends RecursiveVisitor {
557
561
typeArgument: node.typeArgument, isConst: true ));
558
562
}
559
563
final DartType typeArgument = evaluateDartType (node, node.typeArgument);
560
- return canonicalize (new ListConstant (typeArgument, entries));
564
+ return canonicalize (
565
+ backend.lowerListConstant (new ListConstant (typeArgument, entries)));
561
566
}
562
567
563
568
visitSetLiteral (SetLiteral node) {
@@ -580,7 +585,8 @@ class ConstantEvaluator extends RecursiveVisitor {
580
585
typeArgument: node.typeArgument, isConst: true ));
581
586
}
582
587
final DartType typeArgument = evaluateDartType (node, node.typeArgument);
583
- return canonicalize (new SetConstant (typeArgument, entries));
588
+ return canonicalize (
589
+ backend.lowerSetConstant (new SetConstant (typeArgument, entries)));
584
590
}
585
591
586
592
visitMapLiteral (MapLiteral node) {
@@ -616,7 +622,8 @@ class ConstantEvaluator extends RecursiveVisitor {
616
622
}
617
623
final DartType keyType = evaluateDartType (node, node.keyType);
618
624
final DartType valueType = evaluateDartType (node, node.valueType);
619
- return canonicalize (new MapConstant (keyType, valueType, entries));
625
+ return canonicalize (
626
+ backend.lowerMapConstant (new MapConstant (keyType, valueType, entries)));
620
627
}
621
628
622
629
visitFunctionExpression (FunctionExpression node) {
@@ -1037,7 +1044,7 @@ class ConstantEvaluator extends RecursiveVisitor {
1037
1044
if (arguments.length == 0 ) {
1038
1045
switch (node.name.name) {
1039
1046
case 'unary-' :
1040
- return canonicalize (new DoubleConstant (- receiver.value));
1047
+ return canonicalize (makeDoubleConstant (- receiver.value));
1041
1048
}
1042
1049
} else if (arguments.length == 1 ) {
1043
1050
final Constant other = arguments[0 ];
@@ -1390,6 +1397,18 @@ class ConstantEvaluator extends RecursiveVisitor {
1390
1397
1391
1398
// Helper methods:
1392
1399
1400
+ Constant makeDoubleConstant (double value) {
1401
+ if (targetingJavaScript) {
1402
+ // Convert to an integer when possible (matching the runtime behavior
1403
+ // of `is int`).
1404
+ if (value.isFinite) {
1405
+ var i = value.toInt ();
1406
+ if (value == i.toDouble ()) return new IntConstant (i);
1407
+ }
1408
+ }
1409
+ return new DoubleConstant (value);
1410
+ }
1411
+
1393
1412
void ensureIsSubtype (Constant constant, DartType type, TreeNode node) {
1394
1413
DartType constantType = constant.getType (typeEnvironment);
1395
1414
@@ -1456,7 +1475,6 @@ class ConstantEvaluator extends RecursiveVisitor {
1456
1475
}
1457
1476
1458
1477
Constant canonicalize (Constant constant) {
1459
- constant = backend.lowerConstant (constant);
1460
1478
return canonicalizationCache.putIfAbsent (constant, () => constant);
1461
1479
}
1462
1480
@@ -1482,8 +1500,10 @@ class ConstantEvaluator extends RecursiveVisitor {
1482
1500
1483
1501
Constant evaluateBinaryNumericOperation (
1484
1502
String op, num a, num b, TreeNode node) {
1485
- a = backend.prepareNumericOperand (a);
1486
- b = backend.prepareNumericOperand (b);
1503
+ if (targetingJavaScript) {
1504
+ a = a.toDouble ();
1505
+ b = b.toDouble ();
1506
+ }
1487
1507
num result;
1488
1508
switch (op) {
1489
1509
case '+' :
@@ -1506,10 +1526,11 @@ class ConstantEvaluator extends RecursiveVisitor {
1506
1526
break ;
1507
1527
}
1508
1528
1509
- if (result != null ) {
1510
- return canonicalize (result is int
1511
- ? new IntConstant (result.toSigned (64 ))
1512
- : new DoubleConstant (result as double ));
1529
+ if (result is int ) {
1530
+ return canonicalize (new IntConstant (result.toSigned (64 )));
1531
+ }
1532
+ if (result is double ) {
1533
+ return canonicalize (makeDoubleConstant (result));
1513
1534
}
1514
1535
1515
1536
switch (op) {
@@ -1605,16 +1626,30 @@ class EvaluationEnvironment {
1605
1626
}
1606
1627
}
1607
1628
1629
+ /// The different kinds of number semantics supported by the constant evaluator.
1630
+ enum NumberSemantics {
1631
+ /// Dart VM number semantics.
1632
+ vm,
1633
+
1634
+ /// JavaScript (Dart2js and DDC) number semantics.
1635
+ js,
1636
+ }
1637
+
1608
1638
// Backend specific constant evaluation behavior
1609
1639
class ConstantsBackend {
1610
- /// Transformation of constants prior to canonicalization, e.g. to change the
1611
- /// representation of certain kinds of constants, or to implement specific
1612
- /// number semantics.
1613
- Constant lowerConstant (Constant constant) => constant;
1614
-
1615
- /// Transformation of numeric operands prior to a binary operation,
1616
- /// e.g. to implement specific number semantics.
1617
- num prepareNumericOperand (num operand) => operand;
1640
+ const ConstantsBackend ();
1641
+
1642
+ /// Lowering of a list constant to a backend-specific representation.
1643
+ Constant lowerListConstant (ListConstant constant) => constant;
1644
+
1645
+ /// Lowering of a set constant to a backend-specific representation.
1646
+ Constant lowerSetConstant (SetConstant constant) => constant;
1647
+
1648
+ /// Lowering of a map constant to a backend-specific representation.
1649
+ Constant lowerMapConstant (MapConstant constant) => constant;
1650
+
1651
+ /// Number semantics to use for this backend.
1652
+ NumberSemantics get numberSemantics => NumberSemantics .vm;
1618
1653
}
1619
1654
1620
1655
// Used as control-flow to abort the current evaluation.
0 commit comments