@@ -81,6 +81,15 @@ void nativeNonNullAsserts(bool enable) {
81
81
82
82
final metadata = JS ('' , 'Symbol("metadata")' );
83
83
84
+ /// A javascript Symbol used to store a canonical version of T? on T.
85
+ final _cachedNullable = JS ('' , 'Symbol("cachedNullable")' );
86
+
87
+ /// A javascript Symbol used to store a canonical version of T* on T.
88
+ final _cachedLegacy = JS ('' , 'Symbol("cachedLegacy")' );
89
+
90
+ /// A javascript Symbol used to store prior subtype checks and their results.
91
+ final _subtypeCache = JS ('' , 'Symbol("_subtypeCache")' );
92
+
84
93
/// Types in dart are represented internally at runtime as follows.
85
94
///
86
95
/// - Normal nominal types, produced from classes, are represented
@@ -197,48 +206,15 @@ F tearoffInterop<F extends Function?>(F f) {
197
206
return JS ('' , '#' , ret);
198
207
}
199
208
200
- /// The Dart type that represents a JavaScript class(/constructor) type.
209
+ /// Dart type that represents a package:js class type (either anonymous or not) .
201
210
///
202
- /// The JavaScript type may not exist, either because it's not loaded yet, or
203
- /// because it's not available (such as with mocks). To handle this gracefully,
204
- /// we disable type checks for in these cases, and allow any JS object to work
205
- /// as if it were an instance of this JS type.
206
- class LazyJSType extends DartType {
207
- Function () _getRawJSTypeFn;
208
- @notNull
211
+ /// For the purposes of subtype checks, these match any JS type.
212
+ class PackageJSType extends DartType {
209
213
final String _dartName;
210
- Object ? _rawJSType;
211
-
212
- LazyJSType (this ._getRawJSTypeFn, this ._dartName);
213
-
214
- toString () {
215
- var raw = _getRawJSType ();
216
- return raw != null ? typeName (raw) : "JSObject<$_dartName >" ;
217
- }
218
-
219
- Object ? _getRawJSType () {
220
- var raw = _rawJSType;
221
- if (raw != null ) return raw;
222
-
223
- // Try to evaluate the JS type. If this fails for any reason, we'll try
224
- // again next time.
225
- // TODO(jmesserly): is it worth trying again? It may create unnecessary
226
- // overhead, especially if exceptions are being thrown. Also it means the
227
- // behavior of a given type check can change later on.
228
- try {
229
- raw = _getRawJSTypeFn ();
230
- } catch (e) {}
214
+ PackageJSType (this ._dartName);
231
215
232
- if (raw == null ) {
233
- _warn ('Cannot find native JavaScript type ($_dartName ) for type check' );
234
- } else {
235
- _rawJSType = raw;
236
- JS ('' , '#.push(() => # = null)' , _resetFields, _rawJSType);
237
- }
238
- return raw;
239
- }
240
-
241
- Object rawJSTypeForCheck () => _getRawJSType () ?? typeRep <JavaScriptObject >();
216
+ @override
217
+ String toString () => _dartName;
242
218
243
219
@notNull
244
220
@JSExportName ('is' )
@@ -250,23 +226,6 @@ class LazyJSType extends DartType {
250
226
as_T (obj) => is_T (obj) ? obj : castError (obj, this );
251
227
}
252
228
253
- /// An anonymous JS type
254
- ///
255
- /// For the purposes of subtype checks, these match any JS type.
256
- class AnonymousJSType extends DartType {
257
- final String _dartName;
258
- AnonymousJSType (this ._dartName);
259
- toString () => _dartName;
260
-
261
- @JSExportName ('is' )
262
- bool is_T (obj) =>
263
- obj != null &&
264
- (_isJsObject (obj) || isSubtypeOf (getReifiedType (obj), this ));
265
-
266
- @JSExportName ('as' )
267
- as_T (obj) => is_T (obj) ? obj : castError (obj, this );
268
- }
269
-
270
229
void _warn (arg) {
271
230
JS ('void' , 'console.warn(#)' , arg);
272
231
}
@@ -299,35 +258,25 @@ void _nullWarnOnType(type) {
299
258
}
300
259
}
301
260
302
- var _lazyJSTypes = JS <Object >('' , 'new Map()' );
303
- var _anonymousJSTypes = JS <Object >('' , 'new Map()' );
304
-
305
- lazyJSType (Function () getJSTypeCallback, String name) {
306
- var ret = JS ('' , '#.get(#)' , _lazyJSTypes, name);
307
- if (ret == null ) {
308
- ret = LazyJSType (getJSTypeCallback, name);
309
- JS ('' , '#.set(#, #)' , _lazyJSTypes, name, ret);
310
- }
311
- return ret;
312
- }
261
+ var _packageJSTypes = JS <Object >('' , 'new Map()' );
313
262
314
- anonymousJSType (String name) {
315
- var ret = JS ('' , '#.get(#)' , _anonymousJSTypes , name);
263
+ packageJSType (String name) {
264
+ var ret = JS ('' , '#.get(#)' , _packageJSTypes , name);
316
265
if (ret == null ) {
317
- ret = AnonymousJSType (name);
318
- JS ('' , '#.set(#, #)' , _anonymousJSTypes , name, ret);
266
+ ret = PackageJSType (name);
267
+ JS ('' , '#.set(#, #)' , _packageJSTypes , name, ret);
319
268
}
320
269
return ret;
321
270
}
322
271
323
- /// A javascript Symbol used to store a canonical version of T? on T.
324
- final _cachedNullable = JS ( '' , 'Symbol("cachedNullable")' );
325
-
326
- /// A javascript Symbol used to store a canonical version of T* on T.
327
- final _cachedLegacy = JS ( '' , 'Symbol("cachedLegacy")' );
328
-
329
- /// A javascript Symbol used to store prior subtype checks and their results .
330
- final _subtypeCache = JS ( '' , 'Symbol("_subtypeCache") ' );
272
+ /// Since package:js types are all subtypes of each other, we use this var to
273
+ /// denote *some* package:js type in our subtyping logic.
274
+ ///
275
+ /// Used only when a concrete PackageJSType is not available i.e. when neither
276
+ /// the object nor the target type is a PackageJSType. Avoids initializating a
277
+ /// new PackageJSType every time. Note that we don't add it to the set of JS
278
+ /// types, since it's not an actual JS class .
279
+ final _pkgJSTypeForSubtyping = PackageJSType ( ' ' );
331
280
332
281
/// Returns a nullable (question, ?) version of [type] .
333
282
///
@@ -1522,34 +1471,20 @@ bool _isSubtype(t1, t2, @notNull bool strictMode) => JS<bool>('!', '''(() => {
1522
1471
//
1523
1472
// JavaScriptObject <: package:js types
1524
1473
// package:js types <: JavaScriptObject
1525
- //
1526
- // TODO: This doesn't allow package:js type <: another package:js type yet.
1527
1474
1528
1475
if (${_isInterfaceSubtype (t1 , JavaScriptObject , strictMode )}
1529
- && (${_jsInstanceOf (t2 , LazyJSType )}
1530
- || ${_jsInstanceOf (t2 , AnonymousJSType )}
1531
- // TODO: Since package:js types are instances of LazyJSType and
1532
- // AnonymousJSType, we don't have a mechanism to determine if *some*
1533
- // package:js type implements t2. This will possibly require keeping
1534
- // a map of these relationships for this subtyping check. For now,
1535
- // don't execute the following checks.
1536
- // || _isInterfaceSubtype(LazyJSType, t2, strictMode)
1537
- // || _isInterfaceSubtype(AnonymousJSType, t2, strictMode)
1538
- )) {
1476
+ &&
1477
+ // TODO: Since package:js types are instances of PackageJSType and
1478
+ // we don't have a mechanism to determine if *some* package:js type
1479
+ // implements t2. This will possibly require keeping a map of these
1480
+ // relationships for this subtyping check. For now, this will only
1481
+ // work if t2 is also a PackageJSType.
1482
+ ${_isInterfaceSubtype (_pkgJSTypeForSubtyping , t2 , strictMode )}) {
1539
1483
return true;
1540
1484
}
1541
1485
1542
1486
if (${_isInterfaceSubtype (JavaScriptObject , t2 , strictMode )}
1543
- && (${_jsInstanceOf (t1 , LazyJSType )}
1544
- || ${_jsInstanceOf (t1 , AnonymousJSType )}
1545
- // TODO: We don't have a check in `isInterfaceSubtype` to check that
1546
- // a class is a subtype of *some* package:js class. This will likely
1547
- // require modifying `_isInterfaceSubtype` to check if the
1548
- // interfaces of t1 include a package:js type. For now, don't
1549
- // execute the following checks.
1550
- // || _isInterfaceSubtype(t1, LazyJSType, strictMode)
1551
- // || _isInterfaceSubtype(t1, AnonymousJSType, strictMode)
1552
- )) {
1487
+ && ${_isInterfaceSubtype (t1 , _pkgJSTypeForSubtyping , strictMode )}) {
1553
1488
return true;
1554
1489
}
1555
1490
@@ -1617,10 +1552,11 @@ bool _isSubtype(t1, t2, @notNull bool strictMode) => JS<bool>('!', '''(() => {
1617
1552
})()''' );
1618
1553
1619
1554
bool _isInterfaceSubtype (t1, t2, @notNull bool strictMode) => JS ('' , '''(() => {
1620
- // If we have lazy JS types, unwrap them. This will effectively
1621
- // reduce to a prototype check below.
1622
- if (${_jsInstanceOf (t1 , LazyJSType )}) $t1 = $t1 .rawJSTypeForCheck();
1623
- if (${_jsInstanceOf (t2 , LazyJSType )}) $t2 = $t2 .rawJSTypeForCheck();
1555
+ // Instances of PackageJSType are all subtypes of each other.
1556
+ if (${_jsInstanceOf (t1 , PackageJSType )}
1557
+ && ${_jsInstanceOf (t2 , PackageJSType )}) {
1558
+ return true;
1559
+ }
1624
1560
1625
1561
if ($t1 === $t2 ) {
1626
1562
return true;
0 commit comments