Version 2.15.0-161.0.dev
Merge commit 'c74dd07a4a3bc139c6a3b6e21eee79ac4a6440dd' into 'dev'
diff --git a/runtime/vm/compiler/recognized_methods_list.h b/runtime/vm/compiler/recognized_methods_list.h
index 862b338..3ed3608 100644
--- a/runtime/vm/compiler/recognized_methods_list.h
+++ b/runtime/vm/compiler/recognized_methods_list.h
@@ -81,7 +81,7 @@
V(::, _toClampedUint8, ConvertIntToClampedUint8, 0x00fc4650) \
V(::, copyRangeFromUint8ListToOneByteString, \
CopyRangeFromUint8ListToOneByteString, 0x0df019c5) \
- V(_StringBase, _interpolate, StringBaseInterpolate, 0xea1eafca) \
+ V(_StringBase, _interpolate, StringBaseInterpolate, 0xfc28bc84) \
V(_IntegerImplementation, toDouble, IntegerToDouble, 0x97728b46) \
V(_Double, _add, DoubleAdd, 0xea666327) \
V(_Double, _sub, DoubleSub, 0x28474c2e) \
diff --git a/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart b/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart
index 33854c7..89c90d5 100644
--- a/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart
+++ b/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart
@@ -717,7 +717,11 @@
String str(obj) {
if (obj == null) return "null";
if (obj is String) return obj;
- return _notNull(JS('!', '#[#]()', obj, extensionSymbol('toString')));
+ final result = JS('', '#[#]()', obj, extensionSymbol('toString'));
+ // TODO(40614): Declare `result` as String once non-nullability is sound.
+ if (result is String) return result;
+ // Since Dart 2.0, `null` is the only other option.
+ throw ArgumentError.value(obj, 'object', "toString method returned 'null'");
}
// TODO(jmesserly): is the argument type verified statically?
diff --git a/sdk/lib/_internal/js_runtime/lib/js_helper.dart b/sdk/lib/_internal/js_runtime/lib/js_helper.dart
index b39faed..ff38ff8 100644
--- a/sdk/lib/_internal/js_runtime/lib/js_helper.dart
+++ b/sdk/lib/_internal/js_runtime/lib/js_helper.dart
@@ -131,9 +131,12 @@
} else if (value == null) {
return 'null';
}
- var res = value.toString();
- if (res is! String) throw argumentErrorValue(value);
- return res;
+ var result = value.toString();
+ if (result is! String) {
+ throw ArgumentError.value(
+ value, 'object', "toString method returned 'null'");
+ }
+ return result;
}
// Called from generated code.
diff --git a/sdk/lib/_internal/vm/lib/string_buffer_patch.dart b/sdk/lib/_internal/vm/lib/string_buffer_patch.dart
index 3991deb..8a30546 100644
--- a/sdk/lib/_internal/vm/lib/string_buffer_patch.dart
+++ b/sdk/lib/_internal/vm/lib/string_buffer_patch.dart
@@ -61,7 +61,7 @@
@patch
void write(Object? obj) {
- String str = obj.toString();
+ String str = "$obj";
if (str.isEmpty) return;
_consumeBuffer();
_addPart(str);
diff --git a/sdk/lib/_internal/vm/lib/string_patch.dart b/sdk/lib/_internal/vm/lib/string_patch.dart
index ff41360..66e3dcd 100644
--- a/sdk/lib/_internal/vm/lib/string_patch.dart
+++ b/sdk/lib/_internal/vm/lib/string_patch.dart
@@ -829,8 +829,9 @@
static String _interpolateSingle(Object? o) {
if (o is String) return o;
final s = o.toString();
+ // TODO(40614): Remove once non-nullability is sound.
if (s is! String) {
- throw new ArgumentError(s);
+ throw _interpolationError(o, s);
}
return s;
}
@@ -855,15 +856,17 @@
totalLength += s.length;
i++;
} else if (s is! String) {
- throw new ArgumentError(s);
+ // TODO(40614): Remove once non-nullability is sound.
+ throw _interpolationError(e, s);
} else {
// Handle remaining elements without checking for one-byte-ness.
while (++i < numValues) {
final e = values[i];
final s = e.toString();
values[i] = s;
+ // TODO(40614): Remove once non-nullability is sound.
if (s is! String) {
- throw new ArgumentError(s);
+ throw _interpolationError(e, s);
}
}
return _concatRangeNative(values, 0, numValues);
@@ -873,6 +876,12 @@
return _OneByteString._concatAll(values, totalLength);
}
+ static ArgumentError _interpolationError(Object? o, Object? result) {
+ // Since Dart 2.0, [result] can only be null.
+ return new ArgumentError.value(
+ o, "object", "toString method returned 'null'");
+ }
+
Iterable<Match> allMatches(String string, [int start = 0]) {
if (start < 0 || start > string.length) {
throw new RangeError.range(start, 0, string.length, "start");
diff --git a/sdk/lib/core/print.dart b/sdk/lib/core/print.dart
index 460a852..10a0263 100644
--- a/sdk/lib/core/print.dart
+++ b/sdk/lib/core/print.dart
@@ -6,7 +6,7 @@
/// Prints a string representation of the object to the console.
void print(Object? object) {
- String line = checkNotNullable(object.toString(), "object.toString()");
+ String line = "$object";
var toZone = printToZone;
if (toZone == null) {
printToConsole(line);
diff --git a/tests/corelib_2/string_interpolation_error_test.dart b/tests/corelib_2/string_interpolation_error_test.dart
new file mode 100644
index 0000000..b9764e6
--- /dev/null
+++ b/tests/corelib_2/string_interpolation_error_test.dart
@@ -0,0 +1,30 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// @dart = 2.9
+
+import "package:expect/expect.dart";
+
+class BadToString {
+ @override
+ String toString() => null;
+}
+
+void test(expected, object) {
+ var message = '';
+ if (expected == null) {
+ Expect.throws(() => '$object',
+ (error) => '$error'.contains("toString method returned 'null'"));
+ } else {
+ Expect.equals(expected, '$object');
+ }
+}
+
+void main() {
+ test("123", 123);
+ test("null", null);
+ test(null, BadToString());
+ test(null, [BadToString()]);
+ test(null, {BadToString()});
+}
diff --git a/tools/VERSION b/tools/VERSION
index ba9cb17..23ba9f3 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 15
PATCH 0
-PRERELEASE 160
+PRERELEASE 161
PRERELEASE_PATCH 0
\ No newline at end of file