blob: 2c76fa5483b5ee6aa5190761c4c74769e9bfb373 [file] [log] [blame] [edit]
// Copyright (c) 2024, 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.
// Tests that the behavior described in
// https://github.com/dart-lang/language/issues/4127 has been fixed. That is,
// when deciding whether an `==` or `!=` comparison is guaranteed to evaluate to
// `true` or `false`, flow analysis considers promoted fields to have their
// promoted type.
// This test acts as a regression test for #4127.
import '../static_type_helper.dart';
class C {
final Object? _f;
C(this._f);
void testImplicitThisReferenceOnLhsOfEquals() {
int? x = 0;
int? y = 0;
x.expectStaticType<Exactly<int>>();
y.expectStaticType<Exactly<int>>();
if (_f is! Null) return;
_f.expectStaticType<Exactly<Null>>();
if (_f == null) {
x = null;
} else {
y = null;
}
// In analyzing the `==` check, flow analysis assumes that `_f` has its
// promoted type (`Null`), so only the `x = null` branch is
// reachable. Therefore only `x` should be demoted here.
x.expectStaticType<Exactly<int?>>();
y.expectStaticType<Exactly<int>>();
}
void testImplicitThisReferenceOnRhsOfEquals() {
int? x = 0;
int? y = 0;
x.expectStaticType<Exactly<int>>();
y.expectStaticType<Exactly<int>>();
if (_f is! Null) return;
_f.expectStaticType<Exactly<Null>>();
if (null == _f) {
x = null;
} else {
y = null;
}
// In analyzing the `==` check, flow analysis assumes that `_f` has its
// promoted type (`Null`), so only the `x = null` branch is
// reachable. Therefore only `x` should be demoted here.
x.expectStaticType<Exactly<int?>>();
y.expectStaticType<Exactly<int>>();
}
void testImplicitThisReferenceOnLhsOfNotEquals() {
int? x = 0;
int? y = 0;
x.expectStaticType<Exactly<int>>();
y.expectStaticType<Exactly<int>>();
if (_f is! Null) return;
_f.expectStaticType<Exactly<Null>>();
if (_f != null) {
x = null;
} else {
y = null;
}
// In analyzing the `!=` check, flow analysis assumes that `_f` has its
// promoted type (`Null`), so only the `y = null` branch is
// reachable. Therefore only `y` should be demoted here.
x.expectStaticType<Exactly<int>>();
y.expectStaticType<Exactly<int?>>();
}
void testImplicitThisReferenceOnRhsOfNotEquals() {
int? x = 0;
int? y = 0;
x.expectStaticType<Exactly<int>>();
y.expectStaticType<Exactly<int>>();
if (_f is! Null) return;
_f.expectStaticType<Exactly<Null>>();
if (null != _f) {
x = null;
} else {
y = null;
}
// In analyzing the `!=` check, flow analysis assumes that `_f` has its
// promoted type (`Null`), so only the `y = null` branch is
// reachable. Therefore only `y` should be demoted here.
x.expectStaticType<Exactly<int>>();
y.expectStaticType<Exactly<int?>>();
}
void testExplicitThisReferenceOnLhsOfEquals() {
int? x = 0;
int? y = 0;
x.expectStaticType<Exactly<int>>();
y.expectStaticType<Exactly<int>>();
if (this._f is! Null) return;
this._f.expectStaticType<Exactly<Null>>();
if (this._f == null) {
x = null;
} else {
y = null;
}
// In analyzing the `==` check, flow analysis assumes that `this._f` has its
// promoted type (`Null`), so only the `x = null` branch is
// reachable. Therefore only `x` should be demoted here.
x.expectStaticType<Exactly<int?>>();
y.expectStaticType<Exactly<int>>();
}
void testExplicitThisReferenceOnRhsOfEquals() {
int? x = 0;
int? y = 0;
x.expectStaticType<Exactly<int>>();
y.expectStaticType<Exactly<int>>();
if (this._f is! Null) return;
this._f.expectStaticType<Exactly<Null>>();
if (null == this._f) {
x = null;
} else {
y = null;
}
// In analyzing the `==` check, flow analysis assumes that `this._f` has its
// promoted type (`Null`), so only the `x = null` branch is
// reachable. Therefore only `x` should be demoted here.
x.expectStaticType<Exactly<int?>>();
y.expectStaticType<Exactly<int>>();
}
void testExplicitThisReferenceOnLhsOfNotEquals() {
int? x = 0;
int? y = 0;
x.expectStaticType<Exactly<int>>();
y.expectStaticType<Exactly<int>>();
if (this._f is! Null) return;
this._f.expectStaticType<Exactly<Null>>();
if (this._f != null) {
x = null;
} else {
y = null;
}
// In analyzing the `!=` check, flow analysis assumes that `this._f` has its
// promoted type (`Null`), so only the `y = null` branch is
// reachable. Therefore only `y` should be demoted here.
x.expectStaticType<Exactly<int>>();
y.expectStaticType<Exactly<int?>>();
}
void testExplicitThisReferenceOnRhsOfNotEquals() {
int? x = 0;
int? y = 0;
x.expectStaticType<Exactly<int>>();
y.expectStaticType<Exactly<int>>();
if (this._f is! Null) return;
this._f.expectStaticType<Exactly<Null>>();
if (null != this._f) {
x = null;
} else {
y = null;
}
// In analyzing the `!=` check, flow analysis assumes that `this._f` has its
// promoted type (`Null`), so only the `y = null` branch is
// reachable. Therefore only `y` should be demoted here.
x.expectStaticType<Exactly<int>>();
y.expectStaticType<Exactly<int?>>();
}
}
void testExplicitPropertyReferenceOnLhsOfEquals(C c) {
int? x = 0;
int? y = 0;
x.expectStaticType<Exactly<int>>();
y.expectStaticType<Exactly<int>>();
if (c._f is! Null) return;
c._f.expectStaticType<Exactly<Null>>();
if (c._f == null) {
x = null;
} else {
y = null;
}
// In analyzing the `==` check, flow analysis assumes that `c._f` has its
// promoted type (`Null`), so only the `x = null` branch is
// reachable. Therefore only `x` should be demoted here.
x.expectStaticType<Exactly<int?>>();
y.expectStaticType<Exactly<int>>();
}
void testExplicitPropertyReferenceOnRhsOfEquals(C c) {
int? x = 0;
int? y = 0;
x.expectStaticType<Exactly<int>>();
y.expectStaticType<Exactly<int>>();
if (c._f is! Null) return;
c._f.expectStaticType<Exactly<Null>>();
if (null == c._f) {
x = null;
} else {
y = null;
}
// In analyzing the `==` check, flow analysis assumes that `c._f` has its
// promoted type (`Null`), so only the `x = null` branch is
// reachable. Therefore only `x` should be demoted here.
x.expectStaticType<Exactly<int?>>();
y.expectStaticType<Exactly<int>>();
}
void testExplicitPropertyReferenceOnLhsOfNotEquals(C c) {
int? x = 0;
int? y = 0;
x.expectStaticType<Exactly<int>>();
y.expectStaticType<Exactly<int>>();
if (c._f is! Null) return;
c._f.expectStaticType<Exactly<Null>>();
if (c._f != null) {
x = null;
} else {
y = null;
}
// In analyzing the `!=` check, flow analysis assumes that `c._f` has its
// promoted type (`Null`), so only the `y = null` branch is
// reachable. Therefore only `y` should be demoted here.
x.expectStaticType<Exactly<int>>();
y.expectStaticType<Exactly<int?>>();
}
void testExplicitPropertyReferenceOnRhsOfNotEquals(C c) {
int? x = 0;
int? y = 0;
x.expectStaticType<Exactly<int>>();
y.expectStaticType<Exactly<int>>();
if (c._f is! Null) return;
c._f.expectStaticType<Exactly<Null>>();
if (null != c._f) {
x = null;
} else {
y = null;
}
// In analyzing the `!=` check, flow analysis assumes that `c._f` has its
// promoted type (`Null`), so only the `y = null` branch is
// reachable. Therefore only `y` should be demoted here.
x.expectStaticType<Exactly<int>>();
y.expectStaticType<Exactly<int?>>();
}
main() {
for (var value in [null, '']) {
var c = C(value);
c.testImplicitThisReferenceOnLhsOfEquals();
c.testImplicitThisReferenceOnRhsOfEquals();
c.testImplicitThisReferenceOnLhsOfNotEquals();
c.testImplicitThisReferenceOnRhsOfNotEquals();
c.testExplicitThisReferenceOnLhsOfEquals();
c.testExplicitThisReferenceOnRhsOfEquals();
c.testExplicitThisReferenceOnLhsOfNotEquals();
c.testExplicitThisReferenceOnRhsOfNotEquals();
testExplicitPropertyReferenceOnLhsOfEquals(c);
testExplicitPropertyReferenceOnRhsOfEquals(c);
testExplicitPropertyReferenceOnLhsOfNotEquals(c);
testExplicitPropertyReferenceOnRhsOfNotEquals(c);
}
}