Index: runtime/vm/class_finalizer.cc |
diff --git a/runtime/vm/class_finalizer.cc b/runtime/vm/class_finalizer.cc |
index e2fd349fbca1303a46ee84d65af1ed2a07b80b2d..f2c7b12c60438f26ff4deb02f15007448172df37 100644 |
--- a/runtime/vm/class_finalizer.cc |
+++ b/runtime/vm/class_finalizer.cc |
@@ -440,7 +440,7 @@ void ClassFinalizer::ResolveRedirectingFactoryTarget( |
const TypeArguments& type_args = TypeArguments::Handle(type.arguments()); |
Error& bound_error = Error::Handle(); |
target_type ^= target_type.InstantiateFrom( |
- type_args, &bound_error, NULL, Heap::kOld); |
+ type_args, &bound_error, NULL, NULL, Heap::kOld); |
if (bound_error.IsNull()) { |
target_type ^= FinalizeType(cls, target_type, kCanonicalize); |
} else { |
@@ -624,13 +624,14 @@ void ClassFinalizer::CheckRecursiveType(const Class& cls, |
TypeArguments& pending_arguments = TypeArguments::Handle(zone); |
const intptr_t num_pending_types = pending_types->length(); |
for (intptr_t i = num_pending_types - 1; i >= 0; i--) { |
- const Type& pending_type = Type::Cast(pending_types->At(i)); |
+ const AbstractType& pending_type = pending_types->At(i); |
if (FLAG_trace_type_finalization) { |
THR_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.IsType() && |
(pending_type.type_class() == type_cls.raw())) { |
pending_arguments = pending_type.arguments(); |
if (!pending_arguments.IsSubvectorEquivalent(arguments, |
@@ -741,10 +742,10 @@ intptr_t ClassFinalizer::ExpandAndFinalizeTypeArguments( |
} |
} |
if (offset > 0) { |
- TrailPtr trail = new Trail(Z, 4); |
- Error& bound_error = Error::Handle(); |
+ TrailPtr instantiation_trail = new Trail(Z, 4); |
+ Error& bound_error = Error::Handle(Z); |
FinalizeTypeArguments(type_class, full_arguments, offset, |
- &bound_error, pending_types, trail); |
+ &bound_error, pending_types, instantiation_trail); |
} |
if (full_arguments.IsRaw(0, num_type_arguments)) { |
// The parameterized_type is raw. Set its argument vector to null, which |
@@ -761,6 +762,11 @@ intptr_t ClassFinalizer::ExpandAndFinalizeTypeArguments( |
if (!type.IsFinalized()) { |
ASSERT(full_arguments.IsNull() || |
!full_arguments.IsRaw(0, num_type_arguments)); |
+ if (FLAG_trace_type_finalization) { |
+ THR_Print("Marking type '%s' as finalized for class '%s'\n", |
+ String::Handle(Z, type.Name()).ToCString(), |
+ String::Handle(Z, cls.Name()).ToCString()); |
+ } |
// Mark the type as finalized. |
type.SetIsFinalized(); |
// Do not yet remove the type from the pending_types array. |
@@ -808,7 +814,7 @@ void ClassFinalizer::FinalizeTypeArguments( |
intptr_t num_uninitialized_arguments, |
Error* bound_error, |
PendingTypes* pending_types, |
- TrailPtr trail) { |
+ TrailPtr instantiation_trail) { |
ASSERT(arguments.Length() >= cls.NumTypeArguments()); |
if (!cls.is_type_finalized()) { |
FinalizeTypeParameters(cls, pending_types); |
@@ -868,7 +874,7 @@ void ClassFinalizer::FinalizeTypeArguments( |
} |
Error& error = Error::Handle(); |
super_type_arg = super_type_arg.InstantiateFrom( |
- arguments, &error, trail, Heap::kOld); |
+ arguments, &error, instantiation_trail, NULL, Heap::kOld); |
if (!error.IsNull()) { |
// InstantiateFrom does not report an error if the type is still |
// uninstantiated. Instead, it will return a new BoundedType so |
@@ -895,7 +901,7 @@ void ClassFinalizer::FinalizeTypeArguments( |
cls.NumTypeArguments() - cls.NumTypeParameters(), |
bound_error, |
pending_types, |
- trail); |
+ instantiation_trail); |
Type::Cast(super_type_arg).SetIsFinalized(); |
} |
} |
@@ -903,7 +909,7 @@ void ClassFinalizer::FinalizeTypeArguments( |
arguments.SetTypeAt(i, super_type_arg); |
} |
FinalizeTypeArguments(super_class, arguments, super_offset, |
- bound_error, pending_types, trail); |
+ bound_error, pending_types, instantiation_trail); |
} |
} |
@@ -918,7 +924,7 @@ void ClassFinalizer::CheckTypeArgumentBounds(const Class& cls, |
Error* bound_error) { |
if (!cls.is_type_finalized()) { |
FinalizeTypeParameters(cls); |
- FinalizeUpperBounds(cls); |
+ FinalizeUpperBounds(cls, kFinalize); // No canonicalization yet. |
} |
// Note that when finalizing a type, we need to verify the bounds in both |
// production mode and checked mode, because the finalized type may be written |
@@ -970,8 +976,8 @@ void ClassFinalizer::CheckTypeArgumentBounds(const Class& cls, |
if (declared_bound.IsInstantiated()) { |
instantiated_bound = declared_bound.raw(); |
} else { |
- instantiated_bound = |
- declared_bound.InstantiateFrom(arguments, &error, NULL, Heap::kOld); |
+ instantiated_bound = declared_bound.InstantiateFrom( |
+ arguments, &error, NULL, NULL, Heap::kOld); |
} |
if (!instantiated_bound.IsFinalized()) { |
// The bound refers to type parameters, creating a cycle; postpone |
@@ -1001,7 +1007,8 @@ void ClassFinalizer::CheckTypeArgumentBounds(const Class& cls, |
// This may be called only if type needs to be finalized, therefore |
// seems OK to allocate finalized types in old space. |
if (!type_param.CheckBound(type_arg, instantiated_bound, |
- &error, Heap::kOld) && error.IsNull()) { |
+ &error, NULL, Heap::kOld) && |
+ error.IsNull()) { |
// The bound cannot be checked at compile time; postpone to run time. |
type_arg = BoundedType::New(type_arg, instantiated_bound, type_param); |
arguments.SetTypeAt(offset + i, type_arg); |
@@ -1022,32 +1029,47 @@ void ClassFinalizer::CheckTypeArgumentBounds(const Class& cls, |
void ClassFinalizer::CheckTypeBounds(const Class& cls, |
const AbstractType& type) { |
+ Zone* Z = Thread::Current()->zone(); |
ASSERT(type.IsType() || type.IsFunctionType()); |
ASSERT(type.IsFinalized()); |
- TypeArguments& arguments = TypeArguments::Handle(type.arguments()); |
+ ASSERT(!type.IsCanonical()); |
+ TypeArguments& arguments = TypeArguments::Handle(Z, type.arguments()); |
if (arguments.IsNull()) { |
return; |
} |
- const Class& type_class = Class::Handle(type.type_class()); |
- Error& bound_error = Error::Handle(); |
+ if (FLAG_trace_type_finalization) { |
+ THR_Print("Checking bounds of type '%s' for class '%s'\n", |
+ String::Handle(Z, type.Name()).ToCString(), |
+ String::Handle(Z, cls.Name()).ToCString()); |
+ } |
+ const Class& type_class = Class::Handle(Z, type.type_class()); |
+ Error& bound_error = Error::Handle(Z); |
CheckTypeArgumentBounds(type_class, arguments, &bound_error); |
- type.set_arguments(arguments); |
- // If a bound error occurred, mark the type as malbounded. |
- // The bound error will be ignored in production mode. |
- if (!bound_error.IsNull()) { |
- // No compile-time error during finalization. |
- const String& type_name = String::Handle(type.UserVisibleName()); |
- FinalizeMalboundedType(bound_error, |
- Script::Handle(cls.script()), |
- type, |
- "type '%s' has an out of bound type argument", |
- type_name.ToCString()); |
- if (FLAG_trace_type_finalization) { |
- THR_Print("Marking type '%s' as malbounded: %s\n", |
- String::Handle(type.Name()).ToCString(), |
- bound_error.ToCString()); |
+ // CheckTypeArgumentBounds may have indirectly canonicalized this type. |
+ if (!type.IsCanonical()) { |
+ type.set_arguments(arguments); |
+ // If a bound error occurred, mark the type as malbounded. |
+ // The bound error will be ignored in production mode. |
+ if (!bound_error.IsNull()) { |
+ // No compile-time error during finalization. |
+ const String& type_name = String::Handle(Z, type.UserVisibleName()); |
+ FinalizeMalboundedType(bound_error, |
+ Script::Handle(Z, cls.script()), |
+ type, |
+ "type '%s' has an out of bound type argument", |
+ type_name.ToCString()); |
+ if (FLAG_trace_type_finalization) { |
+ THR_Print("Marking type '%s' as malbounded: %s\n", |
+ String::Handle(Z, type.Name()).ToCString(), |
+ bound_error.ToCString()); |
+ } |
} |
} |
+ if (FLAG_trace_type_finalization) { |
+ THR_Print("Done checking bounds of type '%s': %s\n", |
+ String::Handle(Z, type.Name()).ToCString(), |
+ type.ToCString()); |
+ } |
} |
@@ -1062,7 +1084,11 @@ RawAbstractType* ClassFinalizer::FinalizeType( |
if (type.IsFinalized()) { |
// Ensure type is canonical if canonicalization is requested, unless type is |
// malformed. |
- if ((finalization >= kCanonicalize) && !type.IsMalformed()) { |
+ if ((finalization >= kCanonicalize) && |
+ !type.IsMalformed() && |
+ !type.IsCanonical() && |
+ (type.IsType() || type.IsFunctionType())) { |
+ CheckTypeBounds(cls, type); |
return type.Canonicalize(); |
} |
return type.raw(); |
@@ -1091,7 +1117,7 @@ RawAbstractType* ClassFinalizer::FinalizeType( |
if (FLAG_trace_type_finalization) { |
THR_Print("Finalizing type '%s' for class '%s'\n", |
String::Handle(Z, resolved_type.Name()).ToCString(), |
- cls.ToCString()); |
+ String::Handle(Z, cls.Name()).ToCString()); |
} |
if (resolved_type.IsTypeParameter()) { |
@@ -1142,11 +1168,9 @@ RawAbstractType* ClassFinalizer::FinalizeType( |
// bounds. |
if (is_root_type) { |
for (intptr_t i = pending_types->length() - 1; i >= 0; i--) { |
- CheckTypeBounds(cls, pending_types->At(i)); |
- if (FLAG_trace_type_finalization && resolved_type.IsRecursive()) { |
- THR_Print("Done finalizing recursive type '%s': %s\n", |
- String::Handle(Z, resolved_type.Name()).ToCString(), |
- resolved_type.ToCString()); |
+ const AbstractType& type = pending_types->At(i); |
+ if (!type.IsMalformed() && !type.IsCanonical()) { |
+ CheckTypeBounds(cls, type); |
} |
} |
} |
@@ -1178,13 +1202,14 @@ RawAbstractType* ClassFinalizer::FinalizeType( |
} |
if (finalization >= kCanonicalize) { |
- if (FLAG_trace_type_finalization && resolved_type.IsRecursive()) { |
- AbstractType& recursive_type = |
+ if (FLAG_trace_type_finalization) { |
+ THR_Print("Canonicalizing type '%s'\n", |
+ String::Handle(Z, resolved_type.Name()).ToCString()); |
+ AbstractType& canonical_type = |
AbstractType::Handle(Z, resolved_type.Canonicalize()); |
- THR_Print("Done canonicalizing recursive type '%s': %s\n", |
- String::Handle(Z, recursive_type.Name()).ToCString(), |
- recursive_type.ToCString()); |
- return recursive_type.raw(); |
+ THR_Print("Done canonicalizing type '%s'\n", |
+ String::Handle(Z, canonical_type.Name()).ToCString()); |
+ return canonical_type.raw(); |
} |
return resolved_type.Canonicalize(); |
} else { |
@@ -1308,7 +1333,8 @@ void ClassFinalizer::ResolveUpperBounds(const Class& cls) { |
// Finalize the upper bounds of the type parameters of class cls. |
-void ClassFinalizer::FinalizeUpperBounds(const Class& cls) { |
+void ClassFinalizer::FinalizeUpperBounds(const Class& cls, |
+ FinalizationKind finalization) { |
const intptr_t num_type_params = cls.NumTypeParameters(); |
TypeParameter& type_param = TypeParameter::Handle(); |
AbstractType& bound = AbstractType::Handle(); |
@@ -1324,7 +1350,7 @@ void ClassFinalizer::FinalizeUpperBounds(const Class& cls) { |
// A bound involved in F-bounded quantification may form a cycle. |
continue; |
} |
- bound = FinalizeType(cls, bound, kCanonicalize); |
+ bound = FinalizeType(cls, bound, finalization); |
type_param.set_bound(bound); |
} |
} |
@@ -1766,7 +1792,7 @@ void ClassFinalizer::CloneMixinAppTypeParameters(const Class& mixin_app_class) { |
param.set_bound(param_bound); // In case part of recursive type. |
} |
param_bound = param_bound.InstantiateFrom( |
- instantiator, &bound_error, NULL, Heap::kOld); |
+ instantiator, &bound_error, NULL, NULL, Heap::kOld); |
// The instantiator contains only TypeParameter objects and no |
// BoundedType objects, so no bound error may occur. |
ASSERT(!param_bound.IsBoundedType()); |
@@ -2000,20 +2026,20 @@ void ClassFinalizer::ApplyMixinAppAlias(const Class& mixin_app_class, |
if (type.IsBoundedType()) { |
bounded_type = BoundedType::Cast(type).type(); |
bounded_type = bounded_type.InstantiateFrom( |
- instantiator, &bound_error, NULL, Heap::kOld); |
+ instantiator, &bound_error, NULL, NULL, Heap::kOld); |
// 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, NULL, Heap::kOld); |
+ instantiator, &bound_error, NULL, NULL, Heap::kOld); |
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, NULL, Heap::kOld); |
+ instantiator, &bound_error, NULL, NULL, Heap::kOld); |
ASSERT(bound_error.IsNull()); |
} |
} |
@@ -2312,7 +2338,7 @@ void ClassFinalizer::FinalizeTypesInClass(const Class& cls) { |
// unfinalized bounds. It is more efficient to finalize them early. |
// Finalize bounds even if running in production mode, so that a snapshot |
// contains them. |
- FinalizeUpperBounds(cls); |
+ FinalizeUpperBounds(cls, kCanonicalizeWellFormed); |
// Finalize super type. |
AbstractType& super_type = AbstractType::Handle(cls.super_type()); |
if (!super_type.IsNull()) { |