// Copyright (c) 2019, 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. import 'package:expect/expect.dart'; import 'dart:async'; class C { C operator*(int? other) => this; Object? operator-() => null; } // Test ambiguous cases of trailing "!" syntax. Where possible, we verify that // both the compiler and the runtime resolve the ambiguity correctly. main() async { Object? a = null; // `throw a!` means `throw (a!)`, not `(throw a)!`. Since it's a compile-time // error for a thrown expression to be potentially nullable, this is // sufficient to verify that the compiler has resolved the ambiguity // correctly. We check the runtime behavior by verifying that the error that // is thrown is not `NullThrownError`. Expect.throws(() { throw a!; }, (error) => error is! NullThrownError); // `() => a!` means `() => (a!)`, not `(() => a)!`. We check the compile-time // behavior by trying to assign to a function returning non-null. We check // the runtime behavior by ensuring that a call to the closure causes an // exception in the correct circumstances. var x1 = () => a!; Object Function() x2 = x1; Expect.throws(() { x1(); }); // `x = a!` means `x = (a!)`, not `(x = a)!`. We check the compile-time // behavior by trying to assign to a non-nullable variable. We check the // runtime behavior by verifying that the exception is thrown before an // assignment occurs. Object x3 = 0; Expect.throws(() { x3 = a!; }); var x4 = 0 as Object?; Expect.throws(() { x4 = a!; }); Expect.equals(x4, 0); // `true ? null : a!` means `true ? null : (a!)`, not `(true ? null : a)!`. // We check the compile-time behavior by checking that the inferred type of // the expression is nullable. We check the runtime behavior by verifying // that a null value can propagate from the true branch of the conditional. var x5 = true ? null : a!; x5 = null; // `x * i!` means `x * (i!)`, not `(x * i)!`. We check the compile-time // behavior by checking that the multiplication is accepted even though i is // nullable. We check the runtime behavior by using an object whose operator* // ignores its argument, and verify that the appropriate exception is still // thrown. var x6 = 2; var i = 2 as int?; x6 * i!; var x7 = new C(); i = null; Expect.throws(() { x7 * i!; }); // `-x!` means `-(x!)`, not `(-x)!`. We check the compile-time behavior by // checking that the negation is accepted even though x is nullable. We check // the runtime behavior by using an object whose operator- returns null. var x8 = 2 as int?; -x8!; var x9 = new C() as C?; var x10 = -x9!; Expect.isNull(x10); // `await x!` means `await (x!)`, not `(await x)!`. We check the compile-time // behavior by checking that the inferred type of the expression is nullable. // We check the runtime behavior by ensuring that the future completes to a // null value, and this does not produce an exception. FutureOr x11 = new Future.value(null); var x12 = await x11!; Expect.isNull(x12); x12 = null; }