Index: runtime/vm/object.cc |
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc |
index ed737215e2b5f2c70108357d1470eab41711ddde..e6ec51a35d1dcbe05f6a0b2c7fa983aecbfe8fdc 100644 |
--- a/runtime/vm/object.cc |
+++ b/runtime/vm/object.cc |
@@ -3615,6 +3615,7 @@ bool Class::TypeTestNonRecursive(const Class& cls, |
const Class& other, |
const TypeArguments& other_type_arguments, |
Error* bound_error, |
+ TrailPtr bound_trail, |
Heap::Space space) { |
// Use the thsi object as if it was the receiver of this method, but instead |
// of recursing reset it to the super class and loop. |
@@ -3673,6 +3674,7 @@ bool Class::TypeTestNonRecursive(const Class& cls, |
from_index, |
num_type_params, |
bound_error, |
+ bound_trail, |
space); |
} |
if (other.IsFunctionClass()) { |
@@ -3733,7 +3735,11 @@ bool Class::TypeTestNonRecursive(const Class& cls, |
// The index of the type parameters is adjusted upon finalization. |
error = Error::null(); |
interface_args = |
- interface_args.InstantiateFrom(type_arguments, &error, NULL, space); |
+ interface_args.InstantiateFrom(type_arguments, |
+ &error, |
+ NULL, |
+ bound_trail, |
+ space); |
if (!error.IsNull()) { |
// Return the first bound error to the caller if it requests it. |
if ((bound_error != NULL) && bound_error->IsNull()) { |
@@ -3747,6 +3753,7 @@ bool Class::TypeTestNonRecursive(const Class& cls, |
other, |
other_type_arguments, |
bound_error, |
+ bound_trail, |
space)) { |
return true; |
} |
@@ -3773,6 +3780,7 @@ bool Class::TypeTest(TypeTestKind test_kind, |
const Class& other, |
const TypeArguments& other_type_arguments, |
Error* bound_error, |
+ TrailPtr bound_trail, |
Heap::Space space) const { |
return TypeTestNonRecursive(*this, |
test_kind, |
@@ -3780,6 +3788,7 @@ bool Class::TypeTest(TypeTestKind test_kind, |
other, |
other_type_arguments, |
bound_error, |
+ bound_trail, |
space); |
} |
@@ -4289,6 +4298,7 @@ bool TypeArguments::TypeTest(TypeTestKind test_kind, |
intptr_t from_index, |
intptr_t len, |
Error* bound_error, |
+ TrailPtr bound_trail, |
Heap::Space space) const { |
ASSERT(Length() >= (from_index + len)); |
ASSERT(!other.IsNull()); |
@@ -4300,7 +4310,11 @@ bool TypeArguments::TypeTest(TypeTestKind test_kind, |
ASSERT(!type.IsNull()); |
other_type = other.TypeAt(from_index + i); |
ASSERT(!other_type.IsNull()); |
- if (!type.TypeTest(test_kind, other_type, bound_error, space)) { |
+ if (!type.TypeTest(test_kind, |
+ other_type, |
+ bound_error, |
+ bound_trail, |
+ space)) { |
return false; |
} |
} |
@@ -4350,6 +4364,7 @@ RawAbstractType* TypeArguments::TypeAt(intptr_t index) const { |
void TypeArguments::SetTypeAt(intptr_t index, |
const AbstractType& value) const { |
+ ASSERT(!IsCanonical()); |
StorePointer(TypeAddr(index), value.raw()); |
} |
@@ -4527,7 +4542,8 @@ bool TypeArguments::IsBounded() const { |
RawTypeArguments* TypeArguments::InstantiateFrom( |
const TypeArguments& instantiator_type_arguments, |
Error* bound_error, |
- TrailPtr trail, |
+ TrailPtr instantiation_trail, |
+ TrailPtr bound_trail, |
Heap::Space space) const { |
ASSERT(!IsInstantiated()); |
if (!instantiator_type_arguments.IsNull() && |
@@ -4550,7 +4566,8 @@ RawTypeArguments* TypeArguments::InstantiateFrom( |
if (!type.IsNull() && !type.IsInstantiated()) { |
type = type.InstantiateFrom(instantiator_type_arguments, |
bound_error, |
- trail, |
+ instantiation_trail, |
+ bound_trail, |
space); |
} |
instantiated_array.SetTypeAt(i, type); |
@@ -4584,7 +4601,7 @@ RawTypeArguments* TypeArguments::InstantiateAndCanonicalizeFrom( |
// Cache lookup failed. Instantiate the type arguments. |
TypeArguments& result = TypeArguments::Handle(); |
result = InstantiateFrom( |
- instantiator_type_arguments, bound_error, NULL, Heap::kOld); |
+ instantiator_type_arguments, bound_error, NULL, NULL, Heap::kOld); |
if ((bound_error != NULL) && !bound_error->IsNull()) { |
return result.raw(); |
} |
@@ -4815,6 +4832,11 @@ RawTypeArguments* TypeArguments::Canonicalize(TrailPtr trail) const { |
for (intptr_t i = 0; i < num_types; i++) { |
type_arg = TypeAt(i); |
type_arg = type_arg.Canonicalize(trail); |
+ if (IsCanonical()) { |
+ // Canonicalizing this type_arg canonicalized this type. |
+ ASSERT(IsRecursive()); |
+ return this->raw(); |
+ } |
SetTypeAt(i, type_arg); |
} |
// Canonicalization of a recursive type may change its hash. |
@@ -5927,10 +5949,12 @@ bool Function::TestParameterType( |
AbstractType& other_param_type = |
AbstractType::Handle(other.ParameterTypeAt(other_parameter_position)); |
if (!other_param_type.IsInstantiated()) { |
- other_param_type = other_param_type.InstantiateFrom(other_type_arguments, |
- bound_error, |
- NULL, // trail |
- space); |
+ other_param_type = |
+ other_param_type.InstantiateFrom(other_type_arguments, |
+ bound_error, |
+ NULL, // instantiation_trail |
+ NULL, // bound_trail |
+ space); |
ASSERT((bound_error == NULL) || bound_error->IsNull()); |
} |
if (other_param_type.IsDynamicType()) { |
@@ -5939,21 +5963,25 @@ bool Function::TestParameterType( |
AbstractType& param_type = |
AbstractType::Handle(ParameterTypeAt(parameter_position)); |
if (!param_type.IsInstantiated()) { |
- param_type = param_type.InstantiateFrom( |
- type_arguments, bound_error, NULL /*trail*/, space); |
+ param_type = param_type.InstantiateFrom(type_arguments, |
+ bound_error, |
+ NULL, // instantiation_trail |
+ NULL, // bound_trail |
+ space); |
ASSERT((bound_error == NULL) || bound_error->IsNull()); |
} |
if (param_type.IsDynamicType()) { |
return test_kind == kIsSubtypeOf; |
} |
if (test_kind == kIsSubtypeOf) { |
- if (!param_type.IsSubtypeOf(other_param_type, bound_error, space) && |
- !other_param_type.IsSubtypeOf(param_type, bound_error, space)) { |
+ if (!param_type.IsSubtypeOf(other_param_type, bound_error, NULL, space) && |
+ !other_param_type.IsSubtypeOf(param_type, bound_error, NULL, space)) { |
return false; |
} |
} else { |
ASSERT(test_kind == kIsMoreSpecificThan); |
- if (!param_type.IsMoreSpecificThan(other_param_type, bound_error, space)) { |
+ if (!param_type.IsMoreSpecificThan( |
+ other_param_type, bound_error, NULL, space)) { |
return false; |
} |
} |
@@ -6376,7 +6404,9 @@ void Function::BuildSignatureParameters( |
while (i < num_fixed_params) { |
param_type = ParameterTypeAt(i); |
ASSERT(!param_type.IsNull()); |
- if (instantiate && !param_type.IsInstantiated()) { |
+ if (instantiate && |
+ param_type.IsFinalized() && |
+ !param_type.IsInstantiated()) { |
param_type = param_type.InstantiateFrom(instantiator, NULL); |
} |
name = param_type.BuildName(name_visibility); |
@@ -6401,7 +6431,9 @@ void Function::BuildSignatureParameters( |
pieces->Add(Symbols::ColonSpace()); |
} |
param_type = ParameterTypeAt(i); |
- if (instantiate && !param_type.IsInstantiated()) { |
+ if (instantiate && |
+ param_type.IsFinalized() && |
+ !param_type.IsInstantiated()) { |
param_type = param_type.InstantiateFrom(instantiator, NULL); |
} |
ASSERT(!param_type.IsNull()); |
@@ -6499,7 +6531,7 @@ RawString* Function::BuildSignature(bool instantiate, |
&pieces); |
pieces.Add(Symbols::RParenArrow()); |
AbstractType& res_type = AbstractType::Handle(zone, result_type()); |
- if (instantiate && !res_type.IsInstantiated()) { |
+ if (instantiate && res_type.IsFinalized() && !res_type.IsInstantiated()) { |
res_type = res_type.InstantiateFrom(instantiator, NULL); |
} |
name = res_type.BuildName(name_visibility); |
@@ -14269,7 +14301,7 @@ bool Instance::IsInstanceOf(const AbstractType& other, |
} |
other_class = instantiated_other.type_class(); |
return cls.IsSubtypeOf(type_arguments, other_class, other_type_arguments, |
- bound_error, Heap::kOld); |
+ bound_error, NULL, Heap::kOld); |
} |
@@ -14596,7 +14628,8 @@ bool AbstractType::IsRecursive() const { |
RawAbstractType* AbstractType::InstantiateFrom( |
const TypeArguments& instantiator_type_arguments, |
Error* bound_error, |
- TrailPtr trail, |
+ TrailPtr instantiation_trail, |
+ TrailPtr bound_trail, |
Heap::Space space) const { |
// AbstractType is an abstract class. |
UNREACHABLE(); |
@@ -14656,6 +14689,47 @@ void AbstractType::AddOnlyBuddyToTrail(TrailPtr* trail, |
} |
+bool AbstractType::TestAndAddToTrail(TrailPtr* trail) const { |
+ if (*trail == NULL) { |
+ *trail = new Trail(Thread::Current()->zone(), 4); |
+ } else { |
+ const intptr_t len = (*trail)->length(); |
+ for (intptr_t i = 0; i < len; i++) { |
+ if ((*trail)->At(i).raw() == this->raw()) { |
+ return true; |
+ } |
+ } |
+ } |
+ (*trail)->Add(*this); |
+ return false; |
+} |
+ |
+ |
+bool AbstractType::TestAndAddBuddyToTrail(TrailPtr* trail, |
+ const AbstractType& buddy) const { |
+ if (*trail == NULL) { |
+ *trail = new Trail(Thread::Current()->zone(), 4); |
+ } else { |
+ const intptr_t len = (*trail)->length(); |
+ ASSERT((len % 2) == 0); |
+ const bool this_is_typeref = IsTypeRef(); |
+ const bool buddy_is_typeref = buddy.IsTypeRef(); |
+ ASSERT(this_is_typeref || buddy_is_typeref); |
+ for (intptr_t i = 0; i < len; i += 2) { |
+ if ((((*trail)->At(i).raw() == this->raw()) || |
+ (buddy_is_typeref && (*trail)->At(i).Equals(*this))) && |
+ (((*trail)->At(i + 1).raw() == buddy.raw()) || |
+ (this_is_typeref && (*trail)->At(i + 1).Equals(buddy)))) { |
+ return true; |
+ } |
+ } |
+ } |
+ (*trail)->Add(*this); |
+ (*trail)->Add(buddy); |
+ return false; |
+} |
+ |
+ |
RawString* AbstractType::BuildName(NameVisibility name_visibility) const { |
Zone* zone = Thread::Current()->zone(); |
if (IsBoundedType()) { |
@@ -14862,6 +14936,7 @@ bool AbstractType::IsDartFunctionType() const { |
bool AbstractType::TypeTest(TypeTestKind test_kind, |
const AbstractType& other, |
Error* bound_error, |
+ TrailPtr bound_trail, |
Heap::Space space) const { |
ASSERT(IsFinalized()); |
ASSERT(other.IsFinalized()); |
@@ -14932,7 +15007,9 @@ bool AbstractType::TypeTest(TypeTestKind test_kind, |
if (!bound.IsFinalized()) { |
return false; // TODO(regis): Return "maybe after instantiation". |
} |
- if (bound.IsMoreSpecificThan(other, bound_error)) { |
+ // The current bound_trail cannot be used, because operands are swapped and |
+ // the test is different anyway (more specific vs. subtype). |
+ if (bound.IsMoreSpecificThan(other, bound_error, NULL)) { |
return true; |
} |
return false; // TODO(regis): We should return "maybe after instantiation". |
@@ -14992,6 +15069,7 @@ bool AbstractType::TypeTest(TypeTestKind test_kind, |
Class::Handle(zone, other.type_class()), |
TypeArguments::Handle(zone, other.arguments()), |
bound_error, |
+ bound_trail, |
space); |
} |
@@ -15236,7 +15314,8 @@ bool Type::IsInstantiated(TrailPtr trail) const { |
RawAbstractType* Type::InstantiateFrom( |
const TypeArguments& instantiator_type_arguments, |
Error* bound_error, |
- TrailPtr trail, |
+ TrailPtr instantiation_trail, |
+ TrailPtr bound_trail, |
Heap::Space space) const { |
Zone* zone = Thread::Current()->zone(); |
ASSERT(IsFinalized() || IsBeingFinalized()); |
@@ -15250,32 +15329,21 @@ RawAbstractType* Type::InstantiateFrom( |
if (arguments() == instantiator_type_arguments.raw()) { |
return raw(); |
} |
- // If this type is recursive, we may already be instantiating it. |
- Type& instantiated_type = Type::Handle(zone); |
- 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(zone, type_class()); |
- |
- // This uninstantiated type is not modified, as it can be instantiated |
- // with different instantiators. Allocate a new instantiated version of it. |
- instantiated_type = |
- Type::New(cls, TypeArguments::Handle(zone), token_pos(), space); |
TypeArguments& type_arguments = TypeArguments::Handle(zone, 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, |
+ instantiation_trail, |
+ bound_trail, |
space); |
- instantiated_type.set_arguments(type_arguments); |
+ // This uninstantiated type is not modified, as it can be instantiated |
+ // with different instantiators. Allocate a new instantiated version of it. |
+ const Type& instantiated_type = |
+ Type::Handle(zone, Type::New(cls, type_arguments, token_pos(), space)); |
if (IsFinalized()) { |
instantiated_type.SetIsFinalized(); |
} else { |
@@ -15439,6 +15507,11 @@ RawAbstractType* Type::Canonicalize(TrailPtr trail) const { |
// Canonicalize the type arguments of the supertype, if any. |
TypeArguments& type_args = TypeArguments::Handle(zone, arguments()); |
type_args = type_args.Canonicalize(trail); |
+ if (IsCanonical()) { |
+ // Canonicalizing type_args canonicalized this type. |
+ ASSERT(IsRecursive()); |
+ return this->raw(); |
+ } |
set_arguments(type_args); |
type = cls.CanonicalType(); // May be set while canonicalizing type args. |
if (type.IsNull()) { |
@@ -15483,6 +15556,11 @@ RawAbstractType* Type::Canonicalize(TrailPtr trail) const { |
// vector may be longer than necessary. This is not an issue. |
ASSERT(type_args.IsNull() || (type_args.Length() >= cls.NumTypeArguments())); |
type_args = type_args.Canonicalize(trail); |
+ if (IsCanonical()) { |
+ // Canonicalizing type_args canonicalized this type as a side effect. |
+ ASSERT(IsRecursive()); |
+ return this->raw(); |
+ } |
set_arguments(type_args); |
// Canonicalizing the type arguments may have changed the index, may have |
@@ -15541,6 +15619,7 @@ void Type::set_type_class(const Object& value) const { |
void Type::set_arguments(const TypeArguments& value) const { |
+ ASSERT(!IsCanonical()); |
StorePointer(&raw_ptr()->arguments_, value.raw()); |
} |
@@ -15705,7 +15784,8 @@ bool FunctionType::IsInstantiated(TrailPtr trail) const { |
RawAbstractType* FunctionType::InstantiateFrom( |
const TypeArguments& instantiator_type_arguments, |
Error* bound_error, |
- TrailPtr trail, |
+ TrailPtr instantiation_trail, |
+ TrailPtr bound_trail, |
Heap::Space space) const { |
Zone* zone = Thread::Current()->zone(); |
ASSERT(IsFinalized() || IsBeingFinalized()); |
@@ -15716,36 +15796,25 @@ RawAbstractType* FunctionType::InstantiateFrom( |
if (arguments() == instantiator_type_arguments.raw()) { |
return raw(); |
} |
- // If this type is recursive, we may already be instantiating it. |
- FunctionType& instantiated_type = FunctionType::Handle(zone); |
- instantiated_type ^= OnlyBuddyInTrail(trail); |
- if (!instantiated_type.IsNull()) { |
- ASSERT(IsRecursive()); |
- return instantiated_type.raw(); |
- } |
// Note that the scope 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(zone, scope_class()); |
- |
- // This uninstantiated type is not modified, as it can be instantiated |
- // with different instantiators. Allocate a new instantiated version of it. |
- instantiated_type = |
- FunctionType::New(cls, |
- TypeArguments::Handle(zone), |
- Function::Handle(zone, signature()), |
- token_pos(), |
- space); |
TypeArguments& type_arguments = TypeArguments::Handle(zone, 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, |
+ instantiation_trail, |
+ bound_trail, |
space); |
- instantiated_type.set_arguments(type_arguments); |
+ // This uninstantiated type is not modified, as it can be instantiated |
+ // with different instantiators. Allocate a new instantiated version of it. |
+ const FunctionType& instantiated_type = FunctionType::Handle(zone, |
+ FunctionType::New(cls, |
+ type_arguments, |
+ Function::Handle(zone, signature()), |
+ token_pos(), |
+ space)); |
if (IsFinalized()) { |
instantiated_type.SetIsFinalized(); |
} else { |
@@ -15953,6 +16022,13 @@ RawAbstractType* FunctionType::Canonicalize(TrailPtr trail) const { |
ASSERT(type_args.IsNull() || |
(type_args.Length() >= scope_cls.NumTypeArguments())); |
type_args = type_args.Canonicalize(trail); |
+ if (IsCanonical()) { |
+ // Canonicalizing type_args canonicalized this type as a side effect. |
+ ASSERT(IsRecursive()); |
+ // Cycles via typedefs are detected and disallowed, but a function type can |
+ // be recursive due to a cycle in its type arguments. |
+ return this->raw(); |
+ } |
set_arguments(type_args); |
// Replace the actual function by a signature function. |
@@ -16050,6 +16126,7 @@ void FunctionType::set_scope_class(const Class& value) const { |
void FunctionType::set_arguments(const TypeArguments& value) const { |
+ ASSERT(!IsCanonical()); |
StorePointer(&raw_ptr()->arguments_, value.raw()); |
} |
@@ -16150,21 +16227,28 @@ bool TypeRef::IsEquivalent(const Instance& other, TrailPtr trail) const { |
RawTypeRef* TypeRef::InstantiateFrom( |
const TypeArguments& instantiator_type_arguments, |
Error* bound_error, |
- TrailPtr trail, |
+ TrailPtr instantiation_trail, |
+ TrailPtr bound_trail, |
Heap::Space space) const { |
TypeRef& instantiated_type_ref = TypeRef::Handle(); |
- instantiated_type_ref ^= OnlyBuddyInTrail(trail); |
+ instantiated_type_ref ^= OnlyBuddyInTrail(instantiation_trail); |
if (!instantiated_type_ref.IsNull()) { |
return instantiated_type_ref.raw(); |
} |
+ instantiated_type_ref = TypeRef::New(); |
+ AddOnlyBuddyToTrail(&instantiation_trail, instantiated_type_ref); |
+ |
AbstractType& ref_type = AbstractType::Handle(type()); |
ASSERT(!ref_type.IsTypeRef()); |
AbstractType& instantiated_ref_type = AbstractType::Handle(); |
instantiated_ref_type = ref_type.InstantiateFrom( |
- instantiator_type_arguments, bound_error, trail, space); |
+ instantiator_type_arguments, |
+ bound_error, |
+ instantiation_trail, |
+ bound_trail, |
+ space); |
ASSERT(!instantiated_ref_type.IsTypeRef()); |
- instantiated_type_ref = TypeRef::New(instantiated_ref_type); |
- AddOnlyBuddyToTrail(&trail, instantiated_type_ref); |
+ instantiated_type_ref.set_type(instantiated_ref_type); |
return instantiated_type_ref.raw(); |
} |
@@ -16176,13 +16260,14 @@ RawTypeRef* TypeRef::CloneUninstantiated(const Class& new_owner, |
if (!cloned_type_ref.IsNull()) { |
return cloned_type_ref.raw(); |
} |
+ cloned_type_ref = TypeRef::New(); |
+ AddOnlyBuddyToTrail(&trail, cloned_type_ref); |
AbstractType& ref_type = AbstractType::Handle(type()); |
ASSERT(!ref_type.IsTypeRef()); |
AbstractType& cloned_ref_type = AbstractType::Handle(); |
cloned_ref_type = ref_type.CloneUninstantiated(new_owner, trail); |
ASSERT(!cloned_ref_type.IsTypeRef()); |
- cloned_type_ref = TypeRef::New(cloned_ref_type); |
- AddOnlyBuddyToTrail(&trail, cloned_type_ref); |
+ cloned_type_ref.set_type(cloned_ref_type); |
return cloned_type_ref.raw(); |
} |
@@ -16219,42 +16304,6 @@ intptr_t TypeRef::Hash() const { |
} |
-bool TypeRef::TestAndAddToTrail(TrailPtr* trail) const { |
- if (*trail == NULL) { |
- *trail = new Trail(Thread::Current()->zone(), 4); |
- } else { |
- const intptr_t len = (*trail)->length(); |
- for (intptr_t i = 0; i < len; i++) { |
- if ((*trail)->At(i).raw() == this->raw()) { |
- return true; |
- } |
- } |
- } |
- (*trail)->Add(*this); |
- return false; |
-} |
- |
- |
-bool TypeRef::TestAndAddBuddyToTrail(TrailPtr* trail, |
- const AbstractType& buddy) const { |
- if (*trail == NULL) { |
- *trail = new Trail(Thread::Current()->zone(), 4); |
- } else { |
- const intptr_t len = (*trail)->length(); |
- ASSERT((len % 2) == 0); |
- for (intptr_t i = 0; i < len; i += 2) { |
- if (((*trail)->At(i).raw() == this->raw()) && |
- ((*trail)->At(i + 1).raw() == buddy.raw())) { |
- return true; |
- } |
- } |
- } |
- (*trail)->Add(*this); |
- (*trail)->Add(buddy); |
- return false; |
-} |
- |
- |
RawTypeRef* TypeRef::New() { |
RawObject* raw = Object::Allocate(TypeRef::kClassId, |
TypeRef::InstanceSize(), |
@@ -16343,7 +16392,8 @@ void TypeParameter::set_bound(const AbstractType& value) const { |
RawAbstractType* TypeParameter::InstantiateFrom( |
const TypeArguments& instantiator_type_arguments, |
Error* bound_error, |
- TrailPtr trail, |
+ TrailPtr instantiation_trail, |
+ TrailPtr bound_trail, |
Heap::Space space) const { |
ASSERT(IsFinalized()); |
if (instantiator_type_arguments.IsNull()) { |
@@ -16355,6 +16405,12 @@ RawAbstractType* TypeParameter::InstantiateFrom( |
// 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. |
+ |
+ // If the instantiated type parameter type_arg is a BoundedType, it means that |
+ // it is still uninstantiated and that we are instantiating at finalization |
+ // time (i.e. compile time). |
+ // Indeed, the instantiator (type arguments of an instance) is always |
+ // instantiated at run time and any bounds were checked during allocation. |
return type_arg.raw(); |
} |
@@ -16362,12 +16418,21 @@ RawAbstractType* TypeParameter::InstantiateFrom( |
bool TypeParameter::CheckBound(const AbstractType& bounded_type, |
const AbstractType& upper_bound, |
Error* bound_error, |
+ TrailPtr bound_trail, |
Heap::Space space) const { |
ASSERT((bound_error != NULL) && bound_error->IsNull()); |
ASSERT(bounded_type.IsFinalized()); |
ASSERT(upper_bound.IsFinalized()); |
ASSERT(!bounded_type.IsMalformed()); |
- if (bounded_type.IsSubtypeOf(upper_bound, bound_error, space)) { |
+ if (bounded_type.IsTypeRef() || upper_bound.IsTypeRef()) { |
+ // Shortcut the bound check if the pair <bounded_type, upper_bound> is |
+ // already in the trail. |
+ if (bounded_type.TestAndAddBuddyToTrail(&bound_trail, upper_bound)) { |
+ return true; |
+ } |
+ } |
+ |
+ if (bounded_type.IsSubtypeOf(upper_bound, bound_error, bound_trail, space)) { |
return true; |
} |
// Set bound_error if the caller is interested and if this is the first error. |
@@ -16424,18 +16489,24 @@ RawAbstractType* TypeParameter::CloneUnfinalized() const { |
RawAbstractType* TypeParameter::CloneUninstantiated( |
const Class& new_owner, TrailPtr trail) const { |
ASSERT(IsFinalized()); |
- AbstractType& upper_bound = AbstractType::Handle(bound()); |
- upper_bound = upper_bound.CloneUninstantiated(new_owner, trail); |
+ TypeParameter& clone = TypeParameter::Handle(); |
+ clone ^= OnlyBuddyInTrail(trail); |
+ if (!clone.IsNull()) { |
+ return clone.raw(); |
+ } |
const Class& old_owner = Class::Handle(parameterized_class()); |
const intptr_t new_index = index() + |
new_owner.NumTypeArguments() - old_owner.NumTypeArguments(); |
- const TypeParameter& clone = TypeParameter::Handle( |
- TypeParameter::New(new_owner, |
- new_index, |
- String::Handle(name()), |
- upper_bound, |
- token_pos())); |
+ AbstractType& upper_bound = AbstractType::Handle(bound()); |
+ clone = TypeParameter::New(new_owner, |
+ new_index, |
+ String::Handle(name()), |
+ upper_bound, // Not cloned yet. |
+ token_pos()); |
clone.SetIsFinalized(); |
+ AddOnlyBuddyToTrail(&trail, clone); |
+ upper_bound = upper_bound.CloneUninstantiated(new_owner, trail); |
+ clone.set_bound(upper_bound); |
return clone.raw(); |
} |
@@ -16590,18 +16661,24 @@ void BoundedType::set_type_parameter(const TypeParameter& value) const { |
RawAbstractType* BoundedType::InstantiateFrom( |
const TypeArguments& instantiator_type_arguments, |
Error* bound_error, |
- TrailPtr trail, |
+ TrailPtr instantiation_trail, |
+ TrailPtr bound_trail, |
Heap::Space space) const { |
ASSERT(IsFinalized()); |
AbstractType& bounded_type = AbstractType::Handle(type()); |
ASSERT(bounded_type.IsFinalized()); |
+ AbstractType& instantiated_bounded_type = |
+ AbstractType::Handle(bounded_type.raw()); |
if (!bounded_type.IsInstantiated()) { |
- bounded_type = bounded_type.InstantiateFrom(instantiator_type_arguments, |
- bound_error, |
- trail, |
- space); |
- // In case types of instantiator_type_arguments are not finalized, then |
- // the instantiated bounded_type is not finalized either. |
+ instantiated_bounded_type = |
+ bounded_type.InstantiateFrom(instantiator_type_arguments, |
+ bound_error, |
+ instantiation_trail, |
+ bound_trail, |
+ space); |
+ // In case types of instantiator_type_arguments are not finalized |
+ // (or instantiated), then the instantiated_bounded_type is not finalized |
+ // (or instantiated) either. |
// Note that instantiator_type_arguments must have the final length, though. |
} |
if ((Isolate::Current()->flags().type_checks()) && |
@@ -16609,34 +16686,49 @@ RawAbstractType* BoundedType::InstantiateFrom( |
AbstractType& upper_bound = AbstractType::Handle(bound()); |
ASSERT(upper_bound.IsFinalized()); |
ASSERT(!upper_bound.IsObjectType() && !upper_bound.IsDynamicType()); |
- const TypeParameter& type_param = TypeParameter::Handle(type_parameter()); |
+ AbstractType& instantiated_upper_bound = |
+ AbstractType::Handle(upper_bound.raw()); |
if (!upper_bound.IsInstantiated()) { |
- upper_bound = upper_bound.InstantiateFrom(instantiator_type_arguments, |
- bound_error, |
- trail, |
- space); |
- // Instantiated upper_bound may not be finalized. See comment above. |
+ instantiated_upper_bound = |
+ upper_bound.InstantiateFrom(instantiator_type_arguments, |
+ bound_error, |
+ instantiation_trail, |
+ bound_trail, |
+ space); |
+ // The instantiated_upper_bound may not be finalized or instantiated. |
+ // See comment above. |
} |
if (bound_error->IsNull()) { |
- if (bounded_type.IsBeingFinalized() || |
- upper_bound.IsBeingFinalized() || |
- (!type_param.CheckBound(bounded_type, upper_bound, bound_error) && |
+ // Shortcut the F-bounded case where we have reached a fixpoint. |
+ if (instantiated_bounded_type.Equals(bounded_type) && |
+ instantiated_upper_bound.Equals(upper_bound)) { |
+ return bounded_type.raw(); |
+ } |
+ const TypeParameter& type_param = TypeParameter::Handle(type_parameter()); |
+ if (instantiated_bounded_type.IsBeingFinalized() || |
+ instantiated_upper_bound.IsBeingFinalized() || |
+ (!type_param.CheckBound(instantiated_bounded_type, |
+ instantiated_upper_bound, |
+ bound_error, |
+ bound_trail) && |
bound_error->IsNull())) { |
// We cannot determine yet whether the bounded_type is below the |
// upper_bound, because one or both of them is still being finalized or |
// uninstantiated. |
- ASSERT(bounded_type.IsBeingFinalized() || |
- upper_bound.IsBeingFinalized() || |
- !bounded_type.IsInstantiated() || |
- !upper_bound.IsInstantiated()); |
+ ASSERT(instantiated_bounded_type.IsBeingFinalized() || |
+ instantiated_upper_bound.IsBeingFinalized() || |
+ !instantiated_bounded_type.IsInstantiated() || |
+ !instantiated_upper_bound.IsInstantiated()); |
// Postpone bound check by returning a new BoundedType with unfinalized |
// or partially instantiated bounded_type and upper_bound, but keeping |
// type_param. |
- bounded_type = BoundedType::New(bounded_type, upper_bound, type_param); |
+ instantiated_bounded_type = BoundedType::New(instantiated_bounded_type, |
+ instantiated_upper_bound, |
+ type_param); |
} |
} |
} |
- return bounded_type.raw(); |
+ return instantiated_bounded_type.raw(); |
} |