| Index: runtime/vm/object.cc
|
| diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
|
| index 8e3284f3020ddb2e84329e0df43cb0984cd0afb6..b5e035f54a88920ce69eb5d807840ae5d063cbe6 100644
|
| --- a/runtime/vm/object.cc
|
| +++ b/runtime/vm/object.cc
|
| @@ -3876,6 +3876,12 @@ bool Class::TypeTestNonRecursive(const Class& cls,
|
| if (!interface.IsFinalized()) {
|
| // We may be checking bounds at finalization time and can encounter
|
| // a still unfinalized interface.
|
| + if (interface.IsBeingFinalized()) {
|
| + // Interface is part of a still unfinalized recursive type graph.
|
| + // Skip it. The caller will create a bounded type to be checked at
|
| + // runtime if this type test returns false at compile time.
|
| + continue;
|
| + }
|
| ClassFinalizer::FinalizeType(
|
| thsi, interface, ClassFinalizer::kCanonicalize);
|
| interfaces.SetAt(i, interface);
|
| @@ -15513,8 +15519,8 @@ RawString* AbstractType::BuildName(NameVisibility name_visibility) const {
|
| } else if (bound.IsType()) {
|
| const Class& cls = Class::Handle(zone, Type::Cast(bound).type_class());
|
| bound_name = cls.Name();
|
| + pieces.Add(bound_name);
|
| if (Type::Cast(bound).arguments() != TypeArguments::null()) {
|
| - pieces.Add(bound_name);
|
| pieces.Add(Symbols::OptimizedOut());
|
| }
|
| } else {
|
| @@ -15727,6 +15733,11 @@ bool AbstractType::TypeTest(TypeTestKind test_kind,
|
| if (Equals(other)) {
|
| return true;
|
| }
|
| + // Redundant check if other type is equal to the upper bound of this type.
|
| + if (IsBoundedType() &&
|
| + AbstractType::Handle(BoundedType::Cast(*this).bound()).Equals(other)) {
|
| + return true;
|
| + }
|
| return false; // TODO(regis): We should return "maybe after instantiation".
|
| }
|
| // Type parameters cannot be handled by Class::TypeTest().
|
| @@ -16144,6 +16155,13 @@ bool Type::IsEquivalent(const Instance& other, TrailPtr trail) const {
|
| for (intptr_t i = 0; i < from_index; i++) {
|
| type_arg = type_args.TypeAt(i);
|
| other_type_arg = other_type_args.TypeAt(i);
|
| + // Ignore bounds of bounded types.
|
| + while (type_arg.IsBoundedType()) {
|
| + type_arg = BoundedType::Cast(type_arg).type();
|
| + }
|
| + while (other_type_arg.IsBoundedType()) {
|
| + other_type_arg = BoundedType::Cast(other_type_arg).type();
|
| + }
|
| ASSERT(type_arg.IsEquivalent(other_type_arg, trail));
|
| }
|
| }
|
| @@ -16973,13 +16991,20 @@ RawAbstractType* BoundedType::InstantiateFrom(
|
| // Instantiated upper_bound may not be finalized. See comment above.
|
| }
|
| if (bound_error->IsNull()) {
|
| - if (!type_param.CheckBound(bounded_type, upper_bound, bound_error) &&
|
| - bound_error->IsNull()) {
|
| + if (bounded_type.IsBeingFinalized() ||
|
| + upper_bound.IsBeingFinalized() ||
|
| + (!type_param.CheckBound(bounded_type, upper_bound, bound_error) &&
|
| + bound_error->IsNull())) {
|
| // We cannot determine yet whether the bounded_type is below the
|
| - // upper_bound, because one or both of them is still uninstantiated.
|
| - ASSERT(!bounded_type.IsInstantiated() || !upper_bound.IsInstantiated());
|
| - // Postpone bound check by returning a new BoundedType with partially
|
| - // instantiated bounded_type and upper_bound, but keeping type_param.
|
| + // 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());
|
| + // 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);
|
| }
|
| }
|
|
|