| Index: pkg/analyzer_experimental/lib/src/generated/constant.dart | 
| =================================================================== | 
| --- pkg/analyzer_experimental/lib/src/generated/constant.dart	(revision 23549) | 
| +++ pkg/analyzer_experimental/lib/src/generated/constant.dart	(working copy) | 
| @@ -11,6 +11,7 @@ | 
| import 'element.dart'; | 
| import 'engine.dart' show AnalysisEngine; | 
|  | 
| + | 
| /** | 
| * Instances of the class {@code ConstantEvaluator} evaluate constant expressions to produce their | 
| * compile-time value. According to the Dart Language Specification: <blockquote> A constant | 
| @@ -43,10 +44,12 @@ | 
| * those values. | 
| */ | 
| class ConstantEvaluator { | 
| + | 
| /** | 
| * The source containing the expression(s) that will be evaluated. | 
| */ | 
| Source _source; | 
| + | 
| /** | 
| * Initialize a newly created evaluator to evaluate expressions in the given source. | 
| * @param source the source containing the expression(s) that will be evaluated | 
| @@ -67,11 +70,13 @@ | 
| return EvaluationResult.forErrors(new List.from(errors)); | 
| } | 
| } | 
| + | 
| /** | 
| * Instances of the class {@code EvaluationResult} represent the result of attempting to evaluate an | 
| * expression. | 
| */ | 
| class EvaluationResult { | 
| + | 
| /** | 
| * Return an evaluation result representing the result of evaluating an expression that is not a | 
| * compile-time constant because of the given errors. | 
| @@ -79,6 +84,7 @@ | 
| * @return the result of evaluating an expression that is not a compile-time constant | 
| */ | 
| static EvaluationResult forErrors(List<AnalysisError> errors) => new EvaluationResult(null, errors); | 
| + | 
| /** | 
| * Return an evaluation result representing the result of evaluating an expression that is a | 
| * compile-time constant that evaluates to the given value. | 
| @@ -86,14 +92,17 @@ | 
| * @return the result of evaluating an expression that is a compile-time constant | 
| */ | 
| static EvaluationResult forValue(Object value) => new EvaluationResult(value, null); | 
| + | 
| /** | 
| * The value of the expression. | 
| */ | 
| Object _value; | 
| + | 
| /** | 
| * The errors that should be reported for the expression(s) that were evaluated. | 
| */ | 
| List<AnalysisError> _errors; | 
| + | 
| /** | 
| * Initialize a newly created result object with the given state. Clients should use one of the | 
| * factory methods: {@link #forErrors(AnalysisError\[\])} and {@link #forValue(Object)}. | 
| @@ -104,6 +113,7 @@ | 
| this._value = value; | 
| this._errors = errors; | 
| } | 
| + | 
| /** | 
| * Return an array containing the errors that should be reported for the expression(s) that were | 
| * evaluated. If there are no such errors, the array will be empty. The array can be empty even if | 
| @@ -111,12 +121,14 @@ | 
| * other parts of the analysis engine. | 
| */ | 
| List<AnalysisError> get errors => _errors == null ? AnalysisError.NO_ERRORS : _errors; | 
| + | 
| /** | 
| * Return the value of the expression, or {@code null} if the expression evaluated to {@code null}or if the expression could not be evaluated, either because it was not a compile-time constant | 
| * expression or because it would throw an exception when evaluated. | 
| * @return the value of the expression | 
| */ | 
| Object get value => _value; | 
| + | 
| /** | 
| * Return {@code true} if the expression is a compile-time constant expression that would not | 
| * throw an exception when evaluated. | 
| @@ -124,22 +136,20 @@ | 
| */ | 
| bool isValid() => _errors == null; | 
| } | 
| + | 
| /** | 
| * Instances of the class {@code ConstantFinder} are used to traverse the AST structures of all of | 
| * the compilation units being resolved and build a table mapping constant variable elements to the | 
| * declarations of those variables. | 
| */ | 
| class ConstantFinder extends RecursiveASTVisitor<Object> { | 
| + | 
| /** | 
| * A table mapping constant variable elements to the declarations of those variables. | 
| */ | 
| Map<VariableElement, VariableDeclaration> _variableMap = new Map<VariableElement, VariableDeclaration>(); | 
| + | 
| /** | 
| -   * Initialize a newly created constant finder. | 
| -   */ | 
| -  ConstantFinder() : super() { | 
| -  } | 
| -  /** | 
| * Return a table mapping constant variable elements to the declarations of those variables. | 
| * @return a table mapping constant variable elements to the declarations of those variables | 
| */ | 
| @@ -156,6 +166,7 @@ | 
| return null; | 
| } | 
| } | 
| + | 
| /** | 
| * Instances of the class {@code ConstantValueComputer} compute the values of constant variables in | 
| * one or more compilation units. The expected usage pattern is for the compilation units to be | 
| @@ -163,25 +174,24 @@ | 
| * method {@link #computeValues()} will result in unpredictable behavior. | 
| */ | 
| class ConstantValueComputer { | 
| + | 
| /** | 
| * The object used to find constant variables in the compilation units that were added. | 
| */ | 
| ConstantFinder _constantFinder = new ConstantFinder(); | 
| + | 
| /** | 
| * A graph in which the nodes are the constant variables and the edges are from each variable to | 
| * the other constant variables that are referenced in the head's initializer. | 
| */ | 
| DirectedGraph<VariableElement> _referenceGraph = new DirectedGraph<VariableElement>(); | 
| + | 
| /** | 
| * A table mapping constant variables to the declarations of those variables. | 
| */ | 
| Map<VariableElement, VariableDeclaration> _declarationMap; | 
| + | 
| /** | 
| -   * Initialize a newly created constant value computer. | 
| -   */ | 
| -  ConstantValueComputer() : super() { | 
| -  } | 
| -  /** | 
| * Add the constant variables in the given compilation unit to the list of constant variables | 
| * whose value needs to be computed. | 
| * @param unit the compilation unit defining the constant variables to be added | 
| @@ -189,6 +199,7 @@ | 
| void add(CompilationUnit unit) { | 
| unit.accept(_constantFinder); | 
| } | 
| + | 
| /** | 
| * Compute values for all of the constant variables in the compilation units that were added. | 
| */ | 
| @@ -219,6 +230,7 @@ | 
| } | 
| } | 
| } | 
| + | 
| /** | 
| * Compute a value for the given variable. | 
| * @param variable the variable for which a value is to be computed | 
| @@ -239,6 +251,7 @@ | 
| } | 
| } | 
| } | 
| + | 
| /** | 
| * Generate an error indicating that the given variable is not a valid compile-time constant | 
| * because it references at least one of the variables in the given cycle, each of which directly | 
| @@ -249,6 +262,7 @@ | 
| void generateCycleError(List<VariableElement> variablesInCycle, VariableElement variable) { | 
| } | 
| } | 
| + | 
| /** | 
| * Instances of the class {@code ConstantVisitor} evaluate constant expressions to produce their | 
| * compile-time value. According to the Dart Language Specification: <blockquote> A constant | 
| @@ -276,11 +290,6 @@ | 
| * </blockquote> | 
| */ | 
| class ConstantVisitor extends GeneralizingASTVisitor<EvaluationResultImpl> { | 
| -  /** | 
| -   * Initialize a newly created constant visitor. | 
| -   */ | 
| -  ConstantVisitor() : super() { | 
| -  } | 
| EvaluationResultImpl visitAdjacentStrings(AdjacentStrings node) { | 
| EvaluationResultImpl result = null; | 
| for (StringLiteral string in node.strings) { | 
| @@ -295,44 +304,50 @@ | 
| EvaluationResultImpl visitBinaryExpression(BinaryExpression node) { | 
| EvaluationResultImpl leftResult = node.leftOperand.accept(this); | 
| EvaluationResultImpl rightResult = node.rightOperand.accept(this); | 
| +    TokenType operatorType = node.operator.type; | 
| +    if (operatorType != TokenType.BANG_EQ && operatorType != TokenType.EQ_EQ) { | 
| +      if (leftResult is ValidResult && ((leftResult as ValidResult)).isNull() || rightResult is ValidResult && ((rightResult as ValidResult)).isNull()) { | 
| +        return error(node, CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION); | 
| +      } | 
| +    } | 
| while (true) { | 
| -      if (node.operator.type == TokenType.AMPERSAND) { | 
| +      if (operatorType == TokenType.AMPERSAND) { | 
| return leftResult.bitAnd(node, rightResult); | 
| -      } else if (node.operator.type == TokenType.AMPERSAND_AMPERSAND) { | 
| +      } else if (operatorType == TokenType.AMPERSAND_AMPERSAND) { | 
| return leftResult.logicalAnd(node, rightResult); | 
| -      } else if (node.operator.type == TokenType.BANG_EQ) { | 
| +      } else if (operatorType == TokenType.BANG_EQ) { | 
| return leftResult.notEqual(node, rightResult); | 
| -      } else if (node.operator.type == TokenType.BAR) { | 
| +      } else if (operatorType == TokenType.BAR) { | 
| return leftResult.bitOr(node, rightResult); | 
| -      } else if (node.operator.type == TokenType.BAR_BAR) { | 
| +      } else if (operatorType == TokenType.BAR_BAR) { | 
| return leftResult.logicalOr(node, rightResult); | 
| -      } else if (node.operator.type == TokenType.CARET) { | 
| +      } else if (operatorType == TokenType.CARET) { | 
| return leftResult.bitXor(node, rightResult); | 
| -      } else if (node.operator.type == TokenType.EQ_EQ) { | 
| +      } else if (operatorType == TokenType.EQ_EQ) { | 
| return leftResult.equalEqual(node, rightResult); | 
| -      } else if (node.operator.type == TokenType.GT) { | 
| +      } else if (operatorType == TokenType.GT) { | 
| return leftResult.greaterThan(node, rightResult); | 
| -      } else if (node.operator.type == TokenType.GT_EQ) { | 
| +      } else if (operatorType == TokenType.GT_EQ) { | 
| return leftResult.greaterThanOrEqual(node, rightResult); | 
| -      } else if (node.operator.type == TokenType.GT_GT) { | 
| +      } else if (operatorType == TokenType.GT_GT) { | 
| return leftResult.shiftRight(node, rightResult); | 
| -      } else if (node.operator.type == TokenType.LT) { | 
| +      } else if (operatorType == TokenType.LT) { | 
| return leftResult.lessThan(node, rightResult); | 
| -      } else if (node.operator.type == TokenType.LT_EQ) { | 
| +      } else if (operatorType == TokenType.LT_EQ) { | 
| return leftResult.lessThanOrEqual(node, rightResult); | 
| -      } else if (node.operator.type == TokenType.LT_LT) { | 
| +      } else if (operatorType == TokenType.LT_LT) { | 
| return leftResult.shiftLeft(node, rightResult); | 
| -      } else if (node.operator.type == TokenType.MINUS) { | 
| +      } else if (operatorType == TokenType.MINUS) { | 
| return leftResult.minus(node, rightResult); | 
| -      } else if (node.operator.type == TokenType.PERCENT) { | 
| +      } else if (operatorType == TokenType.PERCENT) { | 
| return leftResult.remainder(node, rightResult); | 
| -      } else if (node.operator.type == TokenType.PLUS) { | 
| +      } else if (operatorType == TokenType.PLUS) { | 
| return leftResult.add(node, rightResult); | 
| -      } else if (node.operator.type == TokenType.STAR) { | 
| +      } else if (operatorType == TokenType.STAR) { | 
| return leftResult.times(node, rightResult); | 
| -      } else if (node.operator.type == TokenType.SLASH) { | 
| +      } else if (operatorType == TokenType.SLASH) { | 
| return leftResult.divide(node, rightResult); | 
| -      } else if (node.operator.type == TokenType.TILDE_SLASH) { | 
| +      } else if (operatorType == TokenType.TILDE_SLASH) { | 
| return leftResult.integerDivide(node, rightResult); | 
| } | 
| break; | 
| @@ -398,11 +413,14 @@ | 
| return error(node, null); | 
| } | 
| EvaluationResultImpl visitNode(ASTNode node) => error(node, null); | 
| -  EvaluationResultImpl visitNullLiteral(NullLiteral node) => new ValidResult(null); | 
| +  EvaluationResultImpl visitNullLiteral(NullLiteral node) => ValidResult.RESULT_NULL; | 
| EvaluationResultImpl visitParenthesizedExpression(ParenthesizedExpression node) => node.expression.accept(this); | 
| EvaluationResultImpl visitPrefixedIdentifier(PrefixedIdentifier node) => getConstantValue(node, node.element); | 
| EvaluationResultImpl visitPrefixExpression(PrefixExpression node) { | 
| EvaluationResultImpl operand2 = node.operand.accept(this); | 
| +    if (operand2 is ValidResult && ((operand2 as ValidResult)).isNull()) { | 
| +      return error(node, CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION); | 
| +    } | 
| while (true) { | 
| if (node.operator.type == TokenType.BANG) { | 
| return operand2.logicalNot(node); | 
| @@ -429,6 +447,7 @@ | 
| } | 
| return result; | 
| } | 
| + | 
| /** | 
| * Return a result object representing an error associated with the given node. | 
| * @param node the AST node associated with the error | 
| @@ -436,6 +455,7 @@ | 
| * @return a result object representing an error associated with the given node | 
| */ | 
| ErrorResult error(ASTNode node, ErrorCode code) => new ErrorResult.con1(node, code == null ? CompileTimeErrorCode.INVALID_CONSTANT : code); | 
| + | 
| /** | 
| * Return the constant value of the static constant represented by the given element. | 
| * @param node the node to be used if an error needs to be reported | 
| @@ -453,9 +473,12 @@ | 
| } | 
| } else if (element is ExecutableElement) { | 
| return new ValidResult(element); | 
| +    } else if (element is ClassElement) { | 
| +      return ValidResult.RESULT_OBJECT; | 
| } | 
| return error(node, null); | 
| } | 
| + | 
| /** | 
| * Return the union of the errors encoded in the given results. | 
| * @param leftResult the first set of errors, or {@code null} if there was no previous collection | 
| @@ -475,6 +498,7 @@ | 
| return leftResult; | 
| } | 
| } | 
| + | 
| /** | 
| * Instances of the class {@code DirectedGraph} implement a directed graph in which the nodes are | 
| * arbitrary (client provided) objects and edges are represented implicitly. The graph will allow an | 
| @@ -483,18 +507,15 @@ | 
| * @param N the type of the nodes in the graph | 
| */ | 
| class DirectedGraph<N> { | 
| + | 
| /** | 
| * The table encoding the edges in the graph. An edge is represented by an entry mapping the head | 
| * to a set of tails. Nodes that are not the head of any edge are represented by an entry mapping | 
| * the node to an empty set of tails. | 
| */ | 
| Map<N, Set<N>> _edges = new Map<N, Set<N>>(); | 
| + | 
| /** | 
| -   * Initialize a newly create directed graph to be empty. | 
| -   */ | 
| -  DirectedGraph() : super() { | 
| -  } | 
| -  /** | 
| * Add an edge from the given head node to the given tail node. Both nodes will be a part of the | 
| * graph after this method is invoked, whether or not they were before. | 
| * @param head the node at the head of the edge | 
| @@ -512,6 +533,7 @@ | 
| } | 
| javaSetAdd(tails, tail); | 
| } | 
| + | 
| /** | 
| * Add the given node to the set of nodes in the graph. | 
| * @param node the node to be added | 
| @@ -522,16 +544,19 @@ | 
| _edges[node] = new Set<N>(); | 
| } | 
| } | 
| + | 
| /** | 
| * Return a list of nodes that form a cycle, or {@code null} if there are no cycles in this graph. | 
| * @return a list of nodes that form a cycle | 
| */ | 
| List<N> findCycle() => null; | 
| + | 
| /** | 
| * Return the number of nodes in this graph. | 
| * @return the number of nodes in this graph | 
| */ | 
| int get nodeCount => _edges.length; | 
| + | 
| /** | 
| * Return a set containing the tails of edges that have the given node as their head. The set will | 
| * be empty if there are no such edges or if the node is not part of the graph. Clients must not | 
| @@ -546,11 +571,13 @@ | 
| } | 
| return tails; | 
| } | 
| + | 
| /** | 
| * Return {@code true} if this graph is empty. | 
| * @return {@code true} if this graph is empty | 
| */ | 
| bool isEmpty() => _edges.isEmpty; | 
| + | 
| /** | 
| * Remove all of the given nodes from this graph. As a consequence, any edges for which those | 
| * nodes were either a head or a tail will also be removed. | 
| @@ -561,6 +588,7 @@ | 
| removeNode(node); | 
| } | 
| } | 
| + | 
| /** | 
| * Remove the edge from the given head node to the given tail node. If there was no such edge then | 
| * the graph will be unmodified: the number of edges will be the same and the set of nodes will be | 
| @@ -575,6 +603,7 @@ | 
| tails.remove(tail); | 
| } | 
| } | 
| + | 
| /** | 
| * Remove the given node from this graph. As a consequence, any edges for which that node was | 
| * either a head or a tail will also be removed. | 
| @@ -586,6 +615,7 @@ | 
| tails.remove(node); | 
| } | 
| } | 
| + | 
| /** | 
| * Find one node (referred to as a sink node) that has no outgoing edges (that is, for which there | 
| * are no edges that have that node as the head of the edge) and remove it from this graph. Return | 
| @@ -602,6 +632,7 @@ | 
| removeNode(sink); | 
| return sink; | 
| } | 
| + | 
| /** | 
| * Return one node that has no outgoing edges (that is, for which there are no edges that have | 
| * that node as the head of the edge), or {@code null} if there are no such nodes. | 
| @@ -616,15 +647,18 @@ | 
| return null; | 
| } | 
| } | 
| + | 
| /** | 
| * Instances of the class {@code ErrorResult} represent the result of evaluating an expression that | 
| * is not a valid compile time constant. | 
| */ | 
| class ErrorResult extends EvaluationResultImpl { | 
| + | 
| /** | 
| * The errors that prevent the expression from being a valid compile time constant. | 
| */ | 
| List<ErrorResult_ErrorData> _errors = new List<ErrorResult_ErrorData>(); | 
| + | 
| /** | 
| * Initialize a newly created result representing the error with the given code reported against | 
| * the given node. | 
| @@ -632,11 +666,12 @@ | 
| * @param errorCode the error code for the error to be generated | 
| */ | 
| ErrorResult.con1(ASTNode node, ErrorCode errorCode) { | 
| -    _jtd_constructor_168_impl(node, errorCode); | 
| +    _jtd_constructor_171_impl(node, errorCode); | 
| } | 
| -  _jtd_constructor_168_impl(ASTNode node, ErrorCode errorCode) { | 
| +  _jtd_constructor_171_impl(ASTNode node, ErrorCode errorCode) { | 
| _errors.add(new ErrorResult_ErrorData(node, errorCode)); | 
| } | 
| + | 
| /** | 
| * Initialize a newly created result to represent the union of the errors in the given result | 
| * objects. | 
| @@ -644,9 +679,9 @@ | 
| * @param secondResult the second set of results being merged | 
| */ | 
| ErrorResult.con2(ErrorResult firstResult, ErrorResult secondResult) { | 
| -    _jtd_constructor_169_impl(firstResult, secondResult); | 
| +    _jtd_constructor_172_impl(firstResult, secondResult); | 
| } | 
| -  _jtd_constructor_169_impl(ErrorResult firstResult, ErrorResult secondResult) { | 
| +  _jtd_constructor_172_impl(ErrorResult firstResult, ErrorResult secondResult) { | 
| _errors.addAll(firstResult._errors); | 
| _errors.addAll(secondResult._errors); | 
| } | 
| @@ -717,14 +752,17 @@ | 
| EvaluationResultImpl timesValid(BinaryExpression node, ValidResult leftOperand) => this; | 
| } | 
| class ErrorResult_ErrorData { | 
| + | 
| /** | 
| * The node against which the error should be reported. | 
| */ | 
| ASTNode _node; | 
| + | 
| /** | 
| * The error code for the error to be generated. | 
| */ | 
| ErrorCode _errorCode; | 
| + | 
| /** | 
| * Initialize a newly created data holder to represent the error with the given code reported | 
| * against the given node. | 
| @@ -735,17 +773,20 @@ | 
| this._node = node; | 
| this._errorCode = errorCode; | 
| } | 
| + | 
| /** | 
| * Return the error code for the error to be generated. | 
| * @return the error code for the error to be generated | 
| */ | 
| ErrorCode get errorCode => _errorCode; | 
| + | 
| /** | 
| * Return the node against which the error should be reported. | 
| * @return the node against which the error should be reported | 
| */ | 
| ASTNode get node => _node; | 
| } | 
| + | 
| /** | 
| * Instances of the class {@code InternalResult} represent the result of attempting to evaluate a | 
| * expression. | 
| @@ -816,20 +857,24 @@ | 
| EvaluationResultImpl timesError(BinaryExpression node, ErrorResult leftOperand); | 
| EvaluationResultImpl timesValid(BinaryExpression node, ValidResult leftOperand); | 
| } | 
| + | 
| /** | 
| * Instances of the class {@code ReferenceFinder} add reference information for a given variable to | 
| * the bi-directional mapping used to order the evaluation of constants. | 
| */ | 
| class ReferenceFinder extends RecursiveASTVisitor<Object> { | 
| + | 
| /** | 
| * The element representing the variable whose initializer will be visited. | 
| */ | 
| VariableElement _source; | 
| + | 
| /** | 
| * A graph in which the nodes are the constant variables and the edges are from each variable to | 
| * the other constant variables that are referenced in the head's initializer. | 
| */ | 
| DirectedGraph<VariableElement> _referenceGraph; | 
| + | 
| /** | 
| * Initialize a newly created reference finder to find references from the given variable to other | 
| * variables and to add those references to the given graph. | 
| @@ -855,28 +900,69 @@ | 
| return null; | 
| } | 
| } | 
| + | 
| /** | 
| * Instances of the class {@code ValidResult} represent the result of attempting to evaluate a valid | 
| * compile time constant expression. | 
| */ | 
| class ValidResult extends EvaluationResultImpl { | 
| + | 
| /** | 
| * A result object representing the value 'false'. | 
| */ | 
| static ValidResult RESULT_FALSE = new ValidResult(false); | 
| + | 
| /** | 
| +   * A result object representing the an object without specific type on which no further operations | 
| +   * can be performed. | 
| +   */ | 
| +  static ValidResult RESULT_DYNAMIC = new ValidResult(null); | 
| + | 
| +  /** | 
| +   * A result object representing the an arbitrary integer on which no further operations can be | 
| +   * performed. | 
| +   */ | 
| +  static ValidResult RESULT_INT = new ValidResult(null); | 
| + | 
| +  /** | 
| +   * A result object representing the {@code null} value. | 
| +   */ | 
| +  static ValidResult RESULT_NULL = new ValidResult(null); | 
| + | 
| +  /** | 
| +   * A result object representing the an arbitrary numeric on which no further operations can be | 
| +   * performed. | 
| +   */ | 
| +  static ValidResult RESULT_NUM = new ValidResult(null); | 
| + | 
| +  /** | 
| +   * A result object representing the an arbitrary boolean on which no further operations can be | 
| +   * performed. | 
| +   */ | 
| +  static ValidResult RESULT_BOOL = new ValidResult(null); | 
| + | 
| +  /** | 
| * A result object representing the an arbitrary object on which no further operations can be | 
| * performed. | 
| */ | 
| static ValidResult RESULT_OBJECT = new ValidResult(new Object()); | 
| + | 
| /** | 
| +   * A result object representing the an arbitrary string on which no further operations can be | 
| +   * performed. | 
| +   */ | 
| +  static ValidResult RESULT_STRING = new ValidResult("<string>"); | 
| + | 
| +  /** | 
| * A result object representing the value 'true'. | 
| */ | 
| static ValidResult RESULT_TRUE = new ValidResult(true); | 
| + | 
| /** | 
| * The value of the expression. | 
| */ | 
| Object _value; | 
| + | 
| /** | 
| * Initialize a newly created result to represent the given value. | 
| * @param value the value of the expression | 
| @@ -887,6 +973,9 @@ | 
| EvaluationResultImpl add(BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.addToValid(node, this); | 
| EvaluationResultImpl bitAnd(BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.bitAndValid(node, this); | 
| EvaluationResultImpl bitNot(Expression node) { | 
| +    if (isSomeInt()) { | 
| +      return RESULT_INT; | 
| +    } | 
| if (_value == null) { | 
| return error(node); | 
| } else if (_value is int) { | 
| @@ -907,6 +996,9 @@ | 
| EvaluationResultImpl lessThanOrEqual(BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.lessThanOrEqualValid(node, this); | 
| EvaluationResultImpl logicalAnd(BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.logicalAndValid(node, this); | 
| EvaluationResultImpl logicalNot(Expression node) { | 
| +    if (isSomeBool()) { | 
| +      return RESULT_BOOL; | 
| +    } | 
| if (_value == null) { | 
| return RESULT_TRUE; | 
| } else if (_value is bool) { | 
| @@ -917,6 +1009,9 @@ | 
| EvaluationResultImpl logicalOr(BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.logicalOrValid(node, this); | 
| EvaluationResultImpl minus(BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.minusValid(node, this); | 
| EvaluationResultImpl negated(Expression node) { | 
| +    if (isSomeNum()) { | 
| +      return RESULT_INT; | 
| +    } | 
| if (_value == null) { | 
| return error(node); | 
| } else if (_value is int) { | 
| @@ -953,6 +1048,12 @@ | 
| } | 
| EvaluationResultImpl addToError(BinaryExpression node, ErrorResult leftOperand) => leftOperand; | 
| EvaluationResultImpl addToValid(BinaryExpression node, ValidResult leftOperand2) { | 
| +    if (isSomeNum() || leftOperand2.isSomeNum()) { | 
| +      if (isAnyNum() && leftOperand2.isAnyNum()) { | 
| +        return RESULT_NUM; | 
| +      } | 
| +      return error2(node, CompileTimeErrorCode.CONST_EVAL_TYPE_NUM); | 
| +    } | 
| Object leftValue = leftOperand2.value; | 
| if (leftValue == null) { | 
| return error(node.leftOperand); | 
| @@ -979,6 +1080,12 @@ | 
| } | 
| EvaluationResultImpl bitAndError(BinaryExpression node, ErrorResult leftOperand) => leftOperand; | 
| EvaluationResultImpl bitAndValid(BinaryExpression node, ValidResult leftOperand2) { | 
| +    if (isSomeInt() || leftOperand2.isSomeInt()) { | 
| +      if (isAnyInt() && leftOperand2.isAnyInt()) { | 
| +        return RESULT_INT; | 
| +      } | 
| +      return error2(node, CompileTimeErrorCode.CONST_EVAL_TYPE_INT); | 
| +    } | 
| Object leftValue = leftOperand2.value; | 
| if (leftValue == null) { | 
| return error(node.leftOperand); | 
| @@ -997,6 +1104,12 @@ | 
| } | 
| EvaluationResultImpl bitOrError(BinaryExpression node, ErrorResult leftOperand) => leftOperand; | 
| EvaluationResultImpl bitOrValid(BinaryExpression node, ValidResult leftOperand2) { | 
| +    if (isSomeInt() || leftOperand2.isSomeInt()) { | 
| +      if (isAnyInt() && leftOperand2.isAnyInt()) { | 
| +        return RESULT_INT; | 
| +      } | 
| +      return error2(node, CompileTimeErrorCode.CONST_EVAL_TYPE_INT); | 
| +    } | 
| Object leftValue = leftOperand2.value; | 
| if (leftValue == null) { | 
| return error(node.leftOperand); | 
| @@ -1015,6 +1128,12 @@ | 
| } | 
| EvaluationResultImpl bitXorError(BinaryExpression node, ErrorResult leftOperand) => leftOperand; | 
| EvaluationResultImpl bitXorValid(BinaryExpression node, ValidResult leftOperand2) { | 
| +    if (isSomeInt() || leftOperand2.isSomeInt()) { | 
| +      if (isAnyInt() && leftOperand2.isAnyInt()) { | 
| +        return RESULT_INT; | 
| +      } | 
| +      return error2(node, CompileTimeErrorCode.CONST_EVAL_TYPE_INT); | 
| +    } | 
| Object leftValue = leftOperand2.value; | 
| if (leftValue == null) { | 
| return error(node.leftOperand); | 
| @@ -1041,6 +1160,12 @@ | 
| } | 
| EvaluationResultImpl divideError(BinaryExpression node, ErrorResult leftOperand) => leftOperand; | 
| EvaluationResultImpl divideValid(BinaryExpression node, ValidResult leftOperand2) { | 
| +    if (isSomeNum() || leftOperand2.isSomeNum()) { | 
| +      if (isAnyNum() && leftOperand2.isAnyNum()) { | 
| +        return RESULT_NUM; | 
| +      } | 
| +      return error2(node, CompileTimeErrorCode.CONST_EVAL_TYPE_NUM); | 
| +    } | 
| Object leftValue = leftOperand2.value; | 
| if (leftValue == null) { | 
| return error(node.leftOperand); | 
| @@ -1066,6 +1191,11 @@ | 
| } | 
| EvaluationResultImpl equalEqualError(Expression node, ErrorResult leftOperand) => leftOperand; | 
| EvaluationResultImpl equalEqualValid(Expression node, ValidResult leftOperand) { | 
| +    if (node is BinaryExpression) { | 
| +      if (!isAnyNullBoolNumString() || !leftOperand.isAnyNullBoolNumString()) { | 
| +        return error2(node, CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL_NUM_STRING); | 
| +      } | 
| +    } | 
| Object leftValue = leftOperand.value; | 
| if (leftValue == null) { | 
| return valueOf2(_value == null); | 
| @@ -1099,6 +1229,12 @@ | 
| EvaluationResultImpl greaterThanError(BinaryExpression node, ErrorResult leftOperand) => leftOperand; | 
| EvaluationResultImpl greaterThanOrEqualError(BinaryExpression node, ErrorResult leftOperand) => leftOperand; | 
| EvaluationResultImpl greaterThanOrEqualValid(BinaryExpression node, ValidResult leftOperand2) { | 
| +    if (isSomeNum() || leftOperand2.isSomeNum()) { | 
| +      if (isAnyNum() && leftOperand2.isAnyNum()) { | 
| +        return RESULT_BOOL; | 
| +      } | 
| +      return error2(node, CompileTimeErrorCode.CONST_EVAL_TYPE_NUM); | 
| +    } | 
| Object leftValue = leftOperand2.value; | 
| if (leftValue == null) { | 
| return error(node.leftOperand); | 
| @@ -1120,6 +1256,12 @@ | 
| return error(node); | 
| } | 
| EvaluationResultImpl greaterThanValid(BinaryExpression node, ValidResult leftOperand2) { | 
| +    if (isSomeNum() || leftOperand2.isSomeNum()) { | 
| +      if (isAnyNum() && leftOperand2.isAnyNum()) { | 
| +        return RESULT_BOOL; | 
| +      } | 
| +      return error2(node, CompileTimeErrorCode.CONST_EVAL_TYPE_NUM); | 
| +    } | 
| Object leftValue = leftOperand2.value; | 
| if (leftValue == null) { | 
| return error(node.leftOperand); | 
| @@ -1142,6 +1284,12 @@ | 
| } | 
| EvaluationResultImpl integerDivideError(BinaryExpression node, ErrorResult leftOperand) => leftOperand; | 
| EvaluationResultImpl integerDivideValid(BinaryExpression node, ValidResult leftOperand2) { | 
| +    if (isSomeNum() || leftOperand2.isSomeNum()) { | 
| +      if (isAnyNum() && leftOperand2.isAnyNum()) { | 
| +        return RESULT_INT; | 
| +      } | 
| +      return error2(node, CompileTimeErrorCode.CONST_EVAL_TYPE_NUM); | 
| +    } | 
| Object leftValue = leftOperand2.value; | 
| if (leftValue == null) { | 
| return error(node.leftOperand); | 
| @@ -1171,6 +1319,12 @@ | 
| EvaluationResultImpl lessThanError(BinaryExpression node, ErrorResult leftOperand) => leftOperand; | 
| EvaluationResultImpl lessThanOrEqualError(BinaryExpression node, ErrorResult leftOperand) => leftOperand; | 
| EvaluationResultImpl lessThanOrEqualValid(BinaryExpression node, ValidResult leftOperand2) { | 
| +    if (isSomeNum() || leftOperand2.isSomeNum()) { | 
| +      if (isAnyNum() && leftOperand2.isAnyNum()) { | 
| +        return RESULT_BOOL; | 
| +      } | 
| +      return error2(node, CompileTimeErrorCode.CONST_EVAL_TYPE_NUM); | 
| +    } | 
| Object leftValue = leftOperand2.value; | 
| if (leftValue == null) { | 
| return error(node.leftOperand); | 
| @@ -1192,6 +1346,12 @@ | 
| return error(node); | 
| } | 
| EvaluationResultImpl lessThanValid(BinaryExpression node, ValidResult leftOperand2) { | 
| +    if (isSomeNum() || leftOperand2.isSomeNum()) { | 
| +      if (isAnyNum() && leftOperand2.isAnyNum()) { | 
| +        return RESULT_BOOL; | 
| +      } | 
| +      return error2(node, CompileTimeErrorCode.CONST_EVAL_TYPE_NUM); | 
| +    } | 
| Object leftValue = leftOperand2.value; | 
| if (leftValue == null) { | 
| return error(node.leftOperand); | 
| @@ -1214,14 +1374,29 @@ | 
| } | 
| EvaluationResultImpl logicalAndError(BinaryExpression node, ErrorResult leftOperand) => leftOperand; | 
| EvaluationResultImpl logicalAndValid(BinaryExpression node, ValidResult leftOperand) { | 
| +    if (isSomeBool() || leftOperand.isSomeBool()) { | 
| +      if (isAnyBool() && leftOperand.isAnyBool()) { | 
| +        return RESULT_BOOL; | 
| +      } | 
| +      return error2(node, CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL); | 
| +    } | 
| Object leftValue = leftOperand.value; | 
| -    if (leftValue is bool && ((leftValue as bool))) { | 
| -      return booleanConversion(node.rightOperand, _value); | 
| +    if (leftValue is bool) { | 
| +      if (((leftValue as bool))) { | 
| +        return booleanConversion(node.rightOperand, _value); | 
| +      } | 
| +      return RESULT_FALSE; | 
| } | 
| -    return RESULT_FALSE; | 
| +    return error(node); | 
| } | 
| EvaluationResultImpl logicalOrError(BinaryExpression node, ErrorResult leftOperand) => leftOperand; | 
| EvaluationResultImpl logicalOrValid(BinaryExpression node, ValidResult leftOperand) { | 
| +    if (isSomeBool() || leftOperand.isSomeBool()) { | 
| +      if (isAnyBool() && leftOperand.isAnyBool()) { | 
| +        return RESULT_BOOL; | 
| +      } | 
| +      return error2(node, CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL); | 
| +    } | 
| Object leftValue = leftOperand.value; | 
| if (leftValue is bool && ((leftValue as bool))) { | 
| return RESULT_TRUE; | 
| @@ -1230,6 +1405,12 @@ | 
| } | 
| EvaluationResultImpl minusError(BinaryExpression node, ErrorResult leftOperand) => leftOperand; | 
| EvaluationResultImpl minusValid(BinaryExpression node, ValidResult leftOperand2) { | 
| +    if (isSomeNum() || leftOperand2.isSomeNum()) { | 
| +      if (isAnyNum() && leftOperand2.isAnyNum()) { | 
| +        return RESULT_NUM; | 
| +      } | 
| +      return error2(node, CompileTimeErrorCode.CONST_EVAL_TYPE_NUM); | 
| +    } | 
| Object leftValue = leftOperand2.value; | 
| if (leftValue == null) { | 
| return error(node.leftOperand); | 
| @@ -1252,6 +1433,9 @@ | 
| } | 
| EvaluationResultImpl notEqualError(BinaryExpression node, ErrorResult leftOperand) => leftOperand; | 
| EvaluationResultImpl notEqualValid(BinaryExpression node, ValidResult leftOperand) { | 
| +    if (!isAnyNullBoolNumString() || !leftOperand.isAnyNullBoolNumString()) { | 
| +      return error2(node, CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL_NUM_STRING); | 
| +    } | 
| Object leftValue = leftOperand.value; | 
| if (leftValue == null) { | 
| return valueOf2(_value != null); | 
| @@ -1284,6 +1468,12 @@ | 
| } | 
| EvaluationResultImpl remainderError(BinaryExpression node, ErrorResult leftOperand) => leftOperand; | 
| EvaluationResultImpl remainderValid(BinaryExpression node, ValidResult leftOperand2) { | 
| +    if (isSomeNum() || leftOperand2.isSomeNum()) { | 
| +      if (isAnyNum() && leftOperand2.isAnyNum()) { | 
| +        return RESULT_NUM; | 
| +      } | 
| +      return error2(node, CompileTimeErrorCode.CONST_EVAL_TYPE_NUM); | 
| +    } | 
| Object leftValue = leftOperand2.value; | 
| if (leftValue == null) { | 
| return error(node.leftOperand); | 
| @@ -1309,6 +1499,12 @@ | 
| } | 
| EvaluationResultImpl shiftLeftError(BinaryExpression node, ErrorResult leftOperand) => leftOperand; | 
| EvaluationResultImpl shiftLeftValid(BinaryExpression node, ValidResult leftOperand2) { | 
| +    if (isSomeInt() || leftOperand2.isSomeInt()) { | 
| +      if (isAnyInt() && leftOperand2.isAnyInt()) { | 
| +        return RESULT_INT; | 
| +      } | 
| +      return error2(node, CompileTimeErrorCode.CONST_EVAL_TYPE_INT); | 
| +    } | 
| Object leftValue = leftOperand2.value; | 
| if (leftValue == null) { | 
| return error(node.leftOperand); | 
| @@ -1327,6 +1523,12 @@ | 
| } | 
| EvaluationResultImpl shiftRightError(BinaryExpression node, ErrorResult leftOperand) => leftOperand; | 
| EvaluationResultImpl shiftRightValid(BinaryExpression node, ValidResult leftOperand2) { | 
| +    if (isSomeInt() || leftOperand2.isSomeInt()) { | 
| +      if (isAnyInt() && leftOperand2.isAnyInt()) { | 
| +        return RESULT_INT; | 
| +      } | 
| +      return error2(node, CompileTimeErrorCode.CONST_EVAL_TYPE_INT); | 
| +    } | 
| Object leftValue = leftOperand2.value; | 
| if (leftValue == null) { | 
| return error(node.leftOperand); | 
| @@ -1345,6 +1547,12 @@ | 
| } | 
| EvaluationResultImpl timesError(BinaryExpression node, ErrorResult leftOperand) => leftOperand; | 
| EvaluationResultImpl timesValid(BinaryExpression node, ValidResult leftOperand2) { | 
| +    if (isSomeNum() || leftOperand2.isSomeNum()) { | 
| +      if (isAnyNum() && leftOperand2.isAnyNum()) { | 
| +        return RESULT_NUM; | 
| +      } | 
| +      return error2(node, CompileTimeErrorCode.CONST_EVAL_TYPE_NUM); | 
| +    } | 
| Object leftValue = leftOperand2.value; | 
| if (leftValue == null) { | 
| return error(node.leftOperand); | 
| @@ -1365,6 +1573,8 @@ | 
| } | 
| return error(node); | 
| } | 
| +  bool isNull() => identical(this, RESULT_NULL); | 
| + | 
| /** | 
| * Return the result of applying boolean conversion to the given value. | 
| * @param node the node against which errors should be reported | 
| @@ -1372,14 +1582,17 @@ | 
| * @return the result of applying boolean conversion to the given value | 
| */ | 
| EvaluationResultImpl booleanConversion(ASTNode node, Object value) { | 
| -    if (value == null) { | 
| -      return error(node); | 
| -    } else if (value is bool && ((value as bool))) { | 
| -      return RESULT_TRUE; | 
| +    if (value is bool) { | 
| +      if (((value as bool))) { | 
| +        return RESULT_TRUE; | 
| +      } else { | 
| +        return RESULT_FALSE; | 
| +      } | 
| } | 
| -    return RESULT_FALSE; | 
| +    return error(node); | 
| } | 
| ErrorResult error(ASTNode node) => error2(node, CompileTimeErrorCode.INVALID_CONSTANT); | 
| + | 
| /** | 
| * Return a result object representing an error associated with the given node. | 
| * @param node the AST node associated with the error | 
| @@ -1387,7 +1600,43 @@ | 
| * @return a result object representing an error associated with the given node | 
| */ | 
| ErrorResult error2(ASTNode node, ErrorCode code) => new ErrorResult.con1(node, code); | 
| + | 
| +  /** | 
| +   * Checks if this result has type "bool", with known or unknown value. | 
| +   */ | 
| +  bool isAnyBool() => isSomeBool() || identical(this, RESULT_TRUE) || identical(this, RESULT_FALSE); | 
| + | 
| +  /** | 
| +   * Checks if this result has type "int", with known or unknown value. | 
| +   */ | 
| +  bool isAnyInt() => identical(this, RESULT_INT) || _value is int; | 
| + | 
| +  /** | 
| +   * Checks if this result has one of the types - "bool", "num" or "string"; or may be {@code null}. | 
| +   */ | 
| +  bool isAnyNullBoolNumString() => isNull() || isAnyBool() || isAnyNum() || _value is String; | 
| + | 
| +  /** | 
| +   * Checks if this result has type "num", with known or unknown value. | 
| +   */ | 
| +  bool isAnyNum() => isSomeNum() || _value is num; | 
| + | 
| +  /** | 
| +   * Checks if this result has type "bool", exact value of which we don't know. | 
| +   */ | 
| +  bool isSomeBool() => identical(this, RESULT_BOOL); | 
| + | 
| +  /** | 
| +   * Checks if this result has type "int", exact value of which we don't know. | 
| +   */ | 
| +  bool isSomeInt() => identical(this, RESULT_INT); | 
| + | 
| +  /** | 
| +   * Checks if this result has type "num" (or "int"), exact value of which we don't know. | 
| +   */ | 
| +  bool isSomeNum() => identical(this, RESULT_DYNAMIC) || identical(this, RESULT_INT) || identical(this, RESULT_NUM); | 
| double toDouble(int value) => value.toDouble(); | 
| + | 
| /** | 
| * Return an error result that is the union of the two given error results. | 
| * @param firstError the first error to be combined | 
| @@ -1395,24 +1644,28 @@ | 
| * @return an error result that is the union of the two given error results | 
| */ | 
| ErrorResult union(ErrorResult firstError, ErrorResult secondError) => new ErrorResult.con2(firstError, secondError); | 
| + | 
| /** | 
| * Return a result object representing the given value. | 
| * @param value the value to be represented as a result object | 
| * @return a result object representing the given value | 
| */ | 
| ValidResult valueOf(int value) => new ValidResult(value); | 
| + | 
| /** | 
| * Return a result object representing the given value. | 
| * @param value the value to be represented as a result object | 
| * @return a result object representing the given value | 
| */ | 
| ValidResult valueOf2(bool value) => value ? RESULT_TRUE : RESULT_FALSE; | 
| + | 
| /** | 
| * Return a result object representing the given value. | 
| * @param value the value to be represented as a result object | 
| * @return a result object representing the given value | 
| */ | 
| ValidResult valueOf3(double value) => new ValidResult(value); | 
| + | 
| /** | 
| * Return a result object representing the given value. | 
| * @param value the value to be represented as a result object | 
|  |