blob: da94e5639af5ee2f42c6a5f266bfe96026fceafe [file] [log] [blame]
// Copyright (c) 2012, 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
// Interpolation calls `toString`.
// The evaluation of the interpolation fails if `toString` throws or returns
// null. In Dart 2, any method overriding `Object.toString` must return a
// `String` or `null`. In particular, if `object.toString()` returns null, then
// `"$object"` must not evaluate to the string `"null"`.
//
// The specification states that the expression of an interpolation is
// evaluated as follows:
//
// 1. Evaluate $e_i$ to an object $o_i$.
// 2. Invoke the `toString` method on *o<sub>i</sub>* with no arguments,
// and let *r<sub>i</sub>*$ be the returned value.
// 3. If *r<sub>i</sub>* is not an instance of the built-in type `String`,
// throw an `Error`.
//
// (Then the resulting strings are concatenated with the literal string parts).
//
//
// Adding an object to a `StringBuffer` behaves the same as evaluating
// an expression in an interpolation. It must immediately fail if the
// object's toString throws or returns `null`.
//
// This ensures that implementing interpolation via a `StringBuffer`is
// a valid implementation choice.
import "package:expect/expect.dart";
class ToStringString {
String toString() => "String";
}
class ToStringNull {
String toString() => null;
}
class ToStringThrows {
String toString() => throw "Throw";
}
void main() {
var s = ToStringString();
var n = ToStringNull();
var t = ToStringThrows();
Expect.equals("$s$s", "StringString");
// Throws immediately when evaluating the first interpolated expression.
Expect.throws<String>(() => "$t${throw "unreachable"}", (e) => e == "Throw");
Expect.throws<Error>(() => "$n${throw "unreachable"}");
// Throws immediately when adding object that doesn't return a String.
Expect.equals(
(StringBuffer()..write(s)..write(s)).toString(), "StringString");
Expect.throws<String>(
() => StringBuffer()..write(t)..write(throw "unreachable"),
(e) => e == "Throw");
Expect.throws<Error>(
() => StringBuffer()..write(n)..write(throw "unreachable"));
// Same behavior for constructor argument as if adding it to buffer later.
Expect.equals((StringBuffer(s)..write(s)).toString(), "StringString");
Expect.throws<String>(
() => StringBuffer(t)..write(throw "unreachable"), (e) => e == "Throw");
Expect.throws<Error>(() => StringBuffer(n)..write(throw "unreachable"));
}