@@ -136,8 +136,11 @@ class Rti {
136136 static const kindGenericFunction = 11 ;
137137 static const kindGenericFunctionParameter = 12 ;
138138
139- static bool _isFunctionType (Rti rti) {
139+ static bool _isUnionOfFunctionType (Rti rti) {
140140 int kind = Rti ._getKind (rti);
141+ if (kind == kindStar || kind == kindQuestion || kind == kindFutureOr) {
142+ return _isUnionOfFunctionType (_castToRti (_getPrimary (rti)));
143+ }
141144 return kind == kindFunction || kind == kindGenericFunction;
142145 }
143146
@@ -346,22 +349,56 @@ Rti evalInInstance(instance, String recipe) {
346349 return _rtiEval (instanceType (instance), recipe);
347350}
348351
352+ bool _isClosure (object) => _Utils .instanceOf (object,
353+ JS_BUILTIN ('depends:none;effects:none;' , JsBuiltin .dartClosureConstructor));
354+
355+ Rti _closureFunctionType (closure) {
356+ var signatureName = JS_GET_NAME (JsGetName .SIGNATURE_NAME );
357+ var signature = JS ('' , '#[#]' , closure, signatureName);
358+ if (signature != null ) {
359+ if (JS ('bool' , 'typeof # == "number"' , signature)) {
360+ return getTypeFromTypesTable (_Utils .asInt (signature));
361+ }
362+ return _castToRti (JS ('' , '#[#]()' , closure, signatureName));
363+ }
364+ return null ;
365+ }
366+
367+ // Subclasses of Closure are synthetic classes. The synthetic classes all
368+ // extend a 'normal' class (Closure, BoundClosure, StaticClosure), so make
369+ // them appear to be the superclass.
370+ // TODO(sra): Can this be done less expensively, e.g. by putting $ti on the
371+ // prototype of Closure/BoundClosure/StaticClosure classes?
372+ Rti _closureInterfaceType (closure) => _instanceTypeFromConstructor (
373+ JS ('' , '#.__proto__.__proto__.constructor' , closure));
374+
349375/// Returns the Rti type of [object] . Closures have both an interface type
350376/// (Closures implement `Function` ) and a structural function type. Uses
351377/// [testRti] to choose the appropriate type.
352378///
353379/// Called from generated code.
354380Rti instanceOrFunctionType (object, Rti testRti) {
355- if (Rti ._isFunctionType (testRti)) {
356- Rti rti = _instanceFunctionType (object);
357- if (rti != null ) return rti;
381+ if (_isClosure (object)) {
382+ if (Rti ._isUnionOfFunctionType (testRti)) {
383+ // If [testRti] is e.g. `FutureOr<Action>` (where `Action` is some
384+ // function type), we don't need to worry about the `Future<Action>`
385+ // branch because closures can't be `Future`s.
386+ Rti rti = _closureFunctionType (object);
387+ if (rti != null ) return rti;
388+ }
389+ return _closureInterfaceType (object);
358390 }
359- return instanceType (object);
391+ return _nonClosureInstanceType (object);
360392}
361393
362394/// Returns the Rti type of [object] .
363395/// Called from generated code.
364396Rti instanceType (object) {
397+ if (_isClosure (object)) return _closureInterfaceType (object);
398+ return _nonClosureInstanceType (object);
399+ }
400+
401+ Rti _nonClosureInstanceType (object) {
365402 // TODO(sra): Add specializations of this method. One possible way is to
366403 // arrange that the interceptor has a _getType method that is injected into
367404 // DartObject, Interceptor and JSArray. Then this method can be replaced-by
@@ -375,18 +412,6 @@ Rti instanceType(object) {
375412 var rti = JS ('' , r'#[#]' , object, JS_GET_NAME (JsGetName .RTI_NAME ));
376413 if (rti != null ) return _castToRti (rti);
377414
378- // Subclasses of Closure are synthetic classes. The synthetic classes all
379- // extend a 'normal' class (Closure, BoundClosure, StaticClosure), so make
380- // them appear to be the superclass.
381- // TODO(sra): Can this be done less expensively, e.g. by putting $ti on the
382- // prototype of Closure/BoundClosure/StaticClosure classes?
383- var closureClassConstructor = JS_BUILTIN (
384- 'depends:none;effects:none;' , JsBuiltin .dartClosureConstructor);
385- if (_Utils .instanceOf (object, closureClassConstructor)) {
386- return _instanceTypeFromConstructor (
387- JS ('' , '#.__proto__.__proto__.constructor' , object));
388- }
389-
390415 return _instanceTypeFromConstructor (JS ('' , '#.constructor' , object));
391416 }
392417
@@ -412,19 +437,7 @@ Rti _instanceTypeFromConstructor(constructor) {
412437/// Returns the structural function type of [object] , or `null` if the object is
413438/// not a closure.
414439Rti _instanceFunctionType (object) {
415- if (_Utils .instanceOf (
416- object,
417- JS_BUILTIN (
418- 'depends:none;effects:none;' , JsBuiltin .dartClosureConstructor))) {
419- var signatureName = JS_GET_NAME (JsGetName .SIGNATURE_NAME );
420- var signature = JS ('' , '#[#]' , object, signatureName);
421- if (signature != null ) {
422- if (JS ('bool' , 'typeof # == "number"' , signature)) {
423- return getTypeFromTypesTable (_Utils .asInt (signature));
424- }
425- return _castToRti (JS ('' , '#[#]()' , object, signatureName));
426- }
427- }
440+ if (_isClosure (object)) return _closureFunctionType (object);
428441 return null ;
429442}
430443
@@ -443,7 +456,7 @@ Rti getTypeFromTypesTable(/*int*/ _index) {
443456}
444457
445458Type getRuntimeType (object) {
446- Rti rti = _instanceFunctionType (object) ?? instanceType (object);
459+ Rti rti = _instanceFunctionType (object) ?? _nonClosureInstanceType (object);
447460 return _createRuntimeType (rti);
448461}
449462
@@ -1896,11 +1909,11 @@ bool _isSubtype(universe, Rti s, sEnv, Rti t, tEnv) {
18961909 }
18971910 }
18981911
1899- if (Rti . _isFunctionType (t)) {
1912+ if (isEitherFunctionKind (t)) {
19001913 return _isFunctionSubtype (universe, s, sEnv, t, tEnv);
19011914 }
19021915
1903- if (Rti . _isFunctionType (s)) {
1916+ if (isEitherFunctionKind (s)) {
19041917 return isFunctionType (t);
19051918 }
19061919
@@ -1913,8 +1926,8 @@ bool _isSubtype(universe, Rti s, sEnv, Rti t, tEnv) {
19131926
19141927// TODO(fishythefish): Support required named parameters.
19151928bool _isFunctionSubtype (universe, Rti s, sEnv, Rti t, tEnv) {
1916- assert (Rti . _isFunctionType (t));
1917- if (! Rti . _isFunctionType (s)) return false ;
1929+ assert (isEitherFunctionKind (t));
1930+ if (! isEitherFunctionKind (s)) return false ;
19181931
19191932 if (isGenericFunctionKind (s)) {
19201933 if (! isGenericFunctionKind (t)) return false ;
@@ -2123,6 +2136,9 @@ bool isJsInteropType(Rti t) => Rti._getKind(t) == Rti.kindAny;
21232136
21242137bool isFutureOrType (Rti t) => Rti ._getKind (t) == Rti .kindFutureOr;
21252138
2139+ bool isEitherFunctionKind (Rti t) =>
2140+ isFunctionKind (t) || isGenericFunctionKind (t);
2141+ bool isFunctionKind (Rti t) => Rti ._getKind (t) == Rti .kindFunction;
21262142bool isGenericFunctionKind (Rti t) => Rti ._getKind (t) == Rti .kindGenericFunction;
21272143
21282144bool isGenericFunctionTypeParameter (Rti t) =>
0 commit comments