|
| 1 | +// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file |
| 2 | +// for details. All rights reserved. Use of this source code is governed by a |
| 3 | +// BSD-style license that can be found in the LICENSE file. |
| 4 | + |
| 5 | +import 'dart:_foreign_helper' show JS; |
| 6 | +import 'dart:_runtime' as dart; |
| 7 | +import 'dart:async'; |
| 8 | + |
| 9 | +import 'package:expect/expect.dart'; |
| 10 | + |
| 11 | +// Requirements=nnbd-strong |
| 12 | + |
| 13 | +class A {} |
| 14 | + |
| 15 | +class B extends A {} |
| 16 | + |
| 17 | +class C extends B {} |
| 18 | + |
| 19 | +class D<T extends B> {} |
| 20 | + |
| 21 | +class E<T, S> {} |
| 22 | + |
| 23 | +class F extends E<B, B> {} |
| 24 | + |
| 25 | +// Returns sWrapped<tWrapped> as a wrapped type. |
| 26 | +Type generic1(Type sWrapped, Type tWrapped) { |
| 27 | + var s = dart.unwrapType(sWrapped); |
| 28 | + var t = dart.unwrapType(tWrapped); |
| 29 | + var sGeneric = dart.getGenericClass(s); |
| 30 | + return dart.wrapType(JS('', '#(#)', sGeneric, t)); |
| 31 | +} |
| 32 | + |
| 33 | +// Returns sWrapped<tWrapped, rWrapped> as a wrapped type. |
| 34 | +Type generic2(Type sWrapped, Type tWrapped, Type rWrapped) { |
| 35 | + var s = dart.unwrapType(sWrapped); |
| 36 | + var t = dart.unwrapType(tWrapped); |
| 37 | + var r = dart.unwrapType(rWrapped); |
| 38 | + var sGeneric = dart.getGenericClass(s); |
| 39 | + return dart.wrapType(JS('', '#(#, #)', sGeneric, t, r)); |
| 40 | +} |
| 41 | + |
| 42 | +// Returns a function type of argWrapped -> returnWrapped as a wrapped type. |
| 43 | +Type function1(Type returnWrapped, Type argWrapped) { |
| 44 | + var returnType = dart.unwrapType(returnWrapped); |
| 45 | + var argType = dart.unwrapType(argWrapped); |
| 46 | + var fun = dart.fnType(returnType, [argType]); |
| 47 | + return dart.wrapType(fun); |
| 48 | +} |
| 49 | + |
| 50 | +// Returns a function type with a bounded type argument that takes no argument |
| 51 | +// and returns void as a wrapped type. |
| 52 | +Type genericFunction(Type boundWrapped) => dart.wrapType(dart.gFnType( |
| 53 | + (T) => [dart.VoidType, []], (T) => [dart.unwrapType(boundWrapped)])); |
| 54 | + |
| 55 | +// Returns a function type with a bounded generic return type of |
| 56 | +// <T extends boundWrapped> argWrapped -> T as a wrapped type. |
| 57 | +Type functionGenericReturn(Type boundWrapped, Type argWrapped) => |
| 58 | + dart.wrapType(dart.gFnType( |
| 59 | + (T) => [ |
| 60 | + T, |
| 61 | + [dart.unwrapType(argWrapped)] |
| 62 | + ], |
| 63 | + (T) => [dart.unwrapType(boundWrapped)])); |
| 64 | + |
| 65 | +// Returns a function with a bounded generic argument type of |
| 66 | +// <T extends boundWrapped> T -> returnWrapped as a wrapped type. |
| 67 | +Type functionGenericArg(Type boundWrapped, Type returnWrapped) => |
| 68 | + dart.wrapType(dart.gFnType( |
| 69 | + (T) => [ |
| 70 | + dart.unwrapType(returnWrapped), |
| 71 | + [T] |
| 72 | + ], |
| 73 | + (T) => [dart.unwrapType(boundWrapped)])); |
| 74 | + |
| 75 | +void checkSubtype(Type sWrapped, Type tWrapped) { |
| 76 | + var s = dart.unwrapType(sWrapped); |
| 77 | + var t = dart.unwrapType(tWrapped); |
| 78 | + Expect.isTrue(dart.isSubtypeOf(s, t), '$s should be subtype of $t.'); |
| 79 | +} |
| 80 | + |
| 81 | +void checkProperSubtype(Type sWrapped, Type tWrapped) { |
| 82 | + var s = dart.unwrapType(sWrapped); |
| 83 | + var t = dart.unwrapType(tWrapped); |
| 84 | + Expect.isTrue(dart.isSubtypeOf(s, t), '$s should be subtype of $t.'); |
| 85 | + checkSubtypeFailure(tWrapped, sWrapped); |
| 86 | +} |
| 87 | + |
| 88 | +void checkSubtypeFailure(Type sWrapped, Type tWrapped) { |
| 89 | + var s = dart.unwrapType(sWrapped); |
| 90 | + var t = dart.unwrapType(tWrapped); |
| 91 | + Expect.isFalse(dart.isSubtypeOf(s, t), '$s should not be subtype of $t.'); |
| 92 | +} |
| 93 | + |
| 94 | +// Returns tWrapped? as a wrapped type. |
| 95 | +Type nullable(Type tWrapped) { |
| 96 | + var t = dart.unwrapType(tWrapped); |
| 97 | + var tNullable = dart.nullable(t); |
| 98 | + return dart.wrapType(tNullable); |
| 99 | +} |
| 100 | + |
| 101 | +// Returns tWrapped* as a wrapped type. |
| 102 | +Type legacy(Type tWrapped) { |
| 103 | + var t = dart.unwrapType(tWrapped); |
| 104 | + var tLegacy = dart.legacy(t); |
| 105 | + return dart.wrapType(tLegacy); |
| 106 | +} |
| 107 | + |
| 108 | +void main() { |
| 109 | + // dynamic <\: A |
| 110 | + checkSubtypeFailure(dynamic, A); |
| 111 | + // A <: dynamic |
| 112 | + checkProperSubtype(A, dynamic); |
| 113 | + // A <: void |
| 114 | + checkProperSubtype(A, dart.wrapType(dart.void_)); |
| 115 | + // Null <\: A |
| 116 | + checkSubtypeFailure(Null, A); |
| 117 | + |
| 118 | + // FutureOr<Never> <: Future<Never> |
| 119 | + checkSubtype(generic1(FutureOr, dart.wrapType(dart.never_)), |
| 120 | + generic1(Future, dart.wrapType(dart.never_))); |
| 121 | + // Future<B> <: FutureOr<A> |
| 122 | + checkProperSubtype(generic1(Future, B), generic1(FutureOr, A)); |
| 123 | + // B <: <: FutureOr<A> |
| 124 | + checkProperSubtype(B, generic1(FutureOr, A)); |
| 125 | + // Future<B> <: Future<A> |
| 126 | + checkProperSubtype(generic1(Future, B), generic1(Future, A)); |
| 127 | + |
| 128 | + // B <: A |
| 129 | + checkProperSubtype(B, A); |
| 130 | + // A <: A |
| 131 | + checkSubtype(A, A); |
| 132 | + // C <: B |
| 133 | + checkProperSubtype(C, B); |
| 134 | + // C <: A |
| 135 | + checkProperSubtype(C, A); |
| 136 | + |
| 137 | + // A -> B <: Function |
| 138 | + checkProperSubtype(function1(B, A), Function); |
| 139 | + |
| 140 | + // A -> B <: A -> B |
| 141 | + checkSubtype(function1(B, A), function1(B, A)); |
| 142 | + |
| 143 | + // A -> B <: B -> B |
| 144 | + checkProperSubtype(function1(B, A), function1(B, B)); |
| 145 | + // TODO(nshahan) Subtype check with covariant keyword? |
| 146 | + |
| 147 | + // A -> B <: A -> A |
| 148 | + checkSubtype(function1(B, A), function1(A, A)); |
| 149 | + |
| 150 | + // Generic Function Subtypes. |
| 151 | + // Bound is a built in type. |
| 152 | + // <T extends int> void -> void <: <T extends int> void -> void |
| 153 | + checkSubtype(genericFunction(int), genericFunction(int)); |
| 154 | + |
| 155 | + // <T extends String> A -> T <: <T extends String> B -> T |
| 156 | + checkProperSubtype( |
| 157 | + functionGenericReturn(String, A), functionGenericReturn(String, B)); |
| 158 | + |
| 159 | + // <T extends double> T -> B <: <T extends double> T -> A |
| 160 | + checkProperSubtype( |
| 161 | + functionGenericArg(double, B), functionGenericArg(double, A)); |
| 162 | + |
| 163 | + // Bound is a function type. |
| 164 | + // <T extends A -> B> void -> void <: <T extends A -> B> void -> void |
| 165 | + checkSubtype( |
| 166 | + genericFunction(function1(B, A)), genericFunction(function1(B, A))); |
| 167 | + |
| 168 | + // <T extends A -> B> A -> T <: <T extends A -> B> B -> T |
| 169 | + checkProperSubtype(functionGenericReturn(function1(B, A), A), |
| 170 | + functionGenericReturn(function1(B, A), B)); |
| 171 | + |
| 172 | + // <T extends A -> B> T -> B <: <T extends A -> B> T -> A |
| 173 | + checkProperSubtype(functionGenericArg(function1(B, A), B), |
| 174 | + functionGenericArg(function1(B, A), A)); |
| 175 | + |
| 176 | + // Bound is a user defined class. |
| 177 | + // <T extends B> void -> void <: <T extends B> void -> void |
| 178 | + checkSubtype(genericFunction(B), genericFunction(B)); |
| 179 | + |
| 180 | + // <T extends B> A -> T <: <T extends B> B -> T |
| 181 | + checkProperSubtype(functionGenericReturn(B, A), functionGenericReturn(B, B)); |
| 182 | + |
| 183 | + // <T extends B> T -> B <: <T extends B> T -> A |
| 184 | + checkProperSubtype(functionGenericArg(B, B), functionGenericArg(B, A)); |
| 185 | + |
| 186 | + // Bound is a Future. |
| 187 | + // <T extends Future<B>> void -> void <: <T extends Future<B>> void -> void |
| 188 | + checkSubtype(genericFunction(generic1(Future, B)), |
| 189 | + genericFunction(generic1(Future, B))); |
| 190 | + |
| 191 | + // <T extends Future<B>> A -> T <: <T extends Future<B>> B -> T |
| 192 | + checkProperSubtype(functionGenericReturn(generic1(Future, B), A), |
| 193 | + functionGenericReturn(generic1(Future, B), B)); |
| 194 | + |
| 195 | + // <T extends Future<B>> T -> B <: <T extends Future<B>> T -> A |
| 196 | + checkProperSubtype(functionGenericArg(generic1(Future, B), B), |
| 197 | + functionGenericArg(generic1(Future, B), A)); |
| 198 | + |
| 199 | + // Bound is a FutureOr. |
| 200 | + // <T extends FutureOr<B>> void -> void <: |
| 201 | + // <T extends FutureOr<B>> void -> void |
| 202 | + checkSubtype(genericFunction(generic1(FutureOr, B)), |
| 203 | + genericFunction(generic1(FutureOr, B))); |
| 204 | + |
| 205 | + // <T extends FutureOr<B>> A -> T <: <T extends FutureOr<B>> B -> T |
| 206 | + checkProperSubtype(functionGenericReturn(generic1(FutureOr, B), A), |
| 207 | + functionGenericReturn(generic1(FutureOr, B), B)); |
| 208 | + |
| 209 | + // <T extends FutureOr<B>> T -> B <: <T extends FutureOr<B>> T -> A |
| 210 | + checkProperSubtype(functionGenericArg(generic1(FutureOr, B), B), |
| 211 | + functionGenericArg(generic1(FutureOr, B), A)); |
| 212 | + |
| 213 | + // D <: D<B> |
| 214 | + checkSubtype(D, generic1(D, B)); |
| 215 | + // D<B> <: D |
| 216 | + checkSubtype(generic1(D, B), D); |
| 217 | + // D<C> <: D<B> |
| 218 | + checkProperSubtype(generic1(D, C), generic1(D, B)); |
| 219 | + |
| 220 | + // F <: E |
| 221 | + checkProperSubtype(F, E); |
| 222 | + // F <: E<A, A> |
| 223 | + checkProperSubtype(F, generic2(E, A, A)); |
| 224 | + // // E<B, B> <: E<A, A> |
| 225 | + checkProperSubtype(generic2(E, B, B), E); |
| 226 | + // // E<B, B> <: E<A, A> |
| 227 | + checkProperSubtype(generic2(E, B, B), generic2(E, A, A)); |
| 228 | + |
| 229 | + // A <: A? |
| 230 | + checkProperSubtype(A, nullable(A)); |
| 231 | + // B <: A? |
| 232 | + checkProperSubtype(B, nullable(A)); |
| 233 | + // C <: A? |
| 234 | + checkProperSubtype(C, nullable(A)); |
| 235 | + // B? <: A? |
| 236 | + checkProperSubtype(nullable(B), nullable(A)); |
| 237 | + // C? <: A? |
| 238 | + checkProperSubtype(nullable(C), nullable(A)); |
| 239 | + |
| 240 | + // A <: Object |
| 241 | + checkProperSubtype(A, Object); |
| 242 | + // A* <: Object |
| 243 | + checkProperSubtype(legacy(A), Object); |
| 244 | + // dynamic <\: Object |
| 245 | + checkSubtypeFailure(dynamic, Object); |
| 246 | + // void <\: Object |
| 247 | + checkSubtypeFailure(dart.wrapType(dart.void_), Object); |
| 248 | + // Null <\: Object |
| 249 | + checkSubtypeFailure(Null, Object); |
| 250 | + // A? <\: Object |
| 251 | + checkSubtypeFailure(nullable(A), Object); |
| 252 | + |
| 253 | + // Null <: FutureOr<A?> |
| 254 | + checkProperSubtype(Null, generic1(FutureOr, nullable(A))); |
| 255 | + // Null <: Null |
| 256 | + checkSubtype(Null, Null); |
| 257 | + // Null <: A? |
| 258 | + checkProperSubtype(Null, nullable(A)); |
| 259 | + // Null <: A* |
| 260 | + checkProperSubtype(Null, legacy(A)); |
| 261 | + |
| 262 | + // B* <: A |
| 263 | + checkProperSubtype(legacy(B), A); |
| 264 | + // A* <\: B |
| 265 | + checkSubtypeFailure(legacy(A), B); |
| 266 | + |
| 267 | + // B? <: A* |
| 268 | + checkProperSubtype(nullable(B), legacy(A)); |
| 269 | + // B <: A* |
| 270 | + checkProperSubtype(B, legacy(A)); |
| 271 | + // A <: B* |
| 272 | + checkSubtypeFailure(A, legacy(B)); |
| 273 | + // A? <: B* |
| 274 | + checkSubtypeFailure(nullable(A), legacy(B)); |
| 275 | +} |
0 commit comments