| Index: runtime/vm/class_finalizer.cc
 | 
| ===================================================================
 | 
| --- runtime/vm/class_finalizer.cc	(revision 26025)
 | 
| +++ 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() &&
 | 
| +      (cls.functions() == Object::empty_array().raw())) {
 | 
| +    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,12 +1885,21 @@
 | 
|    }
 | 
|    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());
 | 
|    }
 | 
| +  interface_class = super_type.type_class();
 | 
| +  if (interface_class.IsSignatureClass()) {
 | 
| +    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
 | 
|    // about allowed interfaces are lifted.
 | 
|    if (!cls_belongs_to_core_lib) {
 | 
| @@ -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);
 | 
|  }
 | 
| 
 |