Prepare for a stable, null-safe v3 release (#677)

* Merged prerelease entries in CHANGELOG
* Bumped dependencies to stable versions
* LOTS of misc spelling fixes
diff --git a/CHANGELOG.md b/CHANGELOG.md
index dc3fbcf..7c4be84 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,21 +1,6 @@
-#### 3.0.0-nullsafety.3 - 2021-01-15
+#### 3.0.0 - 2021-02-16
 
-  * Eliminate dependency on package:meta.
-  * Fix: `TreeSet.last` was incorrectly returning the minimum node (same
-    value as `TreeSet.first`). It now correctly returns the maximum
-    node.
-
-#### 3.0.0-nullsafety.2 - 2020-11-05
-
-  * BREAKING CHANGE: This version requires Dart SDK 2.12.0-0 or later.
-
-#### 3.0.0-nullsafety.1 - 2020-11-05
-
-  * Enable non-nullable experiment in `analysis_options.yaml`.
-
-#### 3.0.0-nullsafety - 2020-11-05
-
-  * BREAKING CHANGE: This verion requires Dart SDK 2.10.0 or later.
+  * BREAKING CHANGE: This version requires Dart SDK 2.12.0 or later.
   * BREAKING CHANGE: Remove `assertCheckedMode`. This was deprecated in 2.1.2.
     Checked mode no longer exists in Dart 2.0 since the vast majority of what
     checked mode did is now done in the type system itself.
@@ -41,6 +26,7 @@
   * Deprecate `firstNonNull`. Users of this function should migrate to
     `var v = o1 ?? o2 ?? o3 ?? o4; ArgumentError.checkNotNull(v);`. This will be
     removed in 4.0.0
+  * Eliminate dependency on package:meta.
 
 #### 2.1.5 - 2020-11-05
 
@@ -341,7 +327,7 @@
 #### 0.20.0 - 2014-12-10
    * Multimap: better `toString()` on returned collections.
    * Multimap: Bugfix: support edits on empty value collections.
-   * Multimap: Added missing return statment in `fold`.
+   * Multimap: Added missing return statement in `fold`.
    * Added isEmpty() in `strings`.
    * Added max SDK constraint <2.0.0
    * Minor updates to README.md.
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 1658d92..f291887 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -19,7 +19,7 @@
 
 ### Contribution Guidelines
 
-We welcome your pull requests, issue reports and enhacement requests. To make
+We welcome your pull requests, issue reports and enhancement requests. To make
 the process as smooth as possible, we request the following:
 
    * Sign the [CLA][cla] (see above) before sending your pull request.
diff --git a/README.md b/README.md
index d257bc8..175919a 100644
--- a/README.md
+++ b/README.md
@@ -31,7 +31,7 @@
 `FutureStream` turns a `Future<Stream>` into a `Stream` which emits the same
 events as the stream returned from the future.
 
-`StreamRouter` splits a Stream into mulltiple streams based on a set of
+`StreamRouter` splits a Stream into multiple streams based on a set of
 predicates.
 
 `CountdownTimer` is a simple countdown timer that fires events in regular
@@ -58,12 +58,12 @@
 
 ## [quiver.check][]
 
-`checkArgument` throws `ArgumentError` if the specifed argument check expression
+`checkArgument` throws `ArgumentError` if the specified argument check expression
 is false.
 
 `checkListIndex` throws `RangeError` if the specified index is out of bounds.
 
-`checkState` throws `StateError` if the specifed state check expression is
+`checkState` throws `StateError` if the specified state check expression is
 false.
 
 [quiver.check]: https://pub.dev/documentation/quiver/latest/quiver.check/quiver.check-library.html
diff --git a/lib/src/async/concat.dart b/lib/src/async/concat.dart
index 42ac764..ee938a5 100644
--- a/lib/src/async/concat.dart
+++ b/lib/src/async/concat.dart
@@ -14,7 +14,7 @@
 
 import 'dart:async';
 
-/// Returns the concatentation of the input streams.
+/// Returns the concatenation of the input streams.
 ///
 /// When the returned stream is listened to, the [streams] are iterated through
 /// asynchronously, forwarding all events (both data and error) for the current
diff --git a/lib/src/async/future_stream.dart b/lib/src/async/future_stream.dart
index 1c039e5..a51910c 100644
--- a/lib/src/async/future_stream.dart
+++ b/lib/src/async/future_stream.dart
@@ -26,7 +26,7 @@
 ///
 /// # Example
 ///
-/// This class is useful when you need to retreive some object via a `Future`,
+/// This class is useful when you need to retrieve some object via a `Future`,
 /// then return a `Stream` from that object:
 ///
 ///     var futureOfStream = getResource().then((resource) => resource.stream);
diff --git a/lib/src/collection/treeset.dart b/lib/src/collection/treeset.dart
index d22787d..633c6ef 100644
--- a/lib/src/collection/treeset.dart
+++ b/lib/src/collection/treeset.dart
@@ -691,7 +691,7 @@
   }
 
   /// Search the tree for the matching element, or the 'nearest' node.
