5f36c5f9d8
In Dart2, type bounds checking is either performed by the common front-end or by explicitly generated code, but not by type finalization or runtime anymore, as it was done in Dart1. Consequently, the class BoundedType is not needed anymore, and malbounded or malformed types are not seen by the runtime either. Change-Id: I5d6e4c68d153d6730fa7ff7f6d9dcfa611299c16 Reviewed-on: https://dart-review.googlesource.com/c/86687 Commit-Queue: Régis Crelier <regis@google.com> Reviewed-by: Ryan Macnak <rmacnak@google.com> Reviewed-by: Samir Jindel <sjindel@google.com>
591 lines
19 KiB
Dart
591 lines
19 KiB
Dart
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
|
|
// for details. All rights reserved. Use of this source code is governed by a
|
|
// BSD-style license that can be found in the LICENSE file.
|
|
|
|
// part of "core_patch.dart";
|
|
|
|
@patch
|
|
class Error {
|
|
@patch
|
|
static String _objectToString(Object object) {
|
|
return Object._toString(object);
|
|
}
|
|
|
|
@patch
|
|
static String _stringToSafeString(String string) {
|
|
return json.encode(string);
|
|
}
|
|
|
|
@patch
|
|
StackTrace get stackTrace => _stackTrace;
|
|
|
|
@pragma("vm:entry-point")
|
|
StackTrace _stackTrace;
|
|
}
|
|
|
|
class _AssertionError extends Error implements AssertionError {
|
|
@pragma("vm:entry-point")
|
|
_AssertionError._create(
|
|
this._failedAssertion, this._url, this._line, this._column, this.message);
|
|
|
|
// AssertionError_throwNew in errors.cc fishes the assertion source code
|
|
// out of the script. It expects a Dart stack frame from class
|
|
// _AssertionError. Thus we need a Dart stub that calls the native code.
|
|
@pragma("vm:entry-point")
|
|
static _throwNew(int assertionStart, int assertionEnd, Object message) {
|
|
_doThrowNew(assertionStart, assertionEnd, message);
|
|
}
|
|
|
|
static _doThrowNew(int assertionStart, int assertionEnd, Object message)
|
|
native "AssertionError_throwNew";
|
|
|
|
@pragma("vm:entry-point")
|
|
static _evaluateAssertion(condition) {
|
|
if (identical(condition, true) || identical(condition, false)) {
|
|
return condition;
|
|
}
|
|
if (condition is _Closure) {
|
|
return (condition as dynamic)();
|
|
}
|
|
if (condition is Function) {
|
|
condition = condition();
|
|
}
|
|
return condition;
|
|
}
|
|
|
|
String get _messageString {
|
|
if (message == null) return "is not true.";
|
|
if (message is String) return message;
|
|
return Error.safeToString(message);
|
|
}
|
|
|
|
String toString() {
|
|
if (_url == null) {
|
|
if (message == null) return _failedAssertion?.trim();
|
|
return "'${_failedAssertion?.trim()}': $_messageString";
|
|
}
|
|
var columnInfo = "";
|
|
if (_column > 0) {
|
|
// Only add column information if it is valid.
|
|
columnInfo = " pos $_column";
|
|
}
|
|
return "'$_url': Failed assertion: line $_line$columnInfo: "
|
|
"'$_failedAssertion': $_messageString";
|
|
}
|
|
|
|
final String _failedAssertion;
|
|
final String _url;
|
|
final int _line;
|
|
final int _column;
|
|
final Object message;
|
|
}
|
|
|
|
class _TypeError extends _AssertionError implements TypeError {
|
|
@pragma("vm:entry-point")
|
|
_TypeError._create(String url, int line, int column, String errorMsg)
|
|
: super._create("is assignable", url, line, column, errorMsg);
|
|
|
|
static _throwNew(int location, Object src_value, _Type dst_type,
|
|
String dst_name) native "TypeError_throwNew";
|
|
|
|
String toString() => super.message;
|
|
}
|
|
|
|
class _CastError extends Error implements CastError {
|
|
@pragma("vm:entry-point")
|
|
_CastError._create(this._url, this._line, this._column, this._errorMsg);
|
|
|
|
// A CastError is allocated by TypeError._throwNew() when dst_name equals
|
|
// Symbols::InTypeCast().
|
|
|
|
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 _errorMsg;
|
|
}
|
|
|
|
@patch
|
|
class FallThroughError {
|
|
@patch
|
|
@pragma("vm:entry-point")
|
|
FallThroughError._create(String url, int line)
|
|
: _url = url,
|
|
_line = line;
|
|
|
|
static _throwNew(int case_clause_pos) native "FallThroughError_throwNew";
|
|
|
|
@patch
|
|
String toString() {
|
|
return "'$_url': Switch case fall-through at line $_line.";
|
|
}
|
|
|
|
// These new fields cannot be declared final, because a constructor exists
|
|
// in the original version of this patched class.
|
|
String _url;
|
|
int _line;
|
|
}
|
|
|
|
class _InternalError {
|
|
@pragma("vm:entry-point")
|
|
const _InternalError(this._msg);
|
|
String toString() => "InternalError: '${_msg}'";
|
|
final String _msg;
|
|
}
|
|
|
|
@patch
|
|
@pragma("vm:entry-point")
|
|
class UnsupportedError {
|
|
static _throwNew(String msg) {
|
|
throw new UnsupportedError(msg);
|
|
}
|
|
}
|
|
|
|
@patch
|
|
class CyclicInitializationError {
|
|
static _throwNew(String variableName) {
|
|
throw new CyclicInitializationError(variableName);
|
|
}
|
|
}
|
|
|
|
@patch
|
|
class AbstractClassInstantiationError {
|
|
@pragma("vm:entry-point")
|
|
AbstractClassInstantiationError._create(
|
|
this._className, this._url, this._line);
|
|
|
|
static _throwNew(int case_clause_pos, String className)
|
|
native "AbstractClassInstantiationError_throwNew";
|
|
|
|
@patch
|
|
String toString() {
|
|
return "Cannot instantiate abstract class $_className: "
|
|
"_url '$_url' line $_line";
|
|
}
|
|
|
|
// These new fields cannot be declared final, because a constructor exists
|
|
// in the original version of this patched class.
|
|
String _url;
|
|
int _line;
|
|
}
|
|
|
|
@patch
|
|
class NoSuchMethodError {
|
|
// Deprecated members to be removed.
|
|
Symbol _memberName;
|
|
List _arguments;
|
|
Map<Symbol, dynamic> _namedArguments;
|
|
List _existingArgumentNames;
|
|
|
|
final Object _receiver;
|
|
final _InvocationMirror _invocation;
|
|
|
|
@patch
|
|
NoSuchMethodError.withInvocation(Object receiver, Invocation invocation)
|
|
: _receiver = receiver,
|
|
_invocation = invocation as _InvocationMirror;
|
|
|
|
static void _throwNewInvocation(Object receiver, Invocation invocation) {
|
|
throw new NoSuchMethodError.withInvocation(receiver, invocation);
|
|
}
|
|
|
|
// The compiler emits a call to _throwNew when it cannot resolve a static
|
|
// method at compile time. The receiver is actually the literal class of the
|
|
// unresolved method.
|
|
@pragma("vm:entry-point")
|
|
static void _throwNew(Object receiver, String memberName, int invocation_type,
|
|
Object typeArguments, List arguments, List argumentNames) {
|
|
throw new NoSuchMethodError._withType(receiver, memberName, invocation_type,
|
|
typeArguments, arguments, argumentNames);
|
|
}
|
|
|
|
static void _throwNewIfNotLoaded(
|
|
_LibraryPrefix prefix,
|
|
Object receiver,
|
|
String memberName,
|
|
int invocation_type,
|
|
Object typeArguments,
|
|
List arguments,
|
|
List argumentNames) {
|
|
if (!prefix.isLoaded()) {
|
|
_throwNew(receiver, memberName, invocation_type, typeArguments, arguments,
|
|
argumentNames);
|
|
}
|
|
}
|
|
|
|
// TODO(regis): Deprecated member still used by dart2js to be removed.
|
|
// Remember the type from the invocation mirror or static compilation
|
|
// analysis when thrown directly with _throwNew. A negative value means
|
|
// that no information is available.
|
|
int _invocation_type;
|
|
|
|
// TODO(regis): Deprecated constructor still used by dart2js to be removed.
|
|
@patch
|
|
NoSuchMethodError(Object receiver, Symbol memberName,
|
|
List positionalArguments, Map<Symbol, dynamic> namedArguments,
|
|
[List existingArgumentNames = null])
|
|
: _receiver = receiver,
|
|
_invocation = null,
|
|
_memberName = memberName,
|
|
_arguments = positionalArguments,
|
|
_namedArguments = namedArguments,
|
|
_existingArgumentNames = existingArgumentNames,
|
|
_invocation_type = -1;
|
|
|
|
// Helper to build a map of named arguments.
|
|
static Map<Symbol, dynamic> _NamedArgumentsMap(
|
|
List arguments, List argumentNames) {
|
|
Map<Symbol, dynamic> namedArguments = new Map<Symbol, dynamic>();
|
|
int numPositionalArguments = arguments.length - argumentNames.length;
|
|
for (int i = 0; i < argumentNames.length; i++) {
|
|
var arg_value = arguments[numPositionalArguments + i];
|
|
namedArguments[new Symbol(argumentNames[i])] = arg_value;
|
|
}
|
|
return namedArguments;
|
|
}
|
|
|
|
// Constructor called from Exceptions::ThrowByType(kNoSuchMethod) and from
|
|
// _throwNew above, taking a TypeArguments object rather than an unpacked list
|
|
// of types, as well as a list of all arguments and a list of names, rather
|
|
// than a separate list of positional arguments and a map of named arguments.
|
|
@pragma("vm:entry-point")
|
|
NoSuchMethodError._withType(
|
|
this._receiver,
|
|
String memberName,
|
|
int invocation_type,
|
|
Object typeArguments,
|
|
List arguments,
|
|
List argumentNames)
|
|
: this._invocation = new _InvocationMirror._withType(
|
|
new Symbol(memberName),
|
|
invocation_type,
|
|
typeArguments != null
|
|
// TODO(33073): Use actual count of type arguments in place of 0.
|
|
? _InvocationMirror._unpackTypeArguments(typeArguments, 0)
|
|
: null,
|
|
argumentNames != null
|
|
? arguments.sublist(0, arguments.length - argumentNames.length)
|
|
: arguments,
|
|
argumentNames != null
|
|
? _NamedArgumentsMap(arguments, argumentNames)
|
|
: null);
|
|
|
|
static String _existingMethodSignature(Object receiver, String methodName,
|
|
int invocationType) native "NoSuchMethodError_existingMethodSignature";
|
|
|
|
@patch
|
|
String toString() {
|
|
// TODO(regis): Remove this null check once dart2js is updated.
|
|
if (_invocation == null) {
|
|
// Use deprecated version of toString.
|
|
return _toStringDeprecated();
|
|
}
|
|
String memberName =
|
|
internal.Symbol.computeUnmangledName(_invocation.memberName);
|
|
var level = (_invocation._type >> _InvocationMirror._LEVEL_SHIFT) &
|
|
_InvocationMirror._LEVEL_MASK;
|
|
var kind = _invocation._type & _InvocationMirror._KIND_MASK;
|
|
if (kind == _InvocationMirror._LOCAL_VAR) {
|
|
return "NoSuchMethodError: Cannot assign to final variable '$memberName'";
|
|
}
|
|
|
|
StringBuffer typeArgumentsBuf = null;
|
|
var typeArguments = _invocation.typeArguments;
|
|
if ((typeArguments != null) && (typeArguments.length > 0)) {
|
|
typeArgumentsBuf = new StringBuffer();
|
|
typeArgumentsBuf.write("<");
|
|
for (int i = 0; i < typeArguments.length; i++) {
|
|
if (i > 0) {
|
|
typeArgumentsBuf.write(", ");
|
|
}
|
|
typeArgumentsBuf.write(Error.safeToString(typeArguments[i]));
|
|
}
|
|
typeArgumentsBuf.write(">");
|
|
}
|
|
StringBuffer argumentsBuf = new StringBuffer();
|
|
var positionalArguments = _invocation.positionalArguments;
|
|
int argumentCount = 0;
|
|
if (positionalArguments != null) {
|
|
for (; argumentCount < positionalArguments.length; argumentCount++) {
|
|
if (argumentCount > 0) {
|
|
argumentsBuf.write(", ");
|
|
}
|
|
argumentsBuf
|
|
.write(Error.safeToString(positionalArguments[argumentCount]));
|
|
}
|
|
}
|
|
var namedArguments = _invocation.namedArguments;
|
|
if (namedArguments != null) {
|
|
namedArguments.forEach((Symbol key, var value) {
|
|
if (argumentCount > 0) {
|
|
argumentsBuf.write(", ");
|
|
}
|
|
argumentsBuf.write(internal.Symbol.computeUnmangledName(key));
|
|
argumentsBuf.write(": ");
|
|
argumentsBuf.write(Error.safeToString(value));
|
|
argumentCount++;
|
|
});
|
|
}
|
|
String existingSig =
|
|
_existingMethodSignature(_receiver, memberName, _invocation._type);
|
|
String argsMsg = existingSig != null ? " with matching arguments" : "";
|
|
|
|
String kindBuf;
|
|
if (kind >= 0 && kind < 5) {
|
|
kindBuf = (const [
|
|
"method",
|
|
"getter",
|
|
"setter",
|
|
"getter or setter",
|
|
"variable"
|
|
])[kind];
|
|
}
|
|
|
|
StringBuffer msgBuf = new StringBuffer("NoSuchMethodError: ");
|
|
bool is_type_call = false;
|
|
switch (level) {
|
|
case _InvocationMirror._DYNAMIC:
|
|
{
|
|
if (_receiver == null) {
|
|
if (existingSig != null) {
|
|
msgBuf.writeln("The null object does not have a $kindBuf "
|
|
"'$memberName'$argsMsg.");
|
|
} else {
|
|
msgBuf.writeln("The $kindBuf '$memberName' was called on null.");
|
|
}
|
|
} else {
|
|
if (_receiver is _Closure) {
|
|
msgBuf.writeln("Closure call with mismatched arguments: "
|
|
"function '$memberName'");
|
|
} else if (_receiver is _Type && memberName == "call") {
|
|
is_type_call = true;
|
|
String name = _receiver.toString();
|
|
msgBuf.writeln("Attempted to use type '$name' as a function. "
|
|
"Since types do not define a method 'call', this is not "
|
|
"possible. Did you intend to call the $name constructor and "
|
|
"forget the 'new' operator?");
|
|
} else {
|
|
msgBuf.writeln("Class '${_receiver.runtimeType}' has no instance "
|
|
"$kindBuf '$memberName'$argsMsg.");
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case _InvocationMirror._SUPER:
|
|
{
|
|
msgBuf.writeln("Super class of class '${_receiver.runtimeType}' has "
|
|
"no instance $kindBuf '$memberName'$argsMsg.");
|
|
memberName = "super.$memberName";
|
|
break;
|
|
}
|
|
case _InvocationMirror._STATIC:
|
|
{
|
|
msgBuf.writeln("No static $kindBuf '$memberName'$argsMsg "
|
|
"declared in class '$_receiver'.");
|
|
break;
|
|
}
|
|
case _InvocationMirror._CONSTRUCTOR:
|
|
{
|
|
msgBuf.writeln("No constructor '$memberName'$argsMsg declared "
|
|
"in class '$_receiver'.");
|
|
memberName = "new $memberName";
|
|
break;
|
|
}
|
|
case _InvocationMirror._TOP_LEVEL:
|
|
{
|
|
msgBuf.writeln("No top-level $kindBuf '$memberName'$argsMsg "
|
|
"declared.");
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (level == _InvocationMirror._TOP_LEVEL) {
|
|
msgBuf.writeln("Receiver: top-level");
|
|
} else {
|
|
msgBuf.writeln("Receiver: ${Error.safeToString(_receiver)}");
|
|
}
|
|
|
|
if (kind == _InvocationMirror._METHOD) {
|
|
String m = is_type_call ? "$_receiver" : "$memberName";
|
|
msgBuf.write("Tried calling: $m");
|
|
if (typeArgumentsBuf != null) {
|
|
msgBuf.write(typeArgumentsBuf);
|
|
}
|
|
msgBuf.write("($argumentsBuf)");
|
|
} else if (argumentCount == 0) {
|
|
msgBuf.write("Tried calling: $memberName");
|
|
} else if (kind == _InvocationMirror._SETTER) {
|
|
msgBuf.write("Tried calling: $memberName$argumentsBuf");
|
|
} else {
|
|
msgBuf.write("Tried calling: $memberName = $argumentsBuf");
|
|
}
|
|
|
|
if (existingSig != null) {
|
|
msgBuf.write("\nFound: $memberName$existingSig");
|
|
}
|
|
|
|
return msgBuf.toString();
|
|
}
|
|
|
|
// TODO(regis): Remove this function once dart2js is updated.
|
|
String _toStringDeprecated() {
|
|
var level = (_invocation_type >> _InvocationMirror._LEVEL_SHIFT) &
|
|
_InvocationMirror._LEVEL_MASK;
|
|
var type = _invocation_type & _InvocationMirror._KIND_MASK;
|
|
String memberName = (_memberName == null)
|
|
? ""
|
|
: internal.Symbol.computeUnmangledName(_memberName);
|
|
|
|
if (type == _InvocationMirror._LOCAL_VAR) {
|
|
return "NoSuchMethodError: Cannot assign to final variable '$memberName'";
|
|
}
|
|
|
|
StringBuffer arguments = new StringBuffer();
|
|
int argumentCount = 0;
|
|
if (_arguments != null) {
|
|
for (; argumentCount < _arguments.length; argumentCount++) {
|
|
if (argumentCount > 0) {
|
|
arguments.write(", ");
|
|
}
|
|
arguments.write(Error.safeToString(_arguments[argumentCount]));
|
|
}
|
|
}
|
|
if (_namedArguments != null) {
|
|
_namedArguments.forEach((Symbol key, var value) {
|
|
if (argumentCount > 0) {
|
|
arguments.write(", ");
|
|
}
|
|
arguments.write(internal.Symbol.computeUnmangledName(key));
|
|
arguments.write(": ");
|
|
arguments.write(Error.safeToString(value));
|
|
argumentCount++;
|
|
});
|
|
}
|
|
bool args_mismatch = _existingArgumentNames != null;
|
|
String args_message = args_mismatch ? " with matching arguments" : "";
|
|
|
|
String type_str;
|
|
if (type >= 0 && type < 5) {
|
|
type_str = (const [
|
|
"method",
|
|
"getter",
|
|
"setter",
|
|
"getter or setter",
|
|
"variable"
|
|
])[type];
|
|
}
|
|
|
|
StringBuffer msg_buf = new StringBuffer("NoSuchMethodError: ");
|
|
bool is_type_call = false;
|
|
switch (level) {
|
|
case _InvocationMirror._DYNAMIC:
|
|
{
|
|
if (_receiver == null) {
|
|
if (args_mismatch) {
|
|
msg_buf.writeln("The null object does not have a $type_str "
|
|
"'$memberName'$args_message.");
|
|
} else {
|
|
msg_buf
|
|
.writeln("The $type_str '$memberName' was called on null.");
|
|
}
|
|
} else {
|
|
if (_receiver is _Closure) {
|
|
msg_buf.writeln("Closure call with mismatched arguments: "
|
|
"function '$memberName'");
|
|
} else if (_receiver is _Type && memberName == "call") {
|
|
is_type_call = true;
|
|
String name = _receiver.toString();
|
|
msg_buf.writeln("Attempted to use type '$name' as a function. "
|
|
"Since types do not define a method 'call', this is not "
|
|
"possible. Did you intend to call the $name constructor and "
|
|
"forget the 'new' operator?");
|
|
} else {
|
|
msg_buf
|
|
.writeln("Class '${_receiver.runtimeType}' has no instance "
|
|
"$type_str '$memberName'$args_message.");
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case _InvocationMirror._SUPER:
|
|
{
|
|
msg_buf.writeln("Super class of class '${_receiver.runtimeType}' has "
|
|
"no instance $type_str '$memberName'$args_message.");
|
|
memberName = "super.$memberName";
|
|
break;
|
|
}
|
|
case _InvocationMirror._STATIC:
|
|
{
|
|
msg_buf.writeln("No static $type_str '$memberName'$args_message "
|
|
"declared in class '$_receiver'.");
|
|
break;
|
|
}
|
|
case _InvocationMirror._CONSTRUCTOR:
|
|
{
|
|
msg_buf.writeln("No constructor '$memberName'$args_message declared "
|
|
"in class '$_receiver'.");
|
|
memberName = "new $memberName";
|
|
break;
|
|
}
|
|
case _InvocationMirror._TOP_LEVEL:
|
|
{
|
|
msg_buf.writeln("No top-level $type_str '$memberName'$args_message "
|
|
"declared.");
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (level == _InvocationMirror._TOP_LEVEL) {
|
|
msg_buf.writeln("Receiver: top-level");
|
|
} else {
|
|
msg_buf.writeln("Receiver: ${Error.safeToString(_receiver)}");
|
|
}
|
|
|
|
if (type == _InvocationMirror._METHOD) {
|
|
String m = is_type_call ? "$_receiver" : "$memberName";
|
|
msg_buf.write("Tried calling: $m($arguments)");
|
|
} else if (argumentCount == 0) {
|
|
msg_buf.write("Tried calling: $memberName");
|
|
} else if (type == _InvocationMirror._SETTER) {
|
|
msg_buf.write("Tried calling: $memberName$arguments");
|
|
} else {
|
|
msg_buf.write("Tried calling: $memberName = $arguments");
|
|
}
|
|
|
|
if (args_mismatch) {
|
|
StringBuffer formalParameters = new StringBuffer();
|
|
for (int i = 0; i < _existingArgumentNames.length; i++) {
|
|
if (i > 0) {
|
|
formalParameters.write(", ");
|
|
}
|
|
formalParameters.write(_existingArgumentNames[i]);
|
|
}
|
|
msg_buf.write("\nFound: $memberName($formalParameters)");
|
|
}
|
|
|
|
return msg_buf.toString();
|
|
}
|
|
}
|
|
|
|
@pragma("vm:entry-point")
|
|
class _CompileTimeError extends Error {
|
|
final String _errorMsg;
|
|
_CompileTimeError(this._errorMsg);
|
|
String toString() => _errorMsg;
|
|
}
|
|
|
|
/// Used by Fasta to report a runtime error when a final field with an
|
|
/// initializer is also initialized in a generative constructor.
|
|
///
|
|
/// Note: in strong mode, this is a compile-time error and this class becomes
|
|
/// obsolete.
|
|
class _DuplicatedFieldInitializerError extends Error {
|
|
final String _name;
|
|
|
|
_DuplicatedFieldInitializerError(this._name);
|
|
|
|
toString() => "Error: field '$_name' is already initialized.";
|
|
}
|