@@ -372,6 +372,7 @@ class ConstantsTransformer extends Transformer {
372372
373373class ConstantEvaluator extends RecursiveVisitor {
374374 final ConstantsBackend backend;
375+ final NumberSemantics numberSemantics;
375376 Map <String , String > environmentDefines;
376377 final CoreTypes coreTypes;
377378 final TypeEnvironment typeEnvironment;
@@ -396,9 +397,12 @@ class ConstantEvaluator extends RecursiveVisitor {
396397 Set <TreeNode > unevaluatedNodes;
397398 Set <Expression > replacementNodes;
398399
400+ bool get targetingJavaScript => numberSemantics == NumberSemantics .js;
401+
399402 ConstantEvaluator (this .backend, this .environmentDefines, this .typeEnvironment,
400403 this .enableAsserts, this .errorReporter)
401- : coreTypes = typeEnvironment.coreTypes,
404+ : numberSemantics = backend.numberSemantics,
405+ coreTypes = typeEnvironment.coreTypes,
402406 canonicalizationCache = < Constant , Constant > {},
403407 nodeCache = < Node , Constant > {},
404408 env = new EvaluationEnvironment ();
@@ -517,7 +521,7 @@ class ConstantEvaluator extends RecursiveVisitor {
517521 }
518522
519523 visitDoubleLiteral (DoubleLiteral node) {
520- return canonicalize (new DoubleConstant (node.value));
524+ return canonicalize (makeDoubleConstant (node.value));
521525 }
522526
523527 visitStringLiteral (StringLiteral node) {
@@ -557,7 +561,8 @@ class ConstantEvaluator extends RecursiveVisitor {
557561 typeArgument: node.typeArgument, isConst: true ));
558562 }
559563 final DartType typeArgument = evaluateDartType (node, node.typeArgument);
560- return canonicalize (new ListConstant (typeArgument, entries));
564+ return canonicalize (
565+ backend.lowerListConstant (new ListConstant (typeArgument, entries)));
561566 }
562567
563568 visitSetLiteral (SetLiteral node) {
@@ -580,7 +585,8 @@ class ConstantEvaluator extends RecursiveVisitor {
580585 typeArgument: node.typeArgument, isConst: true ));
581586 }
582587 final DartType typeArgument = evaluateDartType (node, node.typeArgument);
583- return canonicalize (new SetConstant (typeArgument, entries));
588+ return canonicalize (
589+ backend.lowerSetConstant (new SetConstant (typeArgument, entries)));
584590 }
585591
586592 visitMapLiteral (MapLiteral node) {
@@ -616,7 +622,8 @@ class ConstantEvaluator extends RecursiveVisitor {
616622 }
617623 final DartType keyType = evaluateDartType (node, node.keyType);
618624 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)));
620627 }
621628
622629 visitFunctionExpression (FunctionExpression node) {
@@ -1037,7 +1044,7 @@ class ConstantEvaluator extends RecursiveVisitor {
10371044 if (arguments.length == 0 ) {
10381045 switch (node.name.name) {
10391046 case 'unary-' :
1040- return canonicalize (new DoubleConstant (- receiver.value));
1047+ return canonicalize (makeDoubleConstant (- receiver.value));
10411048 }
10421049 } else if (arguments.length == 1 ) {
10431050 final Constant other = arguments[0 ];
@@ -1390,6 +1397,18 @@ class ConstantEvaluator extends RecursiveVisitor {
13901397
13911398 // Helper methods:
13921399
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+
13931412 void ensureIsSubtype (Constant constant, DartType type, TreeNode node) {
13941413 DartType constantType = constant.getType (typeEnvironment);
13951414
@@ -1456,7 +1475,6 @@ class ConstantEvaluator extends RecursiveVisitor {
14561475 }
14571476
14581477 Constant canonicalize (Constant constant) {
1459- constant = backend.lowerConstant (constant);
14601478 return canonicalizationCache.putIfAbsent (constant, () => constant);
14611479 }
14621480
@@ -1482,8 +1500,10 @@ class ConstantEvaluator extends RecursiveVisitor {
14821500
14831501 Constant evaluateBinaryNumericOperation (
14841502 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+ }
14871507 num result;
14881508 switch (op) {
14891509 case '+' :
@@ -1506,10 +1526,11 @@ class ConstantEvaluator extends RecursiveVisitor {
15061526 break ;
15071527 }
15081528
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));
15131534 }
15141535
15151536 switch (op) {
@@ -1605,16 +1626,30 @@ class EvaluationEnvironment {
16051626 }
16061627}
16071628
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+
16081638// Backend specific constant evaluation behavior
16091639class 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;
16181653}
16191654
16201655// Used as control-flow to abort the current evaluation.
0 commit comments