| Index: runtime/vm/object.cc
|
| ===================================================================
|
| --- runtime/vm/object.cc (revision 31085)
|
| +++ runtime/vm/object.cc (working copy)
|
| @@ -902,6 +902,9 @@
|
| cls = Class::New<Type>();
|
| object_store->set_type_class(cls);
|
|
|
| + cls = Class::New<TypeRef>();
|
| + object_store->set_type_ref_class(cls);
|
| +
|
| cls = Class::New<TypeParameter>();
|
| object_store->set_type_parameter_class(cls);
|
|
|
| @@ -1033,6 +1036,10 @@
|
| RegisterPrivateClass(cls, Symbols::Type(), core_lib);
|
| pending_classes.Add(cls);
|
|
|
| + cls = object_store->type_ref_class();
|
| + RegisterPrivateClass(cls, Symbols::TypeRef(), core_lib);
|
| + pending_classes.Add(cls);
|
| +
|
| cls = object_store->type_parameter_class();
|
| RegisterPrivateClass(cls, Symbols::TypeParameter(), core_lib);
|
| pending_classes.Add(cls);
|
| @@ -1290,6 +1297,9 @@
|
| cls = Class::New<Type>();
|
| object_store->set_type_class(cls);
|
|
|
| + cls = Class::New<TypeRef>();
|
| + object_store->set_type_ref_class(cls);
|
| +
|
| cls = Class::New<TypeParameter>();
|
| object_store->set_type_parameter_class(cls);
|
|
|
| @@ -1991,6 +2001,7 @@
|
| void Class::set_super_type(const AbstractType& value) const {
|
| ASSERT(value.IsNull() ||
|
| (value.IsType() && !value.IsDynamicType()) ||
|
| + value.IsTypeRef() ||
|
| value.IsBoundedType() ||
|
| value.IsMixinAppType());
|
| StorePointer(&raw_ptr()->super_type_, value.raw());
|
| @@ -3513,9 +3524,6 @@
|
| // the presence of a malformed bound in checked mode).
|
| continue;
|
| }
|
| - ASSERT((!raw_instantiated && type.IsTypeParameter()) ||
|
| - type.IsBoundedType() ||
|
| - type.IsMalformed());
|
| return false;
|
| }
|
| type_class = type.type_class();
|
| @@ -3579,8 +3587,14 @@
|
|
|
|
|
| void TypeArguments::SetTypeAt(intptr_t index, const AbstractType& value) const {
|
| - ASSERT(!IsCanonical());
|
| - StorePointer(TypeAddr(index), value.raw());
|
| + 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 {
|
| + StorePointer(TypeAddr(index), value.raw());
|
| + }
|
| }
|
|
|
|
|
| @@ -3915,6 +3929,14 @@
|
| TypeArguments& result = TypeArguments::Handle(isolate);
|
| result ^= table.At(index);
|
| if (result.IsNull()) {
|
| + // Canonicalize each type argument.
|
| + const intptr_t num_types = Length();
|
| + AbstractType& type = AbstractType::Handle(isolate);
|
| + for (intptr_t i = 0; i < num_types; i++) {
|
| + type = TypeAt(i);
|
| + type = type.Canonicalize();
|
| + SetTypeAt(i, type);
|
| + }
|
| // Make sure we have an old space object and add it to the table.
|
| if (this->IsNew()) {
|
| result ^= Object::Clone(*this, Heap::kOld);
|
| @@ -11563,8 +11585,8 @@
|
|
|
| bool AbstractType::Equals(const Instance& other) const {
|
| // AbstractType is an abstract class.
|
| - ASSERT(raw() == AbstractType::null());
|
| - return other.IsNull();
|
| + UNREACHABLE();
|
| + return false;
|
| }
|
|
|
|
|
| @@ -11685,7 +11707,8 @@
|
| first_type_param_index = 0;
|
| }
|
| String& type_name = String::Handle();
|
| - if (num_type_params == 0) {
|
| + if ((num_type_params == 0) ||
|
| + args.IsRaw(first_type_param_index, num_type_params)) {
|
| type_name = class_name.raw();
|
| } else {
|
| const String& args_name = String::Handle(
|
| @@ -12054,17 +12077,6 @@
|
| }
|
|
|
|
|
| -RawString* Type::TypeClassName() const {
|
| - if (HasResolvedTypeClass()) {
|
| - const Class& cls = Class::Handle(type_class());
|
| - return cls.Name();
|
| - } else {
|
| - const UnresolvedClass& cls = UnresolvedClass::Handle(unresolved_class());
|
| - return cls.Name();
|
| - }
|
| -}
|
| -
|
| -
|
| RawAbstractTypeArguments* Type::arguments() const {
|
| return raw_ptr()->arguments_;
|
| }
|
| @@ -12086,7 +12098,7 @@
|
| RawAbstractType* Type::InstantiateFrom(
|
| const AbstractTypeArguments& instantiator_type_arguments,
|
| Error* bound_error) const {
|
| - ASSERT(IsResolved());
|
| + ASSERT(IsFinalized() || IsBeingFinalized());
|
| ASSERT(!IsInstantiated());
|
| // Return the uninstantiated type unchanged if malformed. No copy needed.
|
| if (IsMalformed()) {
|
| @@ -12115,6 +12127,10 @@
|
| if (raw() == other.raw()) {
|
| return true;
|
| }
|
| + if (other.IsTypeRef()) {
|
| + // TODO(regis): Use trail. For now, we "unfold" the right hand type.
|
| + return Equals(AbstractType::Handle(TypeRef::Cast(other).type()));
|
| + }
|
| if (!other.IsType()) {
|
| return false;
|
| }
|
| @@ -12133,13 +12149,17 @@
|
| return true;
|
| }
|
| const Class& cls = Class::Handle(type_class());
|
| + const intptr_t num_type_params = cls.NumTypeParameters();
|
| + if (num_type_params == 0) {
|
| + // Shortcut unnecessary handle allocation below.
|
| + return true;
|
| + }
|
| + const intptr_t num_type_args = cls.NumTypeArguments();
|
| + const intptr_t from_index = num_type_args - num_type_params;
|
| const AbstractTypeArguments& type_args = AbstractTypeArguments::Handle(
|
| arguments());
|
| const AbstractTypeArguments& other_type_args = AbstractTypeArguments::Handle(
|
| other_type.arguments());
|
| - const intptr_t num_type_args = cls.NumTypeArguments();
|
| - const intptr_t num_type_params = cls.NumTypeParameters();
|
| - const intptr_t from_index = num_type_args - num_type_params;
|
| if (type_args.IsNull()) {
|
| return other_type_args.IsRaw(from_index, num_type_params);
|
| }
|
| @@ -12346,6 +12366,135 @@
|
| }
|
|
|
|
|
| +bool TypeRef::IsInstantiated() const {
|
| + if (is_being_checked()) {
|
| + return true;
|
| + }
|
| + set_is_being_checked(true);
|
| + const bool result = AbstractType::Handle(type()).IsInstantiated();
|
| + set_is_being_checked(false);
|
| + return result;
|
| +}
|
| +
|
| +
|
| +bool TypeRef::Equals(const Instance& other) const {
|
| + // TODO(regis): Use trail instead of mark bit.
|
| + if (raw() == other.raw()) {
|
| + return true;
|
| + }
|
| + if (is_being_checked()) {
|
| + return true;
|
| + }
|
| + set_is_being_checked(true);
|
| + const bool result = AbstractType::Handle(type()).Equals(other);
|
| + set_is_being_checked(false);
|
| + return result;
|
| +}
|
| +
|
| +
|
| +RawAbstractType* TypeRef::InstantiateFrom(
|
| + const AbstractTypeArguments& instantiator_type_arguments,
|
| + Error* bound_error) const {
|
| + const AbstractType& ref_type = AbstractType::Handle(type());
|
| + // TODO(regis): Use trail instead of mark bit plus temporary redirection,
|
| + // because it could be marked for another reason.
|
| + if (is_being_checked()) {
|
| + ASSERT(ref_type.IsTypeRef());
|
| + return ref_type.raw();
|
| + }
|
| + set_is_being_checked(true);
|
| + ASSERT(!ref_type.IsTypeRef());
|
| + const TypeRef& instantiated_type_ref = TypeRef::Handle(
|
| + TypeRef::New(ref_type));
|
| + // TODO(regis): instantiated_type_ref should be stored in the trail instead.
|
| + set_type(instantiated_type_ref);
|
| + const AbstractType& instantiated_ref_type = AbstractType::Handle(
|
| + ref_type.InstantiateFrom(instantiator_type_arguments, bound_error));
|
| + instantiated_type_ref.set_type(instantiated_ref_type);
|
| + set_type(ref_type);
|
| + set_is_being_checked(false);
|
| + return instantiated_type_ref.raw();
|
| +}
|
| +
|
| +
|
| +void TypeRef::set_type(const AbstractType& value) const {
|
| + ASSERT(value.HasResolvedTypeClass());
|
| + StorePointer(&raw_ptr()->type_, value.raw());
|
| +}
|
| +
|
| +
|
| +void TypeRef::set_is_being_checked(bool value) const {
|
| + raw_ptr()->is_being_checked_ = value;
|
| +}
|
| +
|
| +
|
| +// This function only canonicalizes the referenced type, but not the TypeRef
|
| +// itself, since it cannot be canonical by definition.
|
| +// Consider the type Derived, where class Derived extends Base<Derived>.
|
| +// The first type argument of its flattened type argument vector is Derived,
|
| +// i.e. itself, but pointer equality is not possible.
|
| +RawAbstractType* TypeRef::Canonicalize() const {
|
| + // TODO(regis): Use trail, not mark bit.
|
| + if (is_being_checked()) {
|
| + return raw();
|
| + }
|
| + set_is_being_checked(true);
|
| + AbstractType& ref_type = AbstractType::Handle(type());
|
| + ASSERT(!ref_type.IsTypeRef());
|
| + ref_type = ref_type.Canonicalize();
|
| + set_type(ref_type);
|
| + // No need to call SetCanonical(), since a TypeRef cannot be canonical by
|
| + // definition.
|
| + set_is_being_checked(false);
|
| + // We return the referenced type instead of the TypeRef in order to provide
|
| + // pointer equality in simple cases, e.g. in language/f_bounded_equality_test.
|
| + return ref_type.raw();
|
| +}
|
| +
|
| +
|
| +intptr_t TypeRef::Hash() const {
|
| + // TODO(regis): Use trail and hash of referenced type.
|
| + // Do not calculate the hash of the referenced type to avoid cycles.
|
| + uword result = Class::Handle(AbstractType::Handle(type()).type_class()).id();
|
| + return FinalizeHash(result);
|
| +}
|
| +
|
| +
|
| +RawTypeRef* TypeRef::New() {
|
| + ASSERT(Isolate::Current()->object_store()->type_ref_class() != Class::null());
|
| + RawObject* raw = Object::Allocate(TypeRef::kClassId,
|
| + TypeRef::InstanceSize(),
|
| + Heap::kOld);
|
| + return reinterpret_cast<RawTypeRef*>(raw);
|
| +}
|
| +
|
| +
|
| +RawTypeRef* TypeRef::New(const AbstractType& type) {
|
| + const TypeRef& result = TypeRef::Handle(TypeRef::New());
|
| + result.set_type(type);
|
| + result.set_is_being_checked(false);
|
| + return result.raw();
|
| +}
|
| +
|
| +
|
| +const char* TypeRef::ToCString() const {
|
| + const char* format = "TypeRef: %s%s";
|
| + const char* type_cstr = String::Handle(Class::Handle(AbstractType::Handle(
|
| + type()).type_class()).Name()).ToCString();
|
| + const char* args_cstr = (AbstractType::Handle(
|
| + type()).arguments() == AbstractTypeArguments::null()) ? "" : "<...>";
|
| + intptr_t len = OS::SNPrint(NULL, 0, format, type_cstr, args_cstr) + 1;
|
| + char* chars = Isolate::Current()->current_zone()->Alloc<char>(len);
|
| + OS::SNPrint(chars, len, format, type_cstr, args_cstr);
|
| + return chars;
|
| +}
|
| +
|
| +
|
| +void TypeRef::PrintToJSONStream(JSONStream* stream, bool ref) const {
|
| + JSONObject jsobj(stream);
|
| +}
|
| +
|
| +
|
| void TypeParameter::set_is_finalized() const {
|
| ASSERT(!IsFinalized());
|
| set_type_state(RawTypeParameter::kFinalizedUninstantiated);
|
| @@ -12356,6 +12505,10 @@
|
| if (raw() == other.raw()) {
|
| return true;
|
| }
|
| + if (other.IsTypeRef()) {
|
| + // TODO(regis): Use trail. For now, we "unfold" the right hand type.
|
| + return Equals(AbstractType::Handle(TypeRef::Cast(other).type()));
|
| + }
|
| if (!other.IsTypeParameter()) {
|
| return false;
|
| }
|
| @@ -12400,7 +12553,24 @@
|
| if (instantiator_type_arguments.IsNull()) {
|
| return Type::DynamicType();
|
| }
|
| - return instantiator_type_arguments.TypeAt(index());
|
| + const AbstractType& type_arg = AbstractType::Handle(
|
| + instantiator_type_arguments.TypeAt(index()));
|
| + // There is no need to canonicalize the instantiated type parameter, since all
|
| + // type arguments are canonicalized at type finalization time. It would be too
|
| + // early to canonicalize the returned type argument here, since instantiation
|
| + // not only happens at run time, but also during type finalization.
|
| + // However, if the type argument is a reference to a canonical type, we
|
| + // return the referenced canonical type instead of the type reference to
|
| + // provide pointer equality in some simple cases, e.g. in
|
| + // language/f_bounded_equality_test.
|
| + if (type_arg.IsTypeRef()) {
|
| + const AbstractType& ref_type = AbstractType::Handle(
|
| + TypeRef::Cast(type_arg).type());
|
| + if (ref_type.IsCanonical()) {
|
| + return ref_type.raw();
|
| + }
|
| + }
|
| + return type_arg.raw();
|
| }
|
|
|
|
|
| @@ -12465,8 +12635,7 @@
|
|
|
| intptr_t TypeParameter::Hash() const {
|
| ASSERT(IsFinalized());
|
| - uword result = 0;
|
| - result += Class::Handle(parameterized_class()).id();
|
| + uword result = Class::Handle(parameterized_class()).id();
|
| // Do not include the hash of the bound, which could lead to cycles.
|
| result <<= index();
|
| return FinalizeHash(result);
|
| @@ -12557,6 +12726,10 @@
|
| if (raw() == other.raw()) {
|
| return true;
|
| }
|
| + if (other.IsTypeRef()) {
|
| + // TODO(regis): Use trail. For now, we "unfold" the right hand type.
|
| + return Equals(AbstractType::Handle(TypeRef::Cast(other).type()));
|
| + }
|
| if (!other.IsBoundedType()) {
|
| return false;
|
| }
|
| @@ -12580,7 +12753,7 @@
|
|
|
|
|
| void BoundedType::set_type(const AbstractType& value) const {
|
| - ASSERT(value.IsFinalized());
|
| + ASSERT(value.IsFinalized() || value.IsBeingFinalized());
|
| ASSERT(!value.IsMalformed());
|
| StorePointer(&raw_ptr()->type_, value.raw());
|
| }
|
| @@ -12660,13 +12833,9 @@
|
|
|
|
|
| intptr_t BoundedType::Hash() const {
|
| - uword result = 0;
|
| - result += AbstractType::Handle(type()).Hash();
|
| + uword result = AbstractType::Handle(type()).Hash();
|
| // Do not include the hash of the bound, which could lead to cycles.
|
| - TypeParameter& type_param = TypeParameter::Handle(type_parameter());
|
| - if (!type_param.IsNull()) {
|
| - result += type_param.Hash();
|
| - }
|
| + result += TypeParameter::Handle(type_parameter()).Hash();
|
| return FinalizeHash(result);
|
| }
|
|
|
|
|