| Index: runtime/vm/class_finalizer.cc
|
| diff --git a/runtime/vm/class_finalizer.cc b/runtime/vm/class_finalizer.cc
|
| index 4af663639458e768d06615a0294f9662ee7ee2f3..75b832b970c73ee2c6fbadd69f451ef81d7e8d05 100644
|
| --- a/runtime/vm/class_finalizer.cc
|
| +++ b/runtime/vm/class_finalizer.cc
|
| @@ -18,6 +18,7 @@ namespace dart {
|
| DEFINE_FLAG(bool, print_classes, false, "Prints details about loaded classes.");
|
| DEFINE_FLAG(bool, trace_class_finalization, false, "Trace class finalization.");
|
| DEFINE_FLAG(bool, trace_type_finalization, false, "Trace type finalization.");
|
| +DECLARE_FLAG(bool, supermixin);
|
| DECLARE_FLAG(bool, use_cha_deopt);
|
|
|
|
|
| @@ -1561,14 +1562,16 @@ void ClassFinalizer::ResolveAndFinalizeMemberTypes(const Class& cls) {
|
| // In other words, decorate this mixin application class with type parameters
|
| // that forward to the super type and mixin type (and interface type).
|
| // Example:
|
| -// class S<T> { }
|
| -// class M<T> { }
|
| -// class C<E> extends S<E> with M<List<E>> { }
|
| +// class S<T extends BT> { }
|
| +// class M<T extends BT> { }
|
| +// class C<E extends BE> extends S<E> with M<List<E>> { }
|
| // results in
|
| -// class S&M<T`, T> extends S<T`> implements M<T> { } // mixin == M<T>
|
| -// class C<E> extends S&M<E, List<E>> { }
|
| +// class S&M<T`, T extends BT> extends S<T`> implements M<T> { }
|
| +// class C<E extends BE> extends S&M<E, List<E>> { }
|
| // CloneMixinAppTypeParameters decorates class S&M with type parameters T` and
|
| // T, and use them as type arguments in S<T`> and M<T>.
|
| +// Note that the bound BT on T of S is not applied to T` of S&M. However, the
|
| +// bound BT on T of M is applied to T of S&M. See comments below.
|
| void ClassFinalizer::CloneMixinAppTypeParameters(const Class& mixin_app_class) {
|
| ASSERT(mixin_app_class.type_parameters() == TypeArguments::null());
|
| Isolate* isolate = Isolate::Current();
|
| @@ -1580,8 +1583,6 @@ void ClassFinalizer::CloneMixinAppTypeParameters(const Class& mixin_app_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());
|
|
|
| // The mixin type (in raw form) should have been added to the interfaces
|
| // implemented by the mixin application class. This is necessary so that cycle
|
| @@ -1593,7 +1594,7 @@ void ClassFinalizer::CloneMixinAppTypeParameters(const Class& mixin_app_class) {
|
| // 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;
|
| + TypeArguments& instantiator = TypeArguments::Handle(isolate);
|
| if ((num_super_type_params + num_mixin_type_params) > 0) {
|
| // If the last ampersand in the name of the mixin application class is
|
| // doubled, the same type parameters can propagate the type arguments to
|
| @@ -1630,7 +1631,12 @@ void ClassFinalizer::CloneMixinAppTypeParameters(const Class& mixin_app_class) {
|
| 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.
|
| + // level. As a consequence, if this mixin application is used itself as a
|
| + // mixin in another mixin application, the bounds will be ignored, which
|
| + // is correct, because the other mixin application does not inherit from
|
| + // the super class of its mixin. Note also that the other mixin
|
| + // application will only mixin the last mixin type listed in the first
|
| + // mixin application it is mixing in.
|
| param_bound = isolate->object_store()->object_type();
|
| for (intptr_t i = 0; i < num_super_type_params; i++) {
|
| param ^= super_type_params.TypeAt(i);
|
| @@ -1658,12 +1664,16 @@ void ClassFinalizer::CloneMixinAppTypeParameters(const Class& mixin_app_class) {
|
| // We need to retain the parameter names of the mixin class
|
| // since the code that will be compiled in the context of the
|
| // mixin application class may refer to the type parameters
|
| - // with that name.
|
| + // with that name. We also retain the type parameter bounds.
|
| if (num_mixin_type_params > 0) {
|
| const TypeArguments& mixin_params =
|
| TypeArguments::Handle(isolate, mixin_class.type_parameters());
|
| + const intptr_t offset =
|
| + mixin_class.NumTypeArguments() - mixin_class.NumTypeParameters();
|
| const TypeArguments& mixin_type_args = TypeArguments::Handle(isolate,
|
| TypeArguments::New(num_mixin_type_params));
|
| + instantiator ^= TypeArguments::New(offset + num_mixin_type_params);
|
| + bool has_uninstantiated_bounds = false;
|
| for (intptr_t i = 0; i < num_mixin_type_params; i++) {
|
| param ^= mixin_params.TypeAt(i);
|
| param_name = param.name();
|
| @@ -1672,27 +1682,26 @@ void ClassFinalizer::CloneMixinAppTypeParameters(const Class& mixin_app_class) {
|
| has_uninstantiated_bounds = true;
|
| }
|
| cloned_param = TypeParameter::New(mixin_app_class,
|
| - cloned_index,
|
| + cloned_index, // Unfinalized index.
|
| param_name,
|
| param_bound,
|
| param.token_pos());
|
| cloned_type_params.SetTypeAt(cloned_index, cloned_param);
|
| - mixin_type_args.SetTypeAt(i, cloned_param);
|
| + mixin_type_args.SetTypeAt(i, cloned_param); // Unfinalized length.
|
| + instantiator.SetTypeAt(offset + i, cloned_param); // Finalized length.
|
| 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.
|
| + // done by instantiating each bound using the instantiator built above.
|
| + // If the mixin class extends a generic super class, its first finalized
|
| + // type parameter has a non-zero index, therefore, the instantiator
|
| + // requires shifting by the offset calculated above.
|
| // 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()) {
|
| + if (has_uninstantiated_bounds) {
|
| Error& bound_error = Error::Handle(isolate);
|
| for (intptr_t i = 0; i < num_mixin_type_params; i++) {
|
| param ^= mixin_type_args.TypeAt(i);
|
| @@ -1705,10 +1714,11 @@ void ClassFinalizer::CloneMixinAppTypeParameters(const Class& mixin_app_class) {
|
| FinalizeType(mixin_app_class, param_bound, kCanonicalize);
|
| param.set_bound(param_bound); // In case part of recursive type.
|
| }
|
| - param_bound = param_bound.InstantiateFrom(mixin_type_args,
|
| + 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(!param_bound.IsBoundedType());
|
| ASSERT(bound_error.IsNull());
|
| ASSERT(!param_bound.IsInstantiated());
|
| param.set_bound(param_bound);
|
| @@ -1732,7 +1742,7 @@ void ClassFinalizer::CloneMixinAppTypeParameters(const Class& mixin_app_class) {
|
| // application class. The new class will have the aliased mixin as actual
|
| // mixin.
|
| if (mixin_class.is_mixin_app_alias()) {
|
| - ApplyMixinAppAlias(mixin_app_class, has_uninstantiated_bounds);
|
| + ApplyMixinAppAlias(mixin_app_class, instantiator);
|
| }
|
| }
|
|
|
| @@ -1742,19 +1752,23 @@ Consider the following example:
|
|
|
| class I<T> { }
|
| class J<T> { }
|
| -class S<T> { }
|
| -class M<T> { }
|
| -class A<U, V> = Object with M<Map<U, V>> implements I<V>;
|
| -class C<T, K> = S<T> with A<T, List<K>> implements J<K>;
|
| +class S<T extends num> { }
|
| +class M<T extends Map> { }
|
| +class A<U, V extends List> = Object with M<Map<U, V>> implements I<V>;
|
| +class C<T, K extends T> = S<T> with A<T, List<K>> implements J<K>;
|
|
|
| Before the call to ApplyMixinAppAlias, the VM has already synthesized 2 mixin
|
| application classes Object&M and S&A:
|
|
|
| -Object&M<T> extends Object implements M<T> { ... members of M applied here ... }
|
| -A<U, V> extends Object&M<Map<U, V>> implements I<V> { }
|
| +Object&M<T extends Map> extends Object implements M<T> {
|
| + ... members of M applied here ...
|
| +}
|
| +A<U, V extends List> extends Object&M<Map<U, V>> implements I<V> { }
|
|
|
| -S&A<T`, U, V> extends S<T`> implements A<U, V> { }
|
| -C<T, K> extends S&A<T, T, List<K>> implements J<K> { }
|
| +S&A<T`, U, V extends List> extends S<T`> implements A<U, V> {
|
| + ... members of A applied here, but A has no members ...
|
| +}
|
| +C<T, K extends T> extends S&A<T, T, List<K>> implements J<K> { }
|
|
|
| In theory, class A should be an alias of Object&M instead of extending it.
|
| In practice, the additional class provides a hook for implemented interfaces
|
| @@ -1764,9 +1778,6 @@ type parameters of the alias A).
|
|
|
| Similarly, class C should be an alias of S&A instead of extending it.
|
|
|
| -Since A is used as a mixin, it must extend Object. The fact that it extends
|
| -Object&M must be hidden so that no error is wrongly reported.
|
| -
|
| Now, A does not have any members to be mixed into S&A, because A is an alias.
|
| The members to be mixed in are actually those of M, and they should appear in a
|
| scope where the type parameter T is visible. The class S&A declares the type
|
| @@ -1776,11 +1787,13 @@ Therefore, the call to ApplyMixinAppAlias inserts another synthesized class S&A`
|
| as the superclass of S&A. The class S&A` declares a type argument T:
|
|
|
| Instead of
|
| -S&A<T`, U, V> extends S<T`> implements A<U, V> { }
|
| +S&A<T`, U, V extends List> extends S<T`> implements A<U, V> { }
|
|
|
| We now have:
|
| -S&A`<T`, T> extends S<T`> implements M<T> { ... members of M applied here ... }
|
| -S&A<T`, U, V> extends S&A`<T`, Map<U, V>> implements A<U, V> { }
|
| +S&A`<T`, T extends Map> extends S<T`> implements M<T> {
|
| + ... members of M applied here ...
|
| +}
|
| +S&A<T`, U, V extends List> extends S&A`<T`, Map<U, V>> implements A<U, V> { }
|
|
|
| The main implementation difficulty resides in the fact that the type parameters
|
| U and V in the super type S&A`<T`, Map<U, V>> of S&A must refer to the type
|
| @@ -1789,23 +1802,24 @@ 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 offset in the instantiator of the 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.
|
| +and V, if any. This step is done in CloneMixinAppTypeParameters above, and the
|
| +already built instantiator is passed here.
|
| +
|
| +Also, a possible bound on type parameter T of M 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 shifted by
|
| +an offset corresponding to the finalized index of the first type parameter of M.
|
| +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,
|
| - bool has_uninstantiated_bounds) {
|
| + const TypeArguments& instantiator) {
|
| // 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.
|
| @@ -1817,6 +1831,12 @@ void ClassFinalizer::ApplyMixinAppAlias(const Class& mixin_app_class,
|
| ASSERT(mixin_class.is_mixin_app_alias());
|
| const Class& aliased_mixin_app_class = Class::Handle(isolate,
|
| mixin_class.SuperClass());
|
| + // Note that the super class of aliased_mixin_app_class can itself be a
|
| + // mixin application class (this happens if the alias is mixing more than one
|
| + // type). Instead of trying to recursively insert yet another class as the
|
| + // super class of this inserted class, we apply the composition rules of the
|
| + // spec and only mixin the members of aliased_mixin_app_class, not those of
|
| + // its super class. In other words, we only mixin the last mixin of the alias.
|
| 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
|
| @@ -1851,18 +1871,19 @@ void ClassFinalizer::ApplyMixinAppAlias(const Class& mixin_app_class,
|
|
|
| // The mixin type and interface type must also be set before calling
|
| // CloneMixinAppTypeParameters.
|
| - // After FinalizeTypesInClass, they will refer to the type parameters of
|
| - // the mixin class typedef.
|
| - const Type& generic_mixin_type = Type::Handle(isolate,
|
| + // After FinalizeTypesInClass, if the mixin type and interface type are
|
| + // generic, their type arguments will refer to the type parameters of
|
| + // inserted_class.
|
| + const Type& inserted_class_mixin_type = Type::Handle(isolate,
|
| Type::New(Class::Handle(isolate, aliased_mixin_type.type_class()),
|
| Object::null_type_arguments(),
|
| aliased_mixin_type.token_pos()));
|
| - inserted_class.set_mixin(generic_mixin_type);
|
| + inserted_class.set_mixin(inserted_class_mixin_type);
|
| // Add the mixin type to the list of interfaces that the mixin application
|
| // class implements. This is necessary so that cycle check work at
|
| // compile time (type arguments are ignored by that check).
|
| const Array& interfaces = Array::Handle(Array::New(1));
|
| - interfaces.SetAt(0, generic_mixin_type);
|
| + interfaces.SetAt(0, inserted_class_mixin_type);
|
| ASSERT(inserted_class.interfaces() == Object::empty_array().raw());
|
| inserted_class.set_interfaces(interfaces);
|
| // The type arguments of the interface, if any, will be set in
|
| @@ -1885,60 +1906,68 @@ void ClassFinalizer::ApplyMixinAppAlias(const Class& mixin_app_class,
|
| // 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(isolate, super_type.type_class());
|
| - ASSERT(mixin_app_class.SuperClass() == super_class.raw());
|
| - while (super_class.IsMixinApplication()) {
|
| - super_class = super_class.SuperClass();
|
| - }
|
| + const Class& super_class = Class::Handle(isolate, super_type.type_class());
|
| + ASSERT(mixin_app_class.SuperClass() == super_class.raw()); // Will change.
|
| const intptr_t num_super_type_params = super_class.NumTypeParameters();
|
| - const intptr_t num_mixin_type_params = mixin_class.NumTypeParameters();
|
| - intptr_t offset =
|
| - mixin_class.NumTypeArguments() - mixin_class.NumTypeParameters();
|
| - const TypeArguments& type_params =
|
| - TypeArguments::Handle(isolate, mixin_app_class.type_parameters());
|
| - TypeArguments& instantiator = TypeArguments::Handle(isolate,
|
| - TypeArguments::New(offset + num_mixin_type_params));
|
| 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);
|
| - }
|
| + // The instantiator is mapping finalized type parameters of mixin_class to
|
| + // unfinalized type parameters of mixin_app_class.
|
| ASSERT(aliased_mixin_type.IsFinalized());
|
| 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();
|
| - const intptr_t num_aliased_mixin_type_args =
|
| - aliased_mixin_type_class.NumTypeArguments();
|
| - offset = num_aliased_mixin_type_args - num_aliased_mixin_type_params;
|
| ASSERT(inserted_class.NumTypeParameters() ==
|
| (num_super_type_params + num_aliased_mixin_type_params));
|
| + const AbstractType& mixin_class_super_type =
|
| + AbstractType::Handle(isolate, mixin_class.super_type());
|
| + ASSERT(mixin_class_super_type.IsFinalized());
|
| // The aliased_mixin_type may be raw.
|
| const TypeArguments& mixin_class_super_type_args =
|
| - TypeArguments::Handle(isolate,
|
| - AbstractType::Handle(isolate, mixin_class.super_type()).arguments());
|
| + TypeArguments::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);
|
| + AbstractType& bounded_type = AbstractType::Handle(isolate);
|
| + AbstractType& upper_bound = AbstractType::Handle(isolate);
|
| + TypeParameter& type_parameter = TypeParameter::Handle(isolate);
|
| + Error& bound_error = Error::Handle(isolate);
|
| + const intptr_t offset =
|
| + mixin_class_super_type_args.Length() - num_aliased_mixin_type_params;
|
| for (intptr_t i = 0; i < num_aliased_mixin_type_params; i++) {
|
| type = mixin_class_super_type_args.TypeAt(offset + i);
|
| + if (!type.IsInstantiated()) {
|
| + // In the presence of bounds, the bounded type and the upper bound must
|
| + // be instantiated separately. Instantiating a BoundedType would wrap
|
| + // the BoundedType in another BoundedType.
|
| + if (type.IsBoundedType()) {
|
| + bounded_type = BoundedType::Cast(type).type();
|
| + bounded_type = bounded_type.InstantiateFrom(instantiator,
|
| + &bound_error);
|
| + // The instantiator contains only TypeParameter objects and no
|
| + // BoundedType objects, so no bound error may occur.
|
| + ASSERT(bound_error.IsNull());
|
| + upper_bound = BoundedType::Cast(type).bound();
|
| + upper_bound = upper_bound.InstantiateFrom(instantiator, &bound_error);
|
| + ASSERT(bound_error.IsNull());
|
| + type_parameter = BoundedType::Cast(type).type_parameter();
|
| + // The type parameter that declared the bound does not change.
|
| + type = BoundedType::New(bounded_type, upper_bound, type_parameter);
|
| + } else {
|
| + type = type.InstantiateFrom(instantiator, &bound_error);
|
| + ASSERT(bound_error.IsNull());
|
| + }
|
| + }
|
| new_mixin_type_args.SetTypeAt(i, type);
|
| }
|
| }
|
| - if (!new_mixin_type_args.IsNull() &&
|
| - !new_mixin_type_args.IsInstantiated()) {
|
| - Error& bound_error = Error::Handle(isolate);
|
| - new_mixin_type_args ^=
|
| - new_mixin_type_args.InstantiateFrom(instantiator, &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(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);
|
| + const TypeArguments& type_params =
|
| + TypeArguments::Handle(isolate, mixin_app_class.type_parameters());
|
| for (intptr_t i = 0; i < num_super_type_params; i++) {
|
| type = type_params.TypeAt(i);
|
| new_super_type_args.SetTypeAt(i, type);
|
| @@ -1957,35 +1986,23 @@ void ClassFinalizer::ApplyMixinAppAlias(const Class& mixin_app_class,
|
| 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());
|
| ASSERT(!mixin_app_class.is_mixin_type_applied());
|
| if (FLAG_trace_class_finalization) {
|
| - OS::Print("Inserting class %s to mixin application alias %s "
|
| - "with super type '%s'\n",
|
| - inserted_class.ToCString(),
|
| - mixin_app_class.ToCString(),
|
| - String::Handle(isolate, super_type.Name()).ToCString());
|
| + OS::Print("Inserting class '%s' %s\n"
|
| + " as super type '%s' with %" Pd " type args: %s\n"
|
| + " of mixin application alias '%s' %s\n",
|
| + String::Handle(inserted_class.Name()).ToCString(),
|
| + TypeArguments::Handle(
|
| + inserted_class.type_parameters()).ToCString(),
|
| + String::Handle(isolate, super_type.Name()).ToCString(),
|
| + num_super_type_params + num_aliased_mixin_type_params,
|
| + super_type.ToCString(),
|
| + String::Handle(mixin_app_class.Name()).ToCString(),
|
| + TypeArguments::Handle(
|
| + mixin_app_class.type_parameters()).ToCString());
|
| }
|
| }
|
|
|
| @@ -2007,8 +2024,7 @@ void ClassFinalizer::ApplyMixinType(const Class& mixin_app_class,
|
| mixin_app_class.token_pos());
|
| }
|
|
|
| - // Check for illegal self references. This has to be done before checking
|
| - // that the super class of the mixin class is class Object.
|
| + // Check for illegal self references.
|
| GrowableArray<intptr_t> visited_mixins;
|
| if (!IsMixinCycleFree(mixin_class, &visited_mixins)) {
|
| const String& class_name = String::Handle(mixin_class.Name());
|
| @@ -2017,21 +2033,23 @@ void ClassFinalizer::ApplyMixinType(const Class& mixin_app_class,
|
| class_name.ToCString());
|
| }
|
|
|
| - // Check that the super class of the mixin class is class Object.
|
| - Class& mixin_super_class = Class::Handle(mixin_class.SuperClass());
|
| - // Skip over mixin application alias classes, which are implemented as
|
| - // subclasses of the mixin application classes they name.
|
| - if (!mixin_super_class.IsNull() && mixin_class.is_mixin_app_alias()) {
|
| - while (mixin_super_class.is_mixin_app_alias()) {
|
| + if (!FLAG_supermixin) {
|
| + // Check that the super class of the mixin class is class Object.
|
| + Class& mixin_super_class = Class::Handle(mixin_class.SuperClass());
|
| + // Skip over mixin application alias classes, which are implemented as
|
| + // subclasses of the mixin application classes they name.
|
| + if (!mixin_super_class.IsNull() && mixin_class.is_mixin_app_alias()) {
|
| + while (mixin_super_class.is_mixin_app_alias()) {
|
| + mixin_super_class = mixin_super_class.SuperClass();
|
| + }
|
| mixin_super_class = mixin_super_class.SuperClass();
|
| }
|
| - mixin_super_class = mixin_super_class.SuperClass();
|
| - }
|
| - if (mixin_super_class.IsNull() || !mixin_super_class.IsObjectClass()) {
|
| - const String& class_name = String::Handle(mixin_class.Name());
|
| - ReportError(mixin_app_class, mixin_app_class.token_pos(),
|
| - "mixin class '%s' must extend class 'Object'",
|
| - class_name.ToCString());
|
| + if (mixin_super_class.IsNull() || !mixin_super_class.IsObjectClass()) {
|
| + const String& class_name = String::Handle(mixin_class.Name());
|
| + ReportError(mixin_app_class, mixin_app_class.token_pos(),
|
| + "mixin class '%s' must extend class 'Object'",
|
| + class_name.ToCString());
|
| + }
|
| }
|
|
|
| // Copy type parameters to mixin application class.
|
| @@ -2297,6 +2315,7 @@ void ClassFinalizer::FinalizeTypesInClass(const Class& cls) {
|
| // Check whether the interface is duplicated. We need to wait with
|
| // this check until the super type and interface types are finalized,
|
| // so that we can use Type::Equals() for the test.
|
| + // TODO(regis): This restriction about duplicated interfaces may get lifted.
|
| ASSERT(interface_type.IsFinalized());
|
| ASSERT(super_type.IsNull() || super_type.IsFinalized());
|
| if (!super_type.IsNull() && interface_type.Equals(super_type)) {
|
| @@ -2643,7 +2662,6 @@ RawType* ClassFinalizer::ResolveMixinAppType(
|
| // a BoundedType itself.
|
| CollectTypeArguments(cls, Type::Cast(mixin_super_type), type_args);
|
| AbstractType& mixin_type = AbstractType::Handle(isolate);
|
| - Type& generic_mixin_type = Type::Handle(isolate);
|
| Class& mixin_type_class = Class::Handle(isolate);
|
| Class& mixin_app_class = Class::Handle(isolate);
|
| String& mixin_app_class_name = String::Handle(isolate);
|
| @@ -2704,9 +2722,10 @@ RawType* ClassFinalizer::ResolveMixinAppType(
|
| mixin_type.token_pos());
|
| mixin_app_class.set_super_type(mixin_super_type);
|
| mixin_type_class = mixin_type.type_class();
|
| - generic_mixin_type = Type::New(mixin_type_class,
|
| - Object::null_type_arguments(),
|
| - mixin_type.token_pos());
|
| + const Type& generic_mixin_type = Type::Handle(isolate,
|
| + Type::New(mixin_type_class,
|
| + Object::null_type_arguments(),
|
| + mixin_type.token_pos()));
|
| mixin_app_class.set_mixin(generic_mixin_type);
|
| // Add the mixin type to the list of interfaces that the mixin application
|
| // class implements. This is necessary so that cycle check work at
|
|
|