Enumerate URIs of all types in type errors in order to help the user diagnose

the error (it was previously only printed for types with identical names).
Cleanup and simplify construction of type errors.

R=hausner@google.com, srdjan@google.com

Review URL: https://codereview.chromium.org/1778133002 .
This commit is contained in:
Regis Crelier 2016-03-09 15:16:47 -08:00
parent 4d48fa56d0
commit ba69c8a898
12 changed files with 222 additions and 229 deletions

View file

@ -53,7 +53,7 @@ DEFINE_NATIVE_ENTRY(AssertionError_throwNew, 2) {
// Allocate and throw a new TypeError or CastError.
// Arg0: index of the token of the failed type check.
// Arg1: src value.
// Arg2: dst type name.
// Arg2: dst type.
// Arg3: dst name.
// Arg4: type error message.
// Return value: none, throws an exception.
@ -64,14 +64,13 @@ DEFINE_NATIVE_ENTRY(TypeError_throwNew, 5) {
TokenPosition(Smi::CheckedHandle(arguments->NativeArgAt(0)).Value());
const Instance& src_value =
Instance::CheckedHandle(arguments->NativeArgAt(1));
const String& dst_type_name =
String::CheckedHandle(arguments->NativeArgAt(2));
const AbstractType& dst_type =
AbstractType::CheckedHandle(arguments->NativeArgAt(2));
const String& dst_name = String::CheckedHandle(arguments->NativeArgAt(3));
const String& error_msg = String::CheckedHandle(arguments->NativeArgAt(4));
const String& src_type_name = String::Handle(
AbstractType::Handle(src_value.GetType()).UserVisibleName());
Exceptions::CreateAndThrowTypeError(location, src_type_name,
dst_type_name, dst_name, error_msg);
const AbstractType& src_type = AbstractType::Handle(src_value.GetType());
Exceptions::CreateAndThrowTypeError(
location, src_type, dst_type, dst_name, error_msg);
UNREACHABLE();
return Object::null();
}

View file

@ -45,69 +45,44 @@ class _AssertionError extends Error implements AssertionError {
}
class _TypeError extends _AssertionError implements TypeError {
_TypeError._create(String url, int line, int column,
this._srcType, this._dstType, this._dstName,
this._errorMsg)
_TypeError._create(String url, int line, int column, this._errorMsg)
: super._create("is assignable", url, line, column);
static _throwNew(int location,
Object src_value,
String dst_type_name,
_Type dst_type,
String dst_name,
String error_msg)
String bound_error_msg)
native "TypeError_throwNew";
static _throwNewIfNotLoaded(_LibraryPrefix prefix,
int location,
Object src_value,
String dst_type_name,
_Type dst_type,
String dst_name,
String error_msg) {
String bound_error_msg) {
if (!prefix.isLoaded()) {
_throwNew(location, src_value, dst_type_name, dst_name, error_msg);
_throwNew(location, src_value, dst_type, dst_name, bound_error_msg);
}
}
String toString() => _errorMsg;
String toString() {
String str = (_errorMsg != null) ? _errorMsg : "";
if ((_dstName != null) && (_dstName.length > 0)) {
str = "${str}type '$_srcType' is not a subtype of "
"type '$_dstType' of '$_dstName'.";
} else {
str = "${str}type error.";
}
return str;
}
final String _srcType;
final String _dstType;
final String _dstName;
final String _errorMsg;
}
class _CastError extends Error implements CastError {
_CastError._create(this._url, this._line, this._column,
this._srcType, this._dstType, this._dstName,
this._errorMsg);
_CastError._create(this._url, this._line, this._column, this._errorMsg);
// A CastError is allocated by TypeError._throwNew() when dst_name equals
// Exceptions::kCastErrorDstName.
// Symbols::InTypeCast().
String toString() {
String str = (_errorMsg != null) ? _errorMsg : "";
str = "${str}type '$_srcType' is not a subtype of "
"type '$_dstType' in type cast.";
return str;
}
String toString() => _errorMsg;
// Fields _url, _line, and _column are only used for debugging purposes.
final String _url;
final int _line;
final int _column;
final String _srcType;
final String _dstType;
final String _dstName;
final String _errorMsg;
}

View file

