[cfe] Adjust nullability of FutureOr in ReplacementVisitor

This fix is analogous to that made in _TypeSubstitutor in
https://dart-review.googlesource.com/c/sdk/+/240049, but made for
ReplacementVisitor.

Closes https://github.com/dart-lang/sdk/issues/48768

Change-Id: Ie3ac8fe834210d1249cbd5bd3d68b416f9efc034
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/240722
Auto-Submit: Chloe Stefantsova <cstefantsova@google.com>
Reviewed-by: Johnni Winther <johnniwinther@google.com>
Commit-Queue: Johnni Winther <johnniwinther@google.com>
This commit is contained in:
Chloe Stefantsova
2022-04-11 06:39:50 +00:00
committed by Commit Bot
parent f2b5ba82ab
commit 3d27f5cb79
10 changed files with 132 additions and 2 deletions
@@ -0,0 +1,9 @@
// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
foo(dynamic y) async {
var a = await (<X>(List<X> Function() x, X x2) => x2)(() => y, throw 0);
}
main() {}
@@ -0,0 +1,8 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
static method foo(dynamic y) → dynamic async /* futureValueType= dynamic */ {
dynamic a = await(<X extends core::Object? = dynamic>(() → core::List<X%> x, X% x2) → X% => x2)<FutureOr<dynamic>>(() → core::List<FutureOr<dynamic>> => y as{TypeError,ForDynamic,ForNonNullableByDefault} core::List<FutureOr<dynamic>>, throw 0){(() → core::List<FutureOr<dynamic>?>, FutureOr<dynamic>?) → FutureOr<dynamic>?};
}
static method main() → dynamic {}
@@ -0,0 +1,34 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:async" as asy;
import "dart:core" as core;
static method foo(dynamic y) → dynamic /* futureValueType= dynamic */ /* originally async */ {
final asy::_Future<dynamic> :async_future = new asy::_Future::•<dynamic>();
core::bool* :is_sync = false;
dynamic :return_value;
(dynamic) → dynamic :async_op_then;
(core::Object, core::StackTrace) → dynamic :async_op_error;
core::int :await_jump_var = 0;
dynamic :await_ctx_var;
dynamic :saved_try_context_var0;
function :async_op(dynamic :result_or_exception, dynamic :stack_trace) → dynamic yielding
try {
#L1:
{
[yield] let dynamic #t1 = asy::_awaitHelper((<X extends core::Object? = dynamic>(() → core::List<X%> x, X% x2) → X% => x2)<FutureOr<dynamic>>(() → core::List<FutureOr<dynamic>> => y as{TypeError,ForDynamic,ForNonNullableByDefault} core::List<FutureOr<dynamic>>, throw 0){(() → core::List<FutureOr<dynamic>?>, FutureOr<dynamic>?) → FutureOr<dynamic>?}, :async_op_then, :async_op_error) in null;
dynamic a = :result_or_exception;
}
asy::_completeWithNoFutureOnAsyncReturn(:async_future, :return_value, :is_sync);
return;
}
on dynamic catch(dynamic exception, core::StackTrace stack_trace) {
asy::_completeOnAsyncError(:async_future, exception, stack_trace, :is_sync);
}
:async_op_then = asy::_asyncThenWrapperHelper(:async_op);
:async_op_error = asy::_asyncErrorWrapperHelper(:async_op);
:async_op(null, null){() → dynamic};
:is_sync = true;
return :async_future;
}
static method main() → dynamic {}
@@ -0,0 +1,2 @@
foo(dynamic y) async {}
main() {}
@@ -0,0 +1,2 @@
foo(dynamic y) async {}
main() {}
@@ -0,0 +1,8 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
static method foo(dynamic y) → dynamic async /* futureValueType= dynamic */ {
dynamic a = await(<X extends core::Object? = dynamic>(() → core::List<X%> x, X% x2) → X% => x2)<FutureOr<dynamic>>(() → core::List<FutureOr<dynamic>> => y as{TypeError,ForDynamic,ForNonNullableByDefault} core::List<FutureOr<dynamic>>, throw 0){(() → core::List<FutureOr<dynamic>?>, FutureOr<dynamic>?) → FutureOr<dynamic>?};
}
static method main() → dynamic {}
@@ -0,0 +1,8 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
static method foo(dynamic y) → dynamic async /* futureValueType= dynamic */ {
dynamic a = await(<X extends core::Object? = dynamic>(() → core::List<X%> x, X% x2) → X% => x2)<FutureOr<dynamic>>(() → core::List<FutureOr<dynamic>> => y as{TypeError,ForDynamic,ForNonNullableByDefault} core::List<FutureOr<dynamic>>, throw 0){(() → core::List<FutureOr<dynamic>?>, FutureOr<dynamic>?) → FutureOr<dynamic>?};
}
static method main() → dynamic {}
@@ -0,0 +1,7 @@
library /*isNonNullableByDefault*/;
import self as self;
static method foo(dynamic y) → dynamic async
;
static method main() → dynamic
;
@@ -0,0 +1,34 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:async" as asy;
import "dart:core" as core;
static method foo(dynamic y) → dynamic /* futureValueType= dynamic */ /* originally async */ {
final asy::_Future<dynamic> :async_future = new asy::_Future::•<dynamic>();
core::bool* :is_sync = false;
dynamic :return_value;
(dynamic) → dynamic :async_op_then;
(core::Object, core::StackTrace) → dynamic :async_op_error;
core::int :await_jump_var = 0;
dynamic :await_ctx_var;
dynamic :saved_try_context_var0;
function :async_op(dynamic :result_or_exception, dynamic :stack_trace) → dynamic yielding
try {
#L1:
{
[yield] let dynamic #t1 = asy::_awaitHelper((<X extends core::Object? = dynamic>(() → core::List<X%> x, X% x2) → X% => x2)<FutureOr<dynamic>>(() → core::List<FutureOr<dynamic>> => y as{TypeError,ForDynamic,ForNonNullableByDefault} core::List<FutureOr<dynamic>>, throw 0){(() → core::List<FutureOr<dynamic>?>, FutureOr<dynamic>?) → FutureOr<dynamic>?}, :async_op_then, :async_op_error) in null;
dynamic a = :result_or_exception;
}
asy::_completeWithNoFutureOnAsyncReturn(:async_future, :return_value, :is_sync);
return;
}
on dynamic catch(dynamic exception, core::StackTrace stack_trace) {
asy::_completeOnAsyncError(:async_future, exception, stack_trace, :is_sync);
}
:async_op_then = asy::_asyncThenWrapperHelper(:async_op);
:async_op_error = asy::_asyncErrorWrapperHelper(:async_op);
:async_op(null, null){() → dynamic};
:is_sync = true;
return :async_future;
}
static method main() → dynamic {}
+20 -2
View File
@@ -171,8 +171,26 @@ class ReplacementVisitor implements DartTypeVisitor1<DartType?, int> {
// No nullability or type arguments needed to be substituted.
return null;
} else {
return new FutureOrType(newTypeArgument ?? node.typeArgument,
newNullability ?? node.declaredNullability);
newTypeArgument ??= node.typeArgument;
newNullability ??= node.declaredNullability;
// The top-level nullability of a FutureOr should remain the same, with
// the exception of the case of [Nullability.undetermined]. In that case
// it remains undetermined if the nullability of [typeArgument] is
// undetermined, and otherwise it should become
// [Nullability.nonNullable].
Nullability adjustedNullability;
if (newNullability == Nullability.undetermined) {
if (newTypeArgument.nullability == Nullability.undetermined) {
adjustedNullability = Nullability.undetermined;
} else {
adjustedNullability = Nullability.nonNullable;
}
} else {
adjustedNullability = newNullability;
}
return new FutureOrType(newTypeArgument, adjustedNullability);
}
}