blob: 639cfbd131576c70a356a77f5ae34ad99c63b284 [file] [log] [blame]
// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'dart:typed_data';
import 'package:expect/expect.dart';
// Check that NaN is detected as an invalid index for system Lists, Strings and
// typed lists.
//
// There are several methods called `dynamicCallN` for various N that are called
// with different indexable collection implementations to exercise various
// dart2js optimizations based on knowing (or not knowing) the concrete type of
// the List argument.
void main() {
int nan = makeIntNaN();
Expect.isFalse(nan <= 0);
Expect.isFalse(nan >= 0);
List<int> ints = [1, 2, 3, 4];
final bytes = Uint8List(3)
..[0] = 100
..[1] = 101
..[2] = 102;
final words = Int16List(3)
..[0] = 16000
..[1] = 16001
..[2] = 16002;
Expect.throws(() => ints[nan], anyError, 'List[nan]');
Expect.throws(() => 'abc'[nan], anyError, 'String[nan]');
Expect.throws(() => bytes[nan], anyError, 'UInt8List[nan]');
Expect.throws(() => words[nan], anyError, 'Int16List[nan]');
// [dynamicCall1] Seeded with JSIndexable and Map, so is doing a complete
// interceptor dispatch.
Expect.equals(2, dynamicCall1(ints, 1));
Expect.equals('b', dynamicCall1('abc', 1));
Expect.equals(2, dynamicCall1({'a': 1, 'b': 2, 'c': 3}, 'b'));
Expect.throws(() => dynamicCall1(ints, nan), anyError, 'dynamic List');
Expect.throws(() => dynamicCall1('AB', nan), anyError, 'dynamic String');
Expect.throws(() => dynamicCall1(bytes, nan), anyError, 'dynamic Uint8List');
Expect.throws(() => dynamicCall1(words, nan), anyError, 'dynamic Int16list');
var a = <int>[];
Expect.throws(() => a.removeLast(), contains('-1'));
// [dynamicCall2] seeded with JSIndexable only, so can be optimized to a
// JavaScript indexing operation.
Expect.equals(2, dynamicCall2(ints, 1));
Expect.equals('b', dynamicCall2('abc', 1));
Expect.throws(() => dynamicCall2(ints, nan), anyError, 'JSIndexable List');
Expect.throws(() => dynamicCall2('AB', nan), anyError, 'JSIndexable String');
// [dynamicCall3] Seeded with List of known length only, various indexes. The
// upper bound is fixed.
Expect.throws(() => dynamicCall3(ints, nan), anyError, 'known length nan');
Expect.throws(() => dynamicCall3(ints, null), anyError, 'known length null');
// [dynamicCall4] Seeded with List of known length only.
Expect.throws(() => dynamicCall4(ints, nan), anyError, 'dynamic[] List');
// [dynamicCall5] Seeded with List of unknown length only.
Expect.throws(() => dynamicCall5(ints, nan), anyError, 'dynamic[] List');
Expect.throws(() => dynamicCall5(a, nan), anyError, 'dynamic[] List');
// [dynamicCall6] Seeded with Uint8List only.
Expect.throws(() => dynamicCall6(bytes, nan), anyError, 'dynamic Uint8List');
}
bool anyError(error) => true;
bool Function(dynamic) contains(Pattern pattern) =>
(error) => '$error'.contains(pattern);
@pragma('dart2js:noInline')
dynamic dynamicCall1(dynamic indexable, dynamic index) {
return indexable[index];
}
@pragma('dart2js:noInline')
dynamic dynamicCall2(dynamic indexable, dynamic index) {
return indexable[index];
}
@pragma('dart2js:noInline')
dynamic dynamicCall3(dynamic indexable, dynamic index) {
return indexable[index];
}
@pragma('dart2js:noInline')
dynamic dynamicCall4(dynamic indexable, dynamic index) {
return indexable[index];
}
@pragma('dart2js:noInline')
dynamic dynamicCall5(dynamic indexable, dynamic index) {
return indexable[index];
}
@pragma('dart2js:noInline')
dynamic dynamicCall6(dynamic indexable, dynamic index) {
return indexable[index];
}
int makeIntNaN() {
int n = 2;
// Overflow to Infinity.
for (int i = 0; i < 10; i++, n *= n) {}
// Infinity - Infinity = NaN.
return n - n;
}