| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | |
| 2 // for details. All rights reserved. Use of this source code is governed by a | |
| 3 // BSD-style license that can be found in the LICENSE file. | |
| 4 | |
| 5 part of dart.core; | |
| 6 | |
| 7 /** | |
| 8 * Error objects thrown in the case of a program failure. | |
| 9 * | |
| 10 * An `Error` object represents a program failure that the programmer | |
| 11 * should have avoided. | |
| 12 * | |
| 13 * Examples include calling a function with invalid arguments, | |
| 14 * or even with the wrong number of arguments, | |
| 15 * or calling it at a time when it is not allowed. | |
| 16 * | |
| 17 * These are not errors that a caller should expect or catch - | |
| 18 * if they occur, the program is erroneous, | |
| 19 * and terminating the program may be the safest response. | |
| 20 * | |
| 21 * When deciding that a function throws an error, | |
| 22 * the conditions where it happens should be clearly described, | |
| 23 * and they should be detectable and predictable, | |
| 24 * so the programmer using the function can avoid triggering the error. | |
| 25 * | |
| 26 * Such descriptions often uses words like | |
| 27 * "must" or "must not" to describe the condition, | |
| 28 * and if you see words like that in a function's documentation, | |
| 29 * then not satisfying the requirement | |
| 30 * is very likely to cause an error to be thrown. | |
| 31 * | |
| 32 * Example (from [String.contains]): | |
| 33 * | |
| 34 * `startIndex` must not be negative or greater than `length`. | |
| 35 * | |
| 36 * In this case, an error will be thrown if `startIndex` is negative | |
| 37 * or too large. | |
| 38 * | |
| 39 * If the conditions are not detectable before calling a function, | |
| 40 * the called function should not throw an `Error`. | |
| 41 * It may still throw a value, | |
| 42 * but the caller will have to catch the thrown value, | |
| 43 * effectively making it an alternative result rather than an error. | |
| 44 * The thrown object can choose to implement [Exception] | |
| 45 * to document that it represents an exceptional, but not erroneous, occurrence, | |
| 46 * but it has no other effect than documentation. | |
| 47 * | |
| 48 * All non-`null` values can be thrown in Dart. | |
| 49 * Objects extending `Error` are handled specially: | |
| 50 * The first time they are thrown, | |
| 51 * the stack trace at the throw point is recorded | |
| 52 * and stored in the error object. | |
| 53 * It can be retrieved using the [stackTrace] getter. | |
| 54 * An error object that merely implements `Error`, and doesn't extend it, | |
| 55 * will not store the stack trace automatically. | |
| 56 * | |
| 57 * Error objects are also used for system wide failures | |
| 58 * like stack overflow or an out-of-memory situation. | |
| 59 * | |
| 60 * Since errors are not created to be caught, | |
| 61 * there is no need for subclasses to distinguish the errors. | |
| 62 * Instead subclasses have been created in order to make groups | |
| 63 * of related errors easy to create with consistent error messages. | |
| 64 * For example, the [String.contains] method will use a [RangeError] | |
| 65 * if its `startIndex` isn't in the range `0..length`, | |
| 66 * which is easily created by `new RangeError.range(startIndex, 0, length)`. | |
| 67 */ | |
| 68 class Error { | |
| 69 Error(); // Prevent use as mixin. | |
| 70 | |
| 71 /** | |
| 72 * Safely convert a value to a [String] description. | |
| 73 * | |
| 74 * The conversion is guaranteed to not throw, so it won't use the object's | |
| 75 * toString method. | |
| 76 */ | |
| 77 static String safeToString(Object object) { | |
| 78 if (object is num || object is bool || null == object) { | |
| 79 return object.toString(); | |
| 80 } | |
| 81 if (object is String) { | |
| 82 return _stringToSafeString(object); | |
| 83 } | |
| 84 return _objectToString(object); | |
| 85 } | |
| 86 | |
| 87 /** Convert string to a valid string literal with no control characters. */ | |
| 88 static String _stringToSafeString(String string) { | |
| 89 return jsonEncodeNative(string); | |
| 90 } | |
| 91 | |
| 92 static String _objectToString(Object object) { | |
| 93 return Primitives.objectToString(object); | |
| 94 } | |
| 95 | |
| 96 StackTrace get stackTrace => Primitives.extractStackTrace(this); | |
| 97 } | |
| 98 | |
| 99 /** | |
| 100 * Error thrown by the runtime system when an assert statement fails. | |
| 101 */ | |
| 102 class AssertionError extends Error { | |
| 103 } | |
| 104 | |
| 105 /** | |
| 106 * Error thrown by the runtime system when a type assertion fails. | |
| 107 */ | |
| 108 class TypeError extends AssertionError { | |
| 109 } | |
| 110 | |
| 111 /** | |
| 112 * Error thrown by the runtime system when a cast operation fails. | |
| 113 */ | |
| 114 class CastError extends Error { | |
| 115 } | |
| 116 | |
| 117 /** | |
| 118 * Error thrown when attempting to throw [:null:]. | |
| 119 */ | |
| 120 class NullThrownError extends Error { | |
| 121 String toString() => "Throw of null."; | |
| 122 } | |
| 123 | |
| 124 /** | |
| 125 * Error thrown when a function is passed an unacceptable argument. | |
| 126 */ | |
| 127 class ArgumentError extends Error { | |
| 128 /** Whether value was provided. */ | |
| 129 final bool _hasValue; | |
| 130 /** The invalid value. */ | |
| 131 final invalidValue; | |
| 132 /** Name of the invalid argument, if available. */ | |
| 133 final String name; | |
| 134 /** Message describing the problem. */ | |
| 135 final message; | |
| 136 | |
| 137 /** | |
| 138 * The [message] describes the erroneous argument. | |
| 139 * | |
| 140 * Existing code may be using `message` to hold the invalid value. | |
| 141 * If the `message` is not a [String], it is assumed to be a value instead | |
| 142 * of a message. | |
| 143 */ | |
| 144 ArgumentError([this.message]) | |
| 145 : invalidValue = null, | |
| 146 _hasValue = false, | |
| 147 name = null; | |
| 148 | |
| 149 /** | |
| 150 * Creates error containing the invalid [value]. | |
| 151 * | |
| 152 * A message is built by suffixing the [message] argument with | |
| 153 * the [name] argument (if provided) and the value. Example | |
| 154 * | |
| 155 * "Invalid argument (foo): null" | |
| 156 * | |
| 157 * The `name` should match the argument name of the function, but if | |
| 158 * the function is a method implementing an interface, and its argument | |
| 159 * names differ from the interface, it might be more useful to use the | |
| 160 * interface method's argument name (or just rename arguments to match). | |
| 161 */ | |
| 162 ArgumentError.value(value, | |
| 163 [String this.name, | |
| 164 String this.message = "Invalid argument"]) | |
| 165 : invalidValue = value, | |
| 166 _hasValue = true; | |
| 167 | |
| 168 /** | |
| 169 * Create an argument error for a `null` argument that must not be `null`. | |
| 170 * | |
| 171 * Shorthand for calling [ArgumentError.value] with a `null` value and a | |
| 172 * message of `"Must not be null"`. | |
| 173 */ | |
| 174 ArgumentError.notNull([String name]) | |
| 175 : this.value(null, name, "Must not be null"); | |
| 176 | |
| 177 String toString() { | |
| 178 if (!_hasValue) { | |
| 179 var result = "Invalid arguments(s)"; | |
| 180 if (message != null) { | |
| 181 result = "$result: $message"; | |
| 182 } | |
| 183 return result; | |
| 184 } | |
| 185 String nameString = ""; | |
| 186 if (name != null) { | |
| 187 nameString = " ($name)"; | |
| 188 } | |
| 189 return "$message$nameString: ${Error.safeToString(invalidValue)}"; | |
| 190 } | |
| 191 } | |
| 192 | |
| 193 /** | |
| 194 * Error thrown due to an index being outside a valid range. | |
| 195 */ | |
| 196 class RangeError extends ArgumentError { | |
| 197 /** The minimum value that [value] is allowed to assume. */ | |
| 198 final num start; | |
| 199 /** The maximum value that [value] is allowed to assume. */ | |
| 200 final num end; | |
| 201 | |
| 202 // TODO(lrn): This constructor should be called only with string values. | |
| 203 // It currently isn't in all cases. | |
| 204 /** | |
| 205 * Create a new [RangeError] with the given [message]. | |
| 206 */ | |
| 207 RangeError(var message) | |
| 208 : start = null, end = null, super(message); | |
| 209 | |
| 210 /** | |
| 211 * Create a new [RangeError] with a message for the given [value]. | |
| 212 * | |
| 213 * An optional [name] can specify the argument name that has the | |
| 214 * invalid value, and the [message] can override the default error | |
| 215 * description. | |
| 216 */ | |
| 217 RangeError.value(num value, [String name, String message]) | |
| 218 : start = null, end = null, | |
| 219 super.value(value, name, | |
| 220 (message != null) ? message : "Value not in range"); | |
| 221 | |
| 222 /** | |
| 223 * Create a new [RangeError] with for an invalid value being outside a range. | |
| 224 * | |
| 225 * The allowed range is from [minValue] to [maxValue], inclusive. | |
| 226 * If `minValue` or `maxValue` are `null`, the range is infinite in | |
| 227 * that direction. | |
| 228 * | |
| 229 * For a range from 0 to the length of something, end exclusive, use | |
| 230 * [RangeError.index]. | |
| 231 * | |
| 232 * An optional [name] can specify the argument name that has the | |
| 233 * invalid value, and the [message] can override the default error | |
| 234 * description. | |
| 235 */ | |
| 236 RangeError.range(num invalidValue, int minValue, int maxValue, | |
| 237 [String name, String message]) | |
| 238 : start = minValue, | |
| 239 end = maxValue, | |
| 240 super.value(invalidValue, name, | |
| 241 (message != null) ? message : "Invalid value"); | |
| 242 | |
| 243 /** | |
| 244 * Creates a new [RangeError] stating that [index] is not a valid index | |
| 245 * into [indexable]. | |
| 246 * | |
| 247 * An optional [name] can specify the argument name that has the | |
| 248 * invalid value, and the [message] can override the default error | |
| 249 * description. | |
| 250 * | |
| 251 * The [length] is the length of [indexable] at the time of the error. | |
| 252 * If `length` is omitted, it defaults to `indexable.length`. | |
| 253 */ | |
| 254 factory RangeError.index(int index, indexable, | |
| 255 [String name, | |
| 256 String message, | |
| 257 int length]) = IndexError; | |
| 258 | |
| 259 /** | |
| 260 * Check that a [value] lies in a specific interval. | |
| 261 * | |
| 262 * Throws if [value] is not in the interval. | |
| 263 * The interval is from [minValue] to [maxValue], both inclusive. | |
| 264 */ | |
| 265 static void checkValueInInterval(int value, int minValue, int maxValue, | |
| 266 [String name, String message]) { | |
| 267 if (value < minValue || value > maxValue) { | |
| 268 throw new RangeError.range(value, minValue, maxValue, name, message); | |
| 269 } | |
| 270 } | |
| 271 | |
| 272 /** | |
| 273 * Check that a value is a valid index into an indexable object. | |
| 274 * | |
| 275 * Throws if [index] is not a valid index into [indexable]. | |
| 276 * | |
| 277 * An indexable object is one that has a `length` and a and index-operator | |
| 278 * `[]` that accepts an index if `0 <= index < length`. | |
| 279 * | |
| 280 * If [length] is provided, it is used as the length of the indexable object, | |
| 281 * otherwise the length is found as `idexable.length`. | |
| 282 */ | |
| 283 static void checkValidIndex(int index, var indexable, | |
| 284 [String name, int length, String message]) { | |
| 285 if (length == null) length = indexable.length; | |
| 286 if (index < 0 || index >= length) { | |
| 287 if (name == null) name = "index"; | |
| 288 throw new RangeError.index(index, indexable, name, message, length); | |
| 289 } | |
| 290 } | |
| 291 | |
| 292 /** | |
| 293 * Check that a range represents a slice of an indexable object. | |
| 294 * | |
| 295 * Throws if the range is not valid for an indexable object with | |
| 296 * the given [length]. | |
| 297 * A range is valid for an indexable object with a given [length] | |
| 298 * | |
| 299 * if `0 <= [start] <= [end] <= [length]`. | |
| 300 * An `end` of `null` is considered equivalent to `length`. | |
| 301 * | |
| 302 * The [startName] and [endName] defaults to `"start"` and `"end"`, | |
| 303 * respectively. | |
| 304 */ | |
| 305 static void checkValidRange(int start, int end, int length, | |
| 306 [String startName, String endName, | |
| 307 String message]) { | |
| 308 if (start < 0 || start > length) { | |
| 309 if (startName == null) startName = "start"; | |
| 310 throw new RangeError.range(start, 0, length, startName, message); | |
| 311 } | |
| 312 if (end != null && (end < start || end > length)) { | |
| 313 if (endName == null) endName = "end"; | |
| 314 throw new RangeError.range(end, start, length, endName, message); | |
| 315 } | |
| 316 } | |
| 317 | |
| 318 /** | |
| 319 * Check that an integer value isn't negative. | |
| 320 * | |
| 321 * Throws if the value is negative. | |
| 322 */ | |
| 323 static void checkNotNegative(int value, [String name, String message]) { | |
| 324 if (value < 0) throw new RangeError.range(value, 0, null, name, message); | |
| 325 } | |
| 326 | |
| 327 String toString() { | |
| 328 if (!_hasValue) return "RangeError: $message"; | |
| 329 String value = Error.safeToString(invalidValue); | |
| 330 String explanation = ""; | |
| 331 if (start == null) { | |
| 332 if (end != null) { | |
| 333 explanation = ": Not less than or equal to $end"; | |
| 334 } | |
| 335 // If both are null, we don't add a description of the limits. | |
| 336 } else if (end == null) { | |
| 337 explanation = ": Not greater than or equal to $start"; | |
| 338 } else if (end > start) { | |
| 339 explanation = ": Not in range $start..$end, inclusive."; | |
| 340 } else if (end < start) { | |
| 341 explanation = ": Valid value range is empty"; | |
| 342 } else { | |
| 343 // end == start. | |
| 344 explanation = ": Only valid value is $start"; | |
| 345 } | |
| 346 return "RangeError: $message ($value)$explanation"; | |
| 347 } | |
| 348 } | |
| 349 | |
| 350 /** | |
| 351 * A specialized [RangeError] used when an index is not in the range | |
| 352 * `0..indexable.length-1`. | |
| 353 * | |
| 354 * Also contains the indexable object, its length at the time of the error, | |
| 355 * and the invalid index itself. | |
| 356 */ | |
| 357 class IndexError extends ArgumentError implements RangeError { | |
| 358 /** The indexable object that [index] was not a valid index into. */ | |
| 359 final indexable; | |
| 360 /** The length of [indexable] at the time of the error. */ | |
| 361 final int length; | |
| 362 | |
| 363 /** | |
| 364 * Creates a new [IndexError] stating that [invalidValue] is not a valid index | |
| 365 * into [indexable]. | |
| 366 * | |
| 367 * The [length] is the length of [indexable] at the time of the error. | |
| 368 * If `length` is omitted, it defaults to `indexable.length`. | |
| 369 * | |
| 370 * The message is used as part of the string representation of the error. | |
| 371 */ | |
| 372 IndexError(int invalidValue, indexable, | |
| 373 [String name, String message, int length]) | |
| 374 : this.indexable = indexable, | |
| 375 this.length = (length != null) ? length : indexable.length, | |
| 376 super.value(invalidValue, name, | |
| 377 (message != null) ? message : "Index out of range"); | |
| 378 | |
| 379 // Getters inherited from RangeError. | |
| 380 int get start => 0; | |
| 381 int get end => length - 1; | |
| 382 | |
| 383 String toString() { | |
| 384 assert(_hasValue); | |
| 385 String target = Error.safeToString(indexable); | |
| 386 var explanation = "index should be less than $length"; | |
| 387 if (invalidValue < 0) { | |
| 388 explanation = "index must not be negative"; | |
| 389 } | |
| 390 return "RangeError: $message ($target[$invalidValue]): $explanation"; | |
| 391 } | |
| 392 } | |
| 393 | |
| 394 | |
| 395 /** | |
| 396 * Error thrown when control reaches the end of a switch case. | |
| 397 * | |
| 398 * The Dart specification requires this error to be thrown when | |
| 399 * control reaches the end of a switch case (except the last case | |
| 400 * of a switch) without meeting a break or similar end of the control | |
| 401 * flow. | |
| 402 */ | |
| 403 class FallThroughError extends Error { | |
| 404 FallThroughError(); | |
| 405 } | |
| 406 | |
| 407 /** | |
| 408 * Error thrown when trying to instantiate an abstract class. | |
| 409 */ | |
| 410 class AbstractClassInstantiationError extends Error { | |
| 411 final String _className; | |
| 412 AbstractClassInstantiationError(String this._className); | |
| 413 String toString() => "Cannot instantiate abstract class: '$_className'"; | |
| 414 } | |
| 415 | |
| 416 | |
| 417 /** | |
| 418 * Error thrown by the default implementation of [:noSuchMethod:] on [Object]. | |
| 419 */ | |
| 420 class NoSuchMethodError extends Error { | |
| 421 final Object _receiver; | |
| 422 final Symbol _memberName; | |
| 423 final List _arguments; | |
| 424 final Map<Symbol, dynamic> _namedArguments; | |
| 425 final List _existingArgumentNames; | |
| 426 | |
| 427 /** | |
| 428 * Create a [NoSuchMethodError] corresponding to a failed method call. | |
| 429 * | |
| 430 * The [receiver] is the receiver of the method call. | |
| 431 * That is, the object on which the method was attempted called. | |
| 432 * If the receiver is `null`, it is interpreted as a call to a top-level | |
| 433 * function of a library. | |
| 434 * | |
| 435 * The [memberName] is a [Symbol] representing the name of the called method | |
| 436 * or accessor. It should not be `null`. | |
| 437 * | |
| 438 * The [positionalArguments] is a list of the positional arguments that the | |
| 439 * method was called with. If `null`, it is considered equivalent to the | |
| 440 * empty list. | |
| 441 * | |
| 442 * The [namedArguments] is a map from [Symbol]s to the values of named | |
| 443 * arguments that the method was called with. | |
| 444 * | |
| 445 * The optional [exisitingArgumentNames] is the expected parameters of a | |
| 446 * method with the same name on the receiver, if available. This is | |
| 447 * the signature of the method that would have been called if the parameters | |
| 448 * had matched. | |
| 449 */ | |
| 450 NoSuchMethodError(Object receiver, | |
| 451 Symbol memberName, | |
| 452 List positionalArguments, | |
| 453 Map<Symbol ,dynamic> namedArguments, | |
| 454 [List existingArgumentNames = null]) | |
| 455 : _receiver = receiver, | |
| 456 _memberName = memberName, | |
| 457 _arguments = positionalArguments, | |
| 458 _namedArguments = namedArguments, | |
| 459 _existingArgumentNames = existingArgumentNames; | |
| 460 | |
| 461 String toString() { | |
| 462 StringBuffer sb = new StringBuffer(); | |
| 463 int i = 0; | |
| 464 if (_arguments != null) { | |
| 465 for (; i < _arguments.length; i++) { | |
| 466 if (i > 0) { | |
| 467 sb.write(", "); | |
| 468 } | |
| 469 sb.write(Error.safeToString(_arguments[i])); | |
| 470 } | |
| 471 } | |
| 472 if (_namedArguments != null) { | |
| 473 _namedArguments.forEach((Symbol key, var value) { | |
| 474 if (i > 0) { | |
| 475 sb.write(", "); | |
| 476 } | |
| 477 sb.write(_symbolToString(key)); | |
| 478 sb.write(": "); | |
| 479 sb.write(Error.safeToString(value)); | |
| 480 i++; | |
| 481 }); | |
| 482 } | |
| 483 if (_existingArgumentNames == null) { | |
| 484 return "NoSuchMethodError : method not found: '$_memberName'\n" | |
| 485 "Receiver: ${Error.safeToString(_receiver)}\n" | |
| 486 "Arguments: [$sb]"; | |
| 487 } else { | |
| 488 String actualParameters = sb.toString(); | |
| 489 sb = new StringBuffer(); | |
| 490 for (int i = 0; i < _existingArgumentNames.length; i++) { | |
| 491 if (i > 0) { | |
| 492 sb.write(", "); | |
| 493 } | |
| 494 sb.write(_existingArgumentNames[i]); | |
| 495 } | |
| 496 String formalParameters = sb.toString(); | |
| 497 return "NoSuchMethodError: incorrect number of arguments passed to " | |
| 498 "method named '$_memberName'\n" | |
| 499 "Receiver: ${Error.safeToString(_receiver)}\n" | |
| 500 "Tried calling: $_memberName($actualParameters)\n" | |
| 501 "Found: $_memberName($formalParameters)"; | |
| 502 } | |
| 503 } | |
| 504 } | |
| 505 | |
| 506 | |
| 507 /** | |
| 508 * The operation was not allowed by the object. | |
| 509 * | |
| 510 * This [Error] is thrown when an instance cannot implement one of the methods | |
| 511 * in its signature. | |
| 512 */ | |
| 513 class UnsupportedError extends Error { | |
| 514 final String message; | |
| 515 UnsupportedError(this.message); | |
| 516 String toString() => "Unsupported operation: $message"; | |
| 517 } | |
| 518 | |
| 519 | |
| 520 /** | |
| 521 * Thrown by operations that have not been implemented yet. | |
| 522 * | |
| 523 * This [Error] is thrown by unfinished code that hasn't yet implemented | |
| 524 * all the features it needs. | |
| 525 * | |
| 526 * If a class is not intending to implement the feature, it should throw | |
| 527 * an [UnsupportedError] instead. This error is only intended for | |
| 528 * use during development. | |
| 529 */ | |
| 530 class UnimplementedError extends Error implements UnsupportedError { | |
| 531 final String message; | |
| 532 UnimplementedError([String this.message]); | |
| 533 String toString() => (this.message != null | |
| 534 ? "UnimplementedError: $message" | |
| 535 : "UnimplementedError"); | |
| 536 } | |
| 537 | |
| 538 | |
| 539 /** | |
| 540 * The operation was not allowed by the current state of the object. | |
| 541 * | |
| 542 * This is a generic error used for a variety of different erroneous | |
| 543 * actions. The message should be descriptive. | |
| 544 */ | |
| 545 class StateError extends Error { | |
| 546 final String message; | |
| 547 StateError(this.message); | |
| 548 String toString() => "Bad state: $message"; | |
| 549 } | |
| 550 | |
| 551 | |
| 552 /** | |
| 553 * Error occurring when a collection is modified during iteration. | |
| 554 * | |
| 555 * Some modifications may be allowed for some collections, so each collection | |
| 556 * ([Iterable] or similar collection of values) should declare which operations | |
| 557 * are allowed during an iteration. | |
| 558 */ | |
| 559 class ConcurrentModificationError extends Error { | |
| 560 /** The object that was modified in an incompatible way. */ | |
| 561 final Object modifiedObject; | |
| 562 | |
| 563 ConcurrentModificationError([this.modifiedObject]); | |
| 564 | |
| 565 String toString() { | |
| 566 if (modifiedObject == null) { | |
| 567 return "Concurrent modification during iteration."; | |
| 568 } | |
| 569 return "Concurrent modification during iteration: " | |
| 570 "${Error.safeToString(modifiedObject)}."; | |
| 571 } | |
| 572 } | |
| 573 | |
| 574 | |
| 575 class OutOfMemoryError implements Error { | |
| 576 const OutOfMemoryError(); | |
| 577 String toString() => "Out of Memory"; | |
| 578 | |
| 579 StackTrace get stackTrace => null; | |
| 580 } | |
| 581 | |
| 582 | |
| 583 class StackOverflowError implements Error { | |
| 584 const StackOverflowError(); | |
| 585 String toString() => "Stack Overflow"; | |
| 586 | |
| 587 StackTrace get stackTrace => null; | |
| 588 } | |
| 589 | |
| 590 /** | |
| 591 * Error thrown when a lazily initialized variable cannot be initialized. | |
| 592 * | |
| 593 * A static/library variable with an initializer expression is initialized | |
| 594 * the first time it is read. If evaluating the initializer expression causes | |
| 595 * another read of the variable, this error is thrown. | |
| 596 */ | |
| 597 class CyclicInitializationError extends Error { | |
| 598 final String variableName; | |
| 599 CyclicInitializationError([this.variableName]); | |
| 600 String toString() => variableName == null | |
| 601 ? "Reading static variable during its initialization" | |
| 602 : "Reading static variable '$variableName' during its initialization"; | |
| 603 } | |
| OLD | NEW |