@@ -385,7 +385,7 @@ main() {
385385 test ('FutureOr matches FutureOr with constraints based on arguments' , () {
386386 // `FutureOr<T> <# FutureOr<int>` reduces to `T <# int`
387387 var tcg = _TypeConstraintGatherer ({'T' });
388- check (tcg.performSubtypeConstraintGenerationForFutureOr (
388+ check (tcg.performSubtypeConstraintGenerationForRightFutureOr (
389389 Type ('FutureOr<T>' ), Type ('FutureOr<int>' ),
390390 leftSchema: false , astNodeForTesting: Node .placeholder ()))
391391 .isTrue ();
@@ -396,7 +396,7 @@ main() {
396396 () {
397397 // `FutureOr<int> <# FutureOr<String>` reduces to `int <# String`
398398 var tcg = _TypeConstraintGatherer ({});
399- check (tcg.performSubtypeConstraintGenerationForFutureOr (
399+ check (tcg.performSubtypeConstraintGenerationForRightFutureOr (
400400 Type ('FutureOr<int>' ), Type ('FutureOr<String>' ),
401401 leftSchema: false , astNodeForTesting: Node .placeholder ()))
402402 .isFalse ();
@@ -412,7 +412,7 @@ main() {
412412 // In cases where both branches produce a constraint, the "Future" branch
413413 // is favored.
414414 var tcg = _TypeConstraintGatherer ({'T' });
415- check (tcg.performSubtypeConstraintGenerationForFutureOr (
415+ check (tcg.performSubtypeConstraintGenerationForRightFutureOr (
416416 Type ('Future<int>' ), Type ('FutureOr<T>' ),
417417 leftSchema: false , astNodeForTesting: Node .placeholder ()))
418418 .isTrue ();
@@ -428,7 +428,7 @@ main() {
428428 // In cases where only one branch produces a constraint, that branch is
429429 // favored.
430430 var tcg = _TypeConstraintGatherer ({'T' });
431- check (tcg.performSubtypeConstraintGenerationForFutureOr (
431+ check (tcg.performSubtypeConstraintGenerationForRightFutureOr (
432432 Type ('Future<_>' ), Type ('FutureOr<T>' ),
433433 leftSchema: true , astNodeForTesting: Node .placeholder ()))
434434 .isTrue ();
@@ -444,18 +444,48 @@ main() {
444444 // In cases where both branches produce a constraint, the "Future" branch
445445 // is favored.
446446 var tcg = _TypeConstraintGatherer ({'T' });
447- check (tcg.performSubtypeConstraintGenerationForFutureOr (
447+ check (tcg.performSubtypeConstraintGenerationForRightFutureOr (
448448 Type ('T' ), Type ('FutureOr<int>' ),
449449 leftSchema: false , astNodeForTesting: Node .placeholder ()))
450450 .isTrue ();
451451 check (tcg._constraints).deepEquals (['T <: Future<int>' ]);
452452 });
453453
454+ test ('Testing FutureOr as the lower bound of the constraint' , () {
455+ var tcg = _TypeConstraintGatherer ({'T' });
456+ check (tcg.performSubtypeConstraintGenerationForLeftFutureOr (
457+ Type ('FutureOr<T>' ), Type ('dynamic' ),
458+ leftSchema: false , astNodeForTesting: Node .placeholder ()))
459+ .isTrue ();
460+ check (tcg._constraints).deepEquals (['T <: dynamic' ]);
461+ });
462+
463+ test ('FutureOr does not match Future in general' , () {
464+ // `FutureOr<P0> <# Q` if `Future<P0> <# Q` and `P0 <# Q`. This test case
465+ // verifies that if `Future<P0> <# Q` matches but `P0 <# Q` does not, then
466+ // the match fails.
467+ var tcg = _TypeConstraintGatherer ({'T' });
468+ check (tcg.performSubtypeConstraintGenerationForLeftFutureOr (
469+ Type ('FutureOr<(T,)>' ), Type ('Future<(int,)>' ),
470+ leftSchema: false , astNodeForTesting: Node .placeholder ()))
471+ .isFalse ();
472+ check (tcg._constraints).isEmpty ();
473+ });
474+
475+ test ('Testing nested FutureOr as the lower bound of the constraint' , () {
476+ var tcg = _TypeConstraintGatherer ({'T' });
477+ check (tcg.performSubtypeConstraintGenerationForLeftFutureOr (
478+ Type ('FutureOr<FutureOr<T>>' ), Type ('FutureOr<dynamic>' ),
479+ leftSchema: false , astNodeForTesting: Node .placeholder ()))
480+ .isTrue ();
481+ check (tcg._constraints).deepEquals (['T <: dynamic' , 'T <: dynamic' ]);
482+ });
483+
454484 test ('Future matches FutureOr with no constraints' , () {
455485 // `Future<int> <# FutureOr<int>` matches (taking the "Future" branch of
456486 // the FutureOr) without generating any constraints.
457487 var tcg = _TypeConstraintGatherer ({});
458- check (tcg.performSubtypeConstraintGenerationForFutureOr (
488+ check (tcg.performSubtypeConstraintGenerationForRightFutureOr (
459489 Type ('Future<int>' ), Type ('FutureOr<int>' ),
460490 leftSchema: false , astNodeForTesting: Node .placeholder ()))
461491 .isTrue ();
@@ -467,7 +497,7 @@ main() {
467497 // "non-Future" branch of the FutureOr, so the constraint `T <: int` is
468498 // produced.
469499 var tcg = _TypeConstraintGatherer ({'T' });
470- check (tcg.performSubtypeConstraintGenerationForFutureOr (
500+ check (tcg.performSubtypeConstraintGenerationForRightFutureOr (
471501 Type ('List<T>' ), Type ('FutureOr<List<int>>' ),
472502 leftSchema: false , astNodeForTesting: Node .placeholder ()))
473503 .isTrue ();
@@ -477,7 +507,7 @@ main() {
477507 group ('Nullable FutureOr on RHS:' , () {
478508 test ('Does not match, according to spec' , () {
479509 var tcg = _TypeConstraintGatherer ({'T' });
480- check (tcg.performSubtypeConstraintGenerationForFutureOr (
510+ check (tcg.performSubtypeConstraintGenerationForRightFutureOr (
481511 Type ('FutureOr<T>' ), Type ('FutureOr<int>?' ),
482512 leftSchema: false , astNodeForTesting: Node .placeholder ()))
483513 .isFalse ();
@@ -487,7 +517,7 @@ main() {
487517 test ('Matches, according to CFE discrepancy' , () {
488518 var tcg = _TypeConstraintGatherer ({'T' },
489519 enableDiscrepantObliviousnessOfNullabilitySuffixOfFutureOr: true );
490- check (tcg.performSubtypeConstraintGenerationForFutureOr (
520+ check (tcg.performSubtypeConstraintGenerationForRightFutureOr (
491521 Type ('FutureOr<T>' ), Type ('FutureOr<int>?' ),
492522 leftSchema: false , astNodeForTesting: Node .placeholder ()))
493523 .isTrue ();
@@ -498,7 +528,7 @@ main() {
498528 group ('Nullable FutureOr on LHS:' , () {
499529 test ('Does not match, according to spec' , () {
500530 var tcg = _TypeConstraintGatherer ({'T' });
501- check (tcg.performSubtypeConstraintGenerationForFutureOr (
531+ check (tcg.performSubtypeConstraintGenerationForRightFutureOr (
502532 Type ('FutureOr<T>?' ), Type ('FutureOr<int>' ),
503533 leftSchema: false , astNodeForTesting: Node .placeholder ()))
504534 .isFalse ();
@@ -508,7 +538,7 @@ main() {
508538 test ('Matches, according to CFE discrepancy' , () {
509539 var tcg = _TypeConstraintGatherer ({'T' },
510540 enableDiscrepantObliviousnessOfNullabilitySuffixOfFutureOr: true );
511- check (tcg.performSubtypeConstraintGenerationForFutureOr (
541+ check (tcg.performSubtypeConstraintGenerationForRightFutureOr (
512542 Type ('FutureOr<T>?' ), Type ('FutureOr<int>' ),
513543 leftSchema: false , astNodeForTesting: Node .placeholder ()))
514544 .isTrue ();
@@ -844,6 +874,7 @@ class _TypeConstraintGatherer extends TypeConstraintGenerator<Type,
844874 case (PrimaryType (name: 'int' ), 'String' ):
845875 case (PrimaryType (name: 'List' ), 'Future' ):
846876 case (PrimaryType (name: 'String' ), 'int' ):
877+ case (PrimaryType (name: 'Future' ), 'String' ):
847878 // Unrelated types
848879 return null ;
849880 default :
@@ -891,16 +922,32 @@ class _TypeConstraintGatherer extends TypeConstraintGenerator<Type,
891922 return true ;
892923 }
893924
925+ if (performSubtypeConstraintGenerationForRightFutureOr (p, q,
926+ leftSchema: leftSchema, astNodeForTesting: astNodeForTesting)) {
927+ return true ;
928+ }
929+
894930 if (performSubtypeConstraintGenerationForRightNullableType (p, q,
895931 leftSchema: leftSchema, astNodeForTesting: astNodeForTesting)) {
896932 return true ;
897933 }
898934
935+ if (performSubtypeConstraintGenerationForLeftFutureOr (p, q,
936+ leftSchema: leftSchema, astNodeForTesting: astNodeForTesting)) {
937+ return true ;
938+ }
939+
899940 if (performSubtypeConstraintGenerationForLeftNullableType (p, q,
900941 leftSchema: leftSchema, astNodeForTesting: astNodeForTesting)) {
901942 return true ;
902943 }
903944
945+ if (q is SharedDynamicTypeStructure ||
946+ q is SharedVoidTypeStructure ||
947+ q == typeAnalyzerOperations.objectQuestionType.unwrapTypeView ()) {
948+ return true ;
949+ }
950+
904951 bool ? result = performSubtypeConstraintGenerationForTypeDeclarationTypes (
905952 p, q,
906953 leftSchema: leftSchema, astNodeForTesting: astNodeForTesting);
0 commit comments