diff --git a/sdk/lib/_internal/vm/lib/object_patch.dart b/sdk/lib/_internal/vm/lib/object_patch.dart index 5ef4a5a4e2b..5468b68fa49 100644 --- a/sdk/lib/_internal/vm/lib/object_patch.dart +++ b/sdk/lib/_internal/vm/lib/object_patch.dart @@ -132,6 +132,28 @@ class _Record { return SystemHash.finish(hash); } + // Do not inline to avoid mixing _fieldAt with + // record field accesses. + @pragma("vm:never-inline") + String toString() { + StringBuffer buffer = StringBuffer("("); + final int numFields = _numFields; + final _List fieldNames = _fieldNames; + final int numPositionalFields = numFields - fieldNames.length; + for (int i = 0; i < numFields; ++i) { + if (i != 0) { + buffer.write(", "); + } + if (i >= numPositionalFields) { + buffer.write(unsafeCast(fieldNames[i - numPositionalFields])); + buffer.write(": "); + } + buffer.write(_fieldAt(i).toString()); + } + buffer.write(")"); + return buffer.toString(); + } + @pragma("vm:recognized", "other") @pragma("vm:prefer-inline") external int get _numFields; diff --git a/tests/language/records/simple/to_string_test.dart b/tests/language/records/simple/to_string_test.dart new file mode 100644 index 00000000000..ad91b78df33 --- /dev/null +++ b/tests/language/records/simple/to_string_test.dart @@ -0,0 +1,33 @@ +// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code as governed by a +// BSD-style license that can be found in the LICENSE file. + +// SharedOptions=--enable-experiment=records + +import "package:expect/expect.dart"; + +class A { + final String name; + const A(this.name); + + String toString() => name; +} + +main() { + // Although the order of fields in toString() is unspecified, + // this test assumes that positional fields are printed first and + // named fields are sorted lexicographically. + // This test might need more sophisticated checks if there is + // an implementation which doesn't follow that order. + + Expect.equals("(1, 2)", (1, 2).toString()); + Expect.equals("(1, 2)", (const (1, 2)).toString()); + Expect.equals("(3, 2, 1)", (3, 2, 1).toString()); + + Expect.equals("(1, foo: 2)", (1, foo: 2).toString()); + Expect.equals("(1, foo: 2)", (foo: 2, 1).toString()); + + Expect.equals("(1, abc, bar: 3, foo: 2)", (1, foo: 2, "abc", bar: 3).toString()); + + Expect.equals("((A1, A2), (foo: A3), (A7, bar: A5, baz: A6, foo: A4))", ((A("A1"), A("A2")), const (foo: A("A3")), (foo: A("A4"), bar: A("A5"), baz: A("A6"), A("A7"))).toString()); +}