Index: runtime/vm/class_finalizer.cc |
=================================================================== |
--- runtime/vm/class_finalizer.cc (revision 7523) |
+++ runtime/vm/class_finalizer.cc (working copy) |
@@ -563,9 +563,8 @@ |
FinalizationKind finalization) { |
ASSERT(arguments.Length() >= cls.NumTypeArguments()); |
if (!cls.is_finalized()) { |
- const GrowableObjectArray& visited = |
- GrowableObjectArray::Handle(GrowableObjectArray::New()); |
- ResolveInterfaces(cls, visited); |
+ GrowableArray<intptr_t> visited_interfaces; |
+ ResolveInterfaces(cls, &visited_interfaces); |
FinalizeTypeParameters(cls); |
} |
Type& super_type = Type::Handle(cls.super_type()); |
@@ -669,9 +668,8 @@ |
// parameters of the type class must be finalized. |
Class& type_class = Class::Handle(parameterized_type.type_class()); |
if (!type_class.is_finalized()) { |
- const GrowableObjectArray& visited = |
- GrowableObjectArray::Handle(GrowableObjectArray::New()); |
- ResolveInterfaces(type_class, visited); |
+ GrowableArray<intptr_t> visited_interfaces; |
+ ResolveInterfaces(type_class, &visited_interfaces); |
FinalizeTypeParameters(type_class); |
} |
@@ -752,10 +750,8 @@ |
} |
} |
- // Illegally self referencing types may get finalized indirectly. |
- if (parameterized_type.IsFinalized()) { |
- ASSERT(parameterized_type.IsMalformed()); |
- } else { |
+ // Self referencing types may get finalized indirectly. |
+ if (!parameterized_type.IsFinalized()) { |
// Mark the type as finalized. |
if (parameterized_type.IsInstantiated()) { |
parameterized_type.set_is_finalized_instantiated(); |
@@ -791,18 +787,30 @@ |
} |
} |
- // If the type class is a signature class, we also finalize its signature |
- // type, thereby finalizing the result type and parameter types of its |
- // signature function. |
+ // If the type class is a signature class, we are currently finalizing a |
+ // signature type, i.e. finalizing the result type and parameter types of the |
+ // signature function of this signature type. |
// We do this after marking this type as finalized in order to allow a |
// function type to refer to itself via its parameter types and result type. |
if (type_class.IsSignatureClass()) { |
- // Signature classes are finalized upon creation. |
- ASSERT(type_class.is_finalized()); |
- // Resolve and finalize the result and parameter types of the signature |
- // function of this signature class. |
- ResolveAndFinalizeSignature( |
- type_class, Function::Handle(type_class.signature_function())); |
+ // Signature classes are finalized upon creation, except function type |
+ // aliases. |
+ if (type_class.IsCanonicalSignatureClass()) { |
+ ASSERT(type_class.is_finalized()); |
+ // Resolve and finalize the result and parameter types of the signature |
+ // function of this signature class. |
+ ASSERT(type_class.SignatureType() == type.raw()); |
+ ResolveAndFinalizeSignature( |
+ type_class, Function::Handle(type_class.signature_function())); |
+ } else { |
+ // This type is a function type alias. Its class may need to be finalized |
+ // and checked for illegal self reference. |
+ FinalizeClass(type_class, false); |
+ // Finalizing the signature function here (as in the canonical case above) |
+ // would not mark the canonical signature type as finalized. |
+ const Type& signature_type = Type::Handle(type_class.SignatureType()); |
+ FinalizeType(cls, signature_type, finalization); |
+ } |
} |
return parameterized_type.Canonicalize(); |
@@ -1059,8 +1067,6 @@ |
if (FLAG_trace_class_finalization) { |
OS::Print("Finalize %s\n", cls.ToCString()); |
} |
- // Signature classes are finalized upon creation. |
- ASSERT(!cls.IsSignatureClass()); |
if (!IsSuperCycleFree(cls)) { |
const String& name = String::Handle(cls.Name()); |
const Script& script = Script::Handle(cls.script()); |
@@ -1068,9 +1074,8 @@ |
"class '%s' has a cycle in its superclass relationship", |
name.ToCString()); |
} |
- const GrowableObjectArray& visited = |
- GrowableObjectArray::Handle(GrowableObjectArray::New()); |
- ResolveInterfaces(cls, visited); |
+ GrowableArray<intptr_t> visited_interfaces; |
+ ResolveInterfaces(cls, &visited_interfaces); |
// Finalize super class. |
const Class& super_class = Class::Handle(cls.SuperClass()); |
if (!super_class.IsNull()) { |
@@ -1084,6 +1089,24 @@ |
super_type ^= FinalizeType(cls, super_type, kFinalizeWellFormed); |
cls.set_super_type(super_type); |
} |
+ // Signature classes are finalized upon creation, except function type |
+ // aliases. |
+ if (cls.IsSignatureClass()) { |
+ ASSERT(!cls.IsCanonicalSignatureClass()); |
+ // Check for illegal self references. |
+ GrowableArray<intptr_t> visited_aliases; |
+ if (!IsAliasCycleFree(cls, &visited_aliases)) { |
+ const String& name = String::Handle(cls.Name()); |
+ const Script& script = Script::Handle(cls.script()); |
+ ReportError(script, cls.token_index(), |
+ "typedef '%s' illegally refers to itself", |
+ name.ToCString()); |
+ } |
+ // TODO(regis): Also check this: "It is a compile-time error if any default |
+ // values are specified in the signature of a function type alias". |
+ cls.Finalize(); |
+ return; |
+ } |
// Finalize factory class, if any. |
if (cls.is_interface()) { |
if (cls.HasFactoryClass()) { |
@@ -1153,6 +1176,58 @@ |
} |
+// Returns false if the function type alias illegally refers to itself. |
+bool ClassFinalizer::IsAliasCycleFree(const Class& cls, |
+ GrowableArray<intptr_t>* visited) { |
+ ASSERT(cls.IsSignatureClass()); |
+ ASSERT(!cls.IsCanonicalSignatureClass()); |
+ ASSERT(!cls.is_finalized()); |
+ ASSERT(visited != NULL); |
+ const intptr_t cls_index = cls.index(); |
+ for (int i = 0; i < visited->length(); i++) { |
+ if ((*visited)[i] == cls_index) { |
+ // We have already visited alias 'cls'. We found a cycle. |
+ return false; |
+ } |
+ } |
+ |
+ // Visit the result type and parameter types of this signature type. |
+ visited->Add(cls.index()); |
+ const Function& function = Function::Handle(cls.signature_function()); |
+ // Check class of result type. |
+ AbstractType& type = AbstractType::Handle(function.result_type()); |
+ ResolveType(cls, type, kFinalize); |
+ if (type.IsType() && !type.IsMalformed()) { |
+ const Class& type_class = Class::Handle(type.type_class()); |
+ if (!type_class.is_finalized() && |
+ type_class.IsSignatureClass() && |
+ !type_class.IsCanonicalSignatureClass()) { |
+ if (!IsAliasCycleFree(type_class, visited)) { |
+ return false; |
+ } |
+ } |
+ } |
+ // Check classes of formal parameter types. |
+ const intptr_t num_parameters = function.NumberOfParameters(); |
+ for (intptr_t i = 0; i < num_parameters; i++) { |
+ type = function.ParameterTypeAt(i); |
+ ResolveType(cls, type, kFinalize); |
+ if (type.IsType() && !type.IsMalformed()) { |
+ const Class& type_class = Class::Handle(type.type_class()); |
+ if (!type_class.is_finalized() && |
+ type_class.IsSignatureClass() && |
+ !type_class.IsCanonicalSignatureClass()) { |
+ if (!IsAliasCycleFree(type_class, visited)) { |
+ return false; |
+ } |
+ } |
+ } |
+ } |
+ visited->RemoveLast(); |
+ return true; |
+} |
+ |
+ |
bool ClassFinalizer::AddInterfaceIfUnique( |
const GrowableObjectArray& interface_list, |
const AbstractType& interface, |
@@ -1191,12 +1266,11 @@ |
// graph. If we visit an interface a second time on a given path, |
// we found a loop. |
void ClassFinalizer::ResolveInterfaces(const Class& cls, |
- const GrowableObjectArray& visited) { |
- ASSERT(!visited.IsNull()); |
- Class& visited_cls = Class::Handle(); |
- for (int i = 0; i < visited.Length(); i++) { |
- visited_cls ^= visited.At(i); |
- if (visited_cls.raw() == cls.raw()) { |
+ GrowableArray<intptr_t>* visited) { |
+ ASSERT(visited != NULL); |
+ const intptr_t cls_index = cls.index(); |
+ for (int i = 0; i < visited->length(); i++) { |
+ if ((*visited)[i] == cls_index) { |
// We have already visited interface class 'cls'. We found a cycle. |
const String& interface_name = String::Handle(cls.Name()); |
const Script& script = Script::Handle(cls.script()); |
@@ -1219,7 +1293,7 @@ |
(cls.library() == Library::CoreImplLibrary()); |
// Resolve and check the interfaces of cls. |
- visited.Add(cls); |
+ visited->Add(cls_index); |
AbstractType& interface = AbstractType::Handle(); |
Class& interface_class = Class::Handle(); |
for (intptr_t i = 0; i < super_interfaces.Length(); i++) { |
@@ -1260,7 +1334,7 @@ |
// Now resolve the super interfaces. |
ResolveInterfaces(interface_class, visited); |
} |
- visited.RemoveLast(); |
+ visited->RemoveLast(); |
} |