src/com/google/javascript/jscomp/NodeUtil.java
/**
   * @param locals A predicate to apply to unknown local values.
   * @return Whether the result of the expression node is known to be a primitive value
   * or an object that has not yet escaped.  This guarantee is different
   * than that provided by isLiteralValue (where literal values are immune to side-effects
   * if unescaped) or isImmutableValue (which can be safely aliased).
   *
   * The concept of "local values" allow for the containment of side-effect operations. For
   * example, setting a property on a local value does not produce a global side-effect.
   *
   * Note that the concept of "local value" is not deep, it does not say anything
   * about the properties of the "local value" (all class instances have "constructor" properties
   * that are not local values for instance).
   *
   * Note that this method only provides the starting state of the expression result,
   * it does not guarantee that the value is forever a local value.  If the containing
   * method has any non-local side-effect, "local values" may escape.
   */
@param locals A predicate to apply to unknown local values.
@return Whether the result of the expression node is known to be a primitive value
or an object that has not yet escaped.  This guarantee is different
than that provided by isLiteralValue (where literal values are immune to side-effects
if unescaped) or isImmutableValue (which can be safely aliased).

The concept of "local values" allow for the containment of side-effect operations. For
example, setting a property on a local value does not produce a global side-effect.



Note that this method only provides the starting state of the expression result,
it does not guarantee that the value is forever a local value.  If the containing
method has any non-local side-effect, "local values" may escape.
@param locals A predicate to apply to unknown local values . @return Whether the result of the expression node is known to be a primitive value or an object that has not yet escaped . This guarantee is different than that provided by isLiteralValue ( where literal values are immune to side - effects if unescaped ) or isImmutableValue ( which can be safely aliased ) . The concept of " local values " allow for the containment of side - effect operations . For example setting a property on a local value does not produce a global side - effect . Note that this method only provides the starting state of the expression result it does not guarantee that the value is forever a local value . If the containing method has any non - local side - effect " local values " may escape .
static boolean evaluatesToLocalValue(Node value, Predicate<Node> locals) {
    switch (value.getToken()) {
      case ASSIGN:
        return NodeUtil.isImmutableValue(value.getLastChild())
            || (locals.apply(value) && evaluatesToLocalValue(value.getLastChild(), locals));
      case COMMA:
        return evaluatesToLocalValue(value.getLastChild(), locals);
      case AND:
      case OR:
        return evaluatesToLocalValue(value.getFirstChild(), locals)
            && evaluatesToLocalValue(value.getLastChild(), locals);
      case HOOK:
        return evaluatesToLocalValue(value.getSecondChild(), locals)
            && evaluatesToLocalValue(value.getLastChild(), locals);
      case THIS:
      case SUPER:
        return locals.apply(value);
      case NAME:
        return isImmutableValue(value) || locals.apply(value);
      case GETELEM:
      case GETPROP:
        return locals.apply(value);
      case CALL:
        return callHasLocalResult(value)
            || isToStringMethodCall(value)
            || locals.apply(value);
      case TAGGED_TEMPLATELIT:
        return callHasLocalResult(value) || locals.apply(value);
      case NEW:
        return newHasLocalResult(value) || locals.apply(value);
      case DELPROP:
      case INC:
      case DEC:
      case CLASS:
      case FUNCTION:
      case REGEXP:
      case EMPTY:
      case ARRAYLIT:
      case OBJECTLIT:
      case TEMPLATELIT:
        return true;
      case CAST:
        return evaluatesToLocalValue(value.getFirstChild(), locals);
      case SPREAD:
      case YIELD:
      case AWAIT:
        return false;
      default:
        if (isAssignmentOp(value)
            || isSimpleOperator(value)
            || isImmutableValue(value)) {
          return true;
        }
        throw new IllegalStateException(
            "Unexpected expression node: " + value + "\n parent:" + value.getParent());
    }
  }
static boolean evaluatesToLocalValue ( Node value , Predicate < Node > locals ) { switch ( value . getToken ( ) ) { case ASSIGN : return NodeUtil . isImmutableValue ( value . getLastChild ( ) ) || ( locals . apply ( value ) && evaluatesToLocalValue ( value . getLastChild ( ) , locals ) ) ; case COMMA : return evaluatesToLocalValue ( value . getLastChild ( ) , locals ) ; case AND : case OR : return evaluatesToLocalValue ( value . getFirstChild ( ) , locals ) && evaluatesToLocalValue ( value . getLastChild ( ) , locals ) ; case HOOK : return evaluatesToLocalValue ( value . getSecondChild ( ) , locals ) && evaluatesToLocalValue ( value . getLastChild ( ) , locals ) ; case THIS : case SUPER : return locals . apply ( value ) ; case NAME : return isImmutableValue ( value ) || locals . apply ( value ) ; case GETELEM : case GETPROP : return locals . apply ( value ) ; case CALL : return callHasLocalResult ( value ) || isToStringMethodCall ( value ) || locals . apply ( value ) ; case TAGGED_TEMPLATELIT : return callHasLocalResult ( value ) || locals . apply ( value ) ; case NEW : return newHasLocalResult ( value ) || locals . apply ( value ) ; case DELPROP : case INC : case DEC : case CLASS : case FUNCTION : case REGEXP : case EMPTY : case ARRAYLIT : case OBJECTLIT : case TEMPLATELIT : return true ; case CAST : return evaluatesToLocalValue ( value . getFirstChild ( ) , locals ) ; case SPREAD : case YIELD : case AWAIT : return false ; default : if ( isAssignmentOp ( value ) || isSimpleOperator ( value ) || isImmutableValue ( value ) ) { return true ; } throw new IllegalStateException ( "Unexpected expression node: " + value + "\n parent:" + value . getParent ( ) ) ; } }
@param locals A predicate to apply to unknown local values.
@param locals A predicate to apply to unknown local values .
// A result that is aliased by a non-local name, is the effectively the // same as returning a non-local name, but this doesn't matter if the // value is immutable. // There is no information about the locality of object properties. // TODO(johnlenz): we can do better for await if we use type information.  That is, // if we know the promise being awaited on is a immutable value type (string, etc) // we could return true here. // Other op force a local value: //  '' + g (a local string) //  x -= g (x is now an local number)