Fix handling of &&, || and ?? operators
Change-Id: Ibfe574f381af701932cf30f5fdd77fe50a7c8158
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/106961
Reviewed-by: Paul Berry <paulberry@google.com>
Commit-Queue: Brian Wilkerson <brianwilkerson@google.com>
diff --git a/pkg/nnbd_migration/lib/src/edge_origin.dart b/pkg/nnbd_migration/lib/src/edge_origin.dart
index 487edc1..4b38fa7 100644
--- a/pkg/nnbd_migration/lib/src/edge_origin.dart
+++ b/pkg/nnbd_migration/lib/src/edge_origin.dart
@@ -34,6 +34,11 @@
EdgeOriginWithLocation(this.source, this.offset);
}
+/// Edge origin resulting from the presence of a `??` operator.
+class IfNullOrigin extends EdgeOriginWithLocation {
+ IfNullOrigin(Source source, int offset) : super(source, offset);
+}
+
/// Edge origin resulting from a class that is instantiated to bounds.
///
/// For example, in the following code snippet:
diff --git a/pkg/nnbd_migration/lib/src/graph_builder.dart b/pkg/nnbd_migration/lib/src/graph_builder.dart
index a6942d2..412a3ba 100644
--- a/pkg/nnbd_migration/lib/src/graph_builder.dart
+++ b/pkg/nnbd_migration/lib/src/graph_builder.dart
@@ -215,11 +215,26 @@
}
return _nonNullableBoolType;
} else if (operatorType == TokenType.AMPERSAND_AMPERSAND ||
- operatorType == TokenType.BAR_BAR ||
- operatorType == TokenType.QUESTION_QUESTION) {
+ operatorType == TokenType.BAR_BAR) {
_handleAssignment(_notNullType, node.leftOperand);
- node.rightOperand.accept(this);
+ _handleAssignment(_notNullType, node.rightOperand);
return _nonNullableBoolType;
+ } else if (operatorType == TokenType.QUESTION_QUESTION) {
+ DecoratedType expressionType;
+ var leftType = node.leftOperand.accept(this);
+ try {
+ _guards.add(leftType.node);
+ var rightType = node.rightOperand.accept(this);
+ var ifNullNode = NullabilityNode.forIfNotNull();
+ expressionType = DecoratedType(node.staticType, ifNullNode);
+ _graph.connect(rightType.node, expressionType.node,
+ IfNullOrigin(_source, node.offset),
+ guards: _guards);
+ } finally {
+ _guards.removeLast();
+ }
+ _variables.recordDecoratedExpressionType(node, expressionType);
+ return expressionType;
} else if (operatorType.isUserDefinableOperator) {
_handleAssignment(_notNullType, node.leftOperand);
var callee = node.staticElement;
diff --git a/pkg/nnbd_migration/lib/src/nullability_node.dart b/pkg/nnbd_migration/lib/src/nullability_node.dart
index 6e02eb2..6e7d02d 100644
--- a/pkg/nnbd_migration/lib/src/nullability_node.dart
+++ b/pkg/nnbd_migration/lib/src/nullability_node.dart
@@ -302,6 +302,11 @@
final _upstreamEdges = <NullabilityEdge>[];
/// Creates a [NullabilityNode] representing the nullability of a variable
+ /// whose type is determined by the `??` operator.
+ factory NullabilityNode.forIfNotNull() =>
+ _NullabilityNodeSimple('?? operator');
+
+ /// Creates a [NullabilityNode] representing the nullability of a variable
/// whose type is `dynamic` due to type inference.
///
/// TODO(paulberry): this should go away; we should decorate the actual
diff --git a/pkg/nnbd_migration/test/graph_builder_test.dart b/pkg/nnbd_migration/test/graph_builder_test.dart
index d9a7a43..7835703 100644
--- a/pkg/nnbd_migration/test/graph_builder_test.dart
+++ b/pkg/nnbd_migration/test/graph_builder_test.dart
@@ -479,7 +479,10 @@
int f(int i, int j) => i ?? j;
''');
- assertNoUpstreamNullability(decoratedTypeAnnotation('int i').node);
+ var left = decoratedTypeAnnotation('int i').node;
+ var right = decoratedTypeAnnotation('int j').node;
+ var expression = decoratedExpressionType('??').node;
+ assertEdge(right, expression, guards: [left], hard: false);
}
test_binaryExpression_slash_result_not_null() async {