Skip to content

Commit e34e734

Browse files
[nnbd_migration] track causations for substitution nodes
Change-Id: I7da4f2923d9b99b0bd6c16644a7adeaeda437340 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/125463 Reviewed-by: Paul Berry <[email protected]>
1 parent 7905e78 commit e34e734

5 files changed

Lines changed: 65 additions & 19 deletions

File tree

pkg/analysis_server/lib/src/edit/nnbd_migration/info_builder.dart

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,26 @@ class InfoBuilder {
9191
return units;
9292
}
9393

94+
Iterable<EdgeInfo> upstreamTriggeredEdges(NullabilityNodeInfo node,
95+
[List<RegionDetail> details]) {
96+
var edges = <EdgeInfo>[];
97+
for (EdgeInfo edge in node.upstreamEdges) {
98+
if (node.isExactNullable && edge.sourceNode.isExactNullable) {
99+
// When an exact nullable points here, the nullability propagated
100+
// in the other direction.
101+
continue;
102+
}
103+
if (edge.isTriggered) {
104+
edges.add(edge);
105+
}
106+
}
107+
for (final containerNode in node.outerCompoundNodes) {
108+
edges.addAll(upstreamTriggeredEdges(containerNode, details));
109+
}
110+
111+
return edges;
112+
}
113+
94114
/// Return detail text for a fix built from an edge with [node] as a
95115
/// destination.
96116
String _baseDescriptionForOrigin(
@@ -294,21 +314,14 @@ class InfoBuilder {
294314
}
295315
}
296316

297-
for (EdgeInfo edge in reason.upstreamEdges) {
298-
if (edge.sourceNode.isExactNullable) {
299-
// When an exact nullable points here, the nullability propagated
300-
// in the other direction.
301-
continue;
302-
}
303-
if (edge.isTriggered) {
304-
EdgeOriginInfo origin = info.edgeOrigin[edge];
305-
if (origin != null) {
306-
details.add(_buildDetailForOrigin(
307-
origin, edge, fixInfo.fix.description.kind));
308-
} else {
309-
details.add(
310-
RegionDetail('upstream edge with no origin ($edge)', null));
311-
}
317+
for (EdgeInfo edge in upstreamTriggeredEdges(reason)) {
318+
EdgeOriginInfo origin = info.edgeOrigin[edge];
319+
if (origin != null) {
320+
details.add(_buildDetailForOrigin(
321+
origin, edge, fixInfo.fix.description.kind));
322+
} else {
323+
details.add(
324+
RegionDetail('upstream edge with no origin ($edge)', null));
312325
}
313326
}
314327
} else if (reason is EdgeInfo) {

pkg/analysis_server/test/src/edit/nnbd_migration/info_builder_test.dart

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -208,8 +208,9 @@ void g() {
208208
List<RegionInfo> regions = unit.regions;
209209
expect(regions, hasLength(3));
210210
// regions[0] is the hard edge that f's parameter is non-nullable.
211-
// TODO(mfairhurst): Diagnose why no detail is appearing here.
212-
// assertRegion(region: regions[1], offset: 15, details: ["Null is assigned"]);
211+
assertRegion(region: regions[1], offset: 15, details: [
212+
"An explicit 'null' is assigned",
213+
]);
213214
assertRegion(
214215
region: regions[2],
215216
offset: 66,

pkg/nnbd_migration/lib/instrumentation.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,9 @@ abstract class NullabilityMigrationInstrumentation {
233233
/// Information exposed to the migration client about a single node in the
234234
/// nullability graph.
235235
abstract class NullabilityNodeInfo implements FixReasonInfo {
236+
/// List of compound nodes wrapping this node.
237+
final List<NullabilityNodeInfo> outerCompoundNodes = <NullabilityNodeInfo>[];
238+
236239
/// Some nodes get nullability from downstream, so the downstream edges are
237240
/// available to query as well.
238241
Iterable<EdgeInfo> get downstreamEdges;

pkg/nnbd_migration/lib/src/nullability_node.dart

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,8 @@ class NullabilityGraph {
360360
for (var edge in node._upstreamEdges) {
361361
pendingEdges.add(edge);
362362
}
363+
364+
// TODO(mfairhurst): should this propagate back up outerContainerNodes?
363365
}
364366
}
365367
while (pendingEdges.isNotEmpty) {
@@ -460,6 +462,9 @@ abstract class NullabilityNode implements NullabilityNodeInfo {
460462
/// List of edges that have this node as their destination.
461463
final _upstreamEdges = <NullabilityEdge>[];
462464

465+
/// List of compound nodes wrapping this node.
466+
final List<NullabilityNode> outerCompoundNodes = <NullabilityNode>[];
467+
463468
/// Creates a [NullabilityNode] representing the nullability of a variable
464469
/// whose type comes from an already-migrated library.
465470
factory NullabilityNode.forAlreadyMigrated() =>
@@ -583,7 +588,10 @@ class NullabilityNodeForLUB extends _NullabilityNodeCompound {
583588

584589
final NullabilityNode right;
585590

586-
NullabilityNodeForLUB._(this.left, this.right);
591+
NullabilityNodeForLUB._(this.left, this.right) {
592+
left.outerCompoundNodes.add(this);
593+
right.outerCompoundNodes.add(this);
594+
}
587595

588596
@override
589597
Iterable<NullabilityNode> get _components => [left, right];
@@ -602,7 +610,10 @@ class NullabilityNodeForSubstitution extends _NullabilityNodeCompound
602610
@override
603611
final NullabilityNode outerNode;
604612

605-
NullabilityNodeForSubstitution._(this.innerNode, this.outerNode);
613+
NullabilityNodeForSubstitution._(this.innerNode, this.outerNode) {
614+
innerNode.outerCompoundNodes.add(this);
615+
outerNode.outerCompoundNodes.add(this);
616+
}
606617

607618
@override
608619
Iterable<NullabilityNode> get _components => [innerNode, outerNode];

pkg/nnbd_migration/test/nullability_node_test.dart

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,15 @@ class NullabilityNodeTest {
106106
assertUnsatisfied([]);
107107
}
108108

109+
test_lubNode_relatesInBothDirections() {
110+
final nodeA = newNode(1);
111+
final nodeB = newNode(2);
112+
final lubNode = lub(nodeA, nodeB);
113+
114+
expect(nodeA.outerCompoundNodes, [lubNode]);
115+
expect(nodeB.outerCompoundNodes, [lubNode]);
116+
}
117+
109118
test_never_source() {
110119
// never -> 1
111120
var n1 = newNode(1);
@@ -600,6 +609,15 @@ class NullabilityNodeTest {
600609
expect(subst(n1, null), same(n1));
601610
}
602611

612+
test_substitutionNode_relatesInBothDirections() {
613+
final nodeA = newNode(1);
614+
final nodeB = newNode(2);
615+
final substNode = subst(nodeA, nodeB);
616+
617+
expect(nodeA.outerCompoundNodes, [substNode]);
618+
expect(nodeB.outerCompoundNodes, [substNode]);
619+
}
620+
603621
test_unconstrainted_node_non_nullable() {
604622
var n1 = newNode(1);
605623
propagate();

0 commit comments

Comments
 (0)