Index: runtime/vm/class_finalizer.cc |
=================================================================== |
--- runtime/vm/class_finalizer.cc (revision 26300) |
+++ runtime/vm/class_finalizer.cc (working copy) |
@@ -932,10 +932,11 @@ |
} |
-// Check if an instance field or method of same name exists |
+// Check if an instance field, getter, or method of same name exists |
// in any super class. |
static RawClass* FindSuperOwnerOfInstanceMember(const Class& cls, |
- const String& name) { |
+ const String& name, |
+ const String& getter_name) { |
Class& super_class = Class::Handle(); |
Function& function = Function::Handle(); |
Field& field = Field::Handle(); |
@@ -945,6 +946,10 @@ |
if (!function.IsNull() && !function.is_static()) { |
return super_class.raw(); |
} |
+ function = super_class.LookupFunction(getter_name); |
+ if (!function.IsNull() && !function.is_static()) { |
+ return super_class.raw(); |
+ } |
field = super_class.LookupField(name); |
if (!field.IsNull() && !field.is_static()) { |
return super_class.raw(); |
@@ -1019,17 +1024,30 @@ |
// Note that getters and setters are explicitly listed as such in the list of |
// functions of a class, so we do not need to consider fields as implicitly |
// generating getters and setters. |
- // The only compile errors we report are therefore: |
- // - a getter having the same name as a method (but not a getter) in a super |
- // class or in a subclass. |
- // - a static field, instance field, or static method (but not an instance |
- // method) having the same name as an instance member in a super class. |
+ // Most overriding conflicts are only static warnings, i.e. they are not |
+ // reported as compile-time errors by the vm. However, signature conflicts in |
+ // overrides can be reported if the flag --error_on_bad_override is specified. |
+ // Static warning examples are: |
+ // - a static getter 'v' conflicting with an inherited instance setter 'v='. |
+ // - a static setter 'v=' conflicting with an inherited instance member 'v'. |
+ // - an instance member 'v' conflicting with an accessible static member 'v' |
+ // or 'v=' of a super class (except that an instance method 'v' does not |
+ // conflict with an accessible static setter 'v=' of a super class). |
+ // The compile-time errors we report are: |
+ // - a static member 'v' conflicting with an inherited instance member 'v'. |
+ // - a static setter 'v=' conflicting with an inherited instance setter 'v='. |
+ // - an instance method conflicting with an inherited instance field or |
+ // instance getter. |
+ // - an instance field or instance getter conflicting with an inherited |
+ // instance method. |
// Resolve type of fields and check for conflicts in super classes. |
Array& array = Array::Handle(cls.fields()); |
Field& field = Field::Handle(); |
AbstractType& type = AbstractType::Handle(); |
String& name = String::Handle(); |
+ String& getter_name = String::Handle(); |
+ String& setter_name = String::Handle(); |
Class& super_class = Class::Handle(); |
const intptr_t num_fields = array.Length(); |
for (intptr_t i = 0; i < num_fields; i++) { |
@@ -1040,7 +1058,8 @@ |
field.set_type(type); |
name = field.name(); |
if (field.is_static()) { |
- super_class = FindSuperOwnerOfInstanceMember(cls, name); |
+ getter_name = Field::GetterSymbol(name); |
+ super_class = FindSuperOwnerOfInstanceMember(cls, name, getter_name); |
if (!super_class.IsNull()) { |
const String& class_name = String::Handle(cls.Name()); |
const String& super_class_name = String::Handle(super_class.Name()); |
@@ -1054,6 +1073,25 @@ |
name.ToCString(), |
super_class_name.ToCString()); |
} |
+ // An implicit setter is not generated for a static field, therefore, we |
+ // cannot rely on the code below handling the static setter case to report |
+ // a conflict with an instance setter. So we check explicitly here. |
+ setter_name = Field::SetterSymbol(name); |
+ super_class = FindSuperOwnerOfFunction(cls, setter_name); |
+ if (!super_class.IsNull()) { |
+ 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(Error::Handle(), // No previous error. |
+ script, field.token_pos(), |
+ "static field '%s' of class '%s' conflicts with " |
+ "instance setter '%s=' of super class '%s'", |
+ name.ToCString(), |
+ class_name.ToCString(), |
+ name.ToCString(), |
+ super_class_name.ToCString()); |
+ } |
+ |
} else { |
// Instance field. Check whether the field overrides a method |
// (but not getter). |
@@ -1112,7 +1150,6 @@ |
// Therefore, we undo the optimization performed by the parser, i.e. |
// we create an implicit static final getter and reset the field value |
// to the sentinel value. |
- const String& getter_name = String::Handle(Field::GetterSymbol(name)); |
const Function& getter = Function::Handle( |
Function::New(getter_name, |
RawFunction::kImplicitStaticFinalGetter, |
@@ -1146,52 +1183,78 @@ |
Function& function = Function::Handle(); |
Function& overridden_function = Function::Handle(); |
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); |
- function_name = function.name(); |
- if (function.is_static()) { |
- super_class = FindSuperOwnerOfInstanceMember(cls, function_name); |
- if (!super_class.IsNull()) { |
- 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(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(), |
- class_name.ToCString(), |
- function_name.ToCString(), |
- super_class_name.ToCString()); |
- } |
- // 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 if (FLAG_error_on_bad_override && !function.IsConstructor()) { |
+ name = function.name(); |
+ if (FLAG_error_on_bad_override && // Report signature conflicts only. |
+ !function.is_static() && !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); |
+ overridden_function = super_class.LookupDynamicFunction(name); |
if (!overridden_function.IsNull() && |
!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(error, script, function.token_pos(), |
- "class '%s' overrides function '%s' of super class '%s' " |
+ "class '%s' overrides method '%s' of super class '%s' " |
"with incompatible parameters", |
class_name.ToCString(), |
- function_name.ToCString(), |
+ name.ToCString(), |
super_class_name.ToCString()); |
} |
} |
} |
- if (function.IsGetterFunction()) { |
- name = Field::NameFromGetter(function_name); |
+ if (function.IsSetterFunction() || function.IsImplicitSetterFunction()) { |
+ if (function.is_static()) { |
+ super_class = FindSuperOwnerOfFunction(cls, name); |
+ if (!super_class.IsNull()) { |
+ 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(Error::Handle(), // No previous error. |
+ script, function.token_pos(), |
+ "static setter '%s=' of class '%s' conflicts with " |
+ "instance setter '%s=' of super class '%s'", |
+ name.ToCString(), |
+ class_name.ToCString(), |
+ name.ToCString(), |
+ super_class_name.ToCString()); |
+ } |
+ } |
+ continue; |
+ } |
+ if (function.IsGetterFunction() || function.IsImplicitGetterFunction()) { |
+ getter_name = name.raw(); |
+ name = Field::NameFromGetter(getter_name); |
+ } else { |
+ getter_name = Field::GetterSymbol(name); |
+ } |
+ if (function.is_static()) { |
+ super_class = FindSuperOwnerOfInstanceMember(cls, name, getter_name); |
+ if (!super_class.IsNull()) { |
+ 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(Error::Handle(), // No previous error. |
+ script, function.token_pos(), |
+ "static %s '%s' of class '%s' conflicts with " |
+ "instance member '%s' of super class '%s'", |
+ (function.IsGetterFunction() || |
+ function.IsImplicitGetterFunction()) ? "getter" : "method", |
+ name.ToCString(), |
+ class_name.ToCString(), |
+ name.ToCString(), |
+ super_class_name.ToCString()); |
+ } |
+ // 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 if (function.IsGetterFunction() || |
+ function.IsImplicitGetterFunction()) { |
super_class = FindSuperOwnerOfFunction(cls, name); |
if (!super_class.IsNull()) { |
const String& class_name = String::Handle(cls.Name()); |
@@ -1200,28 +1263,28 @@ |
ReportError(Error::Handle(), // No previous error. |
script, function.token_pos(), |
"getter '%s' of class '%s' conflicts with " |
- "function '%s' of super class '%s'", |
+ "method '%s' of super class '%s'", |
name.ToCString(), |
class_name.ToCString(), |
name.ToCString(), |
super_class_name.ToCString()); |
} |
- } else if (!function.IsSetterFunction()) { |
+ } else if (!function.IsSetterFunction() && |
+ !function.IsImplicitSetterFunction()) { |
// A function cannot conflict with a setter, since they cannot |
// have the same name. Thus, we do not need to check setters. |
- name = Field::GetterName(function_name); |
- super_class = FindSuperOwnerOfFunction(cls, name); |
+ super_class = FindSuperOwnerOfFunction(cls, getter_name); |
if (!super_class.IsNull()) { |
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(Error::Handle(), // No previous error. |
script, function.token_pos(), |
- "function '%s' of class '%s' conflicts with " |
+ "method '%s' of class '%s' conflicts with " |
"getter '%s' of super class '%s'", |
- function_name.ToCString(), |
+ name.ToCString(), |
class_name.ToCString(), |
- function_name.ToCString(), |
+ name.ToCString(), |
super_class_name.ToCString()); |
} |
} |