| Index: runtime/vm/class_finalizer.cc
|
| ===================================================================
|
| --- runtime/vm/class_finalizer.cc (revision 31792)
|
| +++ runtime/vm/class_finalizer.cc (working copy)
|
| @@ -1393,21 +1393,22 @@
|
| // T, and use them as type arguments in S<T`> and M<T>.
|
| void ClassFinalizer::CloneMixinAppTypeParameters(const Class& mixin_app_class) {
|
| ASSERT(mixin_app_class.type_parameters() == AbstractTypeArguments::null());
|
| - const AbstractType& super_type = AbstractType::Handle(
|
| + Isolate* isolate = Isolate::Current();
|
| + const AbstractType& super_type = AbstractType::Handle(isolate,
|
| mixin_app_class.super_type());
|
| ASSERT(super_type.IsResolved());
|
| - const Class& super_class = Class::Handle(super_type.type_class());
|
| + const Class& super_class = Class::Handle(isolate, super_type.type_class());
|
| const intptr_t num_super_type_params = super_class.NumTypeParameters();
|
| - const Type& mixin_type = Type::Handle(mixin_app_class.mixin());
|
| - const Class& mixin_class = Class::Handle(mixin_type.type_class());
|
| + const Type& mixin_type = Type::Handle(isolate, mixin_app_class.mixin());
|
| + const Class& mixin_class = Class::Handle(isolate, mixin_type.type_class());
|
| const intptr_t num_mixin_type_params = mixin_class.NumTypeParameters();
|
| // The mixin class cannot be Object and this was checked earlier.
|
| ASSERT(!mixin_class.IsObjectClass());
|
|
|
| // Add the mixin type to the interfaces that the mixin application
|
| // class implements. This is necessary so that type tests work.
|
| - const Array& interfaces = Array::Handle(Array::New(1));
|
| - const Type& interface = Type::Handle(Type::New(
|
| + const Array& interfaces = Array::Handle(isolate, Array::New(1));
|
| + const Type& interface = Type::Handle(isolate, Type::New(
|
| mixin_class,
|
| Object::null_abstract_type_arguments(), // Set again below if generic.
|
| mixin_app_class.token_pos()));
|
| @@ -1419,35 +1420,30 @@
|
| // If both the super type and the mixin type are non generic, the mixin
|
| // application class is non generic as well and we can skip type parameter
|
| // cloning.
|
| + bool has_uninstantiated_bounds = false;
|
| if ((num_super_type_params + num_mixin_type_params) > 0) {
|
| // First, clone the super class type parameters. Rename them so that
|
| // there can be no name conflict between the parameters of the super
|
| // class and the mixin class.
|
| - const TypeArguments& cloned_type_params = TypeArguments::Handle(
|
| + const TypeArguments& cloned_type_params = TypeArguments::Handle(isolate,
|
| TypeArguments::New(num_super_type_params + num_mixin_type_params));
|
| - TypeParameter& param = TypeParameter::Handle();
|
| - TypeParameter& cloned_param = TypeParameter::Handle();
|
| - String& param_name = String::Handle();
|
| - AbstractType& param_bound = AbstractType::Handle();
|
| + TypeParameter& param = TypeParameter::Handle(isolate);
|
| + TypeParameter& cloned_param = TypeParameter::Handle(isolate);
|
| + String& param_name = String::Handle(isolate);
|
| + AbstractType& param_bound = AbstractType::Handle(isolate);
|
| intptr_t cloned_index = 0;
|
| if (num_super_type_params > 0) {
|
| const TypeArguments& super_type_params =
|
| - TypeArguments::Handle(super_class.type_parameters());
|
| - const TypeArguments& super_type_args =
|
| - TypeArguments::Handle(TypeArguments::New(num_super_type_params));
|
| + TypeArguments::Handle(isolate, super_class.type_parameters());
|
| + const TypeArguments& super_type_args = TypeArguments::Handle(isolate,
|
| + TypeArguments::New(num_super_type_params));
|
| + // The cloned super class type parameters do not need to repeat their
|
| + // bounds, since the bound checks will be performed at the super class
|
| + // level.
|
| + param_bound = isolate->object_store()->object_type();
|
| for (intptr_t i = 0; i < num_super_type_params; i++) {
|
| param ^= super_type_params.TypeAt(i);
|
| param_name = param.name();
|
| - param_bound = param.bound();
|
| - // TODO(14453): handle type bounds.
|
| - if (!param_bound.IsObjectType()) {
|
| - const Script& script = Script::Handle(mixin_app_class.script());
|
| - ReportError(Error::Handle(), // No previous error.
|
| - script, param.token_pos(),
|
| - "type parameter '%s': type bounds not yet"
|
| - " implemented for mixins\n",
|
| - param_name.ToCString());
|
| - }
|
| param_name = String::Concat(param_name, Symbols::Backtick());
|
| param_name = Symbols::New(param_name);
|
| cloned_param = TypeParameter::New(mixin_app_class,
|
| @@ -1461,8 +1457,8 @@
|
| super_type_args.SetTypeAt(cloned_index, cloned_param);
|
| cloned_index++;
|
| }
|
| - // TODO(14453): May need to handle BoundedType here.
|
| - ASSERT(super_type.IsType());
|
| + // The super type may have a BoundedType as type argument, but cannot be
|
| + // a BoundedType itself.
|
| Type::Cast(super_type).set_arguments(super_type_args);
|
| ASSERT(!super_type.IsFinalized());
|
| }
|
| @@ -1474,25 +1470,18 @@
|
| // with that name.
|
| if (num_mixin_type_params > 0) {
|
| const TypeArguments& mixin_params =
|
| - TypeArguments::Handle(mixin_class.type_parameters());
|
| - const TypeArguments& mixin_type_args = TypeArguments::Handle(
|
| + TypeArguments::Handle(isolate, mixin_class.type_parameters());
|
| + const TypeArguments& mixin_type_args = TypeArguments::Handle(isolate,
|
| TypeArguments::New(num_mixin_type_params));
|
| // TODO(regis): Can we share interface type and mixin_type?
|
| - const TypeArguments& interface_type_args = TypeArguments::Handle(
|
| + const TypeArguments& interface_type_args = TypeArguments::Handle(isolate,
|
| TypeArguments::New(num_mixin_type_params));
|
| for (intptr_t i = 0; i < num_mixin_type_params; i++) {
|
| param ^= mixin_params.TypeAt(i);
|
| param_name = param.name();
|
| - param_bound = param.bound();
|
| -
|
| - // TODO(14453): handle type bounds.
|
| - if (!param_bound.IsObjectType()) {
|
| - const Script& script = Script::Handle(mixin_app_class.script());
|
| - ReportError(Error::Handle(), // No previous error.
|
| - script, param.token_pos(),
|
| - "type parameter '%s': type bounds not yet"
|
| - " implemented for mixins\n",
|
| - param_name.ToCString());
|
| + param_bound = param.bound(); // The bound will be adjusted below.
|
| + if (!param_bound.IsInstantiated()) {
|
| + has_uninstantiated_bounds = true;
|
| }
|
| cloned_param = TypeParameter::New(mixin_app_class,
|
| cloned_index,
|
| @@ -1505,6 +1494,34 @@
|
| cloned_index++;
|
| }
|
|
|
| + // Third, replace the type parameters appearing in the bounds of the mixin
|
| + // type parameters, if any, by the cloned type parameters. This can be
|
| + // done by instantiating each bound using the mixin_type_args as
|
| + // instantiator. Since the mixin class must extend Object, its first type
|
| + // parameter has index 0, therefore, the instantiator does not require
|
| + // shifting. There is however an exception where the mixin class is an
|
| + // alias, in which case shifting is required and performed later in
|
| + // ApplyMixinAppAlias.
|
| + // Unfinalized type parameters replace finalized type parameters, which
|
| + // is not a problem since they will get finalized shortly as the mixin
|
| + // application class gets finalized.
|
| + if (has_uninstantiated_bounds && !mixin_class.is_mixin_app_alias()) {
|
| + Error& bound_error = Error::Handle(isolate);
|
| + for (intptr_t i = 0; i < num_mixin_type_params; i++) {
|
| + param ^= mixin_type_args.TypeAt(i);
|
| + param_bound = param.bound();
|
| + if (!param_bound.IsInstantiated()) {
|
| + param_bound = param_bound.InstantiateFrom(mixin_type_args,
|
| + &bound_error);
|
| + // The instantiator contains only TypeParameter objects and no
|
| + // BoundedType objects, so no bound error may occur.
|
| + ASSERT(bound_error.IsNull());
|
| + ASSERT(!param_bound.IsInstantiated());
|
| + param.set_bound(param_bound);
|
| + }
|
| + }
|
| + }
|
| +
|
| // Lastly, set the type arguments of the mixin type and of the single
|
| // interface type.
|
| ASSERT(!mixin_type.IsFinalized());
|
| @@ -1519,7 +1536,7 @@
|
| // application class. The new class will have the aliased mixin as actual
|
| // mixin.
|
| if (mixin_class.is_mixin_app_alias()) {
|
| - ApplyMixinAppAlias(mixin_app_class);
|
| + ApplyMixinAppAlias(mixin_app_class, has_uninstantiated_bounds);
|
| }
|
| }
|
|
|
| @@ -1575,34 +1592,48 @@
|
| Object&M<Map<U, V>> of A and, therefore, U and V refer to A. An instantiation
|
| step with a properly crafted instantiator vector takes care of the required type
|
| parameter substitution.
|
| -
|
| The instantiator vector must end with the type parameters U and V of S&A.
|
| The offset of the first type parameter U of S&A must be at the finalized index
|
| of type parameter U of A.
|
| +
|
| +The same instantiator vector is used to adjust the type parameter bounds on U
|
| +and V, if any. This step was postponed from CloneMixinAppTypeParameters above.
|
| +
|
| +Also, a possible bound on type parameter T of M (not shown in the example above)
|
| +must be applied to type parameter T of S&A`. If the bound is uninstantiated,
|
| +i.e. if it refers to T or other type parameters of M, an instantiation step is
|
| +required to substitute these type parameters of M with type parameters of S&A`.
|
| +The instantiator vector consists of the cloned type parameters of M without
|
| +offset, since class M must extend Object. This is done in the recursive call to
|
| +CloneMixinAppTypeParameters and does not require specific code in
|
| +ApplyMixinAppAlias.
|
| */
|
| -void ClassFinalizer::ApplyMixinAppAlias(const Class& mixin_app_class) {
|
| +void ClassFinalizer::ApplyMixinAppAlias(const Class& mixin_app_class,
|
| + bool has_uninstantiated_bounds) {
|
| // If this mixin alias is aliasing another mixin alias, another class
|
| // will be inserted via recursion. No need to check here.
|
| // The mixin type may or may not be finalized yet.
|
| - AbstractType& super_type = AbstractType::Handle(mixin_app_class.super_type());
|
| - const Type& mixin_type = Type::Handle(mixin_app_class.mixin());
|
| - const Class& mixin_class = Class::Handle(mixin_type.type_class());
|
| + Isolate* isolate = Isolate::Current();
|
| + AbstractType& super_type = AbstractType::Handle(isolate,
|
| + mixin_app_class.super_type());
|
| + const Type& mixin_type = Type::Handle(isolate, mixin_app_class.mixin());
|
| + const Class& mixin_class = Class::Handle(isolate, mixin_type.type_class());
|
| ASSERT(mixin_class.is_mixin_app_alias());
|
| - const Class& aliased_mixin_app_class = Class::Handle(
|
| + const Class& aliased_mixin_app_class = Class::Handle(isolate,
|
| mixin_class.SuperClass());
|
| - const Type& aliased_mixin_type = Type::Handle(
|
| + const Type& aliased_mixin_type = Type::Handle(isolate,
|
| aliased_mixin_app_class.mixin());
|
| // The name of the inserted mixin application class is the name of mixin
|
| // class name with a backtick added.
|
| - String& inserted_class_name = String::Handle(mixin_app_class.Name());
|
| + String& inserted_class_name = String::Handle(isolate, mixin_app_class.Name());
|
| inserted_class_name = String::Concat(inserted_class_name,
|
| Symbols::Backtick());
|
| - const Library& library = Library::Handle(mixin_app_class.library());
|
| - Class& inserted_class = Class::Handle(
|
| + const Library& library = Library::Handle(isolate, mixin_app_class.library());
|
| + Class& inserted_class = Class::Handle(isolate,
|
| library.LookupLocalClass(inserted_class_name));
|
| if (inserted_class.IsNull()) {
|
| inserted_class_name = Symbols::New(inserted_class_name);
|
| - const Script& script = Script::Handle(mixin_app_class.script());
|
| + const Script& script = Script::Handle(isolate, mixin_app_class.script());
|
| inserted_class = Class::New(
|
| inserted_class_name, script, mixin_app_class.token_pos());
|
| inserted_class.set_is_synthesized_class();
|
| @@ -1626,8 +1657,8 @@
|
| // CloneMixinAppTypeParameters.
|
| // After FinalizeTypesInClass, they will refer to the type parameters of
|
| // the mixin class typedef.
|
| - const Type& generic_mixin_type = Type::Handle(
|
| - Type::New(Class::Handle(aliased_mixin_type.type_class()),
|
| + const Type& generic_mixin_type = Type::Handle(isolate,
|
| + Type::New(Class::Handle(isolate, aliased_mixin_type.type_class()),
|
| Object::null_abstract_type_arguments(),
|
| aliased_mixin_type.token_pos()));
|
| inserted_class.set_mixin(generic_mixin_type);
|
| @@ -1649,7 +1680,7 @@
|
| // It is important that the type parameters of the mixin application class
|
| // are not finalized yet, because new type parameters may have been added
|
| // to the super class.
|
| - Class& super_class = Class::Handle(super_type.type_class());
|
| + Class& super_class = Class::Handle(isolate, super_type.type_class());
|
| ASSERT(mixin_app_class.SuperClass() == super_class.raw());
|
| while (super_class.IsMixinApplication()) {
|
| super_class = super_class.SuperClass();
|
| @@ -1659,16 +1690,16 @@
|
| intptr_t offset =
|
| mixin_class.NumTypeArguments() - mixin_class.NumTypeParameters();
|
| const TypeArguments& type_params =
|
| - TypeArguments::Handle(mixin_app_class.type_parameters());
|
| - TypeArguments& instantiator = TypeArguments::Handle(
|
| + TypeArguments::Handle(isolate, mixin_app_class.type_parameters());
|
| + TypeArguments& instantiator = TypeArguments::Handle(isolate,
|
| TypeArguments::New(offset + num_mixin_type_params));
|
| - AbstractType& type = AbstractType::Handle();
|
| + AbstractType& type = AbstractType::Handle(isolate);
|
| for (intptr_t i = 0; i < num_mixin_type_params; i++) {
|
| type = type_params.TypeAt(num_super_type_params + i);
|
| instantiator.SetTypeAt(offset + i, type);
|
| }
|
| ASSERT(aliased_mixin_type.IsFinalized());
|
| - const Class& aliased_mixin_type_class = Class::Handle(
|
| + const Class& aliased_mixin_type_class = Class::Handle(isolate,
|
| aliased_mixin_type.type_class());
|
| const intptr_t num_aliased_mixin_type_params =
|
| aliased_mixin_type_class.NumTypeParameters();
|
| @@ -1679,9 +1710,9 @@
|
| (num_super_type_params + num_aliased_mixin_type_params));
|
| // The aliased_mixin_type may be raw.
|
| const AbstractTypeArguments& mixin_class_super_type_args =
|
| - AbstractTypeArguments::Handle(
|
| - AbstractType::Handle(mixin_class.super_type()).arguments());
|
| - TypeArguments& new_mixin_type_args = TypeArguments::Handle();
|
| + AbstractTypeArguments::Handle(isolate,
|
| + AbstractType::Handle(isolate, mixin_class.super_type()).arguments());
|
| + TypeArguments& new_mixin_type_args = TypeArguments::Handle(isolate);
|
| if ((num_aliased_mixin_type_params > 0) &&
|
| !mixin_class_super_type_args.IsNull()) {
|
| new_mixin_type_args = TypeArguments::New(num_aliased_mixin_type_params);
|
| @@ -1692,13 +1723,14 @@
|
| }
|
| if (!new_mixin_type_args.IsNull() &&
|
| !new_mixin_type_args.IsInstantiated()) {
|
| - Error& bound_error = Error::Handle();
|
| + Error& bound_error = Error::Handle(isolate);
|
| new_mixin_type_args ^=
|
| new_mixin_type_args.InstantiateFrom(instantiator, &bound_error);
|
| - // TODO(14453): Handle bound error.
|
| + // The instantiator contains only TypeParameter objects and no BoundedType
|
| + // objects, so no bound error may occur.
|
| ASSERT(bound_error.IsNull());
|
| }
|
| - TypeArguments& new_super_type_args = TypeArguments::Handle();
|
| + TypeArguments& new_super_type_args = TypeArguments::Handle(isolate);
|
| if ((num_super_type_params + num_aliased_mixin_type_params) > 0) {
|
| new_super_type_args = TypeArguments::New(num_super_type_params +
|
| num_aliased_mixin_type_params);
|
| @@ -1719,6 +1751,26 @@
|
| new_super_type_args,
|
| mixin_app_class.token_pos());
|
| mixin_app_class.set_super_type(super_type);
|
| +
|
| + // Perform the bound adjustment posponed from CloneMixinAppTypeParameters.
|
| + if (has_uninstantiated_bounds) {
|
| + TypeParameter& param = TypeParameter::Handle(isolate);
|
| + AbstractType& param_bound = AbstractType::Handle(isolate);
|
| + Error& bound_error = Error::Handle(isolate);
|
| + for (intptr_t i = 0; i < num_mixin_type_params; i++) {
|
| + param ^= type_params.TypeAt(num_super_type_params + i);
|
| + param_bound = param.bound();
|
| + if (!param_bound.IsInstantiated()) {
|
| + param_bound = param_bound.InstantiateFrom(instantiator, &bound_error);
|
| + // The instantiator contains only TypeParameter objects and no
|
| + // BoundedType objects, so no bound error may occur.
|
| + ASSERT(bound_error.IsNull());
|
| + ASSERT(!param_bound.IsInstantiated());
|
| + param.set_bound(param_bound);
|
| + }
|
| + }
|
| + }
|
| +
|
| // Mark this mixin application class as being an alias.
|
| mixin_app_class.set_is_mixin_app_alias();
|
| ASSERT(!mixin_app_class.is_type_finalized());
|
| @@ -1728,7 +1780,7 @@
|
| "with super type '%s'\n",
|
| inserted_class.ToCString(),
|
| mixin_app_class.ToCString(),
|
| - String::Handle(super_type.Name()).ToCString());
|
| + String::Handle(isolate, super_type.Name()).ToCString());
|
| }
|
| }
|
|
|
| @@ -1806,7 +1858,10 @@
|
| ASSERT(!mixin_type.IsBeingFinalized());
|
| mixin_type ^=
|
| FinalizeType(mixin_app_class, mixin_type, kFinalize, pending_types);
|
| - // TODO(14453): Check for a malbounded mixin_type.
|
| + // The mixin type cannot be malbounded, since it merely substitutes the
|
| + // type parameters of the mixin class with those of the mixin application
|
| + // class, but it does not instantiate them.
|
| + ASSERT(!mixin_type.IsMalbounded());
|
| mixin_app_class.set_mixin(mixin_type);
|
| }
|
|
|
| @@ -1876,7 +1931,8 @@
|
| ASSERT(!mixin_type.IsNull());
|
| ASSERT(mixin_type.HasResolvedTypeClass());
|
| const Class& mixin_cls = Class::Handle(isolate, mixin_type.type_class());
|
| - mixin_cls.EnsureIsFinalized(isolate);
|
| + const Error& error = Error::Handle(mixin_cls.EnsureIsFinalized(isolate));
|
| + ASSERT(error.IsNull());
|
| // If the mixin is a mixin application alias class, there are no members to
|
| // apply here. A new synthesized class representing the aliased mixin
|
| // application class was inserted in the super chain of this mixin application
|
| @@ -1982,7 +2038,8 @@
|
| AbstractType& super_type = AbstractType::Handle(cls.super_type());
|
| if (!super_type.IsNull()) {
|
| // In case of a bound error in the super type in production mode, the
|
| - // finalized super type will be a BoundedType with a malformed bound.
|
| + // finalized super type will have a BoundedType as type argument for the
|
| + // out of bound type argument.
|
| // It should not be a problem if the class is written to a snapshot and
|
| // later executed in checked mode. Note that the finalized type argument
|
| // vector of any type of the base class will contain a BoundedType for the
|
| @@ -2315,9 +2372,9 @@
|
| AbstractType& mixin_super_type =
|
| AbstractType::Handle(mixin_app_type.super_type());
|
| ResolveType(cls, mixin_super_type);
|
| - ASSERT(mixin_super_type.HasResolvedTypeClass());
|
| - // TODO(14453): May need to handle BoundedType here.
|
| - ASSERT(mixin_super_type.IsType());
|
| + ASSERT(mixin_super_type.HasResolvedTypeClass()); // Even if malformed.
|
| + // The super type may have a BoundedType as type argument, but cannot be
|
| + // a BoundedType itself.
|
| CollectTypeArguments(cls, Type::Cast(mixin_super_type), type_args);
|
| AbstractType& mixin_type = AbstractType::Handle();
|
| Type& generic_mixin_type = Type::Handle();
|
| @@ -2330,7 +2387,7 @@
|
| mixin_type = mixin_app_type.MixinTypeAt(i);
|
| ASSERT(!mixin_type.IsNull());
|
| ResolveType(cls, mixin_type);
|
| - ASSERT(mixin_type.HasResolvedTypeClass());
|
| + ASSERT(mixin_type.HasResolvedTypeClass()); // Even if malformed.
|
| ASSERT(mixin_type.IsType());
|
| CollectTypeArguments(cls, Type::Cast(mixin_type), type_args);
|
|
|
|
|