@@ -138,6 +138,55 @@ class ExpressionPropertyTarget<Expression extends Object>
138138/// The client should create one instance of this class for every method, field,
139139/// or top level variable to be analyzed, and call the appropriate methods
140140/// while visiting the code for type inference.
141+ ///
142+ /// The API for flow analysis is event-based, consisting of methods that are
143+ /// intended to be called during a single-pass depth-first pre-order* traversal
144+ /// of the AST of the code being analyzed. The client only needs to make calls
145+ /// into flow analysis when this traversal visits "flow-relevant" AST nodes
146+ /// (i.e. statements and expressions that influence flow control, such as loops,
147+ /// return statements, etc., expressions that reference something potentially
148+ /// promotable, such as a variable and property gets, and anything that performs
149+ /// a type test). Other AST nodes (known as "flow-irrelevant" AST nodes) don't
150+ /// require calls to the flow analysis API on their own, but calls to flow
151+ /// analysis may still be required when visiting their children.
152+ ///
153+ /// *Where child nodes are ordered according to when they first execute. Note
154+ /// that for most constructs this matches the order in which the nodes appear in
155+ /// the source text, but there are a small number of exceptions. For example, in
156+ /// `for (INITIALIZERS; CONDITION; UPDATERS) BODY;` , `UPDATERS` is executed
157+ /// after `BODY` , so `UPDATERS` should be visited after `BODY` . Also, in
158+ /// `PATTERN = EXPRESSION;` , `PATTERN` is executed after `EXPRESSION` , so
159+ /// `PATTERN` should be visited after `EXPRESSION` .
160+ ///
161+ /// With a few exceptions, the methods in this class are named after a kind of
162+ /// AST node, followed by an underscore, followed by a brief phrase indicating
163+ /// when the method should be called during the visit of that kind of AST node.
164+ /// For example, when visiting an `if` statement, the client should call
165+ /// [ifStatement_thenBegin] after visiting its condition expression but before
166+ /// visiting its "then" block. The precise order for visiting any given AST node
167+ /// is described in comments below.
168+ ///
169+ /// Some API calls have arguments representing either the AST node being visited
170+ /// or one of its child nodes. For example, [isExpression_end] has an argument
171+ /// `isExpression` representing the entire "is" expression, and
172+ /// [ifStatement_thenBegin] has an argument `condition` representing the
173+ /// "condition" part of the "if" statement.
174+ ///
175+ /// Among other things, these arguments allow flow analysis to recognize
176+ /// parent/child relationships between parts of the syntax tree. For example,
177+ /// when analyzing `if (x is T)` , the AST node for `x is T` is passed first to
178+ /// [isExpression_end] 's `isExpression` argument and then, immediately
179+ /// afterwards, to [ifStatement_thenBegin] 's `condition` argument; this tells
180+ /// flow analysis that the "is" expression is an immediate child of the "if"
181+ /// statement, and therefore a type promotion should occur.
182+ ///
183+ /// Whereas when analyzing `if (f(x is T))` , the same sequence of calls is made
184+ /// to flow analysis (since the AST node for the invocation of `f` is
185+ /// flow-irrelevant). But the node passed to [isExpression_end] 's `isExpression`
186+ /// argument is `x is T` , whereas the node passed to [ifStatement_thenBegin] 's
187+ /// `condition` argument is `f(x is T)` . Since these nodes are different, flow
188+ /// analysis knows that the "is" expression is *not* an immediate child of the
189+ /// "if" statement, so therefore no type promotion should occur.
141190abstract class FlowAnalysis <Node extends Object , Statement extends Node ,
142191 Expression extends Node , Variable extends Object , Type extends Object > {
143192 factory FlowAnalysis (
@@ -457,6 +506,9 @@ abstract class FlowAnalysis<Node extends Object, Statement extends Node,
457506 /// Call this method to forward information on [oldExpression] to
458507 /// [newExpression] .
459508 ///
509+ /// This method must be called immediately after visiting the expression, and
510+ /// before continuing to visit its parent.
511+ ///
460512 /// This can be used to preserve promotions through a replacement from
461513 /// [oldExpression] to [newExpression] . For instance when rewriting
462514 ///
@@ -4285,18 +4337,57 @@ class _FlowAnalysisImpl<Node extends Object, Statement extends Node,
42854337 /// The most recently visited expression for which an [ExpressionInfo] object
42864338 /// exists, or `null` if no expression has been visited that has a
42874339 /// corresponding [ExpressionInfo] object.
4340+ ///
4341+ /// This field, along with [_expressionInfo] , establishes a mechanism to allow
4342+ /// a flow analysis method that's handling a given AST node to retrieve an
4343+ /// [ExpressionInfo] that was previously created during the handling of one of
4344+ /// that node's children. The mechanism works as follows:
4345+ ///
4346+ /// While visiting the child, [_storeExpressionInfo] is called (passing in the
4347+ /// child node and the [ExpressionInfo] ). It stores the child node in
4348+ /// [_expressionWithInfo] and the info in [_expressionInfo] .
4349+ ///
4350+ /// While visiting the parent, [_getExpressionInfo] is called (passing in the
4351+ /// child node). It checks whether [_expressionWithInfo] matches the child
4352+ /// node; if it does match, that means there are no intervening
4353+ /// flow-irrelevant nodes, and so it returns [_expressionInfo] . If it doesn't
4354+ /// match, that means that some other flow-irrelevant was visited since the
4355+ /// last time [_storeExpressionInfo] was called, and so the info in
4356+ /// [_expressionInfo] is no longer relevant, and so it returns `null` .
4357+ ///
4358+ /// Note that if [_storeExpressionInfo] is called once for expression `e1` and
4359+ /// then again for expression `e2` , the second call will overwrite the info
4360+ /// stored by the first call. So if this is followed by a [_getExpressionInfo]
4361+ /// call for `e1` , `null` will be returned. In principle this situation should
4362+ /// never arise, since the client is expected to visit AST nodes in a
4363+ /// single-pass depth-first pre-order fashion. However, in practice, it
4364+ /// happens sometimes (see https://github.com/dart-lang/sdk/issues/56887).
42884365 Expression ? _expressionWithInfo;
42894366
42904367 /// If [_expressionWithInfo] is not `null` , the [ExpressionInfo] object
42914368 /// corresponding to it. Otherwise `null` .
4369+ ///
4370+ /// See [_expressionWithInfo] for a detailed explanation.
42924371 ExpressionInfo <Type >? _expressionInfo;
42934372
42944373 /// The most recently visited expression which was a reference, or `null` if
42954374 /// no such expression has been visited.
4375+ ///
4376+ /// This field serves the same role as [_expressionWithInfo] , except that it
4377+ /// is only updated for expressions that might refer to something promotable
4378+ /// (a get of a local variable or a property), so it is less likely to have
4379+ /// trouble if the client doesn't visit AST nodes in the proper order (see
4380+ /// https://github.com/dart-lang/sdk/issues/56887).
42964381 Expression ? _expressionWithReference;
42974382
42984383 /// If [_expressionWithReference] is not `null` , the reference corresponding
42994384 /// to it. Otherwise `null` .
4385+ ///
4386+ /// This field serves the same role as [_expressionInfo] , except that it is
4387+ /// only updated for expressions that might refer to something promotable (a
4388+ /// get of a local variable or a property), so it is less likely to have
4389+ /// trouble if the client doesn't visit AST nodes in the proper order (see
4390+ /// https://github.com/dart-lang/sdk/issues/56887).
43004391 _Reference <Type >? _expressionReference;
43014392
43024393 final AssignedVariables <Node , Variable > _assignedVariables;
@@ -5723,6 +5814,15 @@ class _FlowAnalysisImpl<Node extends Object, Statement extends Node,
57235814 /// be the last expression that was traversed). If there is no
57245815 /// [ExpressionInfo] associated with the [expression] , then `null` is
57255816 /// returned.
5817+ ///
5818+ /// See [_expressionWithInfo] for details about how this works.
5819+ ///
5820+ /// To reduce GC pressure, if this method returns a non-null value, it resets
5821+ /// [_expressionInfo] to `null` as a side effect. This means that if
5822+ /// [_getExpressionInfo] is called twice for the same [expression] (without
5823+ /// an intervening call to [_storeExpressionInfo] ), the second call will
5824+ /// return `null` . This should not be a problem because the client is expected
5825+ /// to visit AST nodes in a single-pass depth-first pre-order fashion.
57265826 ExpressionInfo <Type >? _getExpressionInfo (Expression ? expression) {
57275827 if (identical (expression, _expressionWithInfo)) {
57285828 ExpressionInfo <Type >? expressionInfo = _expressionInfo;
@@ -6108,6 +6208,8 @@ class _FlowAnalysisImpl<Node extends Object, Statement extends Node,
61086208 /// Associates [expression] , which should be the most recently visited
61096209 /// expression, with the given [expressionInfo] object, and updates the
61106210 /// current flow model state to correspond to it.
6211+ ///
6212+ /// See [_expressionWithInfo] for details about how this works.
61116213 void _storeExpressionInfo (
61126214 Expression expression, ExpressionInfo <Type > expressionInfo) {
61136215 _expressionWithInfo = expression;
@@ -6116,6 +6218,12 @@ class _FlowAnalysisImpl<Node extends Object, Statement extends Node,
61166218
61176219 /// Associates [expression] , which should be the most recently visited
61186220 /// expression, with the given [expressionReference] object.
6221+ ///
6222+ /// This method serves the same role as [_storeExpressionInfo] , but it only
6223+ /// handles expressions that might refer to something promotable (a get of a
6224+ /// local variable or a property), so it is less likely to have trouble if the
6225+ /// client doesn't visit AST nodes in the proper order (see
6226+ /// https://github.com/dart-lang/sdk/issues/56887).
61196227 void _storeExpressionReference (
61206228 Expression expression, _Reference <Type > expressionReference) {
61216229 _expressionWithReference = expression;
@@ -7150,6 +7258,13 @@ abstract class _PropertyTargetHelper<Expression extends Object,
71507258 /// Gets the [_Reference] associated with the [expression] (which should be
71517259 /// the last expression that was traversed). If there is no [_Reference]
71527260 /// associated with the [expression] , then `null` is returned.
7261+ ///
7262+ /// This method serves the same role as
7263+ /// [_FlowAnalysisImpl._getExpressionInfo] , but it only handles expressions
7264+ /// that might refer to something promotable (a get of a local variable or a
7265+ /// property), so it is less likely to have trouble if the client doesn't
7266+ /// visit AST nodes in the proper order (see
7267+ /// https://github.com/dart-lang/sdk/issues/56887).
71537268 _Reference <Type >? _getExpressionReference (Expression ? expression);
71547269}
71557270
0 commit comments