blob: 8cb6e4aea715152791c02eacfff8fdb65dc3f296 [file] [log] [blame]
// 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<Object?> x11 = new Future<Object?>.value(null);
var x12 = await x11!;
Expect.isNull(x12);
x12 = null;
}