Skip to content

Commit e6db859

Browse files
nshahancommit-bot@chromium.org
authored andcommitted
[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 <[email protected]> Reviewed-by: Leaf Petersen <[email protected]>
1 parent f66964c commit e6db859

File tree

2 files changed

+85
-28
lines changed

2 files changed

+85
-28
lines changed

sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/types.dart

Lines changed: 26 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -695,16 +695,21 @@ List<TypeVariable> _typeFormalsFromFunction(Object typeConstructor) {
695695
FunctionType fnType(returnType, List args, [@undefined extra]) =>
696696
FunctionType.create(returnType, args, extra);
697697

698-
/// Creates a generic function type.
698+
/// Creates a generic function type from [instantiateFn] and [typeBounds].
699699
///
700-
/// A function type consists of two things: an instantiate function, and an
701-
/// function that returns a list of upper bound constraints for each
702-
/// the type formals. Both functions accept the type parameters, allowing us
703-
/// to substitute values. The upper bound constraints can be omitted if all
704-
/// of the type parameters use the default upper bound.
700+
/// A function type consists of two things:
701+
/// * An instantiate function that takes type arguments and returns the
702+
/// function signature in the form of a two element list. The first element
703+
/// is the return type. The second element is a list of the argument types.
704+
/// * A function that returns a list of upper bound constraints for each of
705+
/// the type formals.
706+
///
707+
/// Both functions accept the type parameters, allowing us to substitute values.
708+
/// The upper bound constraints can be omitted if all of the type parameters use
709+
/// the default upper bound.
705710
///
706711
/// For example given the type <T extends Iterable<T>>(T) -> T, we can declare
707-
/// this type with `gFnType(T => [T, [T]], T => [Iterable$(T)])`.\
712+
/// this type with `gFnType(T => [T, [T]], T => [Iterable$(T)])`.
708713
gFnType(instantiateFn, typeBounds) =>
709714
GenericFunctionType(instantiateFn, typeBounds);
710715

@@ -882,6 +887,7 @@ bool _isSubtype(t1, t2) => JS('', '''(() => {
882887
// given t1 is Future<A> | A, then:
883888
// (Future<A> | A) <: t2 iff Future<A> <: t2 and A <: t2.
884889
let t1Future = ${getGenericClass(Future)}(t1TypeArg);
890+
// Known to handle the case FutureOr<Null> <: Future<Null>.
885891
return $_isSubtype(t1Future, $t2) && $_isSubtype(t1TypeArg, $t2);
886892
}
887893
@@ -890,9 +896,7 @@ bool _isSubtype(t1, t2) => JS('', '''(() => {
890896
// t1 <: (Future<A> | A) iff t1 <: Future<A> or t1 <: A
891897
let t2TypeArg = ${getGenericArgs(t2)}[0];
892898
let t2Future = ${getGenericClass(Future)}(t2TypeArg);
893-
let s1 = $_isSubtype($t1, t2Future);
894-
let s2 = $_isSubtype($t1, t2TypeArg);
895-
return s1 || s2;
899+
return $_isSubtype($t1, t2Future) || $_isSubtype($t1, t2TypeArg);
896900
}
897901
898902
// "Traditional" name-based subtype check. Avoid passing
@@ -908,9 +912,11 @@ bool _isSubtype(t1, t2) => JS('', '''(() => {
908912
}
909913
910914
// All JS types are subtypes of anonymous JS types.
911-
if ($t1 === $jsobject && $t2 instanceof $AnonymousJSType) return true;
915+
if ($t1 === $jsobject && $t2 instanceof $AnonymousJSType) {
916+
return true;
917+
}
912918
913-
// Compare two interface types:
919+
// Compare two interface types.
914920
return ${_isInterfaceSubtype(t1, t2)};
915921
}
916922
@@ -942,6 +948,9 @@ bool _isSubtype(t1, t2) => JS('', '''(() => {
942948
// rather it uses JS function parameters to ensure correct binding.
943949
let fresh = $t2.typeFormals;
944950
951+
// TODO(nshahan) Remove this variance check. The types should be equal
952+
// according to the spec and to match other backends.
953+
945954
// Check the bounds of the type parameters of g1 and g2.
946955
// given a type parameter `T1 extends U1` from g1, and a type parameter
947956
// `T2 extends U2` from g2, we must ensure that:
@@ -1000,22 +1009,12 @@ bool _isInterfaceSubtype(t1, t2) => JS('', '''(() => {
10001009
if (raw1 != null && raw1 == raw2) {
10011010
let typeArguments1 = $getGenericArgs($t1);
10021011
let typeArguments2 = $getGenericArgs($t2);
1003-
let length = typeArguments1.length;
1004-
if (typeArguments2.length == 0) {
1005-
// t2 is the raw form of t1
1006-
return true;
1007-
} else if (length == 0) {
1008-
// t1 is raw, but t2 is not
1009-
if (typeArguments2.every($_isTop)) {
1010-
return true;
1011-
}
1012-
return false;
1012+
if (typeArguments1.length != typeArguments2.length) {
1013+
$assertFailed();
10131014
}
1014-
if (length != typeArguments2.length) $assertFailed();
1015-
for (let i = 0; i < length; ++i) {
1016-
let result = $_isSubtype(typeArguments1[i], typeArguments2[i]);
1017-
if (!result) {
1018-
return result;
1015+
for (let i = 0; i < typeArguments1.length; ++i) {
1016+
if (!$_isSubtype(typeArguments1[i], typeArguments2[i])) {
1017+
return false;
10191018
}
10201019
}
10211020
return true;

tests/compiler/dartdevc_native/subtype_test.dart

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22
// for details. All rights reserved. Use of this source code is governed by a
33
// BSD-style license that can be found in the LICENSE file.
44

5-
import 'dart:async';
65
import 'dart:_foreign_helper' show JS;
76
import 'dart:_runtime' as dart;
7+
import 'dart:async';
88

99
import 'package:expect/expect.dart';
1010

@@ -16,6 +16,10 @@ class C extends B {}
1616

1717
class D<T extends B> {}
1818

19+
class E<T, S> {}
20+
21+
class F extends E<B, B> {}
22+
1923
// Returns sWrapped<tWrapped> as a wrapped type.
2024
Object generic1(Type sWrapped, Type tWrapped) {
2125
var s = dart.unwrapType(sWrapped);
@@ -24,6 +28,15 @@ Object generic1(Type sWrapped, Type tWrapped) {
2428
return dart.wrapType(JS('', '#(#)', sGeneric, t));
2529
}
2630

31+
// Returns sWrapped<tWrapped, rWrapped> as a wrapped type.
32+
Object generic2(Type sWrapped, Type tWrapped, Type rWrapped) {
33+
var s = dart.unwrapType(sWrapped);
34+
var t = dart.unwrapType(tWrapped);
35+
var r = dart.unwrapType(rWrapped);
36+
var sGeneric = dart.getGenericClass(s);
37+
return dart.wrapType(JS('', '#(#, #)', sGeneric, t, r));
38+
}
39+
2740
// Returns a function type of argWrapped -> returnWrapped as a wrapped type.
2841
Object function1(Type returnWrapped, Type argWrapped) {
2942
var returnType = dart.unwrapType(returnWrapped);
@@ -32,6 +45,31 @@ Object function1(Type returnWrapped, Type argWrapped) {
3245
return dart.wrapType(fun);
3346
}
3447

48+
// Returns a function type with a bounded type argument that takes no argument
49+
// and returns void as a wrapped type.
50+
Object genericFunction(Type boundWrapped) => dart.wrapType(dart.gFnType(
51+
(T) => [dart.VoidType, []], (T) => [dart.unwrapType(boundWrapped)]));
52+
53+
// Returns a function type with a bounded generic return type of
54+
// <T extends typeBoud> argWrapped -> T as a wrapped type.
55+
Object functionGenericReturn(Type boundWrapped, Type argWrapped) =>
56+
dart.wrapType(dart.gFnType(
57+
(T) => [
58+
T,
59+
[dart.unwrapType(argWrapped)]
60+
],
61+
(T) => [dart.unwrapType(boundWrapped)]));
62+
63+
// Returns a function with a bounded generic argument type of
64+
// <T extends typeBoud> T -> returnWrapped as a wrapped type.
65+
Object functionGenericArg(Type boundWrapped, Type returnWrapped) =>
66+
dart.wrapType(dart.gFnType(
67+
(T) => [
68+
dart.unwrapType(returnWrapped),
69+
[T]
70+
],
71+
(T) => [dart.unwrapType(boundWrapped)]));
72+
3573
void checkSubtype(Type sWrapped, Type tWrapped) {
3674
var s = dart.unwrapType(sWrapped);
3775
var t = dart.unwrapType(tWrapped);
@@ -55,6 +93,8 @@ void main() {
5593
// Null <: A
5694
checkProperSubtype(Null, A);
5795

96+
// FutureOr<Null> <: Future<Null>
97+
checkSubtype(generic1(FutureOr, Null), generic1(Future, Null));
5898
// Future<B> <: FutureOr<A>
5999
checkProperSubtype(generic1(Future, B), generic1(FutureOr, A));
60100
// B <: <: FutureOr<A>
@@ -84,10 +124,28 @@ void main() {
84124
// A -> B <: A -> A
85125
checkSubtype(function1(B, A), function1(A, A));
86126

127+
// <T extends B> void fn() <: <T extends B> void fn()
128+
checkSubtype(genericFunction(B), genericFunction(B));
129+
130+
// <T extends B> T fn(A) <: <T extends B> T fn(B)
131+
checkProperSubtype(functionGenericReturn(B, A), functionGenericReturn(B, B));
132+
133+
// <T extends B> B fn(T) <: <T extends B> A fn(T)
134+
checkProperSubtype(functionGenericArg(B, B), functionGenericArg(B, A));
135+
87136
// D <: D<B>
88137
checkSubtype(D, generic1(D, B));
89138
// D<B> <: D
90139
checkSubtype(generic1(D, B), D);
91140
// D<C> <: D<B>
92141
checkProperSubtype(generic1(D, C), generic1(D, B));
142+
143+
// F <: E
144+
checkProperSubtype(F, E);
145+
// F <: E<A, A>
146+
checkProperSubtype(F, generic2(E, A, A));
147+
// // E<B, B> <: E<A, A>
148+
checkProperSubtype(generic2(E, B, B), E);
149+
// // E<B, B> <: E<A, A>
150+
checkProperSubtype(generic2(E, B, B), generic2(E, A, A));
93151
}

0 commit comments

Comments
 (0)