-  /// NOTE: [BinaryTree.comparator] needs to have finer granulatity than -1,0,1
+  /// NOTE: [BinaryTree.comparator] needs to have finer granularity than -1,0,1
   /// in order for this to return something that's meaningful.
   AvlNode<V>? _searchNearest(V? element,
       {TreeSearch option = TreeSearch.NEAREST}) {
@@ -902,7 +902,7 @@
     }
 
     state = WALK;
-    // Else we've got an anchor we have to worry about initalizing from.
+    // Else we've got an anchor we have to worry about initializing from.
     // This isn't known till the caller actually performs a previous/next.
     _moveNext = () {
       _current = tree._searchNearest(anchorObject,
diff --git a/lib/src/iterables/concat.dart b/lib/src/iterables/concat.dart
index fa97c6c..7e93e50 100644
--- a/lib/src/iterables/concat.dart
+++ b/lib/src/iterables/concat.dart
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-/// Returns the concatentation of the input iterables.
+/// Returns the concatenation of the input iterables.
 ///
 /// The returned iterable is a lazily-evaluated view on the input iterables.
 Iterable<T> concat<T>(Iterable<Iterable<T>> iterables) =>
diff --git a/lib/src/iterables/count.dart b/lib/src/iterables/count.dart
index 533fa30..644ae13 100644
--- a/lib/src/iterables/count.dart
+++ b/lib/src/iterables/count.dart
@@ -29,7 +29,7 @@
   Iterator<num> get iterator => _CountIterator(start, step);
 
   // TODO(justin): return an infinite list for toList() and a special Set
-  // implmentation for toSet()?
+  // implementation for toSet()?
 }
 
 class _CountIterator implements Iterator<num> {
diff --git a/lib/strings.dart b/lib/strings.dart
index 78f7280..6bad8a9 100644
--- a/lib/strings.dart
+++ b/lib/strings.dart
@@ -126,7 +126,7 @@
 /// characters on the left and right from [fill].  On the right, characters are
 /// selected from [fill] starting at the end so that the last character in
 /// [fill] is the last character in the result. [fill] is repeated if
-/// neccessary to pad.
+/// necessary to pad.
 ///
 /// Returns [input] if `input.length` is equal to or greater than width.
 /// [input] can be `null` and is treated as an empty string.
diff --git a/lib/testing/src/async/fake_async.dart b/lib/testing/src/async/fake_async.dart
index 897d2ea..9ac539f 100644
--- a/lib/testing/src/async/fake_async.dart
+++ b/lib/testing/src/async/fake_async.dart
@@ -46,7 +46,7 @@
   /// [elapseBlocking].
   ///
   /// The returned clock starts at [initialTime], and calls to [elapse] and
-  /// [elapseBlocking] advance the clock, even if they occured before the call
+  /// [elapseBlocking] advance the clock, even if they occurred before the call
   /// to this method.
   ///
   /// The clock can be passed as a dependency to the unit under test.
diff --git a/pubspec.yaml b/pubspec.yaml
index 0f4d366..8530532 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -2,15 +2,18 @@
 description: >-
   Quiver is a set of utility libraries for Dart that makes using many Dart
   libraries easier and more convenient, or adds additional functionality.
-homepage: https://github.com/google/quiver-dart
-version: 3.0.0-nullsafety.3
+repository: https://github.com/google/quiver-dart
+version: 3.0.0
+
 environment:
   sdk: '>=2.12.0-0 <3.0.0'
+
 dependencies:
-  matcher: ^0.12.10-nullsafety.3
+  matcher: ^0.12.10
+
 dev_dependencies:
-  path: ^1.8.0-nullsafety.3
-  test: ^1.16.0-nullsafety.8
+  path: ^1.8.0
+  test: ^1.16.0
 #DDC_TEST:  build_runner: ^1.3.1
 #DDC_TEST:  build_test: ^0.10.6
 #DDC_TEST:  build_web_compilers: ^2.0.0
diff --git a/test/collection/bimap_test.dart b/test/collection/bimap_test.dart
index d9ba9f1..f10fac9 100644
--- a/test/collection/bimap_test.dart
+++ b/test/collection/bimap_test.dart
@@ -87,7 +87,7 @@
       expect(map.inverse[v2], k2);
     });
 
