Skip to content

Commit

Permalink
Make utf8.encode() have Uint8List return type
Browse files Browse the repository at this point in the history
Right now `utf8.encode()` has a static return type of `List<int>`
due to extending `Encoding` (which extends `Codec<String, List<int>>`).

We cannot easily change `Encoding` to extend `Codec<String, Uint8List>`
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 #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 <kustermann@google.com>
Reviewed-by: Lasse Nielsen <lrn@google.com>
  • Loading branch information
mkustermann authored and Commit Queue committed Jul 11, 2023
1 parent e1c12b3 commit 81df362
Show file tree
Hide file tree
Showing 12 changed files with 35 additions and 38 deletions.
4 changes: 2 additions & 2 deletions pkg/analysis_server/test/mocks.dart
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,10 @@ class MockProcess implements Process {
int get pid => _pid;

@override
Stream<List<int>> get stderr => Future.value(utf8.encode(_stderr)).asStream();
Stream<List<int>> get stderr => Stream<List<int>>.value(utf8.encode(_stderr));

@override
Stream<List<int>> get stdout => Future.value(utf8.encode(_stdout)).asStream();
Stream<List<int>> get stdout => Stream<List<int>>.value(utf8.encode(_stdout));

@override
bool kill([ProcessSignal signal = ProcessSignal.sigterm]) {
Expand Down
6 changes: 3 additions & 3 deletions pkg/analyzer/lib/file_system/memory_file_system.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down Expand Up @@ -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);
}
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/analyzer/lib/file_system/overlay_file_system.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
Expand Down
3 changes: 1 addition & 2 deletions pkg/analyzer/lib/src/summary2/data_writer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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<String> items) {
Expand Down
5 changes: 1 addition & 4 deletions pkg/front_end/lib/src/api_prototype/memory_file_system.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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<int>, 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) {
Expand Down
25 changes: 11 additions & 14 deletions pkg/front_end/test/crashing_test_case_minimizer_impl.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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}");
Expand Down Expand Up @@ -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}");
Expand Down Expand Up @@ -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 &&
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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)) {
Expand All @@ -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)) {
Expand Down Expand Up @@ -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;
}
}
Expand Down Expand Up @@ -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<int>.from(tmp[i + 1]));
}
Expand Down
7 changes: 3 additions & 4 deletions pkg/front_end/test/dartdoc_test_test.dart
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -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;
Expand All @@ -476,6 +475,6 @@ impl.CommentString? extractFirstComment(String test) {
}

List<impl.Test> 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"));
}
10 changes: 5 additions & 5 deletions pkg/front_end/test/fasta/testing/suite.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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 =
Expand Down Expand Up @@ -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++;
Expand All @@ -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<ComponentResult>? passResult = await performFileInvalidation(
Expand Down
2 changes: 1 addition & 1 deletion pkg/front_end/tool/dart_doctest_impl.dart
Original file line number Diff line number Diff line change
Expand Up @@ -555,7 +555,7 @@ List<Test> 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);
Expand Down
2 changes: 1 addition & 1 deletion pkg/front_end/tool/perf.dart
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ Set<Source> scanReachableFiles(Uri entryUri) {
/// Loads the file contents of all [files] as bytes.
Set<Uint8List> loadFileContentsAsBytes(Set<Source> 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)
Expand Down
2 changes: 1 addition & 1 deletion pkg/vm/bin/kernel_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -701,7 +701,7 @@ String _escapeDependency(Uri uri) {
}

Uint8List _serializeDependencies(List<Uri> uris) {
return utf8.encode(uris.map(_escapeDependency).join(" ")) as Uint8List;
return utf8.encode(uris.map(_escapeDependency).join(" "));
}

Future _processListDependenciesRequest(
Expand Down
5 changes: 5 additions & 0 deletions sdk/lib/convert/utf.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down

0 comments on commit 81df362

Please sign in to comment.