| Index: runtime/vm/object.cc
|
| ===================================================================
|
| --- runtime/vm/object.cc (revision 34737)
|
| +++ runtime/vm/object.cc (working copy)
|
| @@ -4037,7 +4037,9 @@
|
| AbstractType& type = AbstractType::Handle();
|
| for (intptr_t i = 0; i < num_types; i++) {
|
| type = TypeAt(i);
|
| - result = CombineHashes(result, type.Hash());
|
| + // The hash may be calculated during type finalization (for debugging
|
| + // purposes only) while a type argument is still temporarily null.
|
| + result = CombineHashes(result, type.IsNull() ? 0 : type.Hash());
|
| }
|
| return FinalizeHash(result);
|
| }
|
| @@ -4101,7 +4103,11 @@
|
| AbstractType& type = AbstractType::Handle();
|
| for (intptr_t i = 0; i < num_types; i++) {
|
| type = TypeAt(i);
|
| - if (type.IsRecursive()) {
|
| + // If this type argument is null, the type parameterized with this type
|
| + // argument is still being finalized and is definitely recursive. The null
|
| + // type argument will be replaced by a non-null type before the type is
|
| + // marked as finalized.
|
| + if (type.IsNull() || type.IsRecursive()) {
|
| return true;
|
| }
|
| }
|
| @@ -4253,24 +4259,12 @@
|
| }
|
|
|
|
|
| -void TypeArguments::set_type_at(intptr_t index,
|
| +void TypeArguments::SetTypeAt(intptr_t index,
|
| const AbstractType& value) const {
|
| StorePointer(TypeAddr(index), value.raw());
|
| }
|
|
|
|
|
| -void TypeArguments::SetTypeAt(intptr_t index, const AbstractType& value) const {
|
| - const AbstractType& type_arg = AbstractType::Handle(TypeAt(index));
|
| - if (type_arg.IsTypeRef()) {
|
| - if (value.raw() != type_arg.raw()) {
|
| - TypeRef::Cast(type_arg).set_type(value);
|
| - }
|
| - } else {
|
| - set_type_at(index, value);
|
| - }
|
| -}
|
| -
|
| -
|
| bool TypeArguments::IsResolved() const {
|
| AbstractType& type = AbstractType::Handle();
|
| const intptr_t num_types = Length();
|
| @@ -4291,7 +4285,9 @@
|
| AbstractType& type = AbstractType::Handle();
|
| for (intptr_t i = 0; i < len; i++) {
|
| type = TypeAt(from_index + i);
|
| - if (!type.IsInstantiated(trail)) {
|
| + // If the type argument is null, the type parameterized with this type
|
| + // argument is still being finalized. Skip this null type argument.
|
| + if (!type.IsNull() && !type.IsInstantiated(trail)) {
|
| return false;
|
| }
|
| }
|
| @@ -4455,7 +4451,13 @@
|
| AbstractType& type = AbstractType::Handle();
|
| for (intptr_t i = 0; i < num_types; i++) {
|
| type = TypeAt(i);
|
| - if (!type.IsInstantiated()) {
|
| + // If this type argument T is null, the type A containing T in its flattened
|
| + // type argument vector V is recursive and is still being finalized.
|
| + // T is the type argument of a super type of A. T is being instantiated
|
| + // during finalization of V, which is also the instantiator. T depends
|
| + // solely on the type parameters of A and will be replaced by a non-null
|
| + // type before A is marked as finalized.
|
| + if (!type.IsNull() && !type.IsInstantiated()) {
|
| type = type.InstantiateFrom(instantiator_type_arguments,
|
| bound_error,
|
| trail);
|
| @@ -4698,14 +4700,19 @@
|
| type_arg = type_arg.Canonicalize(trail);
|
| SetTypeAt(i, type_arg);
|
| }
|
| - // Canonicalization of a type should not change its hash. Verify.
|
| - ASSERT(Hash() == hash);
|
| + // Canonicalization of a recursive type may change its hash.
|
| + intptr_t canonical_hash = hash;
|
| + if (IsRecursive()) {
|
| + canonical_hash = Hash();
|
| + }
|
| // Canonicalization of the type argument's own type arguments may add an
|
| // entry to the table, or even grow the table, and thereby change the
|
| // previously calculated index.
|
| table = object_store->canonical_type_arguments();
|
| - if (Smi::Value(Smi::RawCast(table.At(table.Length() - 1))) != num_used) {
|
| - index = FindIndexInCanonicalTypeArguments(isolate, table, *this, hash);
|
| + if ((canonical_hash != hash) ||
|
| + (Smi::Value(Smi::RawCast(table.At(table.Length() - 1))) != num_used)) {
|
| + index = FindIndexInCanonicalTypeArguments(
|
| + isolate, table, *this, canonical_hash);
|
| result ^= table.At(index);
|
| }
|
| if (result.IsNull()) {
|
| @@ -13497,26 +13504,40 @@
|
| if (IsMalformed()) {
|
| return raw();
|
| }
|
| + // Instantiating this type with its own type arguments as instantiator can
|
| + // occur during finalization and bounds checking. Return the type unchanged.
|
| + if (arguments() == instantiator_type_arguments.raw()) {
|
| + return raw();
|
| + }
|
| + // If this type is recursive, we may already be instantiating it.
|
| + Type& instantiated_type = Type::Handle();
|
| + instantiated_type ^= OnlyBuddyInTrail(trail);
|
| + if (!instantiated_type.IsNull()) {
|
| + ASSERT(IsRecursive());
|
| + return instantiated_type.raw();
|
| + }
|
| // Note that the type class has to be resolved at this time, but not
|
| // necessarily finalized yet. We may be checking bounds at compile time or
|
| // finalizing the type argument vector of a recursive type.
|
| const Class& cls = Class::Handle(type_class());
|
| +
|
| // This uninstantiated type is not modified, as it can be instantiated
|
| - // with different instantiators.
|
| - Type& instantiated_type = Type::Handle(
|
| - Type::New(cls, TypeArguments::Handle(), token_pos()));
|
| - if (arguments() != TypeArguments::null()) {
|
| - TypeArguments& type_arguments = TypeArguments::Handle(arguments());
|
| - ASSERT(type_arguments.Length() == cls.NumTypeArguments());
|
| - if (type_arguments.IsRecursive()) {
|
| - AddOnlyBuddyToTrail(&trail, instantiated_type);
|
| - }
|
| - type_arguments = type_arguments.InstantiateFrom(instantiator_type_arguments,
|
| - bound_error,
|
| - trail);
|
| - instantiated_type.set_arguments(type_arguments);
|
| + // with different instantiators. Allocate a new instantiated version of it.
|
| + instantiated_type = Type::New(cls, TypeArguments::Handle(), token_pos());
|
| + TypeArguments& type_arguments = TypeArguments::Handle(arguments());
|
| + ASSERT(type_arguments.Length() == cls.NumTypeArguments());
|
| + if (type_arguments.IsRecursive()) {
|
| + AddOnlyBuddyToTrail(&trail, instantiated_type);
|
| }
|
| - instantiated_type.SetIsFinalized();
|
| + type_arguments = type_arguments.InstantiateFrom(instantiator_type_arguments,
|
| + bound_error,
|
| + trail);
|
| + instantiated_type.set_arguments(type_arguments);
|
| + if (IsFinalized()) {
|
| + instantiated_type.SetIsFinalized();
|
| + } else {
|
| + instantiated_type.set_is_resolved();
|
| + }
|
| // Canonicalization is not part of instantiation.
|
| return instantiated_type.raw();
|
| }
|
| @@ -13878,26 +13899,30 @@
|
| }
|
|
|
|
|
| -RawAbstractType* TypeRef::InstantiateFrom(
|
| +RawTypeRef* TypeRef::InstantiateFrom(
|
| const TypeArguments& instantiator_type_arguments,
|
| Error* bound_error,
|
| GrowableObjectArray* trail) const {
|
| + TypeRef& instantiated_type_ref = TypeRef::Handle();
|
| + instantiated_type_ref ^= OnlyBuddyInTrail(trail);
|
| + if (!instantiated_type_ref.IsNull()) {
|
| + return instantiated_type_ref.raw();
|
| + }
|
| AbstractType& ref_type = AbstractType::Handle(type());
|
| ASSERT(!ref_type.IsTypeRef());
|
| AbstractType& instantiated_ref_type = AbstractType::Handle();
|
| - instantiated_ref_type ^= ref_type.OnlyBuddyInTrail(trail);
|
| - if (instantiated_ref_type.IsNull()) {
|
| - // The referenced type is first encountered here during instantiation.
|
| - instantiated_ref_type = ref_type.InstantiateFrom(
|
| + instantiated_ref_type = ref_type.InstantiateFrom(
|
| instantiator_type_arguments, bound_error, trail);
|
| - }
|
| ASSERT(!instantiated_ref_type.IsTypeRef());
|
| - return TypeRef::New(instantiated_ref_type);
|
| + instantiated_type_ref = TypeRef::New(instantiated_ref_type);
|
| + AddOnlyBuddyToTrail(&trail, instantiated_type_ref);
|
| + return instantiated_type_ref.raw();
|
| }
|
|
|
|
|
| void TypeRef::set_type(const AbstractType& value) const {
|
| ASSERT(value.HasResolvedTypeClass());
|
| + ASSERT(!value.IsTypeRef());
|
| StorePointer(&raw_ptr()->type_, value.raw());
|
| }
|
|
|
| @@ -13910,6 +13935,8 @@
|
| if (TestAndAddToTrail(&trail)) {
|
| return raw();
|
| }
|
| + // TODO(regis): Try to reduce the number of nodes required to represent the
|
| + // referenced recursive type.
|
| AbstractType& ref_type = AbstractType::Handle(type());
|
| ref_type = ref_type.Canonicalize(trail);
|
| set_type(ref_type);
|
|
|