| Index: runtime/vm/class_finalizer.cc
|
| ===================================================================
|
| --- runtime/vm/class_finalizer.cc (revision 20601)
|
| +++ runtime/vm/class_finalizer.cc (working copy)
|
| @@ -627,7 +627,8 @@
|
| const intptr_t offset = cls.NumTypeArguments() - num_type_params;
|
| AbstractType& type_arg = AbstractType::Handle();
|
| AbstractType& cls_type_param = AbstractType::Handle();
|
| - AbstractType& bound = AbstractType::Handle();
|
| + AbstractType& declared_bound = AbstractType::Handle();
|
| + AbstractType& instantiated_bound = AbstractType::Handle();
|
| const TypeArguments& cls_type_params =
|
| TypeArguments::Handle(cls.type_parameters());
|
| ASSERT((cls_type_params.IsNull() && (num_type_params == 0)) ||
|
| @@ -640,33 +641,41 @@
|
| cls_type_param = cls_type_params.TypeAt(i);
|
| const TypeParameter& type_param = TypeParameter::Cast(cls_type_param);
|
| ASSERT(type_param.IsFinalized());
|
| - bound = type_param.bound();
|
| - if (!bound.IsObjectType() && !bound.IsDynamicType()) {
|
| + declared_bound = type_param.bound();
|
| + if (!declared_bound.IsObjectType() && !declared_bound.IsDynamicType()) {
|
| Error& malformed_error = Error::Handle();
|
| // Note that the bound may be malformed, in which case the bound check
|
| // will return an error and the bound check will be postponed to run time.
|
| // Note also that the bound may still be unfinalized.
|
| - if (!bound.IsFinalized()) {
|
| - ASSERT(bound.IsBeingFinalized());
|
| + if (!declared_bound.IsFinalized()) {
|
| + ASSERT(declared_bound.IsBeingFinalized());
|
| // The bound refers to type parameters, creating a cycle; postpone
|
| // bound check to run time, when the bound will be finalized.
|
| // TODO(regis): Do we need to instantiate an uninstantiated bound here?
|
| - type_arg = BoundedType::New(type_arg, bound, type_param);
|
| + type_arg = BoundedType::New(type_arg, declared_bound, type_param);
|
| arguments.SetTypeAt(offset + i, type_arg);
|
| continue;
|
| }
|
| - if (!bound.IsInstantiated()) {
|
| - bound = bound.InstantiateFrom(arguments, &malformed_error);
|
| + if (declared_bound.IsInstantiated()) {
|
| + instantiated_bound = declared_bound.raw();
|
| + } else {
|
| + instantiated_bound =
|
| + declared_bound.InstantiateFrom(arguments, &malformed_error);
|
| }
|
| // TODO(regis): We could simplify this code if we could differentiate
|
| // between a failed bound check and a bound check that is undecidable at
|
| // compile time.
|
| - if (malformed_error.IsNull()) {
|
| - type_param.CheckBound(type_arg, bound, &malformed_error);
|
| + // Shortcut the special case where we check a type parameter against its
|
| + // declared upper bound.
|
| + if (malformed_error.IsNull() &&
|
| + (!type_arg.Equals(type_param) ||
|
| + !instantiated_bound.Equals(declared_bound))) {
|
| + type_param.CheckBound(type_arg, instantiated_bound, &malformed_error);
|
| }
|
| if (!malformed_error.IsNull()) {
|
| - if (!type_arg.IsInstantiated() || !bound.IsInstantiated()) {
|
| - type_arg = BoundedType::New(type_arg, bound, type_param);
|
| + if (!type_arg.IsInstantiated() ||
|
| + !instantiated_bound.IsInstantiated()) {
|
| + type_arg = BoundedType::New(type_arg, instantiated_bound, type_param);
|
| arguments.SetTypeAt(offset + i, type_arg);
|
| } else if (bound_error->IsNull()) {
|
| *bound_error = malformed_error.raw();
|
| @@ -1021,7 +1030,8 @@
|
| for (intptr_t i = 0; i < num_type_params; i++) {
|
| type_param ^= type_params.TypeAt(i);
|
| bound = type_param.bound();
|
| - if (bound.IsFinalized()) {
|
| + if (bound.IsFinalized() || bound.IsBeingFinalized()) {
|
| + // A bound involved in F-bounded quantification may form a cycle.
|
| continue;
|
| }
|
| ResolveType(cls, bound, kCanonicalize);
|
|
|