mirror of
https://github.com/dart-lang/sdk
synced 2024-09-16 04:37:12 +00:00
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:
parent
50c5e8f47b
commit
2cdc987724
|
@ -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,
|
||||
|
|
|
@ -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() {}
|
|
@ -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() {}
|
|
@ -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) {}
|
|
@ -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 {}
|
|
@ -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 {}
|
|
@ -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
|
||||
;
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
Loading…
Reference in a new issue