blob: 4190fcd5b059caab89268948a1b683a42b183450 [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.
// Test that the type arguments of object patterns are properly inferred.
import "package:expect/expect.dart";
import "../static_type_helper.dart";
sealed class B<T> {}
class C<T> extends B<T> {
final T t;
// Note: we use this getter to obtain values for `expectStaticType` (rather
// than a getter returning simply `T`) to ensure that an error is reported if
// `T` gets inferred to be `dynamic`.
List<T> get listOfT => [t];
C(this.t);
}
bool explicitTypeArguments(B<int> b) {
switch (b) {
case C<num>(listOfT: var x):
x.expectStaticType<Exactly<List<num>>>();
// Since C<num> isn't a subtype of B<int>, `b` is not promoted.
b.expectStaticType<Exactly<B<int>>>();
return true;
}
// No need for a `return` since the switch is exhaustive.
}
bool simpleInference(B<num> b) {
switch (b) {
case C(listOfT: var x):
x.expectStaticType<Exactly<List<num>>>();
b.expectStaticType<Exactly<C<num>>>();
return true;
}
// No need for a `return` since the switch is exhaustive.
}
bool inferDynamic(Object o) {
switch (o) {
case C(listOfT: var x, t: var t):
x.expectStaticType<Exactly<List<dynamic>>>();
t.isEven; // Should be ok since T is `dynamic`.
o.expectStaticType<Exactly<C<dynamic>>>();
return true;
default:
return false;
}
}
class D<T extends num> {
final T t;
// Note: we use this getter to obtain values for `expectStaticType` (rather
// than a getter returning simply `T`) to ensure that an error is reported if
// `T` gets inferred to be `dynamic`.
List<T> get listOfT => [t];
D(this.t);
}
bool inferBound(Object o) {
switch (o) {
case D(listOfT: var x):
x.expectStaticType<Exactly<List<num>>>();
o.expectStaticType<Exactly<D<num>>>();
return true;
default:
return false;
}
}
class E<T, U> {
final T t;
final U u;
List<T> get listOfT => [t];
List<U> get listOfU => [u];
E(this.t, this.u);
bool inferEnclosingTypeParameters(E<Set<U>, Set<T>> e) {
// This test verifies that the inference logic properly distinguishes
// between the type parameters of the enclosing class and those that are
// part of the type of `e`.
if (e case E(listOfT: var x, listOfU: var y)) {
x.expectStaticType<Exactly<List<Set<U>>>>();
y.expectStaticType<Exactly<List<Set<T>>>>();
return true;
}
// No need for a `return` since the case fully covers the type of `e`.
}
}
class F1<T extends F1<T>> {
late final T t;
List<T> get listOfT => [t];
}
class F2 extends F1<F2> {
F2() {
t = this;
}
}
bool fBounded(Object o) {
switch (o) {
case F1(listOfT: var x):
x.expectStaticType<Exactly<List<F1<Object?>>>>();
o.expectStaticType<Exactly<F1<F1<Object?>>>>();
return true;
default:
return false;
}
}
class G1<T> {
final T t;
List<T> get listOfT => [t];
G1(this.t);
}
class G2<T, U extends Set<T>> extends G1<T> {
final U u;
List<U> get listOfU => [u];
G2(super.t, this.u);
}
bool partialInference(G1<int> g) {
switch (g) {
case G2(listOfT: var x, listOfU: var y):
x.expectStaticType<Exactly<List<int>>>();
y.expectStaticType<Exactly<List<Set<int>>>>();
g.expectStaticType<Exactly<G2<int, Set<int>>>>();
return true;
default:
return false;
}
}
class H1<T, U> {
final T t;
final U u;
List<T> get listOfT => [t];
List<U> get listOfU => [u];
H1(this.t, this.u);
}
typedef H2<S extends num> = H1<S, String>;
bool typedefResolvingToInterfaceType(Object o) {
switch (o) {
case H2(listOfT: var x, listOfU: var y):
x.expectStaticType<Exactly<List<num>>>();
y.expectStaticType<Exactly<List<String>>>();
o.expectStaticType<Exactly<H2<num>>>();
return true;
default:
return false;
}
}
typedef I<S extends num> = String Function(S);
bool typedefResolvingToFunctionType(Object o) {
switch (o) {
case I():
o.expectStaticType<Exactly<I<num>>>();
return true;
default:
return false;
}
}
main() {
Expect.isTrue(explicitTypeArguments(C(0)));
Expect.isTrue(simpleInference(C(0)));
Expect.isTrue(inferDynamic(C(0)));
Expect.isFalse(inferDynamic(0));
Expect.isTrue(inferBound(D(0)));
Expect.isFalse(inferBound(0));
Expect.isTrue(E<int, String>(0, '')
.inferEnclosingTypeParameters(E<Set<String>, Set<int>>({''}, {0})));
Expect.isTrue(fBounded(F2()));
Expect.isFalse(fBounded(0));
Expect.isTrue(partialInference(G2(0, {0})));
Expect.isFalse(partialInference(G1(0)));
Expect.isTrue(typedefResolvingToInterfaceType(H1<int, String>(0, '')));
Expect.isTrue(typedefResolvingToInterfaceType(H1<num, String>(0, '')));
Expect.isFalse(typedefResolvingToInterfaceType(H1<Object, String>(0, '')));
Expect.isTrue(typedefResolvingToFunctionType((Object o) => o.toString()));
Expect.isTrue(typedefResolvingToFunctionType((num n) => n.toString()));
Expect.isFalse(typedefResolvingToFunctionType((int i) => i.toString()));
}