| 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 external static String _stringToSafeString(String string); | |
| 89 | |
| 90 external static String _objectToString(Object object); | |
| 91 | |
| 92 external StackTrace get stackTrace; | |
| 93 } | |
| 94 | |
| 95 /** | |
| 96 * Error thrown by the runtime system when an assert statement fails. | |
| 97 */ | |
| 98 class AssertionError extends Error { | |
| 99 AssertionError(); | |
| 100 String toString() => "Assertion failed"; | |
| 101 } | |
| 102 | |
| 103 /** | |
| 104 * Error thrown by the runtime system when a type assertion fails. | |
| 105 */ | |
| 106 class TypeError extends AssertionError { | |
| 107 } | |
| 108 | |
| 109 /** | |
| 110 * Error thrown by the runtime system when a cast operation fails. | |
| 111 */ | |
| 112 class CastError extends Error { | |
| 113 } | |
| 114 | |
| 115 /** | |
| 116 * Error thrown when attempting to throw [:null:]. | |
| 117 */ | |
| 118 class NullThrownError extends Error { | |
| 119 String toString() => "Throw of null."; | |
| 120 } | |
| 121 | |
| 122 /** | |
| 123 * Error thrown when a function is passed an unacceptable argument. | |
| 124 */ | |
| 125 class ArgumentError extends Error { | |
| 126 /** Whether value was provided. */ | |
| 127 final bool _hasValue; | |
| 128 /** The invalid value. */ | |
| 129 final invalidValue; | |
| 130 /** Name of the invalid argument, if available. */ | |
| 131 final String name; | |
| 132 /** Message describing the problem. */ | |
| 133 final message; | |
| 134 | |
| 135 /** | |
| 136 * The [message] describes the erroneous argument. | |
| 137 * | |
| 138 * Existing code may be using `message` to hold the invalid value. | |
| 139 * If the `message` is not a [String], it is assumed to be a value instead | |
| 140 * of a message. | |
| 141 */ | |
| 142 ArgumentError([this.message]) | |
| 143 : invalidValue = null, | |
| 144 _hasValue = false, | |
| 145 name = null; | |
| 146 | |
| 147 /** | |
| 148 * Creates error containing the invalid [value]. | |
| 149 * | |
| 150 * A message is built by suffixing the [message] argument with | |
| 151 * the [name] argument (if provided) and the value. Example | |
| 152 * | |
| 153 * "Invalid argument (foo): null" | |
| 154 * | |
| 155 * The `name` should match the argument name of the function, but if | |
| 156 * the function is a method implementing an interface, and its argument | |
| 157 * names differ from the interface, it might be more useful to use the | |
| 158 * interface method's argument name (or just rename arguments to match). | |
| 159 */ | |
| 160 ArgumentError.value(value, | |
| 161 [String this.name, | |
| 162 String this.message]) | |
| 163 : invalidValue = value, | |
| 164 _hasValue = true; | |
| 165 | |
| 166 /** | |
| 167 * Create an argument error for a `null` argument that must not be `null`. | |
| 168 */ | |
| 169 ArgumentError.notNull([this.name]) | |
| 170 : _hasValue = false, | |
| 171 message = "Must not be null", | |
| 172 invalidValue = null; | |
| 173 | |
| 174 // Helper functions for toString overridden in subclasses. | |
| 175 String get _errorName => "Invalid argument${!_hasValue ? "(s)" : ""}"; | |
| 176 String get _errorExplanation => ""; | |
| 177 | |
| 178 String toString() { | |
| 179 String nameString = ""; | |
| 180 if (name != null) { | |
| 181 nameString = " ($name)"; | |
| 182 } | |
| 183 var message = (this.message == null) ? "" : ": ${this.message}"; | |
| 184 String prefix = "$_errorName$nameString$message"; | |
| 185 if (!_hasValue) return prefix; | |
| 186 // If we know the invalid value, we can try to describe the problem. | |
| 187 String explanation = _errorExplanation; | |
| 188 String errorValue = Error.safeToString(invalidValue); | |
| 189 return "$prefix$explanation: $errorValue"; | |
| 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 `indexable.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 // Comparing with `0` as receiver produces better dart2js type inference. | |
| 287 if (0 > index || index >= length) { | |
| 288 if (name == null) name = "index"; | |
| 289 throw new RangeError.index(index, indexable, name, message, length); | |
| 290 } | |
| 291 } | |
| 292 | |
| 293 /** | |
| 294 * Check that a range represents a slice of an indexable object. | |
| 295 * | |
| 296 * Throws if the range is not valid for an indexable object with | |
| 297 * the given [length]. | |
| 298 * A range is valid for an indexable object with a given [length] | |
| 299 * | |
| 300 * if `0 <= [start] <= [end] <= [length]`. | |
| 301 * An `end` of `null` is considered equivalent to `length`. | |
| 302 * | |
| 303 * The [startName] and [endName] defaults to `"start"` and `"end"`, | |
| 304 * respectively. | |
| 305 * | |
| 306 * Returns the actual `end` value, which is `length` if `end` is `null`, | |
| 307 * and `end` otherwise. | |
| 308 */ | |
| 309 static int checkValidRange(int start, int end, int length, | |
| 310 [String startName, String endName, | |
| 311 String message]) { | |
| 312 // Comparing with `0` as receiver produces better dart2js type inference. | |
| 313 // Ditto `start > end` below. | |
| 314 if (0 > start || start > length) { | |
| 315 if (startName == null) startName = "start"; | |
| 316 throw new RangeError.range(start, 0, length, startName, message); | |
| 317 } | |
| 318 if (end != null) { | |
| 319 if (start > end || end > length) { | |
| 320 if (endName == null) endName = "end"; | |
| 321 throw new RangeError.range(end, start, length, endName, message); | |
| 322 } | |
| 323 return end; | |
| 324 } | |
| 325 return length; | |
| 326 } | |
| 327 | |
| 328 /** | |
| 329 * Check that an integer value isn't negative. | |
| 330 * | |
| 331 * Throws if the value is negative. | |
| 332 */ | |
| 333 static void checkNotNegative(int value, [String name, String message]) { | |
| 334 if (value < 0) throw new RangeError.range(value, 0, null, name, message); | |
| 335 } | |
| 336 | |
| 337 String get _errorName => "RangeError"; | |
| 338 String get _errorExplanation { | |
| 339 assert(_hasValue); | |
| 340 String explanation = ""; | |
| 341 if (start == null) { | |
| 342 if (end != null) { | |
| 343 explanation = ": Not less than or equal to $end"; | |
| 344 } | |
| 345 // If both are null, we don't add a description of the limits. | |
| 346 } else if (end == null) { | |
| 347 explanation = ": Not greater than or equal to $start"; | |
| 348 } else if (end > start) { | |
| 349 explanation = ": Not in range $start..$end, inclusive"; | |
| 350 } else if (end < start) { | |
| 351 explanation = ": Valid value range is empty"; | |
| 352 } else { | |
| 353 // end == start. | |
| 354 explanation = ": Only valid value is $start"; | |
| 355 } | |
| 356 return explanation; | |
| 357 } | |
| 358 } | |
| 359 | |
| 360 /** | |
| 361 * A specialized [RangeError] used when an index is not in the range | |
| 362 * `0..indexable.length-1`. | |
| 363 * | |
| 364 * Also contains the indexable object, its length at the time of the error, | |
| 365 * and the invalid index itself. | |
| 366 */ | |
| 367 class IndexError extends ArgumentError implements RangeError { | |
| 368 /** The indexable object that [index] was not a valid index into. */ | |
| 369 final indexable; | |
| 370 /** The length of [indexable] at the time of the error. */ | |
| 371 final int length; | |
| 372 | |
| 373 /** | |
| 374 * Creates a new [IndexError] stating that [invalidValue] is not a valid index | |
| 375 * into [indexable]. | |
| 376 * | |
| 377 * The [length] is the length of [indexable] at the time of the error. | |
| 378 * If `length` is omitted, it defaults to `indexable.length`. | |
| 379 * | |
| 380 * The message is used as part of the string representation of the error. | |
| 381 */ | |
| 382 IndexError(int invalidValue, indexable, | |
| 383 [String name, String message, int length]) | |
| 384 : this.indexable = indexable, | |
| 385 this.length = (length != null) ? length : indexable.length, | |
| 386 super.value(invalidValue, name, | |
| 387 (message != null) ? message : "Index out of range"); | |
| 388 | |
| 389 // Getters inherited from RangeError. | |
| 390 int get start => 0; | |
| 391 int get end => length - 1; | |
| 392 | |
| 393 String get _errorName => "RangeError"; | |
| 394 String get _errorExplanation { | |
| 395 assert(_hasValue); | |
| 396 if (invalidValue < 0) { | |
| 397 return ": index must not be negative"; | |
| 398 } | |
| 399 if (length == 0) { | |
| 400 return ": no indices are valid"; | |
| 401 } | |
| 402 return ": index should be less than $length"; | |
| 403 } | |
| 404 } | |
| 405 | |
| 406 | |
| 407 /** | |
| 408 * Error thrown when control reaches the end of a switch case. | |
| 409 * | |
| 410 * The Dart specification requires this error to be thrown when | |
| 411 * control reaches the end of a switch case (except the last case | |
| 412 * of a switch) without meeting a break or similar end of the control | |
| 413 * flow. | |
| 414 */ | |
| 415 class FallThroughError extends Error { | |
| 416 FallThroughError(); | |
| 417 } | |
| 418 | |
| 419 /** | |
| 420 * Error thrown when trying to instantiate an abstract class. | |
| 421 */ | |
| 422 class AbstractClassInstantiationError extends Error { | |
| 423 final String _className; | |
| 424 AbstractClassInstantiationError(String this._className); | |
| 425 String toString() => "Cannot instantiate abstract class: '$_className'"; | |
| 426 } | |
| 427 | |
| 428 | |
| 429 /** | |
| 430 * Error thrown by the default implementation of [:noSuchMethod:] on [Object]. | |
| 431 */ | |
| 432 class NoSuchMethodError extends Error { | |
| 433 final Object _receiver; | |
| 434 final Symbol _memberName; | |
| 435 final List _arguments; | |
| 436 final Map<Symbol, dynamic> _namedArguments; | |
| 437 final List _existingArgumentNames; | |
| 438 | |
| 439 /** | |
| 440 * Create a [NoSuchMethodError] corresponding to a failed method call. | |
| 441 * | |
| 442 * The [receiver] is the receiver of the method call. | |
| 443 * That is, the object on which the method was attempted called. | |
| 444 * If the receiver is `null`, it is interpreted as a call to a top-level | |
| 445 * function of a library. | |
| 446 * | |
| 447 * The [memberName] is a [Symbol] representing the name of the called method | |
| 448 * or accessor. It should not be `null`. | |
| 449 * | |
| 450 * The [positionalArguments] is a list of the positional arguments that the | |
| 451 * method was called with. If `null`, it is considered equivalent to the | |
| 452 * empty list. | |
| 453 * | |
| 454 * The [namedArguments] is a map from [Symbol]s to the values of named | |
| 455 * arguments that the method was called with. | |
| 456 * | |
| 457 * The optional [existingArgumentNames] is the expected parameters of a | |
| 458 * method with the same name on the receiver, if available. This is | |
| 459 * the signature of the method that would have been called if the parameters | |
| 460 * had matched. | |
| 461 */ | |
| 462 NoSuchMethodError(Object receiver, | |
| 463 Symbol memberName, | |
| 464 List positionalArguments, | |
| 465 Map<Symbol ,dynamic> namedArguments, | |
| 466 [List existingArgumentNames = null]) | |
| 467 : _receiver = receiver, | |
| 468 _memberName = memberName, | |
| 469 _arguments = positionalArguments, | |
| 470 _namedArguments = namedArguments, | |
| 471 _existingArgumentNames = existingArgumentNames; | |
| 472 | |
| 473 external String toString(); | |
| 474 } | |
| 475 | |
| 476 | |
| 477 /** | |
| 478 * The operation was not allowed by the object. | |
| 479 * | |
| 480 * This [Error] is thrown when an instance cannot implement one of the methods | |
| 481 * in its signature. | |
| 482 */ | |
| 483 class UnsupportedError extends Error { | |
| 484 final String message; | |
| 485 UnsupportedError(this.message); | |
| 486 String toString() => "Unsupported operation: $message"; | |
| 487 } | |
| 488 | |
| 489 | |
| 490 /** | |
| 491 * Thrown by operations that have not been implemented yet. | |
| 492 * | |
| 493 * This [Error] is thrown by unfinished code that hasn't yet implemented | |
| 494 * all the features it needs. | |
| 495 * | |
| 496 * If a class is not intending to implement the feature, it should throw | |
| 497 * an [UnsupportedError] instead. This error is only intended for | |
| 498 * use during development. | |
| 499 */ | |
| 500 class UnimplementedError extends Error implements UnsupportedError { | |
| 501 final String message; | |
| 502 UnimplementedError([String this.message]); | |
| 503 String toString() => (this.message != null | |
| 504 ? "UnimplementedError: $message" | |
| 505 : "UnimplementedError"); | |
| 506 } | |
| 507 | |
| 508 | |
| 509 /** | |
| 510 * The operation was not allowed by the current state of the object. | |
| 511 * | |
| 512 * This is a generic error used for a variety of different erroneous | |
| 513 * actions. The message should be descriptive. | |
| 514 */ | |
| 515 class StateError extends Error { | |
| 516 final String message; | |
| 517 StateError(this.message); | |
| 518 String toString() => "Bad state: $message"; | |
| 519 } | |
| 520 | |
| 521 | |
| 522 /** | |
| 523 * Error occurring when a collection is modified during iteration. | |
| 524 * | |
| 525 * Some modifications may be allowed for some collections, so each collection | |
| 526 * ([Iterable] or similar collection of values) should declare which operations | |
| 527 * are allowed during an iteration. | |
| 528 */ | |
| 529 class ConcurrentModificationError extends Error { | |
| 530 /** The object that was modified in an incompatible way. */ | |
| 531 final Object modifiedObject; | |
| 532 | |
| 533 ConcurrentModificationError([this.modifiedObject]); | |
| 534 | |
| 535 String toString() { | |
| 536 if (modifiedObject == null) { | |
| 537 return "Concurrent modification during iteration."; | |
| 538 } | |
| 539 return "Concurrent modification during iteration: " | |
| 540 "${Error.safeToString(modifiedObject)}."; | |
| 541 } | |
| 542 } | |
| 543 | |
| 544 | |
| 545 class OutOfMemoryError implements Error { | |
| 546 const OutOfMemoryError(); | |
| 547 String toString() => "Out of Memory"; | |
| 548 | |
| 549 StackTrace get stackTrace => null; | |
| 550 } | |
| 551 | |
| 552 | |
| 553 class StackOverflowError implements Error { | |
| 554 const StackOverflowError(); | |
| 555 String toString() => "Stack Overflow"; | |
| 556 | |
| 557 StackTrace get stackTrace => null; | |
| 558 } | |
| 559 | |
| 560 /** | |
| 561 * Error thrown when a lazily initialized variable cannot be initialized. | |
| 562 * | |
| 563 * A static/library variable with an initializer expression is initialized | |
| 564 * the first time it is read. If evaluating the initializer expression causes | |
| 565 * another read of the variable, this error is thrown. | |
| 566 */ | |
| 567 class CyclicInitializationError extends Error { | |
| 568 final String variableName; | |
| 569 CyclicInitializationError([this.variableName]); | |
| 570 String toString() => variableName == null | |
| 571 ? "Reading static variable during its initialization" | |
| 572 : "Reading static variable '$variableName' during its initialization"; | |
| 573 } | |
| OLD | NEW |