Index: sdk/lib/core/errors.dart |
diff --git a/sdk/lib/core/errors.dart b/sdk/lib/core/errors.dart |
index 905250c351a92e7c11643655744748e4a8f0e165..d6a6e4c96ef6d835d716f1b0c1196779ff4f445c 100644 |
--- a/sdk/lib/core/errors.dart |
+++ b/sdk/lib/core/errors.dart |
@@ -159,16 +159,67 @@ class NullThrownError extends Error { |
* Error thrown when a function is passed an unacceptable argument. |
*/ |
class ArgumentError extends Error { |
+ /** Whether value was provided. */ |
+ final bool _hasValue; |
+ /** The invalid value. */ |
+ final invalidValue; |
+ /** Name of the invalid argument, if available. */ |
+ final String name; |
+ /** Message describing the problem. */ |
final message; |
- /** The [message] describes the erroneous argument. */ |
- ArgumentError([this.message]); |
+ /** |
+ * The [message] describes the erroneous argument. |
+ * |
+ * Existing code may be using `message` to hold the invalid value. |
+ * If the `message` is not a [String], it is assumed to be a value instead |
+ * of a message. |
+ */ |
+ ArgumentError([this.message]) |
+ : invalidValue = null, |
+ _hasValue = false, |
+ name = null; |
+ |
+ /** |
+ * Creates error containing the invalid [value]. |
+ * |
+ * A message is built by suffixing the [message] argument with |
+ * the [name] argument (if provided) and the value. Example |
+ * |
+ * "Invalid argument (foo): null" |
+ * |
+ * The `name` should match the argument name of the function, but if |
+ * the function is a method implementing an interface, and its argument |
+ * names differ from the interface, it might be more useful to use the |
+ * interface method's argument name (or just rename arguments to match). |
+ */ |
+ ArgumentError.value(value, |
+ [String this.name, |
+ String this.message = "Invalid argument"]) |
+ : invalidValue = value, |
+ _hasValue = true; |
+ |
+ /** |
+ * Create an argument error for a `null` argument that must not be `null`. |
+ * |
+ * Shorthand for calling [ArgumentError.value] with a `null` value and a |
+ * message of `"Must not be null"`. |
+ */ |
+ ArgumentError.notNull([String name]) |
+ : this.value(null, name, "Must not be null"); |
String toString() { |
- if (message != null) { |
- return "Illegal argument(s): $message"; |
+ if (!_hasValue) { |
+ if (message != null) { |
+ return "Invalid argument(s): $message"; |
+ } |
+ return "Invalid argument(s)"; |
} |
- return "Illegal argument(s)"; |
+ String nameString = ""; |
+ if (name != null) { |
+ nameString = " ($name)"; |
+ } |
+ return "$message$nameString: ${Error.safeToString(invalidValue)}"; |
} |
} |
@@ -176,25 +227,115 @@ class ArgumentError extends Error { |
* Error thrown due to an index being outside a valid range. |
*/ |
class RangeError extends ArgumentError { |
+ /** The value that is outside its valid range. */ |
+ final num invalidValue; |
+ /** The minimum value that [value] is allowed to assume. */ |
+ final num start; |
+ /** The maximum value that [value] is allowed to assume. */ |
+ final num end; |
+ |
// TODO(lrn): This constructor should be called only with string values. |
// It currently isn't in all cases. |
/** |
* Create a new [RangeError] with the given [message]. |
*/ |
- RangeError(var message) : super(message); |
+ RangeError(var message) |
+ : invalidValue = null, start = null, end = null, super(message); |
/** Create a new [RangeError] with a message for the given [value]. */ |
- RangeError.value(num value) : super("value $value"); |
+ RangeError.value(num value, [String message = "Value not in range"]) |
+ : invalidValue = value, start = null, end = null, |
+ super(message); |
/** |
- * Create a new [RangeError] with a message for a value and a range. |
+ * Create a new [RangeError] with for an invalid value being outside a range. |
* |
* The allowed range is from [start] to [end], inclusive. |
+ * If `start` or `end` are `null`, the range is infinite in that direction. |
+ * |
+ * For a range from 0 to the length of something, end exclusive, use |
+ * [RangeError.index]. |
+ */ |
+ RangeError.range(this.invalidValue, this.start, this.end, |
+ [String message = "Invalid value"]) : super(message); |
+ |
+ /** |
+ * Creates a new [RangeError] stating that [index] is not a valid index |
+ * into [indexable]. |
+ * |
+ * The [length] is the length of [indexable] at the time of the error. |
+ * If `length` is omitted, it defaults to `indexable.length`. |
+ * |
+ * The message is used as part of the string representation of the error. |
*/ |
- RangeError.range(num value, num start, num end) |
- : super("value $value not in range $start..$end"); |
+ factory RangeError.index(int index, indexable, |
+ [String message, |
+ int length]) = IndexError; |
sra1
2014/11/11 22:04:11
Doesn't this forwarding incorrectly store the inde
Lasse Reichstein Nielsen
2014/11/12 07:38:06
Yes, fixed in follow-up CL.
Only Dart2js actually
|
- String toString() => "RangeError: $message"; |
+ String toString() { |
+ if (invalidValue == null) return "$message"; |
+ String value = Error.safeToString(invalidValue); |
+ if (start == null) { |
+ if (end == null) { |
+ return "$message ($value)"; |
+ } |
+ return "$message ($value): Value must be less than or equal to $end"; |
+ } |
+ if (end == null) { |
+ return "$message ($value): Value must be greater than or equal to $start"; |
+ } |
+ if (end > start) { |
+ return "$message ($value): Value must be in range $start..$end, " |
+ "inclusive."; |
+ } |
+ if (end < start) return "$message ($value): Valid range is empty"; |
+ return "$message ($value): Only valid value is $start"; |
+ } |
+} |
+ |
+/** |
+ * A specialized [RangeError] used when an index is not in the range |
+ * `0..indexable.length-1`. |
+ * |
+ * Also contains the indexable object, its length at the time of the error, |
+ * and the invalid index itself. |
+ */ |
+class IndexError extends ArgumentError implements RangeError { |
+ /** The indexable object that [index] was not a valid index into. */ |
+ final indexable; |
+ /** The invalid index. */ |
+ final int invalidValue; |
sra1
2014/11/11 22:04:11
This field shadows the field of the same name in A
Lasse Reichstein Nielsen
2014/11/12 07:38:06
Yes, this is silly. Using implements ArgumentError
|
+ /** The length of [indexable] at the time of the error. */ |
+ final int length; |
+ |
+ /** |
+ * Creates a new [IndexError] stating that [invalidValue] is not a valid index |
+ * into [indexable]. |
+ * |
+ * The [length] is the length of [indexable] at the time of the error. |
+ * If `length` is omitted, it defaults to `indexable.length`. |
+ * |
+ * The message is used as part of the string representation of the error. |
+ */ |
+ IndexError(indexable, this.invalidValue, |
+ [String message = "Index out of range", int length]) |
+ : this.indexable = indexable, |
+ this.length = (length != null) ? length : indexable.length, |
+ super(message); |
+ |
+ // Getters inherited from RangeError. |
+ int get start => 0; |
+ int get end => length - 1; |
+ |
+ String toString() { |
+ String target = Error.safeToString(indexable); |
+ if (invalidValue < 0) { |
+ return "RangeError: $message ($target[$invalidValue]): " |
+ "index must not be negative."; |
+ } |
+ return "RangeError: $message: ($target[$invalidValue]): " |
+ "index should be less than $length."; |
+ } |
} |