mirror of
https://github.com/dart-lang/sdk
synced 2024-11-02 12:24:24 +00:00
[VM/nnbd] Nullability of FutureOr and of its type arg do not necessarily match.
Change-Id: Ie1cb6287cdfa852c8ac73868b571b422fbc9dc0a Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/137460 Commit-Queue: Régis Crelier <regis@google.com> Reviewed-by: Alexander Markov <alexmarkov@google.com>
This commit is contained in:
parent
38508be344
commit
acd7b8367e
9 changed files with 50 additions and 33 deletions
|
@ -2270,7 +2270,9 @@ FlowGraphCompiler::GetTypeTestStubKindForTypeParameter(
|
|||
// never have a value of a function type, then we can safely do a 4-type
|
||||
// test instead of a 6-type test.
|
||||
AbstractType& bound = AbstractType::Handle(zone(), type_param.bound());
|
||||
bound = bound.UnwrapFutureOr();
|
||||
if (bound.IsFutureOrType()) {
|
||||
bound = bound.UnwrapFutureOr();
|
||||
}
|
||||
return !bound.IsTopType() && !bound.IsObjectType() &&
|
||||
!bound.IsFunctionType() && !bound.IsDartFunctionType() &&
|
||||
bound.IsType()
|
||||
|
|
|
@ -628,8 +628,10 @@ void FlowGraphCompiler::GenerateInstanceOf(TokenPosition token_pos,
|
|||
// 'null' is an instance of Null, Object*, Never*, void, and dynamic.
|
||||
// In addition, 'null' is an instance of any nullable type.
|
||||
// It is also an instance of FutureOr<T> if it is an instance of T.
|
||||
const AbstractType& unwrapped_type =
|
||||
AbstractType::Handle(type.UnwrapFutureOr());
|
||||
AbstractType& unwrapped_type = AbstractType::Handle(type.raw());
|
||||
if (unwrapped_type.IsFutureOrType()) {
|
||||
unwrapped_type = unwrapped_type.UnwrapFutureOr();
|
||||
}
|
||||
if (!unwrapped_type.IsTypeParameter() || unwrapped_type.IsNullable()) {
|
||||
// Only nullable type parameter remains nullable after instantiation.
|
||||
// See NullIsInstanceOf().
|
||||
|
|
|
@ -604,8 +604,10 @@ void FlowGraphCompiler::GenerateInstanceOf(TokenPosition token_pos,
|
|||
// 'null' is an instance of Null, Object*, Never*, void, and dynamic.
|
||||
// In addition, 'null' is an instance of any nullable type.
|
||||
// It is also an instance of FutureOr<T> if it is an instance of T.
|
||||
const AbstractType& unwrapped_type =
|
||||
AbstractType::Handle(type.UnwrapFutureOr());
|
||||
AbstractType& unwrapped_type = AbstractType::Handle(type.raw());
|
||||
if (unwrapped_type.IsFutureOrType()) {
|
||||
unwrapped_type = unwrapped_type.UnwrapFutureOr();
|
||||
}
|
||||
if (!unwrapped_type.IsTypeParameter() || unwrapped_type.IsNullable()) {
|
||||
// Only nullable type parameter remains nullable after instantiation.
|
||||
// See NullIsInstanceOf().
|
||||
|
|
|
@ -608,8 +608,10 @@ void FlowGraphCompiler::GenerateInstanceOf(TokenPosition token_pos,
|
|||
// 'null' is an instance of Null, Object*, Never*, void, and dynamic.
|
||||
// In addition, 'null' is an instance of any nullable type.
|
||||
// It is also an instance of FutureOr<T> if it is an instance of T.
|
||||
const AbstractType& unwrapped_type =
|
||||
AbstractType::Handle(type.UnwrapFutureOr());
|
||||
AbstractType& unwrapped_type = AbstractType::Handle(type.raw());
|
||||
if (unwrapped_type.IsFutureOrType()) {
|
||||
unwrapped_type = unwrapped_type.UnwrapFutureOr();
|
||||
}
|
||||
if (!unwrapped_type.IsTypeParameter() || unwrapped_type.IsNullable()) {
|
||||
// Only nullable type parameter remains nullable after instantiation.
|
||||
// See NullIsInstanceOf().
|
||||
|
|
|
@ -626,8 +626,10 @@ void FlowGraphCompiler::GenerateInstanceOf(TokenPosition token_pos,
|
|||
// 'null' is an instance of Null, Object*, Never*, void, and dynamic.
|
||||
// In addition, 'null' is an instance of any nullable type.
|
||||
// It is also an instance of FutureOr<T> if it is an instance of T.
|
||||
const AbstractType& unwrapped_type =
|
||||
AbstractType::Handle(type.UnwrapFutureOr());
|
||||
AbstractType& unwrapped_type = AbstractType::Handle(type.raw());
|
||||
if (unwrapped_type.IsFutureOrType()) {
|
||||
unwrapped_type = unwrapped_type.UnwrapFutureOr();
|
||||
}
|
||||
if (!unwrapped_type.IsTypeParameter() || unwrapped_type.IsNullable()) {
|
||||
// Only nullable type parameter remains nullable after instantiation.
|
||||
// See NullIsInstanceOf().
|
||||
|
|
|
@ -3235,8 +3235,11 @@ static bool MayBeNumber(CompileType* type) {
|
|||
if (type->IsNone()) {
|
||||
return false;
|
||||
}
|
||||
const AbstractType& unwrapped_type =
|
||||
AbstractType::Handle(type->ToAbstractType()->UnwrapFutureOr());
|
||||
AbstractType& unwrapped_type =
|
||||
AbstractType::Handle(type->ToAbstractType()->raw());
|
||||
if (unwrapped_type.IsFutureOrType()) {
|
||||
unwrapped_type = unwrapped_type.UnwrapFutureOr();
|
||||
}
|
||||
// Note that type 'Number' is a subtype of itself.
|
||||
return unwrapped_type.IsTopType() || unwrapped_type.IsObjectType() ||
|
||||
unwrapped_type.IsTypeParameter() ||
|
||||
|
|
|
@ -1104,8 +1104,10 @@ RawBool* CallSpecializer::InstanceOfAsBool(
|
|||
// 'null' is an instance of Null, Object*, Never*, void, and dynamic.
|
||||
// In addition, 'null' is an instance of any nullable type.
|
||||
// It is also an instance of FutureOr<T> if it is an instance of T.
|
||||
const AbstractType& unwrapped_type =
|
||||
AbstractType::Handle(type.UnwrapFutureOr());
|
||||
AbstractType& unwrapped_type = AbstractType::Handle(type.raw());
|
||||
if (unwrapped_type.IsFutureOrType()) {
|
||||
unwrapped_type = unwrapped_type.UnwrapFutureOr();
|
||||
}
|
||||
ASSERT(unwrapped_type.IsInstantiated() &&
|
||||
!unwrapped_type.IsUndetermined());
|
||||
is_subtype = unwrapped_type.IsTopType() || unwrapped_type.IsNullable() ||
|
||||
|
@ -1204,8 +1206,10 @@ bool CallSpecializer::TryOptimizeInstanceOfUsingStaticTypes(
|
|||
// 'null' is an instance of Null, Object*, Never*, void, and dynamic.
|
||||
// In addition, 'null' is an instance of any nullable type.
|
||||
// It is also an instance of FutureOr<T> if it is an instance of T.
|
||||
const AbstractType& unwrapped_type =
|
||||
AbstractType::Handle(type.UnwrapFutureOr());
|
||||
AbstractType& unwrapped_type = AbstractType::Handle(type.raw());
|
||||
if (unwrapped_type.IsFutureOrType()) {
|
||||
unwrapped_type = unwrapped_type.UnwrapFutureOr();
|
||||
}
|
||||
if (unwrapped_type.IsTopType() || !unwrapped_type.IsInstantiated()) {
|
||||
return false; // Always true or cannot tell.
|
||||
}
|
||||
|
|
|
@ -17584,12 +17584,15 @@ bool Instance::NullIsInstanceOf(
|
|||
const TypeArguments& other_function_type_arguments) {
|
||||
ASSERT(other.IsFinalized());
|
||||
ASSERT(!other.IsTypeRef()); // Must be dereferenced at compile time.
|
||||
// TODO(regis): Verify that the nullability of an instantiated FutureOr
|
||||
// always matches the nullability of its type argument. For now, be safe.
|
||||
// Also see issue #40123.
|
||||
AbstractType& type = AbstractType::Handle(other.UnwrapFutureOr());
|
||||
Nullability nullability = type.nullability();
|
||||
if (nullability == Nullability::kNullable) {
|
||||
if (other.IsNullable()) {
|
||||
// The type will remain nullable after instantiation.
|
||||
return true;
|
||||
}
|
||||
AbstractType& type = AbstractType::Handle(other.raw());
|
||||
if (type.IsFutureOrType()) {
|
||||
type = type.UnwrapFutureOr();
|
||||
}
|
||||
if (type.IsNullable()) {
|
||||
// The type will remain nullable after instantiation.
|
||||
return true;
|
||||
}
|
||||
|
@ -17602,13 +17605,13 @@ bool Instance::NullIsInstanceOf(
|
|||
if (type.IsTypeRef()) {
|
||||
type = TypeRef::Cast(type).type();
|
||||
}
|
||||
type = type.UnwrapFutureOr();
|
||||
return Instance::NullIsInstanceOf(mode, type, Object::null_type_arguments(),
|
||||
Object::null_type_arguments());
|
||||
}
|
||||
nullability = type.nullability();
|
||||
if (nullability == Nullability::kLegacy) {
|
||||
return type.IsNullType() || type.IsTopType() || type.IsNeverType();
|
||||
if (type.IsLegacy()) {
|
||||
return type.IsTopType() || type.IsNeverType();
|
||||
}
|
||||
return nullability == Nullability::kNullable;
|
||||
return type.IsNullable();
|
||||
}
|
||||
|
||||
bool Instance::NullIsAssignableTo(const AbstractType& other) {
|
||||
|
@ -17726,7 +17729,7 @@ bool Instance::RuntimeTypeIsSubtypeOf(
|
|||
bool Instance::IsFutureOrInstanceOf(Zone* zone,
|
||||
NNBDMode mode,
|
||||
const AbstractType& other) const {
|
||||
if (other.IsType() && other.IsFutureOrType()) {
|
||||
if (other.IsFutureOrType()) {
|
||||
const TypeArguments& other_type_arguments =
|
||||
TypeArguments::Handle(zone, other.arguments());
|
||||
const AbstractType& other_type_arg =
|
||||
|
@ -18457,9 +18460,7 @@ bool AbstractType::IsFfiPointerType() const {
|
|||
}
|
||||
|
||||
RawAbstractType* AbstractType::UnwrapFutureOr() const {
|
||||
if (!IsType() || !IsFutureOrType()) {
|
||||
return raw();
|
||||
}
|
||||
ASSERT(IsFutureOrType());
|
||||
if (arguments() == TypeArguments::null()) {
|
||||
return Type::dynamic_type().raw();
|
||||
}
|
||||
|
@ -18470,7 +18471,7 @@ RawAbstractType* AbstractType::UnwrapFutureOr() const {
|
|||
REUSABLE_ABSTRACT_TYPE_HANDLESCOPE(thread);
|
||||
AbstractType& type_arg = thread->AbstractTypeHandle();
|
||||
type_arg = type_args.TypeAt(0);
|
||||
while (type_arg.IsType() && type_arg.IsFutureOrType()) {
|
||||
while (type_arg.IsFutureOrType()) {
|
||||
if (type_arg.arguments() == TypeArguments::null()) {
|
||||
return Type::dynamic_type().raw();
|
||||
}
|
||||
|
@ -18594,7 +18595,7 @@ bool AbstractType::IsSubtypeOfFutureOr(Zone* zone,
|
|||
NNBDMode mode,
|
||||
const AbstractType& other,
|
||||
Heap::Space space) const {
|
||||
if (other.IsType() && other.IsFutureOrType()) {
|
||||
if (other.IsFutureOrType()) {
|
||||
// This function is only called with a receiver that is either a function
|
||||
// type or an uninstantiated type parameter, therefore, it cannot be of
|
||||
// class Future and we can spare the check.
|
||||
|
|
|
@ -7484,7 +7484,6 @@ class AbstractType : public Instance {
|
|||
bool IsFutureOrType() const { return type_class_id() == kFutureOrCid; }
|
||||
|
||||
// Returns the type argument of this (possibly nested) 'FutureOr' type.
|
||||
// Returns unmodified type if this type is not a 'FutureOr' type.
|
||||
RawAbstractType* UnwrapFutureOr() const;
|
||||
|
||||
// Check the subtype relationship.
|
||||
|
|
Loading…
Reference in a new issue