Index: runtime/vm/class_finalizer.cc |
=================================================================== |
--- runtime/vm/class_finalizer.cc (revision 25979) |
+++ runtime/vm/class_finalizer.cc (working copy) |
@@ -14,6 +14,8 @@ |
namespace dart { |
+DEFINE_FLAG(bool, error_on_bad_override, false, |
+ "Report error for bad overrides."); |
DEFINE_FLAG(bool, error_on_malformed_type, false, |
"Report error for malformed types."); |
DEFINE_FLAG(bool, print_classes, false, "Prints details about loaded classes."); |
@@ -50,7 +52,7 @@ |
cls = class_table.At(cid); |
ASSERT(!cls.IsNull()); |
array = cls.functions(); |
- intptr_t num_functions = array.IsNull() ? 0 : array.Length(); |
+ const intptr_t num_functions = array.IsNull() ? 0 : array.Length(); |
for (intptr_t f = 0; f < num_functions; f++) { |
function ^= array.At(f); |
ASSERT(!function.IsNull()); |
@@ -140,9 +142,6 @@ |
// First resolve all superclasses. |
for (intptr_t i = 0; i < class_array.Length(); i++) { |
cls ^= class_array.At(i); |
- if (FLAG_trace_class_finalization) { |
- OS::Print("Resolving super and interfaces: %s\n", cls.ToCString()); |
- } |
GrowableArray<intptr_t> visited_interfaces; |
ResolveSuperTypeAndInterfaces(cls, &visited_interfaces); |
} |
@@ -308,7 +307,8 @@ |
if (visited_factories.At(i) == factory.raw()) { |
// A redirection cycle is reported as a compile-time error. |
const Script& script = Script::Handle(cls.script()); |
- ReportError(script, factory.token_pos(), |
+ ReportError(Error::Handle(), // No previous error. |
+ script, factory.token_pos(), |
"factory '%s' illegally redirects to itself", |
String::Handle(factory.name()).ToCString()); |
} |
@@ -382,25 +382,27 @@ |
return; |
} |
- // Verify that the target is compatible with the redirecting factory. |
- if (!target.HasCompatibleParametersWith(factory)) { |
- type = NewFinalizedMalformedType( |
- Error::Handle(), // No previous error. |
- cls, |
- factory.token_pos(), |
- "constructor '%s' has incompatible parameters with " |
- "redirecting factory '%s'", |
- String::Handle(target.name()).ToCString(), |
- String::Handle(factory.name()).ToCString()); |
- factory.SetRedirectionType(type); |
- ASSERT(factory.RedirectionTarget() == Function::null()); |
- return; |
+ if (FLAG_error_on_bad_override) { |
+ // Verify that the target is compatible with the redirecting factory. |
+ Error& error = Error::Handle(); |
+ if (!target.HasCompatibleParametersWith(factory, &error)) { |
+ type = NewFinalizedMalformedType( |
+ error, target_class, target.token_pos(), |
+ "constructor '%s' has incompatible parameters with " |
+ "redirecting factory '%s'", |
+ String::Handle(target.name()).ToCString(), |
+ String::Handle(factory.name()).ToCString()); |
+ factory.SetRedirectionType(type); |
+ ASSERT(factory.RedirectionTarget() == Function::null()); |
+ return; |
+ } |
} |
// Verify that the target is const if the redirecting factory is const. |
if (factory.is_const() && !target.is_const()) { |
- const Script& script = Script::Handle(cls.script()); |
- ReportError(script, factory.token_pos(), |
+ const Script& script = Script::Handle(target_class.script()); |
+ ReportError(Error::Handle(), // No previous error. |
+ script, target.token_pos(), |
"constructor '%s' must be const as required by redirecting" |
"const factory '%s'", |
String::Handle(target.name()).ToCString(), |
@@ -499,7 +501,7 @@ |
const AbstractTypeArguments& arguments = |
AbstractTypeArguments::Handle(type.arguments()); |
if (!arguments.IsNull()) { |
- intptr_t num_arguments = arguments.Length(); |
+ const intptr_t num_arguments = arguments.Length(); |
AbstractType& type_argument = AbstractType::Handle(); |
for (intptr_t i = 0; i < num_arguments; i++) { |
type_argument = arguments.TypeAt(i); |
@@ -768,7 +770,7 @@ |
AbstractTypeArguments& arguments = |
AbstractTypeArguments::Handle(parameterized_type.arguments()); |
if (!arguments.IsNull()) { |
- intptr_t num_arguments = arguments.Length(); |
+ const intptr_t num_arguments = arguments.Length(); |
AbstractType& type_argument = AbstractType::Handle(); |
for (intptr_t i = 0; i < num_arguments; i++) { |
type_argument = arguments.TypeAt(i); |
@@ -795,7 +797,8 @@ |
if (FLAG_error_on_malformed_type) { |
const Script& script = Script::Handle(cls.script()); |
const String& type_class_name = String::Handle(type_class.Name()); |
- ReportError(script, parameterized_type.token_pos(), |
+ ReportError(Error::Handle(), // No previous error. |
+ script, parameterized_type.token_pos(), |
"wrong number of type arguments for class '%s'", |
type_class_name.ToCString()); |
} |
@@ -1028,7 +1031,7 @@ |
AbstractType& type = AbstractType::Handle(); |
String& name = String::Handle(); |
Class& super_class = Class::Handle(); |
- intptr_t num_fields = array.Length(); |
+ const intptr_t num_fields = array.Length(); |
for (intptr_t i = 0; i < num_fields; i++) { |
field ^= array.At(i); |
type = field.type(); |
@@ -1042,7 +1045,8 @@ |
const String& class_name = String::Handle(cls.Name()); |
const String& super_class_name = String::Handle(super_class.Name()); |
const Script& script = Script::Handle(cls.script()); |
- ReportError(script, field.token_pos(), |
+ ReportError(Error::Handle(), // No previous error. |
+ script, field.token_pos(), |
"static field '%s' of class '%s' conflicts with " |
"instance member '%s' of super class '%s'", |
name.ToCString(), |
@@ -1058,7 +1062,8 @@ |
const String& class_name = String::Handle(cls.Name()); |
const String& super_class_name = String::Handle(super_class.Name()); |
const Script& script = Script::Handle(cls.script()); |
- ReportError(script, field.token_pos(), |
+ ReportError(Error::Handle(), // No previous error. |
+ script, field.token_pos(), |
"field '%s' of class '%s' conflicts with method '%s' " |
"of super class '%s'", |
name.ToCString(), |
@@ -1085,23 +1090,18 @@ |
!const_value.IsInstanceOf(type, |
AbstractTypeArguments::Handle(), |
&malformed_error))) { |
- // If the failure is due to a malformed type error, display it instead. |
- if (!malformed_error.IsNull()) { |
- ReportError(malformed_error); |
- } else { |
- const AbstractType& const_value_type = AbstractType::Handle( |
- const_value.GetType()); |
- const String& const_value_type_name = String::Handle( |
- const_value_type.UserVisibleName()); |
- const String& type_name = String::Handle(type.UserVisibleName()); |
- const Script& script = Script::Handle(cls.script()); |
- ReportError(script, field.token_pos(), |
- "error initializing const field '%s': type '%s' is not a " |
- "subtype of type '%s'", |
- name.ToCString(), |
- const_value_type_name.ToCString(), |
- type_name.ToCString()); |
- } |
+ const AbstractType& const_value_type = AbstractType::Handle( |
+ const_value.GetType()); |
+ const String& const_value_type_name = String::Handle( |
+ const_value_type.UserVisibleName()); |
+ const String& type_name = String::Handle(type.UserVisibleName()); |
+ const Script& script = Script::Handle(cls.script()); |
+ ReportError(malformed_error, script, field.token_pos(), |
+ "error initializing const field '%s': type '%s' is not a " |
+ "subtype of type '%s'", |
+ name.ToCString(), |
+ const_value_type_name.ToCString(), |
+ type_name.ToCString()); |
} |
} |
} |
@@ -1121,8 +1121,9 @@ |
array = cls.functions(); |
Function& function = Function::Handle(); |
Function& overridden_function = Function::Handle(); |
- intptr_t num_functions = array.Length(); |
+ const intptr_t num_functions = array.Length(); |
String& function_name = String::Handle(); |
+ Error& error = Error::Handle(); |
for (intptr_t i = 0; i < num_functions; i++) { |
function ^= array.At(i); |
ResolveAndFinalizeSignature(cls, function); |
@@ -1133,7 +1134,8 @@ |
const String& class_name = String::Handle(cls.Name()); |
const String& super_class_name = String::Handle(super_class.Name()); |
const Script& script = Script::Handle(cls.script()); |
- ReportError(script, function.token_pos(), |
+ ReportError(Error::Handle(), // No previous error. |
+ script, function.token_pos(), |
"static function '%s' of class '%s' conflicts with " |
"instance member '%s' of super class '%s'", |
function_name.ToCString(), |
@@ -1143,17 +1145,19 @@ |
} |
// The function may be a still unresolved redirecting factory. Do not yet |
// try to resolve it in order to avoid cycles in class finalization. |
- } else { |
+ } else if (FLAG_error_on_bad_override && !function.IsConstructor()) { |
+ // A constructor cannot override anything. |
for (int i = 0; i < interfaces.Length(); i++) { |
super_class ^= interfaces.At(i); |
overridden_function = super_class.LookupDynamicFunction(function_name); |
if (!overridden_function.IsNull() && |
- !function.HasCompatibleParametersWith(overridden_function)) { |
+ !function.HasCompatibleParametersWith(overridden_function, |
+ &error)) { |
// Function types are purposely not checked for subtyping. |
const String& class_name = String::Handle(cls.Name()); |
const String& super_class_name = String::Handle(super_class.Name()); |
const Script& script = Script::Handle(cls.script()); |
- ReportError(script, function.token_pos(), |
+ ReportError(error, script, function.token_pos(), |
"class '%s' overrides function '%s' of super class '%s' " |
"with incompatible parameters", |
class_name.ToCString(), |
@@ -1169,7 +1173,8 @@ |
const String& class_name = String::Handle(cls.Name()); |
const String& super_class_name = String::Handle(super_class.Name()); |
const Script& script = Script::Handle(cls.script()); |
- ReportError(script, function.token_pos(), |
+ ReportError(Error::Handle(), // No previous error. |
+ script, function.token_pos(), |
"getter '%s' of class '%s' conflicts with " |
"function '%s' of super class '%s'", |
name.ToCString(), |
@@ -1186,7 +1191,8 @@ |
const String& class_name = String::Handle(cls.Name()); |
const String& super_class_name = String::Handle(super_class.Name()); |
const Script& script = Script::Handle(cls.script()); |
- ReportError(script, function.token_pos(), |
+ ReportError(Error::Handle(), // No previous error. |
+ script, function.token_pos(), |
"function '%s' of class '%s' conflicts with " |
"getter '%s' of super class '%s'", |
function_name.ToCString(), |
@@ -1240,7 +1246,8 @@ |
// TODO(hausner): handle type bounds. |
if (!param_bound.IsObjectType()) { |
const Script& script = Script::Handle(mixapp_class.script()); |
- ReportError(script, param.token_pos(), |
+ ReportError(Error::Handle(), // No previous error. |
+ script, param.token_pos(), |
"type parameter '%s': type bounds not yet" |
" implemented for mixins\n", |
param_name.ToCString()); |
@@ -1282,7 +1289,8 @@ |
// TODO(hausner): handle type bounds. |
if (!param_bound.IsObjectType()) { |
const Script& script = Script::Handle(mixapp_class.script()); |
- ReportError(script, param.token_pos(), |
+ ReportError(Error::Handle(), // No previous error. |
+ script, param.token_pos(), |
"type parameter '%s': type bounds not yet" |
" implemented for mixins\n", |
param_name.ToCString()); |
@@ -1333,7 +1341,8 @@ |
if (!mixin_super_type.IsObjectType()) { |
const Script& script = Script::Handle(cls.script()); |
const String& class_name = String::Handle(mixin_cls.Name()); |
- ReportError(script, cls.token_pos(), |
+ ReportError(Error::Handle(), // No previous error. |
+ script, cls.token_pos(), |
"mixin class %s must extend class Object", |
class_name.ToCString()); |
} |
@@ -1359,7 +1368,7 @@ |
const String& super_name = String::Handle(super_class.Name()); |
const Type& dynamic_type = Type::Handle(Type::DynamicType()); |
const Array& functions = Array::Handle(super_class.functions()); |
- intptr_t num_functions = functions.Length(); |
+ const intptr_t num_functions = functions.Length(); |
Function& func = Function::Handle(); |
for (intptr_t i = 0; i < num_functions; i++) { |
func ^= functions.At(i); |
@@ -1437,7 +1446,8 @@ |
// A mixin class must not have explicit constructors. |
if (!func.IsImplicitConstructor()) { |
const Script& script = Script::Handle(isolate, cls.script()); |
- ReportError(script, cls.token_pos(), |
+ ReportError(Error::Handle(), // No previous error. |
+ script, cls.token_pos(), |
"mixin class %s must not have constructors\n", |
String::Handle(isolate, mixin_cls.Name()).ToCString()); |
} |
@@ -1489,7 +1499,8 @@ |
if (!IsSuperCycleFree(cls)) { |
const String& name = String::Handle(cls.Name()); |
const Script& script = Script::Handle(cls.script()); |
- ReportError(script, cls.token_pos(), |
+ ReportError(Error::Handle(), // No previous error. |
+ script, cls.token_pos(), |
"class '%s' has a cycle in its superclass relationship", |
name.ToCString()); |
} |
@@ -1523,7 +1534,8 @@ |
if (!IsAliasCycleFree(cls, &visited_aliases)) { |
const String& name = String::Handle(cls.Name()); |
const Script& script = Script::Handle(cls.script()); |
- ReportError(script, cls.token_pos(), |
+ ReportError(Error::Handle(), // No previous error. |
+ script, cls.token_pos(), |
"typedef '%s' illegally refers to itself", |
name.ToCString()); |
} |
@@ -1561,7 +1573,8 @@ |
ASSERT(super_type.IsNull() || super_type.IsFinalized()); |
if (!super_type.IsNull() && interface_type.Equals(super_type)) { |
const Script& script = Script::Handle(cls.script()); |
- ReportError(script, cls.token_pos(), |
+ ReportError(Error::Handle(), // No previous error. |
+ script, cls.token_pos(), |
"super type '%s' may not be listed in " |
"implements clause of class '%s'", |
String::Handle(super_type.Name()).ToCString(), |
@@ -1571,7 +1584,8 @@ |
seen_interf ^= interface_types.At(j); |
if (interface_type.Equals(seen_interf)) { |
const Script& script = Script::Handle(cls.script()); |
- ReportError(script, cls.token_pos(), |
+ ReportError(Error::Handle(), // No previous error. |
+ script, cls.token_pos(), |
"interface '%s' appears twice in " |
"implements clause of class '%s'", |
String::Handle(interface_type.Name()).ToCString(), |
@@ -1591,9 +1605,15 @@ |
ASSERT(!super_class.IsNull()); |
super_class.AddDirectSubclass(cls); |
} |
- // Top level classes are parsed eagerly so just finalize it. |
+ // A top level class is parsed eagerly so just finalize it. |
if (cls.IsTopLevel()) { |
FinalizeClass(cls); |
+ } else { |
+ // This class should not contain any fields or functions yet, because it has |
+ // not been compiled yet. Since 'ResolveAndFinalizeMemberTypes(cls)' has not |
+ // been called yet, unfinalized member types could choke the snapshotter. |
+ ASSERT(Array::Handle(cls.fields()).Length() == 0); |
+ ASSERT(Array::Handle(cls.functions()).Length() == 0); |
} |
} |
@@ -1619,6 +1639,17 @@ |
} |
// Mark as parsed and finalized. |
cls.Finalize(); |
+ // Mixin typedef classes may still lack their implicit constructor. |
+ // TODO(regis): Implement mixin typedefs with an alias class. |
+ if (cls.is_synthesized_class() && |
+ (Array::Handle(cls.functions()).Length() == 0)) { |
siva
2013/08/12 02:56:43
could be written as:
if (cls.is_synthesized_class
regis
2013/08/12 17:45:27
Done.
|
+ Parser::AddImplicitConstructor(cls); |
+ } |
+ // Every class should have at least a constructor, unless it is a top level |
+ // class or a signature class. |
+ ASSERT(cls.IsTopLevel() || |
+ cls.IsSignatureClass() || |
+ (Array::Handle(cls.functions()).Length() > 0)); |
// Resolve and finalize all member types. |
ResolveAndFinalizeMemberTypes(cls); |
// Run additional checks after all types are finalized. |
@@ -1715,23 +1746,26 @@ |
} |
-void ClassFinalizer::CollectTypeArguments(const Class& cls, |
- const Type& type, |
- const GrowableObjectArray& collected_args) { |
+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(); |
+ const intptr_t num_type_parameters = type_class.NumTypeParameters(); |
+ const 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()); |
+ ReportError(Error::Handle(), // No previous error. |
+ 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); |
@@ -1804,13 +1838,17 @@ |
void ClassFinalizer::ResolveSuperTypeAndInterfaces( |
const Class& cls, GrowableArray<intptr_t>* visited) { |
ASSERT(visited != NULL); |
+ if (FLAG_trace_class_finalization) { |
+ OS::Print("Resolving super and interfaces: %s\n", cls.ToCString()); |
+ } |
const intptr_t cls_index = cls.id(); |
for (int i = 0; i < visited->length(); i++) { |
if ((*visited)[i] == cls_index) { |
// We have already visited class 'cls'. We found a cycle. |
const String& class_name = String::Handle(cls.Name()); |
const Script& script = Script::Handle(cls.script()); |
- ReportError(script, cls.token_pos(), |
+ ReportError(Error::Handle(), // No previous error. |
+ script, cls.token_pos(), |
"cyclic reference found for class '%s'", |
class_name.ToCString()); |
} |
@@ -1847,10 +1885,19 @@ |
} |
if (super_type.IsDynamicType()) { |
const Script& script = Script::Handle(cls.script()); |
- ReportError(script, cls.token_pos(), |
+ ReportError(Error::Handle(), // No previous error. |
+ script, cls.token_pos(), |
"class '%s' may not extend 'dynamic'", |
String::Handle(cls.Name()).ToCString()); |
} |
+ if (Class::Handle(super_type.type_class()).IsSignatureClass()) { |
siva
2013/08/12 02:56:43
Why not move the assignment
interface_class = sup
regis
2013/08/12 17:45:27
Done.
|
+ const Script& script = Script::Handle(cls.script()); |
+ ReportError(Error::Handle(), // No previous error. |
+ script, cls.token_pos(), |
+ "class '%s' may not extend function type alias '%s'", |
+ String::Handle(cls.Name()).ToCString(), |
+ String::Handle(super_type.UserVisibleName()).ToCString()); |
+ } |
interface_class = super_type.type_class(); |
// If cls belongs to core lib or to core lib's implementation, restrictions |
@@ -1896,7 +1943,8 @@ |
} |
if (is_error) { |
const Script& script = Script::Handle(cls.script()); |
- ReportError(script, cls.token_pos(), |
+ ReportError(Error::Handle(), // No previous error. |
+ script, cls.token_pos(), |
"'%s' is not allowed to extend '%s'", |
String::Handle(cls.Name()).ToCString(), |
String::Handle(interface_class.Name()).ToCString()); |
@@ -1915,14 +1963,16 @@ |
} |
if (interface.IsDynamicType()) { |
const Script& script = Script::Handle(cls.script()); |
- ReportError(script, cls.token_pos(), |
+ ReportError(Error::Handle(), // No previous error. |
+ script, cls.token_pos(), |
"'dynamic' may not be used as interface"); |
} |
interface_class = interface.type_class(); |
if (interface_class.IsSignatureClass()) { |
const Script& script = Script::Handle(cls.script()); |
- ReportError(script, cls.token_pos(), |
- "'%s' is used where an interface or class name is expected", |
+ ReportError(Error::Handle(), // No previous error. |
+ script, cls.token_pos(), |
+ "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 |
@@ -1938,7 +1988,8 @@ |
(interface.IsFunctionType() && !cls.IsSignatureClass()) || |
interface.IsDynamicType()) { |
const Script& script = Script::Handle(cls.script()); |
- ReportError(script, cls.token_pos(), |
+ 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()); |
@@ -1966,7 +2017,8 @@ |
const String& class_name = String::Handle(cls.Name()); |
const String& field_name = String::Handle(field.name()); |
const Script& script = Script::Handle(cls.script()); |
- ReportError(script, field.token_pos(), |
+ ReportError(Error::Handle(), // No previous error. |
+ script, field.token_pos(), |
"const class '%s' has non-final field '%s'", |
class_name.ToCString(), field_name.ToCString()); |
} |
@@ -2091,13 +2143,19 @@ |
} |
-void ClassFinalizer::ReportError(const Script& script, |
+void ClassFinalizer::ReportError(const Error& prev_error, |
+ const Script& script, |
intptr_t token_pos, |
const char* format, ...) { |
va_list args; |
va_start(args, format); |
- const Error& error = Error::Handle( |
- Parser::FormatError(script, token_pos, "Error", format, args)); |
+ Error& error = Error::Handle(); |
+ if (prev_error.IsNull()) { |
+ error ^= Parser::FormatError(script, token_pos, "Error", format, args); |
+ } else { |
+ error ^= Parser::FormatErrorWithAppend( |
+ prev_error, script, token_pos, "Error", format, args); |
+ } |
va_end(args); |
ReportError(error); |
} |