@ -138,10 +138,11 @@ DEFINE_NATIVE_ENTRY(Object_instanceOf, 4) {
const char* result_str = is_instance_of ? "true" : "false";
OS::Print("Native Object.instanceOf: result %s\n", result_str);
const AbstractType& instance_type =
AbstractType::Handle(instance.GetType());
AbstractType::Handle(zone, instance.GetType());
OS::Print(" instance type: %s\n",
String::Handle(instance_type.Name()).ToCString());
OS::Print(" test type: %s\n", String::Handle(type.Name()).ToCString());
String::Handle(zone, instance_type.Name()).ToCString());
OS::Print(" test type: %s\n",
String::Handle(zone, type.Name()).ToCString());
if (!bound_error.IsNull()) {
OS::Print(" bound error: %s\n", bound_error.ToErrorCString());
}
@ -155,7 +156,7 @@ DEFINE_NATIVE_ENTRY(Object_instanceOf, 4) {
String& bound_error_message = String::Handle(
zone, String::New(bound_error.ToErrorCString()));
Exceptions::CreateAndThrowTypeError(
location, Symbols::Empty(), Symbols::Empty(),
location, AbstractType::Handle(zone), AbstractType::Handle(zone),
Symbols::Empty(), bound_error_message);
UNREACHABLE();
}
@ -224,15 +225,16 @@ DEFINE_NATIVE_ENTRY(Object_instanceOfString, 2) {
DEFINE_NATIVE_ENTRY(Object_as, 3) {
const Instance& instance = Instance::CheckedHandle(arguments->NativeArgAt(0));
const Instance& instance =
Instance::CheckedHandle(zone, arguments->NativeArgAt(0));
const TypeArguments& instantiator_type_arguments =
TypeArguments::CheckedHandle(arguments->NativeArgAt(1));
const AbstractType& type =
AbstractType::CheckedHandle(arguments->NativeArgAt(2));
TypeArguments::CheckedHandle(zone, arguments->NativeArgAt(1));
AbstractType& type =
AbstractType::CheckedHandle(zone, arguments->NativeArgAt(2));
ASSERT(type.IsFinalized());
ASSERT(!type.IsMalformed());
ASSERT(!type.IsMalbounded());
Error& bound_error = Error::Handle();
Error& bound_error = Error::Handle(zone);
if (instance.IsNull()) {
return instance.raw();
}
@ -243,10 +245,11 @@ DEFINE_NATIVE_ENTRY(Object_as, 3) {
const char* result_str = is_instance_of ? "true" : "false";
OS::Print("Object.as: result %s\n", result_str);
const AbstractType& instance_type =
AbstractType::Handle(instance.GetType());
AbstractType::Handle(zone, instance.GetType());
OS::Print(" instance type: %s\n",
String::Handle(instance_type.Name()).ToCString());
OS::Print(" cast type: %s\n", String::Handle(type.Name()).ToCString());
String::Handle(zone, instance_type.Name()).ToCString());
OS::Print(" cast type: %s\n",
String::Handle(zone, type.Name()).ToCString());
if (!bound_error.IsNull()) {
OS::Print(" bound error: %s\n", bound_error.ToErrorCString());
}
@ -257,33 +260,23 @@ DEFINE_NATIVE_ENTRY(Object_as, 3) {
ASSERT(caller_frame != NULL);
const TokenPosition location = caller_frame->GetTokenPos();
const AbstractType& instance_type =
AbstractType::Handle(instance.GetType());
const String& instance_type_name =
String::Handle(instance_type.UserVisibleName());
String& type_name = String::Handle();
AbstractType::Handle(zone, instance.GetType());
if (!type.IsInstantiated()) {
// Instantiate type before reporting the error.
const AbstractType& instantiated_type = AbstractType::Handle(
type.InstantiateFrom(instantiator_type_arguments, NULL,
NULL, NULL, Heap::kNew));
// Note that instantiated_type may be malformed.
type_name = instantiated_type.UserVisibleName();
} else {
type_name = type.UserVisibleName();
type = type.InstantiateFrom(instantiator_type_arguments, NULL,
NULL, NULL, Heap::kNew);
// Note that the instantiated type may be malformed.
}
String& bound_error_message = String::Handle();
if (bound_error.IsNull()) {
const String& dst_name = String::ZoneHandle(
Symbols::New(Exceptions::kCastErrorDstName));
Exceptions::CreateAndThrowTypeError(
location, instance_type_name, type_name,
dst_name, Object::null_string());
location, instance_type, type,
Symbols::InTypeCast(), Object::null_string());
} else {
ASSERT(isolate->type_checks());
bound_error_message = String::New(bound_error.ToErrorCString());
const String& bound_error_message =
String::Handle(zone, String::New(bound_error.ToErrorCString()));
Exceptions::CreateAndThrowTypeError(
location, instance_type_name, Symbols::Empty(),
location, instance_type, AbstractType::Handle(zone),
Symbols::Empty(), bound_error_message);
}
UNREACHABLE();
@ -294,14 +287,14 @@ DEFINE_NATIVE_ENTRY(Object_as, 3) {
DEFINE_NATIVE_ENTRY(AbstractType_toString, 1) {
const AbstractType& type =
AbstractType::CheckedHandle(arguments->NativeArgAt(0));
AbstractType::CheckedHandle(zone, arguments->NativeArgAt(0));
return type.UserVisibleName();
}
DEFINE_NATIVE_ENTRY(LibraryPrefix_invalidateDependentCode, 1) {
const LibraryPrefix& prefix =
LibraryPrefix::CheckedHandle(arguments->NativeArgAt(0));
LibraryPrefix::CheckedHandle(zone, arguments->NativeArgAt(0));
prefix.InvalidateDependentCode();
return Bool::Get(true).raw();
}
@ -309,7 +302,7 @@ DEFINE_NATIVE_ENTRY(LibraryPrefix_invalidateDependentCode, 1) {
DEFINE_NATIVE_ENTRY(LibraryPrefix_load, 1) {
const LibraryPrefix& prefix =
LibraryPrefix::CheckedHandle(arguments->NativeArgAt(0));
LibraryPrefix::CheckedHandle(zone, arguments->NativeArgAt(0));
bool hasCompleted = prefix.LoadLibrary();
return Bool::Get(hasCompleted).raw();
}
@ -317,19 +310,19 @@ DEFINE_NATIVE_ENTRY(LibraryPrefix_load, 1) {
DEFINE_NATIVE_ENTRY(LibraryPrefix_loadError, 1) {
const LibraryPrefix& prefix =
LibraryPrefix::CheckedHandle(arguments->NativeArgAt(0));
LibraryPrefix::CheckedHandle(zone, arguments->NativeArgAt(0));
// Currently all errors are Dart instances, e.g. I/O errors
// created by deferred loading code. LanguageErrors from
// failed loading or finalization attempts are propagated and result
// in the isolate's death.
const Instance& error = Instance::Handle(prefix.LoadError());
const Instance& error = Instance::Handle(zone, prefix.LoadError());
return error.raw();
}
DEFINE_NATIVE_ENTRY(LibraryPrefix_isLoaded, 1) {
const LibraryPrefix& prefix =
LibraryPrefix::CheckedHandle(arguments->NativeArgAt(0));
LibraryPrefix::CheckedHandle(zone, arguments->NativeArgAt(0));
return Bool::Get(prefix.is_loaded()).raw();
}

View file

@ -2386,14 +2386,12 @@ void AotOptimizer::ReplaceWithTypeCast(InstanceCallInstr* call) {
return;
}
}
const String& dst_name = String::ZoneHandle(Z,
Symbols::New(Exceptions::kCastErrorDstName));
AssertAssignableInstr* assert_as =
new(Z) AssertAssignableInstr(call->token_pos(),
new(Z) Value(left),
new(Z) Value(type_args),
type,
dst_name,
Symbols::InTypeCast(),
call->deopt_id());
ReplaceCall(call, assert_as);
}

View file

@ -190,21 +190,21 @@ DEFINE_RUNTIME_ENTRY(AllocateObject, 2) {
// Arg1: instantiator type arguments.
// Return value: instantiated type.
DEFINE_RUNTIME_ENTRY(InstantiateType, 2) {
AbstractType& type = AbstractType::CheckedHandle(arguments.ArgAt(0));
AbstractType& type = AbstractType::CheckedHandle(zone, arguments.ArgAt(0));
const TypeArguments& instantiator =
TypeArguments::CheckedHandle(arguments.ArgAt(1));
TypeArguments::CheckedHandle(zone, arguments.ArgAt(1));
ASSERT(!type.IsNull() && !type.IsInstantiated());
ASSERT(instantiator.IsNull() || instantiator.IsInstantiated());
Error& bound_error = Error::Handle();
Error& bound_error = Error::Handle(zone);
type =
type.InstantiateFrom(instantiator, &bound_error, NULL, NULL, Heap::kOld);
if (!bound_error.IsNull()) {
// Throw a dynamic type error.
const TokenPosition location = GetCallerLocation();
String& bound_error_message = String::Handle(
String::New(bound_error.ToErrorCString()));
zone, String::New(bound_error.ToErrorCString()));
Exceptions::CreateAndThrowTypeError(
location, Symbols::Empty(), Symbols::Empty(),
location, AbstractType::Handle(zone), AbstractType::Handle(zone),
Symbols::Empty(), bound_error_message);
UNREACHABLE();
}
@ -224,16 +224,16 @@ DEFINE_RUNTIME_ENTRY(InstantiateType, 2) {
// Return value: instantiated type arguments.
DEFINE_RUNTIME_ENTRY(InstantiateTypeArguments, 2) {
TypeArguments& type_arguments =
TypeArguments::CheckedHandle(arguments.ArgAt(0));
TypeArguments::CheckedHandle(zone, arguments.ArgAt(0));
const TypeArguments& instantiator =
TypeArguments::CheckedHandle(arguments.ArgAt(1));
TypeArguments::CheckedHandle(zone, arguments.ArgAt(1));
ASSERT(!type_arguments.IsNull() && !type_arguments.IsInstantiated());
ASSERT(instantiator.IsNull() || instantiator.IsInstantiated());
// Code inlined in the caller should have optimized the case where the
// instantiator can be reused as type argument vector.
ASSERT(instantiator.IsNull() || !type_arguments.IsUninstantiatedIdentity());
if (isolate->type_checks()) {
Error& bound_error = Error::Handle();
Error& bound_error = Error::Handle(zone);
type_arguments =
type_arguments.InstantiateAndCanonicalizeFrom(instantiator,
&bound_error);
@ -241,9 +241,9 @@ DEFINE_RUNTIME_ENTRY(InstantiateTypeArguments, 2) {
// Throw a dynamic type error.
const TokenPosition location = GetCallerLocation();
String& bound_error_message = String::Handle(
String::New(bound_error.ToErrorCString()));
zone, String::New(bound_error.ToErrorCString()));
Exceptions::CreateAndThrowTypeError(
location, Symbols::Empty(), Symbols::Empty(),
location, AbstractType::Handle(zone), AbstractType::Handle(zone),
Symbols::Empty(), bound_error_message);
UNREACHABLE();
}
@ -260,7 +260,7 @@ DEFINE_RUNTIME_ENTRY(InstantiateTypeArguments, 2) {
// Arg0: number of variables.
// Return value: newly allocated context.
DEFINE_RUNTIME_ENTRY(AllocateContext, 1) {
const Smi& num_variables = Smi::CheckedHandle(arguments.ArgAt(0));
const Smi& num_variables = Smi::CheckedHandle(zone, arguments.ArgAt(0));
arguments.SetReturn(Context::Handle(Context::New(num_variables.Value())));
}
@ -270,8 +270,9 @@ DEFINE_RUNTIME_ENTRY(AllocateContext, 1) {
// Arg0: the context to be cloned.
// Return value: newly allocated context.
DEFINE_RUNTIME_ENTRY(CloneContext, 1) {
const Context& ctx = Context::CheckedHandle(arguments.ArgAt(0));
Context& cloned_ctx = Context::Handle(Context::New(ctx.num_variables()));
const Context& ctx = Context::CheckedHandle(zone, arguments.ArgAt(0));
Context& cloned_ctx =
Context::Handle(zone, Context::New(ctx.num_variables()));
cloned_ctx.set_parent(Context::Handle(ctx.parent()));
Object& inst = Object::Handle(zone);
for (int i = 0; i < ctx.num_variables(); i++) {
@ -449,17 +450,18 @@ static void UpdateTypeTestCache(
// Arg3: SubtypeTestCache.
// Return value: true or false, or may throw a type error in checked mode.
DEFINE_RUNTIME_ENTRY(Instanceof, 4) {
const Instance& instance = Instance::CheckedHandle(arguments.ArgAt(0));
const AbstractType& type = AbstractType::CheckedHandle(arguments.ArgAt(1));
const Instance& instance = Instance::CheckedHandle(zone, arguments.ArgAt(0));
const AbstractType& type =
AbstractType::CheckedHandle(zone, arguments.ArgAt(1));
const TypeArguments& instantiator_type_arguments =
TypeArguments::CheckedHandle(arguments.ArgAt(2));
TypeArguments::CheckedHandle(zone, arguments.ArgAt(2));
const SubtypeTestCache& cache =
SubtypeTestCache::CheckedHandle(arguments.ArgAt(3));
SubtypeTestCache::CheckedHandle(zone, arguments.ArgAt(3));
ASSERT(type.IsFinalized());
ASSERT(!type.IsDynamicType()); // No need to check assignment.
ASSERT(!type.IsMalformed()); // Already checked in code generator.
ASSERT(!type.IsMalbounded()); // Already checked in code generator.
Error& bound_error = Error::Handle();
Error& bound_error = Error::Handle(zone);
const Bool& result =
Bool::Get(instance.IsInstanceOf(type,
instantiator_type_arguments,
@ -472,9 +474,9 @@ DEFINE_RUNTIME_ENTRY(Instanceof, 4) {
// Throw a dynamic type error only if the instanceof test fails.
const TokenPosition location = GetCallerLocation();
String& bound_error_message = String::Handle(
String::New(bound_error.ToErrorCString()));
zone, String::New(bound_error.ToErrorCString()));
Exceptions::CreateAndThrowTypeError(
location, Symbols::Empty(), Symbols::Empty(),
location, AbstractType::Handle(zone), AbstractType::Handle(zone),
Symbols::Empty(), bound_error_message);
UNREACHABLE();
}
@ -493,19 +495,21 @@ DEFINE_RUNTIME_ENTRY(Instanceof, 4) {
// Arg4: SubtypeTestCache.
// Return value: instance if a subtype, otherwise throw a TypeError.
DEFINE_RUNTIME_ENTRY(TypeCheck, 5) {
const Instance& src_instance = Instance::CheckedHandle(arguments.ArgAt(0));
AbstractType& dst_type = AbstractType::CheckedHandle(arguments.ArgAt(1));
const Instance& src_instance =
Instance::CheckedHandle(zone, arguments.ArgAt(0));
AbstractType& dst_type =
AbstractType::CheckedHandle(zone, arguments.ArgAt(1));
const TypeArguments& instantiator_type_arguments =
TypeArguments::CheckedHandle(arguments.ArgAt(2));
const String& dst_name = String::CheckedHandle(arguments.ArgAt(3));
TypeArguments::CheckedHandle(zone, arguments.ArgAt(2));
const String& dst_name = String::CheckedHandle(zone, arguments.ArgAt(3));
const SubtypeTestCache& cache =
SubtypeTestCache::CheckedHandle(arguments.ArgAt(4));
SubtypeTestCache::CheckedHandle(zone, arguments.ArgAt(4));
ASSERT(!dst_type.IsDynamicType()); // No need to check assignment.
ASSERT(!dst_type.IsMalformed()); // Already checked in code generator.
ASSERT(!dst_type.IsMalbounded()); // Already checked in code generator.
ASSERT(!src_instance.IsNull()); // Already checked in inlined code.
Error& bound_error = Error::Handle();
Error& bound_error = Error::Handle(zone);
const bool is_instance_of = src_instance.IsInstanceOf(
dst_type, instantiator_type_arguments, &bound_error);
@ -517,25 +521,20 @@ DEFINE_RUNTIME_ENTRY(TypeCheck, 5) {
if (!is_instance_of) {
// Throw a dynamic type error.
const TokenPosition location = GetCallerLocation();
const AbstractType& src_type = AbstractType::Handle(src_instance.GetType());
String& src_type_name = String::Handle(src_type.UserVisibleName());
const AbstractType& src_type =
AbstractType::Handle(zone, src_instance.GetType());
if (!dst_type.IsInstantiated()) {
// Instantiate dst_type before reporting the error.
dst_type = dst_type.InstantiateFrom(instantiator_type_arguments, NULL,
NULL, NULL, Heap::kNew);
// Note that instantiated dst_type may be malbounded.
}
String& dst_type_name = String::Handle(dst_type.UserVisibleName());
String& bound_error_message = String::Handle();
String& bound_error_message = String::Handle(zone);
if (!bound_error.IsNull()) {
ASSERT(isolate->type_checks());
bound_error_message = String::New(bound_error.ToErrorCString());
}
if (src_type_name.Equals(dst_type_name)) {
src_type_name = src_type.UserVisibleNameWithURI();
dst_type_name = dst_type.UserVisibleNameWithURI();
}
Exceptions::CreateAndThrowTypeError(location, src_type_name, dst_type_name,
Exceptions::CreateAndThrowTypeError(location, src_type, dst_type,
dst_name, bound_error_message);
UNREACHABLE();
}
@ -552,17 +551,18 @@ DEFINE_RUNTIME_ENTRY(TypeCheck, 5) {
// Return value: none, throws TypeError or AssertionError.
DEFINE_RUNTIME_ENTRY(NonBoolTypeError, 1) {
const TokenPosition location = GetCallerLocation();
const Instance& src_instance = Instance::CheckedHandle(arguments.ArgAt(0));
const Instance& src_instance =
Instance::CheckedHandle(zone, arguments.ArgAt(0));
if (src_instance.IsNull()) {
const Array& args = Array::Handle(Array::New(4));
args.SetAt(0, String::Handle(
const Array& args = Array::Handle(zone, Array::New(4));
args.SetAt(0, String::Handle(zone,
String::New("Failed assertion: boolean expression must not be null")));
// No source code for this assertion, set url to null.
args.SetAt(1, String::Handle(String::null()));
args.SetAt(2, Smi::Handle(Smi::New(0)));
args.SetAt(3, Smi::Handle(Smi::New(0)));
args.SetAt(1, String::Handle(zone, String::null()));
args.SetAt(2, Smi::Handle(zone, Smi::New(0)));
args.SetAt(3, Smi::Handle(zone, Smi::New(0)));
Exceptions::ThrowByType(Exceptions::kAssertion, args);
UNREACHABLE();
@ -570,12 +570,10 @@ DEFINE_RUNTIME_ENTRY(NonBoolTypeError, 1) {
ASSERT(!src_instance.IsBool());
const Type& bool_interface = Type::Handle(Type::BoolType());
const AbstractType& src_type = AbstractType::Handle(src_instance.GetType());
const String& src_type_name = String::Handle(src_type.UserVisibleName());
const String& bool_type_name =
String::Handle(bool_interface.UserVisibleName());
const String& no_bound_error = String::Handle();
Exceptions::CreateAndThrowTypeError(location, src_type_name, bool_type_name,
const AbstractType& src_type =
AbstractType::Handle(zone, src_instance.GetType());
const String& no_bound_error = String::Handle(zone);
Exceptions::CreateAndThrowTypeError(location, src_type, bool_interface,
Symbols::BooleanExpression(),
no_bound_error);
UNREACHABLE();
@ -589,26 +587,14 @@ DEFINE_RUNTIME_ENTRY(NonBoolTypeError, 1) {
// Return value: none, throws an exception.
DEFINE_RUNTIME_ENTRY(BadTypeError, 3) {
const TokenPosition location = GetCallerLocation();
const Instance& src_value = Instance::CheckedHandle(arguments.ArgAt(0));
const String& dst_name = String::CheckedHandle(arguments.ArgAt(1));
const Instance& src_value = Instance::CheckedHandle(zone, arguments.ArgAt(0));
const String& dst_name = String::CheckedHandle(zone, arguments.ArgAt(1));
const AbstractType& dst_type =
AbstractType::CheckedHandle(arguments.ArgAt(2));
const AbstractType& src_type = AbstractType::Handle(src_value.GetType());
const String& src_type_name = String::Handle(src_type.UserVisibleName());
String& dst_type_name = String::Handle();
LanguageError& error = LanguageError::Handle(dst_type.error());
ASSERT(!error.IsNull());
if (error.kind() == Report::kMalformedType) {
dst_type_name = Symbols::Malformed().raw();
} else {
ASSERT(error.kind() == Report::kMalboundedType);
dst_type_name = Symbols::Malbounded().raw();
}
const String& error_message = String::ZoneHandle(
Symbols::New(error.ToErrorCString()));
AbstractType::CheckedHandle(zone, arguments.ArgAt(2));
const AbstractType& src_type =
AbstractType::Handle(zone, src_value.GetType());
Exceptions::CreateAndThrowTypeError(
location, src_type_name, dst_type_name, dst_name, error_message);
location, src_type, dst_type, dst_name, String::Handle(zone));
UNREACHABLE();
}
@ -635,19 +621,19 @@ DEFINE_RUNTIME_ENTRY(PatchStaticCall, 0) {
DartFrameIterator iterator;
StackFrame* caller_frame = iterator.NextFrame();
ASSERT(caller_frame != NULL);
const Code& caller_code = Code::Handle(caller_frame->LookupDartCode());
const Code& caller_code = Code::Handle(zone, caller_frame->LookupDartCode());
ASSERT(!caller_code.IsNull());
ASSERT(caller_code.is_optimized());
const Function& target_function = Function::Handle(
caller_code.GetStaticCallTargetFunctionAt(caller_frame->pc()));
zone, caller_code.GetStaticCallTargetFunctionAt(caller_frame->pc()));
if (!target_function.HasCode()) {
const Error& error =
Error::Handle(Compiler::CompileFunction(thread, target_function));
Error::Handle(zone, Compiler::CompileFunction(thread, target_function));
if (!error.IsNull()) {
Exceptions::PropagateError(error);
}
}
const Code& target_code = Code::Handle(target_function.CurrentCode());
const Code& target_code = Code::Handle(zone, target_function.CurrentCode());
// Before patching verify that we are not repeatedly patching to the same
// target.
ASSERT(target_code.raw() !=
@ -688,8 +674,9 @@ DEFINE_RUNTIME_ENTRY(BreakpointRuntimeHandler, 0) {
StackFrame* caller_frame = iterator.NextFrame();
ASSERT(caller_frame != NULL);
const Code& orig_stub = Code::Handle(
isolate->debugger()->GetPatchedStubAddress(caller_frame->pc()));
const Error& error = Error::Handle(isolate->debugger()->SignalBpReached());
zone, isolate->debugger()->GetPatchedStubAddress(caller_frame->pc()));
const Error& error =
Error::Handle(zone, isolate->debugger()->SignalBpReached());
if (!error.IsNull()) {
Exceptions::PropagateError(error);
UNREACHABLE();
@ -704,7 +691,7 @@ DEFINE_RUNTIME_ENTRY(SingleStepHandler, 0) {
return;
}
const Error& error =
Error::Handle(isolate->debugger()->DebuggerStepCallback());
Error::Handle(zone, isolate->debugger()->DebuggerStepCallback());
if (!error.IsNull()) {
Exceptions::PropagateError(error);
UNREACHABLE();

View file

@ -10,6 +10,7 @@
#include "vm/dart_entry.h"
#include "vm/debugger.h"
#include "vm/flags.h"
#include "vm/log.h"
#include "vm/object.h"
#include "vm/object_store.h"
#include "vm/stack_frame.h"
@ -23,9 +24,6 @@ DEFINE_FLAG(bool, print_stacktrace_at_throw, false,
"Prints a stack trace everytime a throw occurs.");
const char* Exceptions::kCastErrorDstName = "type cast";
class StacktraceBuilder : public ValueObject {
public:
StacktraceBuilder() { }
@ -371,8 +369,8 @@ static void ThrowExceptionHelper(Thread* thread,
ASSERT(handler_pc != 0);
if (FLAG_print_stacktrace_at_throw) {
OS::Print("Exception '%s' thrown:\n", exception.ToCString());
OS::Print("%s\n", stacktrace.ToCString());
THR_Print("Exception '%s' thrown:\n", exception.ToCString());
THR_Print("%s\n", stacktrace.ToCString());
}
if (handler_exists) {
// Found a dart handler for the exception, jump to it.
@ -434,18 +432,20 @@ RawInstance* Exceptions::NewInstance(const char* class_name) {
// Allocate, initialize, and throw a TypeError or CastError.
// If error_msg is not null, throw a TypeError, even for a type cast.
void Exceptions::CreateAndThrowTypeError(TokenPosition location,
const String& src_type_name,
const String& dst_type_name,
const AbstractType& src_type,
const AbstractType& dst_type,
const String& dst_name,
const String& error_msg) {
const Array& args = Array::Handle(Array::New(7));
const String& bound_error_msg) {
ASSERT(!dst_name.IsNull()); // Pass Symbols::Empty() instead.
Zone* zone = Thread::Current()->zone();
const Array& args = Array::Handle(zone, Array::New(4));
ExceptionType exception_type =
(error_msg.IsNull() && dst_name.Equals(kCastErrorDstName)) ?
kCast : kType;
(bound_error_msg.IsNull() &&
(dst_name.raw() == Symbols::InTypeCast().raw())) ? kCast : kType;
DartFrameIterator iterator;
const Script& script = Script::Handle(GetCallerScript(&iterator));
const Script& script = Script::Handle(zone, GetCallerScript(&iterator));
intptr_t line;
intptr_t column = -1;
if (script.HasSource()) {
@ -454,32 +454,64 @@ void Exceptions::CreateAndThrowTypeError(TokenPosition location,
script.GetTokenLocation(location, &line, NULL);
}
// Initialize '_url', '_line', and '_column' arguments.
args.SetAt(0, String::Handle(script.url()));
args.SetAt(1, Smi::Handle(Smi::New(line)));
args.SetAt(2, Smi::Handle(Smi::New(column)));
args.SetAt(0, String::Handle(zone, script.url()));
args.SetAt(1, Smi::Handle(zone, Smi::New(line)));
args.SetAt(2, Smi::Handle(zone, Smi::New(column)));
// Initialize '_srcType', '_dstType', '_dstName', and '_errorMsg'.
args.SetAt(3, src_type_name);
args.SetAt(4, dst_type_name);
args.SetAt(5, dst_name);
args.SetAt(6, error_msg);
// Construct '_errorMsg'.
GrowableHandlePtrArray<const String> pieces(zone, 20);
// Print bound error first, if any.
if (!bound_error_msg.IsNull() && (bound_error_msg.Length() > 0)) {
pieces.Add(bound_error_msg);
pieces.Add(Symbols::NewLine());
}
// If dst_type is malformed or malbounded, only print the embedded error.
if (!dst_type.IsNull()) {
const LanguageError& error = LanguageError::Handle(zone, dst_type.error());
if (!error.IsNull()) {
// Print the embedded error only.
pieces.Add(String::Handle(zone, Symbols::New(error.ToErrorCString())));
pieces.Add(Symbols::NewLine());
} else {
// Describe the type error.
if (!src_type.IsNull()) {
pieces.Add(Symbols::TypeQuote());
pieces.Add(String::Handle(zone, src_type.UserVisibleName()));
pieces.Add(Symbols::QuoteIsNotASubtypeOf());
}
pieces.Add(Symbols::TypeQuote());
pieces.Add(String::Handle(zone, dst_type.UserVisibleName()));
pieces.Add(Symbols::SingleQuote());
if (exception_type == kCast) {
pieces.Add(dst_name);
} else if (dst_name.Length() > 0) {
pieces.Add(Symbols::SpaceOfSpace());
pieces.Add(Symbols::SingleQuote());
pieces.Add(dst_name);
pieces.Add(Symbols::SingleQuote());
}
// Print URIs of src and dst types.
pieces.Add(Symbols::SpaceWhereNewLine());
if (!src_type.IsNull()) {
pieces.Add(String::Handle(zone, src_type.EnumerateURIs()));
}
if (!dst_type.IsDynamicType() && !dst_type.IsVoidType()) {
pieces.Add(String::Handle(zone, dst_type.EnumerateURIs()));
}
}
}
const String& error_msg =
String::Handle(zone, Symbols::FromConcatAll(pieces));
args.SetAt(3, error_msg);
// Type errors in the core library may be difficult to diagnose.
// Print type error information before throwing the error when debugging.
if (FLAG_print_stacktrace_at_throw) {
if (!error_msg.IsNull()) {
OS::Print("%s\n", error_msg.ToCString());
}
OS::Print("'%s': Failed type check: line %" Pd " pos %" Pd ": ",
String::Handle(script.url()).ToCString(), line, column);
if (!dst_name.IsNull() && (dst_name.Length() > 0)) {
OS::Print("type '%s' is not a subtype of type '%s' of '%s'.\n",
src_type_name.ToCString(),
dst_type_name.ToCString(),
dst_name.ToCString());
} else {
OS::Print("type error.\n");
}
THR_Print("'%s': Failed type check: line %" Pd " pos %" Pd ": ",
String::Handle(zone, script.url()).ToCString(), line, column);
THR_Print("%s\n", error_msg.ToCString());
}
// Throw TypeError or CastError instance.

View file

@ -11,28 +11,21 @@
namespace dart {
// Forward declarations.
class AbstractType;
class Array;
class Class;
class DartFrameIterator;
class Error;
class Instance;
class Integer;
class Object;
class RawInstance;
class RawObject;
class RawScript;
class RawStacktrace;
class RawString;
class Script;
class StackFrame;
class Stacktrace;
class String;
class Thread;
class Exceptions : AllStatic {
public:
static const char* kCastErrorDstName;
static void Throw(Thread* thread, const Instance& exception);
static void ReThrow(Thread* thread,
const Instance& exception,
@ -44,10 +37,10 @@ class Exceptions : AllStatic {
static RawScript* GetCallerScript(DartFrameIterator* iterator);
static RawInstance* NewInstance(const char* class_name);
static void CreateAndThrowTypeError(TokenPosition location,
const String& src_type_name,
const String& dst_type_name,
const AbstractType& src_type,
const AbstractType& dst_type,
const String& dst_name,
const String& error_msg);
const String& bound_error_msg);
enum ExceptionType {
kNone,

View file

@ -1684,12 +1684,10 @@ void EffectGraphVisitor::BuildTypeCast(ComparisonNode* node) {
ValueGraphVisitor for_value(owner());
node->left()->Visit(&for_value);
Append(for_value);
const String& dst_name = String::ZoneHandle(
Z, Symbols::New(Exceptions::kCastErrorDstName));
if (CanSkipTypeCheck(node->token_pos(),
for_value.value(),
type,
dst_name)) {
Symbols::InTypeCast())) {
ReturnValue(for_value.value());
return;
}

View file

@ -2690,14 +2690,12 @@ void JitOptimizer::ReplaceWithTypeCast(InstanceCallInstr* call) {
return;
}
}
const String& dst_name = String::ZoneHandle(Z,
Symbols::New(Exceptions::kCastErrorDstName));
AssertAssignableInstr* assert_as =
new(Z) AssertAssignableInstr(call->token_pos(),
new(Z) Value(left),
new(Z) Value(type_args),
type,
dst_name,
Symbols::InTypeCast(),
call->deopt_id());
ReplaceCall(call, assert_as);
}

View file

@ -6154,11 +6154,15 @@ bool Function::HasCompatibleParametersWith(const Function& other,
Report::kError,
Heap::kNew,
"signature type '%s' of function '%s' is not a subtype of signature "
"type '%s' of function '%s'",
"type '%s' of function '%s' where\n%s%s",
String::Handle(UserVisibleSignature()).ToCString(),
String::Handle(UserVisibleName()).ToCString(),
String::Handle(other.UserVisibleSignature()).ToCString(),
String::Handle(other.UserVisibleName()).ToCString());
String::Handle(other.UserVisibleName()).ToCString(),
String::Handle(FunctionType::Handle(
SignatureType()).EnumerateURIs()).ToCString(),
String::Handle(FunctionType::Handle(
other.SignatureType()).EnumerateURIs()).ToCString());
return false;
}
// We should also check that if the other function explicitly specifies a
@ -7966,7 +7970,7 @@ RawString* TokenStream::GenerateSource(TokenPosition start_pos,
}
}
if ((prev != Token::kINTERPOL_VAR) && (prev != Token::kINTERPOL_END)) {
literals.Add(Symbols::DoubleQuotes());
literals.Add(Symbols::DoubleQuote());
}
if (escape_characters) {
literal = String::EscapeSpecialCharacters(literal);
@ -7975,7 +7979,7 @@ RawString* TokenStream::GenerateSource(TokenPosition start_pos,
literals.Add(literal);
}
if ((next != Token::kINTERPOL_VAR) && (next != Token::kINTERPOL_START)) {
literals.Add(Symbols::DoubleQuotes());
literals.Add(Symbols::DoubleQuote());
}
} else if (curr == Token::kINTERPOL_VAR) {
literals.Add(Symbols::Dollar());
@ -15328,8 +15332,10 @@ RawString* AbstractType::UserVisibleNameWithURI() const {
Zone* zone = Thread::Current()->zone();
GrowableHandlePtrArray<const String> pieces(zone, 3);
pieces.Add(String::Handle(zone, BuildName(kUserVisibleName)));
pieces.Add(Symbols::SpaceWhereNewLine());
pieces.Add(String::Handle(zone, EnumerateURIs()));
if (!IsDynamicType() && !IsVoidType()) {
pieces.Add(Symbols::SpaceWhereNewLine());
pieces.Add(String::Handle(zone, EnumerateURIs()));
}
return Symbols::FromConcatAll(pieces);
}
@ -16050,7 +16056,7 @@ RawAbstractType* Type::Canonicalize(TrailPtr trail) const {
RawString* Type::EnumerateURIs() const {
if (IsDynamicType()) {
if (IsDynamicType() || IsVoidType()) {
return Symbols::Empty().raw();
}
Zone* zone = Thread::Current()->zone();
@ -16540,9 +16546,7 @@ RawString* FunctionType::EnumerateURIs() const {
}
// Handle result type last, since it appears last in the user visible name.
type = sig_fun.result_type();
if (!type.IsDynamicType() && !type.IsVoidType()) {
pieces.Add(String::Handle(zone, type.EnumerateURIs()));
}
pieces.Add(String::Handle(zone, type.EnumerateURIs()));
return Symbols::FromConcatAll(pieces);
}
@ -16751,7 +16755,20 @@ RawAbstractType* TypeRef::Canonicalize(TrailPtr trail) const {
RawString* TypeRef::EnumerateURIs() const {
return Symbols::Empty().raw(); // Break cycle.
const AbstractType& ref_type = AbstractType::Handle(type());
ASSERT(!ref_type.IsDynamicType() && !ref_type.IsVoidType());
Zone* zone = Thread::Current()->zone();
GrowableHandlePtrArray<const String> pieces(zone, 6);
const Class& cls = Class::Handle(zone, ref_type.type_class());
pieces.Add(Symbols::TwoSpaces());
pieces.Add(String::Handle(zone, cls.UserVisibleName()));
// Break cycle by not printing type arguments, but '<optimized out>' instead.
pieces.Add(Symbols::OptimizedOut());
pieces.Add(Symbols::SpaceIsFromSpace());
const Library& library = Library::Handle(zone, cls.library());
pieces.Add(String::Handle(zone, library.url()));
pieces.Add(Symbols::NewLine());
return Symbols::FromConcatAll(pieces);
}
@ -16920,12 +16937,14 @@ bool TypeParameter::CheckBound(const AbstractType& bounded_type,
Report::kMalboundedType,
Heap::kNew,
"type parameter '%s' of class '%s' must extend bound '%s', "
"but type argument '%s' is not a subtype of '%s'\n",
"but type argument '%s' is not a subtype of '%s' where\n%s%s",
type_param_name.ToCString(),
class_name.ToCString(),
declared_bound_name.ToCString(),
bounded_type_name.ToCString(),
upper_bound_name.ToCString());
upper_bound_name.ToCString(),
String::Handle(bounded_type.EnumerateURIs()).ToCString(),
String::Handle(upper_bound.EnumerateURIs()).ToCString());
}
}
return false;

View file

@ -10278,15 +10278,12 @@ AstNode* Parser::ThrowTypeError(TokenPosition type_pos,
type_pos, Integer::ZoneHandle(Z, Integer::New(type_pos.value()))));
// Src value argument.
arguments->Add(new(Z) LiteralNode(type_pos, Object::null_instance()));
// Dst type name argument.
arguments->Add(new(Z) LiteralNode(type_pos, Symbols::Malformed()));
// Dst type argument.
arguments->Add(new(Z) LiteralNode(type_pos, type));
// Dst name argument.
arguments->Add(new(Z) LiteralNode(type_pos, Symbols::Empty()));
// Malformed type error or malbounded type error.
const Error& error = Error::Handle(Z, type.error());
ASSERT(!error.IsNull());
arguments->Add(new(Z) LiteralNode(type_pos, String::ZoneHandle(Z,
Symbols::New(error.ToErrorCString()))));
// Bound error msg argument.
arguments->Add(new(Z) LiteralNode(type_pos, Object::null_instance()));
return MakeStaticCall(Symbols::TypeError(), method_name, arguments);
}
@ -13288,7 +13285,7 @@ AstNode* Parser::ParseNewOperator(Token::Kind op_kind) {
(la3 == Token::kLT) || (la3 == Token::kPERIOD) || (la3 == Token::kHASH);
LibraryPrefix& prefix = LibraryPrefix::ZoneHandle(Z);
AbstractType& type = AbstractType::Handle(Z,
AbstractType& type = AbstractType::ZoneHandle(Z,
ParseType(ClassFinalizer::kCanonicalizeWellFormed,
allow_deferred_type,
consume_unresolved_prefix,
@ -13417,7 +13414,7 @@ AstNode* Parser::ParseNewOperator(Token::Kind op_kind) {
NULL); // No existing function.
} else if (constructor.IsRedirectingFactory()) {
ClassFinalizer::ResolveRedirectingFactory(type_class, constructor);
Type& redirect_type = Type::Handle(Z, constructor.RedirectionType());
Type& redirect_type = Type::ZoneHandle(Z, constructor.RedirectionType());
if (!redirect_type.IsMalformedOrMalbounded() &&
!redirect_type.IsInstantiated()) {
// The type arguments of the redirection type are instantiated from the

View file

@ -309,8 +309,6 @@ class ObjectPointerVisitor;
V(NullThrownError, "NullThrownError") \
V(IsolateSpawnException, "IsolateSpawnException") \
V(BooleanExpression, "boolean expression") \
V(Malformed, "malformed") \
V(Malbounded, "malbounded") \
V(MegamorphicMiss, "megamorphic_miss") \
V(CommaSpace, ", ") \
V(ColonSpace, ": ") \
@ -318,6 +316,9 @@ class ObjectPointerVisitor;
V(SpaceExtendsSpace, " extends ") \
V(SpaceWhereNewLine, " where\n") \
V(SpaceIsFromSpace, " is from ") \
V(InTypeCast, " in type cast") \
V(TypeQuote, "type '") \
V(QuoteIsNotASubtypeOf, "' is not a subtype of ") \
V(SpaceOfSpace, " of ") \
V(SwitchExpr, ":switch_expr") \
V(TwoNewlines, "\n\n") \
@ -499,9 +500,12 @@ class Symbols : public AllStatic {
static const String& NewLine() {
return *(symbol_handles_[kNullCharId + '\n']);
}
static const String& DoubleQuotes() {
static const String& DoubleQuote() {
return *(symbol_handles_[kNullCharId + '"']);
}
static const String& SingleQuote() {
return *(symbol_handles_[kNullCharId + '\'']);
}
static const String& LowercaseR() {
return *(symbol_handles_[kNullCharId + 'r']);
}