-    test('should contain mappings added via its invese', () {
+    test('should contain mappings added via its inverse', () {
       map.inverse[v1] = k1;
       map.inverse[v2] = k2;
       expect(map[k1], v1);
diff --git a/test/collection/treeset_test.dart b/test/collection/treeset_test.dart
index e80ddff..676d256 100644
--- a/test/collection/treeset_test.dart
+++ b/test/collection/treeset_test.dart
@@ -389,7 +389,7 @@
     group('set math', () {
       /// NOTE: set math with sorted sets should have a performance benefit;
       /// we do not check the performance, only that the resulting math
-      /// is equivilant to non-sorted sets.
+      /// is equivalent to non-sorted sets.
 
       late TreeSet<num> tree;
       late List<num> expectedUnion;
@@ -433,7 +433,7 @@
               equals(expectedDifference)));
     });
 
-    group('AVL implementaiton', () {
+    group('AVL implementation', () {
       /// NOTE: This is implementation specific testing for coverage.
       /// Users do not have access to [AvlNode] or [AvlTreeSet]
       test('RightLeftRotation', () {
diff --git a/test/core/utils_test.dart b/test/core/utils_test.dart
index f5c92b2..32ac6ea 100644
--- a/test/core/utils_test.dart
+++ b/test/core/utils_test.dart
@@ -37,7 +37,7 @@
       expect(firstNonNull(null, null, null, 4), 4);
     });
 
-    test('should throw if all argumentsare null', () {
+    test('should throw if all arguments are null', () {
       expect(() => firstNonNull(null, null, null, null), throwsArgumentError);
     });
   });
diff --git a/tool/travis/task.sh b/tool/travis/task.sh
index 21e9c4e..30a596c 100755
--- a/tool/travis/task.sh
+++ b/tool/travis/task.sh
@@ -33,17 +33,17 @@
   dartanalyzer) echo
     echo -e '\033[1mTASK: dartanalyzer\033[22m'
     echo -e 'dartanalyzer --fatal-warnings .'
-    dartanalyzer --enable-experiment=non-nullable --lints --fatal-warnings --fatal-infos . || EXIT_CODE=$?
+    dartanalyzer --lints --fatal-warnings --fatal-infos . || EXIT_CODE=$?
     ;;
   vm_test) echo
     echo -e '\033[1mTASK: vm_test\033[22m'
     echo -e 'pub run test -p vm'
-    pub run --enable-experiment=non-nullable test -p vm -r expanded || EXIT_CODE=$?
+    pub run test -p vm -r expanded || EXIT_CODE=$?
     ;;
   dart2js_test) echo
     echo -e '\033[1mTASK: dart2js_test\033[22m'
     echo -e 'pub run test -p chrome -x fails-on-dart2js'
-    pub run --enable-experiment=non-nullable test -p chrome -x fails-on-dart2js -r expanded || EXIT_CODE=$?
+    pub run test -p chrome -x fails-on-dart2js -r expanded || EXIT_CODE=$?
     ;;
   dartdevc_test) echo
     echo -e '\033[1mTASK: dartdevc_test\033[22m'