Index: runtime/vm/class_finalizer.cc |
=================================================================== |
--- runtime/vm/class_finalizer.cc (revision 20082) |
+++ runtime/vm/class_finalizer.cc (working copy) |
@@ -1184,6 +1184,104 @@ |
} |
+// Copy the type parameters of the super and mixin classes to the |
+// mixin application class. Change type arguments of super type to |
+// refer to the respective type parameters of the mixin application |
+// class. |
+void ClassFinalizer::CloneTypeParameters(const Class& mixapp_class) { |
+ ASSERT(mixapp_class.NumTypeParameters() == 0); |
+ |
+ const AbstractType& super_type = |
+ AbstractType::Handle(mixapp_class.super_type()); |
+ ASSERT(super_type.IsResolved()); |
+ const Class& super_class = Class::Handle(super_type.type_class()); |
+ const Type& mixin_type = Type::Handle(mixapp_class.mixin()); |
+ const Class& mixin_class = Class::Handle(mixin_type.type_class()); |
+ const int num_super_parameters = super_class.NumTypeParameters(); |
+ const int num_mixin_parameters = mixin_class.NumTypeParameters(); |
+ if ((num_super_parameters + num_mixin_parameters) == 0) { |
+ return; |
+ } |
+ |
+ // 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( |
+ TypeArguments::New(num_super_parameters + num_mixin_parameters)); |
+ TypeParameter& param = TypeParameter::Handle(); |
+ TypeParameter& cloned_param = TypeParameter::Handle(); |
+ String& param_name = String::Handle(); |
+ AbstractType& param_bound = AbstractType::Handle(); |
+ int cloned_index = 0; |
+ if (num_super_parameters > 0) { |
+ const TypeArguments& super_params = |
+ TypeArguments::Handle(super_class.type_parameters()); |
+ const TypeArguments& super_type_args = |
+ TypeArguments::Handle(TypeArguments::New(num_super_parameters)); |
+ for (int i = 0; i < num_super_parameters; i++) { |
+ param ^= super_params.TypeAt(i); |
+ param_name = param.name(); |
+ param_bound = param.bound(); |
+ // TODO(hausner): handle type bounds. |
+ if (!param_bound.IsObjectType()) { |
+ const Script& script = Script::Handle(mixapp_class.script()); |
+ ReportError(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(mixapp_class, |
+ cloned_index, |
+ param_name, |
+ param_bound, |
+ param.token_pos()); |
+ cloned_type_params.SetTypeAt(cloned_index, cloned_param); |
+ // Change the type arguments of the super type to refer to the |
+ // cloned type parameters of the mixin application class. |
+ super_type_args.SetTypeAt(cloned_index, cloned_param); |
+ cloned_index++; |
+ } |
+ // TODO(hausner): May need to handle BoundedType here. |
+ ASSERT(super_type.IsType()); |
+ Type::Cast(super_type).set_arguments(super_type_args); |
+ } |
+ |
+ // Second, clone the type parameters of the mixin 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. |
+ if (num_mixin_parameters > 0) { |
+ const TypeArguments& mixin_params = |
+ TypeArguments::Handle(mixin_class.type_parameters()); |
+ for (int i = 0; i < num_mixin_parameters; i++) { |
+ param ^= mixin_params.TypeAt(i); |
+ param_name = param.name(); |
+ param_bound = param.bound(); |
+ |
+ // TODO(hausner): handle type bounds. |
+ if (!param_bound.IsObjectType()) { |
+ const Script& script = Script::Handle(mixapp_class.script()); |
+ ReportError(script, param.token_pos(), |
+ "type parameter '%s': type bounds not yet" |
+ " implemented for mixins\n", |
+ param_name.ToCString()); |
+ } |
+ cloned_param = TypeParameter::New(mixapp_class, |
+ cloned_index, |
+ param_name, |
+ param_bound, |
+ param.token_pos()); |
+ cloned_type_params.SetTypeAt(cloned_index, cloned_param); |
+ cloned_index++; |
+ } |
+ } |
+ mixapp_class.set_type_parameters(cloned_type_params); |
+} |
+ |
+ |
void ClassFinalizer::ApplyMixin(const Class& cls) { |
const Type& mixin_type = Type::Handle(cls.mixin()); |
ASSERT(!mixin_type.IsNull()); |
@@ -1191,9 +1289,10 @@ |
const Class& mixin_cls = Class::Handle(mixin_type.type_class()); |
if (FLAG_trace_class_finalization) { |
- OS::Print("Applying mixin '%s' to '%s'\n", |
+ OS::Print("Applying mixin '%s' to '%s' at pos %"Pd"\n", |
String::Handle(mixin_cls.Name()).ToCString(), |
- cls.ToCString()); |
+ cls.ToCString(), |
+ cls.token_pos()); |
} |
// Check that the super class of the mixin class is extending |
@@ -1208,30 +1307,8 @@ |
class_name.ToCString()); |
} |
- // Copy the type parameters of the mixin class to the mixin |
- // application class. |
- const int num_type_parameters = mixin_cls.NumTypeParameters(); |
- if (num_type_parameters > 0) { |
- ASSERT(cls.NumTypeParameters() == 0); |
- const TypeArguments& type_params = |
- TypeArguments::Handle(mixin_cls.type_parameters()); |
- const TypeArguments& cloned_type_params = |
- TypeArguments::Handle(TypeArguments::New(num_type_parameters)); |
- ASSERT(!type_params.IsNull()); |
- TypeParameter& param = TypeParameter::Handle(); |
- TypeParameter& cloned_param = TypeParameter::Handle(); |
- String& param_name = String::Handle(); |
- AbstractType& param_bound = AbstractType::Handle(); |
- for (int i = 0; i < num_type_parameters; i++) { |
- param ^= type_params.TypeAt(i); |
- param_name = param.name(); |
- param_bound = param.bound(); |
- cloned_param = TypeParameter::New( |
- cls, i, param_name, param_bound, param.token_pos()); |
- cloned_type_params.SetTypeAt(i, cloned_param); |
- } |
- cls.set_type_parameters(cloned_type_params); |
- } |
+ // Copy type parameters to mixin application class. |
+ CloneTypeParameters(cls); |
const GrowableObjectArray& cloned_funcs = |
GrowableObjectArray::Handle(GrowableObjectArray::New()); |
@@ -1284,6 +1361,13 @@ |
} |
fields = Array::MakeArray(cloned_fields); |
cls.SetFields(fields); |
+ |
+ if (FLAG_trace_class_finalization) { |
+ OS::Print("done mixin appl %s %s extending %s\n", |
+ String::Handle(cls.Name()).ToCString(), |
+ TypeArguments::Handle(cls.type_parameters()).ToCString(), |
+ AbstractType::Handle(cls.super_type()).ToCString()); |
+ } |
} |
@@ -1451,6 +1535,86 @@ |
} |
+void ClassFinalizer::CollectTypeArguments(const Class& cls, |
+ const Type& type, |
+ const GrowableObjectArray& collected_args) { |
+ ASSERT(type.HasResolvedTypeClass()); |
+ Class& type_class = Class::Handle(type.type_class()); |
+ AbstractTypeArguments& type_args = |
+ AbstractTypeArguments::Handle(type.arguments()); |
+ intptr_t num_type_parameters = type_class.NumTypeParameters(); |
+ intptr_t num_type_arguments = type_args.IsNull() ? 0 : type_args.Length(); |
+ AbstractType& arg = AbstractType::Handle(); |
+ if (num_type_arguments > 0) { |
+ if (num_type_arguments != num_type_parameters) { |
+ const Script& script = Script::Handle(cls.script()); |
+ const String& type_class_name = String::Handle(type_class.Name()); |
+ ReportError(script, type.token_pos(), |
+ "wrong number of type arguments for class '%s'", |
+ type_class_name.ToCString()); |
+ } |
+ for (int i = 0; i < num_type_arguments; i++) { |
+ arg = type_args.TypeAt(i); |
+ collected_args.Add(arg); |
+ } |
+ } else { |
+ // Fill arguments with type dynamic. |
+ for (int i = 0; i < num_type_parameters; i++) { |
+ arg = Type::DynamicType(); |
+ collected_args.Add(arg); |
+ } |
+ } |
+} |
+ |
+ |
+RawType* ClassFinalizer::ResolveMixinAppType(const Class& cls, |
+ const MixinAppType& mixin_app) { |
+ // Resolve super type and all mixin types. |
+ const GrowableObjectArray& type_args = |
+ GrowableObjectArray::Handle(GrowableObjectArray::New()); |
+ AbstractType& type = AbstractType::Handle(mixin_app.super_type()); |
+ ResolveType(cls, type, kCanonicalizeWellFormed); |
+ ASSERT(type.HasResolvedTypeClass()); |
+ // TODO(hausner): May need to handle BoundedType here. |
+ ASSERT(type.IsType()); |
+ CollectTypeArguments(cls, Type::Cast(type), type_args); |
+ const Array& mixins = Array::Handle(mixin_app.mixin_types()); |
+ for (int i = 0; i < mixins.Length(); i++) { |
+ type ^= mixins.At(i); |
+ ASSERT(type.HasResolvedTypeClass()); // Newly created class in parser. |
+ const Class& mixin_app_class = Class::Handle(type.type_class()); |
+ type = mixin_app_class.mixin(); |
+ ASSERT(!type.IsNull()); |
+ ResolveType(cls, type, kCanonicalizeWellFormed); |
+ ASSERT(type.HasResolvedTypeClass()); |
+ ASSERT(type.IsType()); |
+ CollectTypeArguments(cls, Type::Cast(type), type_args); |
+ } |
+ const TypeArguments& mixin_app_args = |
+ TypeArguments::Handle(TypeArguments::New(type_args.Length())); |
+ for (int i = 0; i < type_args.Length(); i++) { |
+ type ^= type_args.At(i); |
+ mixin_app_args.SetTypeAt(i, type); |
+ } |
+ if (FLAG_trace_class_finalization) { |
+ OS::Print("ResolveMixinAppType: mixin appl type args: %s\n", |
+ mixin_app_args.ToCString()); |
+ } |
+ // The last element in the mixins array is the lowest mixin application |
+ // type in the mixin chain. Build a new super type with its type class |
+ // and the collected type arguments from the super type and all |
+ // mixin types. This super type replaces the MixinAppType object |
+ // in the class that extends the mixin application. |
+ type ^= mixins.At(mixins.Length() - 1); |
+ const Class& resolved_mixin_app_class = Class::Handle(type.type_class()); |
+ Type& resolved_mixin_app_type = Type::Handle(); |
+ resolved_mixin_app_type = Type::New(resolved_mixin_app_class, |
+ mixin_app_args, |
+ mixin_app.token_pos()); |
+ return resolved_mixin_app_type.raw(); |
+} |
+ |
+ |
// Recursively walks the graph of explicitly declared super type and |
// interfaces, resolving unresolved super types and interfaces. |
// Reports an error if there is an interface reference that cannot be |
@@ -1476,16 +1640,16 @@ |
// If the class/interface has no explicit super class/interfaces |
// and is not a mixin application, we are done. |
AbstractType& super_type = AbstractType::Handle(cls.super_type()); |
- Type& mixin_type = Type::Handle(cls.mixin()); |
Array& super_interfaces = Array::Handle(cls.interfaces()); |
if ((super_type.IsNull() || super_type.IsObjectType()) && |
- (super_interfaces.Length() == 0) && |
- (mixin_type.IsNull())) { |
+ (super_interfaces.Length() == 0)) { |
return; |
} |
- if (!mixin_type.IsNull()) { |
- ResolveType(cls, mixin_type, kCanonicalizeWellFormed); |
+ if (super_type.IsMixinAppType()) { |
+ const MixinAppType& mixin_app_type = MixinAppType::Cast(super_type); |
+ super_type = ResolveMixinAppType(cls, mixin_app_type); |
+ cls.set_super_type(super_type); |
} |
// If cls belongs to core lib, restrictions about allowed interfaces |