blob: d1cc807b2f71be551be647043841b722d8ba3e9b [file] [log] [blame]
// Copyright (c) 2023, 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 field promotion works with cascades.
import '../static_type_helper.dart';
class C {
final Object? _field;
C([this._field]);
void f([_]) {}
}
void cascadedAccessReceivesTheBenefitOfPromotion(C c) {
// If a field of an object is promoted prior to its use in a cascade, accesses
// to the field within cascade sections retain the promotion.
c._field as int;
c._field.expectStaticType<Exactly<int>>();
c
.._field.expectStaticType<Exactly<int>>()
.._field.expectStaticType<Exactly<int>>();
// And the promotion remains on later accesses to the same variable.
c._field.expectStaticType<Exactly<int>>();
}
void fieldAccessOnACascadeExpressionRetainsPromotion(C c) {
// If a field of an object is promoted prior to its use in a cascade, accesses
// to the field from outside the cascade retain the promotion.
c._field as int;
c._field.expectStaticType<Exactly<int>>();
(c..f())._field.expectStaticType<Exactly<int>>();
// And the promotion remains on later accesses to the same variable.
c._field.expectStaticType<Exactly<int>>();
}
void fieldsPromotableWithinCascade(C c) {
// Within a cascade, a field can be promoted using `!`.
c
.._field.expectStaticType<Exactly<Object?>>()
.._field!.expectStaticType<Exactly<Object>>()
.._field.expectStaticType<Exactly<Object>>();
// And after the cascade, the promotion is retained.
c._field.expectStaticType<Exactly<Object>>();
}
void cascadeExpressionIsNotPromotable(Object? o) {
// However, null-checking, casting, or type checking the result of a cascade
// expression does not promote the target of the cascade. (It could, in
// principle, but it would be extra work to implement, and it seems unlikely
// that it would be of much benefit).
(o..toString())!;
o.expectStaticType<Exactly<Object?>>();
(o..toString()) as Object;
o.expectStaticType<Exactly<Object?>>();
if ((o..toString()) is Object) {
o.expectStaticType<Exactly<Object?>>();
}
}
void ephemeralValueFieldsArePromotable(C Function() getC) {
// Fields of an ephemeral value (one that is not explicitly stored in a
// variable) can still be promoted in one cascade section, and the results of
// the promotion can be seen in later cascade sections.
getC()
.._field.expectStaticType<Exactly<Object?>>()
.._field!.expectStaticType<Exactly<Object>>()
.._field.expectStaticType<Exactly<Object>>();
// But they won't be seen if a fresh value is created.
getC()._field.expectStaticType<Exactly<Object?>>();
}
void writeCapturedValueFieldsArePromotable(C c) {
// Fields of a write-captured variable can still be promoted in one cascade
// section, and the results of the promotion can be seen in later cascade
// sections. This is because the target of the cascade is stored in an
// implicit temporary variable, separate from the write-captured variable.
f() {
c = C(null);
}
c
.._field.expectStaticType<Exactly<Object?>>()
.._field!.expectStaticType<Exactly<Object>>()
.._field.expectStaticType<Exactly<Object>>();
// But fields of the write-captured variable itself aren't promoted.
c._field.expectStaticType<Exactly<Object?>>();
}
void writeDefeatsLaterAccessesButNotCascadeTarget(C c) {
// If a write to a variable happens during a cascade, any promotions based on
// that variable are invalidated, but the target of the cascade remains
// promoted, since it's stored in an implicit temporarly variable that's
// unaffected by the write.
c._field as C;
c._field.expectStaticType<Exactly<C>>();
c
.._field.f([c = C(C()), c._field.expectStaticType<Exactly<Object?>>()])
.._field.expectStaticType<Exactly<C>>();
c._field.expectStaticType<Exactly<Object?>>();
}
void cascadedInvocationsPermitted(C c) {
// A promoted field may be invoked inside a cascade.
c._field as int Function();
c._field.expectStaticType<Exactly<int Function()>>();
c.._field().expectStaticType<Exactly<int>>();
}
main() {
cascadedAccessReceivesTheBenefitOfPromotion(C(0));
fieldAccessOnACascadeExpressionRetainsPromotion(C(0));
fieldsPromotableWithinCascade(C(0));
cascadeExpressionIsNotPromotable(0);
ephemeralValueFieldsArePromotable(() => C(0));
writeCapturedValueFieldsArePromotable(C(0));
writeDefeatsLaterAccessesButNotCascadeTarget(C(C()));
int f() => 0;
cascadedInvocationsPermitted(C(f));
}