blob: e7eeb50e00103275128eeda1c40b6e5d30c3b9a0 [file] [log] [blame]
// Copyright (c) 2018, 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.
import "package:expect/expect.dart";
class I<X> {}
class C0<T> extends I<T> {}
class C1<T> implements I<T> {}
mixin M0<T> on I<T> {
}
mixin M1<T> on I<T> {
T Function(T) get value => null;
}
mixin M2<T> implements I<T> {}
mixin M3<T> on I<T> {}
class J<X> {}
class C2 extends C1<int> implements J<double> {}
class C3 extends J<double> {}
mixin M4<S, T> on I<S>, J<T> {
S Function(S) get value0 => null;
T Function(T) get value1 => null;
}
///////////////////////////////////////////////////////
// Inference of a single mixin from a super class works
///////////////////////////////////////////////////////
// M1 is inferred as M1<int>
class A00 extends I<int> with M1 {
void check() {
// Verify that M1.T is exactly int
int Function(int) f = this.value;
}
}
// M1 is inferred as M1<int>
class A01 extends C0<int> with M1 {
void check() {
// Verify that M1.T is exactly int
int Function(int) f = this.value;
}
}
// M1 is inferred as M1<int>
class A02 extends C1<int> with M1 {
void check() {
// Verify that M1.T is exactly int
int Function(int) f = this.value;
}
}
///////////////////////////////////////////////////////
// Inference of a single mixin from another mixin works
///////////////////////////////////////////////////////
// M1 is inferred as M1<int>
class B00 extends Object with I<int>, M1 {
void check() {
// Verify that M1.T is exactly int
int Function(int) f = this.value;
}
}
// M1 is inferred as M1<int>
class B01 extends Object with C1<int>, M1 {
void check() {
// Verify that M1.T is exactly int
int Function(int) f = this.value;
}
}
// M1 is inferred as M1<int>
class B02 extends I<int> with M0<int>, M1 {
void check() {
// Verify that M1.T is exactly int
int Function(int) f = this.value;
}
}
// M1 is inferred as M1<int>
class B03 extends Object with M2<int>, M1 {
void check() {
// Verify that M1.T is exactly int
int Function(int) f = this.value;
}
}
///////////////////////////////////////////////////////
// Inference of a single mixin from another mixin works
// with the shorthand syntax
///////////////////////////////////////////////////////
// M1 is inferred as M1<int>
class C00 with I<int>, M1 {
void check() {
// Verify that M1.T is exactly int
int Function(int) f = this.value;
}
}
// M1 is inferred as M1<int>
class C01 with C1<int>, M1 {
void check() {
// Verify that M1.T is exactly int
int Function(int) f = this.value;
}
}
// M1 is inferred as M1<int>
class C02 with I<int>, M0<int>, M1 {
void check() {
// Verify that M1.T is exactly int
int Function(int) f = this.value;
}
}
// M1 is inferred as M1<int>
class C03 with M2<int>, M1 {
void check() {
// Verify that M1.T is exactly int
int Function(int) f = this.value;
}
}
///////////////////////////////////////////////////////
// Inference of two mixins from a super class works
///////////////////////////////////////////////////////
// M1 is inferred as M1<int>
class A10 extends I<int> with M3, M1 {
void check() {
// Verify that M1.T is exactly int
int Function(int) f = this.value;
}
}
// M1 is inferred as M1<int>
class A11 extends C0<int> with M3, M1 {
void check() {
// Verify that M1.T is exactly int
int Function(int) f = this.value;
}
}
// M1 is inferred as M1<int>
class A12 extends C1<int> with M3, M1 {
void check() {
// Verify that M1.T is exactly int
int Function(int) f = this.value;
}
}
///////////////////////////////////////////////////////
// Inference of two mixins from another mixin works
///////////////////////////////////////////////////////
// M1 is inferred as M1<int>
class B10 extends Object with I<int>, M3, M1 {
void check() {
// Verify that M1.T is exactly int
int Function(int) f = this.value;
}
}
// M1 is inferred as M1<int>
class B11 extends Object with C1<int>, M3, M1 {
void check() {
// Verify that M1.T is exactly int
int Function(int) f = this.value;
}
}
// M1 is inferred as M1<int>
class B12 extends I<int> with M0<int>, M3, M1 {
void check() {
// Verify that M1.T is exactly int
int Function(int) f = this.value;
}
}
// M1 is inferred as M1<int>
class B13 extends Object with M2<int>, M3, M1 {
void check() {
// Verify that M1.T is exactly int
int Function(int) f = this.value;
}
}
///////////////////////////////////////////////////////
// Inference of a single mixin from another mixin works
// with the shorthand syntax
///////////////////////////////////////////////////////
// M1 is inferred as M1<int>
class C10 with I<int>, M3, M1 {
void check() {
// Verify that M1.T is exactly int
int Function(int) f = this.value;
}
}
// M1 is inferred as M1<int>
class C11 with C1<int>, M3, M1 {
void check() {
// Verify that M1.T is exactly int
int Function(int) f = this.value;
}
}
// M1 is inferred as M1<int>
class C12 with I<int>, M0<int>, M3, M1 {
void check() {
// Verify that M1.T is exactly int
int Function(int) f = this.value;
}
}
// M1 is inferred as M1<int>
class C13 with M2<int>, M3, M1 {
void check() {
// Verify that M1.T is exactly int
int Function(int) f = this.value;
}
}
///////////////////////////////////////////////////////
// Inference from multiple constraints works
///////////////////////////////////////////////////////
// M4 is inferred as M4<int, double>
class A20 extends C2 with M4 {
void check() {
// Verify that M4.S is exactly int
int Function(int) f0 = this.value0;
// Verify that M4.T is exactly double
double Function(double) f1 = this.value1;
}
}
// M4 is inferred as M4<int, double>
class A21 extends C3 with M2<int>, M4 {
void check() {
// Verify that M4.S is exactly int
int Function(int) f0 = this.value0;
// Verify that M4.T is exactly double
double Function(double) f1 = this.value0;
}
}
// M4 is inferred as M4<int, double>
class A22 extends C2 with M1, M4 {
void check() {
// Verify that M1.T is exactly int
int Function(int) f = this.value;
// Verify that M4.S is exactly int
int Function(int) f0 = this.value0;
// Verify that M4.T is exactly double
double Function(double) f1 = this.value1;
}
}
mixin _M5<T> on I<T> implements J<T> {}
// Inference here puts J<int> in the superclass hierarchy
class _A23 extends C0<int> with _M5 {}
// Inference here should get J<int> for M4.T
// if inference for _M5 is done first (correctly)
// and otherwise J<dynamic>
class A23 extends _A23 with M4 {
void check() {
// Verify that M4.S is exactly int
int Function(int) f0 = this.value0;
// Verify that M4.T is exactly int
int Function(int) f1 = this.value1;
}
}
///////////////////////////////////////////////////////
// Unconstrained parameters go to bounds
///////////////////////////////////////////////////////
mixin M5<S, T extends String> on I<S> {
S Function(S) get value0 => null;
T Function(T) get value1 => null;
}
mixin M6<S, T extends S> on I<S> {
S Function(S) get value0 => null;
T Function(T) get value1 => null;
}
// M5 is inferred as M5<int, String>
class A30 extends C0<int> with M5 {
void check() {
// Verify that M5.S is exactly int
int Function(int) f0 = this.value0;
// Verify that M5.T is exactly String
String Function(String) f1 = this.value1;
}
}
// M6 is inferred as M6<int, int>
class A31 extends C0<int> with M6 {
void check() {
// Verify that M6.S is exactly int
int Function(int) f0 = this.value0;
// Verify that M6.T is exactly int
int Function(int) f1 = this.value1;
}
}
///////////////////////////////////////////////////////
// Non-trivial constraints should work
///////////////////////////////////////////////////////
mixin M7<T> on I<List<T>> {
T Function(T) get value0 => null;
}
mixin M8<T> on I<Iterable<T>> {
T Function(T) get value0 => null;
}
class A40<T> extends I<List<T>> {}
class A41<T> extends A40<Map<T, T>> {}
// M7 is inferred as M7<Map<int, int>>
class A42 extends A41<int> with M7 {
void check() {
// Verify that M7.T is exactly Map<int, int>
Map<int, int> Function(Map<int, int>) f1 = this.value0;
}
}
// M8 is inferred as M8<Map<int, int>>
class A43 extends A41<int> with M8 {
void check() {
// Verify that M8.T is exactly Map<int, int>
Map<int, int> Function(Map<int, int>) f1 = this.value0;
}
}
void main() {
Expect.type<M1<int>>(new A00()..check());
Expect.type<M1<int>>(new A01()..check());
Expect.type<M1<int>>(new A02()..check());
Expect.type<M1<int>>(new B00()..check());
Expect.type<M1<int>>(new B01()..check());
Expect.type<M1<int>>(new B02()..check());
Expect.type<M1<int>>(new B03()..check());
Expect.type<M1<int>>(new C00()..check());
Expect.type<M1<int>>(new C01()..check());
Expect.type<M1<int>>(new C02()..check());
Expect.type<M1<int>>(new C03()..check());
Expect.type<M1<int>>(new A10()..check());
Expect.type<M1<int>>(new A11()..check());
Expect.type<M1<int>>(new A12()..check());
Expect.type<M1<int>>(new B10()..check());
Expect.type<M1<int>>(new B11()..check());
Expect.type<M1<int>>(new B12()..check());
Expect.type<M1<int>>(new B13()..check());
Expect.type<M1<int>>(new C10()..check());
Expect.type<M1<int>>(new C11()..check());
Expect.type<M1<int>>(new C12()..check());
Expect.type<M1<int>>(new C13()..check());
Expect.type<M4<int, double>>(new A20()..check());
Expect.type<M4<int, double>>(new A21()..check());
Expect.type<M4<int, double>>(new A22()..check());
Expect.type<M1<int>>(new A22()..check());
Expect.type<M4<int, int>>(new A23()..check());
Expect.type<M5<int, String>>(new A30()..check());
Expect.type<M6<int, int>>(new A31()..check());
Expect.type<M7<Map<int, int>>>(new A42()..check());
Expect.type<M8<Map<int, int>>>(new A43()..check());
}