Merge the null_safety branch into master (#22)

diff --git a/.travis.yml b/.travis.yml
index 48e46ca..dd4f437 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -2,7 +2,6 @@
 
 dart:
   - dev
-  - 2.0.0
 
 dart_task:
   - test: --platform vm,chrome
@@ -15,13 +14,10 @@
     - dart: dev
       dart_task:
         dartanalyzer: --fatal-warnings --fatal-hints .
-    - dart: 2.0.0
-      dart_task:
-        dartanalyzer: --fatal-warnings .
 
 # Only building master means that we don't run two builds for each pull request.
 branches:
-  only: [master]
+  only: [master, null_safety]
 
 cache:
  directories:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index fb7f74d..abe488c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 1.1.0-nullsafety
+
+- Migrate to null safety.
+
 ## 1.0.5
 
 - Added an example.
diff --git a/analysis_options.yaml b/analysis_options.yaml
index 60abe63..2407da6 100644
--- a/analysis_options.yaml
+++ b/analysis_options.yaml
@@ -4,6 +4,9 @@
   strong-mode:
     implicit-casts: false
 
+  enable-experiment:
+  - non-nullable
+
 linter:
   rules:
     - avoid_bool_literals_in_conditional_expressions
diff --git a/example/example.dart b/example/example.dart
index e92677f..fd36a73 100644
--- a/example/example.dart
+++ b/example/example.dart
@@ -24,11 +24,11 @@
 
   // [Scanner.lastMatch] holds the [MatchData] for the most recent call to
   // [Scanner.scan], [Scanner.expect], or [Scanner.matches].
-  var number = num.parse(scanner.lastMatch[0]);
+  var number = num.parse((scanner.lastMatch![0])!);
 
   if (scanner.scan('.')) {
     scanner.expect(RegExp(r'\d+'));
-    final decimal = scanner.lastMatch[0];
+    final decimal = scanner.lastMatch![0]!;
     number += int.parse(decimal) / math.pow(10, decimal.length);
   }
 
diff --git a/lib/src/eager_span_scanner.dart b/lib/src/eager_span_scanner.dart
index 848cb72..415b9f3 100644
--- a/lib/src/eager_span_scanner.dart
+++ b/lib/src/eager_span_scanner.dart
@@ -31,8 +31,7 @@
 
   @override
   set state(LineScannerState state) {
-    if (state is! _EagerSpanScannerState ||
-        !identical((state as _EagerSpanScannerState)._scanner, this)) {
+    if (state is! _EagerSpanScannerState || !identical(state._scanner, this)) {
       throw ArgumentError('The given LineScannerState was not returned by '
           'this LineScanner.');
     }
@@ -69,7 +68,7 @@
     }
   }
 
-  EagerSpanScanner(String string, {sourceUrl, int position})
+  EagerSpanScanner(String string, {sourceUrl, int? position})
       : super(string, sourceUrl: sourceUrl, position: position);
 
   @override
@@ -99,13 +98,14 @@
   @override
   bool scan(Pattern pattern) {
     if (!super.scan(pattern)) return false;
+    final firstMatch = (lastMatch![0])!;
 
-    final newlines = _newlinesIn(lastMatch[0]);
+    final newlines = _newlinesIn(firstMatch);
     _line += newlines.length;
     if (newlines.isEmpty) {
-      _column += lastMatch[0].length;
+      _column += firstMatch.length;
     } else {
-      _column = lastMatch[0].length - newlines.last.end;
+      _column = firstMatch.length - newlines.last.end;
     }
 
     return true;
diff --git a/lib/src/exception.dart b/lib/src/exception.dart
index 8c994b5..8aa7aab 100644
--- a/lib/src/exception.dart
+++ b/lib/src/exception.dart
@@ -14,7 +14,7 @@
   /// The URL of the source file being parsed.
   ///
   /// This may be `null`, indicating that the source URL is unknown.
-  Uri get sourceUrl => span.sourceUrl;
+  Uri? get sourceUrl => span?.sourceUrl;
 
   StringScannerException(String message, SourceSpan span, String source)
       : super(message, span, source);
diff --git a/lib/src/line_scanner.dart b/lib/src/line_scanner.dart
index 9e7d918..358d4c1 100644
--- a/lib/src/line_scanner.dart
+++ b/lib/src/line_scanner.dart
@@ -73,7 +73,7 @@
     }
   }
 
