| Index: runtime/vm/class_finalizer.cc
|
| ===================================================================
|
| --- runtime/vm/class_finalizer.cc (revision 5063)
|
| +++ runtime/vm/class_finalizer.cc (working copy)
|
| @@ -162,19 +162,26 @@
|
| class_function = test_class.LookupDynamicFunction(function_name);
|
| }
|
| if (class_function.IsNull()) {
|
| - OS::Print("%s implements '%s' missing: '%s'\n",
|
| - class_name.ToCString(),
|
| - interface_name.ToCString(),
|
| - function_name.ToCString());
|
| - } else if (!class_function.IsSubtypeOf(TypeArguments::Handle(),
|
| + OS::PrintErr("%s implements '%s' missing: '%s'\n",
|
| + class_name.ToCString(),
|
| + interface_name.ToCString(),
|
| + function_name.ToCString());
|
| + } else {
|
| + Error& malformed_error = Error::Handle();
|
| + if (!class_function.IsSubtypeOf(TypeArguments::Handle(),
|
| interface_function,
|
| - TypeArguments::Handle())) {
|
| - OS::Print("The type of instance method '%s' in class '%s' is not a "
|
| - "subtype of the type of '%s' in interface '%s'\n",
|
| - function_name.ToCString(),
|
| - class_name.ToCString(),
|
| - function_name.ToCString(),
|
| - interface_name.ToCString());
|
| + TypeArguments::Handle(),
|
| + &malformed_error)) {
|
| + if (!malformed_error.IsNull()) {
|
| + OS::PrintErr("%s\n", malformed_error.ToErrorCString());
|
| + }
|
| + OS::PrintErr("The type of instance method '%s' in class '%s' is not "
|
| + "a subtype of the type of '%s' in interface '%s'\n",
|
| + function_name.ToCString(),
|
| + class_name.ToCString(),
|
| + function_name.ToCString(),
|
| + interface_name.ToCString());
|
| + }
|
| }
|
| }
|
| }
|
| @@ -453,7 +460,8 @@
|
| parameterized_type.set_type_class(Object::Handle(type_class.raw()));
|
| } else {
|
| // The type class could not be resolved. The type is malformed.
|
| - FinalizeMalformedType(cls, parameterized_type, finalization,
|
| + FinalizeMalformedType(Error::Handle(), // No previous error.
|
| + cls, parameterized_type, finalization,
|
| "cannot resolve class name '%s' from '%s'",
|
| String::Handle(unresolved_class.Name()).ToCString(),
|
| String::Handle(cls.Name()).ToCString());
|
| @@ -553,6 +561,7 @@
|
| if (parameterized_type.IsBeingFinalized()) {
|
| // Self reference detected. The type is malformed.
|
| FinalizeMalformedType(
|
| + Error::Handle(), // No previous error.
|
| cls, parameterized_type, finalization,
|
| "type '%s' illegally refers to itself",
|
| String::Handle(parameterized_type.Name()).ToCString());
|
| @@ -612,6 +621,7 @@
|
| if (!arguments.IsNull() && (arguments.Length() != num_type_parameters)) {
|
| // Wrong number of type arguments. The type is malformed.
|
| FinalizeMalformedType(
|
| + Error::Handle(), // No previous error.
|
| cls, parameterized_type, finalization,
|
| "wrong number of type arguments in type '%s'",
|
| String::Handle(parameterized_type.Name()).ToCString());
|
| @@ -652,8 +662,27 @@
|
| // Mark the type as finalized.
|
| parameterized_type.set_is_finalized();
|
|
|
| - // No need to verify the upper bounds of the finalized type arguments, since
|
| - // bound errors are static type errors, which are not reported by the VM.
|
| + // Upper bounds of the finalized type arguments are only verified in checked
|
| + // mode, since bound errors are never reported by the vm in production mode.
|
| + if (FLAG_enable_type_checks && full_arguments.IsInstantiated()) {
|
| + ResolveAndFinalizeUpperBounds(type_class);
|
| + Error& malformed_error = Error::Handle();
|
| + // Pass the full type argument vector as the bounds instantiator.
|
| + if (!full_arguments.IsWithinBoundsOf(type_class,
|
| + full_arguments,
|
| + &malformed_error)) {
|
| + ASSERT(!malformed_error.IsNull());
|
| + // The type argument vector of the type is not within bounds. The type
|
| + // is malformed. Prepend malformed_error to new malformed type error in
|
| + // order to report both locations.
|
| + FinalizeMalformedType(
|
| + malformed_error,
|
| + cls, parameterized_type, finalization,
|
| + "type arguments of type '%s' are not within bounds",
|
| + String::Handle(parameterized_type.Name()).ToCString());
|
| + return parameterized_type.raw();
|
| + }
|
| + }
|
| } else {
|
| parameterized_type.set_is_finalized();
|
| }
|
| @@ -1173,7 +1202,8 @@
|
| }
|
|
|
|
|
| -void ClassFinalizer::FinalizeMalformedType(const Class& cls,
|
| +void ClassFinalizer::FinalizeMalformedType(const Error& prev_error,
|
| + const Class& cls,
|
| const Type& type,
|
| FinalizationKind finalization,
|
| const char* format, ...) {
|
| @@ -1182,8 +1212,13 @@
|
| LanguageError& error = LanguageError::Handle();
|
| if ((finalization == kFinalizeWellFormed) || FLAG_enable_type_checks) {
|
| const Script& script = Script::Handle(cls.script());
|
| - error ^=
|
| - Parser::FormatError(script, type.token_index(), "Error", format, args);
|
| + if (prev_error.IsNull()) {
|
| + error ^= Parser::FormatError(
|
| + script, type.token_index(), "Error", format, args);
|
| + } else {
|
| + error ^= Parser::FormatErrorWithAppend(
|
| + prev_error, script, type.token_index(), "Error", format, args);
|
| + }
|
| if (finalization == kFinalizeWellFormed) {
|
| ReportError(error);
|
| }
|
| @@ -1195,8 +1230,14 @@
|
| // In checked mode, mark type as malformed.
|
| type.set_malformed_error(error);
|
| }
|
| - type.set_is_finalized();
|
| - type.Canonicalize();
|
| + if (!type.IsFinalized()) {
|
| + type.set_is_finalized();
|
| + type.Canonicalize();
|
| + } else {
|
| + // The only case where the malformed type was already finalized is when its
|
| + // type arguments are not within bounds. In that case, we have a prev_error.
|
| + ASSERT(!prev_error.IsNull());
|
| + }
|
| }
|
|
|
|
|
|
|