blob: fc0b9b82a16c4fe46e842bb1f559966bda63e962 [file] [log] [blame]
// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import "package:expect/expect.dart" show Expect;
import "package:kernel/type_environment.dart";
abstract class SubtypeTest<T, E> {
void isSubtype(String subtypeString, String supertypeString,
{String? typeParameters}) {
E environment = extend(typeParameters);
T subtype = toType(subtypeString, environment);
T supertype = toType(supertypeString, environment);
Expect.isTrue(
isSubtypeImpl(subtype, supertype).isSubtypeWhenUsingNullabilities(),
"$subtypeString should be a subtype of ${supertypeString}, "
"regardless of whether the nullability modifiers are ignored or not.");
}
void isNotSubtype(String subtypeString, String supertypeString,
{String? typeParameters}) {
E environment = extend(typeParameters);
T subtype = toType(subtypeString, environment);
T supertype = toType(supertypeString, environment);
Expect.isFalse(
isSubtypeImpl(subtype, supertype).isSubtypeWhenIgnoringNullabilities(),
"$subtypeString shouldn't be a subtype of $supertypeString, "
"regardless of whether the nullability modifiers are ignored or not.");
}
/// Checks if a type is a subtype of the other ignoring nullability modifiers.
void isObliviousSubtype(String subtypeString, String supertypeString,
{String? typeParameters}) {
E environment = extend(typeParameters);
T subtype = toType(subtypeString, environment);
T supertype = toType(supertypeString, environment);
IsSubtypeOf result = isSubtypeImpl(subtype, supertype);
Expect.isFalse(
result.isSubtypeWhenUsingNullabilities(),
"$subtypeString should be a subtype of $supertypeString "
"only if the nullability modifiers are ignored.");
Expect.isFalse(
!result.isSubtypeWhenIgnoringNullabilities(),
"$subtypeString should be a subtype of $supertypeString "
"if the nullability modifiers are ignored.");
}
bool get skipFutureOrPromotion => false;
T toType(String text, E environment);
IsSubtypeOf isSubtypeImpl(T subtype, T supertype);
E extend(String? typeParameters);
void run() {
// Tests for subtypes and supertypes of num.
isSubtype('int*', 'num*');
isSubtype('int*', 'Comparable<num*>*');
isSubtype('int*', 'Comparable<Object*>*');
isSubtype('int*', 'Object*');
isSubtype('double*', 'num*');
isSubtype('num', 'Object');
isSubtype('num*', 'Object');
isSubtype('Null', 'num*');
isSubtype('Null', 'num?');
isSubtype('Never', 'num');
isSubtype('Never', 'num*');
isSubtype('Never', 'num?');
isNotSubtype('int*', 'double*');
isNotSubtype('int*', 'Comparable<int*>*');
isNotSubtype('int*', 'Iterable<int*>*');
isNotSubtype('Comparable<int*>*', 'Iterable<int*>*');
isObliviousSubtype('num?', 'Object');
isObliviousSubtype('Null', 'num');
isNotSubtype('num', 'Never');
// Tests for subtypes and supertypes of List.
isSubtype('List<int*>*', 'List<int*>*');
isSubtype('List<int*>*', 'Iterable<int*>*');
isSubtype('List<int*>*', 'List<num*>*');
isSubtype('List<int*>*', 'Iterable<num*>*');
isSubtype('List<int*>*', 'List<Object*>*');
isSubtype('List<int*>*', 'Iterable<Object*>*');
isSubtype('List<int*>*', 'Object*');
isSubtype('List<int*>*', 'List<Comparable<Object*>*>*');
isSubtype('List<int*>*', 'List<Comparable<num*>*>*');
isSubtype('List<int*>*', 'List<Comparable<Comparable<num*>*>*>*');
isSubtype('List<int*>', 'Object');
isSubtype('List<int*>*', 'Object');
isSubtype('Null', 'List<int*>*');
isSubtype('Null', 'List<int*>?');
isSubtype('Never', 'List<int*>');
isSubtype('Never', 'List<int*>*');
isSubtype('Never', 'List<int*>?');
isSubtype('List<int>', 'List<int>');
isSubtype('List<int>', 'List<int>*');
isSubtype('List<int>', 'List<int>?');
isSubtype('List<int>*', 'List<int>');
isSubtype('List<int>*', 'List<int>*');
isSubtype('List<int>*', 'List<int>?');
isObliviousSubtype('List<int>?', 'List<int>');
isSubtype('List<int>?', 'List<int>*');
isSubtype('List<int>?', 'List<int>?');
isSubtype('List<int>', 'List<int*>');
isSubtype('List<int>', 'List<int?>');
// TODO(dmitryas): Uncomment the following when type arguments are allowed
// to be intersection types.
// isSubtype('List<X & int>', 'List<X>',
// typeParameters: 'X extends Object?');
isSubtype('List<int*>', 'List<int>');
isSubtype('List<int*>', 'List<int*>');
isSubtype('List<int*>', 'List<int?>');
isObliviousSubtype('List<int?>', 'List<int>');
isSubtype('List<int?>', 'List<int*>');
isSubtype('List<int?>', 'List<int?>');
// TODO(dmitryas): Uncomment the following when type arguments are allowed
// to be intersection types.
// isSubtype('List<X & int?>', 'List<X>',
// typeParameters: 'X extends Object?');
isNotSubtype('List<int*>*', 'List<double*>*');
isNotSubtype('List<int*>*', 'Iterable<double*>*');
isNotSubtype('List<int*>*', 'Comparable<int*>*');
isNotSubtype('List<int*>*', 'List<Comparable<int*>*>*');
isNotSubtype('List<int*>*', 'List<Comparable<Comparable<int*>*>*>*');
isObliviousSubtype('List<int*>?', 'Object');
isObliviousSubtype('Null', 'List<int*>');
isNotSubtype('List<int*>', 'Never');
isObliviousSubtype('T?', 'List<int>',
typeParameters: 'T extends List<int>');
// Tests for non-generic one-argument function types.
isSubtype('(num*) ->* num*', '(int*) ->* num*');
isSubtype('(num*) ->* int*', '(num*) ->* num*');
isSubtype('(num*) ->* int*', '(int*) ->* num*');
isNotSubtype('(int*) ->* int*', '(num*) ->* num*');
isSubtype('Null', '(int*) ->* num*');
isSubtype('Null', '(int*) ->? num*');
isSubtype('Never', '(int*) -> num*');
isSubtype('Never', '(int*) ->* num*');
isSubtype('Never', '(int*) ->? num*');
isSubtype('(num*) ->* num*', 'Object');
isSubtype('(num*) -> num*', 'Object');
isObliviousSubtype('(num*) ->? num*', 'Object');
isObliviousSubtype('Null', '(int*) -> num*');
isNotSubtype('(int*) -> num*', 'Never');
isNotSubtype('num', '(num) -> num');
isNotSubtype('Object', '(num) -> num');
isNotSubtype('Object*', '(num) -> num');
isNotSubtype('Object?', '(num) -> num');
isNotSubtype('dynamic', '(num) -> num');
isSubtype('(num) -> num', '(num) ->* num');
isSubtype('(num) ->* num', '(num) -> num');
isSubtype('(num) ->? num', '(num) ->* num');
isSubtype('(num) ->* num', '(num) ->? num');
isSubtype('(num) -> num', '(num) ->? num');
isObliviousSubtype('(num) ->? num', '(num) -> num');
isSubtype('(num) -> num', '(num) -> num?');
isSubtype('(num?) -> num', '(num) -> num');
isSubtype('(num?) -> num', '(num) -> num?');
isObliviousSubtype('(num) -> num', '(num?) -> num?');
// Tests for non-generic two-argument curried function types.
isSubtype('(num*) ->* (num*) ->* num*', '(num*) ->* (int*) ->* num*');
isNotSubtype('(num*) ->* (int*) ->* int*', '(num*) ->* (num*) ->* num*');
// Tests for non-generic one-argument function types with named parameters.
isSubtype('({num* x}) ->* num*', '({int* x}) ->* num*');
isSubtype('(num*, {num* x}) ->* num*', '(int*, {int* x}) ->* num*');
isSubtype('({num* x}) ->* int*', '({num* x}) ->* num*');
isNotSubtype('({int* x}) ->* int*', '({num* x}) ->* num*');
isSubtype('({num x}) -> num', '({num x}) -> num?');
isSubtype('({num? x}) -> num', '({num x}) -> num');
isSubtype('({num? x}) -> num', '({num x}) -> num?');
isObliviousSubtype('({num x}) -> num', '({num? x}) -> num?');
// Tests for non-generic one-argument function types with optional
// positional parameters.
isSubtype('([num]) -> num', '([num]) -> num?');
isSubtype('([num?]) -> num', '([num]) -> num');
isSubtype('([num?]) -> num', '([num]) -> num?');
isObliviousSubtype('([num]) -> num', '([num?]) -> num?');
// Tests for function types with type parameters.
isSubtype('<E>(E) ->* int*', '<E>(E) ->* num*');
isSubtype('<E>(num*) ->* E', '<E>(int*) ->* E');
isSubtype('<E>(E,num*) ->* E', '<E>(E,int*) ->* E');
isNotSubtype('<E>(E,num*) ->* E', '<E>(E,E) ->* E');
// Tests for curried function types with type parameters.
isSubtype('<E>(E) ->* (E) ->* E', '<F>(F) ->* (F) ->* F');
isSubtype('<E>(E, (int*,E) ->* E) ->* E', '<E>(E, (int*,E) ->* E) ->* E');
isSubtype('<E>(E, (int*,E) ->* E) ->* E', '<E>(E, (num*,E) ->* E) ->* E');
isNotSubtype('<E,F>(E) ->* (F) ->* E', '<E>(E) ->* <F>(F) ->* E');
isNotSubtype('<E,F>(E) ->* (F) ->* E', '<F,E>(E) ->* (F) ->* E');
isNotSubtype('<E>(E,num*) ->* E', '<E extends num*>(E*,E*) ->* E*');
isNotSubtype(
'<E extends num*>(E*) ->* int*', '<E extends int*>(E*) ->* int*');
isNotSubtype('<E extends num*>(E*) ->* E*', '<E extends int*>(E*) ->* E*');
isNotSubtype(
'<E extends num*>(int*) ->* E*', '<E extends int*>(int*) ->* E*');
isSubtype('<E extends num*>(E*) ->* E*', '<F extends num*>(F*) ->* num*');
isSubtype('<E extends int*>(E*) ->* E*', '<F extends int*>(F*) ->* num*');
isSubtype('<E extends int*>(E*) ->* E*', '<F extends int*>(F*) ->* int*');
isNotSubtype('<E>(int*) ->* int*', '(int*) ->* int*');
isNotSubtype('<E,F>(int*) ->* int*', '<E>(int*) ->* int*');
// Tests for generic function types with bounded type parameters.
isSubtype(
'<E extends List<E*>*>(E*) ->* E*', '<F extends List<F*>*>(F*) ->* F*');
isNotSubtype('<E extends Iterable<E*>*>(E*) ->* E*',
'<F extends List<F*>*>(F*) ->* F*');
isNotSubtype(
'<E>(E,List<Object*>*) ->* E*', '<F extends List<F*>*>(F*,F*) ->* F*');
isNotSubtype('<E>(E,List<Object*>*) ->* List<E>*',
'<F extends List<F*>*>(F*,F*) ->* F*');
isNotSubtype('<E>(E,List<Object*>*) ->* int*',
'<F extends List<F*>*>(F*,F*) ->* F*');
isNotSubtype(
'<E>(E,List<Object*>*) ->* E', '<F extends List<F*>*>(F*,F*) ->* void');
isSubtype('<E extends num>(E) -> E', '<F extends num*>(F*) -> F*');
isSubtype('<E extends num*>(E*) -> E*', '<F extends num>(F) -> F');
isSubtype('<E extends num?>(E) -> E', '<F extends num*>(F*) -> F*');
isSubtype('<E extends num*>(E*) -> E*', '<F extends num?>(F) -> F');
isObliviousSubtype('<E extends num>(E) -> E', '<F extends num?>(F) -> F');
// Tests for FutureOr.
isSubtype('int*', 'FutureOr<int*>*');
isSubtype('int*', 'FutureOr<num*>*');
isSubtype('Future<int*>*', 'FutureOr<int*>*');
isSubtype('Future<int*>*', 'FutureOr<num*>*');
isSubtype('Future<int*>*', 'FutureOr<Object*>*');
isSubtype('FutureOr<int*>*', 'FutureOr<int*>*');
isSubtype('FutureOr<int*>*', 'Object*');
isSubtype('Null', 'FutureOr<num?>');
isSubtype('Null', 'FutureOr<num>?');
isSubtype('num?', 'FutureOr<num?>');
isSubtype('num?', 'FutureOr<num>?');
isSubtype('Future<num>', 'FutureOr<num?>');
isSubtype('Future<num>', 'FutureOr<num>?');
isSubtype('Future<num>', 'FutureOr<num?>?');
isSubtype('Future<num?>', 'FutureOr<num?>');
isObliviousSubtype('Future<num?>', 'FutureOr<num>?');
isObliviousSubtype('FutureOr<int>?', 'FutureOr<int>');
isObliviousSubtype('Future<int>?', 'FutureOr<int>');
isSubtype('Future<num?>', 'FutureOr<num?>?');
isSubtype('FutureOr<X>', 'FutureOr<Future<X>>',
typeParameters: 'X extends Future<Future<X>>');
isSubtype('FutureOr<int*>*', 'FutureOr<num*>*');
isSubtype('FutureOr<A>', 'FutureOr<B>', typeParameters: 'B,A extends B');
isSubtype('X', 'FutureOr<int>',
typeParameters: 'X extends FutureOr<int*>*');
isSubtype('X*', 'FutureOr<int>',
typeParameters: 'X extends FutureOr<int*>*');
isSubtype('num?', 'FutureOr<FutureOr<FutureOr<num>>?>');
isSubtype('Future<num>?', 'FutureOr<FutureOr<FutureOr<num>>?>');
isSubtype('Future<Future<num>>?', 'FutureOr<FutureOr<FutureOr<num>>?>');
isSubtype(
'Future<Future<Future<num>>>?', 'FutureOr<FutureOr<FutureOr<num>>?>');
isSubtype('Future<num>?', 'FutureOr<FutureOr<FutureOr<num?>>>');
isSubtype('Future<Future<num>>?', 'FutureOr<FutureOr<FutureOr<num?>>>');
isSubtype(
'Future<Future<Future<num>>>?', 'FutureOr<FutureOr<FutureOr<num?>>>');
isSubtype('Future<num?>?', 'FutureOr<FutureOr<FutureOr<num?>>>');
isSubtype('Future<Future<num?>?>?', 'FutureOr<FutureOr<FutureOr<num?>>>');
isSubtype('Future<Future<Future<num?>?>?>?',
'FutureOr<FutureOr<FutureOr<num?>>>');
isSubtype('FutureOr<num>?', 'FutureOr<num?>');
isObliviousSubtype('FutureOr<num?>', 'FutureOr<num>?');
isSubtype('List<FutureOr<List<dynamic>>>',
'List<FutureOr<List<FutureOr<dynamic>>>>');
isSubtype('List<FutureOr<List<FutureOr<dynamic>>>>',
'List<FutureOr<List<dynamic>>>');
isSubtype('X', 'FutureOr<List<X>>',
typeParameters: 'X extends FutureOr<List<X>>');
isNotSubtype('X', 'FutureOr<List<X>>',
typeParameters: 'X extends List<FutureOr<X>>');
isSubtype('dynamic', 'FutureOr<Object?>');
isSubtype('dynamic', 'FutureOr<Object>?');
isSubtype('void', 'FutureOr<Object?>');
isSubtype('void', 'FutureOr<Object>?');
isSubtype('Object*', 'FutureOr<Object?>');
isSubtype('Object*', 'FutureOr<Object>?');
isSubtype('Object?', 'FutureOr<Object?>');
isSubtype('Object?', 'FutureOr<Object>?');
isSubtype('Object', 'FutureOr<Object?>');
isSubtype('Object', 'FutureOr<Object>?');
isObliviousSubtype('dynamic', 'FutureOr<Object>');
isObliviousSubtype('void', 'FutureOr<Object>');
isObliviousSubtype('Object?', 'FutureOr<Object>');
isSubtype('Object', 'FutureOr<Object>');
isSubtype('FutureOr<int>', 'Object');
isSubtype('FutureOr<int>', 'Object*');
isSubtype('FutureOr<int>', 'Object?');
isSubtype('FutureOr<int>*', 'Object');
isSubtype('FutureOr<int>*', 'Object*');
isSubtype('FutureOr<int>*', 'Object?');
isObliviousSubtype('FutureOr<int>?', 'Object');
isSubtype('FutureOr<int>?', 'Object*');
isSubtype('FutureOr<int>?', 'Object?');
isSubtype('FutureOr<int*>', 'Object');
isSubtype('FutureOr<int*>', 'Object*');
isSubtype('FutureOr<int*>', 'Object?');
isObliviousSubtype('FutureOr<int?>', 'Object');
isSubtype('FutureOr<int?>', 'Object*');
isSubtype('FutureOr<int?>', 'Object?');
isSubtype('FutureOr<Future<Object>>', 'Future<Object>');
isObliviousSubtype('FutureOr<Future<Object>>?', 'Future<Object>');
isObliviousSubtype('FutureOr<Future<Object>?>', 'Future<Object>');
isObliviousSubtype('FutureOr<Future<Object>?>?', 'Future<Object>');
isNotSubtype('int*', 'FutureOr<double*>*');
isNotSubtype('FutureOr<double*>*', 'int*');
isNotSubtype('FutureOr<int*>*', 'Future<num*>*');
isNotSubtype('FutureOr<int*>*', 'num*');
isSubtype('Null', 'FutureOr<int*>*');
isSubtype('Null', 'Future<int*>*');
isSubtype('dynamic', 'FutureOr<dynamic>*');
isNotSubtype('dynamic', 'FutureOr<String*>*');
isSubtype('void', 'FutureOr<void>*');
isNotSubtype('void', 'FutureOr<String*>*');
isSubtype('E*', 'FutureOr<E*>*', typeParameters: 'E extends Object*');
isSubtype('E?', 'FutureOr<E>?', typeParameters: 'E extends Object');
isSubtype('E?', 'FutureOr<E?>', typeParameters: 'E extends Object');
isSubtype('E', 'FutureOr<E>?', typeParameters: 'E extends Object?');
isSubtype('E', 'FutureOr<E?>', typeParameters: 'E extends Object?');
isObliviousSubtype('E?', 'FutureOr<E>', typeParameters: 'E extends Object');
isSubtype('E', 'FutureOr<E>', typeParameters: 'E extends Object?');
isNotSubtype('E*', 'FutureOr<String*>*',
typeParameters: 'E extends Object*');
isSubtype('E?', 'FutureOr<String>?', typeParameters: 'E extends String');
isSubtype('E?', 'FutureOr<String?>', typeParameters: 'E extends String');
isSubtype('E', 'FutureOr<String>?', typeParameters: 'E extends String?');
isSubtype('E', 'FutureOr<String?>', typeParameters: 'E extends String?');
isObliviousSubtype('E?', 'FutureOr<String>',
typeParameters: 'E extends String');
isObliviousSubtype('E', 'FutureOr<String>',
typeParameters: 'E extends String?');
isSubtype('X', 'X', typeParameters: 'X extends num?');
isSubtype('FutureOr<X>', 'FutureOr<X>', typeParameters: 'X extends num?');
isSubtype('FutureOr<FutureOr<X>>', 'FutureOr<FutureOr<X>>',
typeParameters: 'X extends num?');
isSubtype('FutureOr<X>', 'FutureOr<FutureOr<X>>',
typeParameters: 'X extends num?');
isSubtype('() ->* String*', 'FutureOr<() ->* void>*');
isSubtype('() -> String', 'FutureOr<() -> void>');
isSubtype('() -> String', 'FutureOr<() ->? void>');
isSubtype('() -> String', 'FutureOr<() -> void>?');
isSubtype('() ->? String', 'FutureOr<() ->? void>');
isSubtype('() ->? String', 'FutureOr<() -> void>?');
isObliviousSubtype('() ->? String', 'FutureOr<() -> void>');
isObliviousSubtype('() ->? String', 'FutureOr<() -> void>');
isNotSubtype('() ->* void', 'FutureOr<() ->* String>*');
isSubtype('FutureOr<int*>*', 'FutureOr<num*>*');
isNotSubtype('FutureOr<num*>*', 'FutureOr<int*>*');
isSubtype('T* & int*', 'FutureOr<num*>*',
typeParameters: 'T extends Object*');
isSubtype('T & int', 'FutureOr<num>', typeParameters: 'T extends Object');
isSubtype('T & int', 'FutureOr<num?>', typeParameters: 'T extends Object');
isSubtype('T & int', 'FutureOr<num>?', typeParameters: 'T extends Object');
isSubtype('T & int', 'FutureOr<num>', typeParameters: 'T extends Object?');
isSubtype('T & int', 'FutureOr<num?>', typeParameters: 'T extends Object?');
isSubtype('T & int', 'FutureOr<num>?', typeParameters: 'T extends Object?');
isObliviousSubtype('T & int?', 'FutureOr<num>',
typeParameters: 'T extends Object?');
isSubtype('T & int?', 'FutureOr<num?>',
typeParameters: 'T extends Object?');
isSubtype('T & int?', 'FutureOr<num>?',
typeParameters: 'T extends Object?');
isObliviousSubtype('T & S', 'FutureOr<Object>',
typeParameters: 'T extends Object?, S extends T');
isSubtype('T & S', 'FutureOr<Object?>',
typeParameters: 'T extends Object?, S extends T');
isSubtype('T & S', 'FutureOr<Object>?',
typeParameters: 'T extends Object?, S extends T');
isSubtype('T* & Future<num*>*', 'FutureOr<num*>*',
typeParameters: 'T extends Object*');
isSubtype('T* & Future<int*>*', 'FutureOr<num*>*',
typeParameters: 'T extends Object*');
isSubtype('T & Future<int>', 'FutureOr<num>',
typeParameters: 'T extends Object');
isSubtype('T & Future<int>', 'FutureOr<num?>',
typeParameters: 'T extends Object');
isSubtype('T & Future<int>', 'FutureOr<num>?',
typeParameters: 'T extends Object');
isSubtype('T & Future<int>', 'FutureOr<num>',
typeParameters: 'T extends Object?');
isSubtype('T & Future<int>', 'FutureOr<num?>',
typeParameters: 'T extends Object?');
isSubtype('T & Future<int>', 'FutureOr<num>?',
typeParameters: 'T extends Object?');
isObliviousSubtype('T & Future<int>?', 'FutureOr<num>',
typeParameters: 'T extends Object?');
isSubtype('T & Future<int>?', 'FutureOr<num?>',
typeParameters: 'T extends Object?');
isSubtype('T & Future<int>?', 'FutureOr<num>?',
typeParameters: 'T extends Object?');
isObliviousSubtype('T & Future<int?>', 'FutureOr<num>',
typeParameters: 'T extends Object');
isSubtype('T & Future<int?>', 'FutureOr<num?>',
typeParameters: 'T extends Object');
isObliviousSubtype('T & Future<int?>', 'FutureOr<num>?',
typeParameters: 'T extends Object');
isNotSubtype('FutureOr<T?>?', 'FutureOr<Never?>?',
typeParameters: 'T extends FutureOr<T?>?');
isSubtype('FutureOr<Never?>?', 'FutureOr<T?>?',
typeParameters: 'T extends FutureOr<T?>?');
if (!skipFutureOrPromotion) {
isSubtype('T & FutureOr<int*>*', 'FutureOr<num*>*', typeParameters: 'T');
isSubtype('T & FutureOr<num*>*', 'FutureOr<num*>*', typeParameters: 'T');
isSubtype('T* & String*', 'FutureOr<num*>*',
typeParameters: 'T extends int*');
isSubtype('T* & Future<String*>*', 'FutureOr<num*>*',
typeParameters: 'T extends Future<num*>*');
isSubtype('T* & FutureOr<String*>*', 'FutureOr<num*>*',
typeParameters: 'T extends FutureOr<int*>*');
isSubtype('T* & FutureOr<String*>*', 'FutureOr<num*>*',
typeParameters: 'T extends FutureOr<num*>*');
isNotSubtype('FutureOr<num>', 'T & FutureOr<num>',
typeParameters: 'T extends FutureOr<num>');
}
isNotSubtype('T & num*', 'FutureOr<int*>*', typeParameters: 'T');
isNotSubtype('T & Future<num*>*', 'FutureOr<int*>*', typeParameters: 'T');
isNotSubtype('T & FutureOr<num*>*', 'FutureOr<int*>*', typeParameters: 'T');
isNotSubtype('T* & String*', 'FutureOr<int*>*',
typeParameters: 'T extends num*');
isNotSubtype('T* & Future<String*>*', 'FutureOr<int*>*',
typeParameters: 'T extends Future<num*>*');
isNotSubtype('T* & FutureOr<String*>*', 'FutureOr<int*>*',
typeParameters: 'T extends FutureOr<num*>*');
isSubtype('Id<int*>*', 'FutureOr<num*>*');
isSubtype('Id<int>', 'FutureOr<num>');
isObliviousSubtype('Id<int?>', 'FutureOr<num>');
isSubtype('Id<int?>', 'FutureOr<num?>');
isSubtype('Id<int?>', 'FutureOr<num>?');
isObliviousSubtype('Id<int>?', 'FutureOr<num>');
isSubtype('Id<int>?', 'FutureOr<num?>');
isSubtype('Id<int>?', 'FutureOr<num>?');
isNotSubtype('Id<num*>*', 'FutureOr<int*>*');
isSubtype('FutureOr<Object*>*', 'FutureOr<FutureOr<Object*>*>*');
isSubtype('FutureOr<num>*', 'Object');
isSubtype('FutureOr<num>', 'Object');
isObliviousSubtype('FutureOr<num>?', 'Object');
isSubtype('Never', 'FutureOr<num>');
isSubtype('Never', 'FutureOr<num*>');
isSubtype('Never', 'FutureOr<num>*');
isSubtype('Never', 'FutureOr<num?>');
isSubtype('Never', 'FutureOr<num>?');
isNotSubtype('FutureOr<num>', 'Never');
// Testing bottom types against an intersection type.
isSubtype('Null', 'T* & num*', typeParameters: 'T extends Object*');
isSubtype('Never', 'T* & num*', typeParameters: 'T extends Object*');
isSubtype('Never', 'T & num', typeParameters: 'T extends Object');
isObliviousSubtype('Null', 'T & num', typeParameters: 'T extends Object?');
isObliviousSubtype('Null', 'T & num?', typeParameters: 'T extends Object?');
isObliviousSubtype('Null', 'T & num', typeParameters: 'T extends Object');
isObliviousSubtype('Null', 'T & S',
typeParameters: 'T extends Object?, S extends T');
isNotSubtype('T* & num*', 'Never', typeParameters: 'T extends Object*');
isSubtype('T', 'Never', typeParameters: 'T extends Never');
isSubtype('T & Never', 'Never', typeParameters: 'T extends Object');
// Testing bottom types against type-parameter types.
isSubtype('Null', 'T?', typeParameters: 'T extends Object');
isSubtype('Null', 'T?', typeParameters: 'T extends Object?');
isObliviousSubtype('Null', 'T', typeParameters: 'T extends Object');
isObliviousSubtype('Null', 'T', typeParameters: 'T extends Object?');
isSubtype('Never', 'T?', typeParameters: 'T extends Object');
isSubtype('Never', 'T?', typeParameters: 'T extends Object?');
isSubtype('Never', 'T', typeParameters: 'T extends Object');
isSubtype('Never', 'T', typeParameters: 'T extends Object?');
isObliviousSubtype('Never?', 'T', typeParameters: 'T extends Object?');
isSubtype('T', 'Null', typeParameters: 'T extends Null');
isSubtype('T?', 'Null', typeParameters: 'T extends Null');
isNotSubtype('T', 'Null', typeParameters: 'T extends Object');
isNotSubtype('T', 'Null', typeParameters: 'T extends Object?');
isSubtype('T', 'Never', typeParameters: 'T extends Never');
isObliviousSubtype('T', 'Never', typeParameters: 'T extends Never?');
isObliviousSubtype('T?', 'Never', typeParameters: 'T extends Never');
isObliviousSubtype('T?', 'Never', typeParameters: 'T extends Never?');
isNotSubtype('T', 'Never', typeParameters: 'T extends Object');
isNotSubtype('T', 'Never', typeParameters: 'T extends Object?');
// Trivial tests for type-parameter types and intersection types.
// T & B <: T & A if B <: A
isSubtype('T* & int*', 'T* & int*', typeParameters: 'T extends Object*');
isSubtype('T* & int*', 'T* & num*', typeParameters: 'T extends Object*');
isSubtype('T* & num*', 'T* & num*', typeParameters: 'T extends Object*');
isNotSubtype('T* & num*', 'T* & int*', typeParameters: 'T extends Object*');
isSubtype('T & int', 'T & num', typeParameters: 'T extends Object');
isSubtype('T & int', 'T & num', typeParameters: 'T extends Object?');
isSubtype('T & int?', 'T & num?', typeParameters: 'T extends Object?');
isObliviousSubtype('T & int?', 'T & num',
typeParameters: 'T extends Object?');
// T & B <: T extends A if B <: A
// (Trivially satisfied since promoted bounds are always a isSubtype of the
// original bound)
isSubtype('T* & int*', 'T*', typeParameters: 'T extends int*');
isSubtype('T* & int*', 'T*', typeParameters: 'T extends num*');
isSubtype('T* & num*', 'T*', typeParameters: 'T extends num*');
// T extends B <: T & A if B <: A
isSubtype('T*', 'T* & int*', typeParameters: 'T extends int*');
isSubtype('T', 'T & int', typeParameters: 'T extends int');
isObliviousSubtype('T?', 'T & int', typeParameters: 'T extends int');
isObliviousSubtype('T', 'T & int', typeParameters: 'T extends int?');
isSubtype('T', 'T & int?', typeParameters: 'T extends int?');
isObliviousSubtype('T?', 'T & int?', typeParameters: 'T extends int?');
isSubtype('T*', 'T* & num*', typeParameters: 'T extends int*');
isSubtype('T', 'T & num', typeParameters: 'T extends int');
isObliviousSubtype('T?', 'T & num', typeParameters: 'T extends int');
isObliviousSubtype('T', 'T & num', typeParameters: 'T extends int?');
isSubtype('T', 'T & num?', typeParameters: 'T extends int?');
isObliviousSubtype('T?', 'T & num?', typeParameters: 'T extends int?');
isSubtype('T*', 'T* & num*', typeParameters: 'T extends num*');
isSubtype('T', 'T & num', typeParameters: 'T extends num');
isObliviousSubtype('T?', 'T & num', typeParameters: 'T extends num');
isObliviousSubtype('T', 'T & num', typeParameters: 'T extends num?');
isSubtype('T', 'T & num?', typeParameters: 'T extends num?');
isObliviousSubtype('T?', 'T & num?', typeParameters: 'T extends num?');
isNotSubtype('T*', 'T* & int*', typeParameters: 'T extends num*');
// T extends A <: T extends A
isSubtype('T*', 'T*', typeParameters: 'T extends num*');
isSubtype('T', 'T', typeParameters: 'T extends num');
isSubtype('T', 'T', typeParameters: 'T extends num?');
isSubtype('T?', 'T?', typeParameters: 'T extends num');
isSubtype('T?', 'T?', typeParameters: 'T extends num?');
isSubtype('T', 'T', typeParameters: 'T');
isNotSubtype('S', 'T', typeParameters: 'S, T');
isSubtype('T*', 'T*', typeParameters: 'T extends Object*');
isNotSubtype('S*', 'T*',
typeParameters: 'S extends Object*, T extends Object*');
isSubtype('T', 'T', typeParameters: 'T extends dynamic');
isNotSubtype('S', 'T',
typeParameters: 'S extends dynamic, T extends dynamic');
// S <: T extends S
isNotSubtype('S', 'T', typeParameters: 'S, T extends S');
isSubtype('T*', 'S*', typeParameters: 'S extends Object*, T extends S*');
isSubtype('T', 'S', typeParameters: 'S extends Object, T extends S');
isSubtype('T', 'S?', typeParameters: 'S extends Object, T extends S');
isObliviousSubtype('T?', 'S',
typeParameters: 'S extends Object, T extends S');
isSubtype('T?', 'S?', typeParameters: 'S extends Object, T extends S');
isSubtype('T', 'S', typeParameters: 'S extends Object?, T extends S');
isSubtype('T', 'S?', typeParameters: 'S extends Object?, T extends S');
isObliviousSubtype('T?', 'S',
typeParameters: 'S extends Object?, T extends S');
isSubtype('T?', 'S?', typeParameters: 'S extends Object?, T extends S');
isObliviousSubtype('T', 'S',
typeParameters: 'S extends Object?, T extends S?');
isSubtype('T', 'S?', typeParameters: 'S extends Object?, T extends S?');
isObliviousSubtype('T?', 'S',
typeParameters: 'S extends Object?, T extends S?');
isSubtype('T?', 'S?', typeParameters: 'S extends Object?, T extends S?');
isObliviousSubtype('T', 'S',
typeParameters: 'S extends Object, T extends S?');
isSubtype('T', 'S?', typeParameters: 'S extends Object, T extends S?');
isObliviousSubtype('T?', 'S',
typeParameters: 'S extends Object, T extends S?');
isSubtype('T?', 'S?', typeParameters: 'S extends Object, T extends S?');
isSubtype('T* & V*', 'S*',
typeParameters: 'S extends Object*, T extends S*, V extends S*');
isSubtype('T & V', 'S',
typeParameters: 'S extends Object, T extends S, V extends S');
isSubtype('T & V?', 'S?',
typeParameters: 'S extends Object, T extends S, V extends S');
isSubtype('T & V', 'S',
typeParameters: 'S extends Object?, T extends S, V extends S');
isSubtype('T & V', 'S',
typeParameters: 'S extends Object?, T extends S?, V extends S');
isObliviousSubtype('T & V', 'S',
typeParameters: 'S extends Object?, T extends S?, V extends S?');
// Non-trivial tests for intersection types.
// S & B <: A if B <: A, A is not S (or a promotion thereof)
isSubtype('S & int*', 'int*', typeParameters: 'S');
isSubtype('S & int*', 'num*', typeParameters: 'S');
isSubtype('S & num*', 'num*', typeParameters: 'S');
isNotSubtype('S & num*', 'int*', typeParameters: 'S');
isNotSubtype('S & num*', 'T', typeParameters: 'S, T');
isNotSubtype('S & num*', 'T & num*', typeParameters: 'S, T');
isSubtype('S & num', 'num', typeParameters: 'S extends Object?');
isObliviousSubtype('S & num?', 'num', typeParameters: 'S extends Object?');
isSubtype('S & num?', 'num?', typeParameters: 'S extends Object?');
isSubtype('S & num?', 'num*', typeParameters: 'S extends Object?');
// S extends B <: A if B <: A, A is not S (or a promotion thereof)
isSubtype('S*', 'int*', typeParameters: 'S extends int*');
isSubtype('S*', 'num*', typeParameters: 'S extends int*');
isSubtype('S*', 'num*', typeParameters: 'S extends num*');
isSubtype('S*', 'Object', typeParameters: 'S extends num*');
isSubtype('S', 'Object', typeParameters: 'S extends num');
isNotSubtype('S*', 'int*', typeParameters: 'S extends num*');
isNotSubtype('S*', 'T', typeParameters: 'S extends num*, T');
isNotSubtype('S*', 'T & num*', typeParameters: 'S extends num*, T');
isObliviousSubtype('S?', 'Object', typeParameters: 'S extends num');
isObliviousSubtype('S', 'Object', typeParameters: 'S extends num?');
isObliviousSubtype('S?', 'Object', typeParameters: 'S extends num?');
isNotSubtype('dynamic', 'int');
isNotSubtype('dynamic', 'int*');
isNotSubtype('dynamic', 'int?');
isNotSubtype('void', 'int');
isNotSubtype('void', 'int*');
isNotSubtype('void', 'int?');
isNotSubtype('Object', 'int');
isNotSubtype('Object', 'int*');
isNotSubtype('Object', 'int?');
isNotSubtype('Object*', 'int');
isNotSubtype('Object*', 'int*');
isNotSubtype('Object*', 'int?');
isNotSubtype('Object?', 'int');
isNotSubtype('Object?', 'int*');
isNotSubtype('Object?', 'int?');
isNotSubtype('() ->* int*', 'int*');
isNotSubtype('Typedef<Object*>*', 'int*');
isSubtype('() -> int*', 'Function');
isSubtype('() -> int*', 'Function*');
isSubtype('() -> int*', 'Function?');
isSubtype('() ->* int*', 'Function');
isSubtype('() ->* int*', 'Function*');
isSubtype('() ->* int*', 'Function?');
isObliviousSubtype('() ->? int*', 'Function');
isSubtype('() ->? int*', 'Function*');
isSubtype('() ->? int*', 'Function?');
isSubtype('() -> int*', 'Object');
isSubtype('() -> int*', 'Object*');
isSubtype('() -> int*', 'Object?');
isSubtype('() ->* int*', 'Object');
isSubtype('() ->* int*', 'Object*');
isSubtype('() ->* int*', 'Object?');
isObliviousSubtype('() ->? int*', 'Object');
isSubtype('() ->? int*', 'Object*');
isSubtype('() ->? int*', 'Object?');
// Tests for "Null".
isSubtype('Null', 'double*');
isSubtype('Null', 'Comparable<Object*>*');
isSubtype('Null', 'Comparable<Object*>?');
isSubtype('Null', 'Typedef<Object*>*');
isSubtype('Null', 'Typedef<Object*>?');
isSubtype('Null', 'T', typeParameters: 'T extends Object*');
isSubtype('Null', 'T?', typeParameters: 'T extends Object');
isObliviousSubtype('Null', 'T', typeParameters: 'T extends Object?');
isObliviousSubtype('Null', 'T', typeParameters: 'T extends Object');
isObliviousSubtype('Null', 'Object');
// Tests for bottom and top types.
isSubtype('Null', 'Null');
isObliviousSubtype('Null', 'Never');
isSubtype('Never', 'Null');
isSubtype('Never', 'Never');
isSubtype('Null', 'Never?');
isSubtype('Never?', 'Null');
isSubtype('Never', 'Never?');
isObliviousSubtype('Never?', 'Never');
isSubtype('Object*', 'Object*');
isSubtype('Object*', 'dynamic');
isSubtype('Object*', 'void');
isSubtype('Object*', 'Object?');
isSubtype('dynamic', 'Object*');
isSubtype('dynamic', 'dynamic');
isSubtype('dynamic', 'void');
isSubtype('dynamic', 'Object?');
isSubtype('void', 'Object*');
isSubtype('void', 'dynamic');
isSubtype('void', 'void');
isSubtype('void', 'Object?');
isSubtype('Object?', 'Object*');
isSubtype('Object?', 'dynamic');
isSubtype('Object?', 'void');
isSubtype('Object?', 'Object?');
isSubtype('Never', 'Object?');
isSubtype('Never', 'Object*');
isSubtype('Never', 'dynamic');
isSubtype('Never', 'void');
isSubtype('Null', 'Object?');
isSubtype('Null', 'Object*');
isSubtype('Null', 'dynamic');
isSubtype('Null', 'void');
isNotSubtype('Object?', 'Never');
isNotSubtype('Object?', 'Null');
isNotSubtype('Object*', 'Never');
isNotSubtype('Object*', 'Null');
isNotSubtype('dynamic', 'Never');
isNotSubtype('dynamic', 'Null');
isNotSubtype('void', 'Never');
isNotSubtype('void', 'Null');
// Tests for Object against the top and the bottom types.
isSubtype('Never', 'Object');
isSubtype('Object', 'dynamic');
isSubtype('Object', 'void');
isSubtype('Object', 'Object?');
isSubtype('Object', 'Object*');
isSubtype('Object*', 'Object');
isNotSubtype('Object', 'Null');
isNotSubtype('Object', 'Never');
isObliviousSubtype('dynamic', 'Object');
isObliviousSubtype('void', 'Object');
isObliviousSubtype('Object?', 'Object');
// Check that the top types are equivalent.
isSubtype(
'<S extends Object*, T extends void, R extends Object?>'
'(S, T, R) ->* void',
'<U extends dynamic, V extends Object*, W extends void>'
'(U, V, W) ->* void');
{
String d = '<T extends void>() ->* T';
String e = '<T extends Object?>() ->* T';
String f = '<T extends dynamic>() ->* T';
String g = '<T extends Object*>() ->* T*';
// d = e.
isSubtype(d, e);
isSubtype(e, d);
// e = f.
isSubtype(e, f);
isSubtype(f, e);
// f = g.
isSubtype(f, g);
isSubtype(g, f);
}
{
String h = '<T extends List<dynamic>*>() ->* T*';
String i = '<T extends List<Object*>*>() ->* T*';
String j = '<T extends List<void>*>() ->* T*';
String k = '<T extends List<Object?>*>() ->* T*';
isSubtype(h, i);
isSubtype(h, j);
isSubtype(h, k);
isSubtype(i, h);
isSubtype(i, j);
isSubtype(i, k);
isSubtype(j, h);
isSubtype(j, i);
isSubtype(j, k);
isSubtype(k, h);
isSubtype(k, i);
isSubtype(k, j);
}
// Tests for checking function types against other kinds of types.
isNotSubtype('dynamic', '() ->* dynamic');
isNotSubtype('FutureOr<() ->* void>*', '() ->* void');
isSubtype('T & () ->* void', '() ->* void', typeParameters: 'T');
isSubtype('T & () ->* void', '() ->* dynamic', typeParameters: 'T');
isSubtype('T & () ->* void', '() ->* Object*', typeParameters: 'T');
isSubtype('T & (void) ->* void', '(void) ->* void', typeParameters: 'T');
isSubtype('T & (void) ->* void', '(dynamic) ->* dynamic',
typeParameters: 'T');
isSubtype('T & (void) ->* void', '(Object*) ->* Object*',
typeParameters: 'T');
isSubtype('T & (void) ->* void', '(void) ->* void', typeParameters: 'T');
isSubtype('T & (void) ->* void', '(Iterable<int*>*) ->* dynamic',
typeParameters: 'T');
isSubtype('T & (void) ->* void', '(int*) ->* Object*', typeParameters: 'T');
isNotSubtype('T & (void) ->* void', '(int*) ->* int*', typeParameters: 'T');
isSubtype('T*', '() ->* void', typeParameters: 'T extends () ->* void');
isSubtype('T', '() -> void', typeParameters: 'T extends () -> void');
isObliviousSubtype('T?', '() -> void',
typeParameters: 'T extends () -> void');
isNotSubtype('T', '() ->* void', typeParameters: 'T');
isNotSubtype('Typedef<void>*', '() ->* void');
isSubtype('VoidFunction*', '() ->* void');
isNotSubtype(
'DefaultTypes<void, void, List<void>*, List<void>*, '
'int*, (int*) ->* void, () ->* int>*',
'() ->* void');
isNotSubtype('void', '() ->* void');
// Tests for checking typedef-types against other kinds of types.
isNotSubtype('dynamic', 'T', typeParameters: 'T');
isNotSubtype('Iterable<T>*', 'T', typeParameters: 'T');
isNotSubtype('() ->* void', 'T', typeParameters: 'T');
isNotSubtype('FutureOr<T>*', 'T', typeParameters: 'T');
isSubtype('Id<T>*', 'T', typeParameters: 'T');
isNotSubtype('VoidFunction*', 'T*',
typeParameters: 'T extends () ->* void');
isNotSubtype('void', 'T', typeParameters: 'T extends void');
// Tests for checking typedef types against other kinds of types.
isSubtype('dynamic', 'Id<dynamic>*');
isNotSubtype('dynamic', 'Id<int*>*');
isSubtype('() ->* void', 'Id<() ->* void>*');
isSubtype('() -> void', 'Id<() -> void>');
isSubtype('() -> void', 'Id<() ->? void>');
isSubtype('() ->? void', 'Id<() ->? void>');
isSubtype('() ->? void', 'Id<() -> void>?');
isSubtype('() ->? void', 'Id<() ->? void>?');
isSubtype('() -> void', 'VoidFunction');
isSubtype('() -> void', 'VoidFunction?');
isSubtype('() ->? void', 'VoidFunction?');
isNotSubtype('() ->* void', 'Id<() ->* int>*');
isNotSubtype('FutureOr<() ->* void>*', 'Id<() ->* void>*');
isSubtype('FutureOr<() ->* void>*', 'Id<FutureOr<() ->* void>*>*');
isSubtype('int*', 'Id<int*>*');
isSubtype('T & () ->* void', 'Id<() ->* void>*', typeParameters: 'T');
isSubtype('T & () ->* void', 'Id<() ->* dynamic>*', typeParameters: 'T');
isSubtype('T & () ->* void', 'Id<() ->* Object*>*', typeParameters: 'T');
isSubtype('Object', 'Id<Object>');
isSubtype('Id<Object>', 'Object');
isSubtype('Object*', 'Id<Object>');
isSubtype('Id<Object>', 'Object*');
isObliviousSubtype('dynamic', 'Id<Object>');
isSubtype('Id<Object>', 'dynamic');
isObliviousSubtype('void', 'Id<Object>');
isSubtype('Id<Object>', 'void');
isObliviousSubtype('Null', 'Id<Object>');
isSubtype('Never', 'Id<Object>');
isSubtype('Never', 'Id<Never>');
isSubtype('Id<Never>', 'Never');
isObliviousSubtype('Null', 'Id<Never>');
isSubtype('Id<Never>', 'Null');
isNotSubtype('Id<Object>', 'Never');
isSubtype('Id<int>', 'num');
isObliviousSubtype('Id<int?>', 'num');
isObliviousSubtype('Id<int>?', 'num');
isObliviousSubtype('Id<int?>?', 'num');
isSubtype('Id<int>', 'num*');
isSubtype('Id<int?>', 'num*');
isSubtype('Id<int>?', 'num*');
isSubtype('Id<int?>?', 'num*');
isSubtype('Id<int>', 'num?');
isSubtype('Id<int?>', 'num?');
isSubtype('Id<int>?', 'num?');
isSubtype('Id<int?>?', 'num?');
isSubtype('T & (void) ->* void', 'Id<(void) ->* void>*',
typeParameters: 'T');
isSubtype('T & (void) ->* void', 'Id<(dynamic) ->* dynamic>*',
typeParameters: 'T');
isSubtype('T & (void) ->* void', 'Id<(Object*) ->* Object*>*',
typeParameters: 'T');
isSubtype('T & (void) ->* void', 'Id<(void) ->* void>*',
typeParameters: 'T');
isSubtype('T & (void) ->* void', 'Id<(Iterable<int*>*) ->* dynamic>*',
typeParameters: 'T');
isSubtype('T & (void) ->* void', 'Id<(int*) ->* Object*>*',
typeParameters: 'T');
isNotSubtype('T & (void) ->* void', 'Id<(int*) ->* int*>*',
typeParameters: 'T');
isNotSubtype('dynamic', 'T & dynamic', typeParameters: 'T extends dynamic');
isNotSubtype('() ->* T*', 'T* & () ->* T*',
typeParameters: 'T extends Object*');
isNotSubtype('FutureOr<T & String*>*', 'T & String*', typeParameters: 'T');
// TODO(dmitryas): Uncomment the following when type arguments are allowed
// to be intersection types.
// isSubtype('Id<T* & String*>*', 'T* & String*',
// typeParameters: 'T extends Object*');
// isSubtype('Id<T & String>', 'T & String',
// typeParameters: 'T extends Object');
// isSubtype('Id<T & String>', 'T & String',
// typeParameters: 'T extends Object?');
// isSubtype('Id<T & String?>', 'T & String?',
// typeParameters: 'T extends Object?');
// isSubtype('Id<T & String>', 'T & String?',
// typeParameters: 'T extends Object?');
// isObliviousSubtype('Id<T & String?>', 'T & String',
// typeParameters: 'T extends Object?');
// isObliviousSubtype('Id<T & String>?', 'T & String',
// typeParameters: 'T extends Object');
// isObliviousSubtype('Id<T & String>?', 'T & String?',
// typeParameters: 'T extends Object');
//
// isSubtype('Id<T* & String*>*', 'T*', typeParameters: 'T extends Object*');
// isSubtype('Id<T & String>', 'T', typeParameters: 'T extends Object');
// isSubtype('Id<T & String>', 'T?', typeParameters: 'T extends Object');
// isSubtype('Id<T & String>', 'T', typeParameters: 'T extends Object?');
// isSubtype('Id<T & String?>', 'T', typeParameters: 'T extends Object?');
// isSubtype('Id<T & String>?', 'T?', typeParameters: 'T extends Object?');
//
// isSubtype('Id<T* & String*>*', 'String*',
// typeParameters: 'T extends Object*');
// isNotSubtype('Id<T & String*>*', 'S & String*', typeParameters: 'T, S');
isNotSubtype('void', 'T* & void', typeParameters: 'T extends Object*');
isNotSubtype('void', 'T & void', typeParameters: 'T extends void');
isNotSubtype('Object', 'T & Object', typeParameters: 'T extends Object');
isNotSubtype('Object?', 'T & Object', typeParameters: 'T extends Object?');
isNotSubtype('Object?', 'T & Object?', typeParameters: 'T extends Object?');
isNotSubtype('Object*', 'T & Object*', typeParameters: 'T extends Object*');
isNotSubtype('num', 'T & num', typeParameters: 'T extends num');
isNotSubtype('FutureOr<num>', 'T & num', typeParameters: 'T extends num');
isSubtype('T', 'Id<T>*', typeParameters: 'T');
isSubtype('T', 'Id<Object*>*', typeParameters: 'T');
isNotSubtype('T', 'Id<Comparable<int*>*>*', typeParameters: 'T');
isSubtype('T*', 'Id<Comparable<int*>*>*',
typeParameters: 'T extends Comparable<int*>*');
isSubtype('Id<int*>*', 'Id<int*>*');
isSubtype('Id<int*>*', 'Id<Object*>*');
isNotSubtype('Id<Object*>*', 'Id<int*>*');
isSubtype('Id<() ->* int*>*', 'Id<() ->* int*>*');
isSubtype('Id<() ->* int*>*', 'Id<() ->* Object*>*');
isNotSubtype('Id<() ->* Object*>*', 'Id<() ->* int*>*');
isSubtype('void', 'Id<void>*');
isNotSubtype('void', 'Id<Null>*');
// The following function type tests are derived from
// ../../../../../pkg/compiler/test/model/subtype_test.dart.
isSubtype("() ->* int*", 'Function*');
isNotSubtype('Function*', "() ->* int*");
isSubtype("() ->* dynamic", "() ->* dynamic");
isSubtype("() ->* dynamic", "() ->* void");
isSubtype("() ->* void", "() ->* dynamic");
isSubtype("() ->* int*", "() ->* void");
isNotSubtype("() ->* void", "() ->* int*");
isSubtype("() ->* void", "() ->* void");
isSubtype("() ->* int*", "() ->* int*");
isSubtype("() ->* int*", "() ->* Object*");
isNotSubtype("() ->* int*", "() ->* double*");
isNotSubtype("() ->* int*", "(int*) ->* void");
isNotSubtype("() ->* void", "(int*) ->* int*");
isNotSubtype("() ->* void", "(int*) ->* void");
isSubtype("(int*) ->* int*", "(int*) ->* int*");
isSubtype("(Object*) ->* int*", "(int*) ->* Object*");
isNotSubtype("(int*) ->* int*", "(double*) ->* int*");
isNotSubtype("() ->* int*", "(int*) ->* int*");
isNotSubtype("(int*) ->* int*", "(int*, int*) ->* int*");
isNotSubtype("(int*, int*) ->* int*", "(int*) ->* int*");
isNotSubtype("(() ->* void) ->* void", "((int*) ->* void) ->* void");
isNotSubtype("((int*) ->* void) ->* void", "(() ->* void) ->* void");
// Optional positional parameters.
isSubtype("([int*]) ->* void", "() ->* void");
isSubtype("([int*]) ->* void", "(int*) ->* void");
isNotSubtype("(int*) ->* void", "([int*]) ->* void");
isSubtype("([int*]) ->* void", "([int*]) ->* void");
isSubtype("([Object*]) ->* void", "([int*]) ->* void");
isNotSubtype("([int*]) ->* void", "([Object*]) ->* void");
isSubtype("(int*, [int*]) ->* void", "(int*) ->* void");
isSubtype("(int*, [int*]) ->* void", "(int*, [int*]) ->* void");
isNotSubtype("(int*) ->* void", "([int*]) ->* void");
isSubtype("([int*, int*]) ->* void", "(int*) ->* void");
isSubtype("([int*, int*]) ->* void", "(int*, [int*]) ->* void");
isNotSubtype("([int*, int*]) ->* void", "(int*, [int*, int*]) ->* void");
isSubtype("([int*, int*, int*]) ->* void", "(int*, [int*, int*]) ->* void");
isNotSubtype("([int*]) ->* void", "(double*) ->* void");
isNotSubtype("([int*]) ->* void", "([int*, int*]) ->* void");
isSubtype("([int*, int*]) ->* void", "([int*]) ->* void");
isSubtype("([Object*, int*]) ->* void", "([int*]) ->* void");
// Optional named parameters.
isSubtype("({int* a}) ->* void", "() ->* void");
isNotSubtype("({int* a}) ->* void", "(int*) ->* void");
isNotSubtype("(int*) ->* void", "({int* a}) ->* void");
isSubtype("({int* a}) ->* void", "({int* a}) ->* void");
isNotSubtype("({int* a}) ->* void", "({int* b}) ->* void");
isSubtype("({Object* a}) ->* void", "({int* a}) ->* void");
isNotSubtype("({int* a}) ->* void", "({Object* a}) ->* void");
isSubtype("(int*, {int* a}) ->* void", "(int*, {int* a}) ->* void");
isNotSubtype("({int* a}) ->* void", "({double* a}) ->* void");
isNotSubtype("({int* a}) ->* void", "({int* a, int* b}) ->* void");
isSubtype("({int* a, int* b}) ->* void", "({int* a}) ->* void");
isSubtype(
"({int* a, int* b, int* c}) ->* void", "({int* a, int* c}) ->* void");
isSubtype(
"({int* c, int* b, int* a}) ->* void", "({int* a, int* c}) ->* void");
isSubtype(
"({int* a, int* b, int* c}) ->* void", "({int* b, int* c}) ->* void");
isSubtype(
"({int* c, int* b, int* a}) ->* void", "({int* b, int* c}) ->* void");
isSubtype("({int* a, int* b, int* c}) ->* void", "({int* c}) ->* void");
isSubtype("({int* c, int* b, int* a}) ->* void", "({int* c}) ->* void");
// Parsing of nullable and legacy types.
isSubtype("int?", "int?");
isSubtype("int*", "int*");
isSubtype("(int) ->? int", "(int) ->? int");
isSubtype("(int) ->* int", "(int) ->* int");
isSubtype("(int, int*, int?) -> int?", "(int, int*, int?) -> int?");
isSubtype("List<int>?", "List<int>?");
isSubtype("List<int?>?", "List<int?>?");
isSubtype("T & int?", "T & int?", typeParameters: "T extends Object?");
isSubtype("T? & int?", "T? & int?", typeParameters: "T extends Object");
// Tests for extension types.
isSubtype("Never", "Extension");
isSubtype("Never", "GenericExtension<Never>");
isSubtype("Extension", "dynamic");
isSubtype("Extension", "void");
isSubtype("Extension", "Object?");
isSubtype("Extension", "FutureOr<dynamic>");
isSubtype("GenericExtension<dynamic>", "dynamic");
isSubtype("GenericExtension<dynamic>", "void");
isSubtype("GenericExtension<dynamic>", "Object?");
isSubtype("GenericExtension<dynamic>", "FutureOr<dynamic>");
isSubtype("dynamic", "TopExtension");
isSubtype("void", "TopExtension");
isSubtype("Object?", "TopExtension");
isSubtype("FutureOr<dynamic>", "TopExtension");
isSubtype("num", "TopExtension");
isSubtype("dynamic", "GenericTopExtension<String>");
isSubtype("void", "GenericTopExtension<String>");
isSubtype("Object?", "GenericTopExtension<String>");
isSubtype("FutureOr<dynamic>", "GenericTopExtension<String>");
isSubtype("num", "GenericTopExtension<String>");
isNotSubtype("Extension", "ExtendedClass");
isNotSubtype("GenericExtension<num>", "ExtendedGenericClass<num>");
isSubtype("ExtendedClass", "Extension");
isSubtype("ExtendedGenericClass<num>", "GenericExtension<num>");
isSubtype("ExtendedSubclass", "Extension");
}
}