| Index: runtime/vm/class_finalizer.cc
|
| ===================================================================
|
| --- runtime/vm/class_finalizer.cc (revision 20937)
|
| +++ runtime/vm/class_finalizer.cc (working copy)
|
| @@ -507,6 +507,7 @@
|
| ASSERT(arguments.Length() >= cls.NumTypeArguments());
|
| if (!cls.is_finalized()) {
|
| FinalizeTypeParameters(cls);
|
| + ResolveUpperBounds(cls);
|
| }
|
| AbstractType& super_type = AbstractType::Handle(cls.super_type());
|
| if (!super_type.IsNull()) {
|
| @@ -574,7 +575,7 @@
|
| const AbstractTypeArguments& arguments,
|
| Error* bound_error) {
|
| if (!cls.is_finalized()) {
|
| - ResolveAndFinalizeUpperBounds(cls);
|
| + FinalizeUpperBounds(cls);
|
| }
|
| // Note that when finalizing a type, we need to verify the bounds in both
|
| // production mode and checked mode, because the finalized type may be written
|
| @@ -607,37 +608,48 @@
|
| // 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 (!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, declared_bound, type_param);
|
| - arguments.SetTypeAt(offset + i, type_arg);
|
| - continue;
|
| - }
|
| if (declared_bound.IsInstantiated()) {
|
| instantiated_bound = declared_bound.raw();
|
| } else {
|
| instantiated_bound =
|
| declared_bound.InstantiateFrom(arguments, &malformed_error);
|
| }
|
| + if (!instantiated_bound.IsFinalized()) {
|
| + // The bound refers to type parameters, creating a cycle; postpone
|
| + // bound check to run time, when the bound will be finalized.
|
| + // The bound may not necessarily be 'IsBeingFinalized' yet, as is the
|
| + // case with a pair of type parameters of the same class referring to
|
| + // each other via their bounds.
|
| + type_arg = BoundedType::New(type_arg, instantiated_bound, type_param);
|
| + arguments.SetTypeAt(offset + i, type_arg);
|
| + continue;
|
| + }
|
| // 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.
|
| // Shortcut the special case where we check a type parameter against its
|
| // declared upper bound.
|
| + bool below_bound = true;
|
| if (malformed_error.IsNull() &&
|
| (!type_arg.Equals(type_param) ||
|
| !instantiated_bound.Equals(declared_bound))) {
|
| - type_param.CheckBound(type_arg, instantiated_bound, &malformed_error);
|
| + // Pass NULL to prevent expensive and unnecessary error formatting in
|
| + // the case the bound check is postponed to run time.
|
| + below_bound = type_param.CheckBound(type_arg, instantiated_bound, NULL);
|
| }
|
| - if (!malformed_error.IsNull()) {
|
| + if (!malformed_error.IsNull() || !below_bound) {
|
| 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()) {
|
| + if (malformed_error.IsNull()) {
|
| + // Call CheckBound again to format error message.
|
| + type_param.CheckBound(type_arg,
|
| + instantiated_bound,
|
| + &malformed_error);
|
| + }
|
| + ASSERT(!malformed_error.IsNull());
|
| *bound_error = malformed_error.raw();
|
| }
|
| }
|
| @@ -717,6 +729,7 @@
|
| Class& type_class = Class::Handle(parameterized_type.type_class());
|
| if (!type_class.is_finalized()) {
|
| FinalizeTypeParameters(type_class);
|
| + ResolveUpperBounds(type_class);
|
| }
|
|
|
| // Finalize the current type arguments of the type, which are still the
|
| @@ -978,8 +991,8 @@
|
| }
|
|
|
|
|
| -// Resolve and finalize the upper bounds of the type parameters of class cls.
|
| -void ClassFinalizer::ResolveAndFinalizeUpperBounds(const Class& cls) {
|
| +// Resolve the upper bounds of the type parameters of class cls.
|
| +void ClassFinalizer::ResolveUpperBounds(const Class& cls) {
|
| const intptr_t num_type_params = cls.NumTypeParameters();
|
| TypeParameter& type_param = TypeParameter::Handle();
|
| AbstractType& bound = AbstractType::Handle();
|
| @@ -987,14 +1000,32 @@
|
| AbstractTypeArguments::Handle(cls.type_parameters());
|
| ASSERT((type_params.IsNull() && (num_type_params == 0)) ||
|
| (type_params.Length() == num_type_params));
|
| + // In a first pass, resolve all bounds. This guarantees that finalization
|
| + // of mutually referencing bounds will not encounter an unresolved bound.
|
| for (intptr_t i = 0; i < num_type_params; i++) {
|
| type_param ^= type_params.TypeAt(i);
|
| bound = type_param.bound();
|
| + ResolveType(cls, bound, kCanonicalize);
|
| + }
|
| +}
|
| +
|
| +
|
| +// Finalize the upper bounds of the type parameters of class cls.
|
| +void ClassFinalizer::FinalizeUpperBounds(const Class& cls) {
|
| + const intptr_t num_type_params = cls.NumTypeParameters();
|
| + TypeParameter& type_param = TypeParameter::Handle();
|
| + AbstractType& bound = AbstractType::Handle();
|
| + const AbstractTypeArguments& type_params =
|
| + AbstractTypeArguments::Handle(cls.type_parameters());
|
| + ASSERT((type_params.IsNull() && (num_type_params == 0)) ||
|
| + (type_params.Length() == num_type_params));
|
| + for (intptr_t i = 0; i < num_type_params; i++) {
|
| + type_param ^= type_params.TypeAt(i);
|
| + bound = type_param.bound();
|
| if (bound.IsFinalized() || bound.IsBeingFinalized()) {
|
| // A bound involved in F-bounded quantification may form a cycle.
|
| continue;
|
| }
|
| - ResolveType(cls, bound, kCanonicalize);
|
| bound = FinalizeType(cls, bound, kCanonicalize);
|
| type_param.set_bound(bound);
|
| }
|
| @@ -1369,6 +1400,7 @@
|
| }
|
| // Finalize type parameters before finalizing the super type.
|
| FinalizeTypeParameters(cls);
|
| + ResolveUpperBounds(cls);
|
| // Finalize super type.
|
| AbstractType& super_type = AbstractType::Handle(cls.super_type());
|
| if (!super_type.IsNull()) {
|
| @@ -1397,7 +1429,7 @@
|
| ASSERT(super_type.IsNull() || super_type.IsObjectType());
|
|
|
| // The type parameters of signature classes may have bounds.
|
| - ResolveAndFinalizeUpperBounds(cls);
|
| + FinalizeUpperBounds(cls);
|
|
|
| // Resolve and finalize the result and parameter types of the signature
|
| // function of this signature class.
|
| @@ -1448,7 +1480,7 @@
|
| cls.Finalize();
|
| // Finalize bounds even if running in production mode, so that a snapshot
|
| // contains them.
|
| - ResolveAndFinalizeUpperBounds(cls);
|
| + FinalizeUpperBounds(cls);
|
| ResolveAndFinalizeMemberTypes(cls);
|
| // Run additional checks after all types are finalized.
|
| if (cls.is_const()) {
|
|
|