blob: 83117b9a39765edc2528677331eab662057e3509 [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 distinguishes `this` accesses from `super`
// accesses when they resolve to different fields.
// In this test, the fields in question have generic types. This is an important
// special case to test because the analyzer uses special "Member" data
// structures to track accesses to fields with generic types.
// Since the analyzer has different logic for resolving ordinary variable gets
// and variable gets that look like member invocations, both scenarios are
// tested.
import '../static_type_helper.dart';
class Base<T extends Object> {
final T? _t;
final T? Function() _f;
Base(this._t, this._f);
}
/// In this class, `_t` and `_f` override the declarations of `_t` and `_f` in
/// `super`, so their promotions should be tracked separately.
class DerivedClassThatOverridesBaseMembers<T extends Object> extends Base<T> {
final T? _t;
final T? Function() _f;
DerivedClassThatOverridesBaseMembers(
this._t, this._f, T? superI, T? Function() superF)
: super(superI, superF);
void ordinaryVariableGet() {
_t.expectStaticType<Exactly<T?>>();
this._t.expectStaticType<Exactly<T?>>();
super._t.expectStaticType<Exactly<T?>>();
if (_t != null) {
_t.expectStaticType<Exactly<T>>();
this._t.expectStaticType<Exactly<T>>();
super._t.expectStaticType<Exactly<T?>>();
}
if (this._t != null) {
_t.expectStaticType<Exactly<T>>();
this._t.expectStaticType<Exactly<T>>();
super._t.expectStaticType<Exactly<T?>>();
}
if (super._t != null) {
_t.expectStaticType<Exactly<T?>>();
this._t.expectStaticType<Exactly<T?>>();
super._t.expectStaticType<Exactly<T>>();
}
}
void invokedVariableGet() {
_f().expectStaticType<Exactly<T?>>();
this._f().expectStaticType<Exactly<T?>>();
super._f().expectStaticType<Exactly<T?>>();
if (_f is T Function()) {
_f().expectStaticType<Exactly<T>>();
this._f().expectStaticType<Exactly<T>>();
super._f().expectStaticType<Exactly<T?>>();
}
if (this._f is T Function()) {
_f().expectStaticType<Exactly<T>>();
this._f().expectStaticType<Exactly<T>>();
super._f().expectStaticType<Exactly<T?>>();
}
if (super._f is T Function()) {
_f().expectStaticType<Exactly<T?>>();
this._f().expectStaticType<Exactly<T?>>();
super._f().expectStaticType<Exactly<T>>();
}
}
}
/// In this class, `_i` and `_f` refer to the declarations of `_i` and `_f` in
/// `super`. However, accesses made through `this` still promote independently
/// from accesses made through `super`, since this is simpler to implement, has
/// no soundness problems, and is unlikely to cause problems in real-world code.
class DerivedClassThatOverridesNothing<T extends Object> extends Base<T> {
DerivedClassThatOverridesNothing(super._t, super.f);
void ordinaryVariableGet() {
_t.expectStaticType<Exactly<T?>>();
this._t.expectStaticType<Exactly<T?>>();
super._t.expectStaticType<Exactly<T?>>();
if (_t != null) {
_t.expectStaticType<Exactly<T>>();
this._t.expectStaticType<Exactly<T>>();
super._t.expectStaticType<Exactly<T?>>();
}
if (this._t != null) {
_t.expectStaticType<Exactly<T>>();
this._t.expectStaticType<Exactly<T>>();
super._t.expectStaticType<Exactly<T?>>();
}
if (super._t != null) {
_t.expectStaticType<Exactly<T?>>();
this._t.expectStaticType<Exactly<T?>>();
super._t.expectStaticType<Exactly<T>>();
}
}
void invokedVariableGet() {
_f().expectStaticType<Exactly<T?>>();
this._f().expectStaticType<Exactly<T?>>();
super._f().expectStaticType<Exactly<T?>>();
if (_f is T Function()) {
_f().expectStaticType<Exactly<T>>();
this._f().expectStaticType<Exactly<T>>();
super._f().expectStaticType<Exactly<T?>>();
}
if (this._f is T Function()) {
_f().expectStaticType<Exactly<T>>();
this._f().expectStaticType<Exactly<T>>();
super._f().expectStaticType<Exactly<T?>>();
}
if (super._f is T Function()) {
_f().expectStaticType<Exactly<T?>>();
this._f().expectStaticType<Exactly<T?>>();
super._f().expectStaticType<Exactly<T>>();
}
}
}
main() {
int f() => 0;
int? g() => null;
DerivedClassThatOverridesBaseMembers<int>(0, f, null, g)
..ordinaryVariableGet()
..invokedVariableGet();
DerivedClassThatOverridesBaseMembers<int>(null, g, 0, f)
..ordinaryVariableGet()
..invokedVariableGet();
DerivedClassThatOverridesNothing<int>(0, f)
..ordinaryVariableGet()
..invokedVariableGet();
}