Revert "Add class modifiers to `dart:convert`."

This reverts commit b2f4cf3e01edf2a26a031ab7151c282713c8bd1b because it breaks flutter analyze.

BUG=https://github.com/flutter/flutter/issues/123157

Original change's description:
> Add class modifiers to `dart:convert`.
>
> The usual approach:
> Pure interfaces marked `interface`.
> Pure implementation classes marked `final`.
> Base classes marked `base` or nothing, and `mixin class` if reasonable.
> Combined X/XBase/XMixin where possible.
>
> CoreLibraryReviewExempt: Aske is away
> Change-Id: I927f9bd488fb385ff9c17c8fc94920a1f5076347
> Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/289200
> Reviewed-by: Stephen Adams <sra@google.com>
> Reviewed-by: Slava Egorov <vegorov@google.com>
> Reviewed-by: Nate Bosch <nbosch@google.com>
> Commit-Queue: Lasse Nielsen <lrn@google.com>

Change-Id: Ia79b9572e623a47ddbefd66efe270a6e3bbaa5e2
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/290340
Reviewed-by: Stephen Adams <sra@google.com>
Commit-Queue: Alexander Aprelev <aam@google.com>
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
Reviewed-by: Devon Carew <devoncarew@google.com>
diff --git a/pkg/analysis_server/benchmark/integration/input_converter.dart b/pkg/analysis_server/benchmark/integration/input_converter.dart
index 2c72d56..f0490ec 100644
--- a/pkg/analysis_server/benchmark/integration/input_converter.dart
+++ b/pkg/analysis_server/benchmark/integration/input_converter.dart
@@ -345,7 +345,7 @@
   }
 }
 
