@@ -81,6 +81,15 @@ void nativeNonNullAsserts(bool enable) {
8181
8282final metadata = JS ('' , 'Symbol("metadata")' );
8383
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+
8493/// Types in dart are represented internally at runtime as follows.
8594///
8695/// - Normal nominal types, produced from classes, are represented
@@ -197,48 +206,15 @@ F tearoffInterop<F extends Function?>(F f) {
197206 return JS ('' , '#' , ret);
198207}
199208
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) .
201210///
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 {
209213 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);
231215
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;
242218
243219 @notNull
244220 @JSExportName ('is' )
@@ -250,23 +226,6 @@ class LazyJSType extends DartType {
250226 as_T (obj) => is_T (obj) ? obj : castError (obj, this );
251227}
252228
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-
270229void _warn (arg) {
271230 JS ('void' , 'console.warn(#)' , arg);
272231}
@@ -299,35 +258,25 @@ void _nullWarnOnType(type) {
299258 }
300259}
301260
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()' );
313262
314- anonymousJSType (String name) {
315- var ret = JS ('' , '#.get(#)' , _anonymousJSTypes , name);
263+ packageJSType (String name) {
264+ var ret = JS ('' , '#.get(#)' , _packageJSTypes , name);
316265 if (ret == null ) {
317- ret = AnonymousJSType (name);
318- JS ('' , '#.set(#, #)' , _anonymousJSTypes , name, ret);
266+ ret = PackageJSType (name);
267+ JS ('' , '#.set(#, #)' , _packageJSTypes , name, ret);
319268 }
320269 return ret;
321270}
322271
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 ( ' ' );
331280
332281/// Returns a nullable (question, ?) version of [type] .
333282///
@@ -1522,34 +1471,20 @@ bool _isSubtype(t1, t2, @notNull bool strictMode) => JS<bool>('!', '''(() => {
15221471 //
15231472 // JavaScriptObject <: package:js types
15241473 // package:js types <: JavaScriptObject
1525- //
1526- // TODO: This doesn't allow package:js type <: another package:js type yet.
15271474
15281475 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 )}) {
15391483 return true;
15401484 }
15411485
15421486 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 )}) {
15531488 return true;
15541489 }
15551490
@@ -1617,10 +1552,11 @@ bool _isSubtype(t1, t2, @notNull bool strictMode) => JS<bool>('!', '''(() => {
16171552})()''' );
16181553
16191554bool _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+ }
16241560
16251561 if ($t1 === $t2 ) {
16261562 return true;
0 commit comments