Report PATTERN_NEVER_MATCHES_VALUE_TYPE for RecordType(s).
Change-Id: I9ade865ae8cd86f97b41d862c30876a31ee32b51
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/294620
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
diff --git a/pkg/analyzer/lib/src/dart/element/type_system.dart b/pkg/analyzer/lib/src/dart/element/type_system.dart
index 0da7997..73c0839 100644
--- a/pkg/analyzer/lib/src/dart/element/type_system.dart
+++ b/pkg/analyzer/lib/src/dart/element/type_system.dart
@@ -238,6 +238,51 @@
}
}
+ if (left is RecordType) {
+ if (right is FunctionType) {
+ return false;
+ }
+ if (right is InterfaceType) {
+ return right.isDartCoreObject || right.isDartCoreRecord;
+ }
+ }
+
+ if (right is RecordType) {
+ if (left is FunctionType) {
+ return false;
+ }
+ if (left is InterfaceType) {
+ return left.isDartCoreObject || left.isDartCoreRecord;
+ }
+ }
+
+ if (left is RecordType && right is RecordType) {
+ if (left.positionalFields.length != right.positionalFields.length) {
+ return false;
+ }
+ for (var i = 0; i < left.positionalFields.length; i++) {
+ final leftField = left.positionalFields[i];
+ final rightField = right.positionalFields[i];
+ if (!canBeSubtypeOf(leftField.type, rightField.type)) {
+ return false;
+ }
+ }
+
+ if (left.namedFields.length != right.namedFields.length) {
+ return false;
+ }
+ for (var i = 0; i < left.namedFields.length; i++) {
+ final leftField = left.namedFields[i];
+ final rightField = right.namedFields[i];
+ if (leftField.name != rightField.name) {
+ return false;
+ }
+ if (!canBeSubtypeOf(leftField.type, rightField.type)) {
+ return false;
+ }
+ }
+ }
+
return true;
}
diff --git a/pkg/analyzer/test/src/diagnostics/pattern_never_matches_value_type_test.dart b/pkg/analyzer/test/src/diagnostics/pattern_never_matches_value_type_test.dart
index 3d3fd96..70a4496 100644
--- a/pkg/analyzer/test/src/diagnostics/pattern_never_matches_value_type_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/pattern_never_matches_value_type_test.dart
@@ -49,6 +49,16 @@
''');
}
+ test_functionType_recordType() async {
+ await assertErrorsInCode('''
+void f(void Function() x) {
+ if (x case (int,) _) {}
+}
+''', [
+ error(WarningCode.PATTERN_NEVER_MATCHES_VALUE_TYPE, 41, 8),
+ ]);
+ }
+
test_functionTypeQuestion_interfaceType_object() async {
await assertNoErrorsInCode('''
void f(void Function()? x) {
@@ -398,6 +408,34 @@
''');
}
+ test_interfaceType_recordType() async {
+ await assertErrorsInCode('''
+void f(A x) {
+ if (x case (A,) _) {}
+}
+
+class A {}
+''', [
+ error(WarningCode.PATTERN_NEVER_MATCHES_VALUE_TYPE, 27, 6),
+ ]);
+ }
+
+ test_interfaceType_recordType_object() async {
+ await assertNoErrorsInCode('''
+void f(Object x) {
+ if (x case (int,) _) {}
+}
+''');
+ }
+
+ test_interfaceType_recordType_record() async {
+ await assertNoErrorsInCode('''
+void f(Record x) {
+ if (x case (int,) _) {}
+}
+''');
+ }
+
test_matchedEnum_requiredDifferentEnum() async {
await assertErrorsInCode('''
void f(A x) {
@@ -564,6 +602,111 @@
]);
}
+ test_recordType2_named_differentCount() async {
+ await assertErrorsInCode('''
+void f(({int f1,}) x) {
+ if (x case ({int f1, int f2,}) _) {}
+}
+''', [
+ error(WarningCode.PATTERN_NEVER_MATCHES_VALUE_TYPE, 37, 21),
+ ]);
+ }
+
+ test_recordType2_named_differentNames() async {
+ await assertErrorsInCode('''
+void f(({int a, int b}) x) {
+ if (x case ({int f1, int f2,}) _) {}
+}
+''', [
+ error(WarningCode.PATTERN_NEVER_MATCHES_VALUE_TYPE, 42, 21),
+ ]);
+ }
+
+ test_recordType2_named_unrelated() async {
+ await assertErrorsInCode('''
+void f(({A f1,}) x) {
+ if (x case ({R f1,}) _) {}
+}
+
+final class A {}
+class R {}
+''', [
+ error(WarningCode.PATTERN_NEVER_MATCHES_VALUE_TYPE, 35, 11),
+ ]);
+ }
+
+ test_recordType2_positional_canMatch() async {
+ await assertNoErrorsInCode('''
+void f((A,) x) {
+ if (x case (B,) _) {}
+}
+
+class A {}
+class B {}
+''');
+ }
+
+ test_recordType2_positional_differentCount() async {
+ await assertErrorsInCode('''
+void f((int,) x) {
+ if (x case (int, String) _) {}
+}
+''', [
+ error(WarningCode.PATTERN_NEVER_MATCHES_VALUE_TYPE, 32, 15),
+ ]);
+ }
+
+ test_recordType2_positional_unrelated() async {
+ await assertErrorsInCode('''
+void f((A,) x) {
+ if (x case (R,) _) {}
+}
+
+final class A {}
+class R {}
+''', [
+ error(WarningCode.PATTERN_NEVER_MATCHES_VALUE_TYPE, 30, 6),
+ ]);
+ }
+
+ test_recordType_functionType() async {
+ await assertErrorsInCode('''
+void f((int,) x) {
+ if (x case void Function() _) {}
+}
+''', [
+ error(WarningCode.PATTERN_NEVER_MATCHES_VALUE_TYPE, 32, 17),
+ ]);
+ }
+
+ test_recordType_interfaceType() async {
+ await assertErrorsInCode('''
+void f((A,) x) {
+ if (x case A _) {}
+}
+
+class A {}
+''', [
+ error(WarningCode.PATTERN_NEVER_MATCHES_VALUE_TYPE, 30, 3),
+ ]);
+ }
+
+ test_recordType_interfaceType_object() async {
+ await assertNoErrorsInCode('''
+void f((int,)? x) {
+ if (x case Object _) {}
+}
+''');
+ }
+
+ test_recordType_interfaceType_record() async {
+ await assertNoErrorsInCode('''
+void f((int,)? x) {
+ if (x case Record _) {}
+}
+''');
+ }
+
test_refutable_pattern_castPattern_match() async {
await assertNoErrorsInCode('''
void f(num x) {