| // Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file | |
| // for details. All rights reserved. Use of this source code is governed by a | |
| // BSD-style license that can be found in the LICENSE file. | |
| part of '../../ast.dart'; | |
| /// Generalized notion of a variable. | |
| sealed class VariableBase extends TreeNode implements Annotatable { | |
| abstract VariableContext context; | |
| /// The cosmetic name of the variable from the source code, if exists. | |
| String? get cosmeticName; | |
| void set cosmeticName(String? value); | |
| int flags = 0; | |
| @override | |
| void toTextInternal(AstPrinter printer) { | |
| printer.write(printer.getVariableName(this)); | |
| } | |
| } | |
| /// The root of the sealed hierarchy of non-type variables. | |
| sealed class Variable extends VariableBase implements ContextConsumer { | |
| // These flags are shared between all [Variable]s since they must all be | |
| // serialized uniformly. | |
| static const int FlagFinal = 1 << 0; // Must match serialized bit positions. | |
| static const int FlagConst = 1 << 1; | |
| static const int FlagHasDeclaredInitializer = 1 << 2; | |
| static const int FlagInitializingFormal = 1 << 3; | |
| static const int FlagCovariantByClass = 1 << 4; | |
| static const int FlagLate = 1 << 5; | |
| static const int FlagRequired = 1 << 6; | |
| static const int FlagCovariantByDeclaration = 1 << 7; | |
| static const int FlagLowered = 1 << 8; | |
| static const int FlagSynthesized = 1 << 9; | |
| static const int FlagHoisted = 1 << 10; | |
| static const int FlagWildcard = 1 << 11; | |
| static const int FlagSuperInitializingFormal = 1 << 12; | |
| static const int FlagErroneouslyInitialized = 1 << 13; | |
| static const int FlagRenamedPrivateNamedParameter = 1 << 14; | |
| /// The static type of the variable, either declared or inferred type during | |
| /// type inference. | |
| abstract DartType type; | |
| /// For locals, this is the initial value. | |
| /// For parameters, this is the default value. | |
| /// | |
| /// Should be null in other cases. | |
| abstract Expression? initializer; | |
| /// List of metadata annotations on the variable declaration. | |
| /// | |
| /// This defaults to an immutable empty list. Use [addAnnotation] to add | |
| /// annotations if needed. | |
| @override | |
| abstract List<Expression> annotations; | |
| /// Whether the variable is declared with the `final` keyword. | |
| abstract bool isFinal; | |
| /// Whether the variable is declared with the `const` keyword. | |
| abstract bool isConst; | |
| /// Whether the variable is declared with the `late` keyword. | |
| /// | |
| /// The `late` modifier is only supported on local variables and not on | |
| /// parameters. | |
| abstract bool isLate; | |
| /// Whether the variable is declared as an initializing formal parameter of | |
| /// a constructor. | |
| abstract bool isInitializingFormal; | |
| /// Whether this variable is synthesized, that is, it is _not_ declared in | |
| /// the source code. | |
| /// | |
| /// The name of a variable can only be omitted if the variable is synthesized. | |
| /// Otherwise, its name is as provided in the source code. | |
| abstract bool isSynthesized; | |
| /// Whether the declaration of this variable is has been moved to an earlier | |
| /// source location. | |
| /// | |
| /// This is for instance the case for variables declared in a pattern, where | |
| /// the lowering requires the variable to be declared before the expression | |
| /// that performs that matching in which its initialization occurs. | |
| abstract bool isHoisted; | |
| /// Whether the variable has an initializer, either by declaration or copied | |
| /// from an original declaration. | |
| /// | |
| /// Note that the variable might have a synthesized initializer expression, | |
| /// so `hasDeclaredInitializer == false` doesn't imply `initializer == null`. | |
| /// For instance, for duplicate variable names, an invalid expression is set | |
| /// as the initializer of the second variable. | |
| abstract bool hasDeclaredInitializer; | |
| /// If this [Variable] is a parameter of a method, indicates | |
| /// whether the method implementation needs to contain a runtime type check to | |
| /// deal with generic covariance. | |
| /// | |
| /// When `true`, runtime checks may need to be performed. | |
| abstract bool isCovariantByClass; | |
| /// Whether the parameter is declared with the `required` keyword. | |
| /// | |
| /// The `required` modifier is only supported on named parameters and not on | |
| /// positional parameters and local variables. | |
| abstract bool isRequired; | |
| /// Whether the parameter is declared with the `covariant` keyword. | |
| abstract bool isCovariantByDeclaration; | |
| /// Whether the variable is part of a lowering. | |
| /// | |
| /// If a variable is part of a lowering its name may be synthesized so that it | |
| /// doesn't reflect the name used in the source code and might not have a | |
| /// one-to-one correspondence with the variable in the source. | |
| /// | |
| /// Lowering is used for instance of encoding of 'this' in extension instance | |
| /// members and encoding of late locals. | |
| abstract bool isLowered; | |
| /// Whether the variable is a wildcard variable, that is, it was named '_' in | |
| /// the source code with the wildcard feature enabled.. | |
| abstract bool isWildcard; | |
| /// Whether the variable is declared as a super initializing formal parameter | |
| /// of a constructor. | |
| abstract bool isSuperInitializingFormal; | |
| abstract bool isErroneouslyInitialized; | |
| /// Offset of the declaration, set and used when writing the binary. | |
| abstract int binaryOffsetNoTag; | |
| /// Offset of the equals sign in the source file it comes from. | |
| /// | |
| /// Valid values are from 0 and up, or -1 ([TreeNode.noOffset]) | |
| /// if the equals sign offset is not available (e.g. if not initialized) | |
| /// (this is the default if none is specifically set). | |
| abstract int fileEqualsOffset; | |
| void clearAnnotations(); | |
| @override | |
| List<int>? get fileOffsetsIfMultiple => [fileOffset, fileEqualsOffset]; | |
| /// Whether the variable is assignable. | |
| /// | |
| /// This is `true` if the variable is neither constant nor final, or if it | |
| /// is late final without an initializer. | |
| bool get isAssignable; | |
| @override | |
| R accept<R>(VariableVisitor<R> visitor); | |
| @override | |
| R accept1<R, A>(VariableVisitor1<R, A> visitor, A arg); | |
| @override | |
| void toTextInternal(AstPrinter printer) { | |
| // TODO(johnniwinther): Update this. | |
| printer.writeVariableInitialization(this); | |
| printer.write(';'); | |
| } | |
| } | |
| /// A variable declared within the body of a member. | |
| /// | |
| /// This excludes [FunctionParameter], [ThisVariable] and [CatchVariable] which | |
| /// are all declared by the enclosing node. | |
| sealed class DeclaredVariable extends Variable { | |
| /// Declaration node for the variable, if available. | |
| abstract VariableDeclaration? variableDeclaration; | |
| } | |
| /// Local variables. They aren't Statements. A [LocalVariable] is "declared" in | |
| /// the [VariableContext] it appears in. [VariableInitializationBase] | |
| /// (which is a [Statement]) marks the spot of the original variable declaration | |
| /// in the Dart program. | |
| class LocalVariable extends DeclaredVariable { | |
| /// The name of the variable as provided in the source code. | |
| String name; | |
| @override | |
| DartType type; | |
| @override | |
| VariableDeclaration? variableDeclaration; | |
| @override | |
| List<Expression> annotations = const <Expression>[]; | |
| @override | |
| late VariableContext context; | |
| @override | |
| // TODO(johnniwinther): Remove this. | |
| Expression? initializer; | |
| new({ | |
| required this.name, | |
| DartType? type, | |
| bool isFinal = false, | |
| bool isWildcard = false, | |
| bool hasDeclaredInitializer = false, | |
| this.initializer, | |
| }) : type = type ?? const DynamicType() { | |
| this.isFinal = isFinal; | |
| this.isWildcard = isWildcard; | |
| this.hasDeclaredInitializer = hasDeclaredInitializer; | |
| this.initializer?.parent = this; | |
| } | |
| @override | |
| void addAnnotation(Expression annotation) { | |
| if (annotations.isEmpty) { | |
| annotations = <Expression>[]; | |
| } | |
| annotations.add(annotation..parent = this); | |
| } | |
| @override | |
| bool get isFinal => flags & Variable.FlagFinal != 0; | |
| @override | |
| void set isFinal(bool value) { | |
| flags = value | |
| ? (flags | Variable.FlagFinal) | |
| : (flags & ~Variable.FlagFinal); | |
| } | |
| @override | |
| bool get isWildcard => flags & Variable.FlagWildcard != 0; | |
| @override | |
| void set isWildcard(bool value) { | |
| flags = value | |
| ? (flags | Variable.FlagWildcard) | |
| : (flags & ~Variable.FlagWildcard); | |
| } | |
| @override | |
| bool get isConst => flags & Variable.FlagConst != 0; | |
| @override | |
| void set isConst(bool value) { | |
| flags = value | |
| ? (flags | Variable.FlagConst) | |
| : (flags & ~Variable.FlagConst); | |
| } | |
| @override | |
| bool get isLate => flags & Variable.FlagLate != 0; | |
| @override | |
| void set isLate(bool value) { | |
| flags = value ? (flags | Variable.FlagLate) : (flags & ~Variable.FlagLate); | |
| } | |
| @override | |
| bool get isLowered => flags & Variable.FlagLowered != 0; | |
| @override | |
| void set isLowered(bool value) { | |
| flags = value | |
| ? (flags | Variable.FlagLowered) | |
| : (flags & ~Variable.FlagLowered); | |
| } | |
| @override | |
| bool get isHoisted => flags & Variable.FlagHoisted != 0; | |
| @override | |
| void set isHoisted(bool value) { | |
| flags = value | |
| ? (flags | Variable.FlagHoisted) | |
| : (flags & ~Variable.FlagHoisted); | |
| } | |
| @override | |
| bool get isCovariantByClass => false; | |
| @override | |
| void set isCovariantByClass(bool value) { | |
| throw new UnsupportedError("${this.runtimeType}"); | |
| } | |
| @override | |
| bool get isCovariantByDeclaration => false; | |
| @override | |
| void set isCovariantByDeclaration(bool value) { | |
| throw new UnsupportedError("${this.runtimeType}"); | |
| } | |
| @override | |
| bool get isErroneouslyInitialized => | |
| flags & Variable.FlagErroneouslyInitialized != 0; | |
| @override | |
| void set isErroneouslyInitialized(bool value) { | |
| flags = value | |
| ? (flags | Variable.FlagErroneouslyInitialized) | |
| : (flags & ~Variable.FlagErroneouslyInitialized); | |
| } | |
| @override | |
| bool get hasDeclaredInitializer => | |
| flags & Variable.FlagHasDeclaredInitializer != 0; | |
| @override | |
| void set hasDeclaredInitializer(bool value) { | |
| flags = value | |
| ? (flags | Variable.FlagHasDeclaredInitializer) | |
| : (flags & ~Variable.FlagHasDeclaredInitializer); | |
| } | |
| @override | |
| bool get isInitializingFormal => false; | |
| @override | |
| void set isInitializingFormal(bool value) { | |
| throw new UnsupportedError("${this.runtimeType}"); | |
| } | |
| @override | |
| bool get isRequired => false; | |
| @override | |
| void set isRequired(bool value) { | |
| throw new UnsupportedError("${this.runtimeType}"); | |
| } | |
| @override | |
| bool get isSuperInitializingFormal => false; | |
| @override | |
| void set isSuperInitializingFormal(bool value) { | |
| throw new UnsupportedError("${this.runtimeType}"); | |
| } | |
| @override | |
| bool get isSynthesized => false; | |
| @override | |
| void set isSynthesized(bool value) { | |
| throw new UnsupportedError("${this.runtimeType}"); | |
| } | |
| @override | |
| bool get isAssignable { | |
| if (isConst) return false; | |
| if (isFinal) { | |
| if (isLate) return initializer == null; | |
| return false; | |
| } | |
| return true; | |
| } | |
| @override | |
| R accept<R>(VariableVisitor<R> v) => v.visitLocalVariable(this); | |
| @override | |
| R accept1<R, A>(VariableVisitor1<R, A> v, A arg) => | |
| v.visitLocalVariable(this, arg); | |
| @override | |
| void transformChildren(Transformer v) { | |
| v.transformList(annotations, this); | |
| type = v.visitDartType(type); | |
| if (initializer != null) { | |
| initializer = v.transform(initializer!); | |
| initializer?.parent = this; | |
| } | |
| } | |
| @override | |
| void transformOrRemoveChildren(RemovingTransformer v) { | |
| v.transformExpressionList(annotations, this); | |
| type = v.visitDartType(type, cannotRemoveSentinel); | |
| if (initializer != null) { | |
| initializer = v.transformOrRemoveExpression(initializer!); | |
| initializer?.parent = this; | |
| } | |
| } | |
| @override | |
| void visitChildren(Visitor v) { | |
| visitList(annotations, v); | |
| type.accept(v); | |
| initializer?.accept(v); | |
| } | |
| @override | |
| String toString() { | |
| return "LocalVariable(${toStringInternal()})"; | |
| } | |
| @override | |
| void toTextInternal(AstPrinter printer) { | |
| printer.writeExpressionVariable(this); | |
| } | |
| @override | |
| int binaryOffsetNoTag = -1; | |
| @override | |
| List<VariableContext>? get capturedContexts { | |
| throw new UnsupportedError("${this.runtimeType}.capturedContexts"); | |
| } | |
| @override | |
| void set capturedContexts(List<VariableContext>? value) { | |
| throw new UnsupportedError("${this.runtimeType}.capturedContexts="); | |
| } | |
| @override | |
| int fileEqualsOffset = TreeNode.noOffset; | |
| @override | |
| void clearAnnotations() { | |
| annotations.clear(); | |
| } | |
| @override | |
| @Deprecated('Use LocalVariable.name instead.') | |
| String? get cosmeticName => name; | |
| @override | |
| @Deprecated('Use LocalVariable.name instead.') | |
| void set cosmeticName(String? value) { | |
| name = value!; | |
| } | |
| } | |
| /// Variable for a local function declaration. | |
| /// | |
| /// Local functions, declared using [FunctionDeclaration], have a | |
| /// [LocalFunctionVariable] which hold their name and is used to identify the | |
| /// function in [LocalFunctionInvocation]s and tear-offs through [VariableGet]. | |
| class LocalFunctionVariable extends DeclaredVariable { | |
| /// The name of the variable as provided in the source code. | |
| String name; | |
| @override | |
| DartType type; | |
| @override | |
| VariableDeclaration? variableDeclaration; | |
| @override | |
| List<Expression> annotations = const <Expression>[]; | |
| @override | |
| late VariableContext context; | |
| @override | |
| // TODO(johnniwinther): Remove this. | |
| Expression? initializer; | |
| new({ | |
| required this.name, | |
| DartType? type, | |
| bool isWildcard = false, | |
| bool isLowered = false, | |
| bool isSynthesized = false, | |
| }) : type = type ?? const DynamicType() { | |
| this.isFinal = true; | |
| this.isWildcard = isWildcard; | |
| this.isLowered = isLowered; | |
| this.isSynthesized = isSynthesized; | |
| } | |
| @override | |
| void addAnnotation(Expression annotation) { | |
| if (annotations.isEmpty) { | |
| annotations = <Expression>[]; | |
| } | |
| annotations.add(annotation..parent = this); | |
| } | |
| @override | |
| bool get isFinal => flags & Variable.FlagFinal != 0; | |
| @override | |
| void set isFinal(bool value) { | |
| flags = value | |
| ? (flags | Variable.FlagFinal) | |
| : (flags & ~Variable.FlagFinal); | |
| } | |
| @override | |
| bool get isWildcard => flags & Variable.FlagWildcard != 0; | |
| @override | |
| void set isWildcard(bool value) { | |
| flags = value | |
| ? (flags | Variable.FlagWildcard) | |
| : (flags & ~Variable.FlagWildcard); | |
| } | |
| @override | |
| bool get isConst => flags & Variable.FlagConst != 0; | |
| @override | |
| void set isConst(bool value) { | |
| flags = value | |
| ? (flags | Variable.FlagConst) | |
| : (flags & ~Variable.FlagConst); | |
| } | |
| @override | |
| bool get isLate => flags & Variable.FlagLate != 0; | |
| @override | |
| void set isLate(bool value) { | |
| flags = value ? (flags | Variable.FlagLate) : (flags & ~Variable.FlagLate); | |
| } | |
| @override | |
| bool get isLowered => flags & Variable.FlagLowered != 0; | |
| @override | |
| void set isLowered(bool value) { | |
| flags = value | |
| ? (flags | Variable.FlagLowered) | |
| : (flags & ~Variable.FlagLowered); | |
| } | |
| @override | |
| bool get isHoisted => flags & Variable.FlagHoisted != 0; | |
| @override | |
| void set isHoisted(bool value) { | |
| flags = value | |
| ? (flags | Variable.FlagHoisted) | |
| : (flags & ~Variable.FlagHoisted); | |
| } | |
| @override | |
| bool get isCovariantByClass => false; | |
| @override | |
| void set isCovariantByClass(bool value) { | |
| throw new UnsupportedError("${this.runtimeType}"); | |
| } | |
| @override | |
| bool get isCovariantByDeclaration => false; | |
| @override | |
| void set isCovariantByDeclaration(bool value) { | |
| throw new UnsupportedError("${this.runtimeType}"); | |
| } | |
| @override | |
| bool get isErroneouslyInitialized => | |
| flags & Variable.FlagErroneouslyInitialized != 0; | |
| @override | |
| void set isErroneouslyInitialized(bool value) { | |
| flags = value | |
| ? (flags | Variable.FlagErroneouslyInitialized) | |
| : (flags & ~Variable.FlagErroneouslyInitialized); | |
| } | |
| @override | |
| bool get hasDeclaredInitializer => | |
| flags & Variable.FlagHasDeclaredInitializer != 0; | |
| @override | |
| void set hasDeclaredInitializer(bool value) { | |
| flags = value | |
| ? (flags | Variable.FlagHasDeclaredInitializer) | |
| : (flags & ~Variable.FlagHasDeclaredInitializer); | |
| } | |
| @override | |
| bool get isInitializingFormal => false; | |
| @override | |
| void set isInitializingFormal(bool value) { | |
| throw new UnsupportedError("${this.runtimeType}"); | |
| } | |
| @override | |
| bool get isRequired => false; | |
| @override | |
| void set isRequired(bool value) { | |
| throw new UnsupportedError("${this.runtimeType}"); | |
| } | |
| @override | |
| bool get isSuperInitializingFormal => false; | |
| @override | |
| void set isSuperInitializingFormal(bool value) { | |
| throw new UnsupportedError("${this.runtimeType}"); | |
| } | |
| @override | |
| bool get isSynthesized => flags & Variable.FlagSynthesized != 0; | |
| @override | |
| void set isSynthesized(bool value) { | |
| flags = value | |
| ? (flags | Variable.FlagSynthesized) | |
| : (flags & ~Variable.FlagSynthesized); | |
| } | |
| @override | |
| bool get isAssignable { | |
| if (isConst) return false; | |
| if (isFinal) { | |
| if (isLate) return initializer == null; | |
| return false; | |
| } | |
| return true; | |
| } | |
| @override | |
| R accept<R>(VariableVisitor<R> v) => v.visitLocalFunctionVariable(this); | |
| @override | |
| R accept1<R, A>(VariableVisitor1<R, A> v, A arg) => | |
| v.visitLocalFunctionVariable(this, arg); | |
| @override | |
| void transformChildren(Transformer v) { | |
| v.transformList(annotations, this); | |
| type = v.visitDartType(type); | |
| if (initializer != null) { | |
| initializer = v.transform(initializer!); | |
| initializer?.parent = this; | |
| } | |
| } | |
| @override | |
| void transformOrRemoveChildren(RemovingTransformer v) { | |
| v.transformExpressionList(annotations, this); | |
| type = v.visitDartType(type, cannotRemoveSentinel); | |
| if (initializer != null) { | |
| initializer = v.transformOrRemoveExpression(initializer!); | |
| initializer?.parent = this; | |
| } | |
| } | |
| @override | |
| void visitChildren(Visitor v) { | |
| visitList(annotations, v); | |
| type.accept(v); | |
| initializer?.accept(v); | |
| } | |
| @override | |
| String toString() { | |
| return "LocalVariable(${toStringInternal()})"; | |
| } | |
| @override | |
| void toTextInternal(AstPrinter printer) { | |
| printer.writeExpressionVariable(this); | |
| } | |
| @override | |
| int binaryOffsetNoTag = -1; | |
| @override | |
| List<VariableContext>? get capturedContexts { | |
| throw new UnsupportedError("${this.runtimeType}.capturedContexts"); | |
| } | |
| @override | |
| void set capturedContexts(List<VariableContext>? value) { | |
| throw new UnsupportedError("${this.runtimeType}.capturedContexts="); | |
| } | |
| @override | |
| int fileEqualsOffset = TreeNode.noOffset; | |
| @override | |
| void clearAnnotations() { | |
| annotations.clear(); | |
| } | |
| @override | |
| @Deprecated('Use LocalFunctionVariable.name instead.') | |
| String? get cosmeticName => name; | |
| @override | |
| @Deprecated('Use LocalFunctionVariable.name instead.') | |
| void set cosmeticName(String? value) { | |
| name = value!; | |
| } | |
| } | |
| /// A late local variable. | |
| class LateVariable extends DeclaredVariable { | |
| String name; | |
| @override | |
| DartType type; | |
| @override | |
| VariableDeclaration? variableDeclaration; | |
| @override | |
| List<Expression> annotations = const <Expression>[]; | |
| @override | |
| late VariableContext context; | |
| Expression? initialValue; | |
| new({ | |
| required String this.name, | |
| DartType? type, | |
| bool isFinal = false, | |
| bool isWildcard = false, | |
| bool hasDeclaredInitializer = false, | |
| this.initialValue, | |
| }) : type = type ?? const DynamicType() { | |
| this.isFinal = isFinal; | |
| this.isLate = true; | |
| this.isWildcard = isWildcard; | |
| this.hasDeclaredInitializer = hasDeclaredInitializer; | |
| this.initialValue?.parent = this; | |
| } | |
| @Deprecated('Use LateVariable.initialValue instead.') | |
| @override | |
| Expression? get initializer => initialValue; | |
| @Deprecated('Use LateVariable.initialValue instead.') | |
| @override | |
| void set initializer(Expression? value) { | |
| initialValue = value; | |
| } | |
| @override | |
| void addAnnotation(Expression annotation) { | |
| if (annotations.isEmpty) { | |
| annotations = <Expression>[]; | |
| } | |
| annotations.add(annotation..parent = this); | |
| } | |
| @override | |
| bool get isFinal => flags & Variable.FlagFinal != 0; | |
| @override | |
| void set isFinal(bool value) { | |
| flags = value | |
| ? (flags | Variable.FlagFinal) | |
| : (flags & ~Variable.FlagFinal); | |
| } | |
| @override | |
| bool get isWildcard => flags & Variable.FlagWildcard != 0; | |
| @override | |
| void set isWildcard(bool value) { | |
| flags = value | |
| ? (flags | Variable.FlagWildcard) | |
| : (flags & ~Variable.FlagWildcard); | |
| } | |
| @override | |
| bool get isConst => flags & Variable.FlagConst != 0; | |
| @override | |
| void set isConst(bool value) { | |
| flags = value | |
| ? (flags | Variable.FlagConst) | |
| : (flags & ~Variable.FlagConst); | |
| } | |
| @override | |
| bool get isLate => flags & Variable.FlagLate != 0; | |
| @override | |
| void set isLate(bool value) { | |
| flags = value ? (flags | Variable.FlagLate) : (flags & ~Variable.FlagLate); | |
| } | |
| @override | |
| bool get isLowered => flags & Variable.FlagLowered != 0; | |
| @override | |
| void set isLowered(bool value) { | |
| flags = value | |
| ? (flags | Variable.FlagLowered) | |
| : (flags & ~Variable.FlagLowered); | |
| } | |
| @override | |
| bool get isHoisted => flags & Variable.FlagHoisted != 0; | |
| @override | |
| void set isHoisted(bool value) { | |
| flags = value | |
| ? (flags | Variable.FlagHoisted) | |
| : (flags & ~Variable.FlagHoisted); | |
| } | |
| @override | |
| bool get isCovariantByClass => false; | |
| @override | |
| void set isCovariantByClass(bool value) { | |
| throw new UnsupportedError("${this.runtimeType}"); | |
| } | |
| @override | |
| bool get isCovariantByDeclaration => false; | |
| @override | |
| void set isCovariantByDeclaration(bool value) { | |
| throw new UnsupportedError("${this.runtimeType}"); | |
| } | |
| @override | |
| bool get isErroneouslyInitialized => | |
| flags & Variable.FlagErroneouslyInitialized != 0; | |
| @override | |
| void set isErroneouslyInitialized(bool value) { | |
| flags = value | |
| ? (flags | Variable.FlagErroneouslyInitialized) | |
| : (flags & ~Variable.FlagErroneouslyInitialized); | |
| } | |
| @override | |
| bool get hasDeclaredInitializer => | |
| flags & Variable.FlagHasDeclaredInitializer != 0; | |
| @override | |
| void set hasDeclaredInitializer(bool value) { | |
| flags = value | |
| ? (flags | Variable.FlagHasDeclaredInitializer) | |
| : (flags & ~Variable.FlagHasDeclaredInitializer); | |
| } | |
| @override | |
| bool get isInitializingFormal => false; | |
| @override | |
| void set isInitializingFormal(bool value) { | |
| throw new UnsupportedError("${this.runtimeType}"); | |
| } | |
| @override | |
| bool get isRequired => false; | |
| @override | |
| void set isRequired(bool value) { | |
| throw new UnsupportedError("${this.runtimeType}"); | |
| } | |
| @override | |
| bool get isSuperInitializingFormal => false; | |
| @override | |
| void set isSuperInitializingFormal(bool value) { | |
| throw new UnsupportedError("${this.runtimeType}"); | |
| } | |
| @override | |
| bool get isSynthesized => false; | |
| @override | |
| void set isSynthesized(bool value) { | |
| throw new UnsupportedError("${this.runtimeType}"); | |
| } | |
| @override | |
| bool get isAssignable { | |
| if (isConst) return false; | |
| if (isFinal) { | |
| if (isLate) return initialValue == null; | |
| return false; | |
| } | |
| return true; | |
| } | |
| @override | |
| R accept<R>(VariableVisitor<R> v) => v.visitLateVariable(this); | |
| @override | |
| R accept1<R, A>(VariableVisitor1<R, A> v, A arg) => | |
| v.visitLateVariable(this, arg); | |
| @override | |
| void transformChildren(Transformer v) { | |
| v.transformList(annotations, this); | |
| type = v.visitDartType(type); | |
| if (initialValue != null) { | |
| initialValue = v.transform(initialValue!); | |
| initialValue?.parent = this; | |
| } | |
| } | |
| @override | |
| void transformOrRemoveChildren(RemovingTransformer v) { | |
| v.transformExpressionList(annotations, this); | |
| type = v.visitDartType(type, cannotRemoveSentinel); | |
| if (initialValue != null) { | |
| initialValue = v.transformOrRemoveExpression(initialValue!); | |
| initialValue?.parent = this; | |
| } | |
| } | |
| @override | |
| void visitChildren(Visitor v) { | |
| visitList(annotations, v); | |
| type.accept(v); | |
| initialValue?.accept(v); | |
| } | |
| @override | |
| String toString() { | |
| return "LateVariable(${toStringInternal()})"; | |
| } | |
| @override | |
| void toTextInternal(AstPrinter printer) { | |
| printer.writeExpressionVariable(this); | |
| } | |
| @override | |
| int binaryOffsetNoTag = -1; | |
| @override | |
| List<VariableContext>? get capturedContexts { | |
| throw new UnsupportedError("${this.runtimeType}.capturedContexts"); | |
| } | |
| @override | |
| void set capturedContexts(List<VariableContext>? value) { | |
| throw new UnsupportedError("${this.runtimeType}.capturedContexts="); | |
| } | |
| @override | |
| int fileEqualsOffset = TreeNode.noOffset; | |
| @override | |
| void clearAnnotations() { | |
| annotations.clear(); | |
| } | |
| @override | |
| @Deprecated('Use LateVariable.name instead.') | |
| String? get cosmeticName => name; | |
| @override | |
| @Deprecated('Use LateVariable.name instead.') | |
| void set cosmeticName(String? value) { | |
| name = value!; | |
| } | |
| } | |
| /// A constant local variable. | |
| class ConstVariable extends DeclaredVariable { | |
| String name; | |
| @override | |
| DartType type; | |
| @override | |
| VariableDeclaration? variableDeclaration; | |
| @override | |
| List<Expression> annotations = const <Expression>[]; | |
| @override | |
| late VariableContext context; | |
| Expression? value; | |
| new({ | |
| required String this.name, | |
| DartType? type, | |
| bool isFinal = false, | |
| bool isWildcard = false, | |
| bool hasDeclaredInitializer = false, | |
| this.value, | |
| }) : type = type ?? const DynamicType() { | |
| this.isFinal = isFinal; | |
| this.isConst = true; | |
| this.isLate = false; | |
| this.isWildcard = isWildcard; | |
| this.hasDeclaredInitializer = hasDeclaredInitializer; | |
| this.value?.parent = this; | |
| } | |
| @Deprecated('Use ConstVariable.value instead.') | |
| @override | |
| Expression? get initializer => value; | |
| @Deprecated('Use ConstVariable.initialValue instead.') | |
| @override | |
| void set initializer(Expression? value) { | |
| this.value = value; | |
| } | |
| @override | |
| void addAnnotation(Expression annotation) { | |
| if (annotations.isEmpty) { | |
| annotations = <Expression>[]; | |
| } | |
| annotations.add(annotation..parent = this); | |
| } | |
| @override | |
| bool get isFinal => flags & Variable.FlagFinal != 0; | |
| @override | |
| void set isFinal(bool value) { | |
| flags = value | |
| ? (flags | Variable.FlagFinal) | |
| : (flags & ~Variable.FlagFinal); | |
| } | |
| @override | |
| bool get isWildcard => flags & Variable.FlagWildcard != 0; | |
| @override | |
| void set isWildcard(bool value) { | |
| flags = value | |
| ? (flags | Variable.FlagWildcard) | |
| : (flags & ~Variable.FlagWildcard); | |
| } | |
| @override | |
| bool get isConst => flags & Variable.FlagConst != 0; | |
| @override | |
| void set isConst(bool value) { | |
| flags = value | |
| ? (flags | Variable.FlagConst) | |
| : (flags & ~Variable.FlagConst); | |
| } | |
| @override | |
| bool get isLate => flags & Variable.FlagLate != 0; | |
| @override | |
| void set isLate(bool value) { | |
| flags = value ? (flags | Variable.FlagLate) : (flags & ~Variable.FlagLate); | |
| } | |
| @override | |
| bool get isLowered => flags & Variable.FlagLowered != 0; | |
| @override | |
| void set isLowered(bool value) { | |
| flags = value | |
| ? (flags | Variable.FlagLowered) | |
| : (flags & ~Variable.FlagLowered); | |
| } | |
| @override | |
| bool get isHoisted => flags & Variable.FlagHoisted != 0; | |
| @override | |
| void set isHoisted(bool value) { | |
| flags = value | |
| ? (flags | Variable.FlagHoisted) | |
| : (flags & ~Variable.FlagHoisted); | |
| } | |
| @override | |
| bool get isCovariantByClass => false; | |
| @override | |
| void set isCovariantByClass(bool value) { | |
| throw new UnsupportedError("${this.runtimeType}"); | |
| } | |
| @override | |
| bool get isCovariantByDeclaration => false; | |
| @override | |
| void set isCovariantByDeclaration(bool value) { | |
| throw new UnsupportedError("${this.runtimeType}"); | |
| } | |
| @override | |
| bool get isErroneouslyInitialized => | |
| flags & Variable.FlagErroneouslyInitialized != 0; | |
| @override | |
| void set isErroneouslyInitialized(bool value) { | |
| flags = value | |
| ? (flags | Variable.FlagErroneouslyInitialized) | |
| : (flags & ~Variable.FlagErroneouslyInitialized); | |
| } | |
| @override | |
| bool get hasDeclaredInitializer => | |
| flags & Variable.FlagHasDeclaredInitializer != 0; | |
| @override | |
| void set hasDeclaredInitializer(bool value) { | |
| flags = value | |
| ? (flags | Variable.FlagHasDeclaredInitializer) | |
| : (flags & ~Variable.FlagHasDeclaredInitializer); | |
| } | |
| @override | |
| bool get isInitializingFormal => false; | |
| @override | |
| void set isInitializingFormal(bool value) { | |
| throw new UnsupportedError("${this.runtimeType}"); | |
| } | |
| @override | |
| bool get isRequired => false; | |
| @override | |
| void set isRequired(bool value) { | |
| throw new UnsupportedError("${this.runtimeType}"); | |
| } | |
| @override | |
| bool get isSuperInitializingFormal => false; | |
| @override | |
| void set isSuperInitializingFormal(bool value) { | |
| throw new UnsupportedError("${this.runtimeType}"); | |
| } | |
| @override | |
| bool get isSynthesized => false; | |
| @override | |
| void set isSynthesized(bool value) { | |
| throw new UnsupportedError("${this.runtimeType}"); | |
| } | |
| @override | |
| bool get isAssignable { | |
| if (isConst) return false; | |
| if (isFinal) { | |
| if (isLate) return value == null; | |
| return false; | |
| } | |
| return true; | |
| } | |
| @override | |
| R accept<R>(VariableVisitor<R> v) => v.visitConstVariable(this); | |
| @override | |
| R accept1<R, A>(VariableVisitor1<R, A> v, A arg) => | |
| v.visitConstVariable(this, arg); | |
| @override | |
| void transformChildren(Transformer v) { | |
| v.transformList(annotations, this); | |
| type = v.visitDartType(type); | |
| if (value != null) { | |
| value = v.transform(value!); | |
| value?.parent = this; | |
| } | |
| } | |
| @override | |
| void transformOrRemoveChildren(RemovingTransformer v) { | |
| v.transformExpressionList(annotations, this); | |
| type = v.visitDartType(type, cannotRemoveSentinel); | |
| if (value != null) { | |
| value = v.transformOrRemoveExpression(value!); | |
| value?.parent = this; | |
| } | |
| } | |
| @override | |
| void visitChildren(Visitor v) { | |
| visitList(annotations, v); | |
| type.accept(v); | |
| value?.accept(v); | |
| } | |
| @override | |
| String toString() { | |
| return "ConstVariable(${toStringInternal()})"; | |
| } | |
| @override | |
| void toTextInternal(AstPrinter printer) { | |
| printer.writeExpressionVariable(this); | |
| } | |
| @override | |
| int binaryOffsetNoTag = -1; | |
| @override | |
| List<VariableContext>? get capturedContexts { | |
| throw new UnsupportedError("${this.runtimeType}.capturedContexts"); | |
| } | |
| @override | |
| void set capturedContexts(List<VariableContext>? value) { | |
| throw new UnsupportedError("${this.runtimeType}.capturedContexts="); | |
| } | |
| @override | |
| int fileEqualsOffset = TreeNode.noOffset; | |
| @override | |
| void clearAnnotations() { | |
| annotations.clear(); | |
| } | |
| @override | |
| @Deprecated('Use ConstVariable.name instead.') | |
| String? get cosmeticName => name; | |
| @override | |
| @Deprecated('Use ConstVariable.name instead.') | |
| void set cosmeticName(String? value) { | |
| name = value!; | |
| } | |
| } | |
| /// Since the `catch` block isn't invoked by the user code, but is redirected to | |
| /// by the runtime, its parameters, the exception and the stack trace, | |
| /// represented by `e` and `s` in the example below, are filled in by the | |
| /// runtime too. The semantics of populating the variables makes them distinct | |
| /// from function parameters, and they have a separate representation from them. | |
| /// | |
| /// try { | |
| /// foo(); | |
| /// } catch (e, s) { | |
| /// bar(); | |
| /// } | |
| class CatchVariable extends Variable { | |
| final String catchVariableName; | |
| @override | |
| DartType type; | |
| @override | |
| List<Expression> annotations = const <Expression>[]; | |
| @override | |
| late VariableContext context; | |
| new({ | |
| required String name, | |
| DartType? type, | |
| bool isWildcard = false, | |
| bool isFinal = false, | |
| bool isSynthesized = false, | |
| }) : catchVariableName = name, | |
| type = type ?? const DynamicType() { | |
| this.isWildcard = isWildcard; | |
| this.isFinal = isFinal; | |
| this.isSynthesized = isSynthesized; | |
| } | |
| @override | |
| @Deprecated('Use CatchVariable.catchVariableName instead.') | |
| String? get cosmeticName => catchVariableName; | |
| @override | |
| @Deprecated('Use CatchVariable.catchVariableName instead.') | |
| void set cosmeticName(String? value) { | |
| throw new UnsupportedError("${this.runtimeType}.cosmeticName="); | |
| } | |
| @override | |
| void addAnnotation(Expression annotation) { | |
| if (annotations.isEmpty) { | |
| annotations = <Expression>[]; | |
| } | |
| annotations.add(annotation..parent = this); | |
| } | |
| @override | |
| bool get isFinal => flags & Variable.FlagFinal != 0; | |
| @override | |
| void set isFinal(bool value) { | |
| flags = value | |
| ? (flags | Variable.FlagFinal) | |
| : (flags & ~Variable.FlagFinal); | |
| } | |
| @override | |
| bool get isWildcard => flags & Variable.FlagWildcard != 0; | |
| @override | |
| void set isWildcard(bool value) { | |
| flags = value | |
| ? (flags | Variable.FlagWildcard) | |
| : (flags & ~Variable.FlagWildcard); | |
| } | |
| @override | |
| bool get isConst => false; | |
| @override | |
| void set isConst(bool value) { | |
| throw new UnsupportedError("${this.runtimeType}.isConst="); | |
| } | |
| @override | |
| bool get isLate => false; | |
| @override | |
| void set isLate(bool value) { | |
| throw new UnsupportedError("${this.runtimeType}.isLate="); | |
| } | |
| @override | |
| bool get isLowered => false; | |
| @override | |
| void set isLowered(bool value) { | |
| throw new UnsupportedError("${this.runtimeType}.isLowered="); | |
| } | |
| @override | |
| bool get isHoisted => false; | |
| @override | |
| void set isHoisted(bool value) { | |
| throw new UnsupportedError("${this.runtimeType}.isHoisted="); | |
| } | |
| @override | |
| bool get isCovariantByClass => false; | |
| @override | |
| void set isCovariantByClass(bool value) { | |
| throw new UnsupportedError("${this.runtimeType}.isCovariantByClass="); | |
| } | |
| @override | |
| bool get isCovariantByDeclaration => false; | |
| @override | |
| void set isCovariantByDeclaration(bool value) { | |
| throw new UnsupportedError("${this.runtimeType}.isCovariantByDeclaration="); | |
| } | |
| @override | |
| bool get isErroneouslyInitialized => false; | |
| @override | |
| void set isErroneouslyInitialized(bool value) { | |
| throw new UnsupportedError("${this.runtimeType}.isErroneouslyInitialized="); | |
| } | |
| @override | |
| bool get hasDeclaredInitializer => false; | |
| @override | |
| void set hasDeclaredInitializer(bool value) { | |
| throw new UnsupportedError("${this.runtimeType}.hasDeclaredInitializer="); | |
| } | |
| @override | |
| bool get isInitializingFormal => false; | |
| @override | |
| void set isInitializingFormal(bool value) { | |
| throw new UnsupportedError("${this.runtimeType}.isInitializingFormal="); | |
| } | |
| @override | |
| bool get isRequired => false; | |
| @override | |
| void set isRequired(bool value) { | |
| throw new UnsupportedError("${this.runtimeType}.isRequired="); | |
| } | |
| @override | |
| bool get isSuperInitializingFormal => false; | |
| @override | |
| void set isSuperInitializingFormal(bool value) { | |
| throw new UnsupportedError( | |
| "${this.runtimeType}.isSuperInitializingFormal=", | |
| ); | |
| } | |
| @override | |
| bool get isSynthesized => flags & Variable.FlagSynthesized != 0; | |
| @override | |
| void set isSynthesized(bool value) { | |
| flags = value | |
| ? (flags | Variable.FlagSynthesized) | |
| : (flags & ~Variable.FlagSynthesized); | |
| } | |
| @override | |
| bool get isAssignable => false; | |
| @override | |
| R accept<R>(VariableVisitor<R> v) => v.visitCatchVariable(this); | |
| @override | |
| R accept1<R, A>(VariableVisitor1<R, A> v, A arg) => | |
| v.visitCatchVariable(this, arg); | |
| @override | |
| void transformChildren(Transformer v) { | |
| v.transformList(annotations, this); | |
| type = v.visitDartType(type); | |
| } | |
| @override | |
| void transformOrRemoveChildren(RemovingTransformer v) { | |
| v.transformExpressionList(annotations, this); | |
| type = v.visitDartType(type, cannotRemoveSentinel); | |
| } | |
| @override | |
| void visitChildren(Visitor v) { | |
| visitList(annotations, v); | |
| type.accept(v); | |
| } | |
| @override | |
| String toString() { | |
| return "CatchVariable(${toStringInternal()})"; | |
| } | |
| @override | |
| void toTextInternal(AstPrinter printer) { | |
| printer.writeExpressionVariable(this); | |
| } | |
| @override | |
| Expression? get initializer => null; | |
| @override | |
| void set initializer(Expression? value) { | |
| throw new UnsupportedError("${this.runtimeType}.initializer="); | |
| } | |
| @override | |
| int binaryOffsetNoTag = -1; | |
| @override | |
| List<VariableContext>? get capturedContexts { | |
| throw new UnsupportedError("${this.runtimeType}.capturedContexts"); | |
| } | |
| @override | |
| void set capturedContexts(List<VariableContext>? value) { | |
| throw new UnsupportedError("${this.runtimeType}.capturedContexts="); | |
| } | |
| @override | |
| int fileEqualsOffset = TreeNode.noOffset; | |
| @override | |
| void clearAnnotations() { | |
| annotations.clear(); | |
| } | |
| } | |
| /// Abstract parameter class, the parent for positional and named parameters. | |
| sealed class FunctionParameter extends Variable { | |
| String parameterName; | |
| Expression? defaultValue; | |
| new({ | |
| required this.parameterName, | |
| required this.defaultValue, | |
| required bool isCovariantByDeclaration, | |
| required bool isCovariantByClass, | |
| required bool isRequired, | |
| required bool isInitializingFormal, | |
| required bool isSuperInitializingFormal, | |
| required bool isFinal, | |
| required bool hasDeclaredDefaultValue, | |
| required bool isLowered, | |
| required bool isSynthesized, | |
| required bool isWildcard, | |
| }) { | |
| this.defaultValue?.parent = this; | |
| this.isCovariantByDeclaration = isCovariantByDeclaration; | |
| this.isCovariantByClass = isCovariantByClass; | |
| this.isRequired = isRequired; | |
| this.isInitializingFormal = isInitializingFormal; | |
| this.isSuperInitializingFormal = isSuperInitializingFormal; | |
| this.isFinal = isFinal; | |
| this.hasDeclaredDefaultValue = hasDeclaredDefaultValue; | |
| this.isLowered = isLowered; | |
| this.isSynthesized = isSynthesized; | |
| this.isWildcard = isWildcard; | |
| } | |
| @override | |
| @Deprecated('Use FunctionParameter.parameterName instead.') | |
| String get cosmeticName => parameterName; | |
| @override | |
| @Deprecated('Use FunctionParameter.parameterName instead.') | |
| void set cosmeticName(String? value) { | |
| parameterName = value!; | |
| } | |
| /// Function parameters can't be `const` or `late`, so they are assignable if | |
| /// they aren't final. | |
| @override | |
| bool get isAssignable => !isFinal; | |
| @Deprecated('Use FunctionParameter.defaultValue instead.') | |
| @override | |
| Expression? get initializer => defaultValue; | |
| @Deprecated('Use FunctionParameter.defaultValue instead.') | |
| @override | |
| void set initializer(Expression? value) { | |
| defaultValue = value; | |
| } | |
| @override | |
| bool get isFinal => flags & Variable.FlagFinal != 0; | |
| @override | |
| void set isFinal(bool value) { | |
| flags = value | |
| ? (flags | Variable.FlagFinal) | |
| : (flags & ~Variable.FlagFinal); | |
| } | |
| @override | |
| bool get isWildcard => flags & Variable.FlagWildcard != 0; | |
| @override | |
| void set isWildcard(bool value) { | |
| flags = value | |
| ? (flags | Variable.FlagWildcard) | |
| : (flags & ~Variable.FlagWildcard); | |
| } | |
| @override | |
| bool get isCovariantByClass => flags & Variable.FlagCovariantByClass != 0; | |
| @override | |
| void set isCovariantByClass(bool value) { | |
| flags = value | |
| ? (flags | Variable.FlagCovariantByClass) | |
| : (flags & ~Variable.FlagCovariantByClass); | |
| } | |
| @override | |
| bool get isCovariantByDeclaration => | |
| flags & Variable.FlagCovariantByDeclaration != 0; | |
| @override | |
| void set isCovariantByDeclaration(bool value) { | |
| flags = value | |
| ? (flags | Variable.FlagCovariantByDeclaration) | |
| : (flags & ~Variable.FlagCovariantByDeclaration); | |
| } | |
| @override | |
| bool get isInitializingFormal => flags & Variable.FlagInitializingFormal != 0; | |
| @override | |
| void set isInitializingFormal(bool value) { | |
| flags = value | |
| ? (flags | Variable.FlagInitializingFormal) | |
| : (flags & ~Variable.FlagInitializingFormal); | |
| } | |
| @override | |
| bool get isSuperInitializingFormal => | |
| flags & Variable.FlagSuperInitializingFormal != 0; | |
| @override | |
| void set isSuperInitializingFormal(bool value) { | |
| flags = value | |
| ? (flags | Variable.FlagSuperInitializingFormal) | |
| : (flags & ~Variable.FlagSuperInitializingFormal); | |
| } | |
| @override | |
| bool get isRequired => flags & Variable.FlagRequired != 0; | |
| @override | |
| void set isRequired(bool value) { | |
| flags = value | |
| ? (flags | Variable.FlagRequired) | |
| : (flags & ~Variable.FlagRequired); | |
| } | |
| @override | |
| bool get isLowered => flags & Variable.FlagLowered != 0; | |
| @override | |
| void set isLowered(bool value) { | |
| flags = value | |
| ? (flags | Variable.FlagLowered) | |
| : (flags & ~Variable.FlagLowered); | |
| } | |
| bool get hasDeclaredDefaultValue => | |
| flags & Variable.FlagHasDeclaredInitializer != 0; | |
| void set hasDeclaredDefaultValue(bool value) { | |
| flags = value | |
| ? (flags | Variable.FlagHasDeclaredInitializer) | |
| : (flags & ~Variable.FlagHasDeclaredInitializer); | |
| } | |
| @Deprecated('Use FunctionParameter.hasDeclaredDefaultValue instead.') | |
| @override | |
| bool get hasDeclaredInitializer => hasDeclaredDefaultValue; | |
| @Deprecated('Use FunctionParameter.hasDeclaredDefaultValue instead.') | |
| @override | |
| void set hasDeclaredInitializer(bool value) { | |
| hasDeclaredDefaultValue = value; | |
| } | |
| @override | |
| bool get isSynthesized => flags & Variable.FlagSynthesized != 0; | |
| @override | |
| void set isSynthesized(bool value) { | |
| flags = value | |
| ? (flags | Variable.FlagSynthesized) | |
| : (flags & ~Variable.FlagSynthesized); | |
| } | |
| bool get hasErroneousDefaultValue => | |
| flags & Variable.FlagErroneouslyInitialized != 0; | |
| void set hasErroneousDefaultValue(bool value) { | |
| flags = value | |
| ? (flags | Variable.FlagErroneouslyInitialized) | |
| : (flags & ~Variable.FlagErroneouslyInitialized); | |
| } | |
| @Deprecated('Use FunctionParameter.hasErroneousDefaultValue instead.') | |
| @override | |
| bool get isErroneouslyInitialized => | |
| flags & Variable.FlagErroneouslyInitialized != 0; | |
| @Deprecated('Use FunctionParameter.hasErroneousDefaultValue instead.') | |
| @override | |
| void set isErroneouslyInitialized(bool value) { | |
| flags = value | |
| ? (flags | Variable.FlagErroneouslyInitialized) | |
| : (flags & ~Variable.FlagErroneouslyInitialized); | |
| } | |
| @override | |
| bool get isLate { | |
| // Function parameters can't be 'late'. | |
| return false; | |
| } | |
| @override | |
| void set isLate(bool value) { | |
| throw new UnsupportedError("${this.runtimeType}"); | |
| } | |
| @override | |
| bool get isConst { | |
| // Function parameters can't be 'const'. | |
| return false; | |
| } | |
| @override | |
| void set isConst(bool value) { | |
| throw new UnsupportedError("${this.runtimeType}"); | |
| } | |
| @override | |
| bool get isHoisted => false; | |
| @override | |
| void set isHoisted(bool value) { | |
| throw new UnsupportedError("${this.runtimeType}"); | |
| } | |
| } | |
| /// Positional parameters. | |
| class PositionalParameter extends FunctionParameter { | |
| @override | |
| DartType type; | |
| @override | |
| List<Expression> annotations = const <Expression>[]; | |
| @override | |
| late VariableContext context; | |
| new({ | |
| required super.parameterName, | |
| DartType? type, | |
| super.defaultValue, | |
| super.isCovariantByDeclaration = false, | |
| super.isCovariantByClass = false, | |
| super.isRequired = false, | |
| super.isInitializingFormal = false, | |
| super.isSuperInitializingFormal = false, | |
| super.isFinal = false, | |
| super.hasDeclaredDefaultValue = false, | |
| super.isLowered = false, | |
| super.isSynthesized = false, | |
| super.isWildcard = false, | |
| }) : type = type ?? const DynamicType(); | |
| @override | |
| // TODO(62620): Conforming to [VariableDeclaration] interface. Remove this. | |
| List<VariableContext>? get capturedContexts { | |
| throw new UnsupportedError("${this.runtimeType}.capturedContexts"); | |
| } | |
| @override | |
| // TODO(62620): Conforming to [VariableDeclaration] interface. Remove this. | |
| void set capturedContexts(List<VariableContext>? value) { | |
| throw new UnsupportedError("${this.runtimeType}.capturedContexts="); | |
| } | |
| @override | |
| void addAnnotation(Expression annotation) { | |
| if (annotations.isEmpty) { | |
| annotations = <Expression>[]; | |
| } | |
| annotations.add(annotation..parent = this); | |
| } | |
| @override | |
| void clearAnnotations() { | |
| annotations = const <Expression>[]; | |
| } | |
| @override | |
| R accept<R>(VariableVisitor<R> v) => v.visitPositionalParameter(this); | |
| @override | |
| R accept1<R, A>(VariableVisitor1<R, A> v, A arg) => | |
| v.visitPositionalParameter(this, arg); | |
| @override | |
| void transformChildren(Transformer v) { | |
| v.transformList(annotations, this); | |
| type = v.visitDartType(type); | |
| if (defaultValue != null) { | |
| defaultValue = v.transform(defaultValue!); | |
| defaultValue?.parent = this; | |
| } | |
| } | |
| @override | |
| void transformOrRemoveChildren(RemovingTransformer v) { | |
| v.transformExpressionList(annotations, this); | |
| type = v.visitDartType(type, cannotRemoveSentinel); | |
| if (defaultValue != null) { | |
| defaultValue = v.transformOrRemoveExpression(defaultValue!); | |
| defaultValue?.parent = this; | |
| } | |
| } | |
| @override | |
| void visitChildren(Visitor v) { | |
| visitList(annotations, v); | |
| type.accept(v); | |
| defaultValue?.accept(v); | |
| } | |
| @override | |
| String toString() { | |
| return "PositionalParameter(${toStringInternal()})"; | |
| } | |
| @override | |
| int binaryOffsetNoTag = -1; | |
| @override | |
| int fileEqualsOffset = TreeNode.noOffset; | |
| } | |
| /// Named parameters. The [name] field is mandatory. | |
| class NamedParameter extends FunctionParameter { | |
| @override | |
| DartType type; | |
| @override | |
| List<Expression> annotations = const <Expression>[]; | |
| @override | |
| late VariableContext context; | |
| new({ | |
| required super.parameterName, | |
| DartType? type, | |
| super.defaultValue, | |
| super.isCovariantByDeclaration = false, | |
| super.isCovariantByClass = false, | |
| super.isRequired = false, | |
| super.isInitializingFormal = false, | |
| super.isSuperInitializingFormal = false, | |
| super.isFinal = false, | |
| super.hasDeclaredDefaultValue = false, | |
| super.isLowered = false, | |
| super.isSynthesized = false, | |
| super.isWildcard = false, | |
| bool isRenamedPrivateNamedParameter = false, | |
| }) : type = type ?? const DynamicType() { | |
| this.isRenamedPrivateNamedParameter = isRenamedPrivateNamedParameter; | |
| } | |
| bool get isRenamedPrivateNamedParameter => | |
| flags & Variable.FlagRenamedPrivateNamedParameter != 0; | |
| void set isRenamedPrivateNamedParameter(bool value) { | |
| flags = value | |
| ? (flags | Variable.FlagRenamedPrivateNamedParameter) | |
| : (flags & ~Variable.FlagRenamedPrivateNamedParameter); | |
| } | |
| @override | |
| // TODO(62620): Conforming to [VariableDeclaration] interface. Remove this. | |
| List<VariableContext>? get capturedContexts { | |
| throw new UnsupportedError("${this.runtimeType}.capturedContexts"); | |
| } | |
| @override | |
| // TODO(62620): Conforming to [VariableDeclaration] interface. Remove this. | |
| void set capturedContexts(List<VariableContext>? value) { | |
| throw new UnsupportedError("${this.runtimeType}.capturedContexts="); | |
| } | |
| @override | |
| void addAnnotation(Expression annotation) { | |
| if (annotations.isEmpty) { | |
| annotations = <Expression>[]; | |
| } | |
| annotations.add(annotation..parent = this); | |
| } | |
| @override | |
| void clearAnnotations() { | |
| annotations = const <Expression>[]; | |
| } | |
| @override | |
| R accept<R>(VariableVisitor<R> v) => v.visitNamedParameter(this); | |
| @override | |
| R accept1<R, A>(VariableVisitor1<R, A> v, A arg) => | |
| v.visitNamedParameter(this, arg); | |
| @override | |
| void transformChildren(Transformer v) { | |
| v.transformList(annotations, this); | |
| type = v.visitDartType(type); | |
| if (defaultValue != null) { | |
| defaultValue = v.transform(defaultValue!); | |
| defaultValue?.parent = this; | |
| } | |
| } | |
| @override | |
| void transformOrRemoveChildren(RemovingTransformer v) { | |
| v.transformExpressionList(annotations, this); | |
| type = v.visitDartType(type, cannotRemoveSentinel); | |
| if (defaultValue != null) { | |
| defaultValue = v.transformOrRemoveExpression(defaultValue!); | |
| defaultValue?.parent = this; | |
| } | |
| } | |
| @override | |
| void visitChildren(Visitor v) { | |
| visitList(annotations, v); | |
| type.accept(v); | |
| defaultValue?.accept(v); | |
| } | |
| @override | |
| String toString() { | |
| return "NamedParameter(${toStringInternal()})"; | |
| } | |
| @override | |
| int binaryOffsetNoTag = -1; | |
| @override | |
| int fileEqualsOffset = TreeNode.noOffset; | |
| } | |
| /// The variable storage for `this`. | |
| class ThisVariable extends Variable { | |
| @override | |
| String get cosmeticName => "this"; | |
| @override | |
| void set cosmeticName(String? value) {} | |
| @override | |
| DartType type; | |
| // TODO(cstefantsova): Consider a throwing implementation instead. | |
| @override | |
| List<Expression> annotations = const <Expression>[]; | |
| @override | |
| late VariableContext context; | |
| new({required this.type}) { | |
| // All [Variable]s must be serialized uniformly. | |
| flags |= Variable.FlagFinal; | |
| } | |
| // TODO(cstefantsova): Consider a throwing implementation instead. | |
| @override | |
| void addAnnotation(Expression annotation) { | |
| if (annotations.isEmpty) { | |
| annotations = <Expression>[]; | |
| } | |
| annotations.add(annotation..parent = this); | |
| } | |
| @override | |
| bool get isConst => false; | |
| @override | |
| void set isConst(bool value) { | |
| throw new UnsupportedError("${this.runtimeType}"); | |
| } | |
| @override | |
| bool get isLate => false; | |
| @override | |
| void set isLate(bool value) { | |
| throw new UnsupportedError("${this.runtimeType}"); | |
| } | |
| @override | |
| bool get isFinal => true; | |
| @override | |
| void set isFinal(bool value) { | |
| throw new UnsupportedError("${this.runtimeType}"); | |
| } | |
| @override | |
| bool get isWildcard => false; | |
| @override | |
| void set isWildcard(bool value) { | |
| throw new UnsupportedError("${this.runtimeType}"); | |
| } | |
| @override | |
| bool get isCovariantByClass => false; | |
| @override | |
| void set isCovariantByClass(bool value) { | |
| throw new UnsupportedError("${this.runtimeType}"); | |
| } | |
| @override | |
| bool get isCovariantByDeclaration => false; | |
| @override | |
| void set isCovariantByDeclaration(bool value) { | |
| throw new UnsupportedError("${this.runtimeType}"); | |
| } | |
| @override | |
| bool get isInitializingFormal => false; | |
| @override | |
| void set isInitializingFormal(bool value) { | |
| throw new UnsupportedError("${this.runtimeType}"); | |
| } | |
| @override | |
| bool get isSuperInitializingFormal => false; | |
| @override | |
| void set isSuperInitializingFormal(bool value) { | |
| throw new UnsupportedError("${this.runtimeType}"); | |
| } | |
| @override | |
| bool get isErroneouslyInitialized => false; | |
| @override | |
| void set isErroneouslyInitialized(bool value) { | |
| throw new UnsupportedError("${this.runtimeType}"); | |
| } | |
| @override | |
| bool get hasDeclaredInitializer => false; | |
| @override | |
| void set hasDeclaredInitializer(bool value) { | |
| throw new UnsupportedError("${this.runtimeType}"); | |
| } | |
| @override | |
| bool get isRequired => false; | |
| @override | |
| void set isRequired(bool value) { | |
| throw new UnsupportedError("${this.runtimeType}"); | |
| } | |
| @override | |
| bool get isSynthesized => false; | |
| @override | |
| void set isSynthesized(bool value) { | |
| throw new UnsupportedError("${this.runtimeType}"); | |
| } | |
| @override | |
| bool get isHoisted => false; | |
| @override | |
| void set isHoisted(bool value) { | |
| throw new UnsupportedError("${this.runtimeType}"); | |
| } | |
| @override | |
| bool get isLowered => false; | |
| @override | |
| void set isLowered(bool value) { | |
| throw new UnsupportedError("${this.runtimeType}"); | |
| } | |
| @override | |
| R accept<R>(VariableVisitor<R> v) => v.visitThisVariable(this); | |
| @override | |
| R accept1<R, A>(VariableVisitor1<R, A> v, A arg) => | |
| v.visitThisVariable(this, arg); | |
| @override | |
| void transformChildren(Transformer v) { | |
| v.transformList(annotations, this); | |
| type = v.visitDartType(type); | |
| } | |
| @override | |
| void transformOrRemoveChildren(RemovingTransformer v) { | |
| v.transformExpressionList(annotations, this); | |
| type = v.visitDartType(type, cannotRemoveSentinel); | |
| } | |
| @override | |
| void visitChildren(Visitor v) { | |
| visitList(annotations, v); | |
| type.accept(v); | |
| } | |
| @override | |
| String toString() { | |
| return "ThisVariable(${toStringInternal()})"; | |
| } | |
| @override | |
| bool get isAssignable => false; | |
| @override | |
| Expression? get initializer => null; | |
| @override | |
| void set initializer(Expression? value) { | |
| throw new UnsupportedError("${this.runtimeType}"); | |
| } | |
| @override | |
| int binaryOffsetNoTag = -1; | |
| @override | |
| List<VariableContext>? get capturedContexts { | |
| throw new UnsupportedError("${this.runtimeType}.capturedContexts"); | |
| } | |
| @override | |
| void set capturedContexts(List<VariableContext>? value) { | |
| throw new UnsupportedError("${this.runtimeType}.capturedContexts="); | |
| } | |
| @override | |
| int fileEqualsOffset = TreeNode.noOffset; | |
| @override | |
| void clearAnnotations() { | |
| annotations.clear(); | |
| } | |
| } | |
| /// A variable introduced during desugaring. Such variables don't correspond to | |
| /// any variable declared by the programmer. | |
| class SyntheticVariable extends DeclaredVariable { | |
| @override | |
| String? cosmeticName; | |
| @override | |
| DartType type; | |
| @override | |
| VariableDeclaration? variableDeclaration; | |
| // TODO(cstefantsova): Consider a throwing implementation instead. | |
| @override | |
| List<Expression> annotations = const <Expression>[]; | |
| @override | |
| late VariableContext context; | |
| @override | |
| @deprecated | |
| // TODO(johnniwinther): Remove this. | |
| Expression? initializer; | |
| new({ | |
| this.cosmeticName, | |
| DartType? type, | |
| this.initializer, | |
| bool isFinal = false, | |
| bool isLowered = false, | |
| // TODO(johnniwinther): Remove the ability for [SyntheticVariable]s to not | |
| // be synthesized. | |
| bool isSynthesized = true, | |
| bool hasDeclaredInitializer = false, | |
| bool isWildcard = false, | |
| }) : type = type ?? const DynamicType() { | |
| // ignore: deprecated_member_use_from_same_package | |
| this.initializer?.parent = this; | |
| this.isFinal = isFinal; | |
| this.isLowered = isLowered; | |
| this.isSynthesized = isSynthesized; | |
| this.hasDeclaredInitializer = hasDeclaredInitializer; | |
| } | |
| // TODO(cstefantsova): Consider a throwing implementation instead. | |
| @override | |
| void addAnnotation(Expression annotation) { | |
| if (annotations.isEmpty) { | |
| annotations = <Expression>[]; | |
| } | |
| annotations.add(annotation..parent = this); | |
| } | |
| @override | |
| bool get isFinal => flags & Variable.FlagFinal != 0; | |
| @override | |
| void set isFinal(bool value) { | |
| flags = value | |
| ? (flags | Variable.FlagFinal) | |
| : (flags & ~Variable.FlagFinal); | |
| } | |
| @override | |
| bool get isLowered => flags & Variable.FlagLowered != 0; | |
| @override | |
| void set isLowered(bool value) { | |
| flags = value | |
| ? (flags | Variable.FlagLowered) | |
| : (flags & ~Variable.FlagLowered); | |
| } | |
| @override | |
| bool get isHoisted => flags & Variable.FlagHoisted != 0; | |
| @override | |
| void set isHoisted(bool value) { | |
| flags = value | |
| ? (flags | Variable.FlagHoisted) | |
| : (flags & ~Variable.FlagHoisted); | |
| } | |
| @override | |
| bool get isCovariantByClass => false; | |
| @override | |
| void set isCovariantByClass(bool value) { | |
| throw new UnsupportedError("${this.runtimeType}"); | |
| } | |
| @override | |
| bool get isCovariantByDeclaration => false; | |
| @override | |
| void set isCovariantByDeclaration(bool value) { | |
| throw new UnsupportedError("${this.runtimeType}"); | |
| } | |
| @override | |
| bool get isErroneouslyInitialized => false; | |
| @override | |
| void set isErroneouslyInitialized(bool value) { | |
| throw new UnsupportedError("${this.runtimeType}"); | |
| } | |
| @override | |
| bool get hasDeclaredInitializer => | |
| flags & Variable.FlagHasDeclaredInitializer != 0; | |
| // TODO(johnniwinther): Remove this. | |
| @override | |
| void set hasDeclaredInitializer(bool value) { | |
| flags = value | |
| ? (flags | Variable.FlagHasDeclaredInitializer) | |
| : (flags & ~Variable.FlagHasDeclaredInitializer); | |
| } | |
| @override | |
| bool get isInitializingFormal => false; | |
| @override | |
| void set isInitializingFormal(bool value) { | |
| throw new UnsupportedError("${this.runtimeType}"); | |
| } | |
| @override | |
| bool get isRequired => false; | |
| @override | |
| void set isRequired(bool value) { | |
| throw new UnsupportedError("${this.runtimeType}"); | |
| } | |
| @override | |
| bool get isSuperInitializingFormal => false; | |
| @override | |
| void set isSuperInitializingFormal(bool value) { | |
| throw new UnsupportedError("${this.runtimeType}"); | |
| } | |
| @override | |
| bool get isSynthesized => flags & Variable.FlagSynthesized != 0; | |
| @override | |
| void set isSynthesized(bool value) { | |
| flags = value | |
| ? (flags | Variable.FlagSynthesized) | |
| : (flags & ~Variable.FlagSynthesized); | |
| } | |
| @override | |
| bool get isConst => flags & Variable.FlagConst != 0; | |
| @override | |
| void set isConst(bool value) { | |
| flags = value | |
| ? (flags | Variable.FlagConst) | |
| : (flags & ~Variable.FlagConst); | |
| } | |
| // TODO(johnniwinther): Should [SyntheticVariable]s be able to be late? | |
| @override | |
| bool get isLate => flags & Variable.FlagLate != 0; | |
| @override | |
| void set isLate(bool value) { | |
| flags = value ? (flags | Variable.FlagLate) : (flags & ~Variable.FlagLate); | |
| } | |
| @override | |
| bool get isWildcard => false; | |
| @override | |
| void set isWildcard(bool value) { | |
| throw new UnsupportedError("${this.runtimeType}"); | |
| } | |
| @override | |
| R accept<R>(VariableVisitor<R> v) => v.visitSyntheticVariable(this); | |
| @override | |
| R accept1<R, A>(VariableVisitor1<R, A> v, A arg) => | |
| v.visitSyntheticVariable(this, arg); | |
| @override | |
| void transformChildren(Transformer v) { | |
| v.transformList(annotations, this); | |
| type = v.visitDartType(type); | |
| // ignore: deprecated_member_use_from_same_package | |
| if (initializer != null) { | |
| // ignore: deprecated_member_use_from_same_package | |
| initializer = v.transform(initializer!); | |
| // ignore: deprecated_member_use_from_same_package | |
| initializer?.parent = this; | |
| } | |
| } | |
| @override | |
| void transformOrRemoveChildren(RemovingTransformer v) { | |
| v.transformExpressionList(annotations, this); | |
| type = v.visitDartType(type, cannotRemoveSentinel); | |
| // ignore: deprecated_member_use_from_same_package | |
| if (initializer != null) { | |
| // ignore: deprecated_member_use_from_same_package | |
| initializer = v.transformOrRemoveExpression(initializer!); | |
| // ignore: deprecated_member_use_from_same_package | |
| initializer?.parent = this; | |
| } | |
| } | |
| @override | |
| void visitChildren(Visitor v) { | |
| visitList(annotations, v); | |
| type.accept(v); | |
| // ignore: deprecated_member_use_from_same_package | |
| initializer?.accept(v); | |
| } | |
| @override | |
| String toString() { | |
| return "SyntheticVariable(${toStringInternal()})"; | |
| } | |
| @override | |
| bool get isAssignable => !isConst && !isFinal; | |
| @override | |
| int binaryOffsetNoTag = -1; | |
| @override | |
| List<VariableContext>? get capturedContexts { | |
| throw new UnsupportedError("${this.runtimeType}.capturedContexts"); | |
| } | |
| @override | |
| void set capturedContexts(List<VariableContext>? value) { | |
| throw new UnsupportedError("${this.runtimeType}.capturedContexts="); | |
| } | |
| @override | |
| int fileEqualsOffset = TreeNode.noOffset; | |
| @override | |
| void clearAnnotations() { | |
| annotations.clear(); | |
| } | |
| } | |
| /// The enum reflecting the kind of a variable context. A context is | |
| /// [assertCaptured] if it contains the variables captured in a closure within | |
| /// an `assert` and not captured anywhere outside of `assert`s. | |
| enum CaptureKind { notCaptured, directCaptured, assertCaptured } | |
| /// The box storing some of the variables in the scope it's associated with. It | |
| /// serves as the "declaration" of the variables it contains for the runtime | |
| /// environments. | |
| class VariableContext { | |
| CaptureKind captureKind; | |
| List<VariableBase> variables; | |
| new({required this.captureKind, required this.variables}) { | |
| for (VariableBase variable in variables) { | |
| variable.context = this; | |
| } | |
| } | |
| void addVariable(VariableBase variable) { | |
| variable.context = this; | |
| variables.add(variable); | |
| } | |
| @override | |
| String toString() { | |
| AstPrinter printer = new AstPrinter(defaultAstTextStrategy); | |
| toTextInternal(printer); | |
| return "VariableContext(${printer.getText()})"; | |
| } | |
| void toTextInternal(AstPrinter printer) { | |
| printer.write('['); | |
| for (int index = 0; index < variables.length; index++) { | |
| if (index > 0) { | |
| printer.write(', '); | |
| } | |
| variables[index].toTextInternal(printer); | |
| } | |
| printer.write(']'); | |
| } | |
| } | |
| /// The collection of the contexts pertaining to a scope-inducing node. The | |
| /// [Scopes] are supposed to be treated as the points of declaration of the | |
| /// variables they contain. They aren't [Statement]s, but a runtime may choose | |
| /// to interpret the [Scope] in an executable way before any [Statement]s or | |
| /// [Expression]s of its node. | |
| class Scope { | |
| final List<VariableContext> contexts; | |
| new({required this.contexts}); | |
| void addContext(VariableContext context) { | |
| contexts.add(context); | |
| } | |
| @override | |
| String toString() { | |
| AstPrinter printer = new AstPrinter(defaultAstTextStrategy); | |
| toTextInternal(printer); | |
| return "Scope(${printer.getText()})"; | |
| } | |
| void toTextInternal(AstPrinter printer) { | |
| printer.write('['); | |
| for (int index = 0; index < contexts.length; index++) { | |
| if (index > 0) { | |
| printer.write(', '); | |
| } | |
| contexts[index].toTextInternal(printer); | |
| } | |
| printer.write(']'); | |
| } | |
| } | |
| /// The root of the sealed hierarchy of the nodes that provide a scope, such as | |
| /// loops, functions, and blocks. | |
| sealed class ScopeProvider implements TreeNode { | |
| /// Scope of the [ScopeProvider]. | |
| /// | |
| /// It's represented as nullable due to the experimental status of the | |
| /// feature. When the feature isn't enabled, [scope] should return null. | |
| abstract Scope? scope; | |
| } | |
| /// The root of the sealed hierarchy of the nodes that consume variable | |
| /// contexts, that is, they capture variables from those contexts, such as | |
| /// functions or initialization nodes of late variables. | |
| sealed class ContextConsumer implements TreeNode { | |
| /// Contexts the variables captured by [ContextConsumer] are from. | |
| abstract List<VariableContext>? capturedContexts; | |
| } | |
| /// Declaration of a variable with an initial value. | |
| class VariableDeclaration extends TreeNode implements ContextConsumer { | |
| /// The declared variable. | |
| DeclaredVariable variable; | |
| /// Contexts of the variables captured by the late variable initializer. | |
| /// | |
| /// If [variable] isn't `late`, [capturedContexts] should be `null`. | |
| @override | |
| List<VariableContext>? capturedContexts; | |
| new(this.variable) { | |
| variable.parent = this; | |
| variable.variableDeclaration = this; | |
| } | |
| /// The declared initializer, if any. | |
| // TODO(johnniwinther): VariableDeclaration should own the initializer. | |
| Expression? get initializer => variable.initializer; | |
| @override | |
| R accept<R>(TreeVisitor<R> v) => v.visitVariableDeclaration(this); | |
| @override | |
| R accept1<R, A>(TreeVisitor1<R, A> v, A arg) => | |
| v.visitVariableDeclaration(this, arg); | |
| @override | |
| void toTextInternal(AstPrinter printer) { | |
| variable.toTextInternal(printer); | |
| } | |
| @override | |
| void transformChildren(Transformer v) { | |
| variable = v.transform(variable)..parent = this; | |
| } | |
| @override | |
| void transformOrRemoveChildren(RemovingTransformer v) { | |
| variable = v.transform(variable)..parent = this; | |
| } | |
| @override | |
| void visitChildren(Visitor<dynamic> v) { | |
| variable.accept(v); | |
| } | |
| @override | |
| String toString() => 'VariableDeclaration(${toStringInternal()})'; | |
| } |