Flow analysis: additional debug support.
I've found these changes helpful as part of developing the new "field
promotion" feature. These changes have no effect unless the
`FlowAnalysisDebug` class is used.
Bug: https://github.com/dart-lang/language/issues/2020
Change-Id: I7badadc14bf901e77b8c166920aedf902093d7e1
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/250220
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Commit-Queue: Paul Berry <paulberry@google.com>
diff --git a/pkg/_fe_analyzer_shared/lib/src/flow_analysis/flow_analysis.dart b/pkg/_fe_analyzer_shared/lib/src/flow_analysis/flow_analysis.dart
index 3256bdc..d91b11e 100644
--- a/pkg/_fe_analyzer_shared/lib/src/flow_analysis/flow_analysis.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/flow_analysis/flow_analysis.dart
@@ -1032,6 +1032,10 @@
class FlowAnalysisDebug<Node extends Object, Statement extends Node,
Expression extends Object, Variable extends Object, Type extends Object>
implements FlowAnalysis<Node, Statement, Expression, Variable, Type> {
+ static int _nextCallbackId = 0;
+
+ static Expando<String> _description = new Expando<String>();
+
FlowAnalysis<Node, Statement, Expression, Variable, Type> _wrapped;
bool _exceptionOccurred = false;
@@ -1538,16 +1542,18 @@
@override
Map<Type, NonPromotionReason> Function() whyNotPromoted(Expression target) {
- return _wrap(
- 'whyNotPromoted($target)', () => _wrapped.whyNotPromoted(target),
+ return _wrap('whyNotPromoted($target)',
+ () => _trackWhyNotPromoted(_wrapped.whyNotPromoted(target)),
isQuery: true);
}
@override
Map<Type, NonPromotionReason> Function() whyNotPromotedImplicitThis(
Type staticType) {
- return _wrap('whyNotPromotedImplicitThis($staticType)',
- () => _wrapped.whyNotPromotedImplicitThis(staticType),
+ return _wrap(
+ 'whyNotPromotedImplicitThis($staticType)',
+ () => _trackWhyNotPromoted(
+ _wrapped.whyNotPromotedImplicitThis(staticType)),
isQuery: true);
}
@@ -1561,6 +1567,19 @@
@override
void _dumpState() => _wrapped._dumpState();
+ /// Wraps [callback] so that when it is called, the call (and its return
+ /// value) will be printed to the console. Also registers the wrapped
+ /// callback in [_description] so that it will be given a unique identifier
+ /// when printed to the console.
+ Map<Type, NonPromotionReason> Function() _trackWhyNotPromoted(
+ Map<Type, NonPromotionReason> Function() callback) {
+ String callbackToString = '#CALLBACK${_nextCallbackId++}';
+ Map<Type, NonPromotionReason> Function() wrappedCallback =
+ () => _wrap('$callbackToString()', callback, isQuery: true);
+ _description[wrappedCallback] = callbackToString;
+ return wrappedCallback;
+ }
+
T _wrap<T>(String description, T callback(),
{bool isQuery: false, bool? isPure}) {
isPure ??= isQuery;
@@ -1578,10 +1597,18 @@
_wrapped._dumpState();
}
if (isQuery) {
- print(' => $result');
+ print(' => ${_describe(result)}');
}
return result;
}
+
+ static String _describe(Object? value) {
+ if (value != null && value is! String && value is! num && value is! bool) {
+ String? description = _description[value];
+ if (description != null) return description;
+ }
+ return value.toString();
+ }
}
/// An instance of the [FlowModel] class represents the information gathered by
@@ -2613,6 +2640,9 @@
final Type type;
ReferenceWithType(this.reference, this.type);
+
+ @override
+ String toString() => 'ReferenceWithType($reference, $type)';
}
/// Data structure representing a unique value that a variable might take on
@@ -2859,6 +2889,9 @@
if (nonPromotionHistory != null) {
parts.add('nonPromotionHistory: $nonPromotionHistory');
}
+ if (properties.isNotEmpty) {
+ parts.add('properties: $properties');
+ }
return 'VariableModel(${parts.join(', ')})';
}
@@ -3358,6 +3391,9 @@
}
@override
+ String toString() => 'VariableReference($variable)';
+
+ @override
VariableModel<Variable, Type>? _getInfo(
Map<Variable?, VariableModel<Variable, Type>> variableInfo) =>
variableInfo[variable];
@@ -5026,6 +5062,10 @@
}
@override
+ String toString() =>
+ '_PropertyGetReference($target, $propertyName, $propertyMember)';
+
+ @override
VariableModel<Variable, Type>? _getInfo(
Map<Variable?, VariableModel<Variable, Type>> variableInfo) {
VariableModel<Variable, Type> targetInfo = target.getInfo(variableInfo);