restrict generic function type subtyping

R=leafp@google.com

Review URL: https://codereview.chromium.org/2540903003 .
This commit is contained in:
Jennifer Messerly 2016-12-01 19:24:15 -08:00
parent db8782f6e6
commit 7a1b6e75b3
6 changed files with 64 additions and 39 deletions

View file

@ -1026,16 +1026,12 @@ class FunctionTypeImpl extends TypeImpl implements FunctionType {
// This type cast is safe, because we checked it above.
FunctionType s = other as FunctionType;
if (t.typeFormals.isNotEmpty) {
if (s.typeFormals.isEmpty) {
t = instantiateToBounds(t);
} else {
List<DartType> freshVariables = relateTypeFormals(t, s, returnRelation);
if (freshVariables == null) {
return false;
}
t = t.instantiate(freshVariables);
s = s.instantiate(freshVariables);
List<DartType> freshVariables = relateTypeFormals(t, s, returnRelation);
if (freshVariables == null) {
return false;
}
t = t.instantiate(freshVariables);
s = s.instantiate(freshVariables);
} else if (s.typeFormals.isNotEmpty) {
return false;
}

View file

@ -1434,15 +1434,7 @@ class _OverrideChecker {
]);
}
}
FunctionType concreteSubType = subType;
FunctionType concreteBaseType = baseType;
if (concreteSubType.typeFormals.isNotEmpty) {
if (concreteBaseType.typeFormals.isEmpty) {
concreteSubType = rules.instantiateToBounds(concreteSubType);
}
}
if (!rules.isOverrideSubtypeOf(concreteSubType, concreteBaseType)) {
if (!rules.isOverrideSubtypeOf(subType, baseType)) {
ErrorCode errorCode;
if (errorLocation is ExtendsClause) {
errorCode = StrongModeCode.INVALID_METHOD_OVERRIDE_FROM_BASE;

View file

@ -1608,7 +1608,34 @@ class StrongSubtypingTest {
DartType u = TypeBuilder.variable("U", bound: intType);
DartType v = TypeBuilder.variable("V", bound: u);
DartType a = TypeBuilder.variable("A");
DartType b = TypeBuilder.variable("B", bound: a);
DartType c = TypeBuilder.variable("C", bound: intType);
DartType d = TypeBuilder.variable("D", bound: c);
_checkIsStrictSubtypeOf(
TypeBuilder.function(types: [s, t], required: [s], result: t),
TypeBuilder.function(
types: [a, b], required: [dynamicType], result: dynamicType));
_checkIsNotSubtypeOf(
TypeBuilder.function(types: [u, v], required: [u], result: v),
TypeBuilder.function(
types: [c, d], required: [objectType], result: objectType));
_checkIsNotSubtypeOf(
TypeBuilder.function(types: [u, v], required: [u], result: v),
TypeBuilder
.function(types: [c, d], required: [intType], result: intType));
}
void test_genericFunction_genericDoesNotSubtypeNonGeneric() {
DartType s = TypeBuilder.variable("S");
DartType t = TypeBuilder.variable("T", bound: s);
DartType u = TypeBuilder.variable("U", bound: intType);
DartType v = TypeBuilder.variable("V", bound: u);
_checkIsNotSubtypeOf(
TypeBuilder.function(types: [s, t], required: [s], result: t),
TypeBuilder.function(required: [dynamicType], result: dynamicType));
@ -1616,7 +1643,7 @@ class StrongSubtypingTest {
TypeBuilder.function(types: [u, v], required: [u], result: v),
TypeBuilder.function(required: [objectType], result: objectType));
_checkIsStrictSubtypeOf(
_checkIsNotSubtypeOf(
TypeBuilder.function(types: [u, v], required: [u], result: v),
TypeBuilder.function(required: [intType], result: intType));
}

View file

@ -3991,6 +3991,27 @@ void main() {
''');
}
void test_universalFunctionSubtyping() {
checkFile(r'''
dynamic foo<T>(dynamic x) => x;
void takesDtoD(dynamic f(dynamic x)) {}
void test() {
// here we currently infer an instantiation.
takesDtoD(/*pass should be error:INVALID_ASSIGNMENT*/foo);
}
class A {
dynamic method(dynamic x) => x;
}
class B extends A {
/*error:INVALID_METHOD_OVERRIDE*/T method<T>(T x) => x;
}
''');
}
void test_voidSubtyping() {
// Regression test for https://github.com/dart-lang/sdk/issues/25069
checkFile('''

View file

@ -2263,26 +2263,8 @@ class C {
dynamic g(int x) => x;
}
class D extends C {
T m<T>(T x) => x;
T g<T>(T x) => x;
}
main() {
int y = /*info:DYNAMIC_CAST*/(/*info:UNNECESSARY_CAST*/new D() as C).m(42);
print(y);
}
''');
}
void test_genericMethods_handleOverrideOfNonGenericWithGeneric_comment() {
// Regression test for crash when adding genericity
checkFile('''
class C {
m(x) => x;
dynamic g(int x) => x;
}
class D extends C {
/*=T*/ m/*<T>*/(/*=T*/ x) => x;
/*=T*/ g/*<T>*/(/*=T*/ x) => x;
/*error:INVALID_METHOD_OVERRIDE*/T m<T>(T x) => x;
/*error:INVALID_METHOD_OVERRIDE*/T g<T>(T x) => x;
}
main() {
int y = /*info:DYNAMIC_CAST*/(/*info:UNNECESSARY_CAST*/new D() as C).m(42);

View file

@ -1,5 +1,12 @@
[error] Couldn't infer type parameter 'T'; '_ControllerEventSinkWrapper<dynamic>' must be of type 'EventSink<T>'. (dart:async/stream.dart, line 1346, col 16)
[error] The argument type '_ControllerEventSinkWrapper' can't be assigned to the parameter type 'EventSink<T>'. (dart:async/stream.dart, line 1346, col 53)
[error] A value of type '<R>(Zone, ZoneDelegate, Zone, () → R) → R' can't be assigned to a parameter of type '(Zone, ZoneDelegate, Zone, () → dynamic) → dynamic'. (dart:async/zone.dart, line 1071, col 51)
[error] A value of type '<R,T>(Zone, ZoneDelegate, Zone, (T) → R, T) → R' can't be assigned to a parameter of type '(Zone, ZoneDelegate, Zone, (dynamic) → dynamic, dynamic) → dynamic'. (dart:async/zone.dart, line 1073, col 56)
[error] A value of type '<R,T1,T2>(Zone, ZoneDelegate, Zone, (T1, T2) → R, T1, T2) → R' can't be assigned to a parameter of type '(Zone, ZoneDelegate, Zone, (dynamic, dynamic) → dynamic, dynamic, dynamic) → dynamic'. (dart:async/zone.dart, line 1075, col 57)
[error] A value of type '<R>(Zone, ZoneDelegate, Zone, () → R) → () → R' can't be assigned to a parameter of type '(Zone, ZoneDelegate, Zone, () → dynamic) → () → dynamic'. (dart:async/zone.dart, line 1078, col 23)
[error] A value of type '<R,T>(Zone, ZoneDelegate, Zone, (T) → R) → (T) → R' can't be assigned to a parameter of type '(Zone, ZoneDelegate, Zone, (dynamic) → dynamic) → (dynamic) → dynamic'. (dart:async/zone.dart, line 1081, col 23)
[error] A value of type '<R,T1,T2>(Zone, ZoneDelegate, Zone, (T1, T2) → R) → (T1, T2) → R' can't be assigned to a parameter of type '(Zone, ZoneDelegate, Zone, (dynamic, dynamic) → dynamic) → (dynamic, dynamic) → dynamic'. (dart:async/zone.dart, line 1084, col 23)
[error] A value of type '<R>(Zone, ZoneDelegate, Zone, dynamic, StackTrace) → R' can't be assigned to a parameter of type '(Zone, ZoneDelegate, Zone, dynamic, StackTrace) → dynamic'. (dart:async/zone.dart, line 1100, col 23)
[error] Invalid override. The type of 'ChunkedConverter.bind' ('(dynamic) → dynamic') isn't a subtype of 'Converter<S, T>.bind' ('(Stream<S>) → Stream<T>'). (dart:convert/chunked_conversion.dart, line 14, col 3)
[error] Invalid override. The type of 'ChunkedConverter.bind' ('(dynamic) → dynamic') isn't a subtype of 'StreamTransformer<S, T>.bind' ('(Stream<S>) → Stream<T>'). (dart:convert/chunked_conversion.dart, line 14, col 3)
[error] Invalid override. The type of 'ChunkedConverter.startChunkedConversion' ('(dynamic) → dynamic') isn't a subtype of 'Converter<S, T>.startChunkedConversion' ('(Sink<T>) → Sink<S>'). (dart:convert/chunked_conversion.dart, line 15, col 3)