-class _InputSink implements ChunkedConversionSink<String> {
+class _InputSink extends ChunkedConversionSink<String> {
   final Converter<String, Operation?> converter;
   final Sink<Operation?> outSink;
 
diff --git a/pkg/analysis_server/lib/src/channel/channel.dart b/pkg/analysis_server/lib/src/channel/channel.dart
index 8c0596c..aedac67 100644
--- a/pkg/analysis_server/lib/src/channel/channel.dart
+++ b/pkg/analysis_server/lib/src/channel/channel.dart
@@ -8,7 +8,7 @@
 
 /// Instances of the class [ChannelChunkSink] uses a [Converter] to translate
 /// chunks.
-class ChannelChunkSink<S, T> implements ChunkedConversionSink<S> {
+class ChannelChunkSink<S, T> extends ChunkedConversionSink<S> {
   /// The converter used to translate chunks.
   final Converter<S, T> converter;
 
diff --git a/pkg/analyzer/lib/src/test_utilities/mock_sdk.dart b/pkg/analyzer/lib/src/test_utilities/mock_sdk.dart
index 3fc6327..06588b5 100644
--- a/pkg/analyzer/lib/src/test_utilities/mock_sdk.dart
+++ b/pkg/analyzer/lib/src/test_utilities/mock_sdk.dart
@@ -254,9 +254,9 @@
   String encode(Object? value, {Object? toEncodable(dynamic object)?}) => '';
 }
 
-abstract mixin class StringConversionSink { }
+abstract class StringConversionSink { }
 
-typedef StringConversionSinkMixin = StringConversionSink;
+abstract mixin class StringConversionSinkMixin implements StringConversionSink { }
 ''',
     )
   ],
diff --git a/sdk/lib/_internal/vm_shared/lib/convert_patch.dart b/sdk/lib/_internal/vm_shared/lib/convert_patch.dart
index 01e8d3a..794f8c2 100644
--- a/sdk/lib/_internal/vm_shared/lib/convert_patch.dart
+++ b/sdk/lib/_internal/vm_shared/lib/convert_patch.dart
@@ -1553,7 +1553,7 @@
  * Implements the chunked conversion from a UTF-8 encoding of JSON
  * to its corresponding object.
  */
-class _JsonUtf8DecoderSink extends ByteConversionSink {
+class _JsonUtf8DecoderSink extends ByteConversionSinkBase {
   final _JsonUtf8Parser _parser;
   final Sink<Object?> _sink;
 
diff --git a/sdk/lib/convert/ascii.dart b/sdk/lib/convert/ascii.dart
index 6768d71..30a9599 100644
--- a/sdk/lib/convert/ascii.dart
+++ b/sdk/lib/convert/ascii.dart
@@ -21,7 +21,7 @@
 
 /// An [AsciiCodec] allows encoding strings as ASCII bytes
 /// and decoding ASCII bytes to strings.
-final class AsciiCodec extends Encoding {
+class AsciiCodec extends Encoding {
   final bool _allowInvalid;
 
   /// Instantiates a new [AsciiCodec].
@@ -118,7 +118,7 @@
 
 /// This class encodes chunked strings to bytes (unsigned 8-bit
 /// integers).
-class _UnicodeSubsetEncoderSink extends StringConversionSink {
+class _UnicodeSubsetEncoderSink extends StringConversionSinkBase {
   final ByteConversionSink _sink;
   final int _subsetMask;
 
@@ -253,7 +253,7 @@
   }
 }
 
-class _ErrorHandlingAsciiDecoderSink extends ByteConversionSink {
+class _ErrorHandlingAsciiDecoderSink extends ByteConversionSinkBase {
   ByteConversionSink _utf8Sink;
   _ErrorHandlingAsciiDecoderSink(this._utf8Sink);
 
@@ -283,7 +283,7 @@
   }
 }
 
-class _SimpleAsciiDecoderSink extends ByteConversionSink {
+class _SimpleAsciiDecoderSink extends ByteConversionSinkBase {
   Sink _sink;
   _SimpleAsciiDecoderSink(this._sink);
 
diff --git a/sdk/lib/convert/base64.dart b/sdk/lib/convert/base64.dart
index 1133ba2..23fa301 100644
--- a/sdk/lib/convert/base64.dart
+++ b/sdk/lib/convert/base64.dart
@@ -64,7 +64,7 @@
 /// It does not allow invalid characters when decoding and it requires,
 /// and generates, padding so that the input is always a multiple of four
 /// characters.
-final class Base64Codec extends Codec<List<int>, String> {
+class Base64Codec extends Codec<List<int>, String> {
   final Base64Encoder _encoder;
   const Base64Codec() : _encoder = const Base64Encoder();
   const Base64Codec.urlSafe() : _encoder = const Base64Encoder.urlSafe();
@@ -231,7 +231,7 @@
 /// final encodedSample = base64Encoder.convert(sample.codeUnits);
 /// print(encodedSample); // RGFydCBpcyBvcGVuIHNvdXJjZQ==
 /// ```
-final class Base64Encoder extends Converter<List<int>, String> {
+class Base64Encoder extends Converter<List<int>, String> {
   final bool _urlSafe;
 
   const Base64Encoder() : _urlSafe = false;
@@ -416,7 +416,7 @@
   }
 }
 
-abstract class _Base64EncoderSink extends ByteConversionSink {
+abstract class _Base64EncoderSink extends ByteConversionSinkBase {
   void add(List<int> source) {
     _add(source, 0, source.length, false);
   }
@@ -491,7 +491,7 @@
 /// // Print as string using UTF-8 decoder
 /// print(utf8.decode(decodedBytes)); // Dart is open source
 /// ```
-final class Base64Decoder extends Converter<String, List<int>> {
+class Base64Decoder extends Converter<String, List<int>> {
   const Base64Decoder();
 
   /// Decodes the characters of [input] from [start] to [end] as base64.
@@ -850,7 +850,7 @@
   }
 }
 
-class _Base64DecoderSink extends StringConversionSink {
+class _Base64DecoderSink extends StringConversionSinkBase {
   /// Output sink
   final Sink<List<int>> _sink;
   final _Base64Decoder _decoder = _Base64Decoder();
diff --git a/sdk/lib/convert/byte_conversion.dart b/sdk/lib/convert/byte_conversion.dart
index 17a9741..3d52d78 100644
--- a/sdk/lib/convert/byte_conversion.dart
+++ b/sdk/lib/convert/byte_conversion.dart
@@ -9,10 +9,12 @@
 ///
 /// Instead of limiting the interface to one non-chunked list of bytes it
 /// accepts its input in chunks (themselves being lists of bytes).
-abstract mixin class ByteConversionSink
-    implements ChunkedConversionSink<List<int>> {
-  const ByteConversionSink();
-
+///
+/// This abstract class will likely get more methods over time. Implementers are
+/// urged to extend or mix in [ByteConversionSinkBase] to ensure that their
+/// class covers the newly added methods.
+abstract class ByteConversionSink extends ChunkedConversionSink<List<int>> {
+  ByteConversionSink();
   factory ByteConversionSink.withCallback(
       void callback(List<int> accumulated)) = _ByteCallbackSink;
   factory ByteConversionSink.from(Sink<List<int>> sink) = _ByteAdapterSink;
@@ -23,24 +25,31 @@
   ///
   /// If [isLast] is `true` closes `this`.
   ///
-  /// Contrary to `add` the given [chunk] must not be held onto.
-  /// Once the method returns, it is safe to overwrite the data in it.
+  /// Contrary to `add` the given [chunk] must not be held onto. Once the method
+  /// returns, it is safe to overwrite the data in it.
+  void addSlice(List<int> chunk, int start, int end, bool isLast);
+
+  // TODO(floitsch): add more methods:
+  // - iterateBytes.
+}
+
+/// This class provides a base-class for converters that need to accept byte
+/// inputs.
+abstract class ByteConversionSinkBase extends ByteConversionSink {
+  void add(List<int> chunk);
+  void close();
+
   void addSlice(List<int> chunk, int start, int end, bool isLast) {
     add(chunk.sublist(start, end));
     if (isLast) close();
   }
 }
 
-/// This class provides a base-class for converters that need to accept byte
-/// inputs.
-@Deprecated("Use ByteConversionSink instead")
-typedef ByteConversionSinkBase = ByteConversionSink;
-
 /// This class adapts a simple [Sink] to a [ByteConversionSink].
 ///
 /// All additional methods of the [ByteConversionSink] (compared to the
 /// ChunkedConversionSink) are redirected to the `add` method.
-class _ByteAdapterSink extends ByteConversionSink {
+class _ByteAdapterSink extends ByteConversionSinkBase {
   final Sink<List<int>> _sink;
 
   _ByteAdapterSink(this._sink);
@@ -58,7 +67,7 @@
 /// and invokes a callback when the sink is closed.
 ///
 /// This class can be used to terminate a chunked conversion.
-class _ByteCallbackSink extends ByteConversionSink {
+class _ByteCallbackSink extends ByteConversionSinkBase {
   static const _INITIAL_BUFFER_SIZE = 1024;
 
   final void Function(List<int>) _callback;
diff --git a/sdk/lib/convert/chunked_conversion.dart b/sdk/lib/convert/chunked_conversion.dart
index a36f584..19a8561 100644
--- a/sdk/lib/convert/chunked_conversion.dart
+++ b/sdk/lib/convert/chunked_conversion.dart
@@ -10,7 +10,10 @@
 /// The basic `ChunkedConversionSink` is just a [Sink], and converters should
 /// work with a plain `Sink`, but may work more efficiently with certain
 /// specialized types of `ChunkedConversionSink`.
-abstract interface class ChunkedConversionSink<T> implements Sink<T> {
+///
+/// It is recommended that implementations of `ChunkedConversionSink` extend
+/// this class, to inherit any further methods that may be added to the class.
+abstract class ChunkedConversionSink<T> implements Sink<T> {
   ChunkedConversionSink();
   factory ChunkedConversionSink.withCallback(
       void callback(List<T> accumulated)) = _SimpleCallbackSink<T>;
@@ -31,7 +34,7 @@
 /// the chunks when the sink is closed.
 ///
 /// This class can be used to terminate a chunked conversion.
-class _SimpleCallbackSink<T> implements ChunkedConversionSink<T> {
+class _SimpleCallbackSink<T> extends ChunkedConversionSink<T> {
   final void Function(List<T>) _callback;
   final List<T> _accumulated = <T>[];
 
diff --git a/sdk/lib/convert/codec.dart b/sdk/lib/convert/codec.dart
index 42205cc..38e4a3c 100644
--- a/sdk/lib/convert/codec.dart
+++ b/sdk/lib/convert/codec.dart
@@ -12,11 +12,7 @@
 ///
 /// Fused codecs generally attempt to optimize the operations and can be faster
 /// than executing each step of an encoding separately.
-///
-/// The [Codec] class provides a default implementation of
-/// [encode], [decode], [fuse] and [inverted].
-/// Subclasses can choose to provide more efficient implementations of these.
-abstract mixin class Codec<S, T> {
+abstract class Codec<S, T> {
   const Codec();
 
   /// Encodes [input].
diff --git a/sdk/lib/convert/converter.dart b/sdk/lib/convert/converter.dart
index a9b1135..2167933 100644
--- a/sdk/lib/convert/converter.dart
+++ b/sdk/lib/convert/converter.dart
@@ -6,9 +6,9 @@
 
 /// A [Converter] converts data from one representation into another.
 ///
-/// The [Converter] class provides a default implementation for every method
-/// other than [convert].
-abstract mixin class Converter<S, T> implements StreamTransformerBase<S, T> {
+/// It is recommended that implementations of `Converter` extend this class,
+/// to inherit any further methods that may be added to the class.
+abstract class Converter<S, T> extends StreamTransformerBase<S, T> {
   const Converter();
 
   /// Adapts [source] to be a `Converter<TS, TT>`.
diff --git a/sdk/lib/convert/encoding.dart b/sdk/lib/convert/encoding.dart
index e2234b5..5974366 100644
--- a/sdk/lib/convert/encoding.dart
+++ b/sdk/lib/convert/encoding.dart
@@ -4,14 +4,7 @@
 
 part of dart.convert;
 
-/// Open-ended set of encodings.
-///
-/// An encoding is a [Codec] encoding strings to lists of byte.
-///
-/// This class provides a default implementation of [decodeStream],
-/// which is not incremental. It collects the entire input before
-/// decoding. Subclasses can choose to use that implementation,
-/// or implement a more efficient stream decoding.
+/// Open-ended Encoding enum.
 abstract class Encoding extends Codec<String, List<int>> {
   const Encoding();
 
diff --git a/sdk/lib/convert/html_escape.dart b/sdk/lib/convert/html_escape.dart
index 29fa2ae..ced0a4a7 100644
--- a/sdk/lib/convert/html_escape.dart
+++ b/sdk/lib/convert/html_escape.dart
@@ -70,7 +70,7 @@
 /// escaped = htmlEscape.convert(unescaped);
 /// print(escaped); // Path: /system/
 /// ```
-final class HtmlEscapeMode {
+class HtmlEscapeMode {
   final String _name;
 
   /// Whether to escape '<' and '>'.
@@ -193,7 +193,7 @@
 /// escaped = htmlEscape.convert(unescaped);
 /// print(escaped); // Path: &#47;system&#47;
 /// ```
-final class HtmlEscape extends Converter<String, String> {
+class HtmlEscape extends Converter<String, String> {
   /// The [HtmlEscapeMode] used by the converter.
   final HtmlEscapeMode mode;
 
@@ -257,7 +257,7 @@
   }
 }
 
-class _HtmlEscapeSink extends StringConversionSink {
+class _HtmlEscapeSink extends StringConversionSinkBase {
   final HtmlEscape _escape;
   final StringConversionSink _sink;
 
diff --git a/sdk/lib/convert/json.dart b/sdk/lib/convert/json.dart
index ef5c82f..bf9ab67 100644
--- a/sdk/lib/convert/json.dart
+++ b/sdk/lib/convert/json.dart
@@ -162,7 +162,7 @@
 /// var encoded = json.encode([1, 2, { "a": null }]);
 /// var decoded = json.decode('["foo", { "bar": 499 }]');
 /// ```
-final class JsonCodec extends Codec<Object?, String> {
+class JsonCodec extends Codec<Object?, String> {
   final Object? Function(Object? key, Object? value)? _reviver;
   final Object? Function(dynamic)? _toEncodable;
 
@@ -268,7 +268,7 @@
 /// //   "value": "2"
 /// // }
 /// ```
-final class JsonEncoder extends Converter<Object?, String> {
+class JsonEncoder extends Converter<Object?, String> {
   /// The string used for indention.
   ///
   /// When generating multi-line output, this string is inserted once at the
@@ -383,7 +383,7 @@
 /// This encoder works equivalently to first converting the object to
 /// a JSON string, and then UTF-8 encoding the string, but without
 /// creating an intermediate string.
-final class JsonUtf8Encoder extends Converter<Object?, List<int>> {
+class JsonUtf8Encoder extends Converter<Object?, List<int>> {
   /// Default buffer size used by the JSON-to-UTF-8 encoder.
   static const int _defaultBufferSize = 256;
 
@@ -585,7 +585,7 @@
 /// When used as a [StreamTransformer], the input stream may emit
 /// multiple strings. The concatenation of all of these strings must
 /// be a valid JSON encoding of a single JSON value.
-final class JsonDecoder extends Converter<String, Object?> {
+class JsonDecoder extends Converter<String, Object?> {
   final Object? Function(Object? key, Object? value)? _reviver;
 
   /// Constructs a new JsonDecoder.
diff --git a/sdk/lib/convert/latin1.dart b/sdk/lib/convert/latin1.dart
index 0156b19..76b2dbd 100644
--- a/sdk/lib/convert/latin1.dart
+++ b/sdk/lib/convert/latin1.dart
@@ -21,7 +21,7 @@
 
 /// A [Latin1Codec] encodes strings to ISO Latin-1 (aka ISO-8859-1) bytes
 /// and decodes Latin-1 bytes to strings.
-final class Latin1Codec extends Encoding {
+class Latin1Codec extends Encoding {
   final bool _allowInvalid;
 
   /// Instantiates a new [Latin1Codec].
@@ -72,7 +72,7 @@
 /// final encoded = latin1Encoder.convert(sample);
 /// print(encoded); // [224, 225, 226, 227, 228, 229]
 /// ```
-final class Latin1Encoder extends _UnicodeSubsetEncoder {
+class Latin1Encoder extends _UnicodeSubsetEncoder {
   const Latin1Encoder() : super(_latin1Mask);
 }
 
@@ -105,7 +105,7 @@
 /// final decoded = latin1Decoder.convert(encodedBytes);
 /// print(decoded); // �
 /// ```
-final class Latin1Decoder extends _UnicodeSubsetDecoder {
+class Latin1Decoder extends _UnicodeSubsetDecoder {
   /// Instantiates a new [Latin1Decoder].
   ///
   /// The optional [allowInvalid] argument defines how [convert] deals
@@ -134,7 +134,7 @@
   }
 }
 
-class _Latin1DecoderSink extends ByteConversionSink {
+class _Latin1DecoderSink extends ByteConversionSinkBase {
   StringConversionSink? _sink;
   _Latin1DecoderSink(this._sink);
 
diff --git a/sdk/lib/convert/line_splitter.dart b/sdk/lib/convert/line_splitter.dart
index 5a7e807..a227046 100644
--- a/sdk/lib/convert/line_splitter.dart
+++ b/sdk/lib/convert/line_splitter.dart
@@ -35,7 +35,7 @@
 /// // 3:  garbage-collected
 /// // 4:  language with C-style syntax
 /// ```
-final class LineSplitter extends StreamTransformerBase<String, String> {
+class LineSplitter extends StreamTransformerBase<String, String> {
   const LineSplitter();
 
   /// Split [lines] into individual lines.
@@ -84,7 +84,7 @@
   }
 }
 
-class _LineSplitterSink extends StringConversionSink {
+class _LineSplitterSink extends StringConversionSinkBase {
   final StringConversionSink _sink;
 
   /// The carry-over from the previous chunk.
diff --git a/sdk/lib/convert/string_conversion.dart b/sdk/lib/convert/string_conversion.dart
index 3770be2..5a31093 100644
--- a/sdk/lib/convert/string_conversion.dart
+++ b/sdk/lib/convert/string_conversion.dart
@@ -4,18 +4,19 @@
 
 part of dart.convert;
 
-/// A sink for converters to efficiently transmit String data.
+/// This class provides an interface for converters to
+/// efficiently transmit String data.
 ///
-/// Instead of limiting the interface to one non-chunked [String] it accepts
+/// Instead of limiting the interface to one non-chunked String it accepts
 /// partial strings or can be transformed into a byte sink that
 /// accepts UTF-8 code units.
 ///
-/// The [StringConversionSink] class provides a default implementation of
-/// [add], [asUtf8Sink] and [asStringSink].
-abstract mixin class StringConversionSink
-    implements ChunkedConversionSink<String> {
-  const StringConversionSink();
-
+/// This abstract class will likely get more methods over time. Implementers are
+/// urged to extend [StringConversionSinkBase] or to mix in
+/// [StringConversionSinkMixin], to ensure that their class covers the newly
+/// added methods.
+abstract class StringConversionSink extends ChunkedConversionSink<String> {
+  StringConversionSink();
   factory StringConversionSink.withCallback(void callback(String accumulated)) =
       _StringCallbackSink;
   factory StringConversionSink.from(Sink<String> sink) = _StringAdapterSink;
@@ -35,30 +36,24 @@
   /// If [isLast] is `true` closes `this`.
   void addSlice(String chunk, int start, int end, bool isLast);
 
-  void add(String str) {
-    addSlice(str, 0, str.length, false);
-  }
-
   /// Returns `this` as a sink that accepts UTF-8 input.
   ///
   /// If used, this method must be the first and only call to `this`. It
   /// invalidates `this`. All further operations must be performed on the result.
-  ByteConversionSink asUtf8Sink(bool allowMalformed) {
-    return _Utf8ConversionSink(this, allowMalformed);
-  }
+  ByteConversionSink asUtf8Sink(bool allowMalformed);
+  // - asRuneSink
+  // - asCodeUnitsSink
 
   /// Returns `this` as a [ClosableStringSink].
   ///
   /// If used, this method must be the first and only call to `this`. It
   /// invalidates `this`. All further operations must be performed on the result.
-  ClosableStringSink asStringSink() {
-    return _StringConversionSinkAsStringSinkAdapter(this);
-  }
+  ClosableStringSink asStringSink();
 }
 
 /// A [ClosableStringSink] extends the [StringSink] interface by adding a
 /// `close` method.
-abstract interface class ClosableStringSink implements StringSink {
+abstract class ClosableStringSink extends StringSink {
   /// Creates a new instance combining a [StringSink] [sink] and a callback
   /// [onClose] which is invoked when the returned instance is closed.
   factory ClosableStringSink.fromStringSink(StringSink sink, void onClose()) =
@@ -156,15 +151,30 @@
 
 /// This class provides a base-class for converters that need to accept String
 /// inputs.
-typedef StringConversionSinkBase = StringConversionSink;
+abstract class StringConversionSinkBase extends StringConversionSinkMixin {}
 
 /// This class provides a mixin for converters that need to accept String
 /// inputs.
-typedef StringConversionSinkMixin = StringConversionSink;
+abstract mixin class StringConversionSinkMixin implements StringConversionSink {
+  void addSlice(String str, int start, int end, bool isLast);
+  void close();
+
+  void add(String str) {
+    addSlice(str, 0, str.length, false);
+  }
+
+  ByteConversionSink asUtf8Sink(bool allowMalformed) {
+    return _Utf8ConversionSink(this, allowMalformed);
+  }
+
+  ClosableStringSink asStringSink() {
+    return _StringConversionSinkAsStringSinkAdapter(this);
+  }
+}
 
 /// This class is a [StringConversionSink] that wraps a [StringSink].
 class _StringSinkConversionSink<TStringSink extends StringSink>
-    extends StringConversionSink {
+    extends StringConversionSinkBase {
   final TStringSink _stringSink;
   _StringSinkConversionSink(this._stringSink);
 
@@ -219,7 +229,7 @@
 ///
 /// All additional methods of the [StringConversionSink] (compared to the
 /// ChunkedConversionSink) are redirected to the `add` method.
-class _StringAdapterSink extends StringConversionSink {
+class _StringAdapterSink extends StringConversionSinkBase {
   final Sink<String> _sink;
 
   _StringAdapterSink(this._sink);
diff --git a/sdk/lib/convert/utf.dart b/sdk/lib/convert/utf.dart
index 7473d82e..85bc297 100644
--- a/sdk/lib/convert/utf.dart
+++ b/sdk/lib/convert/utf.dart
@@ -25,7 +25,7 @@
 
 /// A [Utf8Codec] encodes strings to utf-8 code units (bytes) and decodes
 /// UTF-8 code units to strings.
-final class Utf8Codec extends Encoding {
+class Utf8Codec extends Encoding {
   final bool _allowMalformed;
 
   /// Instantiates a new [Utf8Codec].
@@ -82,7 +82,7 @@
 /// final encodedSample = utf8Encoder.convert(sample);
 /// print(encodedSample);
 /// ```
-final class Utf8Encoder extends Converter<String, List<int>> {
+class Utf8Encoder extends Converter<String, List<int>> {
   const Utf8Encoder();
 
   /// Converts [string] to its UTF-8 code units (a list of
@@ -232,7 +232,7 @@
 
 /// This class encodes chunked strings to UTF-8 code units (unsigned 8-bit
 /// integers).
-class _Utf8EncoderSink extends _Utf8Encoder with StringConversionSink {
+class _Utf8EncoderSink extends _Utf8Encoder with StringConversionSinkMixin {
   final ByteConversionSink _sink;
 
   _Utf8EncoderSink(this._sink);
@@ -318,7 +318,7 @@
 /// final decodedBytes = utf8Decoder.convert(encodedBytes);
 /// print(decodedBytes); // �
 /// ```
-final class Utf8Decoder extends Converter<List<int>, String> {
+class Utf8Decoder extends Converter<List<int>, String> {
   final bool _allowMalformed;
 
   /// Instantiates a new [Utf8Decoder].
diff --git a/sdk/lib/io/string_transformer.dart b/sdk/lib/io/string_transformer.dart
index 8e90aed..5bb7f38 100644
--- a/sdk/lib/io/string_transformer.dart
+++ b/sdk/lib/io/string_transformer.dart
@@ -62,7 +62,7 @@
   external static List<int> _encodeString(String string);
 }
 
-class _WindowsCodePageEncoderSink extends StringConversionSink {
+class _WindowsCodePageEncoderSink extends StringConversionSinkBase {
   // TODO(floitsch): provide more efficient conversions when the input is
   // not a String.
 
@@ -106,7 +106,7 @@
   external static String _decodeBytes(List<int> bytes);
 }
 
-class _WindowsCodePageDecoderSink extends ByteConversionSink {
+class _WindowsCodePageDecoderSink extends ByteConversionSinkBase {
   // TODO(floitsch): provide more efficient conversions when the input is
   // a slice.
 
diff --git a/tests/lib/convert/chunked_conversion1_test.dart b/tests/lib/convert/chunked_conversion1_test.dart
index edf7882..cfbad24 100644
--- a/tests/lib/convert/chunked_conversion1_test.dart
+++ b/tests/lib/convert/chunked_conversion1_test.dart
@@ -9,7 +9,7 @@
 // This test implements a new special interface that can be used to
 // send data more efficiently between two converters.
 
-abstract class MyChunkedIntSink implements ChunkedConversionSink<int> {
+abstract class MyChunkedIntSink extends ChunkedConversionSink<int> {
   MyChunkedIntSink();
   factory MyChunkedIntSink.from(sink) = IntAdapterSink;
   factory MyChunkedIntSink.withCallback(callback) {
@@ -32,7 +32,7 @@
   void specialI(int o) => add(o);
 }
 
-abstract class MyChunkedBoolSink implements ChunkedConversionSink<bool> {
+abstract class MyChunkedBoolSink extends ChunkedConversionSink<bool> {
   MyChunkedBoolSink();
   factory MyChunkedBoolSink.from(sink) = BoolAdapterSink;
   factory MyChunkedBoolSink.withCallback(callback) {
@@ -115,7 +115,7 @@
   }
 }
 
-class IdentitySink<T> implements ChunkedConversionSink<T> {
+class IdentitySink<T> extends ChunkedConversionSink<T> {
   final _sink;
   IdentitySink(this._sink);
   void add(T o) => _sink.add(o);
diff --git a/tests/lib/convert/chunked_conversion2_test.dart b/tests/lib/convert/chunked_conversion2_test.dart
index 717cd4d..ca37d10 100644
--- a/tests/lib/convert/chunked_conversion2_test.dart
+++ b/tests/lib/convert/chunked_conversion2_test.dart
@@ -9,7 +9,7 @@
 // Test that the String and ByteConversionSinks make a copy when they need to
 // adapt.
 
-class MyByteSink extends ByteConversionSink {
+class MyByteSink extends ByteConversionSinkBase {
   var accumulator = [];
   add(List<int> bytes) {
     accumulator.add(bytes);
@@ -28,7 +28,7 @@
   Expect.equals(2, byteSink.accumulator[1][0]);
 }
 
-class MyChunkedSink implements ChunkedConversionSink<List<int>> {
+class MyChunkedSink extends ChunkedConversionSink<List<int>> {
   var accumulator = [];
   add(List<int> bytes) {
     accumulator.add(bytes);
diff --git a/tests/lib/convert/chunked_conversion_json_encode1_test.dart b/tests/lib/convert/chunked_conversion_json_encode1_test.dart
index 5ffad23..d93767f 100644
--- a/tests/lib/convert/chunked_conversion_json_encode1_test.dart
+++ b/tests/lib/convert/chunked_conversion_json_encode1_test.dart
@@ -57,7 +57,7 @@
   [r'\foo', r'"\\foo"'],
 ];
 
-class MyStringConversionSink extends StringConversionSink {
+class MyStringConversionSink extends StringConversionSinkBase {
   var buffer = new StringBuffer();
   var callback;
 
diff --git a/tests/lib/convert/chunked_conversion_utf89_test.dart b/tests/lib/convert/chunked_conversion_utf89_test.dart
index 28911eb..893abea 100644
--- a/tests/lib/convert/chunked_conversion_utf89_test.dart
+++ b/tests/lib/convert/chunked_conversion_utf89_test.dart
@@ -5,7 +5,7 @@
 import "package:expect/expect.dart";
 import 'dart:convert';
 
-class MySink implements ChunkedConversionSink<String> {
+class MySink extends ChunkedConversionSink<String> {
   final Function _add;
   final Function _close;
 
diff --git a/tests/lib_2/convert/chunked_conversion1_test.dart b/tests/lib_2/convert/chunked_conversion1_test.dart
index c998f54..fc16676 100644
--- a/tests/lib_2/convert/chunked_conversion1_test.dart
+++ b/tests/lib_2/convert/chunked_conversion1_test.dart
@@ -11,7 +11,7 @@
 // This test implements a new special interface that can be used to
 // send data more efficiently between two converters.
 
-abstract class MyChunkedIntSink implements ChunkedConversionSink<int> {
+abstract class MyChunkedIntSink extends ChunkedConversionSink<int> {
   MyChunkedIntSink();
   factory MyChunkedIntSink.from(sink) = IntAdapterSink;
   factory MyChunkedIntSink.withCallback(callback) {
@@ -34,7 +34,7 @@
   void specialI(int o) => add(o);
 }
 
-abstract class MyChunkedBoolSink implements ChunkedConversionSink<bool> {
+abstract class MyChunkedBoolSink extends ChunkedConversionSink<bool> {
   MyChunkedBoolSink();
   factory MyChunkedBoolSink.from(sink) = BoolAdapterSink;
   factory MyChunkedBoolSink.withCallback(callback) {
@@ -117,7 +117,7 @@
   }
 }
 
-class IdentitySink<T> implements ChunkedConversionSink<T> {
+class IdentitySink<T> extends ChunkedConversionSink<T> {
   final _sink;
   IdentitySink(this._sink);
   void add(T o) => _sink.add(o);
diff --git a/tests/lib_2/convert/chunked_conversion2_test.dart b/tests/lib_2/convert/chunked_conversion2_test.dart
index ca6336c..93592ad 100644
--- a/tests/lib_2/convert/chunked_conversion2_test.dart
+++ b/tests/lib_2/convert/chunked_conversion2_test.dart
@@ -11,7 +11,7 @@
 // Test that the String and ByteConversionSinks make a copy when they need to
 // adapt.
 
-class MyByteSink extends ByteConversionSink {
+class MyByteSink extends ByteConversionSinkBase {
   var accumulator = [];
   add(List<int> bytes) {
     accumulator.add(bytes);
@@ -30,7 +30,7 @@
   Expect.equals(2, byteSink.accumulator[1][0]);
 }
 
-class MyChunkedSink implements ChunkedConversionSink<List<int>> {
+class MyChunkedSink extends ChunkedConversionSink<List<int>> {
   var accumulator = [];
   add(List<int> bytes) {
     accumulator.add(bytes);
diff --git a/tests/lib_2/convert/chunked_conversion_json_encode1_test.dart b/tests/lib_2/convert/chunked_conversion_json_encode1_test.dart
index 6d77cd7..4a994b1 100644
--- a/tests/lib_2/convert/chunked_conversion_json_encode1_test.dart
+++ b/tests/lib_2/convert/chunked_conversion_json_encode1_test.dart
@@ -59,7 +59,7 @@
   [r'\foo', r'"\\foo"'],
 ];
 
-class MyStringConversionSink extends StringConversionSink {
+class MyStringConversionSink extends StringConversionSinkBase {
   var buffer = new StringBuffer();
   var callback;
 
diff --git a/tests/lib_2/convert/chunked_conversion_utf89_test.dart b/tests/lib_2/convert/chunked_conversion_utf89_test.dart
index fad9fcd..748bfeb 100644
--- a/tests/lib_2/convert/chunked_conversion_utf89_test.dart
+++ b/tests/lib_2/convert/chunked_conversion_utf89_test.dart
@@ -7,7 +7,7 @@
 import "package:expect/expect.dart";
 import 'dart:convert';
 
-class MySink implements ChunkedConversionSink<String> {
+class MySink extends ChunkedConversionSink<String> {
   final Function _add;
   final Function _close;