mirror of
https://github.com/dart-lang/sdk
synced 2024-09-16 01:13:04 +00:00
[dartdevc] Cleanup unused portions of subtyping rules
Add additional subtyping test cases. Change-Id: I3aa65bb5c92cf26836f5f49143083b9634386594 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/109544 Commit-Queue: Nicholas Shahan <nshahan@google.com> Reviewed-by: Leaf Petersen <leafp@google.com>
This commit is contained in:
parent
f66964c66d
commit
e6db859100
|
@ -695,16 +695,21 @@ List<TypeVariable> _typeFormalsFromFunction(Object typeConstructor) {
|
|||
FunctionType fnType(returnType, List args, [@undefined extra]) =>
|
||||
FunctionType.create(returnType, args, extra);
|
||||
|
||||
/// Creates a generic function type.
|
||||
/// Creates a generic function type from [instantiateFn] and [typeBounds].
|
||||
///
|
||||
/// A function type consists of two things: an instantiate function, and an
|
||||
/// function that returns a list of upper bound constraints for each
|
||||
/// the type formals. Both functions accept the type parameters, allowing us
|
||||
/// to substitute values. The upper bound constraints can be omitted if all
|
||||
/// of the type parameters use the default upper bound.
|
||||
/// A function type consists of two things:
|
||||
/// * An instantiate function that takes type arguments and returns the
|
||||
/// function signature in the form of a two element list. The first element
|
||||
/// is the return type. The second element is a list of the argument types.
|
||||
/// * A function that returns a list of upper bound constraints for each of
|
||||
/// the type formals.
|
||||
///
|
||||
/// Both functions accept the type parameters, allowing us to substitute values.
|
||||
/// The upper bound constraints can be omitted if all of the type parameters use
|
||||
/// the default upper bound.
|
||||
///
|
||||
/// For example given the type <T extends Iterable<T>>(T) -> T, we can declare
|
||||
/// this type with `gFnType(T => [T, [T]], T => [Iterable$(T)])`.\
|
||||
/// this type with `gFnType(T => [T, [T]], T => [Iterable$(T)])`.
|
||||
gFnType(instantiateFn, typeBounds) =>
|
||||
GenericFunctionType(instantiateFn, typeBounds);
|
||||
|
||||
|
@ -882,6 +887,7 @@ bool _isSubtype(t1, t2) => JS('', '''(() => {
|
|||
// given t1 is Future<A> | A, then:
|
||||
// (Future<A> | A) <: t2 iff Future<A> <: t2 and A <: t2.
|
||||
let t1Future = ${getGenericClass(Future)}(t1TypeArg);
|
||||
// Known to handle the case FutureOr<Null> <: Future<Null>.
|
||||
return $_isSubtype(t1Future, $t2) && $_isSubtype(t1TypeArg, $t2);
|
||||
}
|
||||
|
||||
|
@ -890,9 +896,7 @@ bool _isSubtype(t1, t2) => JS('', '''(() => {
|
|||
// t1 <: (Future<A> | A) iff t1 <: Future<A> or t1 <: A
|
||||
let t2TypeArg = ${getGenericArgs(t2)}[0];
|
||||
let t2Future = ${getGenericClass(Future)}(t2TypeArg);
|
||||
let s1 = $_isSubtype($t1, t2Future);
|
||||
let s2 = $_isSubtype($t1, t2TypeArg);
|
||||
return s1 || s2;
|
||||
return $_isSubtype($t1, t2Future) || $_isSubtype($t1, t2TypeArg);
|
||||
}
|
||||
|
||||
// "Traditional" name-based subtype check. Avoid passing
|
||||
|
@ -908,9 +912,11 @@ bool _isSubtype(t1, t2) => JS('', '''(() => {
|
|||
}
|
||||
|
||||
// All JS types are subtypes of anonymous JS types.
|
||||
if ($t1 === $jsobject && $t2 instanceof $AnonymousJSType) return true;
|
||||
if ($t1 === $jsobject && $t2 instanceof $AnonymousJSType) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Compare two interface types:
|
||||
// Compare two interface types.
|
||||
return ${_isInterfaceSubtype(t1, t2)};
|
||||
}
|
||||
|
||||
|
@ -942,6 +948,9 @@ bool _isSubtype(t1, t2) => JS('', '''(() => {
|
|||
// rather it uses JS function parameters to ensure correct binding.
|
||||
let fresh = $t2.typeFormals;
|
||||
|
||||
// TODO(nshahan) Remove this variance check. The types should be equal
|
||||
// according to the spec and to match other backends.
|
||||
|
||||
// Check the bounds of the type parameters of g1 and g2.
|
||||
// given a type parameter `T1 extends U1` from g1, and a type parameter
|
||||
// `T2 extends U2` from g2, we must ensure that:
|
||||
|
@ -1000,22 +1009,12 @@ bool _isInterfaceSubtype(t1, t2) => JS('', '''(() => {
|
|||
if (raw1 != null && raw1 == raw2) {
|
||||
let typeArguments1 = $getGenericArgs($t1);
|
||||
let typeArguments2 = $getGenericArgs($t2);
|
||||
let length = typeArguments1.length;
|
||||
if (typeArguments2.length == 0) {
|
||||
// t2 is the raw form of t1
|
||||
return true;
|
||||
} else if (length == 0) {
|
||||
// t1 is raw, but t2 is not
|
||||
if (typeArguments2.every($_isTop)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
if (typeArguments1.length != typeArguments2.length) {
|
||||
$assertFailed();
|
||||
}
|
||||
if (length != typeArguments2.length) $assertFailed();
|
||||
for (let i = 0; i < length; ++i) {
|
||||
let result = $_isSubtype(typeArguments1[i], typeArguments2[i]);
|
||||
if (!result) {
|
||||
return result;
|
||||
for (let i = 0; i < typeArguments1.length; ++i) {
|
||||
if (!$_isSubtype(typeArguments1[i], typeArguments2[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
|
|
@ -2,9 +2,9 @@
|
|||
// 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 'dart:async';
|
||||
import 'dart:_foreign_helper' show JS;
|
||||
import 'dart:_runtime' as dart;
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:expect/expect.dart';
|
||||
|
||||
|
@ -16,6 +16,10 @@ class C extends B {}
|
|||
|
||||
class D<T extends B> {}
|
||||
|
||||
class E<T, S> {}
|
||||
|
||||
class F extends E<B, B> {}
|
||||
|
||||
// Returns sWrapped<tWrapped> as a wrapped type.
|
||||
Object generic1(Type sWrapped, Type tWrapped) {
|
||||
var s = dart.unwrapType(sWrapped);
|
||||
|
@ -24,6 +28,15 @@ Object generic1(Type sWrapped, Type tWrapped) {
|
|||
return dart.wrapType(JS('', '#(#)', sGeneric, t));
|
||||
}
|
||||
|
||||
// Returns sWrapped<tWrapped, rWrapped> as a wrapped type.
|
||||
Object generic2(Type sWrapped, Type tWrapped, Type rWrapped) {
|
||||
var s = dart.unwrapType(sWrapped);
|
||||
var t = dart.unwrapType(tWrapped);
|
||||
var r = dart.unwrapType(rWrapped);
|
||||
var sGeneric = dart.getGenericClass(s);
|
||||
return dart.wrapType(JS('', '#(#, #)', sGeneric, t, r));
|
||||
}
|
||||
|
||||
// Returns a function type of argWrapped -> returnWrapped as a wrapped type.
|
||||
Object function1(Type returnWrapped, Type argWrapped) {
|
||||
var returnType = dart.unwrapType(returnWrapped);
|
||||
|
@ -32,6 +45,31 @@ Object function1(Type returnWrapped, Type argWrapped) {
|
|||
return dart.wrapType(fun);
|
||||
}
|
||||
|
||||
// Returns a function type with a bounded type argument that takes no argument
|
||||
// and returns void as a wrapped type.
|
||||
Object genericFunction(Type boundWrapped) => dart.wrapType(dart.gFnType(
|
||||
(T) => [dart.VoidType, []], (T) => [dart.unwrapType(boundWrapped)]));
|
||||
|
||||
// Returns a function type with a bounded generic return type of
|
||||
// <T extends typeBoud> argWrapped -> T as a wrapped type.
|
||||
Object functionGenericReturn(Type boundWrapped, Type argWrapped) =>
|
||||
dart.wrapType(dart.gFnType(
|
||||
(T) => [
|
||||
T,
|
||||
[dart.unwrapType(argWrapped)]
|
||||
],
|
||||
(T) => [dart.unwrapType(boundWrapped)]));
|
||||
|
||||
// Returns a function with a bounded generic argument type of
|
||||
// <T extends typeBoud> T -> returnWrapped as a wrapped type.
|
||||
Object functionGenericArg(Type boundWrapped, Type returnWrapped) =>
|
||||
dart.wrapType(dart.gFnType(
|
||||
(T) => [
|
||||
dart.unwrapType(returnWrapped),
|
||||
[T]
|
||||
],
|
||||
(T) => [dart.unwrapType(boundWrapped)]));
|
||||
|
||||
void checkSubtype(Type sWrapped, Type tWrapped) {
|
||||
var s = dart.unwrapType(sWrapped);
|
||||
var t = dart.unwrapType(tWrapped);
|
||||
|
@ -55,6 +93,8 @@ void main() {
|
|||
// Null <: A
|
||||
checkProperSubtype(Null, A);
|
||||
|
||||
// FutureOr<Null> <: Future<Null>
|
||||
checkSubtype(generic1(FutureOr, Null), generic1(Future, Null));
|
||||
// Future<B> <: FutureOr<A>
|
||||
checkProperSubtype(generic1(Future, B), generic1(FutureOr, A));
|
||||
// B <: <: FutureOr<A>
|
||||
|
@ -84,10 +124,28 @@ void main() {
|
|||
// A -> B <: A -> A
|
||||
checkSubtype(function1(B, A), function1(A, A));
|
||||
|
||||
// <T extends B> void fn() <: <T extends B> void fn()
|
||||
checkSubtype(genericFunction(B), genericFunction(B));
|
||||
|
||||
// <T extends B> T fn(A) <: <T extends B> T fn(B)
|
||||
checkProperSubtype(functionGenericReturn(B, A), functionGenericReturn(B, B));
|
||||
|
||||
// <T extends B> B fn(T) <: <T extends B> A fn(T)
|
||||
checkProperSubtype(functionGenericArg(B, B), functionGenericArg(B, A));
|
||||
|
||||
// D <: D<B>
|
||||
checkSubtype(D, generic1(D, B));
|
||||
// D<B> <: D
|
||||
checkSubtype(generic1(D, B), D);
|
||||
// D<C> <: D<B>
|
||||
checkProperSubtype(generic1(D, C), generic1(D, B));
|
||||
|
||||
// F <: E
|
||||
checkProperSubtype(F, E);
|
||||
// F <: E<A, A>
|
||||
checkProperSubtype(F, generic2(E, A, A));
|
||||
// // E<B, B> <: E<A, A>
|
||||
checkProperSubtype(generic2(E, B, B), E);
|
||||
// // E<B, B> <: E<A, A>
|
||||
checkProperSubtype(generic2(E, B, B), generic2(E, A, A));
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue