Skip to content

Commit c53b40a

Browse files
authored
Enable stricter type checks (#42)
* Enable stricter type checks Enable the `strict-casts`, `strict-inference`, and `strict-raw-types` options for the analyzer. Fix missing types accordingly. I debated whether to replace `Comparable` with `Comparable<dynamic>` or with `Comparable<Object?>`. `Comparable` is shorthand for `Comparable<dynamic>`, but I think `Comparable<Object?>` should be equivalent without breaking the API. Also remove an obsolete analyzer option. * Fix some more sites that used raw generics * Bump Dart SDK version requirement The `strict-casts` analysis option requires Dart 2.16. * Update the GitHub workflow to test against Dart 2.17 * Change package version to 0.8.1
1 parent 5a78336 commit c53b40a

11 files changed

+73
-57
lines changed

.github/workflows/dart.yml

+8-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,14 @@ on:
1111

1212
jobs:
1313
build:
14-
runs-on: ubuntu-latest
14+
runs-on: ${{ matrix.os }}
15+
strategy:
16+
fail-fast: false
17+
matrix:
18+
os: [ubuntu-latest]
19+
sdk: [2.17.0, stable, dev]
20+
21+
name: build on ${{ matrix.os }} for ${{ matrix.sdk }}
1522

1623
steps:
1724
- uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b

CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## [0.8.1]
2+
3+
* Added stricter type checks.
4+
15
## [0.8.0]
26

37
* Added `ComparableBasics`.

analysis_options.yaml

+5-4
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
include: package:pedantic/analysis_options.1.8.0.yaml
22

33
analyzer:
4-
strong-mode:
5-
implicit-casts: true
6-
implicit-dynamic: true
4+
language:
5+
strict-casts: true
6+
strict-inference: true
7+
strict-raw-types: true
78

89
linter:
910
rules:
@@ -28,4 +29,4 @@ linter:
2829
- unnecessary_brace_in_string_interps
2930
- unnecessary_getters_setters
3031
- unnecessary_new
31-
- unnecessary_statements
32+
- unnecessary_statements

example/main.dart

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
import 'package:basics/basics.dart';
66

7-
main() async {
7+
void main() async {
88
const numbers = <int>[2, 4, 8];
99

1010
if (numbers.all((n) => n.isEven)) {
@@ -15,6 +15,6 @@ main() async {
1515

1616
for (var _ in 5.range) {
1717
print('waiting 500 milliseconds...');
18-
await Future.delayed(500.milliseconds);
18+
await Future<void>.delayed(500.milliseconds);
1919
}
2020
}

lib/iterable_basics.dart

+4-4
Original file line numberDiff line numberDiff line change
@@ -121,8 +121,8 @@ extension IterableBasics<E> on Iterable<E> {
121121
/// ```dart
122122
/// ['a', 'aaa', 'aa'].maxBy((e) => e.length).value; // 'aaa'
123123
/// ```
124-
E? maxBy(Comparable Function(E) sortKey) {
125-
final sortKeyCache = <E, Comparable>{};
124+
E? maxBy(Comparable<dynamic> Function(E) sortKey) {
125+
final sortKeyCache = <E, Comparable<dynamic>>{};
126126
return this.max((a, b) => sortKeyCompare<E>(a, b, sortKey, sortKeyCache));
127127
}
128128

@@ -136,8 +136,8 @@ extension IterableBasics<E> on Iterable<E> {
136136
/// ```dart
137137
/// ['a', 'aaa', 'aa'].minBy((e) => e.length).value; // 'a'
138138
/// ```
139-
E? minBy(Comparable Function(E) sortKey) {
140-
final sortKeyCache = <E, Comparable>{};
139+
E? minBy(Comparable<dynamic> Function(E) sortKey) {
140+
final sortKeyCache = <E, Comparable<dynamic>>{};
141141
return this.min((a, b) => sortKeyCompare<E>(a, b, sortKey, sortKeyCache));
142142
}
143143

lib/list_basics.dart

+3-3
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,8 @@ extension ListBasics<E> on List<E> {
9696
/// var list = [-12, 3, 10];
9797
/// list.sortBy((e) => e.toString().length); // list is now [3, 10, -12].
9898
/// ```
99-
void sortBy(Comparable Function(E) sortKey) {
100-
final sortKeyCache = <E, Comparable>{};
99+
void sortBy(Comparable<dynamic> Function(E) sortKey) {
100+
final sortKeyCache = <E, Comparable<dynamic>>{};
101101
this.sort((a, b) => sortKeyCompare(a, b, sortKey, sortKeyCache));
102102
}
103103

@@ -113,7 +113,7 @@ extension ListBasics<E> on List<E> {
113113
/// var sorted = list.sortedCopyBy((e) => e.toString().length);
114114
/// // list is still [-12, 3, 10]. sorted is [3, 10, -12].
115115
/// ```
116-
List<E> sortedCopyBy(Comparable Function(E) sortKey) {
116+
List<E> sortedCopyBy(Comparable<dynamic> Function(E) sortKey) {
117117
return List<E>.of(this)..sortBy(sortKey);
118118
}
119119

lib/src/sort_key_compare.dart

+5-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,11 @@
1313
/// It is expected that all calls to this function within a single ordering
1414
/// or sorting will provide the same cache instance with each call.
1515
int sortKeyCompare<T>(
16-
T a, T b, Comparable Function(T) sortKey, Map<T, Comparable> sortKeyCache) {
16+
T a,
17+
T b,
18+
Comparable<Object?> Function(T) sortKey,
19+
Map<T, Comparable<Object?>> sortKeyCache,
20+
) {
1721
final keyA = sortKeyCache.putIfAbsent(a, () => sortKey(a));
1822
final keyB = sortKeyCache.putIfAbsent(b, () => sortKey(b));
1923
return keyA.compareTo(keyB);

pubspec.yaml

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@
33
# license that can be found in the LICENSE file.
44

55
name: basics
6-
version: 0.8.0
6+
version: 0.8.1
77
description: A Dart library containing convenient extension methods on basic Dart objects.
88
repository: https://github.com/google/dart-basics
99

1010
environment:
11-
sdk: ">=2.15.0 <3.0.0"
11+
sdk: ">=2.17.0 <3.0.0"
1212

1313
dev_dependencies:
1414
pedantic: ^1.8.0

test/iterable_basics_test.dart

+11-11
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ void main() {
2020
});
2121

2222
test('returns true for an empty iterable', () {
23-
final empty = [];
23+
final empty = <Object>[];
2424
final result = empty.none((e) => e.toString() == 'foo');
2525
expect(result, isTrue);
2626
});
@@ -46,7 +46,7 @@ void main() {
4646
});
4747

4848
test('returns false for an empty iterable', () {
49-
final empty = [];
49+
final empty = <Object>[];
5050
final result = empty.one((e) => e.toString() == 'foo');
5151
expect(result, isFalse);
5252
});
@@ -94,8 +94,8 @@ void main() {
9494
});
9595

9696
test('returns false for two empty iterables', () {
97-
final empty1 = [];
98-
final empty2 = [];
97+
final empty1 = <Object>[];
98+
final empty2 = <Object>[];
9999

100100
expect(empty1.containsAny(empty2), isFalse);
101101
expect(empty2.containsAny(empty1), isFalse);
@@ -147,8 +147,8 @@ void main() {
147147
});
148148

149149
test('returns true for two empty iterables', () {
150-
final empty1 = [];
151-
final empty2 = [];
150+
final empty1 = <Object>[];
151+
final empty2 = <Object>[];
152152

153153
expect(empty1.containsAll(empty2), isTrue);
154154
});
@@ -422,7 +422,7 @@ void main() {
422422
expect(<double>[].sum(), 0);
423423
expect(<num>[].sum((n) => n * 2), 0);
424424
expect(<String>[].sum((s) => s.length), 0);
425-
expect([].sum((n) => n * 2), 0);
425+
expect(<int>[].sum((n) => n * 2), 0);
426426
});
427427

428428
test('returns sum of custom addend', () {
@@ -449,7 +449,7 @@ void main() {
449449

450450
group('getRandom', () {
451451
test('returns null for an empty iterable', () {
452-
expect([].getRandom(), isNull);
452+
expect(<int>[].getRandom(), isNull);
453453
});
454454

455455
test('returns the only value of an iterable of length 1', () {
@@ -467,8 +467,8 @@ void main() {
467467
expect(values.getRange(2, 4), [12, 4]);
468468
expect(values.getRange(0, 2), [3, 8]);
469469
expect(values.getRange(3, 5), [4, 1]);
470-
expect(values.getRange(3, 3), []);
471-
expect(values.getRange(5, 5), []);
470+
expect(values.getRange(3, 3), <int>[]);
471+
expect(values.getRange(5, 5), <int>[]);
472472
});
473473

474474
test('matches the behavior of List#getRange', () {
@@ -515,7 +515,7 @@ num _getItemSize(dynamic item) {
515515
throw UnimplementedError();
516516
}
517517

518-
RangeError _getRangeError(Iterable Function() f) {
518+
RangeError _getRangeError(Iterable<Object?> Function() f) {
519519
try {
520520
f();
521521
} on RangeError catch (e) {

test/list_basics_test.dart

+27-27
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ void main() {
5959
'starts from the final element if start is greater than the length '
6060
'of the list', () {
6161
final list = [1, 2, 3, 4];
62-
expect(list.slice(start: 100, end: 1), []);
62+
expect(list.slice(start: 100, end: 1), <int>[]);
6363
expect(list.slice(start: 100, end: 1, step: -1), [4, 3]);
6464
});
6565

@@ -81,65 +81,65 @@ void main() {
8181
'ends with the first element if end is less than the negative length '
8282
'of the list', () {
8383
final list = [1, 2, 3, 4];
84-
expect(list.slice(start: 2, end: -100), []);
84+
expect(list.slice(start: 2, end: -100), <int>[]);
8585
expect(list.slice(start: 2, end: -100, step: -1), [3, 2, 1]);
8686
});
8787

8888
test('returns an empty list if start and end are equal', () {
8989
final list = [1, 2, 3, 4, 5];
90-
expect(list.slice(start: 2, end: 2), []);
91-
expect(list.slice(start: -2, end: -2), []);
90+
expect(list.slice(start: 2, end: 2), <int>[]);
91+
expect(list.slice(start: -2, end: -2), <int>[]);
9292
});
9393

9494
test(
9595
'returns an empty list if start and end are not equal but correspond '
9696
'to the same element', () {
9797
final list = [1, 2, 3, 4];
98-
expect(list.slice(start: 1, end: -3), []);
99-
expect(list.slice(start: 2, end: -2), []);
98+
expect(list.slice(start: 1, end: -3), <int>[]);
99+
expect(list.slice(start: 2, end: -2), <int>[]);
100100
});
101101

102102
test(
103103
'returns an empty list if start (or its equivalent index) is greater '
104104
'than end (or its equivalent index) and step is positive', () {
105105
final list = [1, 2, 3, 4];
106-
expect(list.slice(start: 3, end: 1), []);
107-
expect(list.slice(start: -1, end: 1), []);
108-
expect(list.slice(start: 3, end: -3), []);
109-
expect(list.slice(start: -1, end: -3), []);
110-
expect(list.slice(start: 3, end: -100), []);
106+
expect(list.slice(start: 3, end: 1), <int>[]);
107+
expect(list.slice(start: -1, end: 1), <int>[]);
108+
expect(list.slice(start: 3, end: -3), <int>[]);
109+
expect(list.slice(start: -1, end: -3), <int>[]);
110+
expect(list.slice(start: 3, end: -100), <int>[]);
111111
});
112112

113113
test(
114114
'returns an empty list if start (or its equivalent index) is less than '
115115
'end (or its equivalent index) and step is negative', () {
116116
final list = [1, 2, 3, 4];
117-
expect(list.slice(start: 1, end: 3, step: -1), []);
118-
expect(list.slice(start: -3, end: 3, step: -1), []);
119-
expect(list.slice(start: 1, end: -1, step: -1), []);
120-
expect(list.slice(start: -3, end: -1, step: -1), []);
121-
expect(list.slice(start: 1, end: 100, step: -1), []);
117+
expect(list.slice(start: 1, end: 3, step: -1), <int>[]);
118+
expect(list.slice(start: -3, end: 3, step: -1), <int>[]);
119+
expect(list.slice(start: 1, end: -1, step: -1), <int>[]);
120+
expect(list.slice(start: -3, end: -1, step: -1), <int>[]);
121+
expect(list.slice(start: 1, end: 100, step: -1), <int>[]);
122122
});
123123

124124
test('behaves predictably when the bounds are increased in any direction',
125125
() {
126126
final list = [1, 2, 3, 4];
127127

128-
expect(list.slice(start: 0, end: 0), []);
128+
expect(list.slice(start: 0, end: 0), <int>[]);
129129
expect(list.slice(start: 0, end: 1), [1]);
130130
expect(list.slice(start: 0, end: 2), [1, 2]);
131131
expect(list.slice(start: 0, end: 3), [1, 2, 3]);
132132
expect(list.slice(start: 0, end: 4), [1, 2, 3, 4]);
133133
expect(list.slice(start: 0, end: 5), [1, 2, 3, 4]);
134134

135-
expect(list.slice(start: 0, end: -5), []);
136-
expect(list.slice(start: 0, end: -4), []);
135+
expect(list.slice(start: 0, end: -5), <int>[]);
136+
expect(list.slice(start: 0, end: -4), <int>[]);
137137
expect(list.slice(start: 0, end: -3), [1]);
138138
expect(list.slice(start: 0, end: -2), [1, 2]);
139139
expect(list.slice(start: 0, end: -1), [1, 2, 3]);
140140

141-
expect(list.slice(start: 5, end: 4), []);
142-
expect(list.slice(start: 4, end: 4), []);
141+
expect(list.slice(start: 5, end: 4), <int>[]);
142+
expect(list.slice(start: 4, end: 4), <int>[]);
143143
expect(list.slice(start: 3, end: 4), [4]);
144144
expect(list.slice(start: 2, end: 4), [3, 4]);
145145
expect(list.slice(start: 1, end: 4), [2, 3, 4]);
@@ -150,18 +150,18 @@ void main() {
150150
expect(list.slice(start: -4, end: 4), [1, 2, 3, 4]);
151151
expect(list.slice(start: -5, end: 4), [1, 2, 3, 4]);
152152

153-
expect(list.slice(start: 3, end: 3, step: -1), []);
153+
expect(list.slice(start: 3, end: 3, step: -1), <int>[]);
154154
expect(list.slice(start: 3, end: 2, step: -1), [4]);
155155
expect(list.slice(start: 3, end: 1, step: -1), [4, 3]);
156156
expect(list.slice(start: 3, end: 0, step: -1), [4, 3, 2]);
157157

158-
expect(list.slice(start: 3, end: -1, step: -1), []);
158+
expect(list.slice(start: 3, end: -1, step: -1), <int>[]);
159159
expect(list.slice(start: 3, end: -2, step: -1), [4]);
160160
expect(list.slice(start: 3, end: -3, step: -1), [4, 3]);
161161
expect(list.slice(start: 3, end: -4, step: -1), [4, 3, 2]);
162162
expect(list.slice(start: 3, end: -5, step: -1), [4, 3, 2, 1]);
163163

164-
expect(list.slice(start: 0, end: 0, step: -1), []);
164+
expect(list.slice(start: 0, end: 0, step: -1), <int>[]);
165165
expect(list.slice(start: 1, end: 0, step: -1), [2]);
166166
expect(list.slice(start: 2, end: 0, step: -1), [3, 2]);
167167
expect(list.slice(start: 3, end: 0, step: -1), [4, 3, 2]);
@@ -171,13 +171,13 @@ void main() {
171171
expect(list.slice(start: -1, end: 0, step: -1), [4, 3, 2]);
172172
expect(list.slice(start: -2, end: 0, step: -1), [3, 2]);
173173
expect(list.slice(start: -3, end: 0, step: -1), [2]);
174-
expect(list.slice(start: -4, end: 0, step: -1), []);
174+
expect(list.slice(start: -4, end: 0, step: -1), <int>[]);
175175

176176
expect(list.slice(start: -1, end: -5, step: -1), [4, 3, 2, 1]);
177177
expect(list.slice(start: -2, end: -5, step: -1), [3, 2, 1]);
178178
expect(list.slice(start: -3, end: -5, step: -1), [2, 1]);
179179
expect(list.slice(start: -4, end: -5, step: -1), [1]);
180-
expect(list.slice(start: -5, end: -5, step: -1), []);
180+
expect(list.slice(start: -5, end: -5, step: -1), <int>[]);
181181
});
182182
});
183183

@@ -248,7 +248,7 @@ void main() {
248248

249249
group('takeRandom', () {
250250
test('returns null for an empty list', () {
251-
expect([].takeRandom(), isNull);
251+
expect(<Object>[].takeRandom(), isNull);
252252
});
253253

254254
test('removes the only element of a list of length 1', () {

test/map_basics_test.dart

+2-2
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,8 @@ void main() {
6060
});
6161

6262
test('returns an empty map when called on an empty map', () {
63-
final map = {};
64-
expect(map.invert(), {});
63+
final map = <Object, Object>{};
64+
expect(map.invert(), <Object, Object>{});
6565
});
6666
});
6767
}

0 commit comments

Comments
 (0)