Skip to content

Commit b37f391

Browse files
creliercommit-bot@chromium.org
authored andcommitted
[VM/nnbd] Make runtimeType return a non-nullable type when the NNBD experiment is enabled.
The nullability of runtimeType must be consistent with the nullability of a class DeclarationType. Currently, it is always kLegacy. However, this needs to be set to kNonNullable when the NNBD experiment is enabled. Note that the nullability of the null instance remains kNullable. Change-Id: I4ba974c2551c3a7fbd190b02175804090f9b48b4 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/125721 Reviewed-by: Alexander Markov <alexmarkov@google.com> Commit-Queue: Régis Crelier <regis@google.com>
1 parent bafd4e8 commit b37f391

File tree

8 files changed

+88
-51
lines changed

8 files changed

+88
-51
lines changed

runtime/vm/clustered_snapshot.cc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5572,6 +5572,13 @@ void FullSnapshotWriter::WriteIsolateSnapshot(intptr_t num_base_objects) {
55725572
ObjectStore* object_store = isolate()->object_store();
55735573
ASSERT(object_store != NULL);
55745574

5575+
// These type arguments must always be retained.
5576+
ASSERT(object_store->type_argument_int()->IsCanonical());
5577+
ASSERT(object_store->type_argument_double()->IsCanonical());
5578+
ASSERT(object_store->type_argument_string()->IsCanonical());
5579+
ASSERT(object_store->type_argument_string_dynamic()->IsCanonical());
5580+
ASSERT(object_store->type_argument_string_string()->IsCanonical());
5581+
55755582
serializer.ReserveHeader();
55765583
serializer.WriteVersionAndFeatures(false);
55775584
// Isolate snapshot roots are:

runtime/vm/compiler/aot/precompiler.cc

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,20 @@ void Precompiler::DoCompileAll() {
322322
AddRoots();
323323
AddAnnotatedRoots();
324324

325+
// With the nnbd experiment enabled, these non-nullable type arguments may
326+
// not be retained, although they will be used and expected to be
327+
// canonical.
328+
AddTypeArguments(
329+
TypeArguments::Handle(Z, I->object_store()->type_argument_int()));
330+
AddTypeArguments(
331+
TypeArguments::Handle(Z, I->object_store()->type_argument_double()));
332+
AddTypeArguments(
333+
TypeArguments::Handle(Z, I->object_store()->type_argument_string()));
334+
AddTypeArguments(TypeArguments::Handle(
335+
Z, I->object_store()->type_argument_string_dynamic()));
336+
AddTypeArguments(TypeArguments::Handle(
337+
Z, I->object_store()->type_argument_string_string()));
338+
325339
// Compile newly found targets and add their callees until we reach a
326340
// fixed point.
327341
Iterate();

runtime/vm/compiler/frontend/bytecode_reader.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1674,7 +1674,8 @@ RawObject* BytecodeReaderHelper::ReadType(intptr_t tag,
16741674
if (!cls.is_declaration_loaded()) {
16751675
LoadReferencedClass(cls);
16761676
}
1677-
return cls.DeclarationType(nullability);
1677+
const Type& type = Type::Handle(Z, cls.DeclarationType());
1678+
return type.ToNullability(nullability, Heap::kOld);
16781679
}
16791680
case kTypeParameter: {
16801681
Object& parent = Object::Handle(Z, ReadObject());

runtime/vm/compiler/frontend/kernel_translation_helper.cc

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -734,7 +734,6 @@ void TranslationHelper::SetupFieldAccessorFunction(
734734

735735
intptr_t pos = 0;
736736
if (is_method) {
737-
// TODO(regis): Set nullability to kNonNullable instead of kLegacy.
738737
function.SetParameterTypeAt(pos, GetDeclarationType(klass));
739738
function.SetParameterNameAt(pos, Symbols::This());
740739
pos++;
@@ -2829,7 +2828,8 @@ void TypeTranslator::BuildInterfaceType(bool simple) {
28292828
// Fast path for non-generic types: retrieve or populate the class's only
28302829
// canonical type (as long as only one nullability variant is used), which
28312830
// is its declaration type.
2832-
result_ = klass.DeclarationType(nullability);
2831+
result_ = klass.DeclarationType();
2832+
result_ = Type::Cast(result_).ToNullability(nullability, Heap::kOld);
28332833
} else {
28342834
// Note that the type argument vector is not yet extended.
28352835
result_ = Type::New(klass, Object::null_type_arguments(),
@@ -3176,9 +3176,10 @@ const Type& TypeTranslator::ReceiverType(const Class& klass) {
31763176
type = klass.DeclarationType();
31773177
} else {
31783178
type = Type::New(klass, TypeArguments::Handle(Z, klass.type_parameters()),
3179-
klass.token_pos());
3179+
klass.token_pos(),
3180+
Dart::non_nullable_flag() ? Nullability::kNonNullable
3181+
: Nullability::kLegacy);
31803182
}
3181-
// TODO(regis): Set nullability to kNonNullable instead of kLegacy.
31823183
return type;
31833184
}
31843185

@@ -3229,7 +3230,6 @@ void TypeTranslator::SetupFunctionParameters(
32293230
intptr_t pos = 0;
32303231
if (is_method) {
32313232
ASSERT(!klass.IsNull());
3232-
// TODO(regis): Set nullability to kNonNullable instead of kLegacy.
32333233
function.SetParameterTypeAt(pos, H.GetDeclarationType(klass));
32343234
function.SetParameterNameAt(pos, Symbols::This());
32353235
pos++;

runtime/vm/object.cc

Lines changed: 49 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1585,7 +1585,9 @@ RawError* Object::Init(Isolate* isolate,
15851585
// patching. The array type allocated below represents the raw type _List
15861586
// and not _List<E> as we could expect. Use with caution.
15871587
type = Type::New(Class::Handle(zone, cls.raw()),
1588-
TypeArguments::Handle(zone), TokenPosition::kNoSource);
1588+
TypeArguments::Handle(zone), TokenPosition::kNoSource,
1589+
Dart::non_nullable_flag() ? Nullability::kNonNullable
1590+
: Nullability::kLegacy);
15891591
type.SetIsFinalized();
15901592
type ^= type.Canonicalize();
15911593
object_store->set_array_type(type);
@@ -2456,8 +2458,10 @@ RawAbstractType* Class::RareType() const {
24562458
return DeclarationType();
24572459
}
24582460
ASSERT(is_declaration_loaded());
2459-
const Type& type = Type::Handle(Type::New(
2460-
*this, Object::null_type_arguments(), TokenPosition::kNoSource));
2461+
const Type& type = Type::Handle(
2462+
Type::New(*this, Object::null_type_arguments(), TokenPosition::kNoSource,
2463+
Dart::non_nullable_flag() ? Nullability::kNonNullable
2464+
: Nullability::kLegacy));
24612465
return ClassFinalizer::FinalizeType(*this, type);
24622466
}
24632467

@@ -4354,19 +4358,19 @@ void Class::set_declaration_type(const Type& value) const {
43544358
ASSERT(!value.IsNull() && value.IsCanonical() && value.IsOld());
43554359
ASSERT((declaration_type() == Object::null()) ||
43564360
(declaration_type() == value.raw())); // Set during own finalization.
4357-
// TODO(regis): Since declaration type is used as the runtime type of
4358-
// instances of a non-generic class, the nullability should be set to
4359-
// kNonNullable instead of kLegacy.
4360-
// For now, we accept any except for Null (kNullable).
4361+
// Since declaration type is used as the runtime type of instances of a
4362+
// non-generic class, the nullability is set to kNonNullable instead of
4363+
// kLegacy when the non-nullable experiment is enabled.
43614364
ASSERT(!value.IsNullType() || value.IsNullable());
4362-
ASSERT(value.IsNullType() || value.IsLegacy());
4365+
ASSERT(
4366+
value.IsNullType() ||
4367+
(Dart::non_nullable_flag() ? value.IsNonNullable() : value.IsLegacy()));
43634368
StorePointer(&raw_ptr()->declaration_type_, value.raw());
43644369
}
43654370

4366-
RawType* Class::DeclarationType(Nullability nullability) const {
4371+
RawType* Class::DeclarationType() const {
43674372
ASSERT(is_declaration_loaded());
43684373
if (IsNullClass()) {
4369-
// Ignore requested nullability (e.g. by mirrors).
43704374
return Type::NullType();
43714375
}
43724376
if (IsDynamicClass()) {
@@ -4378,23 +4382,21 @@ RawType* Class::DeclarationType(Nullability nullability) const {
43784382
if (IsNeverClass()) {
43794383
return Type::NeverType();
43804384
}
4381-
Type& type = Type::Handle(declaration_type());
4382-
if (!type.IsNull()) {
4383-
return type.ToNullability(nullability, Heap::kOld);
4385+
if (declaration_type() != Type::null()) {
4386+
return declaration_type();
43844387
}
4385-
// TODO(regis): We should pass nullabiity to Type::New to avoid having to
4386-
// clone the type to the desired nullability. This however causes issues with
4387-
// the runtimeType intrinsic grabbing DeclarationType without checking its
4388-
// nullability. Indeed, when the CFE provides a non-nullable version of the
4389-
// type first, this non-nullable version gets cached as the declaration type.
4390-
// We consistenly cache the kLegacy version of a type, unless the non-nullable
4388+
// For efficiency, the runtimeType intrinsic returns the type cached by
4389+
// DeclarationType without checking its nullability. Therefore, we
4390+
// consistently cache the kLegacy version of a type, unless the non-nullable
43914391
// experiment is enabled, in which case we store the kNonNullable version.
43924392
// In either cases, the exception is type Null which is stored as kNullable.
4393-
type = Type::New(*this, TypeArguments::Handle(type_parameters()), token_pos(),
4394-
Nullability::kLegacy);
4393+
Type& type = Type::Handle(
4394+
Type::New(*this, TypeArguments::Handle(type_parameters()), token_pos(),
4395+
Dart::non_nullable_flag() ? Nullability::kNonNullable
4396+
: Nullability::kLegacy));
43954397
type ^= ClassFinalizer::FinalizeType(*this, type);
43964398
set_declaration_type(type);
4397-
return type.ToNullability(nullability, Heap::kOld);
4399+
return type.raw();
43984400
}
43994401

44004402
void Class::set_allocation_stub(const Code& value) const {
@@ -16745,10 +16747,10 @@ RawAbstractType* Instance::GetType(Heap::Space space) const {
1674516747
if (cls.NumTypeArguments() > 0) {
1674616748
type_arguments = GetTypeArguments();
1674716749
}
16748-
// TODO(regis): The runtime type of a non-null instance should be
16749-
// non-nullable instead of legacy. Revisit.
1675016750
type = Type::New(cls, type_arguments, TokenPosition::kNoSource,
16751-
Nullability::kLegacy, space);
16751+
Dart::non_nullable_flag() ? Nullability::kNonNullable
16752+
: Nullability::kLegacy,
16753+
space);
1675216754
type.SetIsFinalized();
1675316755
type ^= type.Canonicalize();
1675416756
}
@@ -17783,11 +17785,9 @@ RawType* Type::DartTypeType() {
1778317785
return Isolate::Current()->object_store()->type_type();
1778417786
}
1778517787

17786-
RawType* Type::NewNonParameterizedType(const Class& type_class,
17787-
Nullability nullability) {
17788+
RawType* Type::NewNonParameterizedType(const Class& type_class) {
1778817789
ASSERT(type_class.NumTypeArguments() == 0);
1778917790
if (type_class.IsNullClass()) {
17790-
// Ignore requested nullability (e.g. by mirrors).
1779117791
return Type::NullType();
1779217792
}
1779317793
if (type_class.IsDynamicClass()) {
@@ -17805,13 +17805,14 @@ RawType* Type::NewNonParameterizedType(const Class& type_class,
1780517805
if (type.IsNull()) {
1780617806
type = Type::New(Class::Handle(type_class.raw()),
1780717807
Object::null_type_arguments(), TokenPosition::kNoSource,
17808-
Nullability::kLegacy);
17808+
Dart::non_nullable_flag() ? Nullability::kNonNullable
17809+
: Nullability::kLegacy);
1780917810
type.SetIsFinalized();
1781017811
type ^= type.Canonicalize();
1781117812
type_class.set_declaration_type(type);
1781217813
}
1781317814
ASSERT(type.IsFinalized());
17814-
return type.ToNullability(nullability, Heap::kOld);
17815+
return type.raw();
1781517816
}
1781617817

1781717818
void Type::SetIsFinalized() const {
@@ -17840,6 +17841,7 @@ RawType* Type::ToNullability(Nullability value, Heap::Space space) const {
1784017841
}
1784117842
// Clone type and set new nullability.
1784217843
Type& type = Type::Handle();
17844+
// TODO(regis): Should we always clone in old space and remove space param?
1784317845
type ^= Object::Clone(*this, space);
1784417846
type.set_nullability(value);
1784517847
type.SetHash(0);
@@ -18154,6 +18156,20 @@ bool Type::IsRecursive() const {
1815418156
return TypeArguments::Handle(arguments()).IsRecursive();
1815518157
}
1815618158

18159+
bool Type::IsDeclarationTypeOf(const Class& cls) const {
18160+
ASSERT(type_class() == cls.raw());
18161+
if (IsNullType()) {
18162+
return true;
18163+
}
18164+
if (cls.IsGeneric() || cls.IsClosureClass() || cls.IsTypedefClass()) {
18165+
return false;
18166+
}
18167+
const Nullability declaration_nullability = Dart::non_nullable_flag()
18168+
? Nullability::kNonNullable
18169+
: Nullability::kLegacy;
18170+
return nullability() == declaration_nullability;
18171+
}
18172+
1815718173
RawAbstractType* Type::Canonicalize(TrailPtr trail) const {
1815818174
ASSERT(IsFinalized());
1815918175
if (IsCanonical()) {
@@ -18183,8 +18199,7 @@ RawAbstractType* Type::Canonicalize(TrailPtr trail) const {
1818318199
const Class& cls = Class::Handle(zone, type_class());
1818418200

1818518201
// Fast canonical lookup/registry for simple types.
18186-
if ((IsNullType() || IsLegacy()) && !cls.IsGeneric() &&
18187-
!cls.IsClosureClass() && !cls.IsTypedefClass()) {
18202+
if (IsDeclarationTypeOf(cls)) {
1818818203
ASSERT(!IsFunctionType());
1818918204
ASSERT(!IsNullType() || IsNullable());
1819018205
Type& type = Type::Handle(zone, cls.declaration_type());
@@ -18317,8 +18332,7 @@ bool Type::CheckIsCanonical(Thread* thread) const {
1831718332
const Class& cls = Class::Handle(zone, type_class());
1831818333

1831918334
// Fast canonical lookup/registry for simple types.
18320-
if ((IsNullType() || IsLegacy()) && !cls.IsGeneric() &&
18321-
!cls.IsClosureClass() && !cls.IsTypedefClass()) {
18335+
if (IsDeclarationTypeOf(cls)) {
1832218336
ASSERT(!IsFunctionType());
1832318337
type = cls.declaration_type();
1832418338
ASSERT(type.IsCanonical());
@@ -18652,6 +18666,7 @@ RawTypeParameter* TypeParameter::ToNullability(Nullability value,
1865218666
}
1865318667
// Clone type and set new nullability.
1865418668
TypeParameter& type_parameter = TypeParameter::Handle();
18669+
// TODO(regis): Should we always clone in old space and remove space param?
1865518670
type_parameter ^= Object::Clone(*this, space);
1865618671
type_parameter.set_nullability(value);
1865718672
type_parameter.SetHash(0);

runtime/vm/object.h

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -951,12 +951,9 @@ class Class : public Object {
951951
// class B<T, S>
952952
// class C<R> extends B<R, int>
953953
// C.DeclarationType() --> C [R, int, R]
954-
// The declaration type is legacy by default, but another nullability
955-
// variant may be requested. The first requested type gets cached in the class
956-
// and subsequent nullability variants get cached in the object store.
957-
// TODO(regis): Is this caching still useful or should we eliminate it?
958-
RawType* DeclarationType(
959-
Nullability nullability = Nullability::kLegacy) const;
954+
// The declaration type's nullability is either legacy or non-nullable when
955+
// the non-nullable experiment is enabled.
956+
RawType* DeclarationType() const;
960957

961958
static intptr_t declaration_type_offset() {
962959
return OFFSET_OF(RawClass, declaration_type_);
@@ -7190,6 +7187,11 @@ class Type : public AbstractType {
71907187
bool syntactically,
71917188
TrailPtr trail = NULL) const;
71927189
virtual bool IsRecursive() const;
7190+
7191+
// Return true if this type can be used as the declaration type of cls after
7192+
// canonicalization (passed-in cls must match type_class()).
7193+
bool IsDeclarationTypeOf(const Class& cls) const;
7194+
71937195
// If signature is not null, this type represents a function type. Note that
71947196
// the signature fully represents the type and type arguments can be ignored.
71957197
// However, in case of a generic typedef, they document how the typedef class
@@ -7277,9 +7279,7 @@ class Type : public AbstractType {
72777279
static RawType* DartTypeType();
72787280

72797281
// The finalized type of the given non-parameterized class.
7280-
static RawType* NewNonParameterizedType(
7281-
const Class& type_class,
7282-
Nullability nullability = Nullability::kLegacy);
7282+
static RawType* NewNonParameterizedType(const Class& type_class);
72837283

72847284
static RawType* New(const Class& clazz,
72857285
const TypeArguments& arguments,

sdk/lib/_internal/vm/bin/io_service_patch.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ class _IOService {
6464
final Completer completer = new Completer();
6565
_messageMap[id] = completer;
6666
try {
67-
servicePort.send([id, _replyToPort, request, data]);
67+
servicePort.send(<dynamic>[id, _replyToPort, request, data]);
6868
} catch (error) {
6969
_messageMap.remove(id).complete(error);
7070
if (_messageMap.length == 0) {

sdk_nnbd/lib/_internal/vm/bin/io_service_patch.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ class _IOService {
6464
final Completer completer = new Completer();
6565
_messageMap[id] = completer;
6666
try {
67-
servicePort.send([id, _replyToPort, request, data]);
67+
servicePort.send(<dynamic>[id, _replyToPort, request, data]);
6868
} catch (error) {
6969
_messageMap.remove(id).complete(error);
7070
if (_messageMap.length == 0) {

0 commit comments

Comments
 (0)