// 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. // 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 *oi* with no arguments, // and let *ri*$ be the returned value. // 3. If *ri* 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(() => "$t${throw "unreachable"}", (e) => e == "Throw"); Expect.throws(() => "$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( () => StringBuffer()..write(t)..write(throw "unreachable"), (e) => e == "Throw"); Expect.throws( () => 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( () => StringBuffer(t)..write(throw "unreachable"), (e) => e == "Throw"); Expect.throws(() => StringBuffer(n)..write(throw "unreachable")); }