Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(724)

Unified Diff: runtime/vm/class_finalizer.cc

Issue 23452055: Address comments of committed change https://codereview.chromium.org/24397002/ (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 7 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | runtime/vm/object.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: runtime/vm/class_finalizer.cc
===================================================================
--- runtime/vm/class_finalizer.cc (revision 27836)
+++ runtime/vm/class_finalizer.cc (working copy)
@@ -1436,6 +1436,57 @@
}
+/* Support for mixin typedef.
+Consider the following example:
+
+class I<T> { }
+class J<T> { }
+class S<T> { }
+class M<T> { }
+typedef A<U, V> = Object with M<Map<U, V>> implements I<V>;
+typedef C<T, K> = S<T> with A<T, List<K>> implements J<K>;
+
+Before the call to ApplyMixinTypedef, 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> { }
+
+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> { }
+
+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
+(e.g. I<V>) and for type argument substitution via the super type relation (e.g.
+type parameter T of Object&M is substituted with Map<U, V>, U and V being the
+type parameters of the typedef 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 a typedef.
+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
+parameters of A, i.e. U and V, but not T.
+
+Therefore, the call to ApplyMixinTypedef 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> { }
+
+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> { }
+
+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 refer to the type
+parameters U and V of S&A, not to U and V of A. An instantiation step with
+a properly crafted instantiator vector takes care of the required type parameter
+substitution.
+*/
void ClassFinalizer::ApplyMixinTypedef(const Class& mixin_app_class) {
// If this mixin typedef is aliasing another mixin typedef, another class
// will be inserted via recursion. No need to check here.
@@ -1576,13 +1627,16 @@
ASSERT(!mixin_type.IsNull());
ASSERT(mixin_type.HasResolvedTypeClass());
const Class& mixin_class = Class::Handle(mixin_type.type_class());
- if (mixin_class.IsNullClass()) {
- const Script& script = Script::Handle(mixin_app_class.script());
- ReportError(Error::Handle(), // No previous error.
- script, mixin_app_class.token_pos(),
- "illegal mixin of 'Null'");
+
+ if (FLAG_trace_class_finalization) {
+ OS::Print("Applying mixin type '%s' to %s at pos %" Pd "\n",
+ String::Handle(mixin_type.Name()).ToCString(),
+ mixin_app_class.ToCString(),
+ mixin_app_class.token_pos());
}
- // Check for illegal self references.
+
+ // Check for illegal self references. This has to be done before checking
+ // that the super class of the mixin class is class Object.
GrowableArray<intptr_t> visited_mixins;
if (!IsMixinCycleFree(mixin_class, &visited_mixins)) {
const Script& script = Script::Handle(mixin_class.script());
@@ -1593,13 +1647,6 @@
class_name.ToCString());
}
- if (FLAG_trace_class_finalization) {
- OS::Print("Applying mixin type '%s' to %s at pos %" Pd "\n",
- String::Handle(mixin_type.Name()).ToCString(),
- mixin_app_class.ToCString(),
- mixin_app_class.token_pos());
- }
-
// 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 typedef classes, which are aliases (but are
@@ -1622,6 +1669,11 @@
// Copy type parameters to mixin application class.
CloneMixinAppTypeParameters(mixin_app_class);
+ // Verify that no restricted class is used as a mixin by checking the
+ // interfaces of the mixin application class, which implements its mixin.
+ GrowableArray<intptr_t> visited_interfaces;
+ ResolveSuperTypeAndInterfaces(mixin_app_class, &visited_interfaces);
+
if (FLAG_trace_class_finalization) {
OS::Print("Done applying mixin type '%s' to class '%s' %s extending '%s'\n",
String::Handle(mixin_type.Name()).ToCString(),
@@ -2280,10 +2332,8 @@
"function type alias '%s' may not be used as interface",
String::Handle(interface_class.Name()).ToCString());
}
- // Verify that unless cls belongs to core lib, it cannot extend or implement
- // any of Null, bool, num, int, double, String, Function, dynamic.
- // The exception is signature classes, which are compiler generated and
- // represent a function type, therefore implementing the Function interface.
+ // Verify that unless cls belongs to core lib, it cannot extend, implement,
+ // or mixin any of Null, bool, num, int, double, String, dynamic.
if (!cls_belongs_to_core_lib) {
if (interface.IsBoolType() ||
interface.IsNullType() ||
@@ -2293,11 +2343,19 @@
interface.IsStringType() ||
interface.IsDynamicType()) {
const Script& script = Script::Handle(cls.script());
- ReportError(Error::Handle(), // No previous error.
- script, cls.token_pos(),
- "'%s' is not allowed to extend or implement '%s'",
- String::Handle(cls.Name()).ToCString(),
- String::Handle(interface_class.Name()).ToCString());
+ const String& interface_name = String::Handle(interface_class.Name());
+ if (cls.IsMixinApplication()) {
+ ReportError(Error::Handle(), // No previous error.
+ script, cls.token_pos(),
+ "illegal mixin of '%s'",
+ interface_name.ToCString());
+ } else {
+ ReportError(Error::Handle(), // No previous error.
+ script, cls.token_pos(),
+ "'%s' is not allowed to extend or implement '%s'",
+ String::Handle(cls.Name()).ToCString(),
+ interface_name.ToCString());
+ }
}
}
interface_class.set_is_implemented();
« no previous file with comments | « no previous file | runtime/vm/object.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698