OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 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 | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 part of dart.core; | 5 part of dart.core; |
6 | 6 |
7 /** | 7 /** |
8 * Error objects thrown in the case of a program failure. | 8 * Error objects thrown in the case of a program failure. |
9 * | 9 * |
10 * An `Error` object represents a program failure that the programmer | 10 * An `Error` object represents a program failure that the programmer |
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
150 * | 150 * |
151 * "Invalid argument (foo): null" | 151 * "Invalid argument (foo): null" |
152 * | 152 * |
153 * The `name` should match the argument name of the function, but if | 153 * The `name` should match the argument name of the function, but if |
154 * the function is a method implementing an interface, and its argument | 154 * the function is a method implementing an interface, and its argument |
155 * names differ from the interface, it might be more useful to use the | 155 * names differ from the interface, it might be more useful to use the |
156 * interface method's argument name (or just rename arguments to match). | 156 * interface method's argument name (or just rename arguments to match). |
157 */ | 157 */ |
158 ArgumentError.value(value, | 158 ArgumentError.value(value, |
159 [String this.name, | 159 [String this.name, |
160 String this.message = "Invalid argument"]) | 160 String this.message]) |
161 : invalidValue = value, | 161 : invalidValue = value, |
162 _hasValue = true; | 162 _hasValue = true; |
163 | 163 |
164 /** | 164 /** |
165 * Create an argument error for a `null` argument that must not be `null`. | 165 * Create an argument error for a `null` argument that must not be `null`. |
166 * | |
167 * Shorthand for calling [ArgumentError.value] with a `null` value and a | |
168 * message of `"Must not be null"`. | |
169 */ | 166 */ |
170 ArgumentError.notNull([String name]) | 167 ArgumentError.notNull([this.name]) |
171 : this.value(null, name, "Must not be null"); | 168 : _hasValue = false, |
| 169 message = "Must not be null", |
| 170 invalidValue = null; |
| 171 |
| 172 // Helper functions for toString overridden in subclasses. |
| 173 String get _errorName => "Invalid argument${!_hasValue ? "(s)" : ""}"; |
| 174 String get _errorExplanation => ""; |
172 | 175 |
173 String toString() { | 176 String toString() { |
174 if (!_hasValue) { | |
175 var result = "Invalid arguments(s)"; | |
176 if (message != null) { | |
177 result = "$result: $message"; | |
178 } | |
179 return result; | |
180 } | |
181 String nameString = ""; | 177 String nameString = ""; |
182 if (name != null) { | 178 if (name != null) { |
183 nameString = " ($name)"; | 179 nameString = " ($name)"; |
184 } | 180 } |
185 return "$message$nameString: ${Error.safeToString(invalidValue)}"; | 181 var message = (this.message == null) ? "" : ": ${this.message}"; |
| 182 String prefix = "$_errorName$nameString$message"; |
| 183 if (!_hasValue) return prefix; |
| 184 // If we know the invalid value, we can try to describe the problem. |
| 185 String explanation = _errorExplanation; |
| 186 String errorValue = Error.safeToString(invalidValue); |
| 187 return "$prefix$explanation: $errorValue"; |
186 } | 188 } |
187 } | 189 } |
188 | 190 |
189 /** | 191 /** |
190 * Error thrown due to an index being outside a valid range. | 192 * Error thrown due to an index being outside a valid range. |
191 */ | 193 */ |
192 class RangeError extends ArgumentError { | 194 class RangeError extends ArgumentError { |
193 /** The minimum value that [value] is allowed to assume. */ | 195 /** The minimum value that [value] is allowed to assume. */ |
194 final num start; | 196 final num start; |
195 /** The maximum value that [value] is allowed to assume. */ | 197 /** The maximum value that [value] is allowed to assume. */ |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
267 | 269 |
268 /** | 270 /** |
269 * Check that a value is a valid index into an indexable object. | 271 * Check that a value is a valid index into an indexable object. |
270 * | 272 * |
271 * Throws if [index] is not a valid index into [indexable]. | 273 * Throws if [index] is not a valid index into [indexable]. |
272 * | 274 * |
273 * An indexable object is one that has a `length` and a and index-operator | 275 * An indexable object is one that has a `length` and a and index-operator |
274 * `[]` that accepts an index if `0 <= index < length`. | 276 * `[]` that accepts an index if `0 <= index < length`. |
275 * | 277 * |
276 * If [length] is provided, it is used as the length of the indexable object, | 278 * If [length] is provided, it is used as the length of the indexable object, |
277 * otherwise the length is found as `idexable.length`. | 279 * otherwise the length is found as `indexable.length`. |
278 */ | 280 */ |
279 static void checkValidIndex(int index, var indexable, | 281 static void checkValidIndex(int index, var indexable, |
280 [String name, int length, String message]) { | 282 [String name, int length, String message]) { |
281 if (length == null) length = indexable.length; | 283 if (length == null) length = indexable.length; |
282 if (index < 0 || index >= length) { | 284 // Comparing with `0` as receiver produces better dart2js type inference. |
| 285 if (0 > index || index >= length) { |
283 if (name == null) name = "index"; | 286 if (name == null) name = "index"; |
284 throw new RangeError.index(index, indexable, name, message, length); | 287 throw new RangeError.index(index, indexable, name, message, length); |
285 } | 288 } |
286 } | 289 } |
287 | 290 |
288 /** | 291 /** |
289 * Check that a range represents a slice of an indexable object. | 292 * Check that a range represents a slice of an indexable object. |
290 * | 293 * |
291 * Throws if the range is not valid for an indexable object with | 294 * Throws if the range is not valid for an indexable object with |
292 * the given [length]. | 295 * the given [length]. |
293 * A range is valid for an indexable object with a given [length] | 296 * A range is valid for an indexable object with a given [length] |
294 * | 297 * |
295 * if `0 <= [start] <= [end] <= [length]`. | 298 * if `0 <= [start] <= [end] <= [length]`. |
296 * An `end` of `null` is considered equivalent to `length`. | 299 * An `end` of `null` is considered equivalent to `length`. |
297 * | 300 * |
298 * The [startName] and [endName] defaults to `"start"` and `"end"`, | 301 * The [startName] and [endName] defaults to `"start"` and `"end"`, |
299 * respectively. | 302 * respectively. |
| 303 * |
| 304 * Returns the actual `end` value, which is `length` if `end` is `null`, |
| 305 * and `end` otherwise. |
300 */ | 306 */ |
301 static void checkValidRange(int start, int end, int length, | 307 static int checkValidRange(int start, int end, int length, |
302 [String startName, String endName, | 308 [String startName, String endName, |
303 String message]) { | 309 String message]) { |
304 if (start < 0 || start > length) { | 310 // Comparing with `0` as receiver produces better dart2js type inference. |
| 311 // Ditto `start > end` below. |
| 312 if (0 > start || start > length) { |
305 if (startName == null) startName = "start"; | 313 if (startName == null) startName = "start"; |
306 throw new RangeError.range(start, 0, length, startName, message); | 314 throw new RangeError.range(start, 0, length, startName, message); |
307 } | 315 } |
308 if (end != null && (end < start || end > length)) { | 316 if (end != null) { |
309 if (endName == null) endName = "end"; | 317 if (start > end || end > length) { |
310 throw new RangeError.range(end, start, length, endName, message); | 318 if (endName == null) endName = "end"; |
| 319 throw new RangeError.range(end, start, length, endName, message); |
| 320 } |
| 321 return end; |
311 } | 322 } |
| 323 return length; |
312 } | 324 } |
313 | 325 |
314 /** | 326 /** |
315 * Check that an integer value isn't negative. | 327 * Check that an integer value isn't negative. |
316 * | 328 * |
317 * Throws if the value is negative. | 329 * Throws if the value is negative. |
318 */ | 330 */ |
319 static void checkNotNegative(int value, [String name, String message]) { | 331 static void checkNotNegative(int value, [String name, String message]) { |
320 if (value < 0) throw new RangeError.range(value, 0, null, name, message); | 332 if (value < 0) throw new RangeError.range(value, 0, null, name, message); |
321 } | 333 } |
322 | 334 |
323 String toString() { | 335 String get _errorName => "RangeError"; |
324 if (!_hasValue) return "RangeError: $message"; | 336 String get _errorExplanation { |
325 String value = Error.safeToString(invalidValue); | 337 assert(_hasValue); |
326 String explanation = ""; | 338 String explanation = ""; |
327 if (start == null) { | 339 if (start == null) { |
328 if (end != null) { | 340 if (end != null) { |
329 explanation = ": Not less than or equal to $end"; | 341 explanation = ": Not less than or equal to $end"; |
330 } | 342 } |
331 // If both are null, we don't add a description of the limits. | 343 // If both are null, we don't add a description of the limits. |
332 } else if (end == null) { | 344 } else if (end == null) { |
333 explanation = ": Not greater than or equal to $start"; | 345 explanation = ": Not greater than or equal to $start"; |
334 } else if (end > start) { | 346 } else if (end > start) { |
335 explanation = ": Not in range $start..$end, inclusive."; | 347 explanation = ": Not in range $start..$end, inclusive"; |
336 } else if (end < start) { | 348 } else if (end < start) { |
337 explanation = ": Valid value range is empty"; | 349 explanation = ": Valid value range is empty"; |
338 } else { | 350 } else { |
339 // end == start. | 351 // end == start. |
340 explanation = ": Only valid value is $start"; | 352 explanation = ": Only valid value is $start"; |
341 } | 353 } |
342 return "RangeError: $message ($value)$explanation"; | 354 return explanation; |
343 } | 355 } |
344 } | 356 } |
345 | 357 |
346 /** | 358 /** |
347 * A specialized [RangeError] used when an index is not in the range | 359 * A specialized [RangeError] used when an index is not in the range |
348 * `0..indexable.length-1`. | 360 * `0..indexable.length-1`. |
349 * | 361 * |
350 * Also contains the indexable object, its length at the time of the error, | 362 * Also contains the indexable object, its length at the time of the error, |
351 * and the invalid index itself. | 363 * and the invalid index itself. |
352 */ | 364 */ |
(...skipping 16 matching lines...) Expand all Loading... |
369 [String name, String message, int length]) | 381 [String name, String message, int length]) |
370 : this.indexable = indexable, | 382 : this.indexable = indexable, |
371 this.length = (length != null) ? length : indexable.length, | 383 this.length = (length != null) ? length : indexable.length, |
372 super.value(invalidValue, name, | 384 super.value(invalidValue, name, |
373 (message != null) ? message : "Index out of range"); | 385 (message != null) ? message : "Index out of range"); |
374 | 386 |
375 // Getters inherited from RangeError. | 387 // Getters inherited from RangeError. |
376 int get start => 0; | 388 int get start => 0; |
377 int get end => length - 1; | 389 int get end => length - 1; |
378 | 390 |
379 String toString() { | 391 String get _errorName => "RangeError"; |
| 392 String get _errorExplanation { |
380 assert(_hasValue); | 393 assert(_hasValue); |
381 String target = Error.safeToString(indexable); | |
382 var explanation = "index should be less than $length"; | |
383 if (invalidValue < 0) { | 394 if (invalidValue < 0) { |
384 explanation = "index must not be negative"; | 395 return ": index must not be negative"; |
385 } | 396 } |
386 return "RangeError: $message ($target[$invalidValue]): $explanation"; | 397 if (length == 0) { |
| 398 return ": no indices are valid"; |
| 399 } |
| 400 return ": index should be less than $length"; |
387 } | 401 } |
388 } | 402 } |
389 | 403 |
390 | 404 |
391 /** | 405 /** |
392 * Error thrown when control reaches the end of a switch case. | 406 * Error thrown when control reaches the end of a switch case. |
393 * | 407 * |
394 * The Dart specification requires this error to be thrown when | 408 * The Dart specification requires this error to be thrown when |
395 * control reaches the end of a switch case (except the last case | 409 * control reaches the end of a switch case (except the last case |
396 * of a switch) without meeting a break or similar end of the control | 410 * of a switch) without meeting a break or similar end of the control |
(...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
548 * the first time it is read. If evaluating the initializer expression causes | 562 * the first time it is read. If evaluating the initializer expression causes |
549 * another read of the variable, this error is thrown. | 563 * another read of the variable, this error is thrown. |
550 */ | 564 */ |
551 class CyclicInitializationError extends Error { | 565 class CyclicInitializationError extends Error { |
552 final String variableName; | 566 final String variableName; |
553 CyclicInitializationError([this.variableName]); | 567 CyclicInitializationError([this.variableName]); |
554 String toString() => variableName == null | 568 String toString() => variableName == null |
555 ? "Reading static variable during its initialization" | 569 ? "Reading static variable during its initialization" |
556 : "Reading static variable '$variableName' during its initialization"; | 570 : "Reading static variable '$variableName' during its initialization"; |
557 } | 571 } |
OLD | NEW |