blob: 7de1b69419c6bbebd01114d0a68e78ad084aae43 [file] [log] [blame]
// Copyright (c) 2021, 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 error detection where an inherited method has a parameter `p0`
// that corresponds to a parameter `p1` in the interface, where `p1` is
// covariant-by-class and -by-declaration where needed, but `p0` is not.
//
// The library contains groups of classes depending on each other, and there
// is no connection between the groups. Each group has a number (0 .. 17)
// which is used at the end of most names in the group. For example, the first
// group consists of the classes `B0`, `C0`, `DD0`, and `D0`. The group number
// is shown as `#` in the remainder of this comment.
//
// In every group, the classes `C#` and `D#` are concrete leaf classes
// exhibiting the situation of interest, that is, an inherited implementation
// of the method `m` as well as a signature for `m` in the interface of the
// class, with a parameter that has the above-mentioned properties.
//
// The parameter type in the implementation and the parameter type in the
// method signature is (`num`, `num`), (`int`, `num`) and (`num`, `int`),
// respectively, such that we test a covariant, contravariant and invariant
// parameter type relationship in the overrides.
//
// In every group, the class `B#` contains the implementation of the method
// `m` which is inherited. Class `A#` and mixin `M#`, present in some groups,
// are used to provide the method implementation to `B#` using a mixin
// application.
//
// The classes `BB#`, `I#`, `DD#`, `J#`, and `JJ#` are helper classes for `C#`
// and `#D`.
//
// Class `BB#` is a subclass of `B#` and a superclass of `C#` and `D#`; it
// introduces the method signature of `m` into the superclass chain.
//
// Class `DD#` is implemented by `D#`. Classes `I#`, `J#`, and `JJ#` are
// implemented by `C#` or `D#`. Class `DD#` and `JJ#` ensure that `m` can be
// called with an argument of type `Object`. Class `I#` and `J#` introduce the
// method signature to `C#` or `D#` via an `implements` relation.
//
// Finally, `main` contains test cases where the dynamic type check is
// incurred, using variable types and arguments that make the type check
// fail whenever possible.
//
// The comments below about 'Superclass' and 'interface' indicate the way in
// which the superclass of `C#` and `D#` is structured (it can be a regular
// class or a mixin), and the way in which the superinterface that provides
// the method signature is structured (it can be declared in `C#` or `D#`,
// "immediate", or it can be obtained via an `extends` relation or via an
// `implements` relation).
import 'package:expect/expect.dart';
// Superclass: regular, interface: immediate.
class B0 {
void m(num x) {}
}
abstract class CC0<X extends num> extends B0 {
void m(covariant X x);
}
class C0 extends CC0<num> {}
abstract class DD0<X> {
void m(X x);
}
class D0 extends B0 implements DD0<num> {
void m(num x);
}
// Following the pattern, the classes `B1` .. `D1` are as shown below. They
// are commented out, because the declaration `CC1.m` is an error, because
// its parameter has a type which is neither a subtype nor a supertype of
// the parameter type in `B1.m`. It is not useful to change the bound of `X`
// in `CC1` to `int`, because that yields a set of classes with exactly the
// same properties as those of `B0` .. `D0` (just change `num` to `int`
// everywhere).
//
// class B1 {
// void m(int x) {}
// }
//
// abstract class CC1<X extends num> extends B1 {
// void m(covariant X x);
// }
//
// class C1 extends CC1<int> {}
//
// abstract class DD1<X> {
// void m(X x);
// }
//
// class D1 extends B1 implements DD1<int> {
// void m(int x);
// }
class B2 {
void m(num x) {}
}
abstract class CC2<X extends int> extends B2 {
void m(covariant X x);
}
class C2 extends CC2<int> {}
abstract class DD2<X> {
void m(X x);
}
class D2 extends B2 implements DD2<int> {
void m(num x);
}
// Superclass: regular, interface: extends.
class B3 {
void m(num x) {}
}
abstract class BB3<X extends num> extends B3 {
void m(covariant X x);
}
class C3 extends BB3<num> {}
abstract class DD3<X extends num> {
void m(X x);
}
class D3 extends BB3<num> implements DD3<num> {}
class B4 {
void m(int x) {}
}
abstract class BB4<X extends int> extends B4 {
void m(covariant X x);
}
class C4 extends BB4<int> {}
abstract class DD4<X extends num> {
void m(X x);
}
class D4 extends BB4<int> implements DD4<int> {}
class B5 {
void m(num x) {}
}
abstract class BB5<X extends int> extends B5 {
void m(covariant X x);
}
class C5 extends BB5<int> {}
abstract class DD5<X extends int> {
void m(X x);
}
class D5 extends BB5<int> implements DD5<int> {}
// Superclass: regular, interface: implements.
class B6 {
void m(num x) {}
}
abstract class I6<X extends num> {
void m(X x);
}
class C6 extends B6 implements I6<num> {}
abstract class JJ6 {
void m(Object x);
}
abstract class J6<X extends num> implements JJ6 {
void m(covariant X x);
}
class D6 extends B6 implements J6<num> {}
class B7 {
void m(int x) {}
}
abstract class I7<X extends num> {
void m(X x);
}
class C7 extends B7 implements I7<int> {}
abstract class JJ7 {
void m(Object x);
}
abstract class J7<X extends num> implements JJ7 {
void m(covariant X x);
}
class D7 extends B7 implements J7<int> {}
class B8 {
void m(num x) {}
}
abstract class I8<X extends int> {
void m(X x);
}
class C8 extends B8 implements I8<int> {}
abstract class JJ8 {
void m(Object x);
}
abstract class J8<X extends int> implements JJ8 {
void m(covariant X x);
}
class D8 extends B8 implements J8<int> {}
// Superclass: mixed-in, interface: immediate.
class A9 {}
mixin M9 {
void m(num x) {}
}
class B9 extends A9 with M9 {}
abstract class CC9<X extends num> extends B9 {
void m(covariant X x);
}
class C9 extends CC9<num> {}
abstract class DD9<X> {
void m(X x);
}
class D9 extends B9 implements DD9<num> {
void m(num x);
}
class A10 {}
mixin M10 {
void m(int x) {}
}
class B10 extends A10 with M10 {}
abstract class CC10<X extends int> extends B10 {
void m(covariant X x);
}
class C10 extends CC10<int> {}
abstract class DD10<X> {
void m(X x);
}
class D10 extends B10 implements DD10<int> {
void m(int x);
}
class A11 {}
mixin M11 {
void m(num x) {}
}
class B11 extends A11 with M11 {}
abstract class CC11<X extends int> extends B11 {
void m(covariant X x);
}
class C11 extends CC11<int> {}
abstract class DD11<X> {
void m(X x);
}
class D11 extends B11 implements DD11<int> {
void m(num x);
}
// Superclass: mixed-in, interface: extends.
class A12 {}
mixin M12 {
void m(num x) {}
}
class B12 extends A12 with M12 {}
abstract class BB12<X extends num> extends B12 {
void m(covariant X x);
}
class C12 extends BB12<num> {}
abstract class DD12<X extends num> {
void m(X x);
}
class D12 extends BB12<num> implements DD12<num> {}
class A13 {}
mixin M13 {
void m(int x) {}
}
class B13 extends A13 with M13 {}
abstract class BB13<X extends int> extends B13 {
void m(covariant X x);
}
class C13 extends BB13<int> {}
abstract class DD13<X extends num> {
void m(X x);
}
class D13 extends BB13<int> implements DD13<int> {}
class A14 {}
mixin M14 {
void m(num x) {}
}
class B14 extends A14 with M14 {}
abstract class BB14<X extends int> extends B14 {
void m(covariant X x);
}
class C14 extends BB14<int> {}
abstract class DD14<X extends int> {
void m(X x);
}
class D14 extends BB14<int> implements DD14<int> {}
// Superclass: mixed-in, interface: implements.
class A15 {}
mixin M15 {
void m(num x) {}
}
class B15 extends A15 with M15 {}
abstract class I15<X extends num> {
void m(X x);
}
class C15 extends B15 implements I15<num> {}
abstract class JJ15 {
void m(Object x);
}
abstract class J15<X extends num> implements JJ15 {
void m(covariant X x);
}
class D15 extends B15 implements J15<num> {}
class A16 {}
mixin M16 {
void m(int x) {}
}
class B16 extends A16 with M16 {}
abstract class I16<X extends num> {
void m(X x);
}
class C16 extends B16 implements I16<int> {}
abstract class JJ16 {
void m(Object x);
}
abstract class J16<X extends num> implements JJ16 {
void m(covariant X x);
}
class D16 extends B16 implements J16<int> {}
class A17 {}
mixin M17 {
void m(num x) {}
}
class B17 extends A17 with M17 {}
abstract class I17<X extends int> {
void m(X x);
}
class C17 extends B17 implements I17<int> {}
abstract class JJ17 {
void m(Object x);
}
abstract class J17<X extends int> implements JJ17 {
void m(covariant X x);
}
class D17 extends B17 implements J17<int> {}
void main() {
// Demonstrate that each leaf class requires and has a dynamic
// type check (which is most likely placed in a forwarding stub).
const o = Object();
CC0<Object?> x0 = C0();
Expect.throws(() => x0.m(o));
DD0<Object?> y0 = D0();
Expect.throws(() => y0.m(o));
// Group 1 was eliminated, see comment containing `class B1`.
CC2<Object?> x2 = C2();
Expect.throws(() => x2.m(o));
DD2<Object?> y2 = D2();
Expect.throws(() => y2.m(o));
BB3<Object?> x3 = C3();
Expect.throws(() => x3.m(o));
DD3<Object?> y3 = D3();
Expect.throws(() => y3.m(o));
BB4<Object?> x4 = C4();
Expect.throws(() => x4.m(o));
DD4<Object?> y4 = D4();
Expect.throws(() => y4.m(o));
BB5<Object?> x5 = C5();
Expect.throws(() => x5.m(o));
DD5<Object?> y5 = D5();
Expect.throws(() => y5.m(o));
I6<Object?> x6 = C6();
Expect.throws(() => x6.m(o));
JJ6 y6 = D6();
Expect.throws(() => y6.m(o));
I7<Object?> x7 = C7();
Expect.throws(() => x7.m(o));
JJ7 y7 = D7();
Expect.throws(() => y7.m(o));
I8<Object?> x8 = C8();
Expect.throws(() => x8.m(o));
JJ8 y8 = D8();
Expect.throws(() => y8.m(o));
CC9<Object?> x9 = C9();
Expect.throws(() => x9.m(o));
DD9<Object?> y9 = D9();
Expect.throws(() => y9.m(o));
CC10<Object?> x10 = C10();
Expect.throws(() => x10.m(o));
DD10<Object?> y10 = D10();
Expect.throws(() => y10.m(o));
CC11<Object?> x11 = C11();
Expect.throws(() => x11.m(o));
DD11<Object?> y11 = D11();
Expect.throws(() => y11.m(o));
BB12<Object?> x12 = C12();
Expect.throws(() => x12.m(o));
DD12<Object?> y12 = D12();
Expect.throws(() => y12.m(o));
BB13<Object?> x13 = C13();
Expect.throws(() => x13.m(o));
DD13<Object?> y13 = D13();
Expect.throws(() => y13.m(o));
BB14<Object?> x14 = C14();
Expect.throws(() => x14.m(o));
DD14<Object?> y14 = D14();
Expect.throws(() => y14.m(o));
I15<Object?> x15 = C15();
Expect.throws(() => x15.m(o));
JJ15 y15 = D15();
Expect.throws(() => y15.m(o));
I16<Object?> x16 = C16();
Expect.throws(() => x16.m(o));
JJ16 y16 = D16();
Expect.throws(() => y16.m(o));
I17<Object?> x17 = C17();
Expect.throws(() => x17.m(o));
JJ17 y17 = D17();
Expect.throws(() => y17.m(o));
}