Skip to content

Commit 06509e3

Browse files
fishythefishcommit-bot@chromium.org
authored andcommitted
[dart2js] Account for FutureOr when converting closures to Rtis.
Change-Id: Iffb4a3019ad51a991a15c6f8cd9ad603b88063aa Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/112641 Commit-Queue: Mayank Patke <[email protected]> Reviewed-by: Stephen Adams <[email protected]>
1 parent bd47ec2 commit 06509e3

File tree

1 file changed

+51
-35
lines changed
  • sdk/lib/_internal/js_runtime/lib

1 file changed

+51
-35
lines changed

sdk/lib/_internal/js_runtime/lib/rti.dart

Lines changed: 51 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -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.
354380
Rti 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.
364396
Rti 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.
414439
Rti _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

445458
Type 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.
19151928
bool _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

21242137
bool 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;
21262142
bool isGenericFunctionKind(Rti t) => Rti._getKind(t) == Rti.kindGenericFunction;
21272143

21282144
bool isGenericFunctionTypeParameter(Rti t) =>

0 commit comments

Comments
 (0)