fix #34296, generic function instantiation should be checked eagerly

Change-Id: I8c6e0980c23d8ca2cb22db9411028b59be5eb8db
Reviewed-on: https://dart-review.googlesource.com/72545
Reviewed-by: Vijay Menon <vsm@google.com>
Commit-Queue: Jenny Messerly <jmesserly@google.com>
This commit is contained in:
Jenny Messerly 2018-09-07 21:34:36 +00:00 committed by commit-bot@chromium.org
parent cd3ddede99
commit be5cd6307f
3 changed files with 20 additions and 11 deletions

View file

@ -82,12 +82,14 @@ bindCall(obj, name) {
///
/// We need to apply the type arguments both to the function, as well as its
/// associated function type.
gbind(f, @rest typeArgs) {
gbind(f, @rest List typeArgs) {
GenericFunctionType type = JS('!', '#[#]', f, _runtimeType);
type.checkBounds(typeArgs);
// Create a JS wrapper function that will also pass the type arguments, and
// tag it with the instantiated function type.
var result =
JS('', '(...args) => #.apply(null, #.concat(args))', f, typeArgs);
var sig = JS('', '#[#].instantiate(#)', f, _runtimeType, typeArgs);
fn(result, sig);
return result;
return fn(result, type.instantiate(typeArgs));
}
dloadRepl(obj, field) => dload(obj, replNameLookup(obj, field), false);

View file

@ -536,7 +536,13 @@ class GenericFunctionType extends AbstractFunctionType {
return _typeFormals = _typeFormalsFromFunction(_instantiateTypeParts);
}
checkBounds(List typeArgs) {
/// Checks that [typeArgs] satisfies the upper bounds of the [typeFormals],
/// and throws a [TypeError] if they do not.
void checkBounds(List typeArgs) {
// If we don't have explicit type parameter bounds, the bounds default to
// a top type, so there's nothing to check here.
if (_instantiateTypeBounds == null) return;
var bounds = instantiateTypeBounds(typeArgs);
var typeFormals = this.typeFormals;
for (var i = 0; i < typeArgs.length; i++) {
@ -554,11 +560,12 @@ class GenericFunctionType extends AbstractFunctionType {
var boundsFn = _instantiateTypeBounds;
if (boundsFn == null) {
// The Dart 1 spec says omitted type parameters have an upper bound of
// Object. However strong mode assumes `dynamic` for all purposes
// (such as instantiate to bounds) so we use that here.
// Object. However Dart 2 uses `dynamic` for the purpose of instantiate to
// bounds, so we use that here.
return List.filled(formalCount, _dynamic);
}
// If bounds are recursive, we need to apply type formals and return them.
// Bounds can be recursive or depend on other type parameters, so we need to
// apply type arguments and return the resulting bounds.
return JS('List', '#.apply(null, #)', boundsFn, typeArgs);
}
@ -738,10 +745,11 @@ getFunctionTypeMirror(AbstractFunctionType type) {
bool isType(obj) => JS('', '#[#] === #', obj, _runtimeType, Type);
void checkTypeBound(type, bound, name) {
// TODO(jmesserly): we've optimized `is`/`as`/implicit type checks, it would
// be nice to have similar optimizations for the subtype relation.
if (JS('!', '#', isSubtype(type, bound))) return;
throwTypeError('type `$type` does not extend `$bound`'
' of `$name`.');
throwTypeError('type `$type` does not extend `$bound` of `$name`.');
}
String typeName(type) => JS('', '''(() => {

View file

@ -476,7 +476,6 @@ number_identity2_test: RuntimeError # Issue 29920; Expect.isTrue(false) fails.
number_identity_test: CompileTimeError, OK # Error if web int literal cannot be represented exactly, see http://dartbug.com/33351
numbers_test: RuntimeError # Issue 29920; Expect.equals(expected: <false>, actual: <true>) fails.
parser_quirks_test: CompileTimeError
partial_instantiation_eager_bounds_check_test: RuntimeError # Issue 34296
regress_16640_test: RuntimeError # Issue 29920; Uncaught Error: type arguments should not be null: E => {
regress_22443_test: RuntimeError # Uncaught Expect.isTrue(false) fails.
stack_overflow_stacktrace_test: RuntimeError # Issue 29920; RangeError: Maximum call stack size exceeded