Index: sdk/lib/_internal/compiler/js_lib/js_helper.dart |
diff --git a/sdk/lib/_internal/compiler/js_lib/js_helper.dart b/sdk/lib/_internal/compiler/js_lib/js_helper.dart |
index 1c6183d4f32f67fa48e559fe73df982f09ffb73f..15f22c82bf0ccdd506be8901a516d9644ff7a4b9 100644 |
--- a/sdk/lib/_internal/compiler/js_lib/js_helper.dart |
+++ b/sdk/lib/_internal/compiler/js_lib/js_helper.dart |
@@ -1388,23 +1388,41 @@ class JsCache { |
* for example, if a non-integer index is given to an optimized |
* indexed access. |
*/ |
+@NoInline() |
iae(argument) { |
throw _argumentError(argument); |
} |
/** |
- * Called by generated code to throw an index-out-of-range exception, |
- * for example, if a bounds check fails in an optimized indexed |
- * access. This may also be called when the index is not an integer, in |
- * which case it throws an illegal-argument exception instead, like |
- * [iae], or when the receiver is null. |
+ * Called by generated code to throw an index-out-of-range exception, for |
+ * example, if a bounds check fails in an optimized indexed access. This may |
+ * also be called when the index is not an integer, in which case it throws an |
+ * illegal-argument exception instead, like [iae], or when the receiver is null. |
*/ |
+@NoInline() |
ioore(receiver, index) { |
if (receiver == null) receiver.length; // Force a NoSuchMethodError. |
- if (index is !int) iae(index); |
- throw new RangeError.value(index); |
+ throw diagnoseIndexError(receiver, index); |
+} |
+ |
+/** |
+ * Diagnoses an indexing error. Returns the ArgumentError or RangeError that |
+ * describes the problem. |
+ */ |
+@NoInline() |
+Error diagnoseIndexError(indexable, index) { |
+ if (index is !int) return new ArgumentError.value(index, 'index'); |
+ int length = indexable.length; |
+ // The following returns the same error that would be thrown by calling |
+ // [RangeError.checkValidIndex] with no optional parameters provided. |
+ if (index < 0 || index >= length) { |
+ return new RangeError.index(index, indexable, 'index', null, length); |
+ } |
+ // The above should always match, but if it does not, use the following. |
+ return new RangeError.value(index, 'index'); |
} |
+ |
stringLastIndexOfUnchecked(receiver, element, start) |
=> JS('int', r'#.lastIndexOf(#, #)', receiver, element, start); |
@@ -2015,10 +2033,15 @@ unwrapException(ex) { |
return new StackOverflowError(); |
} |
- // In general, a RangeError is thrown when trying to pass a number |
- // as an argument to a function that does not allow a range that |
- // includes that number. |
- return saveStackTrace(new ArgumentError()); |
+ // In general, a RangeError is thrown when trying to pass a number as an |
+ // argument to a function that does not allow a range that includes that |
+ // number. Translate to a Dart ArgumentError with the same message. |
+ // TODO(sra): Translate to RangeError. |
+ String message = tryStringifyException(ex); |
+ if (message is String) { |
+ message = JS('String', r'#.replace(/^RangeError:\s*/, "")', message); |
+ } |
+ return saveStackTrace(new ArgumentError(message)); |
} |
// Check for the Firefox specific stack overflow signal. |
@@ -2036,6 +2059,20 @@ unwrapException(ex) { |
return ex; |
} |
+String tryStringifyException(ex) { |
+ // Since this function is called from [unwrapException] which is called from |
+ // code injected into a catch-clause, use JavaScript try-catch to avoid a |
+ // potential loop if stringifying crashes. |
+ return JS('String|Null', r''' |
+ (function(ex) { |
+ try { |
+ return String(ex); |
+ } catch (e) {} |
+ return null; |
+ })(#) |
+ ''', ex); |
+} |
+ |
/** |
* Called by generated code to fetch the stack trace from an |
* exception. Should never return null. |