inConstantContext property

  1. @override
bool inConstantContext
override

An expression e is said to occur in a constant context,

  • if e is an element of a constant list literal, or a key or value of an entry of a constant map literal.
  • if e is an actual argument of a constant object expression or of a metadata annotation.
  • if e is the initializing expression of a constant variable declaration.
  • if e is a switch case expression.
  • if e is an immediate subexpression of an expression e1 which occurs in a constant context, unless e1 is a throw expression or a function literal.

This roughly means that everything which is inside a syntactically constant expression is in a constant context. A throw expression is currently not allowed in a constant expression, but extensions affecting that status may be considered. A similar situation arises for function literals.

Note that the default value of an optional formal parameter is not a constant context. This choice reserves some freedom to modify the semantics of default values.

Implementation

@override
bool get inConstantContext {
  AstNode child = this;
  while (child is Expression ||
      child is ArgumentList ||
      child is MapLiteralEntry ||
      child is SpreadElement ||
      child is IfElement ||
      child is ForElement) {
    var parent = child.parent;
    if (parent is ConstantContextForExpressionImpl) {
      return true;
    } else if (parent is ConstantPatternImpl) {
      return true;
    } else if (parent is EnumConstantArguments) {
      return true;
    } else if (parent is TypedLiteralImpl && parent.constKeyword != null) {
      // Inside an explicitly `const` list or map literal.
      return true;
    } else if (parent is InstanceCreationExpression &&
        parent.keyword?.keyword == Keyword.CONST) {
      // Inside an explicitly `const` instance creation expression.
      return true;
    } else if (parent is Annotation) {
      // Inside an annotation.
      return true;
    } else if (parent is RecordLiteral && parent.constKeyword != null) {
      return true;
    } else if (parent is VariableDeclaration) {
      var grandParent = parent.parent;
      // Inside the initializer for a `const` variable declaration.
      return grandParent is VariableDeclarationList &&
          grandParent.keyword?.keyword == Keyword.CONST;
    } else if (parent is SwitchCase) {
      // Inside a switch case.
      return true;
    } else if (parent == null) {
      break;
    }
    child = parent;
  }
  return false;
}