Issue 54686. Fix canBeSubtypeOf() for FutureOr and records.
Bug: https://github.com/dart-lang/sdk/issues/54686 Change-Id: Idbacac0b114f0b84d1703fb1454e0165ea5be69b Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/347643 Reviewed-by: Phil Quitslund <pquitslund@google.com> Reviewed-by: Samuel Rawlins <srawlins@google.com> Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
This commit is contained in:
committed by
Commit Queue
parent
155df2fdbd
commit
4983ea79be
@@ -182,6 +182,22 @@ class TypeSystemImpl implements TypeSystem {
|
||||
return left.isDartCoreFunction || left.isDartCoreObject;
|
||||
}
|
||||
|
||||
// FutureOr<T> = T || Future<T>
|
||||
// So, we attempt to match both to the right.
|
||||
if (left.isDartAsyncFutureOr) {
|
||||
final base = futureOrBase(left);
|
||||
final future = typeProvider.futureType(base);
|
||||
return canBeSubtypeOf(base, right) || canBeSubtypeOf(future, right);
|
||||
}
|
||||
|
||||
// FutureOr<T> = T || Future<T>
|
||||
// So, we attempt to match both to the left.
|
||||
if (right.isDartAsyncFutureOr) {
|
||||
final base = futureOrBase(right);
|
||||
final future = typeProvider.futureType(base);
|
||||
return canBeSubtypeOf(left, base) || canBeSubtypeOf(left, future);
|
||||
}
|
||||
|
||||
if (left is InterfaceTypeImpl && right is InterfaceTypeImpl) {
|
||||
final leftElement = left.element;
|
||||
final rightElement = right.element;
|
||||
@@ -192,22 +208,6 @@ class TypeSystemImpl implements TypeSystem {
|
||||
return true;
|
||||
}
|
||||
|
||||
// FutureOr<T> = T || Future<T>
|
||||
// So, we attempt to match both to the right.
|
||||
if (left.isDartAsyncFutureOr) {
|
||||
final base = futureOrBase(left);
|
||||
final future = typeProvider.futureType(base);
|
||||
return canBeSubtypeOf(base, right) || canBeSubtypeOf(future, right);
|
||||
}
|
||||
|
||||
// FutureOr<T> = T || Future<T>
|
||||
// So, we attempt to match both to the left.
|
||||
if (right.isDartAsyncFutureOr) {
|
||||
final base = futureOrBase(right);
|
||||
final future = typeProvider.futureType(base);
|
||||
return canBeSubtypeOf(left, base) || canBeSubtypeOf(left, future);
|
||||
}
|
||||
|
||||
bool canBeSubtypeOfInterfaces(InterfaceType left, InterfaceType right) {
|
||||
assert(left.element == right.element);
|
||||
final leftArguments = left.typeArguments;
|
||||
|
||||
@@ -858,6 +858,72 @@ enum E<T> { v1<int>(), v2<double>() }
|
||||
]);
|
||||
}
|
||||
|
||||
test_matchedFutureOrRecord_requiredFutureRecord_match() async {
|
||||
await assertNoErrorsInCode('''
|
||||
import 'dart:async';
|
||||
|
||||
void f(FutureOr<(int,)> x) {
|
||||
if (x case Future<(int,)> _) {}
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
test_matchedFutureOrRecord_requiredFutureRecord_notMatch() async {
|
||||
await assertErrorsInCode('''
|
||||
import 'dart:async';
|
||||
|
||||
void f(FutureOr<(int,)> x) {
|
||||
if (x case Future<(String,)> _) {}
|
||||
}
|
||||
''', [
|
||||
error(WarningCode.PATTERN_NEVER_MATCHES_VALUE_TYPE, 64, 17),
|
||||
]);
|
||||
}
|
||||
|
||||
test_matchedFutureOrRecord_requiredRecord_match() async {
|
||||
await assertNoErrorsInCode('''
|
||||
import 'dart:async';
|
||||
|
||||
void f(FutureOr<(int,)> x) {
|
||||
if (x case (int,) _) {}
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
test_matchedFutureOrRecord_requiredRecord_notMatch() async {
|
||||
await assertErrorsInCode('''
|
||||
import 'dart:async';
|
||||
|
||||
void f(FutureOr<(int,)> x) {
|
||||
if (x case (String,) _) {}
|
||||
}
|
||||
''', [
|
||||
error(WarningCode.PATTERN_NEVER_MATCHES_VALUE_TYPE, 64, 9),
|
||||
]);
|
||||
}
|
||||
|
||||
test_matchedFutureRecord_requiredFutureOrRecord_match() async {
|
||||
await assertNoErrorsInCode('''
|
||||
import 'dart:async';
|
||||
|
||||
void f(Future<(int,)> x) {
|
||||
if (x case FutureOr<(int,)> _) {}
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
test_matchedFutureRecord_requiredFutureOrRecord_notMatch() async {
|
||||
await assertErrorsInCode('''
|
||||
import 'dart:async';
|
||||
|
||||
void f(Future<(int,)> x) {
|
||||
if (x case FutureOr<(String,)> _) {}
|
||||
}
|
||||
''', [
|
||||
error(WarningCode.PATTERN_NEVER_MATCHES_VALUE_TYPE, 62, 19),
|
||||
]);
|
||||
}
|
||||
|
||||
test_matchedNull_requiredNotNullable() async {
|
||||
await assertErrorsInCode('''
|
||||
void f(Null x) {
|
||||
@@ -888,6 +954,28 @@ void f(Null x) {
|
||||
]);
|
||||
}
|
||||
|
||||
test_matchedRecord_requiredFutureOrRecord_match() async {
|
||||
await assertNoErrorsInCode('''
|
||||
import 'dart:async';
|
||||
|
||||
void f((int,) x) {
|
||||
if (x case FutureOr<(int,)> _) {}
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
test_matchedRecord_requiredFutureOrRecord_notMatch() async {
|
||||
await assertErrorsInCode('''
|
||||
import 'dart:async';
|
||||
|
||||
void f((int,) x) {
|
||||
if (x case FutureOr<(String,)> _) {}
|
||||
}
|
||||
''', [
|
||||
error(WarningCode.PATTERN_NEVER_MATCHES_VALUE_TYPE, 54, 19),
|
||||
]);
|
||||
}
|
||||
|
||||
test_recordType2_named_differentCount() async {
|
||||
await assertErrorsInCode('''
|
||||
void f(({int f1,}) x) {
|
||||
|
||||
Reference in New Issue
Block a user