mirror of
https://github.com/dart-lang/sdk
synced 2024-10-14 18:49:37 +00:00
[ddk] Modify _isInterfaceSubtype to consider variance annotations during runtime.
Change-Id: Idc1b553d24d76bfe52d51204aae0e0334f210fd0 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/121910 Reviewed-by: Leaf Petersen <leafp@google.com> Reviewed-by: Nicholas Shahan <nshahan@google.com> Commit-Queue: Kallen Tu <kallentu@google.com>
This commit is contained in:
parent
700765a4d7
commit
ef742aa6f0
|
@ -1037,9 +1037,23 @@ bool _isInterfaceSubtype(t1, t2) => JS('', '''(() => {
|
|||
if (typeArguments1.length != typeArguments2.length) {
|
||||
$assertFailed();
|
||||
}
|
||||
let variances = $getGenericArgVariances($t1);
|
||||
for (let i = 0; i < typeArguments1.length; ++i) {
|
||||
if (!$_isSubtype(typeArguments1[i], typeArguments2[i])) {
|
||||
return false;
|
||||
// When using implicit variance, variances will be undefined and
|
||||
// considered covariant.
|
||||
if (variances === void 0 || variances[i] == ${Variance.covariant}) {
|
||||
if (!$_isSubtype(typeArguments1[i], typeArguments2[i])) {
|
||||
return false;
|
||||
}
|
||||
} else if (variances[i] == ${Variance.contravariant}) {
|
||||
if (!$_isSubtype(typeArguments2[i], typeArguments1[i])) {
|
||||
return false;
|
||||
}
|
||||
} else if (variances[i] == ${Variance.invariant}) {
|
||||
if (!$_isSubtype(typeArguments1[i], typeArguments2[i]) ||
|
||||
!$_isSubtype(typeArguments2[i], typeArguments1[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
|
|
@ -1198,9 +1198,23 @@ bool _isInterfaceSubtype(t1, t2) => JS('', '''(() => {
|
|||
if (typeArguments1.length != typeArguments2.length) {
|
||||
$assertFailed();
|
||||
}
|
||||
let variances = $getGenericArgVariances($t1);
|
||||
for (let i = 0; i < typeArguments1.length; ++i) {
|
||||
if (!$_isSubtype(typeArguments1[i], typeArguments2[i])) {
|
||||
return false;
|
||||
// When using implicit variance, variances will be undefined and
|
||||
// considered covariant.
|
||||
if (variances === void 0 || variances[i] == ${Variance.covariant}) {
|
||||
if (!$_isSubtype(typeArguments1[i], typeArguments2[i])) {
|
||||
return false;
|
||||
}
|
||||
} else if (variances[i] == ${Variance.contravariant}) {
|
||||
if (!$_isSubtype(typeArguments2[i], typeArguments1[i])) {
|
||||
return false;
|
||||
}
|
||||
} else if (variances[i] == ${Variance.invariant}) {
|
||||
if (!$_isSubtype(typeArguments1[i], typeArguments2[i]) ||
|
||||
!$_isSubtype(typeArguments2[i], typeArguments1[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
|
|
@ -5,4 +5,5 @@
|
|||
# Sections in this file should contain "$compiler == dartdevc" or dartdevk.
|
||||
|
||||
[ $compiler == dartdevc ]
|
||||
variance_subtype_test: SkipByDesign # Not supported by analyzer based DDC.
|
||||
variance_test: SkipByDesign # Not supported by analyzer based DDC.
|
||||
|
|
148
tests/compiler/dartdevc_native/variance_subtype_test.dart
Normal file
148
tests/compiler/dartdevc_native/variance_subtype_test.dart
Normal file
|
@ -0,0 +1,148 @@
|
|||
// Copyright (c) 2019, 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 runtime subtyping with explicit variance modifiers.
|
||||
|
||||
// SharedOptions=--enable-experiment=variance
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'runtime_utils.dart';
|
||||
|
||||
class Upper {}
|
||||
class Middle extends Upper {}
|
||||
class Lower extends Middle {}
|
||||
|
||||
class Covariant<out T> {}
|
||||
class Contravariant<in T> {}
|
||||
class Invariant<inout T> {}
|
||||
class LegacyCovariant<T> {}
|
||||
|
||||
void main() {
|
||||
// Covariant<Lower> <: Covariant<Middle>
|
||||
checkProperSubtype(generic1(Covariant, Lower), generic1(Covariant, Middle));
|
||||
|
||||
// Covariant<Middle> <: Covariant<Middle>
|
||||
checkSubtype(generic1(Covariant, Middle), generic1(Covariant, Middle));
|
||||
|
||||
// Contravariant<Upper> <: Contravariant<Middle>
|
||||
checkProperSubtype(generic1(Contravariant, Upper), generic1(Contravariant, Middle));
|
||||
|
||||
// Contravariant<Middle> <: Contravariant<Middle>
|
||||
checkSubtype(generic1(Contravariant, Middle), generic1(Contravariant, Middle));
|
||||
|
||||
// Invariant<Middle> <: Invariant<Middle>
|
||||
checkSubtype(generic1(Invariant, Middle), generic1(Invariant, Middle));
|
||||
|
||||
// Invariant<dynamic> <:> Invariant<Object>
|
||||
checkSubtype(generic1(Invariant, dynamic), generic1(Invariant, Object));
|
||||
checkSubtype(generic1(Invariant, Object), generic1(Invariant, dynamic));
|
||||
|
||||
// Invariant<FutureOr<dynamic>> <:> Invariant<dynamic>
|
||||
checkSubtype(generic1(Invariant, generic1(FutureOr, dynamic)), generic1(Invariant, dynamic));
|
||||
checkSubtype(generic1(Invariant, dynamic), generic1(Invariant, generic1(FutureOr, dynamic)));
|
||||
|
||||
// Invariant<FutureOr<Null>> <:> Invariant<Future<Null>>
|
||||
checkSubtype(generic1(Invariant, generic1(FutureOr, Null)), generic1(Invariant, generic1(Future, Null)));
|
||||
checkSubtype(generic1(Invariant, generic1(Future, Null)), generic1(Invariant, generic1(FutureOr, Null)));
|
||||
|
||||
// LegacyCovariant<Lower> <: LegacyCovariant<Middle>
|
||||
checkProperSubtype(generic1(LegacyCovariant, Lower), generic1(LegacyCovariant, Middle));
|
||||
|
||||
// List<Covariant<Lower>> <: Iterable<Covariant<Middle>>
|
||||
checkProperSubtype(generic1(List, generic1(Covariant, Lower)), generic1(Iterable, generic1(Covariant, Middle)));
|
||||
|
||||
// List<Contravariant<Upper>> <: Iterable<Contravariant<Middle>>
|
||||
checkProperSubtype(generic1(List, generic1(Contravariant, Upper)), generic1(Iterable, generic1(Contravariant, Middle)));
|
||||
|
||||
// List<Invariant<Middle>> <: Iterable<Invariant<Middle>>
|
||||
checkProperSubtype(generic1(List, generic1(Invariant, Middle)), generic1(Iterable, generic1(Invariant, Middle)));
|
||||
|
||||
// List<LegacyCovariant<Lower>> <: Iterable<LegacyCovariant<Middle>>
|
||||
checkProperSubtype(generic1(List, generic1(LegacyCovariant, Lower)), generic1(Iterable, generic1(LegacyCovariant, Middle)));
|
||||
|
||||
// String -> Covariant<Lower> <: String -> Covariant<Middle>
|
||||
checkProperSubtype(function1(generic1(Covariant, Lower), String), function1(generic1(Covariant, Middle), String));
|
||||
|
||||
// Covariant<Upper> -> String <: Covariant<Middle> -> String
|
||||
checkProperSubtype(function1(String, generic1(Covariant, Upper)), function1(String, generic1(Covariant, Middle)));
|
||||
|
||||
// String -> Contravariant<Upper> <: String -> Contravariant<Middle>
|
||||
checkProperSubtype(function1(generic1(Contravariant, Upper), String), function1(generic1(Contravariant, Middle), String));
|
||||
|
||||
// Contravariant<Lower> -> String <: Contravariant<Middle> -> String
|
||||
checkProperSubtype(function1(String, generic1(Contravariant, Lower)), function1(String, generic1(Contravariant, Middle)));
|
||||
|
||||
// String -> Invariant<Middle> <: String -> Invariant<Middle>
|
||||
checkSubtype(function1(generic1(Invariant, Middle), String), function1(generic1(Invariant, Middle), String));
|
||||
|
||||
// Invariant<Middle> -> String <: Invariant<Middle> -> String
|
||||
checkSubtype(function1(String, generic1(Invariant, Middle)), function1(String, generic1(Invariant, Middle)));
|
||||
|
||||
// String -> LegacyCovariant<Lower> <: String -> LegacyCovariant<Middle>
|
||||
checkProperSubtype(function1(generic1(LegacyCovariant, Lower), String), function1(generic1(LegacyCovariant, Middle), String));
|
||||
|
||||
// LegacyCovariant<Upper> -> String <: LegacyCovariant<Middle> -> String
|
||||
checkProperSubtype(function1(String, generic1(LegacyCovariant, Upper)), function1(String, generic1(LegacyCovariant, Middle)));
|
||||
|
||||
// Covariant<Upper> </: Covariant<Middle>
|
||||
checkSubtypeFailure(generic1(Covariant, Upper), generic1(Covariant, Middle));
|
||||
|
||||
// Contravariant<Lower> </: Contravariant<Middle>
|
||||
checkSubtypeFailure(generic1(Contravariant, Lower), generic1(Contravariant, Middle));
|
||||
|
||||
// Invariant<Upper> </: Invariant<Middle>
|
||||
checkSubtypeFailure(generic1(Invariant, Upper), generic1(Invariant, Middle));
|
||||
|
||||
// Invariant<Lower> </: Invariant<Middle>
|
||||
checkSubtypeFailure(generic1(Invariant, Lower), generic1(Invariant, Middle));
|
||||
|
||||
// LegacyCovariant<Upper> </: LegacyCovariant<Middle>
|
||||
checkSubtypeFailure(generic1(LegacyCovariant, Upper), generic1(LegacyCovariant, Middle));
|
||||
|
||||
// List<Covariant<Upper>> </: Iterable<Covariant<Middle>>
|
||||
checkSubtypeFailure(generic1(List, generic1(Covariant, Upper)), generic1(Iterable, generic1(Covariant, Middle)));
|
||||
|
||||
// List<Contravariant<Lower>> </: Iterable<Contravariant<Middle>>
|
||||
checkSubtypeFailure(generic1(List, generic1(Contravariant, Lower)), generic1(Iterable, generic1(Contravariant, Middle)));
|
||||
|
||||
// List<Invariant<Upper>> </: Iterable<Invariant<Middle>>
|
||||
checkSubtypeFailure(generic1(List, generic1(Invariant, Upper)), generic1(Iterable, generic1(Invariant, Middle)));
|
||||
|
||||
// List<Invariant<Lower>> </: Iterable<Invariant<Middle>>
|
||||
checkSubtypeFailure(generic1(List, generic1(Invariant, Lower)), generic1(Iterable, generic1(Invariant, Middle)));
|
||||
|
||||
// List<LegacyCovariant<Upper>> </: Iterable<LegacyCovariant<Middle>>
|
||||
checkSubtypeFailure(generic1(List, generic1(LegacyCovariant, Upper)), generic1(Iterable, generic1(LegacyCovariant, Middle)));
|
||||
|
||||
// String -> Covariant<Upper> </: String -> Covariant<Middle>
|
||||
checkSubtypeFailure(function1(generic1(Covariant, Upper), String), function1(generic1(Covariant, Middle), String));
|
||||
|
||||
// Covariant<Lower> -> String </: Covariant<Middle> -> String
|
||||
checkSubtypeFailure(function1(String, generic1(Covariant, Lower)), function1(String, generic1(Covariant, Middle)));
|
||||
|
||||
// String -> Contravariant<Lower> </: String -> Contravariant<Middle>
|
||||
checkSubtypeFailure(function1(generic1(Contravariant, Lower), String), function1(generic1(Contravariant, Middle), String));
|
||||
|
||||
// Contravariant<Upper> -> String </: Contravariant<Middle> -> String
|
||||
checkSubtypeFailure(function1(String, generic1(Contravariant, Upper)), function1(String, generic1(Contravariant, Middle)));
|
||||
|
||||
// String -> Invariant<Upper> </: String -> Invariant<Middle>
|
||||
checkSubtypeFailure(function1(generic1(Invariant, Upper), String), function1(generic1(Invariant, Middle), String));
|
||||
|
||||
// Invariant<Upper> -> String </: Invariant<Middle> -> String
|
||||
checkSubtypeFailure(function1(String, generic1(Invariant, Upper)), function1(String, generic1(Invariant, Middle)));
|
||||
|
||||
// String -> Invariant<Lower> </: String -> Invariant<Middle>
|
||||
checkSubtypeFailure(function1(generic1(Invariant, Lower), String), function1(generic1(Invariant, Middle), String));
|
||||
|
||||
// Invariant<Lower> -> String <: Invariant<Middle> -> String
|
||||
checkSubtypeFailure(function1(String, generic1(Invariant, Lower)), function1(String, generic1(Invariant, Middle)));
|
||||
|
||||
// String -> LegacyCovariant<Upper> </: String -> LegacyCovariant<Middle>
|
||||
checkSubtypeFailure(function1(generic1(LegacyCovariant, Upper), String), function1(generic1(LegacyCovariant, Middle), String));
|
||||
|
||||
// LegacyCovariant<Lower> -> String </: LegacyCovariant<Middle> -> String
|
||||
checkSubtypeFailure(function1(String, generic1(LegacyCovariant, Lower)), function1(String, generic1(LegacyCovariant, Middle)));
|
||||
}
|
|
@ -11,6 +11,7 @@ const_double_in_int_op_test/ii6: Skip # Triple shift
|
|||
extension_methods/*: SkipByDesign # Analyzer DDC is expected to be turned down before releasing extension methods.
|
||||
large_class_declaration_test: Slow
|
||||
nnbd/*: Skip
|
||||
variance/*: SkipByDesign # Analyzer DDC is expected to be turned down before releasing variance.
|
||||
|
||||
[ $compiler == dartdevk && !$checked ]
|
||||
assertion_initializer_const_error2_test/*: SkipByDesign # DDC does not support non-checked mode.
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
|
||||
// SharedOptions=--enable-experiment=variance
|
||||
|
||||
import "package:expect/expect.dart";
|
||||
|
||||
class Contravariant<in T> {}
|
||||
|
||||
class Upper {}
|
||||
|
@ -58,14 +60,23 @@ void testCall(Iterable<Contravariant<Lower>> x) {}
|
|||
|
||||
main() {
|
||||
A a = new A();
|
||||
Expect.type<Contravariant<Middle>>(a.method1());
|
||||
Expect.type<Contravariant<Lower>>(a.method1());
|
||||
Expect.notType<Contravariant<Upper>>(a.method1());
|
||||
a.method2(new Contravariant<Middle>());
|
||||
a.method2(new Contravariant<Upper>());
|
||||
|
||||
B b = new B();
|
||||
Expect.type<Contravariant<Upper>>(b.method1());
|
||||
Expect.type<Contravariant<Middle>>(b.method1());
|
||||
Expect.type<Contravariant<Lower>>(b.method1());
|
||||
b.method2(new Contravariant<Lower>());
|
||||
b.method2(new Contravariant<Middle>());
|
||||
|
||||
C c = new C();
|
||||
Expect.type<Contravariant<Middle>>(c.method1());
|
||||
Expect.type<Contravariant<Lower>>(c.method1());
|
||||
Expect.notType<Contravariant<Upper>>(c.method1());
|
||||
c.method2(new Contravariant<Middle>());
|
||||
c.method2(new Contravariant<Upper>());
|
||||
|
||||
|
@ -73,12 +84,19 @@ main() {
|
|||
D<Contravariant<Middle>> dMiddle = new D<Contravariant<Middle>>();
|
||||
|
||||
E e = new E();
|
||||
Expect.type<D<Contravariant<Upper>>>(e.method1());
|
||||
Expect.type<D<Contravariant<Middle>>>(e.method1());
|
||||
|
||||
F f = new F();
|
||||
Expect.type<D<Contravariant<Middle>>>(e.method1());
|
||||
|
||||
Iterable<Contravariant<Lower>> iterableLower = [new Contravariant<Lower>()];
|
||||
List<Contravariant<Middle>> listMiddle = [new Contravariant<Middle>()];
|
||||
iterableLower = listMiddle;
|
||||
|
||||
testCall(listMiddle);
|
||||
|
||||
Expect.subtype<Contravariant<Upper>, Contravariant<Middle>>();
|
||||
Expect.subtype<Contravariant<Middle>, Contravariant<Middle>>();
|
||||
Expect.notSubtype<Contravariant<Lower>, Contravariant<Middle>>();
|
||||
}
|
||||
|
|
|
@ -6,6 +6,10 @@
|
|||
|
||||
// SharedOptions=--enable-experiment=variance
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import "package:expect/expect.dart";
|
||||
|
||||
class Invariant<inout T> {}
|
||||
|
||||
class Upper {}
|
||||
|
@ -38,22 +42,129 @@ class D {
|
|||
}
|
||||
}
|
||||
|
||||
class E {
|
||||
Invariant<dynamic> method1() {
|
||||
return new Invariant<dynamic>();
|
||||
}
|
||||
|
||||
void method2(Invariant<Object> x) {}
|
||||
}
|
||||
|
||||
class F extends E {
|
||||
@override
|
||||
Invariant<Object> method1() {
|
||||
return new Invariant<Object>();
|
||||
}
|
||||
|
||||
@override
|
||||
void method2(Invariant<dynamic> x) {}
|
||||
}
|
||||
|
||||
class G {
|
||||
Invariant<dynamic> method1() {
|
||||
return new Invariant<dynamic>();
|
||||
}
|
||||
|
||||
void method2(Invariant<FutureOr<dynamic>> x) {}
|
||||
}
|
||||
|
||||
class H extends G {
|
||||
@override
|
||||
Invariant<FutureOr<dynamic>> method1() {
|
||||
return new Invariant<FutureOr<dynamic>>();
|
||||
}
|
||||
|
||||
@override
|
||||
void method2(Invariant<dynamic> x) {}
|
||||
}
|
||||
|
||||
class I {
|
||||
Invariant<FutureOr<Null>> method1() {
|
||||
return new Invariant<FutureOr<Null>>();
|
||||
}
|
||||
|
||||
void method2(Invariant<Future<Null>> x) {}
|
||||
}
|
||||
|
||||
class J extends I {
|
||||
@override
|
||||
Invariant<Future<Null>> method1() {
|
||||
return new Invariant<Future<Null>>();
|
||||
}
|
||||
|
||||
@override
|
||||
void method2(Invariant<FutureOr<Null>> x) {}
|
||||
}
|
||||
|
||||
void testCall(Iterable<Invariant<Middle>> x) {}
|
||||
|
||||
main() {
|
||||
A a = new A();
|
||||
Expect.type<Invariant<Middle>>(a.method1());
|
||||
Expect.notType<Invariant<Upper>>(a.method1());
|
||||
Expect.notType<Invariant<Lower>>(a.method1());
|
||||
a.method2(new Invariant<Middle>());
|
||||
|
||||
B b = new B();
|
||||
Expect.type<Invariant<Middle>>(b.method1());
|
||||
Expect.notType<Invariant<Upper>>(b.method1());
|
||||
Expect.notType<Invariant<Lower>>(b.method1());
|
||||
b.method2(new Invariant<Middle>());
|
||||
|
||||
C<Invariant<Middle>> c = new C<Invariant<Middle>>();
|
||||
|
||||
D d = new D();
|
||||
Expect.type<C<Invariant<Middle>>>(d.method1());
|
||||
|
||||
E e = new E();
|
||||
Expect.type<Invariant<dynamic>>(e.method1());
|
||||
e.method2(new Invariant<Object>());
|
||||
|
||||
// Invariant<dynamic> <:> Invariant<Object>
|
||||
F f = new F();
|
||||
Expect.type<Invariant<Object>>(f.method1());
|
||||
Expect.type<Invariant<dynamic>>(f.method1());
|
||||
f.method2(new Invariant<Object>());
|
||||
f.method2(new Invariant<dynamic>());
|
||||
|
||||
G g = new G();
|
||||
Expect.type<Invariant<dynamic>>(g.method1());
|
||||
g.method2(new Invariant<FutureOr<dynamic>>());
|
||||
|
||||
// Invariant<FutureOr<dynamic>> <:> Invariant<dynamic>
|
||||
H h = new H();
|
||||
Expect.type<Invariant<FutureOr<dynamic>>>(h.method1());
|
||||
Expect.type<Invariant<dynamic>>(h.method1());
|
||||
h.method2(new Invariant<FutureOr<dynamic>>());
|
||||
h.method2(new Invariant<dynamic>());
|
||||
|
||||
I i = new I();
|
||||
Expect.type<Invariant<FutureOr<Null>>>(i.method1());
|
||||
i.method2(new Invariant<Future<Null>>());
|
||||
|
||||
// Invariant<FutureOr<Null>> <:> Invariant<Future<Null>>
|
||||
J j = new J();
|
||||
Expect.type<Invariant<FutureOr<Null>>>(j.method1());
|
||||
Expect.type<Invariant<Future<Null>>>(j.method1());
|
||||
j.method2(new Invariant<FutureOr<Null>>());
|
||||
j.method2(new Invariant<Future<Null>>());
|
||||
|
||||
Iterable<Invariant<Middle>> iterableMiddle = [new Invariant<Middle>()];
|
||||
List<Invariant<Middle>> listMiddle = [new Invariant<Middle>()];
|
||||
iterableMiddle = listMiddle;
|
||||
|
||||
testCall(listMiddle);
|
||||
|
||||
Expect.subtype<Invariant<Middle>, Invariant<Middle>>();
|
||||
Expect.notSubtype<Invariant<Lower>, Invariant<Middle>>();
|
||||
Expect.notSubtype<Invariant<Upper>, Invariant<Middle>>();
|
||||
|
||||
Expect.subtype<Invariant<dynamic>, Invariant<Object>>();
|
||||
Expect.subtype<Invariant<Object>, Invariant<dynamic>>();
|
||||
|
||||
Expect.subtype<Invariant<FutureOr<dynamic>>, Invariant<dynamic>>();
|
||||
Expect.subtype<Invariant<dynamic>, Invariant<FutureOr<dynamic>>>();
|
||||
|
||||
Expect.subtype<Invariant<FutureOr<Null>>, Invariant<Future<Null>>>();
|
||||
Expect.subtype<Invariant<Future<Null>>, Invariant<FutureOr<Null>>>();
|
||||
}
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
|
||||
// SharedOptions=--enable-experiment=variance
|
||||
|
||||
import "package:expect/expect.dart";
|
||||
|
||||
class Covariant<out T> {}
|
||||
|
||||
class Upper {}
|
||||
|
@ -58,14 +60,23 @@ void testCall(Iterable<Covariant<Middle>> x) {}
|
|||
|
||||
main() {
|
||||
A a = new A();
|
||||
Expect.type<Covariant<Middle>>(a.method1());
|
||||
Expect.type<Covariant<Upper>>(a.method1());
|
||||
Expect.notType<Covariant<Lower>>(a.method1());
|
||||
a.method2(new Covariant<Middle>());
|
||||
a.method2(new Covariant<Lower>());
|
||||
|
||||
B b = new B();
|
||||
Expect.type<Covariant<Upper>>(b.method1());
|
||||
Expect.type<Covariant<Middle>>(b.method1());
|
||||
Expect.type<Covariant<Lower>>(b.method1());
|
||||
b.method2(new Covariant<Upper>());
|
||||
b.method2(new Covariant<Middle>());
|
||||
|
||||
C c = new C();
|
||||
Expect.type<Covariant<Middle>>(c.method1());
|
||||
Expect.type<Covariant<Upper>>(c.method1());
|
||||
Expect.notType<Covariant<Lower>>(c.method1());
|
||||
c.method2(new Covariant<Middle>());
|
||||
c.method2(new Covariant<Lower>());
|
||||
|
||||
|
@ -73,12 +84,19 @@ main() {
|
|||
D<Covariant<Middle>> dMiddle = new D<Covariant<Middle>>();
|
||||
|
||||
E e = new E();
|
||||
Expect.type<D<Covariant<Lower>>>(e.method1());
|
||||
Expect.type<D<Covariant<Middle>>>(e.method1());
|
||||
|
||||
F f = new F();
|
||||
Expect.type<D<Covariant<Middle>>>(f.method1());
|
||||
|
||||
Iterable<Covariant<Middle>> iterableMiddle = [new Covariant<Middle>()];
|
||||
List<Covariant<Lower>> listLower = [new Covariant<Lower>()];
|
||||
iterableMiddle = listLower;
|
||||
|
||||
testCall(listLower);
|
||||
|
||||
Expect.subtype<Covariant<Lower>, Covariant<Middle>>();
|
||||
Expect.subtype<Covariant<Middle>, Covariant<Middle>>();
|
||||
Expect.notSubtype<Covariant<Upper>, Covariant<Middle>>();
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue