Support the remaining user-defined binary operators
Change-Id: I796495489605a903330169ff964a3ed296b2783a
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/106722
Reviewed-by: Dan Rubel <danrubel@google.com>
Reviewed-by: Paul Berry <paulberry@google.com>
Commit-Queue: Brian Wilkerson <brianwilkerson@google.com>
diff --git a/pkg/nnbd_migration/lib/src/graph_builder.dart b/pkg/nnbd_migration/lib/src/graph_builder.dart
index 0bd79a9..30029c3 100644
--- a/pkg/nnbd_migration/lib/src/graph_builder.dart
+++ b/pkg/nnbd_migration/lib/src/graph_builder.dart
@@ -195,43 +195,41 @@
@override
DecoratedType visitBinaryExpression(BinaryExpression node) {
- switch (node.operator.type) {
- case TokenType.EQ_EQ:
- case TokenType.BANG_EQ:
- assert(node.leftOperand is! NullLiteral); // TODO(paulberry)
- var leftType = node.leftOperand.accept(this);
- node.rightOperand.accept(this);
- if (node.rightOperand is NullLiteral) {
- // TODO(paulberry): figure out what the rules for isPure should be.
- // TODO(paulberry): only set falseChecksNonNull in unconditional
- // control flow
- bool isPure = node.leftOperand is SimpleIdentifier;
- var conditionInfo = _ConditionInfo(node,
- isPure: isPure,
- trueGuard: leftType.node,
- falseDemonstratesNonNullIntent: leftType.node);
- _conditionInfo = node.operator.type == TokenType.EQ_EQ
- ? conditionInfo
- : conditionInfo.not(node);
- }
- return _nonNullableBoolType;
- case TokenType.PLUS:
- _handleAssignment(_notNullType, node.leftOperand);
- var callee = node.staticElement;
- assert(!(callee is ClassMemberElement &&
- callee.enclosingElement.typeParameters
- .isNotEmpty)); // TODO(paulberry)
- assert(callee != null); // TODO(paulberry)
- var calleeType = getOrComputeElementType(callee);
- // TODO(paulberry): substitute if necessary
- assert(calleeType.positionalParameters.length > 0); // TODO(paulberry)
- _handleAssignment(
- calleeType.positionalParameters[0], node.rightOperand);
- return calleeType.returnType;
- default:
- // TODO(paulberry)
- _unimplemented(
- node, 'Binary expression with operator ${node.operator.lexeme}');
+ var operatorType = node.operator.type;
+ if (operatorType == TokenType.EQ_EQ || operatorType == TokenType.BANG_EQ) {
+ assert(node.leftOperand is! NullLiteral); // TODO(paulberry)
+ var leftType = node.leftOperand.accept(this);
+ node.rightOperand.accept(this);
+ if (node.rightOperand is NullLiteral) {
+ // TODO(paulberry): figure out what the rules for isPure should be.
+ // TODO(paulberry): only set falseChecksNonNull in unconditional
+ // control flow
+ bool isPure = node.leftOperand is SimpleIdentifier;
+ var conditionInfo = _ConditionInfo(node,
+ isPure: isPure,
+ trueGuard: leftType.node,
+ falseDemonstratesNonNullIntent: leftType.node);
+ _conditionInfo = operatorType == TokenType.EQ_EQ
+ ? conditionInfo
+ : conditionInfo.not(node);
+ }
+ return _nonNullableBoolType;
+ } else if (operatorType.isUserDefinableOperator) {
+ _handleAssignment(_notNullType, node.leftOperand);
+ var callee = node.staticElement;
+ assert(!(callee is ClassMemberElement &&
+ callee
+ .enclosingElement.typeParameters.isNotEmpty)); // TODO(paulberry)
+ assert(callee != null); // TODO(paulberry)
+ var calleeType = getOrComputeElementType(callee);
+ // TODO(paulberry): substitute if necessary
+ assert(calleeType.positionalParameters.length > 0); // TODO(paulberry)
+ _handleAssignment(calleeType.positionalParameters[0], node.rightOperand);
+ return calleeType.returnType;
+ } else {
+ // TODO(paulberry)
+ _unimplemented(
+ node, 'Binary expression with operator ${node.operator.lexeme}');
}
}
diff --git a/pkg/nnbd_migration/test/graph_builder_test.dart b/pkg/nnbd_migration/test/graph_builder_test.dart
index 71cd99b..0bc9ba1 100644
--- a/pkg/nnbd_migration/test/graph_builder_test.dart
+++ b/pkg/nnbd_migration/test/graph_builder_test.dart
@@ -286,7 +286,111 @@
assertNoUpstreamNullability(decoratedTypeAnnotation('int').node);
}
- test_binaryExpression_add_left_check() async {
+ test_binaryExpression_ampersand_result_not_null() async {
+ await analyze('''
+int f(int i, int j) => i & j;
+''');
+
+ assertNoUpstreamNullability(decoratedTypeAnnotation('int f').node);
+ }
+
+ test_binaryExpression_bar_result_not_null() async {
+ await analyze('''
+int f(int i, int j) => i | j;
+''');
+
+ assertNoUpstreamNullability(decoratedTypeAnnotation('int f').node);
+ }
+
+ test_binaryExpression_caret_result_not_null() async {
+ await analyze('''
+int f(int i, int j) => i ^ j;
+''');
+
+ assertNoUpstreamNullability(decoratedTypeAnnotation('int f').node);
+ }
+
+ test_binaryExpression_equal() async {
+ await analyze('''
+bool f(int i, int j) => i == j;
+''');
+
+ assertNoUpstreamNullability(decoratedTypeAnnotation('bool f').node);
+ }
+
+ test_binaryExpression_gt_result_not_null() async {
+ await analyze('''
+bool f(int i, int j) => i > j;
+''');
+
+ assertNoUpstreamNullability(decoratedTypeAnnotation('bool f').node);
+ }
+
+ test_binaryExpression_gtEq_result_not_null() async {
+ await analyze('''
+bool f(int i, int j) => i >= j;
+''');
+
+ assertNoUpstreamNullability(decoratedTypeAnnotation('bool f').node);
+ }
+
+ test_binaryExpression_gtGt_result_not_null() async {
+ await analyze('''
+int f(int i, int j) => i >> j;
+''');
+
+ assertNoUpstreamNullability(decoratedTypeAnnotation('int f').node);
+ }
+
+ test_binaryExpression_lt_result_not_null() async {
+ await analyze('''
+bool f(int i, int j) => i < j;
+''');
+
+ assertNoUpstreamNullability(decoratedTypeAnnotation('bool f').node);
+ }
+
+ test_binaryExpression_ltEq_result_not_null() async {
+ await analyze('''
+bool f(int i, int j) => i <= j;
+''');
+
+ assertNoUpstreamNullability(decoratedTypeAnnotation('bool f').node);
+ }
+
+ test_binaryExpression_ltLt_result_not_null() async {
+ await analyze('''
+int f(int i, int j) => i << j;
+''');
+
+ assertNoUpstreamNullability(decoratedTypeAnnotation('int f').node);
+ }
+
+ test_binaryExpression_minus_result_not_null() async {
+ await analyze('''
+int f(int i, int j) => i - j;
+''');
+
+ assertNoUpstreamNullability(decoratedTypeAnnotation('int f').node);
+ }
+
+ test_binaryExpression_notEqual() async {
+ await analyze('''
+bool f(int i, int j) => i != j;
+''');
+
+ assertNoUpstreamNullability(decoratedTypeAnnotation('bool f').node);
+ }
+
+ test_binaryExpression_percent_result_not_null() async {
+ await analyze('''
+int f(int i, int j) => i % j;
+''');
+
+ assertNoUpstreamNullability(decoratedTypeAnnotation('int f').node);
+ }
+
+ test_binaryExpression_plus_left_check() async {
await analyze('''
int f(int i, int j) => i + j;
''');
@@ -295,7 +399,7 @@
assertEdge(decoratedTypeAnnotation('int i').node, never, hard: true));
}
- test_binaryExpression_add_left_check_custom() async {
+ test_binaryExpression_plus_left_check_custom() async {
await analyze('''
class Int {
Int operator+(Int other) => this;
@@ -307,7 +411,7 @@
assertEdge(decoratedTypeAnnotation('Int i').node, never, hard: true));
}
- test_binaryExpression_add_result_custom() async {
+ test_binaryExpression_plus_result_custom() async {
await analyze('''
class Int {
Int operator+(Int other) => this;
@@ -322,7 +426,7 @@
hard: false));
}
- test_binaryExpression_add_result_not_null() async {
+ test_binaryExpression_plus_result_not_null() async {
await analyze('''
int f(int i, int j) => i + j;
''');
@@ -330,7 +434,7 @@
assertNoUpstreamNullability(decoratedTypeAnnotation('int f').node);
}
- test_binaryExpression_add_right_check() async {
+ test_binaryExpression_plus_right_check() async {
await analyze('''
int f(int i, int j) => i + j;
''');
@@ -339,7 +443,7 @@
assertEdge(decoratedTypeAnnotation('int j').node, never, hard: true));
}
- test_binaryExpression_add_right_check_custom() async {
+ test_binaryExpression_plus_right_check_custom() async {
await analyze('''
class Int {
Int operator+(Int other) => this;
@@ -354,12 +458,28 @@
hard: true));
}
- test_binaryExpression_equal() async {
+ test_binaryExpression_slash_result_not_null() async {
await analyze('''
-bool f(int i, int j) => i == j;
+double f(int i, int j) => i / j;
''');
- assertNoUpstreamNullability(decoratedTypeAnnotation('bool f').node);
+ assertNoUpstreamNullability(decoratedTypeAnnotation('double f').node);
+ }
+
+ test_binaryExpression_star_result_not_null() async {
+ await analyze('''
+int f(int i, int j) => i * j;
+''');
+
+ assertNoUpstreamNullability(decoratedTypeAnnotation('int f').node);
+ }
+
+ test_binaryExpression_tildeSlash_result_not_null() async {
+ await analyze('''
+int f(int i, int j) => i ~/ j;
+''');
+
+ assertNoUpstreamNullability(decoratedTypeAnnotation('int f').node);
}
test_boolLiteral() async {