| // Copyright (c) 2024, 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'; | |
| // ------------------------------------------------------------------------ | |
| // CONSTANTS | |
| // ------------------------------------------------------------------------ | |
| /// A fixed-length list of [Constant]s. | |
| extension type const ConstantList._(List<Constant> _list) | |
| implements List<Constant> { | |
| static const ConstantList empty = ConstantList._(const <Constant>[]); | |
| /// Creates a fixed-length list of 1–4 elements without allocating a | |
| /// temporary growable list from a literal. | |
| @pragma('vm:prefer-inline') | |
| factory(Constant c1, [Constant? c2, Constant? c3, Constant? c4]) { | |
| if (c2 == null) { | |
| assert(c3 == null && c4 == null); | |
| return ConstantList._1(c1); | |
| } | |
| if (c3 == null) { | |
| assert(c4 == null); | |
| return ConstantList._2(c1, c2); | |
| } | |
| if (c4 == null) { | |
| return ConstantList._3(c1, c2, c3); | |
| } | |
| return ConstantList._4(c1, c2, c3, c4); | |
| } | |
| factory _1(Constant c1) => ConstantList._(List<Constant>.filled(1, c1)); | |
| factory _2(Constant c1, Constant c2) => | |
| ConstantList._(List<Constant>.filled(2, c1)..[1] = c2); | |
| factory _3(Constant c1, Constant c2, Constant c3) => ConstantList._( | |
| List<Constant>.filled(3, c1) | |
| ..[1] = c2 | |
| ..[2] = c3, | |
| ); | |
| factory _4(Constant c1, Constant c2, Constant c3, Constant c4) => | |
| ConstantList._( | |
| List<Constant>.filled(4, c1) | |
| ..[1] = c2 | |
| ..[2] = c3 | |
| ..[3] = c4, | |
| ); | |
| factory filled(int length, Constant fill) => | |
| length == 0 ? empty : ConstantList._(List.filled(length, fill)); | |
| @pragma('vm:prefer-inline') | |
| factory generate(int length, Constant Function(int index) generator) { | |
| if (length == 0) return empty; | |
| return ConstantList._(List.generate(length, generator, growable: false)); | |
| } | |
| @pragma('vm:prefer-inline') | |
| static ConstantList mapped<T>(List<T> list, Constant Function(T) func) { | |
| if (list.isEmpty) return empty; | |
| return ConstantList._( | |
| List<Constant>.generate( | |
| list.length, | |
| (i) => func(list[i]), | |
| growable: false, | |
| ), | |
| ); | |
| } | |
| factory from(List<Constant> constants) { | |
| if (constants.isEmpty) return empty; | |
| return ConstantList._( | |
| List.generate(constants.length, (i) => constants[i], growable: false), | |
| ); | |
| } | |
| /// Copies [constants] into a new fixed-length list. | |
| factory of(Iterable<Constant> constants) { | |
| final List<Constant> list = List<Constant>.of(constants, growable: false); | |
| return list.isEmpty ? empty : ConstantList._(list); | |
| } | |
| } | |
| /// A fixed-length list of [ConstantMapEntry]s. | |
| extension type const ConstantMapEntryList._(List<ConstantMapEntry> _list) | |
| implements List<ConstantMapEntry> { | |
| static const ConstantMapEntryList empty = ConstantMapEntryList._( | |
| const <ConstantMapEntry>[], | |
| ); | |
| /// Creates a fixed-length list of 1–4 elements without allocating a | |
| /// temporary growable list from a literal. | |
| @pragma('vm:prefer-inline') | |
| factory( | |
| ConstantMapEntry e1, [ | |
| ConstantMapEntry? e2, | |
| ConstantMapEntry? e3, | |
| ConstantMapEntry? e4, | |
| ]) { | |
| if (e2 == null) { | |
| assert(e3 == null && e4 == null); | |
| return ConstantMapEntryList._1(e1); | |
| } | |
| if (e3 == null) { | |
| assert(e4 == null); | |
| return ConstantMapEntryList._2(e1, e2); | |
| } | |
| if (e4 == null) { | |
| return ConstantMapEntryList._3(e1, e2, e3); | |
| } | |
| return ConstantMapEntryList._4(e1, e2, e3, e4); | |
| } | |
| factory _1(ConstantMapEntry e1) => | |
| ConstantMapEntryList._(List<ConstantMapEntry>.filled(1, e1)); | |
| factory _2(ConstantMapEntry e1, ConstantMapEntry e2) => | |
| ConstantMapEntryList._(List<ConstantMapEntry>.filled(2, e1)..[1] = e2); | |
| factory _3(ConstantMapEntry e1, ConstantMapEntry e2, ConstantMapEntry e3) => | |
| ConstantMapEntryList._( | |
| List<ConstantMapEntry>.filled(3, e1) | |
| ..[1] = e2 | |
| ..[2] = e3, | |
| ); | |
| factory _4( | |
| ConstantMapEntry e1, | |
| ConstantMapEntry e2, | |
| ConstantMapEntry e3, | |
| ConstantMapEntry e4, | |
| ) => ConstantMapEntryList._( | |
| List<ConstantMapEntry>.filled(4, e1) | |
| ..[1] = e2 | |
| ..[2] = e3 | |
| ..[3] = e4, | |
| ); | |
| @pragma('vm:prefer-inline') | |
| factory generate(int length, ConstantMapEntry Function(int index) generator) { | |
| if (length == 0) return empty; | |
| return ConstantMapEntryList._( | |
| List.generate(length, generator, growable: false), | |
| ); | |
| } | |
| @pragma('vm:prefer-inline') | |
| static ConstantMapEntryList mapped<T>( | |
| List<T> list, | |
| ConstantMapEntry Function(T) func, | |
| ) { | |
| if (list.isEmpty) return empty; | |
| return ConstantMapEntryList._( | |
| List<ConstantMapEntry>.generate( | |
| list.length, | |
| (i) => func(list[i]), | |
| growable: false, | |
| ), | |
| ); | |
| } | |
| factory from(List<ConstantMapEntry> entries) { | |
| if (entries.isEmpty) return empty; | |
| return ConstantMapEntryList._( | |
| List.generate(entries.length, (i) => entries[i], growable: false), | |
| ); | |
| } | |
| /// Copies [entries] into a new fixed-length list. | |
| factory of(Iterable<ConstantMapEntry> entries) { | |
| final List<ConstantMapEntry> list = List<ConstantMapEntry>.of( | |
| entries, | |
| growable: false, | |
| ); | |
| return list.isEmpty ? empty : ConstantMapEntryList._(list); | |
| } | |
| } | |
| sealed class Constant extends Node { | |
| /// Calls the `visit*ConstantReference()` method on visitor [v] for all | |
| /// constants referenced in this constant. | |
| /// | |
| /// (Note that a constant can be seen as a DAG (directed acyclic graph) and | |
| /// not a tree!) | |
| @override | |
| void visitChildren(Visitor v); | |
| /// Calls the `visit*Constant()` method on the visitor [v]. | |
| @override | |
| R accept<R>(ConstantVisitor<R> v); | |
| /// Calls the `visit*Constant()` method on the visitor [v]. | |
| @override | |
| R accept1<R, A>(ConstantVisitor1<R, A> v, A arg); | |
| /// Calls the `visit*ConstantReference()` method on the visitor [v]. | |
| R acceptReference<R>(ConstantReferenceVisitor<R> v); | |
| /// Calls the `visit*ConstantReference()` method on the visitor [v]. | |
| R acceptReference1<R, A>(ConstantReferenceVisitor1<R, A> v, A arg); | |
| /// The Kernel AST will reference [Constant]s via [ConstantExpression]s. The | |
| /// constants are not required to be canonicalized, but they have to be deeply | |
| /// comparable via hashCode/==! | |
| @override | |
| int get hashCode; | |
| @override | |
| bool operator ==(Object other); | |
| @override | |
| String toString() => throw '$runtimeType'; | |
| /// Returns a textual representation of the this constant. | |
| /// | |
| /// If [verbose] is `true`, qualified names will include the library name/uri. | |
| @override | |
| String toText(AstTextStrategy strategy) { | |
| AstPrinter printer = new AstPrinter(strategy); | |
| printer.writeConstant(this); | |
| return printer.getText(); | |
| } | |
| @override | |
| void toTextInternal(AstPrinter printer); | |
| /// Gets the type of this constant. | |
| DartType getType(StaticTypeContext context); | |
| } | |
| abstract class AuxiliaryConstant extends Constant { | |
| @override | |
| R accept<R>(ConstantVisitor<R> v) => v.visitAuxiliaryConstant(this); | |
| @override | |
| R accept1<R, A>(ConstantVisitor1<R, A> v, A arg) => | |
| v.visitAuxiliaryConstant(this, arg); | |
| @override | |
| R acceptReference<R>(ConstantReferenceVisitor<R> v) => | |
| v.visitAuxiliaryConstantReference(this); | |
| @override | |
| R acceptReference1<R, A>(ConstantReferenceVisitor1<R, A> v, A arg) => | |
| v.visitAuxiliaryConstantReference(this, arg); | |
| } | |
| sealed class PrimitiveConstant<T> extends Constant { | |
| final T value; | |
| new(this.value); | |
| @override | |
| int get hashCode => value.hashCode; | |
| @override | |
| bool operator ==(Object other) => | |
| other is PrimitiveConstant<T> && other.value == value; | |
| @override | |
| void toTextInternal(AstPrinter printer) { | |
| printer.write('$value'); | |
| } | |
| } | |
| class NullConstant extends PrimitiveConstant<Null> { | |
| new() : super(null); | |
| @override | |
| void visitChildren(Visitor v) {} | |
| @override | |
| R accept<R>(ConstantVisitor<R> v) => v.visitNullConstant(this); | |
| @override | |
| R accept1<R, A>(ConstantVisitor1<R, A> v, A arg) => | |
| v.visitNullConstant(this, arg); | |
| @override | |
| R acceptReference<R>(ConstantReferenceVisitor<R> v) => | |
| v.visitNullConstantReference(this); | |
| @override | |
| R acceptReference1<R, A>(ConstantReferenceVisitor1<R, A> v, A arg) => | |
| v.visitNullConstantReference(this, arg); | |
| @override | |
| DartType getType(StaticTypeContext context) => const NullType(); | |
| @override | |
| String toString() => 'NullConstant(${toStringInternal()})'; | |
| } | |
| class BoolConstant extends PrimitiveConstant<bool> { | |
| new(bool value) : super(value); | |
| @override | |
| void visitChildren(Visitor v) {} | |
| @override | |
| R accept<R>(ConstantVisitor<R> v) => v.visitBoolConstant(this); | |
| @override | |
| R accept1<R, A>(ConstantVisitor1<R, A> v, A arg) => | |
| v.visitBoolConstant(this, arg); | |
| @override | |
| R acceptReference<R>(ConstantReferenceVisitor<R> v) => | |
| v.visitBoolConstantReference(this); | |
| @override | |
| R acceptReference1<R, A>(ConstantReferenceVisitor1<R, A> v, A arg) => | |
| v.visitBoolConstantReference(this, arg); | |
| @override | |
| DartType getType(StaticTypeContext context) => | |
| context.typeEnvironment.coreTypes.boolRawType(context.nonNullable); | |
| @override | |
| String toString() => 'BoolConstant(${toStringInternal()})'; | |
| } | |
| /// An integer constant on a non-JS target. | |
| class IntConstant extends PrimitiveConstant<int> { | |
| new(int value) : super(value); | |
| @override | |
| void visitChildren(Visitor v) {} | |
| @override | |
| R accept<R>(ConstantVisitor<R> v) => v.visitIntConstant(this); | |
| @override | |
| R accept1<R, A>(ConstantVisitor1<R, A> v, A arg) => | |
| v.visitIntConstant(this, arg); | |
| @override | |
| R acceptReference<R>(ConstantReferenceVisitor<R> v) => | |
| v.visitIntConstantReference(this); | |
| @override | |
| R acceptReference1<R, A>(ConstantReferenceVisitor1<R, A> v, A arg) => | |
| v.visitIntConstantReference(this, arg); | |
| @override | |
| DartType getType(StaticTypeContext context) => | |
| context.typeEnvironment.coreTypes.intRawType(context.nonNullable); | |
| @override | |
| String toString() => 'IntConstant(${toStringInternal()})'; | |
| } | |
| /// A double constant on a non-JS target or any numeric constant on a JS target. | |
| class DoubleConstant extends PrimitiveConstant<double> { | |
| new(double value) : super(value); | |
| @override | |
| void visitChildren(Visitor v) {} | |
| @override | |
| R accept<R>(ConstantVisitor<R> v) => v.visitDoubleConstant(this); | |
| @override | |
| R accept1<R, A>(ConstantVisitor1<R, A> v, A arg) => | |
| v.visitDoubleConstant(this, arg); | |
| @override | |
| R acceptReference<R>(ConstantReferenceVisitor<R> v) => | |
| v.visitDoubleConstantReference(this); | |
| @override | |
| R acceptReference1<R, A>(ConstantReferenceVisitor1<R, A> v, A arg) => | |
| v.visitDoubleConstantReference(this, arg); | |
| @override | |
| int get hashCode => value.isNaN ? 199 : super.hashCode; | |
| @override | |
| bool operator ==(Object other) => | |
| other is DoubleConstant && identical(value, other.value); | |
| @override | |
| DartType getType(StaticTypeContext context) => | |
| context.typeEnvironment.coreTypes.doubleRawType(context.nonNullable); | |
| @override | |
| String toString() => 'DoubleConstant(${toStringInternal()})'; | |
| } | |
| class StringConstant extends PrimitiveConstant<String> { | |
| new(String value) : super(value); | |
| @override | |
| void visitChildren(Visitor v) {} | |
| @override | |
| R accept<R>(ConstantVisitor<R> v) => v.visitStringConstant(this); | |
| @override | |
| R accept1<R, A>(ConstantVisitor1<R, A> v, A arg) => | |
| v.visitStringConstant(this, arg); | |
| @override | |
| R acceptReference<R>(ConstantReferenceVisitor<R> v) => | |
| v.visitStringConstantReference(this); | |
| @override | |
| R acceptReference1<R, A>(ConstantReferenceVisitor1<R, A> v, A arg) => | |
| v.visitStringConstantReference(this, arg); | |
| @override | |
| DartType getType(StaticTypeContext context) => | |
| context.typeEnvironment.coreTypes.stringRawType(context.nonNullable); | |
| @override | |
| void toTextInternal(AstPrinter printer) { | |
| printer.write('"'); | |
| printer.write(escapeString(value)); | |
| printer.write('"'); | |
| } | |
| @override | |
| String toString() => 'StringConstant(${toStringInternal()})'; | |
| } | |
| class SymbolConstant extends Constant { | |
| final String name; | |
| final Reference? libraryReference; | |
| new(this.name, this.libraryReference); | |
| @override | |
| void visitChildren(Visitor v) {} | |
| @override | |
| R accept<R>(ConstantVisitor<R> v) => v.visitSymbolConstant(this); | |
| @override | |
| R accept1<R, A>(ConstantVisitor1<R, A> v, A arg) => | |
| v.visitSymbolConstant(this, arg); | |
| @override | |
| R acceptReference<R>(ConstantReferenceVisitor<R> v) => | |
| v.visitSymbolConstantReference(this); | |
| @override | |
| R acceptReference1<R, A>(ConstantReferenceVisitor1<R, A> v, A arg) => | |
| v.visitSymbolConstantReference(this, arg); | |
| @override | |
| String toString() => 'SymbolConstant(${toStringInternal()})'; | |
| @override | |
| int get hashCode => _Hash.hash2(name, libraryReference); | |
| @override | |
| bool operator ==(Object other) => | |
| identical(this, other) || | |
| (other is SymbolConstant && | |
| other.name == name && | |
| other.libraryReference == libraryReference); | |
| @override | |
| DartType getType(StaticTypeContext context) => | |
| context.typeEnvironment.coreTypes.symbolRawType(context.nonNullable); | |
| @override | |
| void toTextInternal(AstPrinter printer) { | |
| printer.write('#'); | |
| if (printer.includeAuxiliaryProperties && libraryReference != null) { | |
| printer.write(libraryNameToString(libraryReference!.asLibrary)); | |
| printer.write('::'); | |
| } | |
| printer.write(name); | |
| } | |
| } | |
| class MapConstant extends Constant { | |
| final DartType keyType; | |
| final DartType valueType; | |
| final ConstantMapEntryList entries; | |
| new(this.keyType, this.valueType, this.entries); | |
| @override | |
| void visitChildren(Visitor v) { | |
| keyType.accept(v); | |
| valueType.accept(v); | |
| for (final ConstantMapEntry entry in entries) { | |
| entry.key.acceptReference(v); | |
| entry.value.acceptReference(v); | |
| } | |
| } | |
| @override | |
| R accept<R>(ConstantVisitor<R> v) => v.visitMapConstant(this); | |
| @override | |
| R accept1<R, A>(ConstantVisitor1<R, A> v, A arg) => | |
| v.visitMapConstant(this, arg); | |
| @override | |
| R acceptReference<R>(ConstantReferenceVisitor<R> v) => | |
| v.visitMapConstantReference(this); | |
| @override | |
| R acceptReference1<R, A>(ConstantReferenceVisitor1<R, A> v, A arg) => | |
| v.visitMapConstantReference(this, arg); | |
| @override | |
| void toTextInternal(AstPrinter printer) { | |
| printer.write('const <'); | |
| printer.writeType(keyType); | |
| printer.write(', '); | |
| printer.writeType(valueType); | |
| printer.write('>{'); | |
| for (int i = 0; i < entries.length; i++) { | |
| if (i > 0) { | |
| printer.write(', '); | |
| } | |
| printer.writeConstantMapEntry(entries[i]); | |
| } | |
| printer.write('}'); | |
| } | |
| @override | |
| String toString() => 'MapConstant(${toStringInternal()})'; | |
| @override | |
| late final int hashCode = _Hash.combine2Finish( | |
| keyType.hashCode, | |
| valueType.hashCode, | |
| _Hash.combineListHash(entries), | |
| ); | |
| @override | |
| bool operator ==(Object other) => | |
| identical(this, other) || | |
| (other is MapConstant && | |
| other.keyType == keyType && | |
| other.valueType == valueType && | |
| listEquals(other.entries, entries)); | |
| @override | |
| DartType getType(StaticTypeContext context) => | |
| context.typeEnvironment.mapType(keyType, valueType, context.nonNullable); | |
| } | |
| class ConstantMapEntry { | |
| final Constant key; | |
| final Constant value; | |
| new(this.key, this.value); | |
| @override | |
| String toString() => 'ConstantMapEntry(${toStringInternal()})'; | |
| @override | |
| int get hashCode => _Hash.hash2(key, value); | |
| @override | |
| bool operator ==(Object other) => | |
| other is ConstantMapEntry && other.key == key && other.value == value; | |
| String toStringInternal() => toText(defaultAstTextStrategy); | |
| String toText(AstTextStrategy strategy) { | |
| AstPrinter printer = new AstPrinter(strategy); | |
| printer.writeConstantMapEntry(this); | |
| return printer.getText(); | |
| } | |
| void toTextInternal(AstPrinter printer) { | |
| printer.writeConstant(key); | |
| printer.write(': '); | |
| printer.writeConstant(value); | |
| } | |
| } | |
| class ListConstant extends Constant { | |
| final DartType typeArgument; | |
| final ConstantList entries; | |
| new(this.typeArgument, this.entries); | |
| @override | |
| void visitChildren(Visitor v) { | |
| typeArgument.accept(v); | |
| for (final Constant constant in entries) { | |
| constant.acceptReference(v); | |
| } | |
| } | |
| @override | |
| R accept<R>(ConstantVisitor<R> v) => v.visitListConstant(this); | |
| @override | |
| R accept1<R, A>(ConstantVisitor1<R, A> v, A arg) => | |
| v.visitListConstant(this, arg); | |
| @override | |
| R acceptReference<R>(ConstantReferenceVisitor<R> v) => | |
| v.visitListConstantReference(this); | |
| @override | |
| R acceptReference1<R, A>(ConstantReferenceVisitor1<R, A> v, A arg) => | |
| v.visitListConstantReference(this, arg); | |
| @override | |
| void toTextInternal(AstPrinter printer) { | |
| printer.write('const <'); | |
| printer.writeType(typeArgument); | |
| printer.write('>['); | |
| for (int i = 0; i < entries.length; i++) { | |
| if (i > 0) { | |
| printer.write(', '); | |
| } | |
| printer.writeConstant(entries[i]); | |
| } | |
| printer.write(']'); | |
| } | |
| @override | |
| String toString() => 'ListConstant(${toStringInternal()})'; | |
| @override | |
| late final int hashCode = _Hash.combineFinish( | |
| typeArgument.hashCode, | |
| _Hash.combineListHash(entries), | |
| ); | |
| @override | |
| bool operator ==(Object other) => | |
| identical(this, other) || | |
| (other is ListConstant && | |
| other.typeArgument == typeArgument && | |
| listEquals(other.entries, entries)); | |
| @override | |
| DartType getType(StaticTypeContext context) => | |
| context.typeEnvironment.listType(typeArgument, context.nonNullable); | |
| } | |
| class SetConstant extends Constant { | |
| final DartType typeArgument; | |
| final ConstantList entries; | |
| new(this.typeArgument, this.entries); | |
| @override | |
| void visitChildren(Visitor v) { | |
| typeArgument.accept(v); | |
| for (final Constant constant in entries) { | |
| constant.acceptReference(v); | |
| } | |
| } | |
| @override | |
| R accept<R>(ConstantVisitor<R> v) => v.visitSetConstant(this); | |
| @override | |
| R accept1<R, A>(ConstantVisitor1<R, A> v, A arg) => | |
| v.visitSetConstant(this, arg); | |
| @override | |
| R acceptReference<R>(ConstantReferenceVisitor<R> v) => | |
| v.visitSetConstantReference(this); | |
| @override | |
| R acceptReference1<R, A>(ConstantReferenceVisitor1<R, A> v, A arg) => | |
| v.visitSetConstantReference(this, arg); | |
| @override | |
| void toTextInternal(AstPrinter printer) { | |
| printer.write('const <'); | |
| printer.writeType(typeArgument); | |
| printer.write('>{'); | |
| for (int i = 0; i < entries.length; i++) { | |
| if (i > 0) { | |
| printer.write(', '); | |
| } | |
| printer.writeConstant(entries[i]); | |
| } | |
| printer.write('}'); | |
| } | |
| @override | |
| String toString() => 'SetConstant(${toStringInternal()})'; | |
| @override | |
| late final int hashCode = _Hash.combineFinish( | |
| typeArgument.hashCode, | |
| _Hash.combineListHash(entries), | |
| ); | |
| @override | |
| bool operator ==(Object other) => | |
| identical(this, other) || | |
| (other is SetConstant && | |
| other.typeArgument == typeArgument && | |
| listEquals(other.entries, entries)); | |
| @override | |
| DartType getType(StaticTypeContext context) => | |
| context.typeEnvironment.setType(typeArgument, context.nonNullable); | |
| } | |
| class RecordConstant extends Constant { | |
| /// Positional field values. | |
| final ConstantList positional; | |
| /// Named field values, sorted by name. | |
| final Map<String, Constant> named; | |
| /// The runtime type of the constant. | |
| /// | |
| /// [recordType] is computed from the individual types of the record fields | |
| /// and reflects runtime type of the record constant, as opposed to the | |
| /// static type of the expression that defined the constant. | |
| /// | |
| /// The following program shows the distinction between the static and the | |
| /// runtime types of the constant. The static type of the first record in the | |
| /// invocation of `identical` is `(E, String)`, the static type of the second | |
| /// — `(int, String)`. The runtime type of both constants is `(int, String)`, | |
| /// and the assertion condition should be satisfied. | |
| /// | |
| /// extension type const E(Object? it) {} | |
| /// | |
| /// main() { | |
| /// const bool check = identical(const (E(1), "foo"), const (1, "foo")); | |
| /// assert(check); | |
| /// } | |
| final RecordType recordType; | |
| new(this.positional, this.named, this.recordType) | |
| : assert( | |
| positional.length == recordType.positional.length && | |
| named.length == recordType.named.length && | |
| recordType.named.map((f) => f.name).toSet().containsAll(named.keys), | |
| ), | |
| assert( | |
| () { | |
| // Assert that the named fields are sorted. | |
| String? previous; | |
| for (String name in named.keys) { | |
| if (previous != null && name.compareTo(previous) < 0) { | |
| return false; | |
| } | |
| previous = name; | |
| } | |
| return true; | |
| }(), | |
| "Named fields of a RecordConstant aren't sorted lexicographically: " | |
| "${named.keys.join(", ")}", | |
| ); | |
| new fromTypeContext( | |
| this.positional, | |
| this.named, | |
| StaticTypeContext staticTypeContext, | |
| ) : recordType = new RecordType( | |
| DartTypeList.mapped(positional, (c) => c.getType(staticTypeContext)), | |
| named.isEmpty | |
| ? NamedDartTypeList.empty | |
| : NamedDartTypeList.of( | |
| named.entries.map( | |
| (e) => | |
| new NamedType(e.key, e.value.getType(staticTypeContext)), | |
| ), | |
| ), | |
| staticTypeContext.nonNullable, | |
| ); | |
| @override | |
| void visitChildren(Visitor v) { | |
| recordType.accept(v); | |
| for (final Constant entry in positional) { | |
| entry.acceptReference(v); | |
| } | |
| for (final Constant entry in named.values) { | |
| entry.acceptReference(v); | |
| } | |
| } | |
| @override | |
| R accept<R>(ConstantVisitor<R> v) => v.visitRecordConstant(this); | |
| @override | |
| R accept1<R, A>(ConstantVisitor1<R, A> v, A arg) => | |
| v.visitRecordConstant(this, arg); | |
| @override | |
| R acceptReference<R>(ConstantReferenceVisitor<R> v) => | |
| v.visitRecordConstantReference(this); | |
| @override | |
| R acceptReference1<R, A>(ConstantReferenceVisitor1<R, A> v, A arg) => | |
| v.visitRecordConstantReference(this, arg); | |
| @override | |
| void toTextInternal(AstPrinter printer) { | |
| printer.write("const ("); | |
| String comma = ''; | |
| for (Constant entry in positional) { | |
| printer.write(comma); | |
| printer.writeConstant(entry); | |
| comma = ', '; | |
| } | |
| if (named.isNotEmpty) { | |
| printer.write(comma); | |
| comma = ''; | |
| printer.write("{"); | |
| for (MapEntry<String, Constant> entry in named.entries) { | |
| printer.write(comma); | |
| printer.write(entry.key); | |
| printer.write(": "); | |
| printer.writeConstant(entry.value); | |
| comma = ', '; | |
| } | |
| printer.write("}"); | |
| } | |
| printer.write(")"); | |
| } | |
| @override | |
| String toString() => "RecordConstant(${toStringInternal()})"; | |
| @override | |
| late final int hashCode = _Hash.combineMapHashUnordered( | |
| named, | |
| _Hash.combineListHash(positional), | |
| ); | |
| @override | |
| bool operator ==(Object other) => | |
| identical(this, other) || | |
| (other is RecordConstant && | |
| listEquals(other.positional, positional) && | |
| mapEquals(other.named, named)); | |
| @override | |
| DartType getType(StaticTypeContext context) => recordType; | |
| } | |
| class InstanceConstant extends Constant { | |
| final Reference classReference; | |
| final DartTypeList typeArguments; | |
| final Map<Reference, Constant> fieldValues; | |
| new(this.classReference, this.typeArguments, this.fieldValues); | |
| Class get classNode => classReference.asClass; | |
| @override | |
| void visitChildren(Visitor v) { | |
| classReference.asClass.acceptReference(v); | |
| visitList(typeArguments, v); | |
| for (final Reference reference in fieldValues.keys) { | |
| reference.asField.acceptReference(v); | |
| } | |
| for (final Constant constant in fieldValues.values) { | |
| constant.acceptReference(v); | |
| } | |
| } | |
| @override | |
| R accept<R>(ConstantVisitor<R> v) => v.visitInstanceConstant(this); | |
| @override | |
| R accept1<R, A>(ConstantVisitor1<R, A> v, A arg) => | |
| v.visitInstanceConstant(this, arg); | |
| @override | |
| R acceptReference<R>(ConstantReferenceVisitor<R> v) => | |
| v.visitInstanceConstantReference(this); | |
| @override | |
| R acceptReference1<R, A>(ConstantReferenceVisitor1<R, A> v, A arg) => | |
| v.visitInstanceConstantReference(this, arg); | |
| @override | |
| void toTextInternal(AstPrinter printer) { | |
| printer.write('const '); | |
| printer.writeClassName(classReference); | |
| printer.writeTypeArguments(typeArguments); | |
| printer.write('{'); | |
| String comma = ''; | |
| fieldValues.forEach((Reference fieldRef, Constant constant) { | |
| printer.write(comma); | |
| printer.writeMemberName(fieldRef); | |
| printer.write(': '); | |
| printer.writeConstant(constant); | |
| comma = ', '; | |
| }); | |
| printer.write('}'); | |
| } | |
| @override | |
| String toString() => 'InstanceConstant(${toStringInternal()})'; | |
| @override | |
| late final int hashCode = _Hash.combine2Finish( | |
| classReference.hashCode, | |
| listHashCode(typeArguments), | |
| _Hash.combineMapHashUnordered(fieldValues), | |
| ); | |
| @override | |
| bool operator ==(Object other) { | |
| return identical(this, other) || | |
| (other is InstanceConstant && | |
| other.classReference == classReference && | |
| listEquals(other.typeArguments, typeArguments) && | |
| mapEquals(other.fieldValues, fieldValues)); | |
| } | |
| @override | |
| DartType getType(StaticTypeContext context) => | |
| new InterfaceType(classNode, context.nonNullable, typeArguments); | |
| } | |
| class InstantiationConstant extends Constant { | |
| final Constant tearOffConstant; | |
| final DartTypeList types; | |
| new(this.tearOffConstant, this.types); | |
| @override | |
| void visitChildren(Visitor v) { | |
| tearOffConstant.acceptReference(v); | |
| visitList(types, v); | |
| } | |
| @override | |
| R accept<R>(ConstantVisitor<R> v) => v.visitInstantiationConstant(this); | |
| @override | |
| R accept1<R, A>(ConstantVisitor1<R, A> v, A arg) => | |
| v.visitInstantiationConstant(this, arg); | |
| @override | |
| R acceptReference<R>(ConstantReferenceVisitor<R> v) => | |
| v.visitInstantiationConstantReference(this); | |
| @override | |
| R acceptReference1<R, A>(ConstantReferenceVisitor1<R, A> v, A arg) => | |
| v.visitInstantiationConstantReference(this, arg); | |
| @override | |
| void toTextInternal(AstPrinter printer) { | |
| printer.writeConstant(tearOffConstant); | |
| printer.writeTypeArguments(types); | |
| } | |
| @override | |
| String toString() => 'InstantiationConstant(${toStringInternal()})'; | |
| @override | |
| int get hashCode => _Hash.combineFinish( | |
| tearOffConstant.hashCode, | |
| _Hash.combineListHash(types), | |
| ); | |
| @override | |
| bool operator ==(Object other) { | |
| return other is InstantiationConstant && | |
| other.tearOffConstant == tearOffConstant && | |
| listEquals(other.types, types); | |
| } | |
| @override | |
| DartType getType(StaticTypeContext context) { | |
| final FunctionType type = tearOffConstant.getType(context) as FunctionType; | |
| return FunctionTypeInstantiator.instantiate(type, types); | |
| } | |
| } | |
| abstract class TearOffConstant implements Constant { | |
| Reference get targetReference; | |
| Member get target; | |
| FunctionNode get function; | |
| } | |
| class StaticTearOffConstant extends Constant implements TearOffConstant { | |
| @override | |
| final Reference targetReference; | |
| new(Procedure target) | |
| : assert(target.isStatic), | |
| assert( | |
| target.kind == ProcedureKind.Method, | |
| "Unexpected static tear off target: $target", | |
| ), | |
| targetReference = target.reference; | |
| new byReference(this.targetReference); | |
| @override | |
| Procedure get target => targetReference.asProcedure; | |
| @override | |
| FunctionNode get function => target.function; | |
| @override | |
| void visitChildren(Visitor v) { | |
| target.acceptReference(v); | |
| } | |
| @override | |
| R accept<R>(ConstantVisitor<R> v) => v.visitStaticTearOffConstant(this); | |
| @override | |
| R accept1<R, A>(ConstantVisitor1<R, A> v, A arg) => | |
| v.visitStaticTearOffConstant(this, arg); | |
| @override | |
| R acceptReference<R>(ConstantReferenceVisitor<R> v) => | |
| v.visitStaticTearOffConstantReference(this); | |
| @override | |
| R acceptReference1<R, A>(ConstantReferenceVisitor1<R, A> v, A arg) => | |
| v.visitStaticTearOffConstantReference(this, arg); | |
| @override | |
| void toTextInternal(AstPrinter printer) { | |
| printer.writeMemberName(targetReference); | |
| } | |
| @override | |
| String toString() => 'StaticTearOffConstant(${toStringInternal()})'; | |
| @override | |
| int get hashCode => targetReference.hashCode; | |
| @override | |
| bool operator ==(Object other) { | |
| return other is StaticTearOffConstant && | |
| other.targetReference == targetReference; | |
| } | |
| @override | |
| FunctionType getType(StaticTypeContext context) { | |
| return target.function.computeFunctionType(context.nonNullable); | |
| } | |
| } | |
| class ConstructorTearOffConstant extends Constant implements TearOffConstant { | |
| @override | |
| final Reference targetReference; | |
| new(Member target) | |
| : assert( | |
| target is Constructor || (target is Procedure && target.isFactory), | |
| "Unexpected constructor tear off target: $target", | |
| ), | |
| this.targetReference = getNonNullableMemberReferenceGetter(target); | |
| new byReference(this.targetReference); | |
| @override | |
| Member get target => targetReference.asMember; | |
| @override | |
| FunctionNode get function => target.function!; | |
| @override | |
| void visitChildren(Visitor v) { | |
| target.acceptReference(v); | |
| } | |
| @override | |
| R accept<R>(ConstantVisitor<R> v) => v.visitConstructorTearOffConstant(this); | |
| @override | |
| R accept1<R, A>(ConstantVisitor1<R, A> v, A arg) => | |
| v.visitConstructorTearOffConstant(this, arg); | |
| @override | |
| R acceptReference<R>(ConstantReferenceVisitor<R> v) => | |
| v.visitConstructorTearOffConstantReference(this); | |
| @override | |
| R acceptReference1<R, A>(ConstantReferenceVisitor1<R, A> v, A arg) => | |
| v.visitConstructorTearOffConstantReference(this, arg); | |
| @override | |
| void toTextInternal(AstPrinter printer) { | |
| printer.writeMemberName(targetReference); | |
| } | |
| @override | |
| String toString() => 'ConstructorTearOffConstant(${toStringInternal()})'; | |
| @override | |
| int get hashCode => targetReference.hashCode; | |
| @override | |
| bool operator ==(Object other) { | |
| return other is ConstructorTearOffConstant && | |
| other.targetReference == targetReference; | |
| } | |
| @override | |
| FunctionType getType(StaticTypeContext context) { | |
| return function.computeFunctionType(context.nonNullable); | |
| } | |
| } | |
| class RedirectingFactoryTearOffConstant extends Constant | |
| implements TearOffConstant { | |
| @override | |
| final Reference targetReference; | |
| new(Procedure target) | |
| : assert(target.isRedirectingFactory), | |
| this.targetReference = getNonNullableMemberReferenceGetter(target); | |
| new byReference(this.targetReference); | |
| @override | |
| Procedure get target => targetReference.asProcedure; | |
| @override | |
| FunctionNode get function => target.function; | |
| @override | |
| void visitChildren(Visitor v) { | |
| target.acceptReference(v); | |
| } | |
| @override | |
| R accept<R>(ConstantVisitor<R> v) => | |
| v.visitRedirectingFactoryTearOffConstant(this); | |
| @override | |
| R accept1<R, A>(ConstantVisitor1<R, A> v, A arg) => | |
| v.visitRedirectingFactoryTearOffConstant(this, arg); | |
| @override | |
| R acceptReference<R>(ConstantReferenceVisitor<R> v) => | |
| v.visitRedirectingFactoryTearOffConstantReference(this); | |
| @override | |
| R acceptReference1<R, A>(ConstantReferenceVisitor1<R, A> v, A arg) => | |
| v.visitRedirectingFactoryTearOffConstantReference(this, arg); | |
| @override | |
| void toTextInternal(AstPrinter printer) { | |
| printer.writeMemberName(targetReference); | |
| } | |
| @override | |
| String toString() => | |
| 'RedirectingFactoryTearOffConstant(${toStringInternal()})'; | |
| @override | |
| int get hashCode => targetReference.hashCode; | |
| @override | |
| bool operator ==(Object other) { | |
| return other is RedirectingFactoryTearOffConstant && | |
| other.targetReference == targetReference; | |
| } | |
| @override | |
| FunctionType getType(StaticTypeContext context) { | |
| return function.computeFunctionType(context.nonNullable); | |
| } | |
| } | |
| class TypedefTearOffConstant extends Constant { | |
| final StructuralParameterList parameters; | |
| final TearOffConstant tearOffConstant; | |
| final DartTypeList types; | |
| @override | |
| late final int hashCode = _computeHashCode(); | |
| new(this.parameters, this.tearOffConstant, this.types); | |
| @override | |
| void visitChildren(Visitor v) { | |
| visitList(parameters, v); | |
| tearOffConstant.acceptReference(v); | |
| visitList(types, v); | |
| } | |
| @override | |
| R accept<R>(ConstantVisitor<R> v) => v.visitTypedefTearOffConstant(this); | |
| @override | |
| R accept1<R, A>(ConstantVisitor1<R, A> v, A arg) => | |
| v.visitTypedefTearOffConstant(this, arg); | |
| @override | |
| R acceptReference<R>(ConstantReferenceVisitor<R> v) => | |
| v.visitTypedefTearOffConstantReference(this); | |
| @override | |
| R acceptReference1<R, A>(ConstantReferenceVisitor1<R, A> v, A arg) => | |
| v.visitTypedefTearOffConstantReference(this, arg); | |
| @override | |
| void toTextInternal(AstPrinter printer) { | |
| printer.writeStructuralParameters(parameters); | |
| printer.writeConstant(tearOffConstant); | |
| printer.writeTypeArguments(types); | |
| } | |
| @override | |
| String toString() => 'TypedefTearOffConstant(${toStringInternal()})'; | |
| @override | |
| bool operator ==(Object other) { | |
| if (other is! TypedefTearOffConstant) return false; | |
| if (other.tearOffConstant != tearOffConstant) return false; | |
| if (other.parameters.length != parameters.length) return false; | |
| if (parameters.isNotEmpty) { | |
| Assumptions assumptions = new Assumptions(); | |
| for (int index = 0; index < parameters.length; index++) { | |
| assumptions.assumeStructuralParameter( | |
| parameters[index], | |
| other.parameters[index], | |
| ); | |
| } | |
| for (int index = 0; index < parameters.length; index++) { | |
| if (!parameters[index].bound.equals( | |
| other.parameters[index].bound, | |
| assumptions, | |
| )) { | |
| return false; | |
| } | |
| } | |
| for (int i = 0; i < types.length; ++i) { | |
| if (!types[i].equals(other.types[i], assumptions)) { | |
| return false; | |
| } | |
| } | |
| } | |
| return true; | |
| } | |
| int _computeHashCode() { | |
| int hash = 1237; | |
| for (int i = 0; i < parameters.length; ++i) { | |
| StructuralParameter parameter = parameters[i]; | |
| hash = 0x3fffffff & (hash * 31 + parameter.bound.hashCode); | |
| } | |
| for (int i = 0; i < types.length; ++i) { | |
| hash = 0x3fffffff & (hash * 31 + types[i].hashCode); | |
| } | |
| hash = 0x3fffffff & (hash * 31 + tearOffConstant.hashCode); | |
| return hash; | |
| } | |
| @override | |
| DartType getType(StaticTypeContext context) { | |
| FunctionType type = tearOffConstant.getType(context) as FunctionType; | |
| FreshStructuralParameters freshStructuralParameters = | |
| getFreshStructuralParameters(parameters); | |
| type = freshStructuralParameters.substitute( | |
| FunctionTypeInstantiator.instantiate(type, types), | |
| ) as FunctionType; | |
| return new FunctionType( | |
| type.positionalParameters, | |
| type.returnType, | |
| type.declaredNullability, | |
| namedParameters: type.namedParameters, | |
| typeParameters: freshStructuralParameters.freshTypeParameters, | |
| requiredParameterCount: type.requiredParameterCount, | |
| ); | |
| } | |
| } | |
| class TypeLiteralConstant extends Constant { | |
| final DartType type; | |
| new(this.type); | |
| @override | |
| void visitChildren(Visitor v) { | |
| type.accept(v); | |
| } | |
| @override | |
| R accept<R>(ConstantVisitor<R> v) => v.visitTypeLiteralConstant(this); | |
| @override | |
| R accept1<R, A>(ConstantVisitor1<R, A> v, A arg) => | |
| v.visitTypeLiteralConstant(this, arg); | |
| @override | |
| R acceptReference<R>(ConstantReferenceVisitor<R> v) => | |
| v.visitTypeLiteralConstantReference(this); | |
| @override | |
| R acceptReference1<R, A>(ConstantReferenceVisitor1<R, A> v, A arg) => | |
| v.visitTypeLiteralConstantReference(this, arg); | |
| @override | |
| void toTextInternal(AstPrinter printer) { | |
| printer.writeType(type); | |
| } | |
| @override | |
| String toString() => 'TypeLiteralConstant(${toStringInternal()})'; | |
| @override | |
| int get hashCode => type.hashCode; | |
| @override | |
| bool operator ==(Object other) { | |
| return other is TypeLiteralConstant && other.type == type; | |
| } | |
| @override | |
| DartType getType(StaticTypeContext context) => | |
| context.typeEnvironment.coreTypes.typeRawType(context.nonNullable); | |
| } | |
| class UnevaluatedConstant extends Constant { | |
| final Expression expression; | |
| new(this.expression) { | |
| expression.parent = null; | |
| } | |
| @override | |
| void visitChildren(Visitor v) { | |
| expression.accept(v); | |
| } | |
| @override | |
| R accept<R>(ConstantVisitor<R> v) => v.visitUnevaluatedConstant(this); | |
| @override | |
| R accept1<R, A>(ConstantVisitor1<R, A> v, A arg) => | |
| v.visitUnevaluatedConstant(this, arg); | |
| @override | |
| R acceptReference<R>(ConstantReferenceVisitor<R> v) => | |
| v.visitUnevaluatedConstantReference(this); | |
| @override | |
| R acceptReference1<R, A>(ConstantReferenceVisitor1<R, A> v, A arg) => | |
| v.visitUnevaluatedConstantReference(this, arg); | |
| @override | |
| DartType getType(StaticTypeContext context) => | |
| expression.getStaticType(context); | |
| @override | |
| void toTextInternal(AstPrinter printer) { | |
| printer.write('unevaluated{'); | |
| printer.writeExpression(expression); | |
| printer.write('}'); | |
| } | |
| @override | |
| String toString() { | |
| return "UnevaluatedConstant(${toStringInternal()})"; | |
| } | |
| @override | |
| int get hashCode => expression.hashCode; | |
| @override | |
| bool operator ==(Object other) { | |
| return other is UnevaluatedConstant && other.expression == expression; | |
| } | |
| } |