Chromium Code Reviews| Index: runtime/vm/class_finalizer.cc |
| =================================================================== |
| --- runtime/vm/class_finalizer.cc (revision 24923) |
| +++ runtime/vm/class_finalizer.cc (working copy) |
| @@ -255,15 +255,59 @@ |
| // Resolve unresolved_class in the library of cls, or return null. |
| -RawClass* ClassFinalizer::ResolveClass( |
| - const Class& cls, const UnresolvedClass& unresolved_class) { |
| +RawClass* ClassFinalizer::ResolveClass(const Class& cls, |
| + const UnresolvedClass& unresolved_class, |
| + Error* ambiguity_error) { |
| const String& class_name = String::Handle(unresolved_class.ident()); |
| Library& lib = Library::Handle(); |
| Class& resolved_class = Class::Handle(); |
| if (unresolved_class.library_prefix() == LibraryPrefix::null()) { |
| lib = cls.library(); |
| ASSERT(!lib.IsNull()); |
| - resolved_class = lib.LookupClass(class_name); |
| + // TODO(regis): Call lib.LookupClass(class_name, ambiguity_error) instead |
|
hausner
2013/07/11 22:18:27
Maybe you are right and this ambiguity test should
regis
2013/07/12 00:02:38
Will do in a following cl.
|
| + // once it takes the ambiguity_error parameter. |
| + |
| + // First check if name is found in the local scope of the library. |
| + Object& obj = Object::Handle(lib.LookupLocalObject(class_name)); |
| + if (!obj.IsNull() && obj.IsClass()) { |
| + return Class::Cast(obj).raw(); |
| + } |
| + // Now check if class_name is found in any imported libs. |
| + String& first_lib_url = String::Handle(); |
| + Namespace& import = Namespace::Handle(); |
| + Library& import_lib = Library::Handle(); |
| + for (intptr_t i = 0; i < lib.num_imports(); i++) { |
| + import ^= lib.ImportAt(i); |
| + obj = import.Lookup(class_name); |
| + if (!obj.IsNull()) { |
| + import_lib = import.library(); |
| + if (!first_lib_url.IsNull()) { |
| + // Found duplicate definition. |
| + const Script& script = Script::Handle(cls.script()); |
| + if (first_lib_url.raw() == lib.url()) { |
| + *ambiguity_error = Parser::FormatErrorMsg( |
| + script, unresolved_class.token_pos(), "Error", |
| + "ambiguous reference to '%s', " |
| + "as library '%s' is imported multiple times", |
| + class_name.ToCString(), |
| + first_lib_url.ToCString()); |
| + } else { |
| + *ambiguity_error = Parser::FormatErrorMsg( |
| + script, unresolved_class.token_pos(), "Error", |
| + "ambiguous reference: " |
| + "'%s' is defined in library '%s' and also in '%s'", |
| + class_name.ToCString(), |
| + first_lib_url.ToCString(), |
| + String::Handle(lib.url()).ToCString()); |
| + } |
| + return Class::null(); |
| + } |
| + first_lib_url = lib.url(); |
| + if (obj.IsClass()) { |
| + resolved_class = Class::Cast(obj).raw(); |
| + } |
| + } |
| + } |
| } else { |
| LibraryPrefix& lib_prefix = LibraryPrefix::Handle(); |
| lib_prefix = unresolved_class.library_prefix(); |
| @@ -317,6 +361,19 @@ |
| ASSERT(factory.RedirectionTarget() == Function::null()); |
| return; |
| } |
| + ASSERT(!type.IsTypeParameter()); // Resolved in parser. |
| + if (type.IsDynamicType()) { |
| + // Replace the type with a malformed type and compile a throw when called. |
| + type = NewFinalizedMalformedType( |
| + Error::Handle(), // No previous error. |
| + cls, |
| + factory.token_pos(), |
| + kResolveTypeParameters, // No compile-time error. |
| + "factory may not redirect to 'dynamic'"); |
| + factory.SetRedirectionType(type); |
| + ASSERT(factory.RedirectionTarget() == Function::null()); |
| + return; |
| + } |
| const Class& target_class = Class::Handle(type.type_class()); |
| String& target_class_name = String::Handle(target_class.Name()); |
| String& target_name = String::Handle( |
| @@ -339,7 +396,7 @@ |
| Error::Handle(), // No previous error. |
| cls, |
| factory.token_pos(), |
| - kTryResolve, // No compile-time error. |
| + kResolveTypeParameters, // No compile-time error. |
| "class '%s' has no constructor or factory named '%s'", |
| target_class_name.ToCString(), |
| user_visible_target_name.ToCString()); |
| @@ -354,7 +411,7 @@ |
| Error::Handle(), // No previous error. |
| cls, |
| factory.token_pos(), |
| - kTryResolve, // No compile-time error. |
| + kResolveTypeParameters, // No compile-time error. |
| "constructor '%s' has incompatible parameters with " |
| "redirecting factory '%s'", |
| String::Handle(target.name()).ToCString(), |
| @@ -437,8 +494,9 @@ |
| // Lookup the type class. |
| const UnresolvedClass& unresolved_class = |
| UnresolvedClass::Handle(type.unresolved_class()); |
| + Error& ambiguous_error = Error::Handle(); |
| const Class& type_class = |
| - Class::Handle(ResolveClass(cls, unresolved_class)); |
| + Class::Handle(ResolveClass(cls, unresolved_class, &ambiguous_error)); |
| // Replace unresolved class with resolved type class. |
| const Type& parameterized_type = Type::Cast(type); |
| @@ -446,7 +504,7 @@ |
| parameterized_type.set_type_class(type_class); |
| } else { |
| // The type class could not be resolved. The type is malformed. |
| - FinalizeMalformedType(Error::Handle(), // No previous error. |
| + FinalizeMalformedType(ambiguous_error, // May be null. |
| cls, parameterized_type, finalization, |
| "cannot resolve class name '%s' from '%s'", |
| String::Handle(unresolved_class.Name()).ToCString(), |
| @@ -870,7 +928,8 @@ |
| // If a bound error occurred, return a BoundedType with a malformed bound. |
| // The malformed bound will be ignored in production mode. |
| if (!bound_error.IsNull()) { |
| - FinalizationKind bound_finalization = kTryResolve; // No compile error. |
| + // No compile-time error during finalization. |
| + FinalizationKind bound_finalization = kResolveTypeParameters; |
| if (FLAG_enable_type_checks || FLAG_error_on_malformed_type) { |
| bound_finalization = finalization; |
| } |
| @@ -1062,6 +1121,41 @@ |
| super_class_name.ToCString()); |
| } |
| } |
| + if ((FLAG_enable_type_checks || FLAG_error_on_malformed_type) && |
| + field.is_static() && (field.value() != Object::sentinel().raw())) { |
| + // The parser does not preset the value if the type is a type parameter or |
| + // is parameterized. |
| + Error& malformed_error = Error::Handle(); |
| + if (type.IsMalformed()) { |
| + malformed_error = type.malformed_error(); |
| + } |
| + ASSERT(type.IsInstantiated() || type.IsMalformed()); |
| + const Instance& const_value = Instance::Handle(field.value()); |
| + if (!const_value.IsNull() && |
| + (!malformed_error.IsNull() || |
| + (!type.IsDynamicType() && |
| + !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()); |
| + } |
| + } |
| + } |
| } |
| // Collect interfaces, super interfaces, and super classes of this class. |
| const GrowableObjectArray& interfaces = |
| @@ -1709,6 +1803,12 @@ |
| // Resolve super type. Failures lead to a longjmp. |
| ResolveType(cls, super_type, kCanonicalizeWellFormed); |
| + if (super_type.IsDynamicType()) { |
| + const Script& script = Script::Handle(cls.script()); |
| + ReportError(script, cls.token_pos(), |
| + "class '%s' may not extend 'dynamic'", |
| + String::Handle(cls.Name()).ToCString()); |
| + } |
| interface_class = super_type.type_class(); |
| // If cls belongs to core lib or to core lib's implementation, restrictions |
| @@ -1767,11 +1867,11 @@ |
| for (intptr_t i = 0; i < super_interfaces.Length(); i++) { |
| interface ^= super_interfaces.At(i); |
| ResolveType(cls, interface, kCanonicalizeWellFormed); |
| - if (interface.IsTypeParameter()) { |
| + ASSERT(!interface.IsTypeParameter()); // Should be detected by parser. |
| + if (interface.IsDynamicType()) { |
| const Script& script = Script::Handle(cls.script()); |
| ReportError(script, cls.token_pos(), |
| - "type parameter '%s' cannot be used as interface", |
| - String::Handle(interface.Name()).ToCString()); |
| + "'dynamic' may not be used as interface"); |
| } |
| interface_class = interface.type_class(); |
| if (interface_class.IsSignatureClass()) { |