[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:
Nicholas Shahan 2019-07-23 20:04:42 +00:00 committed by commit-bot@chromium.org
parent f66964c66d
commit e6db859100
2 changed files with 85 additions and 28 deletions

View file

@ -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;

View file

@ -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));
}