blob: fc23eecff21c1d129ab83992c8c989b8c7f75456 [file] [log] [blame]
// Copyright (c) 2022, 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.
/// This test verifies that various constructs involving an expression of type
/// `Never` are properly treated by flow analysis as belonging to unreachable
/// code paths.
import '../../static_type_helper.dart';
void asExpression(int? x, int i) {
if (x == null) {
i as Never;
}
// Since no runtime object can have type `Never`, the code path after `i as
// Never` should be unreachable. Hence, `x` is promoted to static type `int`.
x.expectStaticType<Exactly<int>>();
}
void ifNullExpression(int? x, Null Function() f) {
if (x == null) {
f() ?? (throw '');
}
// Since `f()` has static type `Null`, it must always evaluate to `null`,
// hence the shortcut branch of `f() ?? throw ''` is unreachable. This means
// that the code path after the whole expression `f() ?? throw ''` should be
// unreachable. Hence, `x` is promoted to static type `int`.
x.expectStaticType<Exactly<int>>();
}
void ifNullAssignment(int? x, Null n) {
if (x == null) {
n ??= throw '';
}
// Since `n` has static type `Null`, it must always be `null`, hence the
// shortcut branch of `n ??= throw ''` is unreachable. This means that the
// code path after the whole expression `n ??= throw ''` should be
// unreachable. Hence, `x` is promoted to static type `int`.
x.expectStaticType<Exactly<int>>();
}
void ifExpression(int? x, int? y, Object? Function() f) {
if (x == null || y == null) return;
x.expectStaticType<Exactly<int>>();
y.expectStaticType<Exactly<int>>();
if (f() is Never) {
x = null;
} else {
y = null;
}
// Since the assignment to y was reachable, it should have static type `int?`
// now. But x should still have static type `int`.
x.expectStaticType<Exactly<int>>();
y.expectStaticType<Exactly<int?>>();
}
void nonNullAssert(int? x, Null Function() f) {
if (x == null) {
f()!;
}
// Since `f()` has static type `Null`, it must always evaluate to `null`,
// hence the non-null assertion always fails. This means that the code path
// after the whole expression `f()!` should be unreachable. Hence, `x` is
// promoted to static type `int`.
x.expectStaticType<Exactly<int>>();
}
void nullAwareAccess(int? x, int? y, Null Function() f, Object? Function() g) {
if (x == null || y == null) return;
x.expectStaticType<Exactly<int>>();
y.expectStaticType<Exactly<int>>();
f()?.extensionMethod(x = null);
g()?.extensionMethod(y = null);
// Since `f()` has static type `Null`, it must always evaluate to `null`,
// hence the assignment to x should be unreachable.
// Since the assignment to y was reachable, it should have static type `int?`
// now. But x should still have static type `int`.
x.expectStaticType<Exactly<int>>();
y.expectStaticType<Exactly<int?>>();
}
extension on Object? {
void extensionMethod(Object? o) {}
}
main() {
asExpression(1, 1);
ifNullExpression(1, () => null);
ifNullAssignment(1, null);
ifExpression(1, 1, () => 1);
nonNullAssert(1, () => null);
nullAwareAccess(1, 1, () => null, () => 1);
}