[cfe] Adjust the resulting nullabilities in 'flatten'

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

Change-Id: I428933193611ffc68c750e6dc91f54ee2385036b
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/306400
Reviewed-by: Johnni Winther <johnniwinther@google.com>
Commit-Queue: Chloe Stefantsova <cstefantsova@google.com>
This commit is contained in:
Chloe Stefantsova
2023-05-31 07:33:37 +00:00
committed by Commit Queue
parent bda10d7987
commit 9fecc29dbb
10 changed files with 139 additions and 4 deletions
@@ -0,0 +1,13 @@
// Copyright (c) 2023, 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.
class A {}
Future<void> h1<X extends Future<A>?>(X x) async {
var x2 = await x; // Remains null.
print([x2].runtimeType); // 'List<A>`.
print(x2); // 'null': A soundness violation.
}
void main() async => await h1<Null>(null);
@@ -0,0 +1,17 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
import "dart:async" as asy;
class A extends core::Object {
synthetic constructor •() → self::A
: super core::Object::•()
;
}
static method h1<X extends asy::Future<self::A>?>(self::h1::X% x) → asy::Future<void> async /* futureValueType= void */ {
self::A? x2 = await x /* runtimeCheckType= asy::Future<self::A?> */ ;
core::print(<self::A?>[x2].{core::Object::runtimeType}{core::Type});
core::print(x2);
}
static method main() → void async /* futureValueType= void */
return await self::h1<Null>(null);
@@ -0,0 +1,17 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
import "dart:async" as asy;
class A extends core::Object {
synthetic constructor •() → self::A
: super core::Object::•()
;
}
static method h1<X extends asy::Future<self::A>?>(self::h1::X% x) → asy::Future<void> async /* futureValueType= void */ {
self::A? x2 = await x /* runtimeCheckType= asy::Future<self::A?> */ ;
core::print(core::_GrowableList::_literal1<self::A?>(x2).{core::Object::runtimeType}{core::Type});
core::print(x2);
}
static method main() → void async /* futureValueType= void */
return await self::h1<Null>(null);
@@ -0,0 +1,4 @@
class A {}
Future<void> h1<X extends Future<A>?>(X x) async {}
void main() async => await h1<Null>(null);
@@ -0,0 +1,5 @@
Future<void> h1<X extends Future<A>?>(X x) async {}
class A {}
void main() async => await h1<Null>(null);
@@ -0,0 +1,17 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
import "dart:async" as asy;
class A extends core::Object {
synthetic constructor •() → self::A
: super core::Object::•()
;
}
static method h1<X extends asy::Future<self::A>?>(self::h1::X% x) → asy::Future<void> async /* futureValueType= void */ {
self::A? x2 = await x /* runtimeCheckType= asy::Future<self::A?> */ ;
core::print(<self::A?>[x2].{core::Object::runtimeType}{core::Type});
core::print(x2);
}
static method main() → void async /* futureValueType= void */
return await self::h1<Null>(null);
@@ -0,0 +1,17 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
import "dart:async" as asy;
class A extends core::Object {
synthetic constructor •() → self::A
: super core::Object::•()
;
}
static method h1<X extends asy::Future<self::A>?>(self::h1::X% x) → asy::Future<void> async /* futureValueType= void */ {
self::A? x2 = await x /* runtimeCheckType= asy::Future<self::A?> */ ;
core::print(<self::A?>[x2].{core::Object::runtimeType}{core::Type});
core::print(x2);
}
static method main() → void async /* futureValueType= void */
return await self::h1<Null>(null);
@@ -0,0 +1,13 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
import "dart:async" as asy;
class A extends core::Object {
synthetic constructor •() → self::A
;
}
static method h1<X extends asy::Future<self::A>?>(self::h1::X% x) → asy::Future<void> async
;
static method main() → void async
;
@@ -0,0 +1,17 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
import "dart:async" as asy;
class A extends core::Object {
synthetic constructor •() → self::A
: super core::Object::•()
;
}
static method h1<X extends asy::Future<self::A>?>(self::h1::X% x) → asy::Future<void> async /* futureValueType= void */ {
self::A? x2 = await x /* runtimeCheckType= asy::Future<self::A?> */ ;
core::print(core::_GrowableList::_literal1<self::A?>(x2).{core::Object::runtimeType}{core::Type});
core::print(x2);
}
static method main() → void async /* futureValueType= void */
return await self::h1<Null>(null);
+19 -4
View File
@@ -129,18 +129,33 @@ abstract class TypeEnvironment extends Types {
DartType bound = t.right;
DartType? futureType = _futureTypeOf(bound);
if (futureType != null) {
return _withDeclaredNullability(flatten(futureType), t.nullability);
DartType flattenedFutureType = flatten(futureType);
return _withDeclaredNullability(flattenedFutureType,
uniteNullabilities(t.nullability, flattenedFutureType.nullability));
} else {
return _withDeclaredNullability(flatten(t.left), t.nullability);
DartType flattenedFutureType = flatten(t.left);
return _withDeclaredNullability(flattenedFutureType,
uniteNullabilities(t.nullability, flattenedFutureType.nullability));
}
} else {
DartType? futureType = _futureTypeOf(t);
if (futureType is InterfaceType) {
assert(futureType.classNode == coreTypes.futureClass);
DartType typeArgument = futureType.typeArguments.single;
return _withDeclaredNullability(
futureType.typeArguments.single, t.nullability);
typeArgument,
uniteNullabilities(
t.nullability,
uniteNullabilities(
futureType.nullability, typeArgument.nullability)));
} else if (futureType is FutureOrType) {
return _withDeclaredNullability(futureType.typeArgument, t.nullability);
DartType typeArgument = futureType.typeArgument;
return _withDeclaredNullability(
typeArgument,
uniteNullabilities(
t.nullability,
uniteNullabilities(
futureType.nullability, typeArgument.nullability)));
} else {
return t;
}