| 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 _interceptors; | 5 part of _interceptors; |
| 6 | 6 |
| 7 /** | 7 /** |
| 8 * The interceptor class for [List]. The compiler recognizes this | 8 * The interceptor class for [List]. The compiler recognizes this |
| 9 * class as an interceptor, and changes references to [:this:] to | 9 * class as an interceptor, and changes references to [:this:] to |
| 10 * actually use the receiver of the method, which is generated as an extra | 10 * actually use the receiver of the method, which is generated as an extra |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 107 if (index is !int) throw new ArgumentError(index); | 107 if (index is !int) throw new ArgumentError(index); |
| 108 if (index < 0 || index > length) { | 108 if (index < 0 || index > length) { |
| 109 throw new RangeError.value(index); | 109 throw new RangeError.value(index); |
| 110 } | 110 } |
| 111 checkGrowable('insert'); | 111 checkGrowable('insert'); |
| 112 JS('void', r'#.splice(#, 0, #)', this, index, value); | 112 JS('void', r'#.splice(#, 0, #)', this, index, value); |
| 113 } | 113 } |
| 114 | 114 |
| 115 void insertAll(int index, Iterable<E> iterable) { | 115 void insertAll(int index, Iterable<E> iterable) { |
| 116 checkGrowable('insertAll'); | 116 checkGrowable('insertAll'); |
| 117 IterableMixinWorkaround.insertAllList(this, index, iterable); | 117 RangeError.checkValueInInterval(index, 0, this.length, "index"); |
| 118 if (iterable is! EfficientLength) { |
| 119 iterable = iterable.toList(); |
| 120 } |
| 121 int insertionLength = iterable.length; |
| 122 this.length += insertionLength; |
| 123 int end = index + insertionLength; |
| 124 this.setRange(end, this.length, this, index); |
| 125 this.setRange(index, end, iterable); |
| 118 } | 126 } |
| 119 | 127 |
| 120 void setAll(int index, Iterable<E> iterable) { | 128 void setAll(int index, Iterable<E> iterable) { |
| 121 checkMutable('setAll'); | 129 checkMutable('setAll'); |
| 122 IterableMixinWorkaround.setAllList(this, index, iterable); | 130 RangeError.checkValueInInterval(index, 0, this.length, "index"); |
| 131 for (var element in iterable) { |
| 132 this[index++] = element; |
| 133 } |
| 123 } | 134 } |
| 124 | 135 |
| 125 E removeLast() { | 136 E removeLast() { |
| 126 checkGrowable('removeLast'); | 137 checkGrowable('removeLast'); |
| 127 if (length == 0) throw new RangeError.value(-1); | 138 if (length == 0) throw new RangeError.value(-1); |
| 128 return JS('var', r'#.pop()', this); | 139 return JS('var', r'#.pop()', this); |
| 129 } | 140 } |
| 130 | 141 |
| 131 bool remove(Object element) { | 142 bool remove(Object element) { |
| 132 checkGrowable('remove'); | 143 checkGrowable('remove'); |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 177 for (int i = 0; i < retained.length; i++) { | 188 for (int i = 0; i < retained.length; i++) { |
| 178 this[i] = retained[i]; | 189 this[i] = retained[i]; |
| 179 } | 190 } |
| 180 } | 191 } |
| 181 | 192 |
| 182 Iterable<E> where(bool f(E element)) { | 193 Iterable<E> where(bool f(E element)) { |
| 183 return new WhereIterable<E>(this, f); | 194 return new WhereIterable<E>(this, f); |
| 184 } | 195 } |
| 185 | 196 |
| 186 Iterable expand(Iterable f(E element)) { | 197 Iterable expand(Iterable f(E element)) { |
| 187 return IterableMixinWorkaround.expand(this, f); | 198 return new ExpandIterable<E, dynamic>(this, f); |
| 188 } | 199 } |
| 189 | 200 |
| 190 void addAll(Iterable<E> collection) { | 201 void addAll(Iterable<E> collection) { |
| 191 for (E e in collection) { | 202 for (E e in collection) { |
| 192 this.add(e); | 203 this.add(e); |
| 193 } | 204 } |
| 194 } | 205 } |
| 195 | 206 |
| 196 void clear() { | 207 void clear() { |
| 197 length = 0; | 208 length = 0; |
| (...skipping 16 matching lines...) Expand all Loading... |
| 214 | 225 |
| 215 String join([String separator = ""]) { | 226 String join([String separator = ""]) { |
| 216 var list = new List(this.length); | 227 var list = new List(this.length); |
| 217 for (int i = 0; i < this.length; i++) { | 228 for (int i = 0; i < this.length; i++) { |
| 218 list[i] = "${this[i]}"; | 229 list[i] = "${this[i]}"; |
| 219 } | 230 } |
| 220 return JS('String', "#.join(#)", list, separator); | 231 return JS('String', "#.join(#)", list, separator); |
| 221 } | 232 } |
| 222 | 233 |
| 223 Iterable<E> take(int n) { | 234 Iterable<E> take(int n) { |
| 224 return new IterableMixinWorkaround<E>().takeList(this, n); | 235 return new SubListIterable<E>(this, 0, n); |
| 225 } | 236 } |
| 226 | 237 |
| 227 Iterable<E> takeWhile(bool test(E value)) { | 238 Iterable<E> takeWhile(bool test(E value)) { |
| 228 return new IterableMixinWorkaround<E>().takeWhile(this, test); | 239 return new TakeWhileIterable<E>(this, test); |
| 229 } | 240 } |
| 230 | 241 |
| 231 Iterable<E> skip(int n) { | 242 Iterable<E> skip(int n) { |
| 232 return new IterableMixinWorkaround<E>().skipList(this, n); | 243 return new SubListIterable<E>(this, n, null); |
| 233 } | 244 } |
| 234 | 245 |
| 235 Iterable<E> skipWhile(bool test(E value)) { | 246 Iterable<E> skipWhile(bool test(E value)) { |
| 236 return new IterableMixinWorkaround<E>().skipWhile(this, test); | 247 return new SkipWhileIterable<E>(this, test); |
| 237 } | 248 } |
| 238 | 249 |
| 239 E reduce(E combine(E value, E element)) { | 250 E reduce(E combine(E previousValue, E element)) { |
| 240 return IterableMixinWorkaround.reduce(this, combine); | 251 int length = this.length; |
| 252 if (length == 0) throw IterableElementError.noElement(); |
| 253 E value = this[0]; |
| 254 for (int i = 1; i < length; i++) { |
| 255 // TODO(22407): Improve bounds check elimination to allow this JS code to |
| 256 // be replaced by indexing. |
| 257 var element = JS('', '#[#]', this, i); |
| 258 value = combine(value, element); |
| 259 if (length != this.length) throw new ConcurrentModificationError(this); |
| 260 } |
| 261 return value; |
| 241 } | 262 } |
| 242 | 263 |
| 243 fold(initialValue, combine(previousValue, E element)) { | 264 fold(var initialValue, combine(var previousValue, E element)) { |
| 244 return IterableMixinWorkaround.fold(this, initialValue, combine); | 265 var value = initialValue; |
| 266 int length = this.length; |
| 267 for (int i = 0; i < length; i++) { |
| 268 // TODO(22407): Improve bounds check elimination to allow this JS code to |
| 269 // be replaced by indexing. |
| 270 var element = JS('', '#[#]', this, i); |
| 271 value = combine(value, element); |
| 272 if (this.length != length) throw new ConcurrentModificationError(this); |
| 273 } |
| 274 return value; |
| 245 } | 275 } |
| 246 | 276 |
| 247 E firstWhere(bool test(E value), {E orElse()}) { | 277 E firstWhere(bool test(E value), {E orElse()}) { |
| 248 var end = this.length; | 278 var end = this.length; |
| 249 for (int i = 0; i < end; ++i) { | 279 for (int i = 0; i < end; ++i) { |
| 250 // TODO(22407): Improve bounds check elimination to allow this JS code to | 280 // TODO(22407): Improve bounds check elimination to allow this JS code to |
| 251 // be replaced by indexing. | 281 // be replaced by indexing. |
| 252 var element = JS('', '#[#]', this, i); | 282 var element = JS('', '#[#]', this, i); |
| 253 if (test(element)) return element; | 283 if (test(element)) return element; |
| 254 if (this.length != end) throw new ConcurrentModificationError(this); | 284 if (this.length != end) throw new ConcurrentModificationError(this); |
| 255 } | 285 } |
| 256 if (orElse != null) return orElse(); | 286 if (orElse != null) return orElse(); |
| 257 throw IterableElementError.noElement(); | 287 throw IterableElementError.noElement(); |
| 258 } | 288 } |
| 259 | 289 |
| 260 E lastWhere(bool test(E value), {E orElse()}) { | 290 E lastWhere(bool test(E element), { E orElse() }) { |
| 261 return IterableMixinWorkaround.lastWhereList(this, test, orElse); | 291 int length = this.length; |
| 292 for (int i = length - 1; i >= 0; i--) { |
| 293 // TODO(22407): Improve bounds check elimination to allow this JS code to |
| 294 // be replaced by indexing. |
| 295 var element = JS('', '#[#]', this, i); |
| 296 if (test(element)) return element; |
| 297 if (length != this.length) { |
| 298 throw new ConcurrentModificationError(this); |
| 299 } |
| 300 } |
| 301 if (orElse != null) return orElse(); |
| 302 throw IterableElementError.noElement(); |
| 262 } | 303 } |
| 263 | 304 |
| 264 E singleWhere(bool test(E value)) { | 305 E singleWhere(bool test(E element)) { |
| 265 return IterableMixinWorkaround.singleWhere(this, test); | 306 int length = this.length; |
| 307 E match = null; |
| 308 bool matchFound = false; |
| 309 for (int i = 0; i < length; i++) { |
| 310 // TODO(22407): Improve bounds check elimination to allow this JS code to |
| 311 // be replaced by indexing. |
| 312 var element = JS('', '#[#]', this, i); |
| 313 if (test(element)) { |
| 314 if (matchFound) { |
| 315 throw IterableElementError.tooMany(); |
| 316 } |
| 317 matchFound = true; |
| 318 match = element; |
| 319 } |
| 320 if (length != this.length) { |
| 321 throw new ConcurrentModificationError(this); |
| 322 } |
| 323 } |
| 324 if (matchFound) return match; |
| 325 throw IterableElementError.noElement(); |
| 266 } | 326 } |
| 267 | 327 |
| 268 E elementAt(int index) { | 328 E elementAt(int index) { |
| 269 return this[index]; | 329 return this[index]; |
| 270 } | 330 } |
| 271 | 331 |
| 272 List<E> sublist(int start, [int end]) { | 332 List<E> sublist(int start, [int end]) { |
| 273 checkNull(start); // TODO(ahe): This is not specified but co19 tests it. | 333 checkNull(start); // TODO(ahe): This is not specified but co19 tests it. |
| 274 if (start is !int) throw new ArgumentError(start); | 334 if (start is !int) throw new ArgumentError(start); |
| 275 if (start < 0 || start > length) { | 335 if (start < 0 || start > length) { |
| 276 throw new RangeError.range(start, 0, length); | 336 throw new RangeError.range(start, 0, length); |
| 277 } | 337 } |
| 278 if (end == null) { | 338 if (end == null) { |
| 279 end = length; | 339 end = length; |
| 280 } else { | 340 } else { |
| 281 if (end is !int) throw new ArgumentError(end); | 341 if (end is !int) throw new ArgumentError(end); |
| 282 if (end < start || end > length) { | 342 if (end < start || end > length) { |
| 283 throw new RangeError.range(end, start, length); | 343 throw new RangeError.range(end, start, length); |
| 284 } | 344 } |
| 285 } | 345 } |
| 286 if (start == end) return <E>[]; | 346 if (start == end) return <E>[]; |
| 287 return new JSArray<E>.markGrowable( | 347 return new JSArray<E>.markGrowable( |
| 288 JS('', r'#.slice(#, #)', this, start, end)); | 348 JS('', r'#.slice(#, #)', this, start, end)); |
| 289 } | 349 } |
| 290 | 350 |
| 291 | 351 |
| 292 Iterable<E> getRange(int start, int end) { | 352 Iterable<E> getRange(int start, int end) { |
| 293 return new IterableMixinWorkaround<E>().getRangeList(this, start, end); | 353 RangeError.checkValidRange(start, end, this.length); |
| 354 return new SubListIterable<E>(this, start, end); |
| 294 } | 355 } |
| 295 | 356 |
| 296 E get first { | 357 E get first { |
| 297 if (length > 0) return this[0]; | 358 if (length > 0) return this[0]; |
| 298 throw IterableElementError.noElement(); | 359 throw IterableElementError.noElement(); |
| 299 } | 360 } |
| 300 | 361 |
| 301 E get last { | 362 E get last { |
| 302 if (length > 0) return this[length - 1]; | 363 if (length > 0) return this[length - 1]; |
| 303 throw IterableElementError.noElement(); | 364 throw IterableElementError.noElement(); |
| 304 } | 365 } |
| 305 | 366 |
| 306 E get single { | 367 E get single { |
| 307 if (length == 1) return this[0]; | 368 if (length == 1) return this[0]; |
| 308 if (length == 0) throw IterableElementError.noElement(); | 369 if (length == 0) throw IterableElementError.noElement(); |
| 309 throw IterableElementError.tooMany(); | 370 throw IterableElementError.tooMany(); |
| 310 } | 371 } |
| 311 | 372 |
| 312 void removeRange(int start, int end) { | 373 void removeRange(int start, int end) { |
| 313 checkGrowable('removeRange'); | 374 checkGrowable('removeRange'); |
| 314 int receiverLength = this.length; | 375 RangeError.checkValidRange(start, end, this.length); |
| 315 if (start < 0 || start > receiverLength) { | |
| 316 throw new RangeError.range(start, 0, receiverLength); | |
| 317 } | |
| 318 if (end < start || end > receiverLength) { | |
| 319 throw new RangeError.range(end, start, receiverLength); | |
| 320 } | |
| 321 int deleteCount = end - start; | 376 int deleteCount = end - start; |
| 322 JS('', '#.splice(#, #)', this, start, deleteCount); | 377 JS('', '#.splice(#, #)', this, start, deleteCount); |
| 323 } | 378 } |
| 324 | 379 |
| 325 void setRange(int start, int end, Iterable<E> iterable, [int skipCount = 0]) { | 380 void setRange(int start, int end, Iterable<E> iterable, [int skipCount = 0]) { |
| 326 checkMutable('set range'); | 381 checkMutable('set range'); |
| 327 IterableMixinWorkaround.setRangeList(this, start, end, iterable, skipCount); | 382 |
| 383 RangeError.checkValidRange(start, end, this.length); |
| 384 int length = end - start; |
| 385 if (length == 0) return; |
| 386 RangeError.checkNotNegative(skipCount, "skipCount"); |
| 387 |
| 388 List otherList; |
| 389 int otherStart; |
| 390 // TODO(floitsch): Make this accept more. |
| 391 if (iterable is List) { |
| 392 otherList = iterable; |
| 393 otherStart = skipCount; |
| 394 } else { |
| 395 otherList = iterable.skip(skipCount).toList(growable: false); |
| 396 otherStart = 0; |
| 397 } |
| 398 if (otherStart + length > otherList.length) { |
| 399 throw IterableElementError.tooFew(); |
| 400 } |
| 401 if (otherStart < start) { |
| 402 // Copy backwards to ensure correct copy if [from] is this. |
| 403 // TODO(sra): If [from] is the same Array as [this], we can copy without |
| 404 // type annotation checks on the stores. |
| 405 for (int i = length - 1; i >= 0; i--) { |
| 406 // Use JS to avoid bounds check (the bounds check elimination |
| 407 // optimzation is too weak). The 'E' type annotation is a store type |
| 408 // check - we can't rely on iterable, it could be List<dynamic>. |
| 409 E element = otherList[otherStart + i]; |
| 410 JS('', '#[#] = #', this, start + i, element); |
| 411 } |
| 412 } else { |
| 413 for (int i = 0; i < length; i++) { |
| 414 E element = otherList[otherStart + i]; |
| 415 JS('', '#[#] = #', this, start + i, element); |
| 416 } |
| 417 } |
| 328 } | 418 } |
| 329 | 419 |
| 330 void fillRange(int start, int end, [E fillValue]) { | 420 void fillRange(int start, int end, [E fillValue]) { |
| 331 checkMutable('fill range'); | 421 checkMutable('fill range'); |
| 332 IterableMixinWorkaround.fillRangeList(this, start, end, fillValue); | 422 RangeError.checkValidRange(start, end, this.length); |
| 423 for (int i = start; i < end; i++) { |
| 424 // Store is safe since [fillValue] type has been checked as parameter. |
| 425 JS('', '#[#] = #', this, i, fillValue); |
| 426 } |
| 333 } | 427 } |
| 334 | 428 |
| 335 void replaceRange(int start, int end, Iterable<E> iterable) { | 429 void replaceRange(int start, int end, Iterable<E> replacement) { |
| 336 checkGrowable('removeRange'); | 430 checkGrowable('replace range'); |
| 337 IterableMixinWorkaround.replaceRangeList(this, start, end, iterable); | 431 RangeError.checkValidRange(start, end, this.length); |
| 432 if (replacement is! EfficientLength) { |
| 433 replacement = replacement.toList(); |
| 434 } |
| 435 int removeLength = end - start; |
| 436 int insertLength = replacement.length; |
| 437 if (removeLength >= insertLength) { |
| 438 int delta = removeLength - insertLength; |
| 439 int insertEnd = start + insertLength; |
| 440 int newLength = this.length - delta; |
| 441 this.setRange(start, insertEnd, replacement); |
| 442 if (delta != 0) { |
| 443 this.setRange(insertEnd, newLength, this, end); |
| 444 this.length = newLength; |
| 445 } |
| 446 } else { |
| 447 int delta = insertLength - removeLength; |
| 448 int newLength = this.length + delta; |
| 449 int insertEnd = start + insertLength; // aka. end + delta. |
| 450 this.length = newLength; |
| 451 this.setRange(insertEnd, newLength, this, end); |
| 452 this.setRange(start, insertEnd, replacement); |
| 453 } |
| 338 } | 454 } |
| 339 | 455 |
| 340 bool any(bool test(E element)) { | 456 bool any(bool test(E element)) { |
| 341 int end = this.length; | 457 int end = this.length; |
| 342 for (int i = 0; i < end; i++) { | 458 for (int i = 0; i < end; i++) { |
| 343 // TODO(22407): Improve bounds check elimination to allow this JS code to | 459 // TODO(22407): Improve bounds check elimination to allow this JS code to |
| 344 // be replaced by indexing. | 460 // be replaced by indexing. |
| 345 var element = JS('', '#[#]', this, i); | 461 var element = JS('', '#[#]', this, i); |
| 346 if (test(element)) return true; | 462 if (test(element)) return true; |
| 347 if (this.length != end) throw new ConcurrentModificationError(this); | 463 if (this.length != end) throw new ConcurrentModificationError(this); |
| 348 } | 464 } |
| 349 return false; | 465 return false; |
| 350 } | 466 } |
| 351 | 467 |
| 352 bool every(bool test(E element)) { | 468 bool every(bool test(E element)) { |
| 353 int end = this.length; | 469 int end = this.length; |
| 354 for (int i = 0; i < end; i++) { | 470 for (int i = 0; i < end; i++) { |
| 355 // TODO(22407): Improve bounds check elimination to allow this JS code to | 471 // TODO(22407): Improve bounds check elimination to allow this JS code to |
| 356 // be replaced by indexing. | 472 // be replaced by indexing. |
| 357 var element = JS('', '#[#]', this, i); | 473 var element = JS('', '#[#]', this, i); |
| 358 if (!test(element)) return false; | 474 if (!test(element)) return false; |
| 359 if (this.length != end) throw new ConcurrentModificationError(this); | 475 if (this.length != end) throw new ConcurrentModificationError(this); |
| 360 } | 476 } |
| 361 return true; | 477 return true; |
| 362 } | 478 } |
| 363 | 479 |
| 364 Iterable<E> get reversed => | 480 Iterable<E> get reversed => new ReversedListIterable<E>(this); |
| 365 new IterableMixinWorkaround<E>().reversedList(this); | |
| 366 | 481 |
| 367 void sort([int compare(E a, E b)]) { | 482 void sort([int compare(E a, E b)]) { |
| 368 checkMutable('sort'); | 483 checkMutable('sort'); |
| 369 IterableMixinWorkaround.sortList(this, compare); | 484 Sort.sort(this, compare == null ? Comparable.compare : compare); |
| 370 } | 485 } |
| 371 | 486 |
| 372 void shuffle([Random random]) { | 487 void shuffle([Random random]) { |
| 373 IterableMixinWorkaround.shuffleList(this, random); | 488 checkMutable('shuffle'); |
| 489 if (random == null) random = new Random(); |
| 490 int length = this.length; |
| 491 while (length > 1) { |
| 492 int pos = random.nextInt(length); |
| 493 length -= 1; |
| 494 var tmp = this[length]; |
| 495 this[length] = this[pos]; |
| 496 this[pos] = tmp; |
| 497 } |
| 374 } | 498 } |
| 375 | 499 |
| 376 int indexOf(Object element, [int start = 0]) { | 500 int indexOf(Object element, [int start = 0]) { |
| 377 return IterableMixinWorkaround.indexOfList(this, element, start); | 501 if (start >= this.length) { |
| 502 return -1; |
| 503 } |
| 504 if (start < 0) { |
| 505 start = 0; |
| 506 } |
| 507 for (int i = start; i < this.length; i++) { |
| 508 if (this[i] == element) { |
| 509 return i; |
| 510 } |
| 511 } |
| 512 return -1; |
| 378 } | 513 } |
| 379 | 514 |
| 380 int lastIndexOf(Object element, [int start]) { | 515 int lastIndexOf(Object element, [int startIndex]) { |
| 381 return IterableMixinWorkaround.lastIndexOfList(this, element, start); | 516 if (startIndex == null) { |
| 517 startIndex = this.length - 1; |
| 518 } else { |
| 519 if (startIndex < 0) { |
| 520 return -1; |
| 521 } |
| 522 if (startIndex >= this.length) { |
| 523 startIndex = this.length - 1; |
| 524 } |
| 525 } |
| 526 for (int i = startIndex; i >= 0; i--) { |
| 527 if (this[i] == element) { |
| 528 return i; |
| 529 } |
| 530 } |
| 531 return -1; |
| 382 } | 532 } |
| 383 | 533 |
| 384 bool contains(Object other) { | 534 bool contains(Object other) { |
| 385 for (int i = 0; i < length; i++) { | 535 for (int i = 0; i < length; i++) { |
| 386 if (this[i] == other) return true; | 536 if (this[i] == other) return true; |
| 387 } | 537 } |
| 388 return false; | 538 return false; |
| 389 } | 539 } |
| 390 | 540 |
| 391 bool get isEmpty => length == 0; | 541 bool get isEmpty => length == 0; |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 424 } | 574 } |
| 425 | 575 |
| 426 void operator []=(int index, E value) { | 576 void operator []=(int index, E value) { |
| 427 checkMutable('indexed set'); | 577 checkMutable('indexed set'); |
| 428 if (index is !int) throw new ArgumentError(index); | 578 if (index is !int) throw new ArgumentError(index); |
| 429 if (index >= length || index < 0) throw new RangeError.value(index); | 579 if (index >= length || index < 0) throw new RangeError.value(index); |
| 430 JS('void', r'#[#] = #', this, index, value); | 580 JS('void', r'#[#] = #', this, index, value); |
| 431 } | 581 } |
| 432 | 582 |
| 433 Map<int, E> asMap() { | 583 Map<int, E> asMap() { |
| 434 return new IterableMixinWorkaround<E>().asMapList(this); | 584 return new ListMapView<E>(this); |
| 435 } | 585 } |
| 436 } | 586 } |
| 437 | 587 |
| 438 /** | 588 /** |
| 439 * Dummy subclasses that allow the backend to track more precise | 589 * Dummy subclasses that allow the backend to track more precise |
| 440 * information about arrays through their type. The CPA type inference | 590 * information about arrays through their type. The CPA type inference |
| 441 * relies on the fact that these classes do not override [] nor []=. | 591 * relies on the fact that these classes do not override [] nor []=. |
| 442 */ | 592 */ |
| 443 class JSMutableArray<E> extends JSArray<E> implements JSMutableIndexable {} | 593 class JSMutableArray<E> extends JSArray<E> implements JSMutableIndexable {} |
| 444 class JSFixedArray<E> extends JSMutableArray<E> {} | 594 class JSFixedArray<E> extends JSMutableArray<E> {} |
| 445 class JSExtendableArray<E> extends JSMutableArray<E> {} | 595 class JSExtendableArray<E> extends JSMutableArray<E> {} |
| OLD | NEW |