From 81df36216feda133754e88458fd640d8edc038ef Mon Sep 17 00:00:00 2001 From: Martin Kustermann Date: Tue, 11 Jul 2023 08:54:33 +0000 Subject: [PATCH] Make utf8.encode() have Uint8List return type Right now `utf8.encode()` has a static return type of `List` due to extending `Encoding` (which extends `Codec>`). We cannot easily change `Encoding` to extend `Codec` because that would also change `utf8.decode()` to require `Uint8List` which would be a breaking change. So instead we override `utf8.encode()` to have more precise return type. Some parts of our SDK are run using the checked-in SDK, so it cannot rely on the changed return type yet (until checked-in SDK is rolled). So we use `const Utf8Encoder().convert()` as a temporary change, as that already has `Uint8List` return type. Issue https://github.com/dart-lang/sdk/issues/52801 TEST=ci CoreLibraryReviewExempt: More precise return type for existing API Change-Id: I2861d1f0eb3d292d8e3ec8437c0d441a2d2bd193 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/254903 Commit-Queue: Martin Kustermann Reviewed-by: Lasse Nielsen --- pkg/analysis_server/test/mocks.dart | 4 +-- .../lib/file_system/memory_file_system.dart | 6 ++--- .../lib/file_system/overlay_file_system.dart | 2 +- .../lib/src/summary2/data_writer.dart | 3 +-- .../src/api_prototype/memory_file_system.dart | 5 +--- .../crashing_test_case_minimizer_impl.dart | 25 ++++++++----------- pkg/front_end/test/dartdoc_test_test.dart | 7 +++--- pkg/front_end/test/fasta/testing/suite.dart | 10 ++++---- pkg/front_end/tool/dart_doctest_impl.dart | 2 +- pkg/front_end/tool/perf.dart | 2 +- pkg/vm/bin/kernel_service.dart | 2 +- sdk/lib/convert/utf.dart | 5 ++++ 12 files changed, 35 insertions(+), 38 deletions(-) diff --git a/pkg/analysis_server/test/mocks.dart b/pkg/analysis_server/test/mocks.dart index 9f4b5a6f8ff6..d345635b551b 100644 --- a/pkg/analysis_server/test/mocks.dart +++ b/pkg/analysis_server/test/mocks.dart @@ -68,10 +68,10 @@ class MockProcess implements Process { int get pid => _pid; @override - Stream> get stderr => Future.value(utf8.encode(_stderr)).asStream(); + Stream> get stderr => Stream>.value(utf8.encode(_stderr)); @override - Stream> get stdout => Future.value(utf8.encode(_stdout)).asStream(); + Stream> get stdout => Stream>.value(utf8.encode(_stdout)); @override bool kill([ProcessSignal signal = ProcessSignal.sigterm]) { diff --git a/pkg/analyzer/lib/file_system/memory_file_system.dart b/pkg/analyzer/lib/file_system/memory_file_system.dart index c338d1024bf3..cafd0e1526cd 100644 --- a/pkg/analyzer/lib/file_system/memory_file_system.dart +++ b/pkg/analyzer/lib/file_system/memory_file_system.dart @@ -145,14 +145,14 @@ class MemoryResourceProvider implements ResourceProvider { } _pathToData[path] = _FileData( - bytes: utf8.encode(content) as Uint8List, + bytes: const Utf8Encoder().convert(content), timeStamp: nextStamp++, ); _notifyWatchers(path, ChangeType.MODIFY); } File newFile(String path, String content) { - var bytes = utf8.encode(content) as Uint8List; + var bytes = const Utf8Encoder().convert(content); return newFileWithBytes(path, bytes); } @@ -422,7 +422,7 @@ class _MemoryFile extends _MemoryResource implements File { @override void writeAsStringSync(String content) { - var bytes = utf8.encode(content) as Uint8List; + var bytes = const Utf8Encoder().convert(content); writeAsBytesSync(bytes); } } diff --git a/pkg/analyzer/lib/file_system/overlay_file_system.dart b/pkg/analyzer/lib/file_system/overlay_file_system.dart index 469de5d9ce57..3165440021f0 100644 --- a/pkg/analyzer/lib/file_system/overlay_file_system.dart +++ b/pkg/analyzer/lib/file_system/overlay_file_system.dart @@ -182,7 +182,7 @@ class _OverlayFile extends _OverlayResource implements File { Uint8List readAsBytesSync() { String? content = provider._getOverlayContent(path); if (content != null) { - return utf8.encode(content) as Uint8List; + return const Utf8Encoder().convert(content); } return _file.readAsBytesSync(); } diff --git a/pkg/analyzer/lib/src/summary2/data_writer.dart b/pkg/analyzer/lib/src/summary2/data_writer.dart index e2a028cd4b8e..39e8f7e023a2 100644 --- a/pkg/analyzer/lib/src/summary2/data_writer.dart +++ b/pkg/analyzer/lib/src/summary2/data_writer.dart @@ -178,8 +178,7 @@ class BufferedSink { /// Write the [value] as UTF8 encoded byte array. void writeStringUtf8(String value) { - var bytes = utf8.encode(value); - writeUint8List(bytes as Uint8List); + writeUint8List(const Utf8Encoder().convert(value)); } void writeStringUtf8Iterable(Iterable items) { diff --git a/pkg/front_end/lib/src/api_prototype/memory_file_system.dart b/pkg/front_end/lib/src/api_prototype/memory_file_system.dart index b510fc4c178b..71f579692877 100644 --- a/pkg/front_end/lib/src/api_prototype/memory_file_system.dart +++ b/pkg/front_end/lib/src/api_prototype/memory_file_system.dart @@ -131,10 +131,7 @@ class MemoryFileSystemEntity implements FileSystemEntity { /// If no file exists, one is created. If a file exists already, it is /// overwritten. void writeAsStringSync(String s) { - // Note: the return type of utf8.encode is List, but in practice it - // always returns Uint8List. We rely on that for efficiency, so that we - // don't have to make an extra copy. - _update(uri, utf8.encode(s) as Uint8List); + _update(uri, const Utf8Encoder().convert(s)); } void _update(Uri uri, Uint8List data) { diff --git a/pkg/front_end/test/crashing_test_case_minimizer_impl.dart b/pkg/front_end/test/crashing_test_case_minimizer_impl.dart index e088d805ee2c..86b45ea15cff 100644 --- a/pkg/front_end/test/crashing_test_case_minimizer_impl.dart +++ b/pkg/front_end/test/crashing_test_case_minimizer_impl.dart @@ -293,7 +293,7 @@ class TestMinimizer { Future _tryToMinimizeImpl() async { // Set main to be basically empty up front. _settings._useInitialFs = true; - _fs.data[_mainUri] = utf8.encode("main() {}") as Uint8List; + _fs.data[_mainUri] = utf8.encode("main() {}"); Component initialComponent = await _getInitialComponent(); print("Compiled initially (without data)"); // Remove fake cache. @@ -326,7 +326,7 @@ class TestMinimizer { if (_knownByCompiler(uri!)) { String parsedString = _getFileAsStringContent(_fs.data[uri]!, _isUriNnbd(uri)); - _fs.data[uri] = utf8.encode(parsedString) as Uint8List; + _fs.data[uri] = utf8.encode(parsedString); } } catch (e) { // crash in scanner/parser --- keep original file. This crash might @@ -628,8 +628,7 @@ class TestMinimizer { for (int i = offsetOfLast; i < withoutInlineableString.length; i++) { builder.writeCharCode(withoutInlineableString.codeUnitAt(i)); } - final Uint8List inlinedWithoutChange = - utf8.encode(builder.toString()) as Uint8List; + final Uint8List inlinedWithoutChange = utf8.encode(builder.toString()); if (!_parsesWithoutError(inlinedWithoutChange, _isUriNnbd(uri))) { print("WARNING: Parser error after stuff at ${StackTrace.current}"); @@ -669,8 +668,7 @@ class TestMinimizer { for (int i = offsetOfLast; i < withoutInlineableString.length; i++) { builder.writeCharCode(withoutInlineableString.codeUnitAt(i)); } - Uint8List inlinedWithChange = - utf8.encode(builder.toString()) as Uint8List; + Uint8List inlinedWithChange = utf8.encode(builder.toString()); if (!_parsesWithoutError(inlinedWithChange, _isUriNnbd(uri))) { print("WARNING: Parser error after stuff at ${StackTrace.current}"); @@ -1015,7 +1013,7 @@ worlds: bool outlined = false; if (textualOutlined != null) { - Uint8List candidate = utf8.encode(textualOutlined) as Uint8List; + Uint8List candidate = utf8.encode(textualOutlined); // Because textual outline doesn't do the right thing for nnbd, only // replace if it's syntactically valid. if (candidate.length != _fs.data[uri]!.length && @@ -1041,8 +1039,7 @@ worlds: if (!string.trim().startsWith("//")) stringsLeft.add(string); } - Uint8List candidate = - utf8.encode(stringsLeft.join("\n")) as Uint8List; + Uint8List candidate = utf8.encode(stringsLeft.join("\n")); if (candidate.length != _fs.data[uri]!.length) { if (await _shouldQuit()) return; _fs.data[uri] = candidate; @@ -1088,7 +1085,7 @@ worlds: } } string = lines.join("\n"); - _fs.data[uri] = utf8.encode(string) as Uint8List; + _fs.data[uri] = utf8.encode(string); if (!await _crashesOnCompile(initialComponent)) { // For some reason that didn't work. _fs.data[uri] = data; @@ -1226,7 +1223,7 @@ worlds: } } string = lines.join("\n"); - Uint8List candidate = utf8.encode(string) as Uint8List; + Uint8List candidate = utf8.encode(string); if (candidate.length != data.length) { _fs.data[uri] = candidate; if (!await _crashesOnCompile(initialComponent)) { @@ -1248,7 +1245,7 @@ worlds: while (i < packagesModified.length) { var oldEntry = packagesModified.removeAt(i); String jsonString = jsonEncoder.convert(jsonModified); - candidate = utf8.encode(jsonString) as Uint8List; + candidate = utf8.encode(jsonString); Uint8List? previous = _fs.data[uri]; _fs.data[uri] = candidate; if (!await _crashesOnCompile(initialComponent)) { @@ -2071,7 +2068,7 @@ worlds: builder.writeCharCode(_dataCacheString!.codeUnitAt(j)); } - Uint8List candidate = utf8.encode(builder.toString()) as Uint8List; + Uint8List candidate = utf8.encode(builder.toString()); return candidate; } } @@ -2130,7 +2127,7 @@ class _FakeFileSystem extends FileSystem { if (tmp[i + 1] == null) { data[key] = null; } else if (tmp[i + 1] is String) { - data[key] = utf8.encode(tmp[i + 1]) as Uint8List; + data[key] = utf8.encode(tmp[i + 1]); } else { data[key] = Uint8List.fromList(new List.from(tmp[i + 1])); } diff --git a/pkg/front_end/test/dartdoc_test_test.dart b/pkg/front_end/test/dartdoc_test_test.dart index 35de3377ca24..3ccff98890e0 100644 --- a/pkg/front_end/test/dartdoc_test_test.dart +++ b/pkg/front_end/test/dartdoc_test_test.dart @@ -1,5 +1,4 @@ import 'dart:convert'; -import 'dart:typed_data'; import 'package:_fe_analyzer_shared/src/scanner/token.dart'; import 'package:front_end/src/api_prototype/memory_file_system.dart'; @@ -460,7 +459,7 @@ bool _expectImpl(dynamic actual, dynamic expected, StringBuffer explainer) { } impl.CommentString? extractFirstComment(String test) { - Token firstToken = impl.scanRawBytes(utf8.encode(test) as Uint8List); + Token firstToken = impl.scanRawBytes(utf8.encode(test)); Token token = firstToken; while (true) { CommentToken? comment = token.precedingComments; @@ -476,6 +475,6 @@ impl.CommentString? extractFirstComment(String test) { } List extractTests(String test, [Uri? uri]) { - return impl.extractTests(utf8.encode(test) as Uint8List, - uri ?? new Uri(scheme: "darttest", path: "/foo.dart")); + return impl.extractTests( + utf8.encode(test), uri ?? new Uri(scheme: "darttest", path: "/foo.dart")); } diff --git a/pkg/front_end/test/fasta/testing/suite.dart b/pkg/front_end/test/fasta/testing/suite.dart index ebe4d84b53c6..e23acdad520f 100644 --- a/pkg/front_end/test/fasta/testing/suite.dart +++ b/pkg/front_end/test/fasta/testing/suite.dart @@ -4,7 +4,7 @@ library fasta.testing.suite; -import 'dart:convert' show jsonDecode, utf8; +import 'dart:convert' show jsonDecode, utf8, Utf8Encoder; import 'dart:io' show Directory, File, Platform; import 'dart:typed_data' show Uint8List; @@ -1528,7 +1528,7 @@ class FuzzCompiles for (FuzzAstVisitorSorterChunk chunk in fuzzAstVisitorSorter.chunks) { sb.writeln(chunk.getSource()); } - Uint8List sortedData = utf8.encode(sb.toString()) as Uint8List; + Uint8List sortedData = const Utf8Encoder().convert(sb.toString()); fs.data[uri] = sortedData; incrementalCompiler = new IncrementalCompiler.fromComponent( new CompilerContext(compilationSetup.options), platform); @@ -1644,7 +1644,7 @@ class FuzzCompiles print("Skipping $uri -- couldn't find builder for it."); continue; } - Uint8List orgData = fs.data[uri] as Uint8List; + Uint8List orgData = fs.data[uri]!; FuzzAstVisitorSorter fuzzAstVisitorSorter; try { fuzzAstVisitorSorter = @@ -1696,7 +1696,7 @@ class FuzzCompiles sb.writeln("import '${uri.pathSegments.last}';"); sb.writeln(chunk.getSource()); fs.data[getUriForChunk(currentSubFile)] = - utf8.encode(sb.toString()) as Uint8List; + const Utf8Encoder().convert(sb.toString()); print(" => Split into ${getUriForChunk(currentSubFile)}:\n" "${sb.toString()}\n-------------\n"); currentSubFile++; @@ -1711,7 +1711,7 @@ class FuzzCompiles } sb.writeln(orgFileOnlyHeaderSb.toString()); print(" => Main file becomes:\n${sb.toString()}\n-------------\n"); - fs.data[uri] = utf8.encode(sb.toString()) as Uint8List; + fs.data[uri] = const Utf8Encoder().convert(sb.toString()); } Result? passResult = await performFileInvalidation( diff --git a/pkg/front_end/tool/dart_doctest_impl.dart b/pkg/front_end/tool/dart_doctest_impl.dart index a28b542a9ff3..12e04aa8d1d3 100644 --- a/pkg/front_end/tool/dart_doctest_impl.dart +++ b/pkg/front_end/tool/dart_doctest_impl.dart @@ -555,7 +555,7 @@ List extractTestsFromComment( Test scanDartDoc(int scanOffset) { final Token firstToken = - scanRawBytes(utf8.encode(comments.substring(scanOffset)) as Uint8List); + scanRawBytes(utf8.encode(comments.substring(scanOffset))); final ErrorListener listener = new ErrorListener(); final Parser parser = new Parser(listener, useImplicitCreationExpression: useImplicitCreationExpressionInCfe); diff --git a/pkg/front_end/tool/perf.dart b/pkg/front_end/tool/perf.dart index 78e3ff360ab0..42072d18d4c6 100644 --- a/pkg/front_end/tool/perf.dart +++ b/pkg/front_end/tool/perf.dart @@ -209,7 +209,7 @@ Set scanReachableFiles(Uri entryUri) { /// Loads the file contents of all [files] as bytes. Set loadFileContentsAsBytes(Set files) { return files.map((Source source) { - final bytes = utf8.encode(source.contents.data) as Uint8List; + final bytes = utf8.encode(source.contents.data); // CFE needs files to e 0-terminated. return Uint8List(bytes.length + 1) ..setRange(0, bytes.length, bytes) diff --git a/pkg/vm/bin/kernel_service.dart b/pkg/vm/bin/kernel_service.dart index 4554b4f2b2ba..1a540c3ae483 100644 --- a/pkg/vm/bin/kernel_service.dart +++ b/pkg/vm/bin/kernel_service.dart @@ -701,7 +701,7 @@ String _escapeDependency(Uri uri) { } Uint8List _serializeDependencies(List uris) { - return utf8.encode(uris.map(_escapeDependency).join(" ")) as Uint8List; + return utf8.encode(uris.map(_escapeDependency).join(" ")); } Future _processListDependenciesRequest( diff --git a/sdk/lib/convert/utf.dart b/sdk/lib/convert/utf.dart index 7473d82e2b5e..5484de66fe45 100644 --- a/sdk/lib/convert/utf.dart +++ b/sdk/lib/convert/utf.dart @@ -63,6 +63,11 @@ final class Utf8Codec extends Encoding { return decoder.convert(codeUnits); } + /// Encodes the [string] as UTF-8. + Uint8List encode(String string) { + return const Utf8Encoder().convert(string); + } + Utf8Encoder get encoder => const Utf8Encoder(); Utf8Decoder get decoder { // Switch between const objects to avoid allocation.