Migration: fix handling of async functions that return FutureOr.

Change-Id: I613d0bfd8340062bb78b20a8fd035d24a4ccdf8d
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/155543
Commit-Queue: Paul Berry <paulberry@google.com>
Reviewed-by: Samuel Rawlins <srawlins@google.com>
This commit is contained in:
Paul Berry 2020-07-23 13:27:28 +00:00 committed by commit-bot@chromium.org
parent f907e561c9
commit 2225b6f472
3 changed files with 54 additions and 2 deletions

View file

@ -2995,11 +2995,26 @@ class EdgeBuilder extends GeneralizingAstVisitor<DecoratedType>
/// upcast T to that type if possible, skipping the flatten when not
/// necessary.
DecoratedType _wrapFuture(DecoratedType type, AstNode node) {
if (type.type.isDartCoreNull || type.type.isBottom) {
var dartType = type.type;
if (dartType.isDartCoreNull || dartType.isBottom) {
return _futureOf(type, node);
}
if (_typeSystem.isSubtypeOf(type.type, typeProvider.futureDynamicType)) {
if (dartType is InterfaceType &&
dartType.element == typeProvider.futureOrElement) {
var typeArguments = type.typeArguments;
if (typeArguments.length == 1) {
// Wrapping FutureOr<T?1>?2 should produce Future<T?3>, where either 1
// or 2 being nullable causes 3 to become nullable.
var typeArgument = typeArguments[0];
return _futureOf(
typeArgument
.withNode(NullabilityNode.forLUB(typeArgument.node, type.node)),
node);
}
}
if (_typeSystem.isSubtypeOf(dartType, typeProvider.futureDynamicType)) {
return _decoratedClassHierarchy.asInstanceOf(
type, typeProvider.futureDynamicType.element);
}

View file

@ -5583,6 +5583,20 @@ test() => C.one();
await _checkSingleFileChanges(content, expected);
}
Future<void> test_return_future_or_null_from_async_method() async {
var content = '''
import 'dart:async';
Future<Null> f() async => g();
FutureOr<Null> g() => null;
''';
var expected = '''
import 'dart:async';
Future<Null> f() async => g();
FutureOr<Null> g() => null;
''';
await _checkSingleFileChanges(content, expected);
}
Future<void> test_setter_overrides_implicit_setter() async {
var content = '''
class A {

View file

@ -6812,6 +6812,29 @@ int g() => 1;
// No assertions; just checking that it doesn't crash.
}
Future<void> test_return_from_async_futureOr_to_future() async {
await analyze('''
import 'dart:async';
Future<Object> f(FutureOr<int> x) async => x;
''');
var lubNodeMatcher = anyNode;
assertEdge(lubNodeMatcher, decoratedTypeAnnotation('Object').node,
hard: false, checkable: false);
var lubNode = lubNodeMatcher.matchingNode as NullabilityNodeForLUB;
expect(lubNode.left, same(decoratedTypeAnnotation('int> x').node));
expect(lubNode.right, same(decoratedTypeAnnotation('FutureOr<int>').node));
}
Future<void> test_return_from_async_list_to_future() async {
await analyze('''
import 'dart:async';
Future<Object> f(List<int> x) async => x;
''');
assertEdge(decoratedTypeAnnotation('List<int>').node,
decoratedTypeAnnotation('Object').node,
hard: false, checkable: false);
}
Future<void> test_return_from_async_null() async {
await analyze('''
Future<int> f() async {