blob: 5331e95cf8d3c0bb67f1b669b0eb970b60e2c31c [file] [log] [blame]
// Copyright (c) 2025, 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.
// Exercises flow analysis of patterns that match a Null scrutinee when
// `sound-flow-analysis` is disabled.
// @dart = 3.8
import '../static_type_helper.dart';
typedef IntQuestion = int?;
// `<pattern> as <nullable>` is known to match a null expression.
// (this behavior predates sound-flow-analysis)
testCast({required Null nullValue, required Null Function() nullFunction}) {
{
// null case <pattern> as <nullable>
int? shouldNotBeDemoted = 0;
int? shouldBePromoted;
if (null case _ as Null) {
shouldBePromoted = 0; // Reachable
} else {
shouldNotBeDemoted = null; // Unreachable
}
shouldNotBeDemoted.expectStaticType<Exactly<int>>();
shouldBePromoted.expectStaticType<Exactly<int>>();
}
{
// null case <pattern> as <nullable>
int? shouldNotBeDemoted = 0;
int? shouldBePromoted;
if (null case _ as int?) {
shouldBePromoted = 0; // Reachable
} else {
shouldNotBeDemoted = null; // Unreachable
}
shouldNotBeDemoted.expectStaticType<Exactly<int>>();
shouldBePromoted.expectStaticType<Exactly<int>>();
}
{
// null case <pattern> as <nullable>
int? shouldNotBeDemoted = 0;
int? shouldBePromoted;
if (null case _ as IntQuestion) {
shouldBePromoted = 0; // Reachable
} else {
shouldNotBeDemoted = null; // Unreachable
}
shouldNotBeDemoted.expectStaticType<Exactly<int>>();
shouldBePromoted.expectStaticType<Exactly<int>>();
}
{
// <var> case <pattern> as <nullable>
int? shouldNotBeDemoted = 0;
int? shouldBePromoted;
if (nullValue case _ as Null) {
shouldBePromoted = 0; // Reachable
} else {
shouldNotBeDemoted = null; // Unreachable
}
shouldNotBeDemoted.expectStaticType<Exactly<int>>();
shouldBePromoted.expectStaticType<Exactly<int>>();
}
{
// <var> case <pattern> as <nullable>
int? shouldNotBeDemoted = 0;
int? shouldBePromoted;
if (nullValue case _ as int?) {
shouldBePromoted = 0; // Reachable
} else {
shouldNotBeDemoted = null; // Unreachable
}
shouldNotBeDemoted.expectStaticType<Exactly<int>>();
shouldBePromoted.expectStaticType<Exactly<int>>();
}
{
// <var> case <pattern> as <nullable>
int? shouldNotBeDemoted = 0;
int? shouldBePromoted;
if (nullValue case _ as IntQuestion) {
shouldBePromoted = 0; // Reachable
} else {
shouldNotBeDemoted = null; // Unreachable
}
shouldNotBeDemoted.expectStaticType<Exactly<int>>();
shouldBePromoted.expectStaticType<Exactly<int>>();
}
{
// <expr> case <pattern> as <nullable>
int? shouldNotBeDemoted = 0;
int? shouldBePromoted;
if (nullFunction() case _ as Null) {
shouldBePromoted = 0; // Reachable
} else {
shouldNotBeDemoted = null; // Unreachable
}
shouldNotBeDemoted.expectStaticType<Exactly<int>>();
shouldBePromoted.expectStaticType<Exactly<int>>();
}
{
// <expr> case <pattern> as <nullable>
int? shouldNotBeDemoted = 0;
int? shouldBePromoted;
if (nullFunction() case _ as int?) {
shouldBePromoted = 0; // Reachable
} else {
shouldNotBeDemoted = null; // Unreachable
}
shouldNotBeDemoted.expectStaticType<Exactly<int>>();
shouldBePromoted.expectStaticType<Exactly<int>>();
}
{
// <expr> case <pattern> as <nullable>
int? shouldNotBeDemoted = 0;
int? shouldBePromoted;
if (nullFunction() case _ as IntQuestion) {
shouldBePromoted = 0; // Reachable
} else {
shouldNotBeDemoted = null; // Unreachable
}
shouldNotBeDemoted.expectStaticType<Exactly<int>>();
shouldBePromoted.expectStaticType<Exactly<int>>();
}
}
// `<nullable> <var>` is known to match a null expression.
// (this behavior predates sound-flow-analysis)
testDeclaredVar({
required Null nullValue,
required Null Function() nullFunction,
}) {
{
// null case <nullable> <var>
int? shouldNotBeDemoted = 0;
int? shouldBePromoted;
if (null case Null v) {
shouldBePromoted = 0; // Reachable
} else {
shouldNotBeDemoted = null; // Unreachable
}
shouldNotBeDemoted.expectStaticType<Exactly<int>>();
shouldBePromoted.expectStaticType<Exactly<int>>();
}
{
// null case <nullable> <var>
int? shouldNotBeDemoted = 0;
int? shouldBePromoted;
if (null case int? v) {
shouldBePromoted = 0; // Reachable
} else {
shouldNotBeDemoted = null; // Unreachable
}
shouldNotBeDemoted.expectStaticType<Exactly<int>>();
shouldBePromoted.expectStaticType<Exactly<int>>();
}
{
// null case <nullable> <var>
int? shouldNotBeDemoted = 0;
int? shouldBePromoted;
if (null case IntQuestion v) {
shouldBePromoted = 0; // Reachable
} else {
shouldNotBeDemoted = null; // Unreachable
}
shouldNotBeDemoted.expectStaticType<Exactly<int>>();
shouldBePromoted.expectStaticType<Exactly<int>>();
}
{
// <var> case <nullable> <var>
int? shouldNotBeDemoted = 0;
int? shouldBePromoted;
if (nullValue case Null v) {
shouldBePromoted = 0; // Reachable
} else {
shouldNotBeDemoted = null; // Unreachable
}
shouldNotBeDemoted.expectStaticType<Exactly<int>>();
shouldBePromoted.expectStaticType<Exactly<int>>();
}
{
// <var> case <nullable> <var>
int? shouldNotBeDemoted = 0;
int? shouldBePromoted;
if (nullValue case int? v) {
shouldBePromoted = 0; // Reachable
} else {
shouldNotBeDemoted = null; // Unreachable
}
shouldNotBeDemoted.expectStaticType<Exactly<int>>();
shouldBePromoted.expectStaticType<Exactly<int>>();
}
{
// <var> case <nullable> <var>
int? shouldNotBeDemoted = 0;
int? shouldBePromoted;
if (nullValue case IntQuestion v) {
shouldBePromoted = 0; // Reachable
} else {
shouldNotBeDemoted = null; // Unreachable
}
shouldNotBeDemoted.expectStaticType<Exactly<int>>();
shouldBePromoted.expectStaticType<Exactly<int>>();
}
{
// <expr> case <nullable> <var>
int? shouldNotBeDemoted = 0;
int? shouldBePromoted;
if (nullFunction() case Null v) {
shouldBePromoted = 0; // Reachable
} else {
shouldNotBeDemoted = null; // Unreachable
}
shouldNotBeDemoted.expectStaticType<Exactly<int>>();
shouldBePromoted.expectStaticType<Exactly<int>>();
}
{
// <expr> case <nullable> <var>
int? shouldNotBeDemoted = 0;
int? shouldBePromoted;
if (nullFunction() case int? v) {
shouldBePromoted = 0; // Reachable
} else {
shouldNotBeDemoted = null; // Unreachable
}
shouldNotBeDemoted.expectStaticType<Exactly<int>>();
shouldBePromoted.expectStaticType<Exactly<int>>();
}
{
// <expr> case <nullable> <var>
int? shouldNotBeDemoted = 0;
int? shouldBePromoted;
if (nullFunction() case IntQuestion v) {
shouldBePromoted = 0; // Reachable
} else {
shouldNotBeDemoted = null; // Unreachable
}
shouldNotBeDemoted.expectStaticType<Exactly<int>>();
shouldBePromoted.expectStaticType<Exactly<int>>();
}
}
// `<nullable>()` is known to match a null expression.
// (this behavior predates sound-flow-analysis)
testObject({required Null nullValue, required Null Function() nullFunction}) {
{
// null case <nullable>()
int? shouldNotBeDemoted = 0;
int? shouldBePromoted;
if (null case Null()) {
shouldBePromoted = 0; // Reachable
} else {
shouldNotBeDemoted = null; // Unreachable
}
shouldNotBeDemoted.expectStaticType<Exactly<int>>();
shouldBePromoted.expectStaticType<Exactly<int>>();
}
{
// null case <nullable>()
int? shouldNotBeDemoted = 0;
int? shouldBePromoted;
if (null case IntQuestion()) {
shouldBePromoted = 0; // Reachable
} else {
shouldNotBeDemoted = null; // Unreachable
}
shouldNotBeDemoted.expectStaticType<Exactly<int>>();
shouldBePromoted.expectStaticType<Exactly<int>>();
}
{
// <var> case <nullable>()
int? shouldNotBeDemoted = 0;
int? shouldBePromoted;
if (nullValue case Null()) {
shouldBePromoted = 0; // Reachable
} else {
shouldNotBeDemoted = null; // Unreachable
}
shouldNotBeDemoted.expectStaticType<Exactly<int>>();
shouldBePromoted.expectStaticType<Exactly<int>>();
}
{
// <var> case <nullable>()
int? shouldNotBeDemoted = 0;
int? shouldBePromoted;
if (nullValue case IntQuestion()) {
shouldBePromoted = 0; // Reachable
} else {
shouldNotBeDemoted = null; // Unreachable
}
shouldNotBeDemoted.expectStaticType<Exactly<int>>();
shouldBePromoted.expectStaticType<Exactly<int>>();
}
{
// <expr> case <nullable>()
int? shouldNotBeDemoted = 0;
int? shouldBePromoted;
if (nullFunction() case Null()) {
shouldBePromoted = 0; // Reachable
} else {
shouldNotBeDemoted = null; // Unreachable
}
shouldNotBeDemoted.expectStaticType<Exactly<int>>();
shouldBePromoted.expectStaticType<Exactly<int>>();
}
{
// <expr> case <nullable>()
int? shouldNotBeDemoted = 0;
int? shouldBePromoted;
if (nullFunction() case IntQuestion()) {
shouldBePromoted = 0; // Reachable
} else {
shouldNotBeDemoted = null; // Unreachable
}
shouldNotBeDemoted.expectStaticType<Exactly<int>>();
shouldBePromoted.expectStaticType<Exactly<int>>();
}
}
// `<nullable> _` is known to match a null expression.
// (this behavior predates sound-flow-analysis)
testWildcard({required Null nullValue, required Null Function() nullFunction}) {
{
// null case <nullable> _
int? shouldNotBeDemoted = 0;
int? shouldBePromoted;
if (null case Null _) {
shouldBePromoted = 0; // Reachable
} else {
shouldNotBeDemoted = null; // Unreachable
}
shouldNotBeDemoted.expectStaticType<Exactly<int>>();
shouldBePromoted.expectStaticType<Exactly<int>>();
}
{
// null case <nullable> _
int? shouldNotBeDemoted = 0;
int? shouldBePromoted;
if (null case int? _) {
shouldBePromoted = 0; // Reachable
} else {
shouldNotBeDemoted = null; // Unreachable
}
shouldNotBeDemoted.expectStaticType<Exactly<int>>();
shouldBePromoted.expectStaticType<Exactly<int>>();
}
{
// null case <nullable> _
int? shouldNotBeDemoted = 0;
int? shouldBePromoted;
if (null case IntQuestion _) {
shouldBePromoted = 0; // Reachable
} else {
shouldNotBeDemoted = null; // Unreachable
}
shouldNotBeDemoted.expectStaticType<Exactly<int>>();
shouldBePromoted.expectStaticType<Exactly<int>>();
}
{
// <var> case <nullable> _
int? shouldNotBeDemoted = 0;
int? shouldBePromoted;
if (nullValue case Null _) {
shouldBePromoted = 0; // Reachable
} else {
shouldNotBeDemoted = null; // Unreachable
}
shouldNotBeDemoted.expectStaticType<Exactly<int>>();
shouldBePromoted.expectStaticType<Exactly<int>>();
}
{
// <var> case <nullable> _
int? shouldNotBeDemoted = 0;
int? shouldBePromoted;
if (nullValue case int? _) {
shouldBePromoted = 0; // Reachable
} else {
shouldNotBeDemoted = null; // Unreachable
}
shouldNotBeDemoted.expectStaticType<Exactly<int>>();
shouldBePromoted.expectStaticType<Exactly<int>>();
}
{
// <var> case <nullable> _
int? shouldNotBeDemoted = 0;
int? shouldBePromoted;
if (nullValue case IntQuestion _) {
shouldBePromoted = 0; // Reachable
} else {
shouldNotBeDemoted = null; // Unreachable
}
shouldNotBeDemoted.expectStaticType<Exactly<int>>();
shouldBePromoted.expectStaticType<Exactly<int>>();
}
{
// <expr> case <nullable> _
int? shouldNotBeDemoted = 0;
int? shouldBePromoted;
if (nullFunction() case Null _) {
shouldBePromoted = 0; // Reachable
} else {
shouldNotBeDemoted = null; // Unreachable
}
shouldNotBeDemoted.expectStaticType<Exactly<int>>();
shouldBePromoted.expectStaticType<Exactly<int>>();
}
{
// <expr> case <nullable> _
int? shouldNotBeDemoted = 0;
int? shouldBePromoted;
if (nullFunction() case int? _) {
shouldBePromoted = 0; // Reachable
} else {
shouldNotBeDemoted = null; // Unreachable
}
shouldNotBeDemoted.expectStaticType<Exactly<int>>();
shouldBePromoted.expectStaticType<Exactly<int>>();
}
{
// <expr> case <nullable> _
int? shouldNotBeDemoted = 0;
int? shouldBePromoted;
if (nullFunction() case IntQuestion _) {
shouldBePromoted = 0; // Reachable
} else {
shouldNotBeDemoted = null; // Unreachable
}
shouldNotBeDemoted.expectStaticType<Exactly<int>>();
shouldBePromoted.expectStaticType<Exactly<int>>();
}
}
main() {
testCast(nullValue: null, nullFunction: () => null);
testDeclaredVar(nullValue: null, nullFunction: () => null);
testObject(nullValue: null, nullFunction: () => null);
testWildcard(nullValue: null, nullFunction: () => null);
}