[ddc] Avoid weak mode warning in FutureOr casts

This is not intended to change the result of the cast in any mode.

An optimization for casting null in weak mode accidentally added
warnings when casting to a FutureOr (non-nullable) of a legacy
type.

Also moves the `is` and `as` methods for FutureOr types from being
hard-coded in the compiler to the runtime method that builds the
type.

Tested on golem and found no attributable performance regressions:
https://golem.corp.goog/Comparison?team=dartdevc#targetA%3Ddartdevc-null%3BmachineTypeA%3Dlinux-x64%3BrevisionA%3D88970%3BpatchA%3Dnshahan-FutureOr-Fix%3BtargetB%3Ddartdevc-null%3BmachineTypeB%3Dlinux-x64%3BrevisionB%3D88964%3BpatchB%3DNone

Change-Id: I44a23c7e2e1d15bc6c383fc95b19f99b584a3f7a
Fixes: https://github.com/dart-lang/sdk/issues/43990
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/170001
Reviewed-by: Mark Zhou <markzipan@google.com>
Commit-Queue: Nicholas Shahan <nshahan@google.com>
This commit is contained in:
Nicholas Shahan 2020-11-02 21:45:09 +00:00 committed by commit-bot@chromium.org
parent 53c82cbc4b
commit ab7dc265d7
2 changed files with 25 additions and 23 deletions

View file

@ -1082,29 +1082,8 @@ class ProgramCompiler extends ComputeOnceConstantVisitor<js_ast.Expression>
}
if (c == _coreTypes.deprecatedFutureOrClass) {
// These methods are difficult to place in the runtime or patch files.
// * They need to be callable from the class but they can't be static
// methods on the FutureOr class in Dart because they reference the
// generic type parameter.
// * There isn't an obvious place in dart:_runtime were we could place a
// method that adds these type tests (similar to addTypeTests()) because
// in the bootstrap ordering the Future class hasn't been defined yet.
var typeParam =
TypeParameterType(c.typeParameters[0], Nullability.undetermined);
var typeT = visitTypeParameterType(typeParam);
var futureOfT = visitInterfaceType(InterfaceType(
_coreTypes.futureClass, currentLibrary.nonNullable, [typeParam]));
body.add(js.statement('''
#.is = function is_FutureOr(o) {
return #.is(o) || #.is(o);
}
''', [className, typeT, futureOfT]));
body.add(js.statement('''
#.as = function as_FutureOr(o) {
if (#.is(o) || #.is(o)) return o;
return #.as(o, this);
}
''', [className, typeT, futureOfT, runtimeModule]));
// Custom type tests for FutureOr types are attached when the type is
// constructed in the runtime normalizeFutureOr method.
return null;
}

View file

@ -164,6 +164,29 @@ normalizeFutureOr(typeConstructor, setBaseClass) {
// as a FutureOr because it is equal to 'async.FutureOr` (in the JS).
JS('!', '#[#] = #', genericType, _originalDeclaration, normalize);
JS('!', '#(#)', addTypeCaches, genericType);
// Add FutureOr specific is and as methods.
is_FutureOr(obj) =>
JS<bool>('!', '#.is(#)', typeArg, obj) ||
JS<bool>('!', '#(#).is(#)', getGenericClass(Future), typeArg, obj);
JS('!', '#.is = #', genericType, is_FutureOr);
as_FutureOr(obj) {
// Special test to handle case for mixed mode non-nullable FutureOr of a
// legacy type. This allows casts like `null as FutureOr<int*>` to work
// in weak and sound mode.
if (obj == null && _jsInstanceOf(typeArg, LegacyType)) {
return obj;
}
if (JS<bool>('!', '#.is(#)', typeArg, obj) ||
JS<bool>('!', '#(#).is(#)', getGenericClass(Future), typeArg, obj)) {
return obj;
}
return cast(obj, JS('!', '#(#)', getGenericClass(FutureOr), typeArg));
}
JS('!', '#.as = #', genericType, as_FutureOr);
return genericType;
}