blob: 69eb1be823d984682982f037126d09ea127ec130 [file] [log] [blame]
Asger Feldthaus02604e92016-04-26 08:39:151// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5/// -----------------------------------------------------------------------
6/// ERROR HANDLING
7/// -----------------------------------------------------------------------
8///
Asger Feldthaus0d9ab902016-08-17 11:51:339/// As a rule of thumb, errors that can be detected statically are handled by
10/// the frontend, typically by translating the erroneous code into a 'throw' or
11/// a call to 'noSuchMethod'.
Asger Feldthaus02604e92016-04-26 08:39:1512///
Asger Feldthaus0d9ab902016-08-17 11:51:3313/// For example, there are no arity mismatches in static invocations, and
14/// there are no direct invocations of a constructor on a abstract class.
Asger Feldthaus02604e92016-04-26 08:39:1515///
16/// -----------------------------------------------------------------------
Asger Feldthaus02604e92016-04-26 08:39:1517/// STATIC vs TOP-LEVEL
18/// -----------------------------------------------------------------------
19///
20/// The term `static` includes both static class members and top-level members.
21///
22/// "Static class member" is the preferred term for non-top level statics.
23///
24/// Static class members are not lifted to the library level because mirrors
25/// and stack traces can observe that they are class members.
26///
27/// -----------------------------------------------------------------------
28/// PROCEDURES
29/// -----------------------------------------------------------------------
30///
31/// "Procedure" is an umbrella term for method, getter, setter, index-getter,
32/// index-setter, operator overloader, and factory constructor.
33///
34/// Generative constructors, field initializers, local functions are NOT
35/// procedures.
36///
37/// -----------------------------------------------------------------------
38/// TRANSFORMATIONS
39/// -----------------------------------------------------------------------
40///
41/// AST transformations can be performed using [TreeNode.replaceWith] or the
42/// [Transformer] visitor class.
43///
44/// Use [Transformer] for bulk transformations that are likely to transform lots
45/// of nodes, and [TreeNode.replaceWith] for sparse transformations that mutate
46/// relatively few nodes. Or use whichever is more convenient.
47///
48/// The AST can also be mutated by direct field manipulation, but the user then
49/// has to update parent pointers manually.
50///
51library kernel.ast;
52
53import 'visitor.dart';
54export 'visitor.dart';
55
Martin Kustermann1392dcb2016-08-09 10:53:4256import 'type_propagation/type_propagation.dart';
57export 'type_propagation/type_propagation.dart';
58
Asger Feldthaus760da8e2016-08-24 14:46:5059import 'transformations/flags.dart';
Asger Feldthaus02604e92016-04-26 08:39:1560import 'text/ast_to_text.dart';
61import 'type_algebra.dart';
Asger Feldthaus2eaa8842016-09-06 09:40:1362import 'type_environment.dart';
Asger Feldthaus02604e92016-04-26 08:39:1563
64/// Any type of node in the IR.
65abstract class Node {
66 const Node();
67
68 accept(Visitor v);
69 visitChildren(Visitor v);
70
71 /// Returns the textual representation of this node for use in debugging.
72 ///
73 /// [toString] should only be used for debugging and short-running test tools
74 /// as it can cause serious memory leaks.
75 ///
76 /// Synthetic names are cached globally to retain consistency across different
77 /// [toString] calls (hence the memory leak).
Asger Feldthaus246f6c12016-05-25 11:56:4378 ///
79 /// Nodes that are named, such as [Class] and [Member], return their
80 /// (possibly synthesized) name, whereas other AST nodes return the complete
81 /// textual representation of their subtree.
Asger Feldthaus02604e92016-04-26 08:39:1582 String toString() => debugNodeToString(this);
83}
84
85/// A mutable AST node with a parent pointer.
86///
87/// This is anything other than [Name] and [DartType] nodes.
88abstract class TreeNode extends Node {
89 static int _hashCounter = 0;
Asger Feldthaus885be102016-05-25 11:09:5990 final int hashCode = _hashCounter = (_hashCounter + 1) & 0x3fffffff;
Jens Johansena85aabb2016-09-29 09:26:4091 static const int noOffset = -1;
Asger Feldthaus02604e92016-04-26 08:39:1592
93 TreeNode parent;
94
Jens Johansena85aabb2016-09-29 09:26:4095 /// Offset in the source file it comes from. Valid values are from 0 and up,
96 /// or -1 ([noOffset]) if the file offset is not available
97 /// (this is the default if none is specifically set).
98 int fileOffset = noOffset;
99
Asger Feldthaus02604e92016-04-26 08:39:15100 accept(TreeVisitor v);
101 visitChildren(Visitor v);
102 transformChildren(Transformer v);
103
104 /// Replaces [child] with [replacement].
105 ///
106 /// The caller is responsible for ensuring that the AST remains a tree. In
107 /// particular, [replacement] should be an orphan or be part of an orphaned
108 /// subtree.
109 ///
110 /// Has no effect if [child] is not actually a child of this node.
111 ///
112 /// If [replacement] is `null`, this will [remove] the [child] node.
113 void replaceChild(TreeNode child, TreeNode replacement) {
114 transformChildren(new _ChildReplacer(child, replacement));
115 }
116
117 /// Inserts another node in place of this one.
118 ///
119 /// The caller is responsible for ensuring that the AST remains a tree. In
120 /// particular, [replacement] should be an orphan or be part of an orphaned
121 /// subtree.
122 ///
123 /// If [replacement] is `null`, this will [remove] the node.
124 void replaceWith(TreeNode replacement) {
125 parent.replaceChild(this, replacement);
126 parent = null;
127 }
128
129 /// Removes this node from the [List] it is currently stored in, or assigns
130 /// `null` to the field on the parent currently pointing to the node.
131 ///
132 /// Has no effect if the node is orphaned or if the parent pointer is stale.
133 void remove() {
134 parent?.replaceChild(this, null);
135 parent = null;
136 }
Asger Feldthaus5a406362016-10-31 10:29:37137
138 Program get enclosingProgram => parent?.enclosingProgram;
139
140 /// Returns the best known source location of the given AST node, or `null` if
141 /// the node is orphaned.
142 ///
143 /// This getter is intended for diagnostics and debugging, and should be
144 /// avoided in production code.
145 Location get location {
146 if (fileOffset == noOffset) return parent?.location;
147 return _getLocationInEnclosingFile(fileOffset);
148 }
149
150 Location _getLocationInEnclosingFile(int offset) {
151 return parent?._getLocationInEnclosingFile(offset);
152 }
Asger Feldthaus02604e92016-04-26 08:39:15153}
154
155// ------------------------------------------------------------------------
156// LIBRARIES and CLASSES
157// ------------------------------------------------------------------------
158
Asger Feldthaus7ad92c22016-05-09 12:12:40159class Library extends TreeNode implements Comparable<Library> {
Asger Feldthaus02604e92016-04-26 08:39:15160 /// An absolute import path to this library.
161 ///
162 /// The [Uri] should have the `dart`, `package`, or `file` scheme.
Asger Feldthaus02604e92016-04-26 08:39:15163 Uri importUri;
164
Jens Johansena85aabb2016-09-29 09:26:40165 /// The uri of the source file this library was loaded from.
166 String fileUri;
167
Asger Feldthauscd94dc02016-10-04 15:26:10168 /// If true, the library is part of another build unit and its contents
169 /// are only partially loaded.
Asger Feldthaus02604e92016-04-26 08:39:15170 ///
Asger Feldthaus3ac36ac2016-10-04 11:30:46171 /// Classes of an external library are loaded at one of the [ClassLevel]s
172 /// other than [ClassLevel.Body]. Members in an external library have no
173 /// body, but have their typed interface present.
Asger Feldthaus02604e92016-04-26 08:39:15174 ///
Asger Feldthaus3ac36ac2016-10-04 11:30:46175 /// If the libary is non-external, then its classes are at [ClassLevel.Body]
176 /// and all members are loaded.
177 bool isExternal;
Asger Feldthaus02604e92016-04-26 08:39:15178
Asger Feldthaus3ac36ac2016-10-04 11:30:46179 String name;
Asger Feldthaus02604e92016-04-26 08:39:15180 final List<Class> classes;
181 final List<Procedure> procedures;
182 final List<Field> fields;
183
184 Library(this.importUri,
185 {this.name,
Asger Feldthaus3ac36ac2016-10-04 11:30:46186 this.isExternal: false,
Asger Feldthaus02604e92016-04-26 08:39:15187 List<Class> classes,
188 List<Procedure> procedures,
189 List<Field> fields})
190 : this.classes = classes ?? <Class>[],
191 this.procedures = procedures ?? <Procedure>[],
192 this.fields = fields ?? <Field>[] {
Asger Feldthaus246f6c12016-05-25 11:56:43193 setParents(this.classes, this);
194 setParents(this.procedures, this);
195 setParents(this.fields, this);
Asger Feldthaus02604e92016-04-26 08:39:15196 }
197
Asger Feldthaus246f6c12016-05-25 11:56:43198 /// Returns the top-level fields and procedures defined in this library.
199 ///
200 /// This getter is for convenience, not efficiency. Consider manually
201 /// iterating the members to speed up code in production.
202 Iterable<Member> get members =>
203 <Iterable<Member>>[fields, procedures].expand((x) => x);
204
Asger Feldthaus02604e92016-04-26 08:39:15205 void addMember(Member member) {
206 member.parent = this;
207 if (member is Procedure) {
208 procedures.add(member);
209 } else if (member is Field) {
210 fields.add(member);
211 } else {
212 throw new ArgumentError(member);
213 }
214 }
215
216 void addClass(Class class_) {
217 class_.parent = this;
218 classes.add(class_);
219 }
220
221 accept(TreeVisitor v) => v.visitLibrary(this);
222
223 visitChildren(Visitor v) {
Asger Feldthaus246f6c12016-05-25 11:56:43224 visitList(classes, v);
225 visitList(procedures, v);
226 visitList(fields, v);
Asger Feldthaus02604e92016-04-26 08:39:15227 }
228
229 transformChildren(Transformer v) {
Asger Feldthaus246f6c12016-05-25 11:56:43230 transformList(classes, v, this);
231 transformList(procedures, v, this);
232 transformList(fields, v, this);
Asger Feldthaus02604e92016-04-26 08:39:15233 }
234
Asger Feldthaus7ad92c22016-05-09 12:12:40235 static int _libraryIdCounter = 0;
236 int _libraryId = ++_libraryIdCounter;
237
238 int compareTo(Library other) => _libraryId - other._libraryId;
Asger Feldthaus246f6c12016-05-25 11:56:43239
240 /// Returns a possibly synthesized name for this library, consistent with
241 /// the names across all [toString] calls.
242 String toString() => debugLibraryName(this);
Asger Feldthaus5a406362016-10-31 10:29:37243
244 Location _getLocationInEnclosingFile(int offset) {
245 return enclosingProgram.getLocation(fileUri, offset);
246 }
Asger Feldthaus02604e92016-04-26 08:39:15247}
248
Asger Feldthaus3ac36ac2016-10-04 11:30:46249/// The degree to which the contents of a class have been loaded into memory.
250///
251/// Each level imply the requirements of the previous ones.
252enum ClassLevel {
253 /// Temporary loading level for internal use by IR producers. Consumers of
254 /// kernel code should not expect to see classes at this level.
255 Temporary,
256
257 /// The class may be used as a type, and it may contain members that are
258 /// referenced from this build unit.
259 ///
260 /// The type parameters and their bounds are present.
261 ///
262 /// There is no guarantee that all members are present.
263 ///
264 /// All supertypes of this class are at [Type] level or higher.
265 Type,
266
267 /// All instance members of the class are present.
268 ///
269 /// All supertypes of this class are at [Hierarchy] level or higher.
270 ///
271 /// This level exists so supertypes of a fully loaded class contain all the
272 /// members needed to detect override constraints.
273 Hierarchy,
274
275 /// All members of the class are fully loaded and are in the correct order.
276 ///
277 /// Annotations are present on classes and members.
278 ///
279 /// All supertypes of this class are at [Hierarchy] level or higher,
280 /// not necessarily at [Body] level.
281 Body,
282}
283
Asger Feldthausd1f47022016-08-22 10:35:18284/// Declaration of a regular class or a mixin application.
Asger Feldthaus02604e92016-04-26 08:39:15285///
Asger Feldthausd1f47022016-08-22 10:35:18286/// Mixin applications may not contain fields or procedures, as they implicitly
287/// use those from its mixed-in type. However, the IR does not enforce this
288/// rule directly, as doing so can obstruct transformations. It is possible to
289/// transform a mixin application to become a regular class, and vice versa.
290class Class extends TreeNode {
Asger Feldthaus3ac36ac2016-10-04 11:30:46291 /// The degree to which the contents of the class have been loaded.
292 ClassLevel level = ClassLevel.Body;
293
Asger Feldthausfd6064c2016-08-09 14:32:23294 /// List of metadata annotations on the class.
295 ///
296 /// This defaults to an immutable empty list. Use [addAnnotation] to add
297 /// annotations if needed.
298 List<Expression> annotations = const <Expression>[];
299
Asger Feldthaus97111b82016-08-31 07:42:55300 /// Name of the class.
301 ///
302 /// Must be non-null and must be unique within the library.
303 ///
304 /// The name may contain characters that are not valid in a Dart identifier,
305 /// in particular, the symbol '&' is used in class names generated for mixin
306 /// applications.
307 String name;
Asger Feldthaus02604e92016-04-26 08:39:15308 bool isAbstract;
Jens Johansena85aabb2016-09-29 09:26:40309
310 /// The uri of the source file this class was loaded from.
311 String fileUri;
312
Asger Feldthaus02604e92016-04-26 08:39:15313 final List<TypeParameter> typeParameters;
314
315 /// The immediate super type, or `null` if this is the root class.
Asger Feldthause1c26f82016-10-24 14:21:52316 Supertype supertype;
Asger Feldthaus02604e92016-04-26 08:39:15317
Asger Feldthausd1f47022016-08-22 10:35:18318 /// The mixed-in type if this is a mixin application, otherwise `null`.
Asger Feldthause1c26f82016-10-24 14:21:52319 Supertype mixedInType;
Asger Feldthausd1f47022016-08-22 10:35:18320
Asger Feldthaus02604e92016-04-26 08:39:15321 /// The types from the `implements` clause.
Asger Feldthause1c26f82016-10-24 14:21:52322 final List<Supertype> implementedTypes;
Asger Feldthaus02604e92016-04-26 08:39:15323
324 /// Fields declared in the class.
325 ///
Asger Feldthausd1f47022016-08-22 10:35:18326 /// For mixin applications this should be empty.
Asger Feldthaus02604e92016-04-26 08:39:15327 final List<Field> fields;
328
329 /// Constructors declared in the class.
330 final List<Constructor> constructors;
331
332 /// Procedures declared in the class.
333 ///
Asger Feldthausd1f47022016-08-22 10:35:18334 /// For mixin applications this should be empty.
Asger Feldthaus02604e92016-04-26 08:39:15335 final List<Procedure> procedures;
336
Asger Feldthaus2eaa8842016-09-06 09:40:13337 Class(
338 {this.name,
Asger Feldthausd1f47022016-08-22 10:35:18339 this.isAbstract: false,
340 this.supertype,
341 this.mixedInType,
342 List<TypeParameter> typeParameters,
343 List<InterfaceType> implementedTypes,
344 List<Constructor> constructors,
345 List<Procedure> procedures,
Jens Johansena85aabb2016-09-29 09:26:40346 List<Field> fields,
347 this.fileUri})
Asger Feldthausd1f47022016-08-22 10:35:18348 : this.typeParameters = typeParameters ?? <TypeParameter>[],
Asger Feldthause1c26f82016-10-24 14:21:52349 this.implementedTypes = implementedTypes ?? <Supertype>[],
Asger Feldthausd1f47022016-08-22 10:35:18350 this.fields = fields ?? <Field>[],
351 this.constructors = constructors ?? <Constructor>[],
352 this.procedures = procedures ?? <Procedure>[] {
353 setParents(this.typeParameters, this);
354 setParents(this.constructors, this);
355 setParents(this.procedures, this);
356 setParents(this.fields, this);
Asger Feldthaus02604e92016-04-26 08:39:15357 }
358
Asger Feldthaus246f6c12016-05-25 11:56:43359 /// The immediate super class, or `null` if this is the root class.
360 Class get superclass => supertype?.classNode;
361
Asger Feldthaus246f6c12016-05-25 11:56:43362 /// The mixed-in class if this is a mixin application, otherwise `null`.
Asger Feldthaus760da8e2016-08-24 14:46:50363 ///
364 /// Note that this may itself be a mixin application. Use [mixin] to get the
365 /// class that has the fields and procedures.
Asger Feldthaus246f6c12016-05-25 11:56:43366 Class get mixedInClass => mixedInType?.classNode;
367
Asger Feldthaus760da8e2016-08-24 14:46:50368 /// The class that declares the field and procedures of this class.
369 Class get mixin => mixedInClass?.mixin ?? this;
Asger Feldthaus246f6c12016-05-25 11:56:43370
Asger Feldthausd1f47022016-08-22 10:35:18371 bool get isMixinApplication => mixedInType != null;
Asger Feldthaus02604e92016-04-26 08:39:15372
373 /// Members declared in this class.
374 ///
375 /// This getter is for convenience, not efficiency. Consider manually
376 /// iterating the members to speed up code in production.
377 Iterable<Member> get members =>
378 <Iterable<Member>>[fields, constructors, procedures].expand((x) => x);
379
380 /// The immediately extended, mixed-in, and implemented types.
381 ///
382 /// This getter is for convenience, not efficiency. Consider manually
383 /// iterating the super types to speed up code in production.
Asger Feldthause1c26f82016-10-24 14:21:52384 Iterable<Supertype> get supers => <Iterable<Supertype>>[
Asger Feldthaus246f6c12016-05-25 11:56:43385 supertype == null ? const [] : [supertype],
Asger Feldthaus02604e92016-04-26 08:39:15386 mixedInType == null ? const [] : [mixedInType],
387 implementedTypes
388 ].expand((x) => x);
389
390 /// The library containing this class.
391 Library get enclosingLibrary => parent;
392
393 /// Adds a member to this class.
394 ///
395 /// Throws an error if attempting to add a field or procedure to a mixin
396 /// application.
397 void addMember(Member member) {
398 member.parent = this;
399 if (member is Constructor) {
400 constructors.add(member);
401 } else if (member is Procedure) {
402 procedures.add(member);
403 } else if (member is Field) {
404 fields.add(member);
405 } else {
406 throw new ArgumentError(member);
407 }
408 }
409
Asger Feldthausfd6064c2016-08-09 14:32:23410 void addAnnotation(Expression node) {
411 if (annotations.isEmpty) {
412 annotations = <Expression>[];
413 }
414 annotations.add(node);
415 node.parent = this;
416 }
417
Asger Feldthausd1f47022016-08-22 10:35:18418 accept(TreeVisitor v) => v.visitClass(this);
419 acceptReference(Visitor v) => v.visitClassReference(this);
Asger Feldthaus02604e92016-04-26 08:39:15420
Asger Feldthaus3ac36ac2016-10-04 11:30:46421 /// If true, the class is part of an external library, that is, it is defined
422 /// in another build unit. Only a subset of its members are present.
423 ///
424 /// These classes should be loaded at either [ClassLevel.Type] or
425 /// [ClassLevel.Hierarchy] level.
426 bool get isInExternalLibrary => enclosingLibrary.isExternal;
Asger Feldthaus02604e92016-04-26 08:39:15427
Asger Feldthause1c26f82016-10-24 14:21:52428 Supertype get asRawSupertype {
429 return new Supertype(this,
430 new List<DartType>.filled(typeParameters.length, const DynamicType()));
431 }
432
433 Supertype get asThisSupertype {
434 return new Supertype(this, _getAsTypeArguments(typeParameters));
435 }
436
Asger Feldthaus02604e92016-04-26 08:39:15437 InterfaceType _rawType;
438 InterfaceType get rawType => _rawType ??= new InterfaceType(this);
439
440 InterfaceType _thisType;
441 InterfaceType get thisType {
442 return _thisType ??=
443 new InterfaceType(this, _getAsTypeArguments(typeParameters));
444 }
445
Asger Feldthaus2eaa8842016-09-06 09:40:13446 InterfaceType _bottomType;
447 InterfaceType get bottomType {
448 return _bottomType ??= new InterfaceType(this,
449 new List<DartType>.filled(typeParameters.length, const BottomType()));
450 }
451
Asger Feldthaus02604e92016-04-26 08:39:15452 /// Returns a possibly synthesized name for this class, consistent with
Asger Feldthaus246f6c12016-05-25 11:56:43453 /// the names used across all [toString] calls.
454 String toString() => debugQualifiedClassName(this);
Asger Feldthaus02604e92016-04-26 08:39:15455
456 visitChildren(Visitor v) {
Asger Feldthausfd6064c2016-08-09 14:32:23457 visitList(annotations, v);
Asger Feldthaus246f6c12016-05-25 11:56:43458 visitList(typeParameters, v);
459 supertype?.accept(v);
Asger Feldthausd1f47022016-08-22 10:35:18460 mixedInType?.accept(v);
Asger Feldthaus246f6c12016-05-25 11:56:43461 visitList(implementedTypes, v);
462 visitList(constructors, v);
463 visitList(procedures, v);
464 visitList(fields, v);
Asger Feldthaus02604e92016-04-26 08:39:15465 }
466
467 transformChildren(Transformer v) {
Asger Feldthausfd6064c2016-08-09 14:32:23468 transformList(annotations, v, this);
Asger Feldthaus246f6c12016-05-25 11:56:43469 transformList(typeParameters, v, this);
Asger Feldthaus760da8e2016-08-24 14:46:50470 if (supertype != null) {
Asger Feldthause1c26f82016-10-24 14:21:52471 supertype = v.visitSupertype(supertype);
Asger Feldthaus760da8e2016-08-24 14:46:50472 }
473 if (mixedInType != null) {
Asger Feldthause1c26f82016-10-24 14:21:52474 mixedInType = v.visitSupertype(mixedInType);
Asger Feldthaus760da8e2016-08-24 14:46:50475 }
Asger Feldthause1c26f82016-10-24 14:21:52476 transformSupertypeList(implementedTypes, v);
Asger Feldthaus246f6c12016-05-25 11:56:43477 transformList(constructors, v, this);
478 transformList(procedures, v, this);
479 transformList(fields, v, this);
Asger Feldthaus02604e92016-04-26 08:39:15480 }
Asger Feldthaus5a406362016-10-31 10:29:37481
482 Location _getLocationInEnclosingFile(int offset) {
483 return enclosingProgram.getLocation(fileUri, offset);
484 }
Asger Feldthaus02604e92016-04-26 08:39:15485}
486
Asger Feldthaus02604e92016-04-26 08:39:15487// ------------------------------------------------------------------------
488// MEMBERS
489// ------------------------------------------------------------------------
490
Asger Feldthaus2efc48c2016-09-23 10:34:06491/// A indirect reference to a member, which can be updated to point at another
492/// member at a later time.
493class _MemberAccessor {
494 Member target;
495 _MemberAccessor(this.target);
496}
497
Asger Feldthaus02604e92016-04-26 08:39:15498abstract class Member extends TreeNode {
Harry Terkelsen9509d282016-08-22 16:56:05499 /// List of metadata annotations on the member.
Asger Feldthausfd6064c2016-08-09 14:32:23500 ///
501 /// This defaults to an immutable empty list. Use [addAnnotation] to add
502 /// annotations if needed.
503 List<Expression> annotations = const <Expression>[];
Asger Feldthaus7ad92c22016-05-09 12:12:40504 Name name;
505
Asger Feldthaus760da8e2016-08-24 14:46:50506 /// Flags summarizing the kinds of AST nodes contained in this member, for
507 /// speeding up transformations that only affect certain types of nodes.
508 ///
509 /// See [TransformerFlag] for the meaning of each bit.
510 ///
511 /// These should not be used for any purpose other than skipping certain
512 /// members if it can be determined that no work is needed in there.
513 ///
514 /// It is valid for these flags to be false positives in rare cases, so
515 /// transformers must tolerate the case where a flag is spuriously set.
516 ///
517 /// This value is not serialized; it is populated by the frontend and the
518 /// deserializer.
519 //
520 // TODO(asgerf): It might be worthwhile to put this on classes as well.
521 int transformerFlags = 0;
522
Asger Feldthaus7ad92c22016-05-09 12:12:40523 Member(this.name);
Asger Feldthaus02604e92016-04-26 08:39:15524
525 Class get enclosingClass => parent is Class ? parent : null;
526 Library get enclosingLibrary => parent is Class ? parent.parent : parent;
527
528 accept(MemberVisitor v);
529 acceptReference(MemberReferenceVisitor v);
530
Asger Feldthaus3ac36ac2016-10-04 11:30:46531 /// If true, the member is part of an external library, that is, it is defined
532 /// in another build unit. Such members have no body or initializer present
533 /// in the IR.
534 bool get isInExternalLibrary => enclosingLibrary.isExternal;
Asger Feldthaus02604e92016-04-26 08:39:15535
Asger Feldthaus7ad92c22016-05-09 12:12:40536 /// Returns true if this is an abstract procedure.
537 bool get isAbstract => false;
538
Asger Feldthause3f2bae2016-09-13 10:40:11539 /// True if this is a field or non-setter procedure.
540 ///
541 /// Note that operators and factories return `true`, even though there are
542 /// normally no calls to their getter.
543 bool get hasGetter;
544
545 /// True if this is a setter or a mutable field.
546 bool get hasSetter;
547
Asger Feldthaus246f6c12016-05-25 11:56:43548 /// True if this is a non-static field or procedure.
549 bool get isInstanceMember;
550
Asger Feldthaus3ac36ac2016-10-04 11:30:46551 /// True if the member has the `external` modifier, implying that the
552 /// implementation is provided by the backend, and is not necessarily written
553 /// in Dart.
554 ///
555 /// Members can have this modifier independently of whether the enclosing
556 /// library is external.
Asger Feldthaus3781ba12016-08-16 11:18:46557 bool get isExternal;
558 void set isExternal(bool value);
559
Asger Feldthaus8a3e7532016-08-02 16:22:54560 /// The body of the procedure or constructor, or `null` if this is a field.
561 FunctionNode get function => null;
562
Asger Feldthaus02604e92016-04-26 08:39:15563 /// Returns a possibly synthesized name for this member, consistent with
Asger Feldthaus246f6c12016-05-25 11:56:43564 /// the names used across all [toString] calls.
565 String toString() => debugQualifiedMemberName(this);
Asger Feldthausfd6064c2016-08-09 14:32:23566
567 void addAnnotation(Expression node) {
568 if (annotations.isEmpty) {
569 annotations = <Expression>[];
570 }
571 annotations.add(node);
572 node.parent = this;
573 }
Asger Feldthaus760da8e2016-08-24 14:46:50574
Asger Feldthaus2eaa8842016-09-06 09:40:13575 DartType get getterType;
576 DartType get setterType;
577
Asger Feldthaus760da8e2016-08-24 14:46:50578 bool get containsSuperCalls {
579 return transformerFlags & TransformerFlag.superCalls != 0;
580 }
Asger Feldthaus2efc48c2016-09-23 10:34:06581
582 _MemberAccessor get _getterInterface;
583 _MemberAccessor get _setterInterface;
Asger Feldthaus02604e92016-04-26 08:39:15584}
585
586/// A field declaration.
587///
Asger Feldthaus2efc48c2016-09-23 10:34:06588/// The implied getter and setter for the field are not represented explicitly,
589/// but can be made explicit if needed.
Asger Feldthaus02604e92016-04-26 08:39:15590class Field extends Member {
Asger Feldthaus2efc48c2016-09-23 10:34:06591 _MemberAccessor _getterInterface, _setterInterface;
592
Asger Feldthaus02604e92016-04-26 08:39:15593 DartType type; // Not null. Defaults to DynamicType.
Martin Kustermann1392dcb2016-08-09 10:53:42594 InferredValue inferredValue; // May be null.
Asger Feldthaus02604e92016-04-26 08:39:15595 int flags = 0;
596 Expression initializer; // May be null.
597
Jens Johansena85aabb2016-09-29 09:26:40598 /// The uri of the source file this field was loaded from.
599 String fileUri;
600
Asger Feldthaus7ad92c22016-05-09 12:12:40601 Field(Name name,
Asger Feldthaus243ea892016-06-06 13:01:51602 {this.type: const DynamicType(),
Martin Kustermann1392dcb2016-08-09 10:53:42603 this.inferredValue,
Asger Feldthaus02604e92016-04-26 08:39:15604 this.initializer,
605 bool isFinal: false,
606 bool isConst: false,
Asger Feldthaus760da8e2016-08-24 14:46:50607 bool isStatic: false,
Asger Feldthaus2efc48c2016-09-23 10:34:06608 bool hasImplicitGetter,
609 bool hasImplicitSetter,
Jens Johansena85aabb2016-09-29 09:26:40610 int transformerFlags: 0,
611 this.fileUri})
Asger Feldthaus243ea892016-06-06 13:01:51612 : super(name) {
Asger Feldthaus2efc48c2016-09-23 10:34:06613 _getterInterface = new _MemberAccessor(this);
614 _setterInterface = new _MemberAccessor(this);
Asger Feldthaus243ea892016-06-06 13:01:51615 assert(type != null);
Asger Feldthaus02604e92016-04-26 08:39:15616 initializer?.parent = this;
617 this.isFinal = isFinal;
618 this.isConst = isConst;
619 this.isStatic = isStatic;
Asger Feldthaus2efc48c2016-09-23 10:34:06620 this.hasImplicitGetter = hasImplicitGetter ?? !isStatic;
621 this.hasImplicitSetter = hasImplicitSetter ?? (!isStatic && !isFinal);
Asger Feldthaus760da8e2016-08-24 14:46:50622 this.transformerFlags = transformerFlags;
Asger Feldthaus02604e92016-04-26 08:39:15623 }
624
625 static const int FlagFinal = 1 << 0; // Must match serialized bit positions.
626 static const int FlagConst = 1 << 1;
627 static const int FlagStatic = 1 << 2;
Asger Feldthaus2efc48c2016-09-23 10:34:06628 static const int FlagHasImplicitGetter = 1 << 3;
629 static const int FlagHasImplicitSetter = 1 << 4;
Asger Feldthaus02604e92016-04-26 08:39:15630
631 bool get isFinal => flags & FlagFinal != 0;
632 bool get isConst => flags & FlagConst != 0;
633 bool get isStatic => flags & FlagStatic != 0;
634
Asger Feldthaus2efc48c2016-09-23 10:34:06635 /// If true, a getter should be generated for this field.
636 ///
637 /// If false, there may or may not exist an explicit getter in the same class
638 /// with the same name as the field.
639 ///
640 /// By default, all non-static fields have implicit getters.
641 bool get hasImplicitGetter => flags & FlagHasImplicitGetter != 0;
642
643 /// If true, a setter should be generated for this field.
644 ///
645 /// If false, there may or may not exist an explicit setter in the same class
646 /// with the same name as the field.
647 ///
648 /// Final fields never have implicit setters, but a field without an implicit
649 /// setter is not necessarily final, as it may be mutated by direct field
650 /// access.
651 ///
652 /// By default, all non-static, non-final fields have implicit getters.
653 bool get hasImplicitSetter => flags & FlagHasImplicitSetter != 0;
654
Asger Feldthaus02604e92016-04-26 08:39:15655 void set isFinal(bool value) {
Martin Kustermann1eb5f622016-07-08 07:22:36656 flags = value ? (flags | FlagFinal) : (flags & ~FlagFinal);
Asger Feldthaus02604e92016-04-26 08:39:15657 }
658
659 void set isConst(bool value) {
Martin Kustermann1eb5f622016-07-08 07:22:36660 flags = value ? (flags | FlagConst) : (flags & ~FlagConst);
Asger Feldthaus02604e92016-04-26 08:39:15661 }
662
663 void set isStatic(bool value) {
Martin Kustermann1eb5f622016-07-08 07:22:36664 flags = value ? (flags | FlagStatic) : (flags & ~FlagStatic);
Asger Feldthaus02604e92016-04-26 08:39:15665 }
666
Asger Feldthaus2efc48c2016-09-23 10:34:06667 void set hasImplicitGetter(bool value) {
668 flags = value
669 ? (flags | FlagHasImplicitGetter)
670 : (flags & ~FlagHasImplicitGetter);
671 }
672
673 void set hasImplicitSetter(bool value) {
674 flags = value
675 ? (flags | FlagHasImplicitSetter)
676 : (flags & ~FlagHasImplicitSetter);
677 }
678
Asger Feldthaus02604e92016-04-26 08:39:15679 /// True if the field is neither final nor const.
Harry Terkelsen9509d282016-08-22 16:56:05680 bool get isMutable => flags & (FlagFinal | FlagConst) == 0;
Asger Feldthaus246f6c12016-05-25 11:56:43681 bool get isInstanceMember => !isStatic;
Asger Feldthause3f2bae2016-09-13 10:40:11682 bool get hasGetter => true;
683 bool get hasSetter => isMutable;
Asger Feldthaus02604e92016-04-26 08:39:15684
Asger Feldthaus3781ba12016-08-16 11:18:46685 bool get isExternal => false;
686 void set isExternal(bool value) {
687 if (value) throw 'Fields cannot be external';
688 }
689
Asger Feldthaus02604e92016-04-26 08:39:15690 accept(MemberVisitor v) => v.visitField(this);
691
692 acceptReference(MemberReferenceVisitor v) => v.visitFieldReference(this);
693
694 visitChildren(Visitor v) {
Asger Feldthausfd6064c2016-08-09 14:32:23695 visitList(annotations, v);
Asger Feldthaus02604e92016-04-26 08:39:15696 type?.accept(v);
Martin Kustermann1392dcb2016-08-09 10:53:42697 inferredValue?.accept(v);
Asger Feldthaus02604e92016-04-26 08:39:15698 name?.accept(v);
699 initializer?.accept(v);
700 }
701
702 transformChildren(Transformer v) {
Asger Feldthaus760da8e2016-08-24 14:46:50703 type = v.visitDartType(type);
Asger Feldthausfd6064c2016-08-09 14:32:23704 transformList(annotations, v, this);
Asger Feldthaus02604e92016-04-26 08:39:15705 if (initializer != null) {
706 initializer = initializer.accept(v);
707 initializer?.parent = this;
708 }
709 }
Asger Feldthaus2eaa8842016-09-06 09:40:13710
711 DartType get getterType => type;
712 DartType get setterType => isMutable ? type : const BottomType();
Asger Feldthaus2efc48c2016-09-23 10:34:06713
714 /// Makes all [PropertyGet]s that have this field as its interface target
715 /// use [getter] as its interface target instead.
716 ///
717 /// That can be used to introduce an explicit getter for a field instead of
718 /// its implicit getter.
719 ///
720 /// This method only updates the stored interface target -- the caller must
721 /// ensure that [getter] actually becomes the target for dispatches that
722 /// would previously hit the implicit field getter.
723 ///
724 /// [DirectPropertyGet]s are not affected, and will continue to access the
725 /// field directly. [PropertyGet] nodes created after the call will not be
726 /// affected until the method is called again.
727 ///
728 /// Existing [ClassHierarchy] instances are not affected by this call.
729 void replaceGetterInterfaceWith(Procedure getter) {
730 _getterInterface.target = getter;
731 _getterInterface = new _MemberAccessor(this);
732 }
733
734 /// Makes all [PropertySet]s that have this field as its interface target
735 /// use [setter] as its interface target instead.
736 ///
737 /// That can be used to introduce an explicit setter for a field instead of
738 /// its implicit setter.
739 ///
740 /// This method only updates the stored interface target -- the caller must
741 /// ensure that [setter] actually becomes the target for dispatches that
742 /// would previously hit the implicit field setter.
743 ///
744 /// [DirectPropertySet] and [FieldInitializer]s are not affected, and will
745 /// continue to access the field directly. [PropertySet] nodes created after
746 /// the call will not be affected until the method is called again.
747 ///
748 /// Existing [ClassHierarchy] instances are not affected by this call.
749 void replaceSetterInterfaceWith(Procedure setter) {
750 _setterInterface.target = setter;
751 _setterInterface = new _MemberAccessor(this);
752 }
Asger Feldthaus5a406362016-10-31 10:29:37753
754 Location _getLocationInEnclosingFile(int offset) {
755 return enclosingProgram.getLocation(fileUri, offset);
756 }
Asger Feldthaus02604e92016-04-26 08:39:15757}
758
759/// A generative constructor, possibly redirecting.
760///
761/// Note that factory constructors are treated as [Procedure]s.
762///
763/// Constructors do not take type parameters. Type arguments from a constructor
764/// invocation should be matched with the type parameters declared in the class.
Asger Feldthaus7ad92c22016-05-09 12:12:40765///
Asger Feldthaus3ac36ac2016-10-04 11:30:46766/// For unnamed constructors, the name is an empty string (in a [Name]).
Asger Feldthaus02604e92016-04-26 08:39:15767class Constructor extends Member {
768 int flags = 0;
Asger Feldthaus02604e92016-04-26 08:39:15769 FunctionNode function;
770 List<Initializer> initializers;
771
772 Constructor(this.function,
Asger Feldthaus7ad92c22016-05-09 12:12:40773 {Name name,
Asger Feldthaus02604e92016-04-26 08:39:15774 bool isConst: false,
775 bool isExternal: false,
Asger Feldthaus760da8e2016-08-24 14:46:50776 List<Initializer> initializers,
777 int transformerFlags: 0})
Asger Feldthaus7ad92c22016-05-09 12:12:40778 : this.initializers = initializers ?? <Initializer>[],
779 super(name) {
Asger Feldthaus02604e92016-04-26 08:39:15780 function?.parent = this;
Asger Feldthaus246f6c12016-05-25 11:56:43781 setParents(this.initializers, this);
Asger Feldthaus02604e92016-04-26 08:39:15782 this.isConst = isConst;
783 this.isExternal = isExternal;
Asger Feldthaus760da8e2016-08-24 14:46:50784 this.transformerFlags = transformerFlags;
Asger Feldthaus02604e92016-04-26 08:39:15785 }
786
787 static const int FlagConst = 1 << 0; // Must match serialized bit positions.
788 static const int FlagExternal = 1 << 1;
789
790 bool get isConst => flags & FlagConst != 0;
791 bool get isExternal => flags & FlagExternal != 0;
792
793 void set isConst(bool value) {
Martin Kustermann1eb5f622016-07-08 07:22:36794 flags = value ? (flags | FlagConst) : (flags & ~FlagConst);
Asger Feldthaus02604e92016-04-26 08:39:15795 }
796
797 void set isExternal(bool value) {
Martin Kustermann1eb5f622016-07-08 07:22:36798 flags = value ? (flags | FlagExternal) : (flags & ~FlagExternal);
Asger Feldthaus02604e92016-04-26 08:39:15799 }
800
Asger Feldthaus246f6c12016-05-25 11:56:43801 bool get isInstanceMember => false;
Asger Feldthause3f2bae2016-09-13 10:40:11802 bool get hasGetter => false;
803 bool get hasSetter => false;
Asger Feldthaus246f6c12016-05-25 11:56:43804
Asger Feldthaus02604e92016-04-26 08:39:15805 accept(MemberVisitor v) => v.visitConstructor(this);
806
807 acceptReference(MemberReferenceVisitor v) =>
808 v.visitConstructorReference(this);
809
810 visitChildren(Visitor v) {
Asger Feldthausfd6064c2016-08-09 14:32:23811 visitList(annotations, v);
Asger Feldthaus02604e92016-04-26 08:39:15812 name?.accept(v);
813 function?.accept(v);
Asger Feldthaus246f6c12016-05-25 11:56:43814 visitList(initializers, v);
Asger Feldthaus02604e92016-04-26 08:39:15815 }
816
817 transformChildren(Transformer v) {
Asger Feldthausfd6064c2016-08-09 14:32:23818 transformList(annotations, v, this);
Asger Feldthaus02604e92016-04-26 08:39:15819 if (function != null) {
820 function = function.accept(v);
821 function?.parent = this;
822 }
Asger Feldthaus246f6c12016-05-25 11:56:43823 transformList(initializers, v, this);
Asger Feldthaus02604e92016-04-26 08:39:15824 }
Asger Feldthaus2eaa8842016-09-06 09:40:13825
826 DartType get getterType => const BottomType();
827 DartType get setterType => const BottomType();
Asger Feldthaus2efc48c2016-09-23 10:34:06828
829 _MemberAccessor get _getterInterface {
830 throw 'Constructors cannot be used as getters';
831 }
832
833 _MemberAccessor get _setterInterface {
834 throw 'Constructors cannot be used as setters';
835 }
Asger Feldthaus02604e92016-04-26 08:39:15836}
837
838/// A method, getter, setter, index-getter, index-setter, operator overloader,
839/// or factory.
840///
841/// Procedures can have the static, abstract, and/or external modifier, although
842/// only the static and external modifiers may be used together.
Asger Feldthaus7ad92c22016-05-09 12:12:40843///
Asger Feldthaus7ad92c22016-05-09 12:12:40844/// For non-static procedures the name is required for dynamic dispatch.
845/// For external procedures the name is required for identifying the external
846/// implementation.
847///
848/// For methods, getters, and setters the name is just as it was declared.
849/// For setters this does not include a trailing `=`.
850/// For index-getters/setters, this is `[]` and `[]=`.
851/// For operators, this is the token for the operator, e.g. `+` or `==`,
852/// except for the unary minus operator, whose name is `unary-`.
Asger Feldthaus02604e92016-04-26 08:39:15853class Procedure extends Member {
Asger Feldthaus2efc48c2016-09-23 10:34:06854 _MemberAccessor _reference;
Asger Feldthaus02604e92016-04-26 08:39:15855 ProcedureKind kind;
856 int flags = 0;
Asger Feldthaus133498e2016-04-27 14:44:25857 FunctionNode function; // Body is null if and only if abstract or external.
Asger Feldthaus02604e92016-04-26 08:39:15858
Jens Johansena85aabb2016-09-29 09:26:40859 /// The uri of the source file this procedure was loaded from.
860 String fileUri;
861
Asger Feldthaus7ad92c22016-05-09 12:12:40862 Procedure(Name name, this.kind, this.function,
Asger Feldthaus7f120342016-04-28 10:28:32863 {bool isAbstract: false,
864 bool isStatic: false,
865 bool isExternal: false,
Asger Feldthaus760da8e2016-08-24 14:46:50866 bool isConst: false,
Jens Johansena85aabb2016-09-29 09:26:40867 int transformerFlags: 0,
868 this.fileUri})
Asger Feldthaus7ad92c22016-05-09 12:12:40869 : super(name) {
Asger Feldthaus2efc48c2016-09-23 10:34:06870 _reference = new _MemberAccessor(this);
Asger Feldthaus02604e92016-04-26 08:39:15871 function?.parent = this;
872 this.isAbstract = isAbstract;
873 this.isStatic = isStatic;
874 this.isExternal = isExternal;
Asger Feldthaus7f120342016-04-28 10:28:32875 this.isConst = isConst;
Asger Feldthaus760da8e2016-08-24 14:46:50876 this.transformerFlags = transformerFlags;
Asger Feldthaus02604e92016-04-26 08:39:15877 }
Asger Feldthaus02604e92016-04-26 08:39:15878
879 static const int FlagStatic = 1 << 0; // Must match serialized bit positions.
880 static const int FlagAbstract = 1 << 1;
881 static const int FlagExternal = 1 << 2;
Asger Feldthaus7f120342016-04-28 10:28:32882 static const int FlagConst = 1 << 3; // Only for external const factories.
Asger Feldthaus02604e92016-04-26 08:39:15883
884 bool get isStatic => flags & FlagStatic != 0;
885 bool get isAbstract => flags & FlagAbstract != 0;
886 bool get isExternal => flags & FlagExternal != 0;
887
Asger Feldthaus7f120342016-04-28 10:28:32888 /// True if this has the `const` modifier. This is only possible for external
889 /// constant factories, such as `String.fromEnvironment`.
890 bool get isConst => flags & FlagConst != 0;
891
Asger Feldthaus02604e92016-04-26 08:39:15892 void set isStatic(bool value) {
Martin Kustermann1eb5f622016-07-08 07:22:36893 flags = value ? (flags | FlagStatic) : (flags & ~FlagStatic);
Asger Feldthaus02604e92016-04-26 08:39:15894 }
895
896 void set isAbstract(bool value) {
Martin Kustermann1eb5f622016-07-08 07:22:36897 flags = value ? (flags | FlagAbstract) : (flags & ~FlagAbstract);
Asger Feldthaus02604e92016-04-26 08:39:15898 }
899
900 void set isExternal(bool value) {
Martin Kustermann1eb5f622016-07-08 07:22:36901 flags = value ? (flags | FlagExternal) : (flags & ~FlagExternal);
Asger Feldthaus02604e92016-04-26 08:39:15902 }
903
Asger Feldthaus7f120342016-04-28 10:28:32904 void set isConst(bool value) {
Martin Kustermann1eb5f622016-07-08 07:22:36905 flags = value ? (flags | FlagConst) : (flags & ~FlagConst);
Asger Feldthaus7f120342016-04-28 10:28:32906 }
907
Asger Feldthaus246f6c12016-05-25 11:56:43908 bool get isInstanceMember => !isStatic;
909 bool get isGetter => kind == ProcedureKind.Getter;
910 bool get isSetter => kind == ProcedureKind.Setter;
911 bool get isAccessor => isGetter || isSetter;
Asger Feldthause3f2bae2016-09-13 10:40:11912 bool get hasGetter => kind != ProcedureKind.Setter;
913 bool get hasSetter => kind == ProcedureKind.Setter;
Asger Feldthaus246f6c12016-05-25 11:56:43914
Asger Feldthaus02604e92016-04-26 08:39:15915 accept(MemberVisitor v) => v.visitProcedure(this);
916
917 acceptReference(MemberReferenceVisitor v) => v.visitProcedureReference(this);
918
919 visitChildren(Visitor v) {
Asger Feldthausfd6064c2016-08-09 14:32:23920 visitList(annotations, v);
Asger Feldthaus02604e92016-04-26 08:39:15921 name?.accept(v);
922 function?.accept(v);
923 }
924
925 transformChildren(Transformer v) {
Asger Feldthausfd6064c2016-08-09 14:32:23926 transformList(annotations, v, this);
Asger Feldthaus02604e92016-04-26 08:39:15927 if (function != null) {
928 function = function.accept(v);
929 function?.parent = this;
930 }
931 }
Asger Feldthaus2eaa8842016-09-06 09:40:13932
933 DartType get getterType {
934 return isGetter ? function.returnType : function.functionType;
935 }
936
937 DartType get setterType {
938 return isSetter
939 ? function.positionalParameters[0].type
940 : const BottomType();
941 }
Asger Feldthaus2efc48c2016-09-23 10:34:06942
943 _MemberAccessor get _getterInterface => _reference;
944 _MemberAccessor get _setterInterface => _reference;
Asger Feldthaus02604e92016-04-26 08:39:15945}
946
Asger Feldthaus0defa952016-11-16 14:16:24947enum ProcedureKind {
948 Method,
949 Getter,
950 Setter,
951 Operator,
952 Factory,
953}
Asger Feldthaus02604e92016-04-26 08:39:15954
955// ------------------------------------------------------------------------
956// CONSTRUCTOR INITIALIZERS
957// ------------------------------------------------------------------------
958
959/// Part of an initializer list in a constructor.
960abstract class Initializer extends TreeNode {
961 accept(InitializerVisitor v);
962}
963
964/// An initializer with a compile-time error.
965///
966/// Should throw an exception at runtime.
967//
968// DESIGN TODO: The frontend should use this in a lot more cases to catch
969// invalid cases.
970class InvalidInitializer extends Initializer {
971 accept(InitializerVisitor v) => v.visitInvalidInitializer(this);
972
973 visitChildren(Visitor v) {}
974 transformChildren(Transformer v) {}
975}
976
Harry Terkelsen9509d282016-08-22 16:56:05977/// A field assignment `field = value` occurring in the initializer list of
Asger Feldthaus02604e92016-04-26 08:39:15978/// a constructor.
979///
980/// This node has nothing to do with declaration-site field initializers; those
981/// are [Expression]s stored in [Field.initializer].
982//
983// TODO: The frontend should check that all final fields are initialized
984// exactly once, and that no fields are assigned twice in the initializer list.
985class FieldInitializer extends Initializer {
986 /// Reference to the field being initialized. Not null.
987 Field field;
988 Expression value;
989
990 FieldInitializer(this.field, this.value) {
991 value?.parent = this;
992 }
993
994 accept(InitializerVisitor v) => v.visitFieldInitializer(this);
995
996 visitChildren(Visitor v) {
997 field?.acceptReference(v);
998 value?.accept(v);
999 }
1000
1001 transformChildren(Transformer v) {
1002 if (value != null) {
1003 value = value.accept(v);
1004 value?.parent = this;
1005 }
1006 }
1007}
1008
Harry Terkelsen9509d282016-08-22 16:56:051009/// A super call `super(x,y)` occurring in the initializer list of a
1010/// constructor.
Asger Feldthaus02604e92016-04-26 08:39:151011///
1012/// There are no type arguments on this call.
1013//
1014// TODO: The frontend should check that there is no more than one super call.
1015//
1016// DESIGN TODO: Consider if the frontend should insert type arguments derived
1017// from the extends clause.
1018class SuperInitializer extends Initializer {
1019 /// Reference to the constructor being invoked in the super class. Not null.
1020 Constructor target;
1021 Arguments arguments;
1022
1023 SuperInitializer(this.target, this.arguments) {
1024 arguments?.parent = this;
1025 }
1026
1027 accept(InitializerVisitor v) => v.visitSuperInitializer(this);
1028
1029 visitChildren(Visitor v) {
1030 target?.acceptReference(v);
1031 arguments?.accept(v);
1032 }
1033
1034 transformChildren(Transformer v) {
1035 if (arguments != null) {
1036 arguments = arguments.accept(v);
1037 arguments?.parent = this;
1038 }
1039 }
1040}
1041
Harry Terkelsen9509d282016-08-22 16:56:051042/// A redirecting call `this(x,y)` occurring in the initializer list of
Asger Feldthaus02604e92016-04-26 08:39:151043/// a constructor.
1044//
1045// TODO: The frontend should check that this is the only initializer and if the
1046// constructor has a body or if there is a cycle in the initializer calls.
1047class RedirectingInitializer extends Initializer {
1048 /// Reference to the constructor being invoked in the same class. Not null.
1049 Constructor target;
1050 Arguments arguments;
1051
1052 RedirectingInitializer(this.target, this.arguments) {
1053 arguments?.parent = this;
1054 }
1055
1056 accept(InitializerVisitor v) => v.visitRedirectingInitializer(this);
1057
1058 visitChildren(Visitor v) {
1059 target?.acceptReference(v);
1060 arguments?.accept(v);
1061 }
1062
1063 transformChildren(Transformer v) {
1064 if (arguments != null) {
1065 arguments = arguments.accept(v);
1066 arguments?.parent = this;
1067 }
1068 }
1069}
1070
Asger Feldthaused443ef2016-06-28 12:27:011071/// Binding of a temporary variable in the initializer list of a constructor.
1072///
1073/// The variable is in scope for the remainder of the initializer list, but is
1074/// not in scope in the constructor body.
1075class LocalInitializer extends Initializer {
1076 VariableDeclaration variable;
1077
1078 LocalInitializer(this.variable) {
1079 variable?.parent = this;
1080 }
1081
1082 accept(InitializerVisitor v) => v.visitLocalInitializer(this);
1083
1084 visitChildren(Visitor v) {
1085 variable?.accept(v);
1086 }
1087
1088 transformChildren(Transformer v) {
1089 if (variable != null) {
1090 variable = variable.accept(v);
1091 variable?.parent = this;
1092 }
1093 }
1094}
1095
Asger Feldthaus02604e92016-04-26 08:39:151096// ------------------------------------------------------------------------
1097// FUNCTIONS
1098// ------------------------------------------------------------------------
1099
1100/// A function declares parameters and has a body.
1101///
1102/// This may occur in a procedure, constructor, function expression, or local
1103/// function declaration.
1104class FunctionNode extends TreeNode {
1105 AsyncMarker asyncMarker;
1106 List<TypeParameter> typeParameters;
1107 int requiredParameterCount;
1108 List<VariableDeclaration> positionalParameters;
Asger Feldthaus0defa952016-11-16 14:16:241109 List<VariableDeclaration> namedParameters; // Must be sorted.
Martin Kustermann1392dcb2016-08-09 10:53:421110 InferredValue inferredReturnValue; // May be null.
Asger Feldthaus2eaa8842016-09-06 09:40:131111 DartType returnType; // Not null.
Asger Feldthaus02604e92016-04-26 08:39:151112 Statement body;
1113
1114 FunctionNode(this.body,
1115 {List<TypeParameter> typeParameters,
1116 List<VariableDeclaration> positionalParameters,
1117 List<VariableDeclaration> namedParameters,
1118 int requiredParameterCount,
Asger Feldthaus243ea892016-06-06 13:01:511119 this.returnType: const DynamicType(),
Martin Kustermann1392dcb2016-08-09 10:53:421120 this.inferredReturnValue,
Asger Feldthaus02604e92016-04-26 08:39:151121 this.asyncMarker: AsyncMarker.Sync})
1122 : this.positionalParameters =
1123 positionalParameters ?? <VariableDeclaration>[],
1124 this.requiredParameterCount =
1125 requiredParameterCount ?? positionalParameters?.length ?? 0,
1126 this.namedParameters = namedParameters ?? <VariableDeclaration>[],
1127 this.typeParameters = typeParameters ?? <TypeParameter>[] {
Asger Feldthaus243ea892016-06-06 13:01:511128 assert(returnType != null);
Asger Feldthaus246f6c12016-05-25 11:56:431129 setParents(this.typeParameters, this);
1130 setParents(this.positionalParameters, this);
1131 setParents(this.namedParameters, this);
Asger Feldthaus02604e92016-04-26 08:39:151132 body?.parent = this;
1133 }
1134
Asger Feldthaus2eaa8842016-09-06 09:40:131135 static DartType _getTypeOfVariable(VariableDeclaration node) => node.type;
1136
Asger Feldthaus0defa952016-11-16 14:16:241137 static NamedType _getNamedTypeOfVariable(VariableDeclaration node) {
1138 return new NamedType(node.name, node.type);
1139 }
1140
Asger Feldthaus2eaa8842016-09-06 09:40:131141 FunctionType get functionType {
1142 Map<String, DartType> named = const <String, DartType>{};
1143 if (namedParameters.isNotEmpty) {
1144 named = <String, DartType>{};
1145 for (var node in namedParameters) {
1146 named[node.name] = node.type;
1147 }
1148 }
1149 TreeNode parent = this.parent;
1150 return new FunctionType(
1151 positionalParameters.map(_getTypeOfVariable).toList(), returnType,
Asger Feldthaus0defa952016-11-16 14:16:241152 namedParameters: namedParameters.map(_getNamedTypeOfVariable).toList(),
Asger Feldthaus2eaa8842016-09-06 09:40:131153 typeParameters: parent is Constructor
1154 ? parent.enclosingClass.typeParameters
1155 : typeParameters,
1156 requiredParameterCount: requiredParameterCount);
1157 }
1158
Asger Feldthaus02604e92016-04-26 08:39:151159 accept(TreeVisitor v) => v.visitFunctionNode(this);
1160
1161 visitChildren(Visitor v) {
Asger Feldthaus246f6c12016-05-25 11:56:431162 visitList(typeParameters, v);
1163 visitList(positionalParameters, v);
1164 visitList(namedParameters, v);
Asger Feldthaus02604e92016-04-26 08:39:151165 returnType?.accept(v);
Martin Kustermann1392dcb2016-08-09 10:53:421166 inferredReturnValue?.accept(v);
Asger Feldthaus02604e92016-04-26 08:39:151167 body?.accept(v);
1168 }
1169
1170 transformChildren(Transformer v) {
Asger Feldthaus246f6c12016-05-25 11:56:431171 transformList(typeParameters, v, this);
1172 transformList(positionalParameters, v, this);
1173 transformList(namedParameters, v, this);
Asger Feldthaus760da8e2016-08-24 14:46:501174 returnType = v.visitDartType(returnType);
Asger Feldthaus02604e92016-04-26 08:39:151175 if (body != null) {
1176 body = body.accept(v);
1177 body?.parent = this;
1178 }
1179 }
1180}
1181
1182enum AsyncMarker {
1183 // Do not change the order of these, the frontends depend on it.
1184 Sync,
1185 SyncStar,
1186 Async,
Martin Kustermann4f5ae272016-07-08 11:09:291187 AsyncStar,
Vyacheslav Egorovffb724a2016-08-23 08:27:271188
1189 // `SyncYielding` is a marker that tells Dart VM that this function is an
1190 // artificial closure introduced by an async transformer which desugared all
1191 // async syntax into a combination of native yields and helper method calls.
1192 //
1193 // Native yields (formatted as `[yield]`) are semantically close to
1194 // `yield x` statement: they denote a yield/resume point within a function
1195 // but are completely decoupled from the notion of iterators. When
1196 // execution of the closure reaches `[yield] x` it stops and return the
1197 // value of `x` to the caller. If closure is called again it continues
1198 // to the next statement after this yield as if it was suspended and resumed.
1199 //
1200 // Consider this example:
1201 //
1202 // g() {
1203 // var :await_jump_var = 0;
1204 // var :await_ctx_var;
1205 //
1206 // f(x) yielding {
1207 // [yield] '${x}:0';
1208 // [yield] '${x}:1';
1209 // [yield] '${x}:2';
1210 // }
1211 //
1212 // return f;
1213 // }
1214 //
1215 // print(f('a')); /* prints 'a:0', :await_jump_var = 1 */
1216 // print(f('b')); /* prints 'b:1', :await_jump_var = 2 */
1217 // print(f('c')); /* prints 'c:2', :await_jump_var = 3 */
1218 //
1219 // Note: currently Dart VM implicitly relies on async transformer to
1220 // inject certain artificial variables into g (like `:await_jump_var`).
1221 // As such SyncYielding and native yield are not intended to be used on their
1222 // own, but are rather an implementation artifact of the async transformer
1223 // itself.
Martin Kustermann4f5ae272016-07-08 11:09:291224 SyncYielding,
Asger Feldthaus02604e92016-04-26 08:39:151225}
1226
1227// ------------------------------------------------------------------------
1228// EXPRESSIONS
1229// ------------------------------------------------------------------------
1230
1231abstract class Expression extends TreeNode {
Asger Feldthaus2eaa8842016-09-06 09:40:131232 /// Returns the static type of the expression.
1233 ///
1234 /// Should only be used on code compiled in strong mode, as this method
1235 /// assumes the IR is strongly typed.
1236 DartType getStaticType(TypeEnvironment types);
1237
1238 /// Returns the static type of the expression as an instantiation of
1239 /// [superclass].
1240 ///
1241 /// Should only be used on code compiled in strong mode, as this method
1242 /// assumes the IR is strongly typed.
1243 ///
1244 /// This method futhermore assumes that the type of the expression actually
1245 /// is a subtype of (some instantiation of) the given [superclass].
1246 /// If this is not the case, either an exception is thrown or the raw type of
1247 /// [superclass] is returned.
1248 InterfaceType getStaticTypeAsInstanceOf(
1249 Class superclass, TypeEnvironment types) {
1250 // This method assumes the program is correctly typed, so if the superclass
1251 // is not generic, we can just return its raw type without computing the
1252 // type of this expression. It also ensures that all types are considered
1253 // subtypes of Object (not just interface types), and function types are
1254 // considered subtypes of Function.
1255 if (superclass.typeParameters.isEmpty) {
1256 return superclass.rawType;
1257 }
1258 var type = getStaticType(types);
1259 while (type is TypeParameterType) {
Asger Feldthaus73463482016-11-14 09:23:371260 type = (type as TypeParameterType).parameter.bound;
Asger Feldthaus2eaa8842016-09-06 09:40:131261 }
1262 if (type is InterfaceType) {
1263 var upcastType = types.hierarchy.getTypeAsInstanceOf(type, superclass);
1264 if (upcastType != null) return upcastType;
1265 } else if (type is BottomType) {
1266 return superclass.bottomType;
1267 }
1268 types.typeError(this, '$type is not a subtype of $superclass');
1269 return superclass.rawType;
1270 }
1271
Asger Feldthaus02604e92016-04-26 08:39:151272 accept(ExpressionVisitor v);
1273}
1274
1275/// An expression containing compile-time errors.
1276///
1277/// Should throw a runtime error when evaluated.
1278class InvalidExpression extends Expression {
Asger Feldthaus2eaa8842016-09-06 09:40:131279 DartType getStaticType(TypeEnvironment types) => const BottomType();
1280
Asger Feldthaus02604e92016-04-26 08:39:151281 accept(ExpressionVisitor v) => v.visitInvalidExpression(this);
1282
1283 visitChildren(Visitor v) {}
1284 transformChildren(Transformer v) {}
1285}
1286
1287/// Read a local variable, a local function, or a function parameter.
1288class VariableGet extends Expression {
1289 VariableDeclaration variable;
Asger Feldthaus2eaa8842016-09-06 09:40:131290 DartType promotedType; // Null if not promoted.
Asger Feldthaus02604e92016-04-26 08:39:151291
Asger Feldthaus2eaa8842016-09-06 09:40:131292 VariableGet(this.variable, [this.promotedType]);
1293
1294 DartType getStaticType(TypeEnvironment types) {
1295 return promotedType ?? variable.type;
1296 }
Asger Feldthaus02604e92016-04-26 08:39:151297
1298 accept(ExpressionVisitor v) => v.visitVariableGet(this);
1299
Asger Feldthaus2eaa8842016-09-06 09:40:131300 visitChildren(Visitor v) {
1301 promotedType?.accept(v);
1302 }
1303
Asger Feldthausf9851b32016-10-04 15:28:451304 transformChildren(Transformer v) {
1305 if (promotedType != null) {
1306 promotedType = v.visitDartType(promotedType);
1307 }
1308 }
Asger Feldthaus02604e92016-04-26 08:39:151309}
1310
1311/// Assign a local variable or function parameter.
1312class VariableSet extends Expression {
1313 VariableDeclaration variable;
1314 Expression value;
1315
1316 VariableSet(this.variable, this.value) {
1317 value?.parent = this;
1318 }
1319
Asger Feldthaus2eaa8842016-09-06 09:40:131320 DartType getStaticType(TypeEnvironment types) => value.getStaticType(types);
1321
Asger Feldthaus02604e92016-04-26 08:39:151322 accept(ExpressionVisitor v) => v.visitVariableSet(this);
1323
1324 visitChildren(Visitor v) {
1325 value?.accept(v);
1326 }
1327
1328 transformChildren(Transformer v) {
1329 if (value != null) {
1330 value = value.accept(v);
1331 value?.parent = this;
1332 }
1333 }
1334}
1335
1336/// Expression of form `x.field`.
1337///
1338/// This may invoke a getter, read a field, or tear off a method.
1339class PropertyGet extends Expression {
1340 Expression receiver;
1341 Name name;
1342
Asger Feldthaus2efc48c2016-09-23 10:34:061343 _MemberAccessor _interfaceTargetReference;
Asger Feldthaus2eaa8842016-09-06 09:40:131344
Asger Feldthaus2efc48c2016-09-23 10:34:061345 PropertyGet(this.receiver, this.name, [Member interfaceTarget]) {
Asger Feldthaus02604e92016-04-26 08:39:151346 receiver?.parent = this;
Asger Feldthaus2efc48c2016-09-23 10:34:061347 this.interfaceTarget = interfaceTarget;
1348 }
1349
1350 Member get interfaceTarget => _interfaceTargetReference?.target;
1351
1352 void set interfaceTarget(Member newTarget) {
1353 _interfaceTargetReference = newTarget?._getterInterface;
Asger Feldthaus02604e92016-04-26 08:39:151354 }
1355
Asger Feldthaus2eaa8842016-09-06 09:40:131356 DartType getStaticType(TypeEnvironment types) {
Asger Feldthaus2efc48c2016-09-23 10:34:061357 var interfaceTarget = this.interfaceTarget;
Asger Feldthaus2eaa8842016-09-06 09:40:131358 if (interfaceTarget != null) {
1359 Class superclass = interfaceTarget.enclosingClass;
1360 var receiverType = receiver.getStaticTypeAsInstanceOf(superclass, types);
Asger Feldthause1c26f82016-10-24 14:21:521361 return Substitution
1362 .fromInterfaceType(receiverType)
1363 .substituteType(interfaceTarget.getterType);
Asger Feldthaus2eaa8842016-09-06 09:40:131364 }
1365 // Treat the properties of Object specially.
1366 String nameString = name.name;
1367 if (nameString == 'hashCode') {
1368 return types.intType;
1369 } else if (nameString == 'runtimeType') {
1370 return types.typeType;
1371 }
1372 return const DynamicType();
1373 }
1374
Asger Feldthaus02604e92016-04-26 08:39:151375 accept(ExpressionVisitor v) => v.visitPropertyGet(this);
1376
1377 visitChildren(Visitor v) {
1378 receiver?.accept(v);
1379 name?.accept(v);
1380 }
1381
1382 transformChildren(Transformer v) {
1383 if (receiver != null) {
1384 receiver = receiver.accept(v);
1385 receiver?.parent = this;
1386 }
1387 }
1388}
1389
1390/// Expression of form `x.field = value`.
1391///
1392/// This may invoke a setter or assign a field.
1393class PropertySet extends Expression {
1394 Expression receiver;
1395 Name name;
1396 Expression value;
1397
Asger Feldthaus2efc48c2016-09-23 10:34:061398 _MemberAccessor _interfaceTargetReference;
Asger Feldthaus2eaa8842016-09-06 09:40:131399
Asger Feldthaus2efc48c2016-09-23 10:34:061400 PropertySet(this.receiver, this.name, this.value, [Member interfaceTarget]) {
Asger Feldthaus02604e92016-04-26 08:39:151401 receiver?.parent = this;
1402 value?.parent = this;
Asger Feldthaus2efc48c2016-09-23 10:34:061403 this.interfaceTarget = interfaceTarget;
1404 }
1405
1406 Member get interfaceTarget => _interfaceTargetReference?.target;
1407
1408 void set interfaceTarget(Member newTarget) {
1409 _interfaceTargetReference = newTarget?._setterInterface;
Asger Feldthaus02604e92016-04-26 08:39:151410 }
1411
Asger Feldthaus2eaa8842016-09-06 09:40:131412 DartType getStaticType(TypeEnvironment types) => value.getStaticType(types);
1413
Asger Feldthaus02604e92016-04-26 08:39:151414 accept(ExpressionVisitor v) => v.visitPropertySet(this);
1415
1416 visitChildren(Visitor v) {
1417 receiver?.accept(v);
1418 name?.accept(v);
1419 value?.accept(v);
1420 }
1421
1422 transformChildren(Transformer v) {
1423 if (receiver != null) {
1424 receiver = receiver.accept(v);
1425 receiver?.parent = this;
1426 }
1427 if (value != null) {
1428 value = value.accept(v);
1429 value?.parent = this;
1430 }
1431 }
1432}
1433
Asger Feldthaus760da8e2016-08-24 14:46:501434/// Directly read a field, call a getter, or tear off a method.
1435class DirectPropertyGet extends Expression {
1436 Expression receiver;
1437 Member target;
1438
1439 DirectPropertyGet(this.receiver, this.target) {
1440 receiver?.parent = this;
1441 }
1442
1443 visitChildren(Visitor v) {
1444 receiver?.accept(v);
1445 target?.acceptReference(v);
1446 }
1447
1448 transformChildren(Transformer v) {
1449 if (receiver != null) {
1450 receiver = receiver.accept(v);
1451 receiver?.parent = this;
1452 }
1453 }
1454
1455 accept(ExpressionVisitor v) => v.visitDirectPropertyGet(this);
Asger Feldthaus2eaa8842016-09-06 09:40:131456
1457 DartType getStaticType(TypeEnvironment types) {
1458 Class superclass = target.enclosingClass;
1459 var receiverType = receiver.getStaticTypeAsInstanceOf(superclass, types);
Asger Feldthause1c26f82016-10-24 14:21:521460 return Substitution
1461 .fromInterfaceType(receiverType)
1462 .substituteType(target.getterType);
Asger Feldthaus2eaa8842016-09-06 09:40:131463 }
Asger Feldthaus760da8e2016-08-24 14:46:501464}
1465
1466/// Directly assign a field, or call a setter.
1467class DirectPropertySet extends Expression {
1468 Expression receiver;
1469 Member target;
1470 Expression value;
1471
1472 DirectPropertySet(this.receiver, this.target, this.value) {
1473 receiver?.parent = this;
1474 value?.parent = this;
1475 }
1476
1477 visitChildren(Visitor v) {
1478 receiver?.accept(v);
1479 target?.acceptReference(v);
1480 value?.accept(v);
1481 }
1482
1483 transformChildren(Transformer v) {
1484 if (receiver != null) {
1485 receiver = receiver.accept(v);
1486 receiver?.parent = this;
1487 }
1488 if (value != null) {
1489 value = value.accept(v);
1490 value?.parent = this;
1491 }
1492 }
1493
1494 accept(ExpressionVisitor v) => v.visitDirectPropertySet(this);
Asger Feldthaus2eaa8842016-09-06 09:40:131495
1496 DartType getStaticType(TypeEnvironment types) => value.getStaticType(types);
Asger Feldthaus760da8e2016-08-24 14:46:501497}
1498
1499/// Directly call an instance method, bypassing ordinary dispatch.
1500class DirectMethodInvocation extends Expression {
1501 Expression receiver;
1502 Procedure target;
1503 Arguments arguments;
1504
1505 DirectMethodInvocation(this.receiver, this.target, this.arguments) {
1506 receiver?.parent = this;
1507 arguments?.parent = this;
1508 }
1509
1510 visitChildren(Visitor v) {
1511 receiver?.accept(v);
1512 target?.acceptReference(v);
1513 arguments?.accept(v);
1514 }
1515
1516 transformChildren(Transformer v) {
1517 if (receiver != null) {
1518 receiver = receiver.accept(v);
1519 receiver?.parent = this;
1520 }
1521 if (arguments != null) {
1522 arguments = arguments.accept(v);
1523 arguments?.parent = this;
1524 }
1525 }
1526
1527 accept(ExpressionVisitor v) => v.visitDirectMethodInvocation(this);
Asger Feldthaus2eaa8842016-09-06 09:40:131528
1529 DartType getStaticType(TypeEnvironment types) {
1530 if (types.isOverloadedArithmeticOperator(target)) {
1531 return types.getTypeOfOverloadedArithmetic(receiver.getStaticType(types),
1532 arguments.positional[0].getStaticType(types));
1533 }
1534 Class superclass = target.enclosingClass;
1535 var receiverType = receiver.getStaticTypeAsInstanceOf(superclass, types);
Asger Feldthause1c26f82016-10-24 14:21:521536 var returnType = Substitution
1537 .fromInterfaceType(receiverType)
1538 .substituteType(target.function.returnType);
1539 return Substitution
1540 .fromPairs(target.function.typeParameters, arguments.types)
1541 .substituteType(returnType);
Asger Feldthaus2eaa8842016-09-06 09:40:131542 }
Asger Feldthaus760da8e2016-08-24 14:46:501543}
1544
Asger Feldthaus02604e92016-04-26 08:39:151545/// Expression of form `super.field`.
1546///
1547/// This may invoke a getter, read a field, or tear off a method.
1548class SuperPropertyGet extends Expression {
Asger Feldthaus760da8e2016-08-24 14:46:501549 Name name;
Asger Feldthaus2efc48c2016-09-23 10:34:061550 _MemberAccessor _interfaceTargetReference;
Asger Feldthaus02604e92016-04-26 08:39:151551
Asger Feldthaus2efc48c2016-09-23 10:34:061552 SuperPropertyGet(this.name, [Member interfaceTarget]) {
1553 _interfaceTargetReference = interfaceTarget?._getterInterface;
1554 }
1555
1556 Member get interfaceTarget => _interfaceTargetReference?.target;
1557
1558 void set interfaceTarget(Member newTarget) {
1559 _interfaceTargetReference = newTarget?._getterInterface;
1560 }
Asger Feldthaus2eaa8842016-09-06 09:40:131561
1562 DartType getStaticType(TypeEnvironment types) {
1563 Class declaringClass = interfaceTarget.enclosingClass;
1564 if (declaringClass.typeParameters.isEmpty) {
1565 return interfaceTarget.getterType;
1566 }
1567 var receiver =
1568 types.hierarchy.getTypeAsInstanceOf(types.thisType, declaringClass);
Asger Feldthause1c26f82016-10-24 14:21:521569 return Substitution
1570 .fromInterfaceType(receiver)
1571 .substituteType(interfaceTarget.getterType);
Asger Feldthaus2eaa8842016-09-06 09:40:131572 }
Asger Feldthaus02604e92016-04-26 08:39:151573
1574 accept(ExpressionVisitor v) => v.visitSuperPropertyGet(this);
1575
Peter von der Ahé184dda52016-09-05 14:25:341576 visitChildren(Visitor v) {
1577 name?.accept(v);
1578 }
Asger Feldthaus02604e92016-04-26 08:39:151579
1580 transformChildren(Transformer v) {}
1581}
1582
1583/// Expression of form `super.field = value`.
1584///
1585/// This may invoke a setter or assign a field.
1586class SuperPropertySet extends Expression {
Asger Feldthaus760da8e2016-08-24 14:46:501587 Name name;
Asger Feldthaus02604e92016-04-26 08:39:151588 Expression value;
Asger Feldthaus2efc48c2016-09-23 10:34:061589 _MemberAccessor _interfaceTargetReference;
Asger Feldthaus02604e92016-04-26 08:39:151590
Asger Feldthaus2efc48c2016-09-23 10:34:061591 SuperPropertySet(this.name, this.value, [Member interfaceTarget]) {
Asger Feldthaus02604e92016-04-26 08:39:151592 value?.parent = this;
Asger Feldthaus2efc48c2016-09-23 10:34:061593 _interfaceTargetReference = interfaceTarget?._setterInterface;
1594 }
1595
1596 Member get interfaceTarget => _interfaceTargetReference?.target;
1597
1598 void set interfaceTarget(Member newTarget) {
1599 _interfaceTargetReference = newTarget?._setterInterface;
Asger Feldthaus02604e92016-04-26 08:39:151600 }
1601
Asger Feldthaus2eaa8842016-09-06 09:40:131602 DartType getStaticType(TypeEnvironment types) => value.getStaticType(types);
1603
Asger Feldthaus02604e92016-04-26 08:39:151604 accept(ExpressionVisitor v) => v.visitSuperPropertySet(this);
1605
1606 visitChildren(Visitor v) {
Peter von der Ahé184dda52016-09-05 14:25:341607 name?.accept(v);
Asger Feldthaus02604e92016-04-26 08:39:151608 value?.accept(v);
1609 }
1610
1611 transformChildren(Transformer v) {
1612 if (value != null) {
1613 value = value.accept(v);
1614 value?.parent = this;
1615 }
1616 }
1617}
1618
1619/// Read a static field, call a static getter, or tear off a static method.
1620class StaticGet extends Expression {
1621 /// A static field, getter, or method (for tear-off).
1622 Member target;
1623
1624 StaticGet(this.target);
1625
Asger Feldthaus2eaa8842016-09-06 09:40:131626 DartType getStaticType(TypeEnvironment types) => target.getterType;
1627
Asger Feldthaus02604e92016-04-26 08:39:151628 accept(ExpressionVisitor v) => v.visitStaticGet(this);
1629
1630 visitChildren(Visitor v) {
1631 target?.acceptReference(v);
1632 }
1633
1634 transformChildren(Transformer v) {}
1635}
1636
1637/// Assign a static field or call a static setter.
1638class StaticSet extends Expression {
1639 /// A mutable static field or a static setter.
1640 Member target;
1641 Expression value;
1642
1643 StaticSet(this.target, this.value) {
1644 value?.parent = this;
1645 }
1646
Asger Feldthaus2eaa8842016-09-06 09:40:131647 DartType getStaticType(TypeEnvironment types) => value.getStaticType(types);
1648
Asger Feldthaus02604e92016-04-26 08:39:151649 accept(ExpressionVisitor v) => v.visitStaticSet(this);
1650
1651 visitChildren(Visitor v) {
1652 target?.acceptReference(v);
1653 value?.accept(v);
1654 }
1655
1656 transformChildren(Transformer v) {
1657 if (value != null) {
1658 value = value.accept(v);
1659 value?.parent = this;
1660 }
1661 }
1662}
1663
1664/// The arguments to a function call, divided into type arguments,
1665/// positional arguments, and named arguments.
1666class Arguments extends TreeNode {
1667 final List<DartType> types;
1668 final List<Expression> positional;
1669 final List<NamedExpression> named;
1670
1671 Arguments(this.positional,
1672 {List<DartType> types, List<NamedExpression> named})
1673 : this.types = types ?? <DartType>[],
1674 this.named = named ?? <NamedExpression>[] {
Asger Feldthaus246f6c12016-05-25 11:56:431675 setParents(this.positional, this);
1676 setParents(this.named, this);
Asger Feldthaus02604e92016-04-26 08:39:151677 }
1678
1679 Arguments.empty()
1680 : types = <DartType>[],
1681 positional = <Expression>[],
1682 named = <NamedExpression>[];
1683
1684 accept(TreeVisitor v) => v.visitArguments(this);
1685
1686 visitChildren(Visitor v) {
Asger Feldthaus246f6c12016-05-25 11:56:431687 visitList(types, v);
1688 visitList(positional, v);
1689 visitList(named, v);
Asger Feldthaus02604e92016-04-26 08:39:151690 }
1691
1692 transformChildren(Transformer v) {
Asger Feldthaus760da8e2016-08-24 14:46:501693 transformTypeList(types, v);
Asger Feldthaus246f6c12016-05-25 11:56:431694 transformList(positional, v, this);
1695 transformList(named, v, this);
Asger Feldthaus02604e92016-04-26 08:39:151696 }
1697}
1698
1699/// A named argument, `name: value`.
1700class NamedExpression extends TreeNode {
1701 String name;
1702 Expression value;
1703
1704 NamedExpression(this.name, this.value) {
1705 value?.parent = this;
1706 }
1707
1708 accept(TreeVisitor v) => v.visitNamedExpression(this);
1709
1710 visitChildren(Visitor v) {
1711 value?.accept(v);
1712 }
1713
1714 transformChildren(Transformer v) {
1715 if (value != null) {
1716 value = value.accept(v);
1717 value?.parent = this;
1718 }
1719 }
1720}
1721
1722/// Common super class for [MethodInvocation], [SuperMethodInvocation],
1723/// [StaticInvocation], and [ConstructorInvocation].
1724abstract class InvocationExpression extends Expression {
1725 Arguments get arguments;
1726 set arguments(Arguments value);
1727
Asger Feldthaus02604e92016-04-26 08:39:151728 /// Name of the invoked method.
1729 ///
Asger Feldthaus7f120342016-04-28 10:28:321730 /// May be `null` if the target is a synthetic static member without a name.
Asger Feldthaus02604e92016-04-26 08:39:151731 Name get name;
1732}
1733
1734/// Expression of form `x.foo(y)`.
1735class MethodInvocation extends InvocationExpression {
1736 Expression receiver;
1737 Name name;
1738 Arguments arguments;
1739
Asger Feldthaus2eaa8842016-09-06 09:40:131740 Procedure interfaceTarget;
1741
1742 MethodInvocation(this.receiver, this.name, this.arguments,
1743 [this.interfaceTarget]) {
Asger Feldthaus02604e92016-04-26 08:39:151744 receiver?.parent = this;
1745 arguments?.parent = this;
1746 }
1747
Asger Feldthaus2eaa8842016-09-06 09:40:131748 DartType getStaticType(TypeEnvironment types) {
1749 if (interfaceTarget != null) {
1750 if (types.isOverloadedArithmeticOperator(interfaceTarget)) {
1751 return types.getTypeOfOverloadedArithmetic(
1752 receiver.getStaticType(types),
1753 arguments.positional[0].getStaticType(types));
1754 }
1755 Class superclass = interfaceTarget.enclosingClass;
1756 var receiverType = receiver.getStaticTypeAsInstanceOf(superclass, types);
Asger Feldthause1c26f82016-10-24 14:21:521757 var returnType = Substitution
1758 .fromInterfaceType(receiverType)
1759 .substituteType(interfaceTarget.function.returnType);
1760 return Substitution
1761 .fromPairs(interfaceTarget.function.typeParameters, arguments.types)
1762 .substituteType(returnType);
Asger Feldthaus2eaa8842016-09-06 09:40:131763 }
1764 if (name.name == 'call') {
1765 var receiverType = receiver.getStaticType(types);
1766 if (receiverType is FunctionType) {
1767 if (receiverType.typeParameters.length != arguments.types.length) {
1768 return const BottomType();
1769 }
Asger Feldthause1c26f82016-10-24 14:21:521770 return Substitution
1771 .fromPairs(receiverType.typeParameters, arguments.types)
1772 .substituteType(receiverType.returnType);
Asger Feldthaus2eaa8842016-09-06 09:40:131773 }
1774 }
1775 if (name.name == '==') {
1776 // We use this special case to simplify generation of '==' checks.
1777 return types.boolType;
1778 }
1779 return const DynamicType();
1780 }
Asger Feldthaus02604e92016-04-26 08:39:151781
1782 accept(ExpressionVisitor v) => v.visitMethodInvocation(this);
1783
1784 visitChildren(Visitor v) {
1785 receiver?.accept(v);
1786 name?.accept(v);
1787 arguments?.accept(v);
1788 }
1789
1790 transformChildren(Transformer v) {
1791 if (receiver != null) {
1792 receiver = receiver.accept(v);
1793 receiver?.parent = this;
1794 }
1795 if (arguments != null) {
1796 arguments = arguments.accept(v);
1797 arguments?.parent = this;
1798 }
1799 }
1800}
1801
1802/// Expression of form `super.foo(x)`.
1803///
1804/// The provided arguments might not match the parameters of the target.
1805class SuperMethodInvocation extends InvocationExpression {
Asger Feldthaus760da8e2016-08-24 14:46:501806 Name name;
Asger Feldthaus02604e92016-04-26 08:39:151807 Arguments arguments;
1808
Asger Feldthaus2eaa8842016-09-06 09:40:131809 Member interfaceTarget;
1810
1811 SuperMethodInvocation(this.name, this.arguments, this.interfaceTarget) {
Asger Feldthaus02604e92016-04-26 08:39:151812 arguments?.parent = this;
1813 }
1814
Asger Feldthaus2eaa8842016-09-06 09:40:131815 DartType getStaticType(TypeEnvironment types) {
1816 if (interfaceTarget == null) return const DynamicType();
1817 Class superclass = interfaceTarget.enclosingClass;
1818 var receiverType =
1819 types.hierarchy.getTypeAsInstanceOf(types.thisType, superclass);
Asger Feldthause1c26f82016-10-24 14:21:521820 var returnType = Substitution
1821 .fromInterfaceType(receiverType)
1822 .substituteType(interfaceTarget.function.returnType);
1823 return Substitution
1824 .fromPairs(interfaceTarget.function.typeParameters, arguments.types)
1825 .substituteType(returnType);
Asger Feldthaus2eaa8842016-09-06 09:40:131826 }
Asger Feldthaus760da8e2016-08-24 14:46:501827
Asger Feldthaus02604e92016-04-26 08:39:151828 accept(ExpressionVisitor v) => v.visitSuperMethodInvocation(this);
1829
1830 visitChildren(Visitor v) {
Peter von der Ahé184dda52016-09-05 14:25:341831 name?.accept(v);
Asger Feldthaus02604e92016-04-26 08:39:151832 arguments?.accept(v);
1833 }
1834
1835 transformChildren(Transformer v) {
1836 if (arguments != null) {
1837 arguments = arguments.accept(v);
1838 arguments?.parent = this;
1839 }
1840 }
1841}
1842
Asger Feldthausbe5b7d32016-04-28 10:58:421843/// Expression of form `foo(x)`, or `const foo(x)` if the target is an
1844/// external constant factory.
Asger Feldthaus02604e92016-04-26 08:39:151845///
1846/// The provided arguments might not match the parameters of the target.
1847class StaticInvocation extends InvocationExpression {
Asger Feldthaus7f120342016-04-28 10:28:321848 Procedure target;
Asger Feldthaus02604e92016-04-26 08:39:151849 Arguments arguments;
1850
Asger Feldthausbe5b7d32016-04-28 10:58:421851 /// True if this is a constant call to an external constant factory.
1852 bool isConst;
1853
Asger Feldthaus02604e92016-04-26 08:39:151854 Name get name => target?.name;
1855
Asger Feldthausbe5b7d32016-04-28 10:58:421856 StaticInvocation(this.target, this.arguments, {this.isConst: false}) {
Asger Feldthaus02604e92016-04-26 08:39:151857 arguments?.parent = this;
1858 }
1859
Asger Feldthaus2eaa8842016-09-06 09:40:131860 DartType getStaticType(TypeEnvironment types) {
Asger Feldthause1c26f82016-10-24 14:21:521861 return Substitution
1862 .fromPairs(target.function.typeParameters, arguments.types)
1863 .substituteType(target.function.returnType);
Asger Feldthaus2eaa8842016-09-06 09:40:131864 }
1865
Asger Feldthaus02604e92016-04-26 08:39:151866 accept(ExpressionVisitor v) => v.visitStaticInvocation(this);
1867
1868 visitChildren(Visitor v) {
1869 target?.acceptReference(v);
1870 arguments?.accept(v);
1871 }
1872
1873 transformChildren(Transformer v) {
1874 if (arguments != null) {
1875 arguments = arguments.accept(v);
1876 arguments?.parent = this;
1877 }
1878 }
1879}
1880
1881/// Expression of form `new Foo(x)` or `const Foo(x)`.
1882///
1883/// The provided arguments might not match the parameters of the target.
1884//
1885// DESIGN TODO: Should we pass type arguments in a separate field
1886// `classTypeArguments`? They are quite different from type arguments to
1887// generic functions.
Peter von der Ahée56467e2016-06-28 11:11:251888class ConstructorInvocation extends InvocationExpression {
Asger Feldthaus02604e92016-04-26 08:39:151889 Constructor target;
1890 Arguments arguments;
1891 bool isConst;
1892
Peter von der Ahée56467e2016-06-28 11:11:251893 Name get name => target?.name;
1894
Asger Feldthaus02604e92016-04-26 08:39:151895 ConstructorInvocation(this.target, this.arguments, {this.isConst: false}) {
1896 arguments?.parent = this;
1897 }
1898
Asger Feldthaus2eaa8842016-09-06 09:40:131899 DartType getStaticType(TypeEnvironment types) {
1900 return arguments.types.isEmpty
1901 ? target.enclosingClass.rawType
1902 : new InterfaceType(target.enclosingClass, arguments.types);
1903 }
1904
Asger Feldthaus02604e92016-04-26 08:39:151905 accept(ExpressionVisitor v) => v.visitConstructorInvocation(this);
1906
1907 visitChildren(Visitor v) {
1908 target?.acceptReference(v);
1909 arguments?.accept(v);
1910 }
1911
1912 transformChildren(Transformer v) {
1913 if (arguments != null) {
1914 arguments = arguments.accept(v);
1915 arguments?.parent = this;
1916 }
1917 }
Asger Feldthaus246f6c12016-05-25 11:56:431918
1919 InterfaceType get constructedType {
1920 return arguments.types.isEmpty
1921 ? target.enclosingClass.rawType
1922 : new InterfaceType(target.enclosingClass, arguments.types);
1923 }
Asger Feldthaus02604e92016-04-26 08:39:151924}
1925
1926/// Expression of form `!x`.
1927///
1928/// The `is!` and `!=` operators are desugared into [Not] nodes with `is` and
1929/// `==` expressions inside, respectively.
1930class Not extends Expression {
1931 Expression operand;
1932
1933 Not(this.operand) {
1934 operand?.parent = this;
1935 }
1936
Asger Feldthaus2eaa8842016-09-06 09:40:131937 DartType getStaticType(TypeEnvironment types) => types.boolType;
1938
Asger Feldthaus02604e92016-04-26 08:39:151939 accept(ExpressionVisitor v) => v.visitNot(this);
1940
1941 visitChildren(Visitor v) {
1942 operand?.accept(v);
1943 }
1944
1945 transformChildren(Transformer v) {
1946 if (operand != null) {
1947 operand = operand.accept(v);
1948 operand?.parent = this;
1949 }
1950 }
1951}
1952
Asger Feldthausd9b00562016-09-23 10:52:001953/// Expression of form `x && y` or `x || y`
Asger Feldthaus02604e92016-04-26 08:39:151954class LogicalExpression extends Expression {
1955 Expression left;
1956 String operator; // && or || or ??
1957 Expression right;
1958
Asger Feldthausd9b00562016-09-23 10:52:001959 LogicalExpression(this.left, this.operator, this.right) {
Asger Feldthaus02604e92016-04-26 08:39:151960 left?.parent = this;
1961 right?.parent = this;
1962 }
1963
Asger Feldthausd9b00562016-09-23 10:52:001964 DartType getStaticType(TypeEnvironment types) => types.boolType;
Asger Feldthaus2eaa8842016-09-06 09:40:131965
Asger Feldthaus02604e92016-04-26 08:39:151966 accept(ExpressionVisitor v) => v.visitLogicalExpression(this);
1967
1968 visitChildren(Visitor v) {
1969 left?.accept(v);
1970 right?.accept(v);
1971 }
1972
1973 transformChildren(Transformer v) {
1974 if (left != null) {
1975 left = left.accept(v);
1976 left?.parent = this;
1977 }
1978 if (right != null) {
1979 right = right.accept(v);
1980 right?.parent = this;
1981 }
1982 }
1983}
1984
1985/// Expression of form `x ? y : z`.
1986class ConditionalExpression extends Expression {
1987 Expression condition;
1988 Expression then;
1989 Expression otherwise;
1990
Asger Feldthausc227e782016-11-01 15:04:101991 /// The static type of the expression. Should not be `null`.
Asger Feldthaus2eaa8842016-09-06 09:40:131992 DartType staticType;
1993
Asger Feldthaus0defa952016-11-16 14:16:241994 ConditionalExpression(
1995 this.condition, this.then, this.otherwise, this.staticType) {
Asger Feldthaus02604e92016-04-26 08:39:151996 condition?.parent = this;
1997 then?.parent = this;
1998 otherwise?.parent = this;
1999 }
2000
Asger Feldthausc227e782016-11-01 15:04:102001 DartType getStaticType(TypeEnvironment types) => staticType;
Asger Feldthaus2eaa8842016-09-06 09:40:132002
Asger Feldthaus02604e92016-04-26 08:39:152003 accept(ExpressionVisitor v) => v.visitConditionalExpression(this);
2004
2005 visitChildren(Visitor v) {
2006 condition?.accept(v);
2007 then?.accept(v);
2008 otherwise?.accept(v);
Asger Feldthausf9851b32016-10-04 15:28:452009 staticType?.accept(v);
Asger Feldthaus02604e92016-04-26 08:39:152010 }
2011
2012 transformChildren(Transformer v) {
2013 if (condition != null) {
2014 condition = condition.accept(v);
2015 condition?.parent = this;
2016 }
2017 if (then != null) {
2018 then = then.accept(v);
2019 then?.parent = this;
2020 }
2021 if (otherwise != null) {
2022 otherwise = otherwise.accept(v);
2023 otherwise?.parent = this;
2024 }
Asger Feldthausf9851b32016-10-04 15:28:452025 if (staticType != null) {
2026 staticType = v.visitDartType(staticType);
2027 }
Asger Feldthaus02604e92016-04-26 08:39:152028 }
2029}
2030
2031/// Convert expressions to strings and concatenate them. Semantically, calls
2032/// `toString` on every argument, checks that a string is returned, and returns
2033/// the concatenation of all the strings.
2034///
2035/// If [expressions] is empty then an empty string is returned.
2036///
2037/// These arise from string interpolations and adjacent string literals.
2038class StringConcatenation extends Expression {
2039 final List<Expression> expressions;
2040
2041 StringConcatenation(this.expressions) {
Asger Feldthaus246f6c12016-05-25 11:56:432042 setParents(expressions, this);
Asger Feldthaus02604e92016-04-26 08:39:152043 }
2044
Asger Feldthaus2eaa8842016-09-06 09:40:132045 DartType getStaticType(TypeEnvironment types) => types.stringType;
2046
Asger Feldthaus02604e92016-04-26 08:39:152047 accept(ExpressionVisitor v) => v.visitStringConcatenation(this);
2048
2049 visitChildren(Visitor v) {
Asger Feldthaus246f6c12016-05-25 11:56:432050 visitList(expressions, v);
Asger Feldthaus02604e92016-04-26 08:39:152051 }
2052
2053 transformChildren(Transformer v) {
Asger Feldthaus246f6c12016-05-25 11:56:432054 transformList(expressions, v, this);
Asger Feldthaus02604e92016-04-26 08:39:152055 }
2056}
2057
2058/// Expression of form `x is T`.
2059class IsExpression extends Expression {
2060 Expression operand;
2061 DartType type;
2062
2063 IsExpression(this.operand, this.type) {
2064 operand?.parent = this;
2065 }
2066
Asger Feldthaus2eaa8842016-09-06 09:40:132067 DartType getStaticType(TypeEnvironment types) => types.boolType;
2068
Asger Feldthaus02604e92016-04-26 08:39:152069 accept(ExpressionVisitor v) => v.visitIsExpression(this);
2070
2071 visitChildren(Visitor v) {
2072 operand?.accept(v);
2073 type?.accept(v);
2074 }
2075
2076 transformChildren(Transformer v) {
2077 if (operand != null) {
2078 operand = operand.accept(v);
2079 operand?.parent = this;
2080 }
Asger Feldthaus2eaa8842016-09-06 09:40:132081 type = v.visitDartType(type);
Asger Feldthaus02604e92016-04-26 08:39:152082 }
2083}
2084
2085/// Expression of form `x as T`.
2086class AsExpression extends Expression {
2087 Expression operand;
2088 DartType type;
2089
2090 AsExpression(this.operand, this.type) {
2091 operand?.parent = this;
2092 }
2093
Asger Feldthaus2eaa8842016-09-06 09:40:132094 DartType getStaticType(TypeEnvironment types) => type;
2095
Asger Feldthaus02604e92016-04-26 08:39:152096 accept(ExpressionVisitor v) => v.visitAsExpression(this);
2097
2098 visitChildren(Visitor v) {
2099 operand?.accept(v);
2100 type?.accept(v);
2101 }
2102
2103 transformChildren(Transformer v) {
2104 if (operand != null) {
2105 operand = operand.accept(v);
2106 operand?.parent = this;
2107 }
Asger Feldthaus760da8e2016-08-24 14:46:502108 type = v.visitDartType(type);
Asger Feldthaus02604e92016-04-26 08:39:152109 }
2110}
2111
2112/// An integer, double, boolean, string, or null constant.
2113abstract class BasicLiteral extends Expression {
2114 Object get value;
2115
2116 visitChildren(Visitor v) {}
2117 transformChildren(Transformer v) {}
2118}
2119
2120class StringLiteral extends BasicLiteral {
2121 String value;
2122
2123 StringLiteral(this.value);
2124
Asger Feldthaus2eaa8842016-09-06 09:40:132125 DartType getStaticType(TypeEnvironment types) => types.stringType;
2126
Asger Feldthaus02604e92016-04-26 08:39:152127 accept(ExpressionVisitor v) => v.visitStringLiteral(this);
2128}
2129
2130class IntLiteral extends BasicLiteral {
2131 int value;
2132
2133 IntLiteral(this.value);
2134
Asger Feldthaus2eaa8842016-09-06 09:40:132135 DartType getStaticType(TypeEnvironment types) => types.intType;
2136
Asger Feldthaus02604e92016-04-26 08:39:152137 accept(ExpressionVisitor v) => v.visitIntLiteral(this);
2138}
2139
2140class DoubleLiteral extends BasicLiteral {
2141 double value;
2142
2143 DoubleLiteral(this.value);
2144
Asger Feldthaus2eaa8842016-09-06 09:40:132145 DartType getStaticType(TypeEnvironment types) => types.doubleType;
2146
Asger Feldthaus02604e92016-04-26 08:39:152147 accept(ExpressionVisitor v) => v.visitDoubleLiteral(this);
2148}
2149
2150class BoolLiteral extends BasicLiteral {
2151 bool value;
2152
2153 BoolLiteral(this.value);
2154
Asger Feldthaus2eaa8842016-09-06 09:40:132155 DartType getStaticType(TypeEnvironment types) => types.boolType;
2156
Asger Feldthaus02604e92016-04-26 08:39:152157 accept(ExpressionVisitor v) => v.visitBoolLiteral(this);
2158}
2159
2160class NullLiteral extends BasicLiteral {
2161 Object get value => null;
2162
Asger Feldthaus2eaa8842016-09-06 09:40:132163 DartType getStaticType(TypeEnvironment types) => const BottomType();
2164
Asger Feldthaus02604e92016-04-26 08:39:152165 accept(ExpressionVisitor v) => v.visitNullLiteral(this);
2166}
2167
2168class SymbolLiteral extends Expression {
2169 String value; // Everything strictly after the '#'.
2170
2171 SymbolLiteral(this.value);
2172
Asger Feldthaus2eaa8842016-09-06 09:40:132173 DartType getStaticType(TypeEnvironment types) => types.symbolType;
2174
Asger Feldthaus02604e92016-04-26 08:39:152175 accept(ExpressionVisitor v) => v.visitSymbolLiteral(this);
2176
2177 visitChildren(Visitor v) {}
2178 transformChildren(Transformer v) {}
2179}
2180
2181class TypeLiteral extends Expression {
2182 DartType type;
2183
2184 TypeLiteral(this.type);
2185
Asger Feldthaus2eaa8842016-09-06 09:40:132186 DartType getStaticType(TypeEnvironment types) => types.typeType;
2187
Asger Feldthaus02604e92016-04-26 08:39:152188 accept(ExpressionVisitor v) => v.visitTypeLiteral(this);
2189
2190 visitChildren(Visitor v) {
2191 type?.accept(v);
2192 }
2193
Asger Feldthaus760da8e2016-08-24 14:46:502194 transformChildren(Transformer v) {
2195 type = v.visitDartType(type);
2196 }
Asger Feldthaus02604e92016-04-26 08:39:152197}
2198
2199class ThisExpression extends Expression {
Asger Feldthaus2eaa8842016-09-06 09:40:132200 DartType getStaticType(TypeEnvironment types) => types.thisType;
2201
Asger Feldthaus02604e92016-04-26 08:39:152202 accept(ExpressionVisitor v) => v.visitThisExpression(this);
2203
2204 visitChildren(Visitor v) {}
2205 transformChildren(Transformer v) {}
2206}
2207
2208class Rethrow extends Expression {
Asger Feldthaus2eaa8842016-09-06 09:40:132209 DartType getStaticType(TypeEnvironment types) => const BottomType();
2210
Asger Feldthaus02604e92016-04-26 08:39:152211 accept(ExpressionVisitor v) => v.visitRethrow(this);
2212
2213 visitChildren(Visitor v) {}
2214 transformChildren(Transformer v) {}
2215}
2216
2217class Throw extends Expression {
2218 Expression expression;
2219
2220 Throw(this.expression) {
2221 expression?.parent = this;
2222 }
2223
Asger Feldthaus2eaa8842016-09-06 09:40:132224 DartType getStaticType(TypeEnvironment types) => const BottomType();
2225
Asger Feldthaus02604e92016-04-26 08:39:152226 accept(ExpressionVisitor v) => v.visitThrow(this);
2227
2228 visitChildren(Visitor v) {
2229 expression?.accept(v);
2230 }
2231
2232 transformChildren(Transformer v) {
2233 if (expression != null) {
2234 expression = expression.accept(v);
2235 expression?.parent = this;
2236 }
2237 }
2238}
2239
2240class ListLiteral extends Expression {
2241 bool isConst;
2242 DartType typeArgument; // Not null, defaults to DynamicType.
2243 final List<Expression> expressions;
2244
2245 ListLiteral(this.expressions,
2246 {this.typeArgument: const DynamicType(), this.isConst: false}) {
Asger Feldthaus243ea892016-06-06 13:01:512247 assert(typeArgument != null);
Asger Feldthaus246f6c12016-05-25 11:56:432248 setParents(expressions, this);
Asger Feldthaus02604e92016-04-26 08:39:152249 }
2250
Asger Feldthaus2eaa8842016-09-06 09:40:132251 DartType getStaticType(TypeEnvironment types) {
Asger Feldthaus3baff072016-11-01 14:43:312252 return types.literalListType(typeArgument);
Asger Feldthaus2eaa8842016-09-06 09:40:132253 }
2254
Asger Feldthaus02604e92016-04-26 08:39:152255 accept(ExpressionVisitor v) => v.visitListLiteral(this);
2256
2257 visitChildren(Visitor v) {
2258 typeArgument?.accept(v);
Asger Feldthaus246f6c12016-05-25 11:56:432259 visitList(expressions, v);
Asger Feldthaus02604e92016-04-26 08:39:152260 }
2261
2262 transformChildren(Transformer v) {
Asger Feldthaus760da8e2016-08-24 14:46:502263 typeArgument = v.visitDartType(typeArgument);
Asger Feldthaus246f6c12016-05-25 11:56:432264 transformList(expressions, v, this);
Asger Feldthaus02604e92016-04-26 08:39:152265 }
2266}
2267
2268class MapLiteral extends Expression {
2269 bool isConst;
2270 DartType keyType; // Not null, defaults to DynamicType.
2271 DartType valueType; // Not null, defaults to DynamicType.
2272 final List<MapEntry> entries;
2273
2274 MapLiteral(this.entries,
2275 {this.keyType: const DynamicType(),
2276 this.valueType: const DynamicType(),
2277 this.isConst: false}) {
Asger Feldthaus243ea892016-06-06 13:01:512278 assert(keyType != null);
2279 assert(valueType != null);
Asger Feldthaus246f6c12016-05-25 11:56:432280 setParents(entries, this);
Asger Feldthaus02604e92016-04-26 08:39:152281 }
2282
Asger Feldthaus2eaa8842016-09-06 09:40:132283 DartType getStaticType(TypeEnvironment types) {
Asger Feldthaus3baff072016-11-01 14:43:312284 return types.literalMapType(keyType, valueType);
Asger Feldthaus2eaa8842016-09-06 09:40:132285 }
2286
Asger Feldthaus02604e92016-04-26 08:39:152287 accept(ExpressionVisitor v) => v.visitMapLiteral(this);
2288
2289 visitChildren(Visitor v) {
2290 keyType?.accept(v);
2291 valueType?.accept(v);
Asger Feldthaus246f6c12016-05-25 11:56:432292 visitList(entries, v);
Asger Feldthaus02604e92016-04-26 08:39:152293 }
2294
2295 transformChildren(Transformer v) {
Asger Feldthaus760da8e2016-08-24 14:46:502296 keyType = v.visitDartType(keyType);
2297 valueType = v.visitDartType(valueType);
Asger Feldthaus246f6c12016-05-25 11:56:432298 transformList(entries, v, this);
Asger Feldthaus02604e92016-04-26 08:39:152299 }
2300}
2301
2302class MapEntry extends TreeNode {
2303 Expression key;
2304 Expression value;
2305
2306 MapEntry(this.key, this.value) {
2307 key?.parent = this;
2308 value?.parent = this;
2309 }
2310
2311 accept(TreeVisitor v) => v.visitMapEntry(this);
2312
2313 visitChildren(Visitor v) {
2314 key?.accept(v);
2315 value?.accept(v);
2316 }
2317
2318 transformChildren(Transformer v) {
2319 if (key != null) {
2320 key = key.accept(v);
2321 key?.parent = this;
2322 }
2323 if (value != null) {
2324 value = value.accept(v);
2325 value?.parent = this;
2326 }
2327 }
2328}
2329
2330/// Expression of form `await x`.
2331class AwaitExpression extends Expression {
2332 Expression operand;
2333
2334 AwaitExpression(this.operand) {
2335 operand?.parent = this;
2336 }
2337
Asger Feldthaus2eaa8842016-09-06 09:40:132338 DartType getStaticType(TypeEnvironment types) {
2339 return types.unfutureType(operand.getStaticType(types));
2340 }
2341
Asger Feldthaus02604e92016-04-26 08:39:152342 accept(ExpressionVisitor v) => v.visitAwaitExpression(this);
2343
2344 visitChildren(Visitor v) {
2345 operand?.accept(v);
2346 }
2347
2348 transformChildren(Transformer v) {
2349 if (operand != null) {
2350 operand = operand.accept(v);
2351 operand?.parent = this;
2352 }
2353 }
2354}
2355
2356/// Expression of form `(x,y) => ...` or `(x,y) { ... }`
2357///
2358/// The arrow-body form `=> e` is desugared into `return e;`.
2359class FunctionExpression extends Expression {
2360 FunctionNode function;
2361
2362 FunctionExpression(this.function) {
2363 function?.parent = this;
2364 }
2365
Asger Feldthaus2eaa8842016-09-06 09:40:132366 DartType getStaticType(TypeEnvironment types) => function.functionType;
2367
Asger Feldthaus02604e92016-04-26 08:39:152368 accept(ExpressionVisitor v) => v.visitFunctionExpression(this);
2369
2370 visitChildren(Visitor v) {
2371 function?.accept(v);
2372 }
2373
2374 transformChildren(Transformer v) {
2375 if (function != null) {
2376 function = function.accept(v);
2377 function?.parent = this;
2378 }
2379 }
2380}
2381
2382/// Synthetic expression of form `let v = x in y`
2383class Let extends Expression {
2384 VariableDeclaration variable; // Must have an initializer.
2385 Expression body;
2386
2387 Let(this.variable, this.body) {
2388 variable?.parent = this;
2389 body?.parent = this;
2390 }
2391
Asger Feldthaus2eaa8842016-09-06 09:40:132392 DartType getStaticType(TypeEnvironment types) => body.getStaticType(types);
2393
Asger Feldthaus02604e92016-04-26 08:39:152394 accept(ExpressionVisitor v) => v.visitLet(this);
2395
2396 visitChildren(Visitor v) {
2397 variable?.accept(v);
2398 body?.accept(v);
2399 }
2400
2401 transformChildren(Transformer v) {
2402 if (variable != null) {
2403 variable = variable.accept(v);
2404 variable?.parent = this;
2405 }
2406 if (body != null) {
2407 body = body.accept(v);
2408 body?.parent = this;
2409 }
2410 }
2411}
2412
2413// ------------------------------------------------------------------------
2414// STATEMENTS
2415// ------------------------------------------------------------------------
2416
2417abstract class Statement extends TreeNode {
2418 accept(StatementVisitor v);
2419}
2420
2421/// A statement with a compile-time error.
2422///
2423/// Should throw an exception at runtime.
2424class InvalidStatement extends Statement {
2425 accept(StatementVisitor v) => v.visitInvalidStatement(this);
2426
2427 visitChildren(Visitor v) {}
2428 transformChildren(Transformer v) {}
2429}
2430
2431class ExpressionStatement extends Statement {
2432 Expression expression;
2433
2434 ExpressionStatement(this.expression) {
2435 expression?.parent = this;
2436 }
2437
2438 accept(StatementVisitor v) => v.visitExpressionStatement(this);
2439
2440 visitChildren(Visitor v) {
2441 expression?.accept(v);
2442 }
2443
2444 transformChildren(Transformer v) {
2445 if (expression != null) {
2446 expression = expression.accept(v);
2447 expression?.parent = this;
2448 }
2449 }
2450}
2451
2452class Block extends Statement {
2453 final List<Statement> statements;
2454
2455 Block(this.statements) {
Asger Feldthaus246f6c12016-05-25 11:56:432456 setParents(statements, this);
Asger Feldthaus02604e92016-04-26 08:39:152457 }
2458
2459 accept(StatementVisitor v) => v.visitBlock(this);
2460
2461 visitChildren(Visitor v) {
Asger Feldthaus246f6c12016-05-25 11:56:432462 visitList(statements, v);
Asger Feldthaus02604e92016-04-26 08:39:152463 }
2464
2465 transformChildren(Transformer v) {
Asger Feldthaus246f6c12016-05-25 11:56:432466 transformList(statements, v, this);
Asger Feldthaus02604e92016-04-26 08:39:152467 }
Asger Feldthause60caa22016-11-15 13:27:222468
2469 void addStatement(Statement node) {
2470 statements.add(node);
2471 node.parent = this;
2472 }
Asger Feldthaus02604e92016-04-26 08:39:152473}
2474
2475class EmptyStatement extends Statement {
2476 accept(StatementVisitor v) => v.visitEmptyStatement(this);
2477
2478 visitChildren(Visitor v) {}
2479 transformChildren(Transformer v) {}
2480}
2481
2482class AssertStatement extends Statement {
2483 Expression condition;
2484 Expression message; // May be null.
2485
2486 AssertStatement(this.condition, [this.message]) {
2487 condition?.parent = this;
2488 message?.parent = this;
2489 }
2490
2491 accept(StatementVisitor v) => v.visitAssertStatement(this);
2492
2493 visitChildren(Visitor v) {
2494 condition?.accept(v);
2495 message?.accept(v);
2496 }
2497
2498 transformChildren(Transformer v) {
2499 if (condition != null) {
2500 condition = condition.accept(v);
2501 condition?.parent = this;
2502 }
2503 if (message != null) {
2504 message = message.accept(v);
2505 message?.parent = this;
2506 }
2507 }
2508}
2509
2510/// A target of a [Break] statement.
2511///
2512/// The label itself has no name; breaks reference the statement directly.
2513///
2514/// The frontend does not generate labeled statements without uses.
2515class LabeledStatement extends Statement {
2516 Statement body;
2517
2518 LabeledStatement(this.body) {
2519 body?.parent = this;
2520 }
2521
2522 accept(StatementVisitor v) => v.visitLabeledStatement(this);
2523
2524 visitChildren(Visitor v) {
2525 body?.accept(v);
2526 }
2527
2528 transformChildren(Transformer v) {
2529 if (body != null) {
2530 body = body.accept(v);
2531 body?.parent = this;
2532 }
2533 }
2534}
2535
2536/// Breaks out of an enclosing [LabeledStatement].
2537///
2538/// Both `break` and loop `continue` statements are translated into this node.
2539///
2540/// For example, the following loop with a `continue` will be desugared:
2541///
2542/// while(x) {
2543/// if (y) continue;
2544/// BODY'
2545/// }
2546///
2547/// ==>
2548///
2549/// while(x) {
2550/// L: {
2551/// if (y) break L;
2552/// BODY'
2553/// }
2554/// }
2555//
2556class BreakStatement extends Statement {
2557 LabeledStatement target;
2558
2559 BreakStatement(this.target);
2560
2561 accept(StatementVisitor v) => v.visitBreakStatement(this);
2562
2563 visitChildren(Visitor v) {}
2564 transformChildren(Transformer v) {}
2565}
2566
2567class WhileStatement extends Statement {
2568 Expression condition;
2569 Statement body;
2570
2571 WhileStatement(this.condition, this.body) {
2572 condition?.parent = this;
2573 body?.parent = this;
2574 }
2575
2576 accept(StatementVisitor v) => v.visitWhileStatement(this);
2577
2578 visitChildren(Visitor v) {
2579 condition?.accept(v);
2580 body?.accept(v);
2581 }
2582
2583 transformChildren(Transformer v) {
2584 if (condition != null) {
2585 condition = condition.accept(v);
2586 condition?.parent = this;
2587 }
2588 if (body != null) {
2589 body = body.accept(v);
2590 body?.parent = this;
2591 }
2592 }
2593}
2594
2595class DoStatement extends Statement {
2596 Statement body;
2597 Expression condition;
2598
2599 DoStatement(this.body, this.condition) {
2600 body?.parent = this;
2601 condition?.parent = this;
2602 }
2603
2604 accept(StatementVisitor v) => v.visitDoStatement(this);
2605
2606 visitChildren(Visitor v) {
2607 body?.accept(v);
2608 condition?.accept(v);
2609 }
2610
2611 transformChildren(Transformer v) {
2612 if (body != null) {
2613 body = body.accept(v);
2614 body?.parent = this;
2615 }
2616 if (condition != null) {
2617 condition = condition.accept(v);
2618 condition?.parent = this;
2619 }
2620 }
2621}
2622
2623class ForStatement extends Statement {
2624 final List<VariableDeclaration> variables; // May be empty, but not null.
2625 Expression condition; // May be null.
2626 final List<Expression> updates; // May be empty, but not null.
2627 Statement body;
2628
2629 ForStatement(this.variables, this.condition, this.updates, this.body) {
Asger Feldthaus246f6c12016-05-25 11:56:432630 setParents(variables, this);
Asger Feldthaus02604e92016-04-26 08:39:152631 condition?.parent = this;
Asger Feldthaus246f6c12016-05-25 11:56:432632 setParents(updates, this);
Asger Feldthaus02604e92016-04-26 08:39:152633 body?.parent = this;
2634 }
2635
2636 accept(StatementVisitor v) => v.visitForStatement(this);
2637
2638 visitChildren(Visitor v) {
Asger Feldthaus246f6c12016-05-25 11:56:432639 visitList(variables, v);
Asger Feldthaus02604e92016-04-26 08:39:152640 condition?.accept(v);
Asger Feldthaus246f6c12016-05-25 11:56:432641 visitList(updates, v);
Asger Feldthaus02604e92016-04-26 08:39:152642 body?.accept(v);
2643 }
2644
2645 transformChildren(Transformer v) {
Asger Feldthaus246f6c12016-05-25 11:56:432646 transformList(variables, v, this);
Asger Feldthaus02604e92016-04-26 08:39:152647 if (condition != null) {
2648 condition = condition.accept(v);
2649 condition?.parent = this;
2650 }
Asger Feldthaus246f6c12016-05-25 11:56:432651 transformList(updates, v, this);
Asger Feldthaus02604e92016-04-26 08:39:152652 if (body != null) {
2653 body = body.accept(v);
2654 body?.parent = this;
2655 }
2656 }
2657}
2658
2659class ForInStatement extends Statement {
2660 VariableDeclaration variable; // Has no initializer.
2661 Expression iterable;
2662 Statement body;
2663 bool isAsync; // True if this is an 'await for' loop.
2664
2665 ForInStatement(this.variable, this.iterable, this.body,
2666 {this.isAsync: false}) {
2667 variable?.parent = this;
2668 iterable?.parent = this;
2669 body?.parent = this;
2670 }
2671
2672 accept(StatementVisitor v) => v.visitForInStatement(this);
2673
2674 visitChildren(Visitor v) {
2675 variable?.accept(v);
2676 iterable?.accept(v);
2677 body?.accept(v);
2678 }
2679
2680 transformChildren(Transformer v) {
2681 if (variable != null) {
2682 variable = variable.accept(v);
2683 variable?.parent = this;
2684 }
2685 if (iterable != null) {
2686 iterable = iterable.accept(v);
2687 iterable?.parent = this;
2688 }
2689 if (body != null) {
2690 body = body.accept(v);
2691 body?.parent = this;
2692 }
2693 }
2694}
2695
2696/// Statement of form `switch (e) { case x: ... }`.
2697///
2698/// Adjacent case clauses have been merged into a single [SwitchCase]. A runtime
2699/// exception must be thrown if one [SwitchCase] falls through to another case.
2700class SwitchStatement extends Statement {
2701 Expression expression;
2702 final List<SwitchCase> cases;
2703
2704 SwitchStatement(this.expression, this.cases) {
2705 expression?.parent = this;
Asger Feldthaus246f6c12016-05-25 11:56:432706 setParents(cases, this);
Asger Feldthaus02604e92016-04-26 08:39:152707 }
2708
2709 accept(StatementVisitor v) => v.visitSwitchStatement(this);
2710
2711 visitChildren(Visitor v) {
2712 expression?.accept(v);
Asger Feldthaus246f6c12016-05-25 11:56:432713 visitList(cases, v);
Asger Feldthaus02604e92016-04-26 08:39:152714 }
2715
2716 transformChildren(Transformer v) {
2717 if (expression != null) {
2718 expression = expression.accept(v);
2719 expression?.parent = this;
2720 }
Asger Feldthaus246f6c12016-05-25 11:56:432721 transformList(cases, v, this);
Asger Feldthaus02604e92016-04-26 08:39:152722 }
2723}
2724
2725/// A group of `case` clauses and/or a `default` clause.
2726///
2727/// This is a potential target of [ContinueSwitchStatement].
2728class SwitchCase extends TreeNode {
2729 final List<Expression> expressions;
2730 Statement body;
2731 bool isDefault;
2732
2733 SwitchCase(this.expressions, this.body, {this.isDefault: false}) {
Asger Feldthaus246f6c12016-05-25 11:56:432734 setParents(expressions, this);
Asger Feldthaus02604e92016-04-26 08:39:152735 body?.parent = this;
2736 }
2737
2738 SwitchCase.defaultCase(this.body)
2739 : isDefault = true,
2740 expressions = <Expression>[] {
2741 body?.parent = this;
2742 }
2743
2744 SwitchCase.empty()
2745 : expressions = <Expression>[],
2746 body = null,
2747 isDefault = false;
2748
2749 accept(TreeVisitor v) => v.visitSwitchCase(this);
2750
2751 visitChildren(Visitor v) {
Asger Feldthaus246f6c12016-05-25 11:56:432752 visitList(expressions, v);
Asger Feldthaus02604e92016-04-26 08:39:152753 body?.accept(v);
2754 }
2755
2756 transformChildren(Transformer v) {
Asger Feldthaus246f6c12016-05-25 11:56:432757 transformList(expressions, v, this);
Asger Feldthaus02604e92016-04-26 08:39:152758 if (body != null) {
2759 body = body.accept(v);
2760 body?.parent = this;
2761 }
2762 }
2763}
2764
2765/// Jump to a case in an enclosing switch.
2766class ContinueSwitchStatement extends Statement {
2767 SwitchCase target;
2768
2769 ContinueSwitchStatement(this.target);
2770
2771 accept(StatementVisitor v) => v.visitContinueSwitchStatement(this);
2772
2773 visitChildren(Visitor v) {}
2774 transformChildren(Transformer v) {}
2775}
2776
2777class IfStatement extends Statement {
2778 Expression condition;
2779 Statement then;
2780 Statement otherwise;
2781
2782 IfStatement(this.condition, this.then, this.otherwise) {
2783 condition?.parent = this;
2784 then?.parent = this;
2785 otherwise?.parent = this;
2786 }
2787
2788 accept(StatementVisitor v) => v.visitIfStatement(this);
2789
2790 visitChildren(Visitor v) {
2791 condition?.accept(v);
2792 then?.accept(v);
2793 otherwise?.accept(v);
2794 }
2795
2796 transformChildren(Transformer v) {
2797 if (condition != null) {
2798 condition = condition.accept(v);
2799 condition?.parent = this;
2800 }
2801 if (then != null) {
2802 then = then.accept(v);
2803 then?.parent = this;
2804 }
2805 if (otherwise != null) {
2806 otherwise = otherwise.accept(v);
2807 otherwise?.parent = this;
2808 }
2809 }
2810}
2811
2812class ReturnStatement extends Statement {
2813 Expression expression; // May be null.
2814
2815 ReturnStatement([this.expression]) {
2816 expression?.parent = this;
2817 }
2818
2819 accept(StatementVisitor v) => v.visitReturnStatement(this);
2820
2821 visitChildren(Visitor v) {
2822 expression?.accept(v);
2823 }
2824
2825 transformChildren(Transformer v) {
2826 if (expression != null) {
2827 expression = expression.accept(v);
2828 expression?.parent = this;
2829 }
2830 }
2831}
2832
2833class TryCatch extends Statement {
2834 Statement body;
2835 List<Catch> catches;
2836
2837 TryCatch(this.body, this.catches) {
2838 body?.parent = this;
Asger Feldthaus246f6c12016-05-25 11:56:432839 setParents(catches, this);
Asger Feldthaus02604e92016-04-26 08:39:152840 }
2841
2842 accept(StatementVisitor v) => v.visitTryCatch(this);
2843
2844 visitChildren(Visitor v) {
2845 body?.accept(v);
Asger Feldthaus246f6c12016-05-25 11:56:432846 visitList(catches, v);
Asger Feldthaus02604e92016-04-26 08:39:152847 }
2848
2849 transformChildren(Transformer v) {
2850 if (body != null) {
2851 body = body.accept(v);
2852 body?.parent = this;
2853 }
Asger Feldthaus246f6c12016-05-25 11:56:432854 transformList(catches, v, this);
Asger Feldthaus02604e92016-04-26 08:39:152855 }
2856}
2857
2858class Catch extends TreeNode {
Asger Feldthaus243ea892016-06-06 13:01:512859 DartType guard; // Not null, defaults to dynamic.
2860 VariableDeclaration exception; // May be null.
Asger Feldthaus02604e92016-04-26 08:39:152861 VariableDeclaration stackTrace; // May be null.
2862 Statement body;
2863
Asger Feldthaus243ea892016-06-06 13:01:512864 Catch(this.exception, this.body,
2865 {this.guard: const DynamicType(), this.stackTrace}) {
2866 assert(guard != null);
Asger Feldthaus02604e92016-04-26 08:39:152867 exception?.parent = this;
2868 stackTrace?.parent = this;
2869 body?.parent = this;
2870 }
2871
2872 accept(TreeVisitor v) => v.visitCatch(this);
2873
2874 visitChildren(Visitor v) {
Asger Feldthaus246f6c12016-05-25 11:56:432875 guard?.accept(v);
Asger Feldthaus02604e92016-04-26 08:39:152876 exception?.accept(v);
2877 stackTrace?.accept(v);
2878 body?.accept(v);
2879 }
2880
2881 transformChildren(Transformer v) {
Asger Feldthaus760da8e2016-08-24 14:46:502882 guard = v.visitDartType(guard);
Asger Feldthaus02604e92016-04-26 08:39:152883 if (exception != null) {
2884 exception = exception.accept(v);
2885 exception?.parent = this;
2886 }
2887 if (stackTrace != null) {
2888 stackTrace = stackTrace.accept(v);
2889 stackTrace?.parent = this;
2890 }
2891 if (body != null) {
2892 body = body.accept(v);
2893 body?.parent = this;
2894 }
2895 }
2896}
2897
2898class TryFinally extends Statement {
2899 Statement body;
2900 Statement finalizer;
2901
2902 TryFinally(this.body, this.finalizer) {
2903 body?.parent = this;
2904 finalizer?.parent = this;
2905 }
2906
2907 accept(StatementVisitor v) => v.visitTryFinally(this);
2908
2909 visitChildren(Visitor v) {
2910 body?.accept(v);
2911 finalizer?.accept(v);
2912 }
2913
2914 transformChildren(Transformer v) {
2915 if (body != null) {
2916 body = body.accept(v);
2917 body?.parent = this;
2918 }
2919 if (finalizer != null) {
2920 finalizer = finalizer.accept(v);
2921 finalizer?.parent = this;
2922 }
2923 }
2924}
2925
2926/// Statement of form `yield x` or `yield* x`.
Vyacheslav Egorovffb724a2016-08-23 08:27:272927///
2928/// For native yield semantics see `AsyncMarker.SyncYielding`.
Asger Feldthaus02604e92016-04-26 08:39:152929class YieldStatement extends Statement {
2930 Expression expression;
Martin Kustermann1febd482016-07-07 19:24:102931 int flags = 0;
Asger Feldthaus02604e92016-04-26 08:39:152932
Vyacheslav Egorov8af4a2e2016-07-07 18:05:062933 YieldStatement(this.expression,
Asger Feldthausd1f47022016-08-22 10:35:182934 {bool isYieldStar: false, bool isNative: false}) {
Asger Feldthaus02604e92016-04-26 08:39:152935 expression?.parent = this;
Martin Kustermann1febd482016-07-07 19:24:102936 this.isYieldStar = isYieldStar;
2937 this.isNative = isNative;
2938 }
2939
2940 static const int FlagYieldStar = 1 << 0;
2941 static const int FlagNative = 1 << 1;
2942
2943 bool get isYieldStar => flags & FlagYieldStar != 0;
2944 bool get isNative => flags & FlagNative != 0;
2945
2946 void set isYieldStar(bool value) {
2947 flags = value ? (flags | FlagYieldStar) : (flags & ~FlagYieldStar);
2948 }
2949
2950 void set isNative(bool value) {
2951 flags = value ? (flags | FlagNative) : (flags & ~FlagNative);
Asger Feldthaus02604e92016-04-26 08:39:152952 }
2953
2954 accept(StatementVisitor v) => v.visitYieldStatement(this);
2955
2956 visitChildren(Visitor v) {
2957 expression?.accept(v);
2958 }
2959
2960 transformChildren(Transformer v) {
2961 if (expression != null) {
2962 expression = expression.accept(v);
2963 expression?.parent = this;
2964 }
2965 }
2966}
2967
2968/// Declaration of a local variable.
2969///
2970/// This may occur as a statement, but is also used in several non-statement
2971/// contexts, such as in [ForStatement], [Catch], and [FunctionNode].
Asger Feldthausb3a0d202016-05-25 14:49:392972///
Asger Feldthaus0642e6b2016-06-27 10:23:022973/// When this occurs as a statement, it must be a direct child of a [Block].
Asger Feldthaus02604e92016-04-26 08:39:152974//
2975// DESIGN TODO: Should we remove the 'final' modifier from variables?
Asger Feldthaus0defa952016-11-16 14:16:242976class VariableDeclaration extends Statement
2977 implements Comparable<VariableDeclaration> {
Asger Feldthaus02604e92016-04-26 08:39:152978 /// For named parameters, this is the name of the parameter. No two named
2979 /// parameters (in the same parameter list) can have the same name.
2980 ///
2981 /// In all other cases, the name is cosmetic, may be empty or null,
2982 /// and is not necessarily unique.
2983 String name;
2984 int flags = 0;
Asger Feldthaus243ea892016-06-06 13:01:512985 DartType type; // Not null, defaults to dynamic.
Martin Kustermann1392dcb2016-08-09 10:53:422986 InferredValue inferredValue; // May be null.
Asger Feldthaus02604e92016-04-26 08:39:152987
2988 /// For locals, this is the initial value.
2989 /// For parameters, this is the default value.
2990 ///
2991 /// Should be null in other cases.
2992 Expression initializer; // May be null.
2993
2994 VariableDeclaration(this.name,
Asger Feldthaus243ea892016-06-06 13:01:512995 {this.initializer,
2996 this.type: const DynamicType(),
Martin Kustermann1392dcb2016-08-09 10:53:422997 this.inferredValue,
Asger Feldthaus243ea892016-06-06 13:01:512998 bool isFinal: false,
2999 bool isConst: false}) {
3000 assert(type != null);
Asger Feldthaus02604e92016-04-26 08:39:153001 initializer?.parent = this;
3002 this.isFinal = isFinal;
3003 this.isConst = isConst;
3004 }
3005
3006 /// Creates a synthetic variable with the given expression as initializer.
3007 VariableDeclaration.forValue(this.initializer,
Asger Feldthaus243ea892016-06-06 13:01:513008 {bool isFinal: true,
3009 bool isConst: false,
3010 this.type: const DynamicType()}) {
3011 assert(type != null);
Asger Feldthaus02604e92016-04-26 08:39:153012 initializer?.parent = this;
3013 this.isFinal = isFinal;
3014 this.isConst = isConst;
3015 }
3016
3017 static const int FlagFinal = 1 << 0; // Must match serialized bit positions.
3018 static const int FlagConst = 1 << 1;
3019
3020 bool get isFinal => flags & FlagFinal != 0;
3021 bool get isConst => flags & FlagConst != 0;
3022
3023 void set isFinal(bool value) {
Martin Kustermann1eb5f622016-07-08 07:22:363024 flags = value ? (flags | FlagFinal) : (flags & ~FlagFinal);
Asger Feldthaus02604e92016-04-26 08:39:153025 }
3026
3027 void set isConst(bool value) {
Martin Kustermann1eb5f622016-07-08 07:22:363028 flags = value ? (flags | FlagConst) : (flags & ~FlagConst);
Asger Feldthaus02604e92016-04-26 08:39:153029 }
3030
3031 accept(StatementVisitor v) => v.visitVariableDeclaration(this);
3032
3033 visitChildren(Visitor v) {
3034 type?.accept(v);
Martin Kustermann1392dcb2016-08-09 10:53:423035 inferredValue?.accept(v);
Asger Feldthaus02604e92016-04-26 08:39:153036 initializer?.accept(v);
3037 }
3038
3039 transformChildren(Transformer v) {
Asger Feldthaus760da8e2016-08-24 14:46:503040 type = v.visitDartType(type);
Asger Feldthaus02604e92016-04-26 08:39:153041 if (initializer != null) {
3042 initializer = initializer.accept(v);
3043 initializer?.parent = this;
3044 }
3045 }
3046
3047 /// Returns a possibly synthesized name for this variable, consistent with
Asger Feldthaus246f6c12016-05-25 11:56:433048 /// the names used across all [toString] calls.
3049 String toString() => debugVariableDeclarationName(this);
Asger Feldthaus0defa952016-11-16 14:16:243050
3051 int compareTo(VariableDeclaration other) {
3052 return name.compareTo(other.name);
3053 }
Asger Feldthaus02604e92016-04-26 08:39:153054}
3055
3056/// Declaration a local function.
3057///
3058/// The body of the function may use [variable] as its self-reference.
3059class FunctionDeclaration extends Statement {
3060 VariableDeclaration variable; // Is final and has no initializer.
3061 FunctionNode function;
3062
3063 FunctionDeclaration(this.variable, this.function) {
3064 variable?.parent = this;
3065 function?.parent = this;
3066 }
3067
3068 accept(StatementVisitor v) => v.visitFunctionDeclaration(this);
3069
3070 visitChildren(Visitor v) {
3071 variable?.accept(v);
3072 function?.accept(v);
3073 }
3074
3075 transformChildren(Transformer v) {
3076 if (variable != null) {
3077 variable = variable.accept(v);
3078 variable?.parent = this;
3079 }
3080 if (function != null) {
3081 function = function.accept(v);
3082 function?.parent = this;
3083 }
3084 }
3085}
3086
3087// ------------------------------------------------------------------------
3088// NAMES
3089// ------------------------------------------------------------------------
3090
3091/// A public name, or a private name qualified by a library.
3092///
3093/// Names are only used for expressions with dynamic dispatch, as all
3094/// statically resolved references are represented in nameless form.
3095///
3096/// [Name]s are immutable and compare based on structural equality, and they
3097/// are not AST nodes.
3098///
3099/// The [toString] method returns a human-readable string that includes the
3100/// library name for private names; uniqueness is not guaranteed.
3101abstract class Name implements Node {
Asger Feldthaus7ad92c22016-05-09 12:12:403102 final int hashCode;
Asger Feldthaus02604e92016-04-26 08:39:153103 final String name;
3104 Library get library;
3105 bool get isPrivate;
3106
Asger Feldthaus7ad92c22016-05-09 12:12:403107 Name._internal(this.hashCode, this.name);
Asger Feldthaus02604e92016-04-26 08:39:153108
3109 factory Name(String name, [Library library]) {
3110 /// Use separate subclasses for the public and private case to save memory
3111 /// for public names.
3112 if (name.startsWith('_')) {
Asger Feldthaus246f6c12016-05-25 11:56:433113 assert(library != null);
Asger Feldthaus02604e92016-04-26 08:39:153114 return new _PrivateName(name, library);
3115 } else {
3116 return new _PublicName(name);
3117 }
3118 }
3119
3120 bool operator ==(other) {
3121 return other is Name && name == other.name && library == other.library;
3122 }
3123
Asger Feldthaus02604e92016-04-26 08:39:153124 accept(Visitor v) => v.visitName(this);
3125
3126 visitChildren(Visitor v) {
3127 // DESIGN TODO: Should we visit the library as a library reference?
3128 }
3129}
3130
3131class _PrivateName extends Name {
3132 final Library library;
3133 bool get isPrivate => true;
3134
Asger Feldthaus7ad92c22016-05-09 12:12:403135 _PrivateName(String name, Library library)
3136 : this.library = library,
3137 super._internal(_computeHashCode(name, library), name);
Asger Feldthaus02604e92016-04-26 08:39:153138
Asger Feldthaus246f6c12016-05-25 11:56:433139 String toString() => library != null ? '$library::$name' : name;
Asger Feldthaus7ad92c22016-05-09 12:12:403140
3141 static int _computeHashCode(String name, Library library) {
3142 return 131 * name.hashCode + 17 * library.hashCode;
3143 }
Asger Feldthaus02604e92016-04-26 08:39:153144}
3145
3146class _PublicName extends Name {
3147 Library get library => null;
3148 bool get isPrivate => false;
3149
Asger Feldthaus7ad92c22016-05-09 12:12:403150 _PublicName(String name) : super._internal(name.hashCode, name);
Asger Feldthaus02604e92016-04-26 08:39:153151
3152 String toString() => name;
3153}
3154
3155// ------------------------------------------------------------------------
3156// TYPES
3157// ------------------------------------------------------------------------
3158
3159/// A syntax-independent notion of a type.
3160///
3161/// [DartType]s are not AST nodes and may be shared between different parents.
3162///
3163/// [DartType] objects should be treated as unmodifiable objects, although
3164/// immutability is not enforced for List fields, and [TypeParameter]s are
3165/// cyclic structures that are constructed by mutation.
3166///
3167/// The `==` operator on [DartType]s compare based on type equality, not
Asger Feldthaus885be102016-05-25 11:09:593168/// object identity.
Asger Feldthaus02604e92016-04-26 08:39:153169abstract class DartType extends Node {
3170 const DartType();
3171
3172 accept(DartTypeVisitor v);
3173
3174 bool operator ==(Object other);
Asger Feldthaus02604e92016-04-26 08:39:153175}
3176
3177/// The type arising from invalid type annotations.
3178///
3179/// Can usually be treated as 'dynamic', but should occasionally be handled
3180/// differently, e.g. `x is ERROR` should evaluate to false.
3181class InvalidType extends DartType {
Asger Feldthaus885be102016-05-25 11:09:593182 final int hashCode = 12345;
3183
Asger Feldthaus02604e92016-04-26 08:39:153184 const InvalidType();
3185
3186 accept(DartTypeVisitor v) => v.visitInvalidType(this);
3187 visitChildren(Visitor v) {}
3188
3189 bool operator ==(Object other) => other is InvalidType;
3190}
3191
3192class DynamicType extends DartType {
Asger Feldthaus885be102016-05-25 11:09:593193 final int hashCode = 54321;
3194
Asger Feldthaus02604e92016-04-26 08:39:153195 const DynamicType();
3196
3197 accept(DartTypeVisitor v) => v.visitDynamicType(this);
3198 visitChildren(Visitor v) {}
3199
3200 bool operator ==(Object other) => other is DynamicType;
3201}
3202
3203class VoidType extends DartType {
Asger Feldthaus885be102016-05-25 11:09:593204 final int hashCode = 123121;
3205
Asger Feldthaus02604e92016-04-26 08:39:153206 const VoidType();
3207
3208 accept(DartTypeVisitor v) => v.visitVoidType(this);
3209 visitChildren(Visitor v) {}
3210
3211 bool operator ==(Object other) => other is VoidType;
3212}
3213
Asger Feldthaus2eaa8842016-09-06 09:40:133214class BottomType extends DartType {
3215 final int hashCode = 514213;
3216
3217 const BottomType();
3218
3219 accept(DartTypeVisitor v) => v.visitBottomType(this);
3220 visitChildren(Visitor v) {}
3221
3222 bool operator ==(Object other) => other is BottomType;
3223}
3224
Asger Feldthaus02604e92016-04-26 08:39:153225class InterfaceType extends DartType {
3226 final Class classNode;
3227 final List<DartType> typeArguments;
3228
3229 /// The [typeArguments] list must not be modified after this call. If the
3230 /// list is omitted, 'dynamic' type arguments are filled in.
3231 InterfaceType(Class classNode, [List<DartType> typeArguments])
3232 : this.classNode = classNode,
3233 this.typeArguments = typeArguments ?? _defaultTypeArguments(classNode);
3234
3235 static List<DartType> _defaultTypeArguments(Class classNode) {
3236 if (classNode.typeParameters.length == 0) {
3237 // Avoid allocating a list in this very common case.
3238 return const <DartType>[];
3239 } else {
3240 return new List<DartType>.filled(
3241 classNode.typeParameters.length, const DynamicType());
3242 }
3243 }
3244
3245 accept(DartTypeVisitor v) => v.visitInterfaceType(this);
3246
3247 visitChildren(Visitor v) {
3248 classNode.acceptReference(v);
Asger Feldthaus246f6c12016-05-25 11:56:433249 visitList(typeArguments, v);
Asger Feldthaus02604e92016-04-26 08:39:153250 }
3251
3252 bool operator ==(Object other) {
3253 if (identical(this, other)) return true;
3254 if (other is InterfaceType) {
3255 if (classNode != other.classNode) return false;
3256 if (typeArguments.length != other.typeArguments.length) return false;
3257 for (int i = 0; i < typeArguments.length; ++i) {
3258 if (typeArguments[i] != other.typeArguments[i]) return false;
3259 }
3260 return true;
3261 } else {
3262 return false;
3263 }
3264 }
Peter von der Ahé30372f02016-05-19 11:40:483265
Asger Feldthaus885be102016-05-25 11:09:593266 int get hashCode {
3267 int hash = 0x3fffffff & classNode.hashCode;
3268 for (int i = 0; i < typeArguments.length; ++i) {
3269 hash = 0x3fffffff & (hash * 31 + (hash ^ typeArguments[i].hashCode));
3270 }
3271 return hash;
3272 }
Asger Feldthaus02604e92016-04-26 08:39:153273}
3274
3275/// A possibly generic function type.
3276class FunctionType extends DartType {
3277 final List<TypeParameter> typeParameters;
3278 final int requiredParameterCount;
3279 final List<DartType> positionalParameters;
Asger Feldthaus0defa952016-11-16 14:16:243280 final List<NamedType> namedParameters; // Must be sorted.
Asger Feldthaus02604e92016-04-26 08:39:153281 final DartType returnType;
Asger Feldthaus885be102016-05-25 11:09:593282 int _hashCode;
Asger Feldthaus02604e92016-04-26 08:39:153283
3284 FunctionType(List<DartType> positionalParameters, this.returnType,
Asger Feldthaus0defa952016-11-16 14:16:243285 {this.namedParameters: const <NamedType>[],
Asger Feldthaus02604e92016-04-26 08:39:153286 this.typeParameters: const <TypeParameter>[],
3287 int requiredParameterCount})
3288 : this.positionalParameters = positionalParameters,
3289 this.requiredParameterCount =
3290 requiredParameterCount ?? positionalParameters.length;
3291
3292 accept(DartTypeVisitor v) => v.visitFunctionType(this);
3293
3294 visitChildren(Visitor v) {
Asger Feldthaus246f6c12016-05-25 11:56:433295 visitList(typeParameters, v);
3296 visitList(positionalParameters, v);
Asger Feldthaus0defa952016-11-16 14:16:243297 visitList(namedParameters, v);
Asger Feldthaus02604e92016-04-26 08:39:153298 returnType.accept(v);
3299 }
3300
3301 bool operator ==(Object other) {
3302 if (identical(this, other)) return true;
3303 if (other is FunctionType) {
3304 if (typeParameters.length != other.typeParameters.length ||
3305 requiredParameterCount != other.requiredParameterCount ||
3306 positionalParameters.length != other.positionalParameters.length ||
3307 namedParameters.length != other.namedParameters.length) {
3308 return false;
3309 }
3310 if (typeParameters.isEmpty) {
3311 for (int i = 0; i < positionalParameters.length; ++i) {
3312 if (positionalParameters[i] != other.positionalParameters[i]) {
3313 return false;
3314 }
3315 }
Asger Feldthaus0defa952016-11-16 14:16:243316 for (int i = 0; i < namedParameters.length; ++i) {
3317 if (namedParameters[i] != other.namedParameters[i]) {
Asger Feldthaus02604e92016-04-26 08:39:153318 return false;
3319 }
3320 }
3321 return returnType == other.returnType;
3322 } else {
3323 // Structural equality does not tell us if two generic function types
3324 // are the same type. If they are unifiable without substituting any
3325 // type variables, they are equal.
3326 return unifyTypes(this, other, new Set<TypeParameter>()) != null;
3327 }
3328 } else {
3329 return false;
3330 }
3331 }
3332
3333 /// Returns a variant of this function type that does not declare any type
3334 /// parameters.
3335 ///
3336 /// Any uses of its type parameters become free variables in the returned
3337 /// type.
3338 FunctionType get withoutTypeParameters {
3339 if (typeParameters.isEmpty) return this;
3340 return new FunctionType(positionalParameters, returnType,
3341 requiredParameterCount: requiredParameterCount,
3342 namedParameters: namedParameters);
3343 }
Asger Feldthaus885be102016-05-25 11:09:593344
3345 int get hashCode => _hashCode ??= _computeHashCode();
3346
3347 int _computeHashCode() {
3348 int hash = 1237;
3349 hash = 0x3fffffff & (hash * 31 + requiredParameterCount);
3350 for (int i = 0; i < typeParameters.length; ++i) {
3351 TypeParameter parameter = typeParameters[i];
3352 _temporaryHashCodeTable[parameter] = _temporaryHashCodeTable.length;
3353 hash = 0x3fffffff & (hash * 31 + parameter.bound.hashCode);
3354 }
3355 for (int i = 0; i < positionalParameters.length; ++i) {
3356 hash = 0x3fffffff & (hash * 31 + positionalParameters[i].hashCode);
3357 }
Asger Feldthaus0defa952016-11-16 14:16:243358 for (int i = 0; i < namedParameters.length; ++i) {
3359 hash = 0x3fffffff & (hash * 31 + namedParameters[i].hashCode);
3360 }
Asger Feldthaus885be102016-05-25 11:09:593361 hash = 0x3fffffff & (hash * 31 + returnType.hashCode);
3362 for (int i = 0; i < typeParameters.length; ++i) {
3363 // Remove the type parameters from the scope again.
3364 _temporaryHashCodeTable.remove(typeParameters[i]);
3365 }
3366 return hash;
3367 }
Asger Feldthaus02604e92016-04-26 08:39:153368}
3369
Asger Feldthaus0defa952016-11-16 14:16:243370/// A named parameter in [FunctionType].
3371class NamedType extends Node implements Comparable<NamedType> {
3372 final String name;
3373 final DartType type;
3374
3375 NamedType(this.name, this.type);
3376
3377 bool operator ==(Object other) {
3378 return other is NamedType && name == other.name && type == other.type;
3379 }
3380
3381 int get hashCode {
3382 return name.hashCode * 31 + type.hashCode * 37;
3383 }
3384
3385 int compareTo(NamedType other) => name.compareTo(other.name);
3386
3387 accept(Visitor v) => v.visitNamedType(this);
3388
3389 void visitChildren(Visitor v) {
3390 type.accept(v);
3391 }
3392}
3393
Asger Feldthaus885be102016-05-25 11:09:593394/// Stores the hash code of function type parameters while computing the hash
3395/// code of a [FunctionType] object.
3396///
3397/// This ensures that distinct [FunctionType] objects get the same hash code
3398/// if they represent the same type, even though their type parameters are
3399/// represented by different objects.
3400final Map<TypeParameter, int> _temporaryHashCodeTable = <TypeParameter, int>{};
3401
Asger Feldthaus02604e92016-04-26 08:39:153402/// Reference to a type variable.
3403class TypeParameterType extends DartType {
3404 TypeParameter parameter;
3405
3406 TypeParameterType(this.parameter);
3407
3408 accept(DartTypeVisitor v) => v.visitTypeParameterType(this);
3409
3410 visitChildren(Visitor v) {}
3411
3412 bool operator ==(Object other) {
3413 return other is TypeParameterType && parameter == other.parameter;
3414 }
Peter von der Ahé30372f02016-05-19 11:40:483415
Asger Feldthaus885be102016-05-25 11:09:593416 int get hashCode => _temporaryHashCodeTable[parameter] ?? parameter.hashCode;
Asger Feldthaus02604e92016-04-26 08:39:153417}
3418
3419/// Declaration of a type variable.
3420///
3421/// Type parameters declared in a [Class] or [FunctionNode] are part of the AST,
3422/// have a parent pointer to its declaring class or function, and will be seen
3423/// by tree visitors.
3424///
3425/// Type parameters declared by a [FunctionType] are orphans and have a `null`
3426/// parent pointer. [TypeParameter] objects should not be shared between
3427/// different [FunctionType] objects.
3428class TypeParameter extends TreeNode {
3429 String name; // Cosmetic name.
3430
Asger Feldthaus98a6a2c2016-10-14 11:29:363431 /// The bound on the type variable.
3432 ///
3433 /// Should not be null except temporarily during IR construction. Should
3434 /// be set to the root class for type parameters without an explicit bound.
Asger Feldthaus02604e92016-04-26 08:39:153435 DartType bound;
3436
Asger Feldthaus90ebc0b2016-10-11 13:21:483437 TypeParameter([this.name, this.bound]);
Asger Feldthaus02604e92016-04-26 08:39:153438
3439 accept(TreeVisitor v) => v.visitTypeParameter(this);
3440
3441 visitChildren(Visitor v) {
3442 bound.accept(v);
3443 }
3444
Asger Feldthaus760da8e2016-08-24 14:46:503445 transformChildren(Transformer v) {
3446 bound = v.visitDartType(bound);
3447 }
Asger Feldthaus02604e92016-04-26 08:39:153448
3449 /// Returns a possibly synthesized name for this type parameter, consistent
Asger Feldthaus246f6c12016-05-25 11:56:433450 /// with the names used across all [toString] calls.
3451 String toString() => debugQualifiedTypeParameterName(this);
Asger Feldthaus02604e92016-04-26 08:39:153452}
3453
Asger Feldthause1c26f82016-10-24 14:21:523454class Supertype extends Node {
3455 final Class classNode;
3456 final List<DartType> typeArguments;
3457
3458 Supertype(this.classNode, this.typeArguments);
3459
3460 accept(Visitor v) => v.visitSupertype(this);
3461
3462 visitChildren(Visitor v) {
3463 classNode.acceptReference(v);
3464 visitList(typeArguments, v);
3465 }
3466
3467 InterfaceType get asInterfaceType {
3468 return new InterfaceType(classNode, typeArguments);
3469 }
3470
3471 bool operator ==(Object other) {
3472 if (identical(this, other)) return true;
3473 if (other is Supertype) {
3474 if (classNode != other.classNode) return false;
3475 if (typeArguments.length != other.typeArguments.length) return false;
3476 for (int i = 0; i < typeArguments.length; ++i) {
3477 if (typeArguments[i] != other.typeArguments[i]) return false;
3478 }
3479 return true;
3480 } else {
3481 return false;
3482 }
3483 }
3484
3485 int get hashCode {
3486 int hash = 0x3fffffff & classNode.hashCode;
3487 for (int i = 0; i < typeArguments.length; ++i) {
3488 hash = 0x3fffffff & (hash * 31 + (hash ^ typeArguments[i].hashCode));
3489 }
3490 return hash;
3491 }
3492}
3493
Asger Feldthaus02604e92016-04-26 08:39:153494// ------------------------------------------------------------------------
3495// PROGRAM
3496// ------------------------------------------------------------------------
3497
3498/// A way to bundle up all the libraries in a program.
3499class Program extends TreeNode {
3500 final List<Library> libraries;
3501
Jens Johansena85aabb2016-09-29 09:26:403502 /// Map from a source file uri to a line-starts table.
3503 /// Given a source file uri and a offset in that file one can translate
3504 /// it to a line:column position in that file.
3505 final Map<String, List<int>> uriToLineStarts;
3506
Asger Feldthaus02604e92016-04-26 08:39:153507 /// Reference to the main method in one of the libraries.
3508 Procedure mainMethod;
3509
Jens Johansena85aabb2016-09-29 09:26:403510 Program([List<Library> libraries, Map<String, List<int>> uriToLineStarts])
3511 : libraries = libraries ?? <Library>[],
3512 uriToLineStarts = uriToLineStarts ?? {} {
Asger Feldthaus246f6c12016-05-25 11:56:433513 setParents(libraries, this);
Asger Feldthaus02604e92016-04-26 08:39:153514 }
3515
3516 accept(TreeVisitor v) => v.visitProgram(this);
3517
3518 visitChildren(Visitor v) {
Asger Feldthaus246f6c12016-05-25 11:56:433519 visitList(libraries, v);
Asger Feldthaus02604e92016-04-26 08:39:153520 mainMethod?.acceptReference(v);
3521 }
3522
3523 transformChildren(Transformer v) {
Asger Feldthaus246f6c12016-05-25 11:56:433524 transformList(libraries, v, this);
Asger Feldthaus02604e92016-04-26 08:39:153525 }
Asger Feldthaus5a406362016-10-31 10:29:373526
3527 Program get enclosingProgram => this;
3528
3529 /// Translates an offset to line and column numbers in the given file.
3530 Location getLocation(String file, int offset) {
3531 List<int> lines = uriToLineStarts[file];
3532 int low = 0, high = lines.length - 1;
3533 while (low < high) {
3534 int mid = high - ((high - low) >> 1); // Get middle, rounding up.
3535 int pivot = lines[mid];
3536 if (pivot <= offset) {
3537 low = mid;
3538 } else {
3539 high = mid - 1;
3540 }
3541 }
3542 int lineIndex = low;
3543 int lineStart = lines[lineIndex];
3544 int lineNumber = 1 + lineIndex;
3545 int columnNumber = offset - lineStart;
3546 return new Location(file, lineNumber, columnNumber);
3547 }
3548}
3549
3550/// A tuple with file, line, and column number, for displaying human-readable
3551/// locations.
3552class Location {
3553 final String file;
3554 final int line; // 1-based.
3555 final int column; // 1-based.
3556
3557 Location(this.file, this.line, this.column);
3558
3559 String toString() => '$file:$line:$column';
Asger Feldthaus02604e92016-04-26 08:39:153560}
3561
3562// ------------------------------------------------------------------------
3563// INTERNAL FUNCTIONS
3564// ------------------------------------------------------------------------
3565
Asger Feldthaus246f6c12016-05-25 11:56:433566void setParents(List<TreeNode> nodes, TreeNode parent) {
Asger Feldthaus02604e92016-04-26 08:39:153567 for (int i = 0; i < nodes.length; ++i) {
3568 nodes[i].parent = parent;
3569 }
3570}
3571
Asger Feldthaus246f6c12016-05-25 11:56:433572void visitList(List<Node> nodes, Visitor visitor) {
Asger Feldthaus02604e92016-04-26 08:39:153573 for (int i = 0; i < nodes.length; ++i) {
3574 nodes[i].accept(visitor);
3575 }
3576}
3577
Asger Feldthaus246f6c12016-05-25 11:56:433578void visitIterable(Iterable<Node> nodes, Visitor visitor) {
Asger Feldthaus02604e92016-04-26 08:39:153579 for (var node in nodes) {
3580 node.accept(visitor);
3581 }
3582}
3583
Asger Feldthaus760da8e2016-08-24 14:46:503584void transformTypeList(List<DartType> nodes, Transformer visitor) {
3585 int storeIndex = 0;
3586 for (int i = 0; i < nodes.length; ++i) {
3587 var result = visitor.visitDartType(nodes[i]);
3588 if (result != null) {
3589 nodes[storeIndex] = result;
3590 ++storeIndex;
3591 }
3592 }
3593 if (storeIndex < nodes.length) {
3594 nodes.length = storeIndex;
3595 }
3596}
3597
Asger Feldthause1c26f82016-10-24 14:21:523598void transformSupertypeList(List<Supertype> nodes, Transformer visitor) {
3599 int storeIndex = 0;
3600 for (int i = 0; i < nodes.length; ++i) {
3601 var result = visitor.visitSupertype(nodes[i]);
3602 if (result != null) {
3603 nodes[storeIndex] = result;
3604 ++storeIndex;
3605 }
3606 }
3607 if (storeIndex < nodes.length) {
3608 nodes.length = storeIndex;
3609 }
3610}
3611
Asger Feldthaus246f6c12016-05-25 11:56:433612void transformList(List<TreeNode> nodes, Transformer visitor, TreeNode parent) {
Asger Feldthaus02604e92016-04-26 08:39:153613 int storeIndex = 0;
3614 for (int i = 0; i < nodes.length; ++i) {
3615 var result = nodes[i].accept(visitor);
3616 if (result != null) {
3617 nodes[storeIndex] = result;
3618 result.parent = parent;
3619 ++storeIndex;
3620 }
3621 }
3622 if (storeIndex < nodes.length) {
3623 nodes.length = storeIndex;
3624 }
3625}
3626
3627List<DartType> _getAsTypeArguments(List<TypeParameter> typeParameters) {
3628 if (typeParameters.isEmpty) return const <DartType>[];
3629 return new List<DartType>.generate(
3630 typeParameters.length, (i) => new TypeParameterType(typeParameters[i]),
3631 growable: false);
3632}
3633
3634class _ChildReplacer extends Transformer {
3635 final TreeNode child;
3636 final TreeNode replacement;
3637
3638 _ChildReplacer(this.child, this.replacement);
3639
Asger Feldthaus2eaa8842016-09-06 09:40:133640 @override
3641 defaultTreeNode(TreeNode node) {
Asger Feldthaus02604e92016-04-26 08:39:153642 if (node == child) {
Asger Feldthaus02604e92016-04-26 08:39:153643 return replacement;
3644 } else {
3645 return node;
3646 }
3647 }
3648}