-  LineScanner(String string, {sourceUrl, int position})
+  LineScanner(String string, {sourceUrl, int? position})
       : super(string, sourceUrl: sourceUrl, position: position);
 
   @override
@@ -104,12 +104,12 @@
   bool scan(Pattern pattern) {
     if (!super.scan(pattern)) return false;
 
-    final newlines = _newlinesIn(lastMatch[0]);
+    final newlines = _newlinesIn(lastMatch![0]!);
     _line += newlines.length;
     if (newlines.isEmpty) {
-      _column += lastMatch[0].length;
+      _column += (lastMatch![0])!.length;
     } else {
-      _column = lastMatch[0].length - newlines.last.end;
+      _column = (lastMatch![0])!.length - newlines.last.end;
     }
 
     return true;
diff --git a/lib/src/relative_span_scanner.dart b/lib/src/relative_span_scanner.dart
index a7a035a..150d507 100644
--- a/lib/src/relative_span_scanner.dart
+++ b/lib/src/relative_span_scanner.dart
@@ -47,8 +47,7 @@
 
   @override
   set state(LineScannerState state) {
-    if (state is! _SpanScannerState ||
-        !identical((state as _SpanScannerState)._scanner, this)) {
+    if (state is! _SpanScannerState || !identical(state._scanner, this)) {
       throw ArgumentError('The given LineScannerState was not returned by '
           'this LineScanner.');
     }
@@ -57,8 +56,8 @@
   }
 
   @override
-  FileSpan get lastSpan => _lastSpan;
-  FileSpan _lastSpan;
+  FileSpan? get lastSpan => _lastSpan;
+  FileSpan? _lastSpan;
 
   @override
   FileLocation get location =>
@@ -73,7 +72,7 @@
         super(span.text, sourceUrl: span.sourceUrl);
 
   @override
-  FileSpan spanFrom(LineScannerState startState, [LineScannerState endState]) {
+  FileSpan spanFrom(LineScannerState startState, [LineScannerState? endState]) {
     final endPosition = endState == null ? position : endState.position;
     return _sourceFile.span(_startLocation.offset + startState.position,
         _startLocation.offset + endPosition);
@@ -87,12 +86,12 @@
     }
 
     _lastSpan = _sourceFile.span(_startLocation.offset + position,
-        _startLocation.offset + lastMatch.end);
+        _startLocation.offset + lastMatch!.end);
     return true;
   }
 
   @override
-  void error(String message, {Match match, int position, int length}) {
+  Never error(String message, {Match? match, int? position, int? length}) {
     validateErrorArgs(string, match, position, length);
 
     if (match == null && position == null && length == null) match = lastMatch;
diff --git a/lib/src/span_scanner.dart b/lib/src/span_scanner.dart
index 1a8ca2a..806a8f8 100644
--- a/lib/src/span_scanner.dart
+++ b/lib/src/span_scanner.dart
@@ -29,8 +29,7 @@
 
   @override
   set state(LineScannerState state) {
-    if (state is! _SpanScannerState ||
-        !identical((state as _SpanScannerState)._scanner, this)) {
+    if (state is! _SpanScannerState || !identical(state._scanner, this)) {
       throw ArgumentError('The given LineScannerState was not returned by '
           'this LineScanner.');
     }
@@ -42,12 +41,12 @@
   ///
   /// This is the span for the entire match. There's no way to get spans for
   /// subgroups since [Match] exposes no information about their positions.
-  FileSpan get lastSpan {
+  FileSpan? get lastSpan {
     if (lastMatch == null) _lastSpan = null;
     return _lastSpan;
   }
 
-  FileSpan _lastSpan;
+  FileSpan? _lastSpan;
 
   /// The current location of the scanner.
   FileLocation get location => _sourceFile.location(position);
@@ -60,7 +59,7 @@
   /// [sourceUrl] is used as [SourceLocation.sourceUrl] for the returned
   /// [FileSpan]s as well as for error reporting. It can be a [String], a
   /// [Uri], or `null`.
-  SpanScanner(String string, {sourceUrl, int position})
+  SpanScanner(String string, {sourceUrl, int? position})
       : _sourceFile = SourceFile.fromString(string, url: sourceUrl),
         super(string, sourceUrl: sourceUrl, position: position);
 
@@ -75,7 +74,7 @@
   /// itself and its `LineScannerState` are eagerly computed. To limit their
   /// memory footprint, returned spans and locations will still lazily compute
   /// their line and column numbers.
-  factory SpanScanner.eager(String string, {sourceUrl, int position}) =
+  factory SpanScanner.eager(String string, {sourceUrl, int? position}) =
       EagerSpanScanner;
 
   /// Creates a new [SpanScanner] that scans within [span].
@@ -88,7 +87,7 @@
 
   /// Creates a [FileSpan] representing the source range between [startState]
   /// and the current position.
-  FileSpan spanFrom(LineScannerState startState, [LineScannerState endState]) {
+  FileSpan spanFrom(LineScannerState startState, [LineScannerState? endState]) {
     final endPosition = endState == null ? position : endState.position;
     return _sourceFile.span(startState.position, endPosition);
   }
@@ -100,12 +99,12 @@
       return false;
     }
 
-    _lastSpan = _sourceFile.span(position, lastMatch.end);
+    _lastSpan = _sourceFile.span(position, lastMatch!.end);
     return true;
   }
 
   @override
-  void error(String message, {Match match, int position, int length}) {
+  Never error(String message, {Match? match, int? position, int? length}) {
     validateErrorArgs(string, match, position, length);
 
     if (match == null && position == null && length == null) match = lastMatch;
diff --git a/lib/src/string_scanner.dart b/lib/src/string_scanner.dart
index 55ff17d..f29bc3a 100644
--- a/lib/src/string_scanner.dart
+++ b/lib/src/string_scanner.dart
@@ -3,7 +3,6 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:charcode/charcode.dart';
-import 'package:meta/meta.dart';
 import 'package:source_span/source_span.dart';
 
 import 'exception.dart';
@@ -15,7 +14,7 @@
   ///
   /// This is used for error reporting. It may be `null`, indicating that the
   /// source URL is unknown or unavailable.
-  final Uri sourceUrl;
+  final Uri? sourceUrl;
 
   /// The string being scanned through.
   final String string;
@@ -36,15 +35,15 @@
   /// The data about the previous match made by the scanner.
   ///
   /// If the last match failed, this will be `null`.
-  Match get lastMatch {
+  Match? get lastMatch {
     // Lazily unset [_lastMatch] so that we avoid extra assignments in
     // character-by-character methods that are used in core loops.
     if (_position != _lastMatchPosition) _lastMatch = null;
     return _lastMatch;
   }
 
-  Match _lastMatch;
-  int _lastMatchPosition;
+  Match? _lastMatch;
+  int? _lastMatchPosition;
 
   /// The portion of the string that hasn't yet been scanned.
   String get rest => string.substring(position);
@@ -57,9 +56,10 @@
   /// [position] defaults to 0, the beginning of the string. [sourceUrl] is the
   /// URL of the source of the string being scanned, if available. It can be
   /// a [String], a [Uri], or `null`.
-  StringScanner(this.string, {sourceUrl, int position})
-      : sourceUrl =
-            sourceUrl is String ? Uri.parse(sourceUrl) : sourceUrl as Uri {
+  StringScanner(this.string, {sourceUrl, int? position})
+      : sourceUrl = sourceUrl == null
+            ? null
+            : sourceUrl is String ? Uri.parse(sourceUrl) : sourceUrl as Uri {
     if (position != null) this.position = position;
   }
 
@@ -79,7 +79,7 @@
   ///
   /// This returns `null` if [offset] points outside the string. It doesn't
   /// affect [lastMatch].
-  int peekChar([int offset]) {
+  int? peekChar([int? offset]) {
     offset ??= 0;
     final index = position + offset;
     if (index < 0 || index >= string.length) return null;
@@ -102,7 +102,7 @@
   /// describing the position of the failure. [name] is used in this error as
   /// the expected name of the character being matched; if it's `null`, the
   /// character itself is used instead.
-  void expectChar(int character, {String name}) {
+  void expectChar(int character, {String? name}) {
     if (scanChar(character)) return;
 
     if (name == null) {
@@ -125,7 +125,7 @@
   bool scan(Pattern pattern) {
     final success = matches(pattern);
     if (success) {
-      _position = _lastMatch.end;
+      _position = _lastMatch!.end;
       _lastMatchPosition = _position;
     }
     return success;
@@ -138,7 +138,7 @@
   /// position of the failure. [name] is used in this error as the expected name
   /// of the pattern being matched; if it's `null`, the pattern itself is used
   /// instead.
-  void expect(Pattern pattern, {String name}) {
+  void expect(Pattern pattern, {String? name}) {
     if (scan(pattern)) return;
 
     if (name == null) {
@@ -175,7 +175,7 @@
   ///
   /// Unlike [String.substring], [end] defaults to [position] rather than the
   /// end of the string.
-  String substring(int start, [int end]) {
+  String substring(int start, [int? end]) {
     end ??= position;
     return string.substring(start, end);
   }
@@ -193,8 +193,7 @@
   /// position; if only [position] is passed, [length] defaults to 0.
   ///
   /// It's an error to pass [match] at the same time as [position] or [length].
-  @alwaysThrows
-  void error(String message, {Match match, int position, int length}) {
+  Never error(String message, {Match? match, int? position, int? length}) {
     validateErrorArgs(string, match, position, length);
 
     if (match == null && position == null && length == null) match = lastMatch;
@@ -209,7 +208,7 @@
   // TODO(nweiz): Make this handle long lines more gracefully.
   /// Throws a [FormatException] describing that [name] is expected at the
   /// current position in the string.
-  void _fail(String name) {
+  Never _fail(String name) {
     error('expected $name.', position: position, length: 0);
   }
 }
diff --git a/lib/src/utils.dart b/lib/src/utils.dart
index 7fe3d52..52dfb63 100644
--- a/lib/src/utils.dart
+++ b/lib/src/utils.dart
@@ -5,7 +5,8 @@
 import 'string_scanner.dart';
 
 /// Validates the arguments passed to [StringScanner.error].
-void validateErrorArgs(String string, Match match, int position, int length) {
+void validateErrorArgs(
+    String string, Match? match, int? position, int? length) {
   if (match != null && (position != null || length != null)) {
     throw ArgumentError("Can't pass both match and position/length.");
   }
diff --git a/pubspec.yaml b/pubspec.yaml
index d5cefce..7a9826d 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,17 +1,90 @@
 name: string_scanner
-version: 1.0.5
+version: 1.1.0-nullsafety
 
 description: A class for parsing strings using a sequence of patterns.
 homepage: https://github.com/dart-lang/string_scanner
 
 environment:
-  sdk: '>=2.0.0 <3.0.0'
+  sdk: '>=2.9.0-18.0 <2.9.0'
 
 dependencies:
-  charcode: ^1.1.0
-  meta: ^1.1.0
-  source_span: ^1.4.0
+  charcode: '>=1.2.0-nullsafety <1.2.0'
+  source_span: '>=1.8.0-nullsafety <1.8.0'
 
 dev_dependencies:
-  test: ^1.0.0
+  test: '>=1.16.0-nullsafety <1.16.0'
 
+dependency_overrides:
+  async:
+    git:
+      url: git://github.com/dart-lang/async.git
+      ref: null_safety
+  boolean_selector:
+    git:
+      url: git://github.com/dart-lang/boolean_selector.git
+      ref: null_safety
+  charcode:
+    git:
+      url: git://github.com/dart-lang/charcode.git
+      ref: null_safety
+  collection: 1.15.0-nullsafety
+  js:
+    git:
+      url: git://github.com/dart-lang/sdk.git
+      path: pkg/js
+  matcher:
+    git:
+      url: git://github.com/dart-lang/matcher.git
+      ref: null_safety
+  meta: 1.3.0-nullsafety
+  path:
+    git:
+      url: git://github.com/dart-lang/path.git
+      ref: null_safety
+  pedantic:
+    git:
+      url: git://github.com/dart-lang/pedantic.git
+      ref: null_safety
+  pool:
+    git:
+      url: git://github.com/dart-lang/pool.git
+      ref: null_safety
+  source_maps:
+    git:
+      url: git://github.com/dart-lang/source_maps.git
+      ref: null_safety
+  source_map_stack_trace:
+    git:
+      url: git://github.com/dart-lang/source_map_stack_trace.git
+      ref: null_safety
+  source_span:
+    git:
+      url: git://github.com/dart-lang/source_span.git
+      ref: null_safety
+  stack_trace:
+    git:
+      url: git://github.com/dart-lang/stack_trace.git
+      ref: null_safety
+  stream_channel:
+    git:
+      url: git://github.com/dart-lang/stream_channel.git
+      ref: null_safety
+  term_glyph:
+    git:
+      url: git://github.com/dart-lang/term_glyph.git
+      ref: null_safety
+  test_api:
+    git:
+      url: git://github.com/dart-lang/test.git
+      ref: null_safety
+      path: pkgs/test_api
+  test_core:
+    git:
+      url: git://github.com/dart-lang/test.git
+      ref: null_safety
+      path: pkgs/test_core
+  test:
+    git:
+      url: git://github.com/dart-lang/test.git
+      ref: null_safety
+      path: pkgs/test
diff --git a/test/error_test.dart b/test/error_test.dart
index 6173040..1f98c32 100644
--- a/test/error_test.dart
+++ b/test/error_test.dart
@@ -106,7 +106,7 @@
   });
 
   group('argument errors', () {
-    StringScanner scanner;
+    late StringScanner scanner;
     setUp(() {
       scanner = StringScanner('foo bar baz');
       scanner.scan('foo');
diff --git a/test/line_scanner_test.dart b/test/line_scanner_test.dart
index aafc74a..0bbd499 100644
--- a/test/line_scanner_test.dart
+++ b/test/line_scanner_test.dart
@@ -7,7 +7,7 @@
 import 'package:test/test.dart';
 
 void main() {
-  LineScanner scanner;
+  late LineScanner scanner;
   setUp(() {
     scanner = LineScanner('foo\nbar\r\nbaz');
   });
diff --git a/test/span_scanner_test.dart b/test/span_scanner_test.dart
index 2034d0a..828745f 100644
--- a/test/span_scanner_test.dart
+++ b/test/span_scanner_test.dart
@@ -11,19 +11,19 @@
 void main() {
   testForImplementation(
       'lazy',
-      ([String string]) =>
+      ([String? string]) =>
           SpanScanner(string ?? 'foo\nbar\nbaz', sourceUrl: 'source'));
 
   testForImplementation(
       'eager',
-      ([String string]) =>
+      ([String? string]) =>
           SpanScanner.eager(string ?? 'foo\nbar\nbaz', sourceUrl: 'source'));
 
   group('within', () {
     const text = 'first\nbefore: foo\nbar\nbaz :after\nlast';
     final startOffset = text.indexOf('foo');
 
-    SpanScanner scanner;
+    late SpanScanner scanner;
     setUp(() {
       final file = SourceFile.fromString(text, url: 'source');
       scanner =
@@ -51,7 +51,7 @@
       scanner.scan('fo');
       scanner.scan('o\nba');
 
-      final span = scanner.lastSpan;
+      final span = scanner.lastSpan!;
       expect(span.start.offset, equals(startOffset + 2));
       expect(span.start.line, equals(1));
       expect(span.start.column, equals(10));
@@ -108,14 +108,14 @@
 void testForImplementation(
     String name, SpanScanner Function([String string]) create) {
   group('for a $name scanner', () {
-    SpanScanner scanner;
+    late SpanScanner scanner;
     setUp(() => scanner = create());
 
     test('tracks the span for the last match', () {
       scanner.scan('fo');
       scanner.scan('o\nba');
 
-      final span = scanner.lastSpan;
+      final span = scanner.lastSpan!;
       expect(span.start.offset, equals(2));
       expect(span.start.line, equals(0));
       expect(span.start.column, equals(2));
diff --git a/test/string_scanner_test.dart b/test/string_scanner_test.dart
index 9dee9d1..0327499 100644
--- a/test/string_scanner_test.dart
+++ b/test/string_scanner_test.dart
@@ -8,7 +8,7 @@
 
 void main() {
   group('with an empty string', () {
-    StringScanner scanner;
+    late StringScanner scanner;
     setUp(() {
       scanner = StringScanner('');
     });
@@ -90,7 +90,7 @@
   });
 
   group('at the beginning of a string', () {
-    StringScanner scanner;
+    late StringScanner scanner;
     setUp(() {
       scanner = StringScanner('foo bar');
     });
@@ -156,7 +156,7 @@
 
     test('a matching scan returns true and changes the state', () {
       expect(scanner.scan(RegExp('f(..)')), isTrue);
-      expect(scanner.lastMatch[1], equals('oo'));
+      expect(scanner.lastMatch![1], equals('oo'));
       expect(scanner.position, equals(3));
       expect(scanner.rest, equals(' bar'));
     });
@@ -173,7 +173,7 @@
 
     test('a matching expect changes the state', () {
       scanner.expect(RegExp('f(..)'));
-      expect(scanner.lastMatch[1], equals('oo'));
+      expect(scanner.lastMatch![1], equals('oo'));
       expect(scanner.position, equals(3));
       expect(scanner.rest, equals(' bar'));
     });
@@ -192,7 +192,7 @@
 
     test('a matching matches returns true and only changes lastMatch', () {
       expect(scanner.matches(RegExp('f(..)')), isTrue);
-      expect(scanner.lastMatch[1], equals('oo'));
+      expect(scanner.lastMatch![1], equals('oo'));
       expect(scanner.position, equals(0));
       expect(scanner.rest, equals('foo bar'));
     });
@@ -223,7 +223,7 @@
       expect(scanner.rest, equals('oo bar'));
 
       expect(scanner.scan(RegExp('oo.')), isTrue);
-      expect(scanner.lastMatch[0], equals('oo '));
+      expect(scanner.lastMatch![0], equals('oo '));
       expect(scanner.position, equals(4));
       expect(scanner.rest, equals('bar'));
     });
@@ -242,19 +242,19 @@
 
     test('scan accepts any Pattern', () {
       expect(scanner.scan('foo'), isTrue);
-      expect(scanner.lastMatch[0], equals('foo'));
+      expect(scanner.lastMatch![0], equals('foo'));
       expect(scanner.position, equals(3));
       expect(scanner.rest, equals(' bar'));
     });
 
     test('scans multiple times', () {
       expect(scanner.scan(RegExp('f(..)')), isTrue);
-      expect(scanner.lastMatch[1], equals('oo'));
+      expect(scanner.lastMatch![1], equals('oo'));
       expect(scanner.position, equals(3));
       expect(scanner.rest, equals(' bar'));
 
       expect(scanner.scan(RegExp(' b(..)')), isTrue);
-      expect(scanner.lastMatch[1], equals('ar'));
+      expect(scanner.lastMatch![1], equals('ar'));
       expect(scanner.position, equals(7));
       expect(scanner.rest, equals(''));
       expect(scanner.isDone, isTrue);
@@ -263,7 +263,7 @@
   });
 
   group('after a scan', () {
-    StringScanner scanner;
+    late StringScanner scanner;
     setUp(() {
       scanner = StringScanner('foo bar');
       expect(scanner.scan('foo'), isTrue);
@@ -289,7 +289,7 @@
   });
 
   group('at the end of a string', () {
-    StringScanner scanner;
+    late StringScanner scanner;
     setUp(() {
       scanner = StringScanner('foo bar');
       expect(scanner.scan('foo bar'), isTrue);
@@ -368,7 +368,7 @@
       expect(scanner.rest, equals('oo bar'));
 
       expect(scanner.scan(RegExp('oo.')), isTrue);
-      expect(scanner.lastMatch[0], equals('oo '));
+      expect(scanner.lastMatch![0], equals('oo '));
       expect(scanner.position, equals(4));
       expect(scanner.rest, equals('bar'));
     });
@@ -400,7 +400,7 @@
       expect(scanner.rest, equals('oo bar'));
 
       expect(scanner.scan(RegExp('oo.')), isTrue);
-      expect(scanner.lastMatch[0], equals('oo '));
+      expect(scanner.lastMatch![0], equals('oo '));
       expect(scanner.position, equals(4));
       expect(scanner.rest, equals('bar'));
     });
diff --git a/test/utils.dart b/test/utils.dart
index 676b695..ca03c06 100644
--- a/test/utils.dart
+++ b/test/utils.dart
@@ -9,4 +9,4 @@
 /// [StringScannerException] with the given [text].
 Matcher throwsStringScannerException(String text) =>
     throwsA(const TypeMatcher<StringScannerException>()
-        .having((e) => e.span.text, 'span.text', text));
+        .having((e) => e.span!.text, 'span.text', text));