Field promotion: more thorough language tests, plus a CFE bug fix.

Bug: https://github.com/dart-lang/language/issues/2020
Change-Id: I1c604b548f2635b50addc0a97b105da8391b043c
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/269641
Commit-Queue: Paul Berry <paulberry@google.com>
Reviewed-by: Johnni Winther <johnniwinther@google.com>
This commit is contained in:
Paul Berry 2022-11-18 14:54:48 +00:00 committed by Commit Queue
parent 50c5e8f47b
commit 2cdc987724
13 changed files with 761 additions and 3 deletions

View file

@ -2960,6 +2960,7 @@ abstract class InferenceVisitorBase implements InferenceVisitor {
target.isObjectMember ||
target.isNullableInstanceMember);
Field field = target.member as Field;
Expression originalReceiver = receiver;
DartType calleeType = target.getGetterType(this);
FunctionType functionType = getFunctionTypeForImplicitCall(calleeType);
@ -2977,11 +2978,10 @@ abstract class InferenceVisitorBase implements InferenceVisitor {
// We won't report the error until later (after we have an
// invocationResult), but we need to gather "why not promoted" info now,
// before we tell flow analysis about the property get.
whyNotPromoted = flowAnalysis.whyNotPromoted(receiver);
whyNotPromoted = flowAnalysis.whyNotPromoted(originalReceiver);
}
Name originalName = field.name;
Expression originalReceiver = receiver;
Member originalTarget = field;
InstanceAccessKind kind;
switch (target.kind) {
@ -2998,7 +2998,7 @@ abstract class InferenceVisitorBase implements InferenceVisitor {
throw new UnsupportedError('Unexpected target kind $target');
}
InstanceGet originalPropertyGet = new InstanceGet(
kind, originalReceiver, originalName,
kind, receiver, originalName,
resultType: calleeType, interfaceTarget: originalTarget)
..fileOffset = fileOffset;
calleeType = flowAnalysis.propertyGet(originalPropertyGet, originalReceiver,

View file

@ -0,0 +1,31 @@
// 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.
// Tests a corner case of promotion with implicit `.call` hoisting.
class A {
num call(int value) => 0;
}
class B extends A {
int call(num value) => 0;
}
class C {
final A _a;
C(this._a);
}
void test(C c, num n) {
if (c._a is B) {
// Since the call has arguments, it is subject to hoisting by the front end.
// We need to verify that the hoisting process properly passes the original
// receiver (`c._a`) to flow analysis so that the promotion information is
// not lost.
c._a(n);
}
}
main() {}

View file

@ -0,0 +1,15 @@
class A {
num call(int value) => 0;
}
class B extends A {
int call(num value) => 0;
}
class C {
final A _a;
C(this._a);
}
void test(C c, num n) {}
main() {}

View file

@ -0,0 +1,15 @@
class A {
num call(int value) => 0;
}
class B extends A {
int call(num value) => 0;
}
class C {
C(this._a);
final A _a;
}
main() {}
void test(C c, num n) {}

View file

@ -0,0 +1,30 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
class A extends core::Object {
synthetic constructor •() → self::A
: super core::Object::•()
;
method call(core::int value) → core::num
return 0;
}
class B extends self::A {
synthetic constructor •() → self::B
: super self::A::•()
;
method call(core::num value) → core::int
return 0;
}
class C extends core::Object {
final field self::A _a;
constructor •(self::A _a) → self::C
: self::C::_a = _a, super core::Object::•()
;
}
static method test(self::C c, core::num n) → void {
if(c.{self::C::_a}{self::A} is{ForNonNullableByDefault} self::B) {
let final self::C #t1 = c in let final core::num #t2 = n in #t1.{self::C::_a}{self::B}.{self::B::call}(#t2){(core::num) → core::int};
}
}
static method main() → dynamic {}

View file

@ -0,0 +1,30 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
class A extends core::Object {
synthetic constructor •() → self::A
: super core::Object::•()
;
method call(core::int value) → core::num
return 0;
}
class B extends self::A {
synthetic constructor •() → self::B
: super self::A::•()
;
method call(core::num value) → core::int
return 0;
}
class C extends core::Object {
final field self::A _a;
constructor •(self::A _a) → self::C
: self::C::_a = _a, super core::Object::•()
;
}
static method test(self::C c, core::num n) → void {
if(c.{self::C::_a}{self::A} is{ForNonNullableByDefault} self::B) {
let final self::C #t1 = c in let final core::num #t2 = n in #t1.{self::C::_a}{self::B}.{self::B::call}(#t2){(core::num) → core::int};
}
}
static method main() → dynamic {}

View file

@ -0,0 +1,25 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
class A extends core::Object {
synthetic constructor •() → self::A
;
method call(core::int value) → core::num
;
}
class B extends self::A {
synthetic constructor •() → self::B
;
method call(core::num value) → core::int
;
}
class C extends core::Object {
final field self::A _a;
constructor •(self::A _a) → self::C
;
}
static method test(self::C c, core::num n) → void
;
static method main() → dynamic
;

View file

@ -64,6 +64,7 @@ inference/mixin_inference_unification_2: TypeCheckError
inference_new/infer_assign_to_index_super_upwards: TypeCheckError
inference_new/infer_assign_to_index_this_upwards: TypeCheckError
inference_new/infer_assign_to_index_upwards: TypeCheckError
inference_update_2/call_invocation_with_hoisting: TypeCheckError
late_lowering/covariant_late_field: TypeCheckError
nnbd/covariant_late_field: TypeCheckError
nnbd/getter_vs_setter_type: TypeCheckError

View file

@ -206,6 +206,7 @@ inference/override_equals: RuntimeError
inference_new/infer_assign_to_index_super_upwards: TypeCheckError
inference_new/infer_assign_to_index_this_upwards: TypeCheckError
inference_new/infer_assign_to_index_upwards: TypeCheckError
inference_update_2/call_invocation_with_hoisting: TypeCheckError
late_lowering/covariant_late_field: TypeCheckError
nnbd/covariant_late_field: TypeCheckError
nnbd/getter_vs_setter_type: TypeCheckError

View file

@ -0,0 +1,158 @@
// 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.
// Tests that promotion of a field makes it possible to access methods, getters,
// and operators in an extension that doesn't apply to the unpromoted type.
// SharedOptions=--enable-experiment=inference-update-2
import '../static_type_helper.dart';
class A {}
class B extends A {
final int Function(int) field;
B(this.field);
}
extension on B {
int Function(int) get getter => field;
int method(int value) => 0;
int call(int value) => 0;
int operator [](int index) => 0;
operator []=(int index, int value) {}
int operator +(int other) => 0;
}
class C {
final A _a;
C(this._a);
void testThisAccess() {
if (_a is B) {
_a.field.expectStaticType<Exactly<int Function(int)>>();
_a
.field(contextType(0)..expectStaticType<Exactly<int>>())
.expectStaticType<Exactly<int>>();
_a.getter.expectStaticType<Exactly<int Function(int)>>();
_a
.getter(contextType(0)..expectStaticType<Exactly<int>>())
.expectStaticType<Exactly<int>>();
_a.method.expectStaticType<Exactly<int Function(int)>>();
_a
.method(contextType(0)..expectStaticType<Exactly<int>>())
.expectStaticType<Exactly<int>>();
_a(contextType(0)..expectStaticType<Exactly<int>>())
.expectStaticType<Exactly<int>>();
_a[contextType(0)..expectStaticType<Exactly<int>>()]
.expectStaticType<Exactly<int>>();
_a[contextType(0)..expectStaticType<Exactly<int>>()] = contextType(0)
..expectStaticType<Exactly<int>>();
(_a + (contextType(0)..expectStaticType<Exactly<int>>()))
.expectStaticType<Exactly<int>>();
}
}
}
class D extends C {
D(super._a);
void testSuperAccess() {
if (super._a is B) {
super._a.field.expectStaticType<Exactly<int Function(int)>>();
super
._a
.field(contextType(0)..expectStaticType<Exactly<int>>())
.expectStaticType<Exactly<int>>();
super._a.getter.expectStaticType<Exactly<int Function(int)>>();
super
._a
.getter(contextType(0)..expectStaticType<Exactly<int>>())
.expectStaticType<Exactly<int>>();
super._a.method.expectStaticType<Exactly<int Function(int)>>();
super
._a
.method(contextType(0)..expectStaticType<Exactly<int>>())
.expectStaticType<Exactly<int>>();
super
._a(contextType(0)..expectStaticType<Exactly<int>>())
.expectStaticType<Exactly<int>>();
super
._a[contextType(0)..expectStaticType<Exactly<int>>()]
.expectStaticType<Exactly<int>>();
super._a[contextType(0)..expectStaticType<Exactly<int>>()] =
contextType(0)..expectStaticType<Exactly<int>>();
(super._a + (contextType(0)..expectStaticType<Exactly<int>>()))
.expectStaticType<Exactly<int>>();
}
}
}
void testPrefixedIdentifier(C c) {
if (c._a is B) {
c._a.field.expectStaticType<Exactly<int Function(int)>>();
c._a
.field(contextType(0)..expectStaticType<Exactly<int>>())
.expectStaticType<Exactly<int>>();
c._a.getter.expectStaticType<Exactly<int Function(int)>>();
c._a
.getter(contextType(0)..expectStaticType<Exactly<int>>())
.expectStaticType<Exactly<int>>();
c._a.method.expectStaticType<Exactly<int Function(int)>>();
c._a
.method(contextType(0)..expectStaticType<Exactly<int>>())
.expectStaticType<Exactly<int>>();
c
._a(contextType(0)..expectStaticType<Exactly<int>>())
.expectStaticType<Exactly<int>>();
c._a[contextType(0)..expectStaticType<Exactly<int>>()]
.expectStaticType<Exactly<int>>();
c._a[contextType(0)..expectStaticType<Exactly<int>>()] = contextType(0)
..expectStaticType<Exactly<int>>();
(c._a + (contextType(0)..expectStaticType<Exactly<int>>()))
.expectStaticType<Exactly<int>>();
}
}
void testGeneralPropertyAccess(C c) {
// The analyzer uses a special data structure for `IDENTIFIER.IDENTIFIER`, so
// we need to test the general case of property accesses as well.
if ((c)._a is B) {
(c)._a.field.expectStaticType<Exactly<int Function(int)>>();
(c)
._a
.field(contextType(0)..expectStaticType<Exactly<int>>())
.expectStaticType<Exactly<int>>();
(c)._a.getter.expectStaticType<Exactly<int Function(int)>>();
(c)
._a
.getter(contextType(0)..expectStaticType<Exactly<int>>())
.expectStaticType<Exactly<int>>();
(c)._a.method.expectStaticType<Exactly<int Function(int)>>();
(c)
._a
.method(contextType(0)..expectStaticType<Exactly<int>>())
.expectStaticType<Exactly<int>>();
(c)
._a(contextType(0)..expectStaticType<Exactly<int>>())
.expectStaticType<Exactly<int>>();
(c)
._a[contextType(0)..expectStaticType<Exactly<int>>()]
.expectStaticType<Exactly<int>>();
(c)._a[contextType(0)..expectStaticType<Exactly<int>>()] = contextType(0)
..expectStaticType<Exactly<int>>();
((c)._a + (contextType(0)..expectStaticType<Exactly<int>>()))
.expectStaticType<Exactly<int>>();
}
}
main() {
var d = D(B((_) => 0));
d.testThisAccess();
d.testSuperAccess();
testPrefixedIdentifier(d);
testGeneralPropertyAccess(d);
}

View file

@ -0,0 +1,156 @@
// 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.
// Tests that promotion of a field makes it possible to access methods, getters,
// and operators in an extension that doesn't apply to the unpromoted type.
// SharedOptions=--enable-experiment=inference-update-2
import '../static_type_helper.dart';
class A {
final int Function(int) field;
A(this.field);
}
extension on A {
int Function(int) get getter => field;
int method(int value) => 0;
int call(int value) => 0;
int operator [](int index) => 0;
operator []=(int index, int value) {}
int operator +(int other) => 0;
}
class C {
final A? _a;
C(this._a);
void testThisAccess() {
if (_a != null) {
_a.field.expectStaticType<Exactly<int Function(int)>>();
_a
.field(contextType(0)..expectStaticType<Exactly<int>>())
.expectStaticType<Exactly<int>>();
_a.getter.expectStaticType<Exactly<int Function(int)>>();
_a
.getter(contextType(0)..expectStaticType<Exactly<int>>())
.expectStaticType<Exactly<int>>();
_a.method.expectStaticType<Exactly<int Function(int)>>();
_a
.method(contextType(0)..expectStaticType<Exactly<int>>())
.expectStaticType<Exactly<int>>();
_a(contextType(0)..expectStaticType<Exactly<int>>())
.expectStaticType<Exactly<int>>();
_a[contextType(0)..expectStaticType<Exactly<int>>()]
.expectStaticType<Exactly<int>>();
_a[contextType(0)..expectStaticType<Exactly<int>>()] = contextType(0)
..expectStaticType<Exactly<int>>();
(_a + (contextType(0)..expectStaticType<Exactly<int>>()))
.expectStaticType<Exactly<int>>();
}
}
}
class D extends C {
D(super._a);
void testSuperAccess() {
if (super._a != null) {
super._a.field.expectStaticType<Exactly<int Function(int)>>();
super
._a
.field(contextType(0)..expectStaticType<Exactly<int>>())
.expectStaticType<Exactly<int>>();
super._a.getter.expectStaticType<Exactly<int Function(int)>>();
super
._a
.getter(contextType(0)..expectStaticType<Exactly<int>>())
.expectStaticType<Exactly<int>>();
super._a.method.expectStaticType<Exactly<int Function(int)>>();
super
._a
.method(contextType(0)..expectStaticType<Exactly<int>>())
.expectStaticType<Exactly<int>>();
super
._a(contextType(0)..expectStaticType<Exactly<int>>())
.expectStaticType<Exactly<int>>();
super
._a[contextType(0)..expectStaticType<Exactly<int>>()]
.expectStaticType<Exactly<int>>();
super._a[contextType(0)..expectStaticType<Exactly<int>>()] =
contextType(0)..expectStaticType<Exactly<int>>();
(super._a + (contextType(0)..expectStaticType<Exactly<int>>()))
.expectStaticType<Exactly<int>>();
}
}
}
void testPrefixedIdentifier(C c) {
if (c._a != null) {
c._a.field.expectStaticType<Exactly<int Function(int)>>();
c._a
.field(contextType(0)..expectStaticType<Exactly<int>>())
.expectStaticType<Exactly<int>>();
c._a.getter.expectStaticType<Exactly<int Function(int)>>();
c._a
.getter(contextType(0)..expectStaticType<Exactly<int>>())
.expectStaticType<Exactly<int>>();
c._a.method.expectStaticType<Exactly<int Function(int)>>();
c._a
.method(contextType(0)..expectStaticType<Exactly<int>>())
.expectStaticType<Exactly<int>>();
c
._a(contextType(0)..expectStaticType<Exactly<int>>())
.expectStaticType<Exactly<int>>();
c._a[contextType(0)..expectStaticType<Exactly<int>>()]
.expectStaticType<Exactly<int>>();
c._a[contextType(0)..expectStaticType<Exactly<int>>()] = contextType(0)
..expectStaticType<Exactly<int>>();
(c._a + (contextType(0)..expectStaticType<Exactly<int>>()))
.expectStaticType<Exactly<int>>();
}
}
void testGeneralPropertyAccess(C c) {
// The analyzer uses a special data structure for `IDENTIFIER.IDENTIFIER`, so
// we need to test the general case of property accesses as well.
if ((c)._a != null) {
(c)._a.field.expectStaticType<Exactly<int Function(int)>>();
(c)
._a
.field(contextType(0)..expectStaticType<Exactly<int>>())
.expectStaticType<Exactly<int>>();
(c)._a.getter.expectStaticType<Exactly<int Function(int)>>();
(c)
._a
.getter(contextType(0)..expectStaticType<Exactly<int>>())
.expectStaticType<Exactly<int>>();
(c)._a.method.expectStaticType<Exactly<int Function(int)>>();
(c)
._a
.method(contextType(0)..expectStaticType<Exactly<int>>())
.expectStaticType<Exactly<int>>();
(c)
._a(contextType(0)..expectStaticType<Exactly<int>>())
.expectStaticType<Exactly<int>>();
(c)
._a[contextType(0)..expectStaticType<Exactly<int>>()]
.expectStaticType<Exactly<int>>();
(c)._a[contextType(0)..expectStaticType<Exactly<int>>()] = contextType(0)
..expectStaticType<Exactly<int>>();
((c)._a + (contextType(0)..expectStaticType<Exactly<int>>()))
.expectStaticType<Exactly<int>>();
}
}
main() {
var d = D(A((_) => 0));
d.testThisAccess();
d.testSuperAccess();
testPrefixedIdentifier(d);
testGeneralPropertyAccess(d);
}

View file

@ -0,0 +1,155 @@
// 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.
// Tests that promotion of a field makes it possible to access methods, getters,
// and operators that aren't exposed from the unpromoted type.
// SharedOptions=--enable-experiment=inference-update-2
import '../static_type_helper.dart';
class A {}
class B extends A {
final int Function(int) field;
int Function(int) get getter => field;
int method(int value) => 0;
int call(int value) => 0;
int operator [](int index) => 0;
operator []=(int index, int value) {}
int operator +(int other) => 0;
B(this.field);
}
class C {
final A _a;
C(this._a);
void testThisAccess() {
if (_a is B) {
_a.field.expectStaticType<Exactly<int Function(int)>>();
_a
.field(contextType(0)..expectStaticType<Exactly<int>>())
.expectStaticType<Exactly<int>>();
_a.getter.expectStaticType<Exactly<int Function(int)>>();
_a
.getter(contextType(0)..expectStaticType<Exactly<int>>())
.expectStaticType<Exactly<int>>();
_a.method.expectStaticType<Exactly<int Function(int)>>();
_a
.method(contextType(0)..expectStaticType<Exactly<int>>())
.expectStaticType<Exactly<int>>();
_a(contextType(0)..expectStaticType<Exactly<int>>())
.expectStaticType<Exactly<int>>();
_a[contextType(0)..expectStaticType<Exactly<int>>()]
.expectStaticType<Exactly<int>>();
_a[contextType(0)..expectStaticType<Exactly<int>>()] = contextType(0)
..expectStaticType<Exactly<int>>();
(_a + (contextType(0)..expectStaticType<Exactly<int>>()))
.expectStaticType<Exactly<int>>();
}
}
}
class D extends C {
D(super._a);
void testSuperAccess() {
if (super._a is B) {
super._a.field.expectStaticType<Exactly<int Function(int)>>();
super
._a
.field(contextType(0)..expectStaticType<Exactly<int>>())
.expectStaticType<Exactly<int>>();
super._a.getter.expectStaticType<Exactly<int Function(int)>>();
super
._a
.getter(contextType(0)..expectStaticType<Exactly<int>>())
.expectStaticType<Exactly<int>>();
super._a.method.expectStaticType<Exactly<int Function(int)>>();
super
._a
.method(contextType(0)..expectStaticType<Exactly<int>>())
.expectStaticType<Exactly<int>>();
super
._a(contextType(0)..expectStaticType<Exactly<int>>())
.expectStaticType<Exactly<int>>();
super
._a[contextType(0)..expectStaticType<Exactly<int>>()]
.expectStaticType<Exactly<int>>();
super._a[contextType(0)..expectStaticType<Exactly<int>>()] =
contextType(0)..expectStaticType<Exactly<int>>();
(super._a + (contextType(0)..expectStaticType<Exactly<int>>()))
.expectStaticType<Exactly<int>>();
}
}
}
void testPrefixedIdentifier(C c) {
if (c._a is B) {
c._a.field.expectStaticType<Exactly<int Function(int)>>();
c._a
.field(contextType(0)..expectStaticType<Exactly<int>>())
.expectStaticType<Exactly<int>>();
c._a.getter.expectStaticType<Exactly<int Function(int)>>();
c._a
.getter(contextType(0)..expectStaticType<Exactly<int>>())
.expectStaticType<Exactly<int>>();
c._a.method.expectStaticType<Exactly<int Function(int)>>();
c._a
.method(contextType(0)..expectStaticType<Exactly<int>>())
.expectStaticType<Exactly<int>>();
c
._a(contextType(0)..expectStaticType<Exactly<int>>())
.expectStaticType<Exactly<int>>();
c._a[contextType(0)..expectStaticType<Exactly<int>>()]
.expectStaticType<Exactly<int>>();
c._a[contextType(0)..expectStaticType<Exactly<int>>()] = contextType(0)
..expectStaticType<Exactly<int>>();
(c._a + (contextType(0)..expectStaticType<Exactly<int>>()))
.expectStaticType<Exactly<int>>();
}
}
void testGeneralPropertyAccess(C c) {
// The analyzer uses a special data structure for `IDENTIFIER.IDENTIFIER`, so
// we need to test the general case of property accesses as well.
if ((c)._a is B) {
(c)._a.field.expectStaticType<Exactly<int Function(int)>>();
(c)
._a
.field(contextType(0)..expectStaticType<Exactly<int>>())
.expectStaticType<Exactly<int>>();
(c)._a.getter.expectStaticType<Exactly<int Function(int)>>();
(c)
._a
.getter(contextType(0)..expectStaticType<Exactly<int>>())
.expectStaticType<Exactly<int>>();
(c)._a.method.expectStaticType<Exactly<int Function(int)>>();
(c)
._a
.method(contextType(0)..expectStaticType<Exactly<int>>())
.expectStaticType<Exactly<int>>();
(c)
._a(contextType(0)..expectStaticType<Exactly<int>>())
.expectStaticType<Exactly<int>>();
(c)
._a[contextType(0)..expectStaticType<Exactly<int>>()]
.expectStaticType<Exactly<int>>();
(c)._a[contextType(0)..expectStaticType<Exactly<int>>()] = contextType(0)
..expectStaticType<Exactly<int>>();
((c)._a + (contextType(0)..expectStaticType<Exactly<int>>()))
.expectStaticType<Exactly<int>>();
}
}
main() {
var d = D(B((_) => 0));
d.testThisAccess();
d.testSuperAccess();
testPrefixedIdentifier(d);
testGeneralPropertyAccess(d);
}

View file

@ -0,0 +1,141 @@
// 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.
// Tests that promotion of a field narrows the types of methods, getters,
// and operators that are also exposed from the unpromoted type.
// SharedOptions=--enable-experiment=inference-update-2
import '../static_type_helper.dart';
class A {
Object get getter => 0;
num method(int value) => 0;
num call(int value) => 0;
num operator [](int index) => 0;
operator []=(int index, int value) {}
num operator +(int other) => 0;
}
class B extends A {
int Function(num) get getter => (_) => 0;
int method(num value) => 0;
int call(num value) => 0;
int operator [](num index) => 0;
operator []=(num index, num value) {}
int operator +(num other) => 0;
}
class C {
final A _a;
C(this._a);
void testThisAccess() {
if (_a is B) {
_a.getter.expectStaticType<Exactly<int Function(num)>>();
_a
.getter(contextType(0)..expectStaticType<Exactly<num>>())
.expectStaticType<Exactly<int>>();
_a.method.expectStaticType<Exactly<int Function(num)>>();
_a
.method(contextType(0)..expectStaticType<Exactly<num>>())
.expectStaticType<Exactly<int>>();
_a(contextType(0)..expectStaticType<Exactly<num>>())
.expectStaticType<Exactly<int>>();
_a[contextType(0)..expectStaticType<Exactly<num>>()]
.expectStaticType<Exactly<int>>();
_a[contextType(0)..expectStaticType<Exactly<num>>()] = contextType(0)
..expectStaticType<Exactly<num>>();
(_a + (contextType(0)..expectStaticType<Exactly<num>>()))
.expectStaticType<Exactly<int>>();
}
}
}
class D extends C {
D(super._a);
void testSuperAccess() {
if (super._a is B) {
super._a.getter.expectStaticType<Exactly<int Function(num)>>();
super
._a
.getter(contextType(0)..expectStaticType<Exactly<num>>())
.expectStaticType<Exactly<int>>();
super._a.method.expectStaticType<Exactly<int Function(num)>>();
super
._a
.method(contextType(0)..expectStaticType<Exactly<num>>())
.expectStaticType<Exactly<int>>();
super
._a(contextType(0)..expectStaticType<Exactly<num>>())
.expectStaticType<Exactly<int>>();
super
._a[contextType(0)..expectStaticType<Exactly<num>>()]
.expectStaticType<Exactly<int>>();
super._a[contextType(0)..expectStaticType<Exactly<num>>()] =
contextType(0)..expectStaticType<Exactly<num>>();
(super._a + (contextType(0)..expectStaticType<Exactly<num>>()))
.expectStaticType<Exactly<int>>();
}
}
}
void testPrefixedIdentifier(C c) {
if (c._a is B) {
c._a.getter.expectStaticType<Exactly<int Function(num)>>();
c._a
.getter(contextType(0)..expectStaticType<Exactly<num>>())
.expectStaticType<Exactly<int>>();
c._a.method.expectStaticType<Exactly<int Function(num)>>();
c._a
.method(contextType(0)..expectStaticType<Exactly<num>>())
.expectStaticType<Exactly<int>>();
c
._a(contextType(0)..expectStaticType<Exactly<num>>())
.expectStaticType<Exactly<int>>();
c._a[contextType(0)..expectStaticType<Exactly<num>>()]
.expectStaticType<Exactly<int>>();
c._a[contextType(0)..expectStaticType<Exactly<num>>()] = contextType(0)
..expectStaticType<Exactly<num>>();
(c._a + (contextType(0)..expectStaticType<Exactly<num>>()))
.expectStaticType<Exactly<int>>();
}
}
void testGeneralPropertyAccess(C c) {
// The analyzer uses a special data structure for `IDENTIFIER.IDENTIFIER`, so
// we need to test the general case of property accesses as well.
if ((c)._a is B) {
(c)._a.getter.expectStaticType<Exactly<int Function(num)>>();
(c)
._a
.getter(contextType(0)..expectStaticType<Exactly<num>>())
.expectStaticType<Exactly<int>>();
(c)._a.method.expectStaticType<Exactly<int Function(num)>>();
(c)
._a
.method(contextType(0)..expectStaticType<Exactly<num>>())
.expectStaticType<Exactly<int>>();
(c)
._a(contextType(0)..expectStaticType<Exactly<num>>())
.expectStaticType<Exactly<int>>();
(c)
._a[contextType(0)..expectStaticType<Exactly<num>>()]
.expectStaticType<Exactly<int>>();
(c)._a[contextType(0)..expectStaticType<Exactly<num>>()] = contextType(0)
..expectStaticType<Exactly<num>>();
((c)._a + (contextType(0)..expectStaticType<Exactly<num>>()))
.expectStaticType<Exactly<int>>();
}
}
main() {
var d = D(B());
d.testThisAccess();
d.testSuperAccess();
testPrefixedIdentifier(d);
testGeneralPropertyAccess(d);
}