From 7d8d3bb8078a3f0ce9a2a41f2120ff7db75ce0df Mon Sep 17 00:00:00 2001 From: Chloe Stefantsova Date: Tue, 5 Apr 2022 13:52:04 +0000 Subject: [PATCH] [cfe] Adjust nullability of FutureOrType after substitution Bug: https://github.com/dart-lang/sdk/issues/48631 Change-Id: I329a70386d59425cf3f157dc4b6316649f8aa389 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/240049 Reviewed-by: Johnni Winther Commit-Queue: Chloe Stefantsova --- .../testcases/nnbd/issue48631_1.dart | 13 +++++++ .../nnbd/issue48631_1.dart.strong.expect | 11 ++++++ ...ssue48631_1.dart.strong.transformed.expect | 11 ++++++ .../issue48631_1.dart.textual_outline.expect | 5 +++ ...631_1.dart.textual_outline_modelled.expect | 5 +++ .../nnbd/issue48631_1.dart.weak.expect | 11 ++++++ .../issue48631_1.dart.weak.modular.expect | 11 ++++++ .../issue48631_1.dart.weak.outline.expect | 12 +++++++ .../issue48631_1.dart.weak.transformed.expect | 11 ++++++ .../testcases/nnbd/issue48631_2.dart | 29 ++++++++++++++++ .../nnbd/issue48631_2.dart.strong.expect | 34 +++++++++++++++++++ ...ssue48631_2.dart.strong.transformed.expect | 34 +++++++++++++++++++ .../issue48631_2.dart.textual_outline.expect | 22 ++++++++++++ ...631_2.dart.textual_outline_modelled.expect | 22 ++++++++++++ .../nnbd/issue48631_2.dart.weak.expect | 34 +++++++++++++++++++ .../issue48631_2.dart.weak.modular.expect | 34 +++++++++++++++++++ .../issue48631_2.dart.weak.outline.expect | 28 +++++++++++++++ .../issue48631_2.dart.weak.transformed.expect | 34 +++++++++++++++++++ pkg/kernel/lib/type_algebra.dart | 17 +++++++++- 19 files changed, 377 insertions(+), 1 deletion(-) create mode 100644 pkg/front_end/testcases/nnbd/issue48631_1.dart create mode 100644 pkg/front_end/testcases/nnbd/issue48631_1.dart.strong.expect create mode 100644 pkg/front_end/testcases/nnbd/issue48631_1.dart.strong.transformed.expect create mode 100644 pkg/front_end/testcases/nnbd/issue48631_1.dart.textual_outline.expect create mode 100644 pkg/front_end/testcases/nnbd/issue48631_1.dart.textual_outline_modelled.expect create mode 100644 pkg/front_end/testcases/nnbd/issue48631_1.dart.weak.expect create mode 100644 pkg/front_end/testcases/nnbd/issue48631_1.dart.weak.modular.expect create mode 100644 pkg/front_end/testcases/nnbd/issue48631_1.dart.weak.outline.expect create mode 100644 pkg/front_end/testcases/nnbd/issue48631_1.dart.weak.transformed.expect create mode 100644 pkg/front_end/testcases/nnbd/issue48631_2.dart create mode 100644 pkg/front_end/testcases/nnbd/issue48631_2.dart.strong.expect create mode 100644 pkg/front_end/testcases/nnbd/issue48631_2.dart.strong.transformed.expect create mode 100644 pkg/front_end/testcases/nnbd/issue48631_2.dart.textual_outline.expect create mode 100644 pkg/front_end/testcases/nnbd/issue48631_2.dart.textual_outline_modelled.expect create mode 100644 pkg/front_end/testcases/nnbd/issue48631_2.dart.weak.expect create mode 100644 pkg/front_end/testcases/nnbd/issue48631_2.dart.weak.modular.expect create mode 100644 pkg/front_end/testcases/nnbd/issue48631_2.dart.weak.outline.expect create mode 100644 pkg/front_end/testcases/nnbd/issue48631_2.dart.weak.transformed.expect diff --git a/pkg/front_end/testcases/nnbd/issue48631_1.dart b/pkg/front_end/testcases/nnbd/issue48631_1.dart new file mode 100644 index 000000000000..f995c3ee21da --- /dev/null +++ b/pkg/front_end/testcases/nnbd/issue48631_1.dart @@ -0,0 +1,13 @@ +// 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. + +import 'dart:async'; + +FutureOr foo(T t) {} + +bar(bool t, S s) { + var x = [foo(s), s]; +} + +main() {} diff --git a/pkg/front_end/testcases/nnbd/issue48631_1.dart.strong.expect b/pkg/front_end/testcases/nnbd/issue48631_1.dart.strong.expect new file mode 100644 index 000000000000..a26757b9d275 --- /dev/null +++ b/pkg/front_end/testcases/nnbd/issue48631_1.dart.strong.expect @@ -0,0 +1,11 @@ +library /*isNonNullableByDefault*/; +import self as self; +import "dart:core" as core; + +import "dart:async"; + +static method foo(self::foo::T% t) → FutureOr {} +static method bar(core::bool t, self::bar::S% s) → dynamic { + core::List?> x = ?>[self::foo(s), s]; +} +static method main() → dynamic {} diff --git a/pkg/front_end/testcases/nnbd/issue48631_1.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/issue48631_1.dart.strong.transformed.expect new file mode 100644 index 000000000000..b425585cdec9 --- /dev/null +++ b/pkg/front_end/testcases/nnbd/issue48631_1.dart.strong.transformed.expect @@ -0,0 +1,11 @@ +library /*isNonNullableByDefault*/; +import self as self; +import "dart:core" as core; + +import "dart:async"; + +static method foo(self::foo::T% t) → FutureOr {} +static method bar(core::bool t, self::bar::S% s) → dynamic { + core::List?> x = core::_GrowableList::_literal2?>(self::foo(s), s); +} +static method main() → dynamic {} diff --git a/pkg/front_end/testcases/nnbd/issue48631_1.dart.textual_outline.expect b/pkg/front_end/testcases/nnbd/issue48631_1.dart.textual_outline.expect new file mode 100644 index 000000000000..65faadde8bd1 --- /dev/null +++ b/pkg/front_end/testcases/nnbd/issue48631_1.dart.textual_outline.expect @@ -0,0 +1,5 @@ +import 'dart:async'; + +FutureOr foo(T t) {} +bar(bool t, S s) {} +main() {} diff --git a/pkg/front_end/testcases/nnbd/issue48631_1.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/nnbd/issue48631_1.dart.textual_outline_modelled.expect new file mode 100644 index 000000000000..65faadde8bd1 --- /dev/null +++ b/pkg/front_end/testcases/nnbd/issue48631_1.dart.textual_outline_modelled.expect @@ -0,0 +1,5 @@ +import 'dart:async'; + +FutureOr foo(T t) {} +bar(bool t, S s) {} +main() {} diff --git a/pkg/front_end/testcases/nnbd/issue48631_1.dart.weak.expect b/pkg/front_end/testcases/nnbd/issue48631_1.dart.weak.expect new file mode 100644 index 000000000000..a26757b9d275 --- /dev/null +++ b/pkg/front_end/testcases/nnbd/issue48631_1.dart.weak.expect @@ -0,0 +1,11 @@ +library /*isNonNullableByDefault*/; +import self as self; +import "dart:core" as core; + +import "dart:async"; + +static method foo(self::foo::T% t) → FutureOr {} +static method bar(core::bool t, self::bar::S% s) → dynamic { + core::List?> x = ?>[self::foo(s), s]; +} +static method main() → dynamic {} diff --git a/pkg/front_end/testcases/nnbd/issue48631_1.dart.weak.modular.expect b/pkg/front_end/testcases/nnbd/issue48631_1.dart.weak.modular.expect new file mode 100644 index 000000000000..a26757b9d275 --- /dev/null +++ b/pkg/front_end/testcases/nnbd/issue48631_1.dart.weak.modular.expect @@ -0,0 +1,11 @@ +library /*isNonNullableByDefault*/; +import self as self; +import "dart:core" as core; + +import "dart:async"; + +static method foo(self::foo::T% t) → FutureOr {} +static method bar(core::bool t, self::bar::S% s) → dynamic { + core::List?> x = ?>[self::foo(s), s]; +} +static method main() → dynamic {} diff --git a/pkg/front_end/testcases/nnbd/issue48631_1.dart.weak.outline.expect b/pkg/front_end/testcases/nnbd/issue48631_1.dart.weak.outline.expect new file mode 100644 index 000000000000..f36627964b3d --- /dev/null +++ b/pkg/front_end/testcases/nnbd/issue48631_1.dart.weak.outline.expect @@ -0,0 +1,12 @@ +library /*isNonNullableByDefault*/; +import self as self; +import "dart:core" as core; + +import "dart:async"; + +static method foo(self::foo::T% t) → FutureOr + ; +static method bar(core::bool t, self::bar::S% s) → dynamic + ; +static method main() → dynamic + ; diff --git a/pkg/front_end/testcases/nnbd/issue48631_1.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/issue48631_1.dart.weak.transformed.expect new file mode 100644 index 000000000000..b425585cdec9 --- /dev/null +++ b/pkg/front_end/testcases/nnbd/issue48631_1.dart.weak.transformed.expect @@ -0,0 +1,11 @@ +library /*isNonNullableByDefault*/; +import self as self; +import "dart:core" as core; + +import "dart:async"; + +static method foo(self::foo::T% t) → FutureOr {} +static method bar(core::bool t, self::bar::S% s) → dynamic { + core::List?> x = core::_GrowableList::_literal2?>(self::foo(s), s); +} +static method main() → dynamic {} diff --git a/pkg/front_end/testcases/nnbd/issue48631_2.dart b/pkg/front_end/testcases/nnbd/issue48631_2.dart new file mode 100644 index 000000000000..2cf30baa01c8 --- /dev/null +++ b/pkg/front_end/testcases/nnbd/issue48631_2.dart @@ -0,0 +1,29 @@ +// 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. + +import 'dart:async'; + +abstract class A { + T foo(B b); +} + +class B { + B(X x); +} + +class C { + final Bar, D> bar; + + C(this.bar); +} + +abstract class D implements A {} + +typedef Bar = V Function(U); + +final baz = C((a) { + return a.foo(B(Future.value(0))); +}); + +main() {} diff --git a/pkg/front_end/testcases/nnbd/issue48631_2.dart.strong.expect b/pkg/front_end/testcases/nnbd/issue48631_2.dart.strong.expect new file mode 100644 index 000000000000..e842794b2817 --- /dev/null +++ b/pkg/front_end/testcases/nnbd/issue48631_2.dart.strong.expect @@ -0,0 +1,34 @@ +library /*isNonNullableByDefault*/; +import self as self; +import "dart:core" as core; +import "dart:async" as asy; + +import "dart:async"; + +typedef Bar = (U) → V%; +abstract class A extends core::Object { + synthetic constructor •() → self::A + : super core::Object::•() + ; + abstract method foo(self::B b) → self::A::foo::T%; +} +class B extends core::Object { + constructor •(self::B::X% x) → self::B + : super core::Object::•() + ; +} +class C extends core::Object { + final field (self::D) → FutureOr% bar; + constructor •((self::D) → FutureOr% bar) → self::C + : self::C::bar = bar, super core::Object::•() + ; +} +abstract class D extends core::Object implements self::A { + synthetic constructor •() → self::D + : super core::Object::•() + ; +} +static final field self::C baz = new self::C::•((self::D a) → FutureOr { + return a.{self::A::foo}>(new self::B::•>(asy::Future::value(0))){(self::B>) → FutureOr}; +}); +static method main() → dynamic {} diff --git a/pkg/front_end/testcases/nnbd/issue48631_2.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/issue48631_2.dart.strong.transformed.expect new file mode 100644 index 000000000000..e842794b2817 --- /dev/null +++ b/pkg/front_end/testcases/nnbd/issue48631_2.dart.strong.transformed.expect @@ -0,0 +1,34 @@ +library /*isNonNullableByDefault*/; +import self as self; +import "dart:core" as core; +import "dart:async" as asy; + +import "dart:async"; + +typedef Bar = (U) → V%; +abstract class A extends core::Object { + synthetic constructor •() → self::A + : super core::Object::•() + ; + abstract method foo(self::B b) → self::A::foo::T%; +} +class B extends core::Object { + constructor •(self::B::X% x) → self::B + : super core::Object::•() + ; +} +class C extends core::Object { + final field (self::D) → FutureOr% bar; + constructor •((self::D) → FutureOr% bar) → self::C + : self::C::bar = bar, super core::Object::•() + ; +} +abstract class D extends core::Object implements self::A { + synthetic constructor •() → self::D + : super core::Object::•() + ; +} +static final field self::C baz = new self::C::•((self::D a) → FutureOr { + return a.{self::A::foo}>(new self::B::•>(asy::Future::value(0))){(self::B>) → FutureOr}; +}); +static method main() → dynamic {} diff --git a/pkg/front_end/testcases/nnbd/issue48631_2.dart.textual_outline.expect b/pkg/front_end/testcases/nnbd/issue48631_2.dart.textual_outline.expect new file mode 100644 index 000000000000..a409162df57c --- /dev/null +++ b/pkg/front_end/testcases/nnbd/issue48631_2.dart.textual_outline.expect @@ -0,0 +1,22 @@ +import 'dart:async'; + +abstract class A { + T foo(B b); +} + +class B { + B(X x); +} + +class C { + final Bar, D> bar; + C(this.bar); +} + +abstract class D implements A {} + +typedef Bar = V Function(U); +final baz = C((a) { + return a.foo(B(Future.value(0))); +}); +main() {} diff --git a/pkg/front_end/testcases/nnbd/issue48631_2.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/nnbd/issue48631_2.dart.textual_outline_modelled.expect new file mode 100644 index 000000000000..bee82dc4ea11 --- /dev/null +++ b/pkg/front_end/testcases/nnbd/issue48631_2.dart.textual_outline_modelled.expect @@ -0,0 +1,22 @@ +import 'dart:async'; + +abstract class A { + T foo(B b); +} + +abstract class D implements A {} + +class B { + B(X x); +} + +class C { + C(this.bar); + final Bar, D> bar; +} + +final baz = C((a) { + return a.foo(B(Future.value(0))); +}); +main() {} +typedef Bar = V Function(U); diff --git a/pkg/front_end/testcases/nnbd/issue48631_2.dart.weak.expect b/pkg/front_end/testcases/nnbd/issue48631_2.dart.weak.expect new file mode 100644 index 000000000000..e842794b2817 --- /dev/null +++ b/pkg/front_end/testcases/nnbd/issue48631_2.dart.weak.expect @@ -0,0 +1,34 @@ +library /*isNonNullableByDefault*/; +import self as self; +import "dart:core" as core; +import "dart:async" as asy; + +import "dart:async"; + +typedef Bar = (U) → V%; +abstract class A extends core::Object { + synthetic constructor •() → self::A + : super core::Object::•() + ; + abstract method foo(self::B b) → self::A::foo::T%; +} +class B extends core::Object { + constructor •(self::B::X% x) → self::B + : super core::Object::•() + ; +} +class C extends core::Object { + final field (self::D) → FutureOr% bar; + constructor •((self::D) → FutureOr% bar) → self::C + : self::C::bar = bar, super core::Object::•() + ; +} +abstract class D extends core::Object implements self::A { + synthetic constructor •() → self::D + : super core::Object::•() + ; +} +static final field self::C baz = new self::C::•((self::D a) → FutureOr { + return a.{self::A::foo}>(new self::B::•>(asy::Future::value(0))){(self::B>) → FutureOr}; +}); +static method main() → dynamic {} diff --git a/pkg/front_end/testcases/nnbd/issue48631_2.dart.weak.modular.expect b/pkg/front_end/testcases/nnbd/issue48631_2.dart.weak.modular.expect new file mode 100644 index 000000000000..e842794b2817 --- /dev/null +++ b/pkg/front_end/testcases/nnbd/issue48631_2.dart.weak.modular.expect @@ -0,0 +1,34 @@ +library /*isNonNullableByDefault*/; +import self as self; +import "dart:core" as core; +import "dart:async" as asy; + +import "dart:async"; + +typedef Bar = (U) → V%; +abstract class A extends core::Object { + synthetic constructor •() → self::A + : super core::Object::•() + ; + abstract method foo(self::B b) → self::A::foo::T%; +} +class B extends core::Object { + constructor •(self::B::X% x) → self::B + : super core::Object::•() + ; +} +class C extends core::Object { + final field (self::D) → FutureOr% bar; + constructor •((self::D) → FutureOr% bar) → self::C + : self::C::bar = bar, super core::Object::•() + ; +} +abstract class D extends core::Object implements self::A { + synthetic constructor •() → self::D + : super core::Object::•() + ; +} +static final field self::C baz = new self::C::•((self::D a) → FutureOr { + return a.{self::A::foo}>(new self::B::•>(asy::Future::value(0))){(self::B>) → FutureOr}; +}); +static method main() → dynamic {} diff --git a/pkg/front_end/testcases/nnbd/issue48631_2.dart.weak.outline.expect b/pkg/front_end/testcases/nnbd/issue48631_2.dart.weak.outline.expect new file mode 100644 index 000000000000..4eff2cf00b26 --- /dev/null +++ b/pkg/front_end/testcases/nnbd/issue48631_2.dart.weak.outline.expect @@ -0,0 +1,28 @@ +library /*isNonNullableByDefault*/; +import self as self; +import "dart:core" as core; + +import "dart:async"; + +typedef Bar = (U) → V%; +abstract class A extends core::Object { + synthetic constructor •() → self::A + ; + abstract method foo(self::B b) → self::A::foo::T%; +} +class B extends core::Object { + constructor •(self::B::X% x) → self::B + ; +} +class C extends core::Object { + final field (self::D) → FutureOr% bar; + constructor •((self::D) → FutureOr% bar) → self::C + ; +} +abstract class D extends core::Object implements self::A { + synthetic constructor •() → self::D + ; +} +static final field self::C baz; +static method main() → dynamic + ; diff --git a/pkg/front_end/testcases/nnbd/issue48631_2.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/issue48631_2.dart.weak.transformed.expect new file mode 100644 index 000000000000..e842794b2817 --- /dev/null +++ b/pkg/front_end/testcases/nnbd/issue48631_2.dart.weak.transformed.expect @@ -0,0 +1,34 @@ +library /*isNonNullableByDefault*/; +import self as self; +import "dart:core" as core; +import "dart:async" as asy; + +import "dart:async"; + +typedef Bar = (U) → V%; +abstract class A extends core::Object { + synthetic constructor •() → self::A + : super core::Object::•() + ; + abstract method foo(self::B b) → self::A::foo::T%; +} +class B extends core::Object { + constructor •(self::B::X% x) → self::B + : super core::Object::•() + ; +} +class C extends core::Object { + final field (self::D) → FutureOr% bar; + constructor •((self::D) → FutureOr% bar) → self::C + : self::C::bar = bar, super core::Object::•() + ; +} +abstract class D extends core::Object implements self::A { + synthetic constructor •() → self::D + : super core::Object::•() + ; +} +static final field self::C baz = new self::C::•((self::D a) → FutureOr { + return a.{self::A::foo}>(new self::B::•>(asy::Future::value(0))){(self::B>) → FutureOr}; +}); +static method main() → dynamic {} diff --git a/pkg/kernel/lib/type_algebra.dart b/pkg/kernel/lib/type_algebra.dart index 7afdf2dbe495..fe6e3562dc08 100644 --- a/pkg/kernel/lib/type_algebra.dart +++ b/pkg/kernel/lib/type_algebra.dart @@ -614,7 +614,22 @@ abstract class _TypeSubstitutor extends DartTypeVisitor { int before = useCounter; DartType typeArgument = node.typeArgument.accept(this); if (useCounter == before) return node; - return new FutureOrType(typeArgument, 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 nullability; + if (node.declaredNullability == Nullability.undetermined) { + if (typeArgument.nullability == Nullability.undetermined) { + nullability = Nullability.undetermined; + } else { + nullability = Nullability.nonNullable; + } + } else { + nullability = node.declaredNullability; + } + return new FutureOrType(typeArgument, nullability); } @override