Index: runtime/vm/class_finalizer.cc |
=================================================================== |
--- runtime/vm/class_finalizer.cc (revision 34737) |
+++ runtime/vm/class_finalizer.cc (working copy) |
@@ -512,20 +512,24 @@ |
} |
-// This function reports a compilation error if the recursive 'type' being |
-// finalized is a non-contractive type, i.e. if the induced type set of the |
-// instantiation of 'type' with its own type parameters is not finite (see |
-// the Dart Language Specification for the definition of the induced type set). |
-// This can be detected by looking at the queue of types pending finalization |
-// that may be mutually recursive with the checked type. |
+// This function reports a compilation error if the recursive 'type' T being |
+// finalized is a non-contractive type, i.e. if the induced type set S of P is |
+// not finite, where P is the instantiation of T with its own type parameters. |
+// The induced type set S consists of the super types of any type in S as well |
+// as the type arguments of any parameterized type in S. |
+// The Dart Language Specification does not disallow the declaration and use of |
+// non-contractive types (this may change). They are nevertheless disallowed |
+// as an implementation restriction in the VM since they cause divergence. |
+// A non-contractive type can be detected by looking at the queue of types |
+// pending finalization that are mutually recursive with the checked type. |
void ClassFinalizer::CheckRecursiveType(const Class& cls, |
const Type& type, |
GrowableObjectArray* pending_types) { |
Isolate* isolate = Isolate::Current(); |
if (FLAG_trace_type_finalization) { |
- OS::Print("Checking recursive type '%s' for class '%s'\n", |
+ OS::Print("Checking recursive type '%s': %s\n", |
String::Handle(type.Name()).ToCString(), |
- cls.ToCString()); |
+ type.ToCString()); |
} |
const Class& type_cls = Class::Handle(isolate, type.type_class()); |
const TypeArguments& arguments = |
@@ -554,8 +558,9 @@ |
for (intptr_t i = num_pending_types - 1; i >= 0; i--) { |
pending_type ^= pending_types->At(i); |
if (FLAG_trace_type_finalization) { |
- OS::Print(" Comparing with pending type '%s'\n", |
- String::Handle(pending_type.Name()).ToCString()); |
+ OS::Print(" Comparing with pending type '%s': %s\n", |
+ String::Handle(pending_type.Name()).ToCString(), |
+ pending_type.ToCString()); |
} |
if ((pending_type.raw() != type.raw()) && |
(pending_type.type_class() == type_cls.raw())) { |
@@ -648,9 +653,9 @@ |
ASSERT(super_type_arg.IsType()); |
CheckRecursiveType(cls, Type::Cast(super_type_arg), pending_types); |
if (FLAG_trace_type_finalization) { |
- OS::Print("Creating TypeRef '%s' for class '%s'\n", |
+ OS::Print("Creating TypeRef '%s': '%s'\n", |
String::Handle(super_type_arg.Name()).ToCString(), |
- cls.ToCString()); |
+ super_type_arg.ToCString()); |
} |
super_type_arg = TypeRef::New(super_type_arg); |
super_type_args.SetTypeAt(i, super_type_arg); |
@@ -661,13 +666,20 @@ |
super_type_args.SetTypeAt(i, super_type_arg); |
// Note that super_type_arg may still not be finalized here, in |
// which case it is a TypeRef to a legal recursive type. |
- // Therefore, it does not need to be instantiated below. |
- // See tests/language/regress_16640_test.dart for an example. |
} |
} |
} |
- if (!super_type_arg.IsBeingFinalized() && |
- !super_type_arg.IsInstantiated()) { |
+ // Instantiate super_type_arg with the current argument vector. |
+ if (!super_type_arg.IsInstantiated()) { |
+ if (FLAG_trace_type_finalization && super_type_arg.IsTypeRef()) { |
+ AbstractType& ref_type = AbstractType::Handle( |
+ TypeRef::Cast(super_type_arg).type()); |
+ OS::Print("Instantiating TypeRef '%s': '%s'\n" |
+ " instantiator: '%s'\n", |
+ String::Handle(super_type_arg.Name()).ToCString(), |
+ ref_type.ToCString(), |
+ arguments.ToCString()); |
+ } |
Error& error = Error::Handle(); |
super_type_arg = |
super_type_arg.InstantiateFrom(arguments, &error, trail); |
@@ -681,6 +693,25 @@ |
*bound_error = error.raw(); |
} |
} |
+ if (!super_type_arg.IsFinalized() && |
+ !super_type_arg.IsBeingFinalized()) { |
+ // The super_type_arg was instantiated from a type being finalized. |
+ // We need to finish finalizing its type arguments. |
+ if (super_type_arg.IsTypeRef()) { |
+ super_type_arg = TypeRef::Cast(super_type_arg).type(); |
+ } |
+ Type::Cast(super_type_arg).set_is_being_finalized(); |
+ pending_types->Add(super_type_arg); |
+ const Class& cls = Class::Handle(super_type_arg.type_class()); |
+ FinalizeTypeArguments( |
+ cls, |
+ TypeArguments::Handle(super_type_arg.arguments()), |
+ cls.NumTypeArguments() - cls.NumTypeParameters(), |
+ bound_error, |
+ pending_types, |
+ trail); |
+ Type::Cast(super_type_arg).SetIsFinalized(); |
+ } |
} |
} |
arguments.SetTypeAt(i, super_type_arg); |
@@ -986,8 +1017,7 @@ |
// num_type_parameters) of this type being finalized with the still |
// unfinalized run-time argument vector (of length num_type_arguments). |
// This type being finalized may be recursively reached via bounds |
- // checking, in which case type arguments of super classes will be seen |
- // as dynamic. |
+ // checking or type arguments of its super type. |
parameterized_type.set_arguments(full_arguments); |
// Finalize the current type arguments of the type, which are still the |
// parsed type arguments. |
@@ -1050,9 +1080,14 @@ |
// bounds. |
if (is_root_type) { |
Type& type = Type::Handle(isolate); |
- for (intptr_t i = 0; i < types.Length(); i++) { |
+ for (intptr_t i = types.Length() - 1; i >= 0; i--) { |
type ^= types.At(i); |
CheckTypeBounds(cls, type); |
+ if (FLAG_trace_type_finalization && type.IsRecursive()) { |
+ OS::Print("Done finalizing recursive type '%s': %s\n", |
+ String::Handle(isolate, type.Name()).ToCString(), |
+ type.ToCString()); |
+ } |
} |
} |
@@ -1076,6 +1111,14 @@ |
} |
if (finalization >= kCanonicalize) { |
+ if (FLAG_trace_type_finalization && parameterized_type.IsRecursive()) { |
+ AbstractType& type = Type::Handle(isolate); |
+ type = parameterized_type.Canonicalize(); |
+ OS::Print("Done canonicalizing recursive type '%s': %s\n", |
+ String::Handle(isolate, type.Name()).ToCString(), |
+ type.ToCString()); |
+ return type.raw(); |
+ } |
return parameterized_type.Canonicalize(); |
} else { |
return parameterized_type.raw(); |