| Index: pkg/analyzer/test/src/task/strong/inferred_type_test.dart
|
| diff --git a/pkg/analyzer/test/src/task/strong/inferred_type_test.dart b/pkg/analyzer/test/src/task/strong/inferred_type_test.dart
|
| index ae546d5bd34082ff52a9ca1b9438553695659c71..79798808ad6ae847a1a0e2906bf8fb5c657e042d 100644
|
| --- a/pkg/analyzer/test/src/task/strong/inferred_type_test.dart
|
| +++ b/pkg/analyzer/test/src/task/strong/inferred_type_test.dart
|
| @@ -1067,6 +1067,28 @@ void main () {
|
| checkFile('''
|
| void main () {
|
| {
|
| + T f<T>(T x) => null;
|
| + var v1 = f;
|
| + v1 = /*info:INFERRED_TYPE_CLOSURE*/<S>(x) => x;
|
| + }
|
| + {
|
| + List<T> f<T>(T x) => null;
|
| + var v2 = f;
|
| + v2 = /*info:INFERRED_TYPE_CLOSURE*/<S>(x) => /*info:INFERRED_TYPE_LITERAL*/[x];
|
| + Iterable<int> r = v2(42);
|
| + Iterable<String> s = v2('hello');
|
| + Iterable<List<int>> t = v2(<int>[]);
|
| + Iterable<num> u = v2(42);
|
| + Iterable<num> v = v2<num>(42);
|
| + }
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_downwardsInferenceOnFunctionOfTUsingTheT_comment() {
|
| + checkFile('''
|
| +void main () {
|
| + {
|
| /*=T*/ f/*<T>*/(/*=T*/ x) => null;
|
| var v1 = f;
|
| v1 = /*info:INFERRED_TYPE_CLOSURE*//*<S>*/(x) => x;
|
| @@ -1150,6 +1172,53 @@ void main() {
|
| checkFile('''
|
| void main () {
|
| {
|
| + String f<S>(int x) => null;
|
| + var v = f;
|
| + v = /*info:INFERRED_TYPE_CLOSURE*/<T>(int x) => null;
|
| + v = <T>(int x) => "hello";
|
| + v = /*error:INVALID_ASSIGNMENT*/<T>(String x) => "hello";
|
| + v = /*error:INVALID_ASSIGNMENT*/<T>(int x) => 3;
|
| + v = /*info:INFERRED_TYPE_CLOSURE*/<T>(int x) {return /*error:RETURN_OF_INVALID_TYPE*/3;};
|
| + }
|
| + {
|
| + String f<S>(int x) => null;
|
| + var v = f;
|
| + v = /*info:INFERRED_TYPE_CLOSURE, info:INFERRED_TYPE_CLOSURE*/<T>(x) => null;
|
| + v = /*info:INFERRED_TYPE_CLOSURE*/<T>(x) => "hello";
|
| + v = /*info:INFERRED_TYPE_CLOSURE, error:INVALID_ASSIGNMENT*/<T>(x) => 3;
|
| + v = /*info:INFERRED_TYPE_CLOSURE, info:INFERRED_TYPE_CLOSURE*/<T>(x) {return /*error:RETURN_OF_INVALID_TYPE*/3;};
|
| + v = /*info:INFERRED_TYPE_CLOSURE, info:INFERRED_TYPE_CLOSURE*/<T>(x) {return /*error:RETURN_OF_INVALID_TYPE*/x;};
|
| + }
|
| + {
|
| + List<String> f<S>(int x) => null;
|
| + var v = f;
|
| + v = /*info:INFERRED_TYPE_CLOSURE*/<T>(int x) => null;
|
| + v = <T>(int x) => /*info:INFERRED_TYPE_LITERAL*/["hello"];
|
| + v = /*error:INVALID_ASSIGNMENT*/<T>(String x) => /*info:INFERRED_TYPE_LITERAL*/["hello"];
|
| + v = <T>(int x) => /*info:INFERRED_TYPE_LITERAL,error:COULD_NOT_INFER*/[/*error:LIST_ELEMENT_TYPE_NOT_ASSIGNABLE*/3];
|
| + v = /*info:INFERRED_TYPE_CLOSURE*/<T>(int x) {return /*info:INFERRED_TYPE_LITERAL,error:COULD_NOT_INFER*/[/*error:LIST_ELEMENT_TYPE_NOT_ASSIGNABLE*/3];};
|
| + }
|
| + {
|
| + int int2int<S>(int x) => null;
|
| + String int2String<T>(int x) => null;
|
| + String string2String<T>(String x) => null;
|
| + var x = int2int;
|
| + x = /*info:INFERRED_TYPE_CLOSURE*/<T>(x) => x;
|
| + x = /*info:INFERRED_TYPE_CLOSURE*/<T>(x) => x+1;
|
| + var y = int2String;
|
| + y = /*info:INFERRED_TYPE_CLOSURE, error:INVALID_ASSIGNMENT*/<T>(x) => x;
|
| + y = /*info:INFERRED_TYPE_CLOSURE, info:INFERRED_TYPE_CLOSURE*/<T>(x) => /*info:DYNAMIC_INVOKE, info:DYNAMIC_CAST*/x.substring(3);
|
| + var z = string2String;
|
| + z = /*info:INFERRED_TYPE_CLOSURE*/<T>(x) => x.substring(3);
|
| + }
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_downwardsInferenceOnGenericFunctionExpressions_comment() {
|
| + checkFile('''
|
| +void main () {
|
| + {
|
| String f/*<S>*/(int x) => null;
|
| var v = f;
|
| v = /*info:INFERRED_TYPE_CLOSURE*//*<T>*/(int x) => null;
|
| @@ -1537,6 +1606,46 @@ class MyFuture<T> implements Future<T> {
|
| MyFuture() {}
|
| MyFuture.value(T x) {}
|
| dynamic noSuchMethod(invocation);
|
| + MyFuture<S> then<S>(dynamic f(T x), {Function onError}) => null;
|
| +}
|
| +
|
| +void main() {
|
| + $declared f;
|
| + $downwards<int> t1 = f.then((_) async => await new $upwards<int>.value(3));
|
| + $downwards<int> t2 = f.then(/*info:INFERRED_TYPE_CLOSURE*/(_) async {
|
| + return await new $upwards<int>.value(3);});
|
| + $downwards<int> t3 = f.then((_) async => 3);
|
| + $downwards<int> t4 = f.then(/*info:INFERRED_TYPE_CLOSURE*/(_) async {
|
| + return 3;});
|
| + $downwards<int> t5 = f.then((_) => new $upwards<int>.value(3));
|
| + $downwards<int> t6 = f.then(/*info:INFERRED_TYPE_CLOSURE*/(_) {return new $upwards<int>.value(3);});
|
| + $downwards<int> t7 = f.then((_) async => new $upwards<int>.value(3));
|
| + $downwards<int> t8 = f.then(/*info:INFERRED_TYPE_CLOSURE*/(_) async {
|
| + return new $upwards<int>.value(3);});
|
| +}
|
| +''';
|
| +
|
| + checkFile(
|
| + build(declared: "MyFuture", downwards: "Future", upwards: "Future"));
|
| + checkFile(
|
| + build(declared: "MyFuture", downwards: "Future", upwards: "MyFuture"));
|
| + checkFile(
|
| + build(declared: "MyFuture", downwards: "MyFuture", upwards: "Future"));
|
| + checkFile(build(
|
| + declared: "MyFuture", downwards: "MyFuture", upwards: "MyFuture"));
|
| + checkFile(
|
| + build(declared: "Future", downwards: "Future", upwards: "MyFuture"));
|
| + checkFile(
|
| + build(declared: "Future", downwards: "Future", upwards: "Future"));
|
| + }
|
| +
|
| + void test_futureThen_comment() {
|
| + String build({String declared, String downwards, String upwards}) => '''
|
| +import 'dart:async';
|
| +class MyFuture<T> implements Future<T> {
|
| + MyFuture() {}
|
| + MyFuture.value(T x) {}
|
| + dynamic noSuchMethod(invocation);
|
| MyFuture/*<S>*/ then/*<S>*/(dynamic f(T x), {Function onError}) => null;
|
| }
|
|
|
| @@ -1577,6 +1686,42 @@ class MyFuture<T> implements Future<T> {
|
| MyFuture() {}
|
| MyFuture.value(T x) {}
|
| dynamic noSuchMethod(invocation);
|
| + MyFuture<S> then<S>(dynamic f(T x), {Function onError}) => null;
|
| +}
|
| +
|
| +void main() {
|
| + $declared<bool> f;
|
| + $downwards<int> t1 = f.then(/*info:INFERRED_TYPE_CLOSURE*/
|
| + (x) async => x ? 2 : await new $upwards<int>.value(3));
|
| + $downwards<int> t2 = f.then(/*info:INFERRED_TYPE_CLOSURE,info:INFERRED_TYPE_CLOSURE*/(x) async { // TODO(leafp): Why the duplicate here?
|
| + return await x ? 2 : new $upwards<int>.value(3);});
|
| + $downwards<int> t5 = f.then(/*info:INFERRED_TYPE_CLOSURE*/
|
| + (x) => x ? 2 : new $upwards<int>.value(3));
|
| + $downwards<int> t6 = f.then(/*info:INFERRED_TYPE_CLOSURE*/
|
| + (x) {return x ? 2 : new $upwards<int>.value(3);});
|
| +}
|
| +''';
|
| + checkFile(
|
| + build(declared: "MyFuture", downwards: "Future", upwards: "Future"));
|
| + checkFile(
|
| + build(declared: "MyFuture", downwards: "Future", upwards: "MyFuture"));
|
| + checkFile(
|
| + build(declared: "MyFuture", downwards: "MyFuture", upwards: "Future"));
|
| + checkFile(build(
|
| + declared: "MyFuture", downwards: "MyFuture", upwards: "MyFuture"));
|
| + checkFile(
|
| + build(declared: "Future", downwards: "Future", upwards: "MyFuture"));
|
| + checkFile(
|
| + build(declared: "Future", downwards: "Future", upwards: "Future"));
|
| + }
|
| +
|
| + void test_futureThen_conditional_comment() {
|
| + String build({String declared, String downwards, String upwards}) => '''
|
| +import 'dart:async';
|
| +class MyFuture<T> implements Future<T> {
|
| + MyFuture() {}
|
| + MyFuture.value(T x) {}
|
| + dynamic noSuchMethod(invocation);
|
| MyFuture/*<S>*/ then/*<S>*/(dynamic f(T x), {Function onError}) => null;
|
| }
|
|
|
| @@ -1625,6 +1770,17 @@ main() {
|
| import "dart:async";
|
| main() {
|
| Future<int> f;
|
| + var x = f.then<Future<List<int>>>(/*info:INFERRED_TYPE_CLOSURE*/(x) => /*info:INFERRED_TYPE_LITERAL*/[]);
|
| + Future<List<int>> y = x;
|
| +}
|
| + ''');
|
| + }
|
| +
|
| + void test_futureThen_explicitFuture_comment() {
|
| + checkFile(r'''
|
| +import "dart:async";
|
| +main() {
|
| + Future<int> f;
|
| var x = f.then/*<Future<List<int>>>*/(/*info:INFERRED_TYPE_CLOSURE*/(x) => /*info:INFERRED_TYPE_LITERAL*/[]);
|
| Future<List<int>> y = x;
|
| }
|
| @@ -1639,6 +1795,36 @@ class MyFuture<T> implements Future<T> {
|
| MyFuture() {}
|
| MyFuture.value(T x) {}
|
| dynamic noSuchMethod(invocation);
|
| + MyFuture<S> then<S>(dynamic f(T x), {Function onError}) => null;
|
| +}
|
| +
|
| +void main() {
|
| + var f = foo().then((_) => 2.3);
|
| + $downwards<int> f2 = /*error:INVALID_ASSIGNMENT*/f;
|
| +
|
| + // The unnecessary cast is to illustrate that we inferred <double> for
|
| + // the generic type args, even though we had a return type context.
|
| + $downwards<num> f3 = /*info:UNNECESSARY_CAST*/foo().then(
|
| + (_) => 2.3) as $upwards<double>;
|
| +}
|
| +$declared foo() => new $declared<int>.value(1);
|
| + ''';
|
| + checkFile(
|
| + build(declared: "MyFuture", downwards: "Future", upwards: "Future"));
|
| + checkFile(build(
|
| + declared: "MyFuture", downwards: "MyFuture", upwards: "MyFuture"));
|
| + checkFile(
|
| + build(declared: "Future", downwards: "Future", upwards: "Future"));
|
| + }
|
| +
|
| + void test_futureThen_upwards_comment() {
|
| + // Regression test for https://github.com/dart-lang/sdk/issues/27088.
|
| + String build({String declared, String downwards, String upwards}) => '''
|
| +import 'dart:async';
|
| +class MyFuture<T> implements Future<T> {
|
| + MyFuture() {}
|
| + MyFuture.value(T x) {}
|
| + dynamic noSuchMethod(invocation);
|
| MyFuture/*<S>*/ then/*<S>*/(dynamic f(T x), {Function onError}) => null;
|
| }
|
|
|
| @@ -1682,6 +1868,29 @@ class MyFuture<T> implements Future<T> {
|
| MyFuture() {}
|
| MyFuture.value(T x) {}
|
| dynamic noSuchMethod(invocation);
|
| + MyFuture<S> then<S>(dynamic f(T x), {Function onError}) => null;
|
| +}
|
| +
|
| +$downwards<int> g1(bool x) async {
|
| + return x ? 42 : /*info:INFERRED_TYPE_ALLOCATION*/new $upwards.value(42); }
|
| +$downwards<int> g2(bool x) async =>
|
| + x ? 42 : /*info:INFERRED_TYPE_ALLOCATION*/new $upwards.value(42);
|
| +$downwards<int> g3(bool x) async {
|
| + var y = x ? 42 : /*info:INFERRED_TYPE_ALLOCATION*/new $upwards.value(42);
|
| + return y;
|
| +}
|
| + ''';
|
| + checkFile(build(downwards: "Future", upwards: "Future"));
|
| + checkFile(build(downwards: "Future", upwards: "MyFuture"));
|
| + }
|
| +
|
| + void test_futureUnion_asyncConditional_comment() {
|
| + String build({String declared, String downwards, String upwards}) => '''
|
| +import 'dart:async';
|
| +class MyFuture<T> implements Future<T> {
|
| + MyFuture() {}
|
| + MyFuture.value(T x) {}
|
| + dynamic noSuchMethod(invocation);
|
| MyFuture/*<S>*/ then/*<S>*/(dynamic f(T x), {Function onError}) => null;
|
| }
|
|
|
| @@ -1711,6 +1920,48 @@ class MyFuture<T> implements Future<T> {
|
| MyFuture() {}
|
| MyFuture.value([T x]) {}
|
| dynamic noSuchMethod(invocation);
|
| + MyFuture<S> then<S>(dynamic f(T x), {Function onError}) => null;
|
| +}
|
| +
|
| +$declared f;
|
| +// Instantiates Future<int>
|
| +$downwards<int> t1 = f.then((_) =>
|
| + ${allocInfo}new /*error:COULD_NOT_INFER*/$upwards.value(
|
| + /*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/'hi'));
|
| +
|
| +// Instantiates List<int>
|
| +$downwards<List<int>> t2 = f.then((_) => /*info:INFERRED_TYPE_LITERAL*/[3]);
|
| +$downwards<List<int>> g2() async { return /*info:INFERRED_TYPE_LITERAL*/[3]; }
|
| +$downwards<List<int>> g3() async {
|
| + return /*info:INFERRED_TYPE_ALLOCATION*/new $upwards.value(
|
| + /*info:INFERRED_TYPE_LITERAL*/[3]); }
|
| +''';
|
| + }
|
| +
|
| + ;
|
| + checkFile(
|
| + build(declared: "MyFuture", downwards: "Future", upwards: "Future"));
|
| + checkFile(
|
| + build(declared: "MyFuture", downwards: "Future", upwards: "MyFuture"));
|
| + checkFile(
|
| + build(declared: "Future", downwards: "Future", upwards: "Future"));
|
| + checkFile(
|
| + build(declared: "Future", downwards: "Future", upwards: "MyFuture"));
|
| + }
|
| +
|
| + void test_futureUnion_downwards_comment() {
|
| + String build({String declared, String downwards, String upwards}) {
|
| + // TODO(leafp): The use of matchTypes in visitInstanceCreationExpression
|
| + // in the resolver visitor isn't powerful enough to catch this for the
|
| + // subclass. See the TODO there.
|
| + var allocInfo =
|
| + (upwards == "Future") ? "/*info:INFERRED_TYPE_ALLOCATION*/" : "";
|
| + return '''
|
| +import 'dart:async';
|
| +class MyFuture<T> implements Future<T> {
|
| + MyFuture() {}
|
| + MyFuture.value([T x]) {}
|
| + dynamic noSuchMethod(invocation);
|
| MyFuture/*<S>*/ then/*<S>*/(dynamic f(T x), {Function onError}) => null;
|
| }
|
|
|
| @@ -1763,6 +2014,20 @@ class A {}
|
| checkFile(r'''
|
| import 'dart:async';
|
|
|
| +T id<T>(T x) => x;
|
| +
|
| +main() async {
|
| + Future<String> f;
|
| + String s = await id(f);
|
| +}
|
| + ''');
|
| + }
|
| +
|
| + void test_futureUnion_downwardsGenericMethodWithGenericReturn_comment() {
|
| + // Regression test for https://github.com/dart-lang/sdk/issues/27284
|
| + checkFile(r'''
|
| +import 'dart:async';
|
| +
|
| /*=T*/ id/*<T>*/(/*=T*/ x) => x;
|
|
|
| main() async {
|
| @@ -1798,6 +2063,20 @@ class C extends A {}
|
| typedef void ToValue<T>(T value);
|
|
|
| main() {
|
| + ToValue<T> f<T>(T x) => null;
|
| + var x = f<int>(42);
|
| + var y = f(42);
|
| + ToValue<int> takesInt = x;
|
| + takesInt = y;
|
| +}
|
| + ''');
|
| + }
|
| +
|
| + void test_genericFunctions_returnTypedef_comment() {
|
| + checkFile(r'''
|
| +typedef void ToValue<T>(T value);
|
| +
|
| +main() {
|
| ToValue/*<T>*/ f/*<T>*/(dynamic /*=T*/ x) => null;
|
| var x = f/*<int>*/(42);
|
| var y = f(42);
|
| @@ -1809,6 +2088,16 @@ main() {
|
|
|
| void test_genericMethods_basicDownwardInference() {
|
| checkFile(r'''
|
| +T f<S, T>(S s) => null;
|
| +main() {
|
| + String x = f(42);
|
| + String y = (f)(42);
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_genericMethods_basicDownwardInference_comment() {
|
| + checkFile(r'''
|
| /*=T*/ f/*<S, T>*/(/*=S*/ s) => null;
|
| main() {
|
| String x = f(42);
|
| @@ -1821,6 +2110,28 @@ main() {
|
| // Regression test for https://github.com/dart-lang/sdk/issues/25740.
|
| checkFile(r'''
|
| class Foo<T extends Pattern> {
|
| + U method<U extends T>(U u) => u;
|
| +}
|
| +main() {
|
| + String s;
|
| + var a = new Foo().method<String>("str");
|
| + s = a;
|
| + new Foo();
|
| +
|
| + var b = new Foo<String>().method("str");
|
| + s = b;
|
| + var c = new Foo().method("str");
|
| + s = c;
|
| +
|
| + new Foo<String>()./*error:COULD_NOT_INFER*/method(/*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/42);
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_genericMethods_correctlyRecognizeGenericUpperBound_comment() {
|
| + // Regression test for https://github.com/dart-lang/sdk/issues/25740.
|
| + checkFile(r'''
|
| +class Foo<T extends Pattern> {
|
| /*=U*/ method/*<U extends T>*/(/*=U*/ u) => u;
|
| }
|
| main() {
|
| @@ -1877,6 +2188,21 @@ main() {
|
| void test_genericMethods_doNotInferInvalidOverrideOfGenericMethod() {
|
| checkFile('''
|
| class C {
|
| +T m<T>(T x) => x;
|
| +}
|
| +class D extends C {
|
| +/*error:INVALID_METHOD_OVERRIDE*/m(x) => x;
|
| +}
|
| +main() {
|
| + int y = /*info:DYNAMIC_CAST*/new D()./*error:WRONG_NUMBER_OF_TYPE_ARGUMENTS_METHOD*/m<int>(42);
|
| + print(y);
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_genericMethods_doNotInferInvalidOverrideOfGenericMethod_comment() {
|
| + checkFile('''
|
| +class C {
|
| /*=T*/ m/*<T>*/(/*=T*/ x) => x;
|
| }
|
| class D extends C {
|
| @@ -1891,6 +2217,16 @@ main() {
|
|
|
| void test_genericMethods_downwardsInferenceAffectsArguments() {
|
| checkFile(r'''
|
| +T f<T>(List<T> s) => null;
|
| +main() {
|
| + String x = f(/*info:INFERRED_TYPE_LITERAL*/['hi']);
|
| + String y = f(/*info:INFERRED_TYPE_LITERAL,error:COULD_NOT_INFER*/[/*error:LIST_ELEMENT_TYPE_NOT_ASSIGNABLE*/42]);
|
| +}
|
| +''');
|
| + }
|
| +
|
| + void test_genericMethods_downwardsInferenceAffectsArguments_comment() {
|
| + checkFile(r'''
|
| /*=T*/ f/*<T>*/(List/*<T>*/ s) => null;
|
| main() {
|
| String x = f(/*info:INFERRED_TYPE_LITERAL*/['hi']);
|
| @@ -1927,6 +2263,24 @@ 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;
|
| }
|
| @@ -1949,10 +2303,10 @@ main() {
|
| void test_genericMethods_inferGenericFunctionParameterType() {
|
| var mainUnit = checkFile('''
|
| class C<T> extends D<T> {
|
| - f/*<U>*/(x) {}
|
| + f<U>(x) {}
|
| }
|
| class D<T> {
|
| - F/*<U>*/ f/*<U>*/(/*=U*/ u) => null;
|
| + F<U> f<U>(U u) => null;
|
| }
|
| typedef void F<V>(V v);
|
| ''');
|
| @@ -1963,6 +2317,20 @@ typedef void F<V>(V v);
|
| void test_genericMethods_inferGenericFunctionParameterType2() {
|
| var mainUnit = checkFile('''
|
| class C<T> extends D<T> {
|
| + f<U>(g) => null;
|
| +}
|
| +abstract class D<T> {
|
| + void f<U>(G<U> g);
|
| +}
|
| +typedef List<V> G<V>();
|
| +''');
|
| + var f = mainUnit.getType('C').methods[0];
|
| + expect(f.type.toString(), '<U>(() → List<U>) → void');
|
| + }
|
| +
|
| + void test_genericMethods_inferGenericFunctionParameterType2_comment() {
|
| + var mainUnit = checkFile('''
|
| +class C<T> extends D<T> {
|
| f/*<U>*/(g) => null;
|
| }
|
| abstract class D<T> {
|
| @@ -1974,21 +2342,139 @@ typedef List<V> G<V>();
|
| expect(f.type.toString(), '<U>(() → List<U>) → void');
|
| }
|
|
|
| + void test_genericMethods_inferGenericFunctionParameterType_comment() {
|
| + var mainUnit = checkFile('''
|
| +class C<T> extends D<T> {
|
| + f/*<U>*/(x) {}
|
| +}
|
| +class D<T> {
|
| + F/*<U>*/ f/*<U>*/(/*=U*/ u) => null;
|
| +}
|
| +typedef void F<V>(V v);
|
| +''');
|
| + var f = mainUnit.getType('C').methods[0];
|
| + expect(f.type.toString(), '<U>(U) → (U) → void');
|
| + }
|
| +
|
| void test_genericMethods_inferGenericFunctionReturnType() {
|
| var mainUnit = checkFile('''
|
| class C<T> extends D<T> {
|
| + f<U>(x) {}
|
| +}
|
| +class D<T> {
|
| + F<U> f<U>(U u) => null;
|
| +}
|
| +typedef V F<V>();
|
| +''');
|
| + var f = mainUnit.getType('C').methods[0];
|
| + expect(f.type.toString(), '<U>(U) → () → U');
|
| + }
|
| +
|
| + void test_genericMethods_inferGenericFunctionReturnType_comment() {
|
| + var mainUnit = checkFile('''
|
| +class C<T> extends D<T> {
|
| f/*<U>*/(x) {}
|
| }
|
| class D<T> {
|
| F/*<U>*/ f/*<U>*/(/*=U*/ u) => null;
|
| }
|
| -typedef V F<V>();
|
| +typedef V F<V>();
|
| +''');
|
| + var f = mainUnit.getType('C').methods[0];
|
| + expect(f.type.toString(), '<U>(U) → () → U');
|
| + }
|
| +
|
| + void test_genericMethods_inferGenericInstantiation() {
|
| + checkFile('''
|
| +import 'dart:math' as math;
|
| +import 'dart:math' show min;
|
| +
|
| +class C {
|
| +T m<T extends num>(T x, T y) => null;
|
| +}
|
| +
|
| +main() {
|
| +takeIII(math.max);
|
| +takeDDD(math.max);
|
| +takeNNN(math.max);
|
| +takeIDN(math.max);
|
| +takeDIN(math.max);
|
| +takeIIN(math.max);
|
| +takeDDN(math.max);
|
| +takeIIO(math.max);
|
| +takeDDO(math.max);
|
| +
|
| +takeOOI(/*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/math.max);
|
| +takeIDI(/*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/math.max);
|
| +takeDID(/*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/math.max);
|
| +takeOON(/*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/math.max);
|
| +takeOOO(/*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/math.max);
|
| +
|
| +// Also test SimpleIdentifier
|
| +takeIII(min);
|
| +takeDDD(min);
|
| +takeNNN(min);
|
| +takeIDN(min);
|
| +takeDIN(min);
|
| +takeIIN(min);
|
| +takeDDN(min);
|
| +takeIIO(min);
|
| +takeDDO(min);
|
| +
|
| +takeOOI(/*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/min);
|
| +takeIDI(/*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/min);
|
| +takeDID(/*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/min);
|
| +takeOON(/*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/min);
|
| +takeOOO(/*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/min);
|
| +
|
| +// Also PropertyAccess
|
| +takeIII(new C().m);
|
| +takeDDD(new C().m);
|
| +takeNNN(new C().m);
|
| +takeIDN(new C().m);
|
| +takeDIN(new C().m);
|
| +takeIIN(new C().m);
|
| +takeDDN(new C().m);
|
| +takeIIO(new C().m);
|
| +takeDDO(new C().m);
|
| +
|
| +// Note: this is a warning because a downcast of a method tear-off could work
|
| +// (derived method can be a subtype):
|
| +//
|
| +// class D extends C {
|
| +// S m<S extends num>(Object x, Object y);
|
| +// }
|
| +//
|
| +// That's legal because we're loosening parameter types.
|
| +//
|
| +takeOON(/*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/new C().m);
|
| +takeOOO(/*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/new C().m);
|
| +
|
| +// Note: this is a warning because a downcast of a method tear-off could work
|
| +// in "normal" Dart, due to bivariance.
|
| +takeOOI(/*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/new C().m);
|
| +takeIDI(/*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/new C().m);
|
| +takeDID(/*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/new C().m);
|
| +}
|
| +
|
| +void takeIII(int fn(int a, int b)) {}
|
| +void takeDDD(double fn(double a, double b)) {}
|
| +void takeIDI(int fn(double a, int b)) {}
|
| +void takeDID(double fn(int a, double b)) {}
|
| +void takeIDN(num fn(double a, int b)) {}
|
| +void takeDIN(num fn(int a, double b)) {}
|
| +void takeIIN(num fn(int a, int b)) {}
|
| +void takeDDN(num fn(double a, double b)) {}
|
| +void takeNNN(num fn(num a, num b)) {}
|
| +void takeOON(num fn(Object a, Object b)) {}
|
| +void takeOOO(num fn(Object a, Object b)) {}
|
| +void takeOOI(int fn(Object a, Object b)) {}
|
| +void takeIIO(Object fn(int a, int b)) {}
|
| +void takeDDO(Object fn(double a, double b)) {}
|
| ''');
|
| - var f = mainUnit.getType('C').methods[0];
|
| - expect(f.type.toString(), '<U>(U) → () → U');
|
| }
|
|
|
| - void test_genericMethods_inferGenericInstantiation() {
|
| + void test_genericMethods_inferGenericInstantiation_comment() {
|
| checkFile('''
|
| import 'dart:math' as math;
|
| import 'dart:math' show min;
|
| @@ -2082,6 +2568,22 @@ void takeDDO(Object fn(double a, double b)) {}
|
| // Regression test for https://github.com/dart-lang/sdk/issues/25668
|
| checkFile('''
|
| class C {
|
| + T m<T>(T x) => x;
|
| +}
|
| +class D extends C {
|
| + m<S>(x) => x;
|
| +}
|
| +main() {
|
| + int y = new D().m<int>(42);
|
| + print(y);
|
| +}
|
| + ''');
|
| + }
|
| +
|
| + void test_genericMethods_inferGenericMethodType_comment() {
|
| + // Regression test for https://github.com/dart-lang/sdk/issues/25668
|
| + checkFile('''
|
| +class C {
|
| /*=T*/ m/*<T>*/(/*=T*/ x) => x;
|
| }
|
| class D extends C {
|
| @@ -2128,6 +2630,19 @@ main() {
|
| typedef Iterable<num> F(int x);
|
| typedef List<int> G(double x);
|
|
|
| +T generic<T>(a(T _), b(T _)) => null;
|
| +
|
| +var v = generic((F f) => null, (G g) => null);
|
| +''');
|
| + var v = mainUnit.topLevelVariables[0];
|
| + expect(v.type.toString(), '(num) → List<int>');
|
| + }
|
| +
|
| + void test_genericMethods_usesGreatestLowerBound_comment() {
|
| + var mainUnit = checkFile(r'''
|
| +typedef Iterable<num> F(int x);
|
| +typedef List<int> G(double x);
|
| +
|
| /*=T*/ generic/*<T>*/(a(/*=T*/ _), b(/*=T*/ _)) => null;
|
|
|
| var v = generic((F f) => null, (G g) => null);
|
| @@ -2712,6 +3227,16 @@ test1() {
|
| void test_inferGenericMethodType_named() {
|
| var unit = checkFile('''
|
| class C {
|
| + T m<T>(int a, {String b, T c}) => null;
|
| +}
|
| +var y = new C().m(1, b: 'bbb', c: 2.0);
|
| + ''');
|
| + expect(unit.topLevelVariables[0].type.toString(), 'double');
|
| + }
|
| +
|
| + void test_inferGenericMethodType_named_comment() {
|
| + var unit = checkFile('''
|
| +class C {
|
| /*=T*/ m/*<T>*/(int a, {String b, /*=T*/ c}) => null;
|
| }
|
| var y = new C().m(1, b: 'bbb', c: 2.0);
|
| @@ -2722,7 +3247,7 @@ var y = new C().m(1, b: 'bbb', c: 2.0);
|
| void test_inferGenericMethodType_positional() {
|
| var unit = checkFile('''
|
| class C {
|
| - /*=T*/ m/*<T>*/(int a, [/*=T*/ b]) => null;
|
| + T m<T>(int a, [T b]) => null;
|
| }
|
| var y = new C().m(1, 2.0);
|
| ''');
|
| @@ -2732,6 +3257,16 @@ var y = new C().m(1, 2.0);
|
| void test_inferGenericMethodType_positional2() {
|
| var unit = checkFile('''
|
| class C {
|
| + T m<T>(int a, [String b, T c]) => null;
|
| +}
|
| +var y = new C().m(1, 'bbb', 2.0);
|
| + ''');
|
| + expect(unit.topLevelVariables[0].type.toString(), 'double');
|
| + }
|
| +
|
| + void test_inferGenericMethodType_positional2_comment() {
|
| + var unit = checkFile('''
|
| +class C {
|
| /*=T*/ m/*<T>*/(int a, [String b, /*=T*/ c]) => null;
|
| }
|
| var y = new C().m(1, 'bbb', 2.0);
|
| @@ -2739,9 +3274,29 @@ var y = new C().m(1, 'bbb', 2.0);
|
| expect(unit.topLevelVariables[0].type.toString(), 'double');
|
| }
|
|
|
| + void test_inferGenericMethodType_positional_comment() {
|
| + var unit = checkFile('''
|
| +class C {
|
| + /*=T*/ m/*<T>*/(int a, [/*=T*/ b]) => null;
|
| +}
|
| +var y = new C().m(1, 2.0);
|
| + ''');
|
| + expect(unit.topLevelVariables[0].type.toString(), 'double');
|
| + }
|
| +
|
| void test_inferGenericMethodType_required() {
|
| var unit = checkFile('''
|
| class C {
|
| + T m<T>(T x) => x;
|
| +}
|
| +var y = new C().m(42);
|
| + ''');
|
| + expect(unit.topLevelVariables[0].type.toString(), 'int');
|
| + }
|
| +
|
| + void test_inferGenericMethodType_required_comment() {
|
| + var unit = checkFile('''
|
| +class C {
|
| /*=T*/ m/*<T>*/(/*=T*/ x) => x;
|
| }
|
| var y = new C().m(42);
|
| @@ -3958,6 +4513,18 @@ var x = { null: null };
|
| void test_methodCall_withTypeArguments_instanceMethod() {
|
| var mainUnit = checkFile('''
|
| class C {
|
| + D<T> f<T>() => null;
|
| +}
|
| +class D<T> {}
|
| +var f = new C().f<int>();
|
| +''');
|
| + var v = mainUnit.topLevelVariables[0];
|
| + expect(v.type.toString(), 'D<int>');
|
| + }
|
| +
|
| + void test_methodCall_withTypeArguments_instanceMethod_comment() {
|
| + var mainUnit = checkFile('''
|
| +class C {
|
| D/*<T>*/ f/*<T>*/() => null;
|
| }
|
| class D<T> {}
|
| @@ -3970,6 +4537,21 @@ var f = new C().f/*<int>*/();
|
| void test_methodCall_withTypeArguments_instanceMethod_identifierSequence() {
|
| var mainUnit = checkFile('''
|
| class C {
|
| + D<T> f<T>() => null;
|
| +}
|
| +class D<T> {}
|
| +C c;
|
| +var f = c.f<int>();
|
| +''');
|
| + var v = mainUnit.topLevelVariables[1];
|
| + expect(v.name, 'f');
|
| + expect(v.type.toString(), 'D<int>');
|
| + }
|
| +
|
| + void
|
| + test_methodCall_withTypeArguments_instanceMethod_identifierSequence_comment() {
|
| + var mainUnit = checkFile('''
|
| +class C {
|
| D/*<T>*/ f/*<T>*/() => null;
|
| }
|
| class D<T> {}
|
| @@ -3984,6 +4566,18 @@ var f = c.f/*<int>*/();
|
| void test_methodCall_withTypeArguments_staticMethod() {
|
| var mainUnit = checkFile('''
|
| class C {
|
| + static D<T> f<T>() => null;
|
| +}
|
| +class D<T> {}
|
| +var f = C.f<int>();
|
| +''');
|
| + var v = mainUnit.topLevelVariables[0];
|
| + expect(v.type.toString(), 'D<int>');
|
| + }
|
| +
|
| + void test_methodCall_withTypeArguments_staticMethod_comment() {
|
| + var mainUnit = checkFile('''
|
| +class C {
|
| static D/*<T>*/ f/*<T>*/() => null;
|
| }
|
| class D<T> {}
|
| @@ -3995,6 +4589,16 @@ var f = C.f/*<int>*/();
|
|
|
| void test_methodCall_withTypeArguments_topLevelFunction() {
|
| var mainUnit = checkFile('''
|
| +D<T> f<T>() => null;
|
| +class D<T> {}
|
| +var g = f<int>();
|
| +''');
|
| + var v = mainUnit.topLevelVariables[0];
|
| + expect(v.type.toString(), 'D<int>');
|
| + }
|
| +
|
| + void test_methodCall_withTypeArguments_topLevelFunction_comment() {
|
| + var mainUnit = checkFile('''
|
| D/*<T>*/ f/*<T>*/() => null;
|
| class D<T> {}
|
| var g = f/*<int>*/();
|
| @@ -4381,6 +4985,17 @@ var v = new C(/*info:INFERRED_TYPE_CLOSURE*/() { return 1; });
|
|
|
| void test_unsafeBlockClosureInference_functionCall_explicitDynamicParam() {
|
| var mainUnit = checkFile('''
|
| +List<T> f<T>(T g()) => <T>[g()];
|
| +var v = f<dynamic>(/*info:INFERRED_TYPE_CLOSURE*/() { return 1; });
|
| +''');
|
| + var v = mainUnit.topLevelVariables[0];
|
| + expect(v.name, 'v');
|
| + expect(v.type.toString(), 'List<dynamic>');
|
| + }
|
| +
|
| + void
|
| + test_unsafeBlockClosureInference_functionCall_explicitDynamicParam_comment() {
|
| + var mainUnit = checkFile('''
|
| dynamic /*=List<T>*/ f/*<T>*/(dynamic/*=T*/ g()) => <T>[g()];
|
| var v = f/*<dynamic>*/(/*info:INFERRED_TYPE_CLOSURE*/() { return 1; });
|
| ''');
|
| @@ -4395,6 +5010,20 @@ var v = f/*<dynamic>*/(/*info:INFERRED_TYPE_CLOSURE*/() { return 1; });
|
| // Note: (f/*<dynamic>*/) is nort properly resulting in an instantiated
|
| // function type due to dartbug.com/25824.
|
| var mainUnit = checkFile('''
|
| +List<T> f<T>(T g()) => <T>[g()];
|
| +var v = (f<dynamic>)(/*info:INFERRED_TYPE_CLOSURE*/() { return 1; });
|
| +''');
|
| + var v = mainUnit.topLevelVariables[0];
|
| + expect(v.name, 'v');
|
| + expect(v.type.toString(), 'List<dynamic>');
|
| + }
|
| +
|
| + @failingTest
|
| + void
|
| + test_unsafeBlockClosureInference_functionCall_explicitDynamicParam_viaExpr1_comment() {
|
| + // Note: (f/*<dynamic>*/) is nort properly resulting in an instantiated
|
| + // function type due to dartbug.com/25824.
|
| + var mainUnit = checkFile('''
|
| dynamic /*=List<T>*/ f/*<T>*/(dynamic/*=T*/ g()) => <T>[g()];
|
| var v = (f/*<dynamic>*/)(/*info:INFERRED_TYPE_CLOSURE*/() { return 1; });
|
| ''');
|
| @@ -4406,6 +5035,17 @@ var v = (f/*<dynamic>*/)(/*info:INFERRED_TYPE_CLOSURE*/() { return 1; });
|
| void
|
| test_unsafeBlockClosureInference_functionCall_explicitDynamicParam_viaExpr2() {
|
| var mainUnit = checkFile('''
|
| +List<T> f<T>(T g()) => <T>[g()];
|
| +var v = (f)<dynamic>(/*info:INFERRED_TYPE_CLOSURE*/() { return 1; });
|
| +''');
|
| + var v = mainUnit.topLevelVariables[0];
|
| + expect(v.name, 'v');
|
| + expect(v.type.toString(), 'List<dynamic>');
|
| + }
|
| +
|
| + void
|
| + test_unsafeBlockClosureInference_functionCall_explicitDynamicParam_viaExpr2_comment() {
|
| + var mainUnit = checkFile('''
|
| dynamic /*=List<T>*/ f/*<T>*/(dynamic/*=T*/ g()) => <T>[g()];
|
| var v = (f)/*<dynamic>*/(/*info:INFERRED_TYPE_CLOSURE*/() { return 1; });
|
| ''');
|
| @@ -4416,6 +5056,17 @@ var v = (f)/*<dynamic>*/(/*info:INFERRED_TYPE_CLOSURE*/() { return 1; });
|
|
|
| void test_unsafeBlockClosureInference_functionCall_explicitTypeParam() {
|
| var mainUnit = checkFile('''
|
| +List<T> f<T>(T g()) => <T>[g()];
|
| +var v = f<int>(/*info:INFERRED_TYPE_CLOSURE*/() { return 1; });
|
| +''');
|
| + var v = mainUnit.topLevelVariables[0];
|
| + expect(v.name, 'v');
|
| + expect(v.type.toString(), 'List<int>');
|
| + }
|
| +
|
| + void
|
| + test_unsafeBlockClosureInference_functionCall_explicitTypeParam_comment() {
|
| + var mainUnit = checkFile('''
|
| dynamic /*=List<T>*/ f/*<T>*/(dynamic/*=T*/ g()) => <T>[g()];
|
| var v = f/*<int>*/(/*info:INFERRED_TYPE_CLOSURE*/() { return 1; });
|
| ''');
|
| @@ -4430,6 +5081,20 @@ var v = f/*<int>*/(/*info:INFERRED_TYPE_CLOSURE*/() { return 1; });
|
| // TODO(paulberry): for some reason (f/*<int>) is nort properly resulting
|
| // in an instantiated function type.
|
| var mainUnit = checkFile('''
|
| +List<T> f<T>(T g()) => <T>[g()];
|
| +var v = (f/int>)(/*info:INFERRED_TYPE_CLOSURE*/() { return 1; });
|
| +''');
|
| + var v = mainUnit.topLevelVariables[0];
|
| + expect(v.name, 'v');
|
| + expect(v.type.toString(), 'List<int>');
|
| + }
|
| +
|
| + @failingTest
|
| + void
|
| + test_unsafeBlockClosureInference_functionCall_explicitTypeParam_viaExpr1_comment() {
|
| + // TODO(paulberry): for some reason (f/*<int>) is nort properly resulting
|
| + // in an instantiated function type.
|
| + var mainUnit = checkFile('''
|
| dynamic /*=List<T>*/ f/*<T>*/(dynamic/*=T*/ g()) => <T>[g()];
|
| var v = (f/*<int>*/)(/*info:INFERRED_TYPE_CLOSURE*/() { return 1; });
|
| ''');
|
| @@ -4441,6 +5106,17 @@ var v = (f/*<int>*/)(/*info:INFERRED_TYPE_CLOSURE*/() { return 1; });
|
| void
|
| test_unsafeBlockClosureInference_functionCall_explicitTypeParam_viaExpr2() {
|
| var mainUnit = checkFile('''
|
| +List<T> f<T>(T g()) => <T>[g()];
|
| +var v = (f)<int>(/*info:INFERRED_TYPE_CLOSURE*/() { return 1; });
|
| +''');
|
| + var v = mainUnit.topLevelVariables[0];
|
| + expect(v.name, 'v');
|
| + expect(v.type.toString(), 'List<int>');
|
| + }
|
| +
|
| + void
|
| + test_unsafeBlockClosureInference_functionCall_explicitTypeParam_viaExpr2_comment() {
|
| + var mainUnit = checkFile('''
|
| dynamic /*=List<T>*/ f/*<T>*/(dynamic/*=T*/ g()) => <T>[g()];
|
| var v = (f)/*<int>*/(/*info:INFERRED_TYPE_CLOSURE*/() { return 1; });
|
| ''');
|
| @@ -4451,6 +5127,20 @@ var v = (f)/*<int>*/(/*info:INFERRED_TYPE_CLOSURE*/() { return 1; });
|
|
|
| void test_unsafeBlockClosureInference_functionCall_implicitTypeParam() {
|
| var mainUnit = checkFile('''
|
| +List<T> f<T>(T g()) => <T>[g()];
|
| +var v = f(
|
| + /*info:INFERRED_TYPE_CLOSURE,warning:UNSAFE_BLOCK_CLOSURE_INFERENCE*/() {
|
| + return 1;
|
| + });
|
| +''');
|
| + var v = mainUnit.topLevelVariables[0];
|
| + expect(v.name, 'v');
|
| + expect(v.type.toString(), 'List<int>');
|
| + }
|
| +
|
| + void
|
| + test_unsafeBlockClosureInference_functionCall_implicitTypeParam_comment() {
|
| + var mainUnit = checkFile('''
|
| dynamic /*=List<T>*/ f/*<T>*/(dynamic/*=T*/ g()) => <T>[g()];
|
| var v = f(
|
| /*info:INFERRED_TYPE_CLOSURE,warning:UNSAFE_BLOCK_CLOSURE_INFERENCE*/() {
|
| @@ -4465,6 +5155,20 @@ var v = f(
|
| void
|
| test_unsafeBlockClosureInference_functionCall_implicitTypeParam_viaExpr() {
|
| var mainUnit = checkFile('''
|
| +List<T> f<T>(T g()) => <T>[g()];
|
| +var v = (f)(
|
| + /*info:INFERRED_TYPE_CLOSURE,warning:UNSAFE_BLOCK_CLOSURE_INFERENCE*/() {
|
| + return 1;
|
| + });
|
| +''');
|
| + var v = mainUnit.topLevelVariables[0];
|
| + expect(v.name, 'v');
|
| + expect(v.type.toString(), 'List<int>');
|
| + }
|
| +
|
| + void
|
| + test_unsafeBlockClosureInference_functionCall_implicitTypeParam_viaExpr_comment() {
|
| + var mainUnit = checkFile('''
|
| dynamic /*=List<T>*/ f/*<T>*/(dynamic/*=T*/ g()) => <T>[g()];
|
| var v = (f)(
|
| /*info:INFERRED_TYPE_CLOSURE,warning:UNSAFE_BLOCK_CLOSURE_INFERENCE*/() {
|
| @@ -4561,6 +5265,19 @@ var v = /*info:INFERRED_TYPE_LITERAL*/{
|
| void test_unsafeBlockClosureInference_methodCall_explicitDynamicParam() {
|
| var mainUnit = checkFile('''
|
| class C {
|
| + List<T> f<T>(T g()) => <T>[g()];
|
| +}
|
| +var v = new C().f<dynamic>(/*info:INFERRED_TYPE_CLOSURE*/() { return 1; });
|
| +''');
|
| + var v = mainUnit.topLevelVariables[0];
|
| + expect(v.name, 'v');
|
| + expect(v.type.toString(), 'List<dynamic>');
|
| + }
|
| +
|
| + void
|
| + test_unsafeBlockClosureInference_methodCall_explicitDynamicParam_comment() {
|
| + var mainUnit = checkFile('''
|
| +class C {
|
| dynamic /*=List<T>*/ f/*<T>*/(dynamic/*=T*/ g()) => <T>[g()];
|
| }
|
| var v = new C().f/*<dynamic>*/(/*info:INFERRED_TYPE_CLOSURE*/() { return 1; });
|
| @@ -4573,6 +5290,18 @@ var v = new C().f/*<dynamic>*/(/*info:INFERRED_TYPE_CLOSURE*/() { return 1; });
|
| void test_unsafeBlockClosureInference_methodCall_explicitTypeParam() {
|
| var mainUnit = checkFile('''
|
| class C {
|
| + List<T> f<T>(T g()) => <T>[g()];
|
| +}
|
| +var v = new C().f<int>(/*info:INFERRED_TYPE_CLOSURE*/() { return 1; });
|
| +''');
|
| + var v = mainUnit.topLevelVariables[0];
|
| + expect(v.name, 'v');
|
| + expect(v.type.toString(), 'List<int>');
|
| + }
|
| +
|
| + void test_unsafeBlockClosureInference_methodCall_explicitTypeParam_comment() {
|
| + var mainUnit = checkFile('''
|
| +class C {
|
| dynamic /*=List<T>*/ f/*<T>*/(dynamic/*=T*/ g()) => <T>[g()];
|
| }
|
| var v = new C().f/*<int>*/(/*info:INFERRED_TYPE_CLOSURE*/() { return 1; });
|
| @@ -4585,6 +5314,21 @@ var v = new C().f/*<int>*/(/*info:INFERRED_TYPE_CLOSURE*/() { return 1; });
|
| void test_unsafeBlockClosureInference_methodCall_implicitTypeParam() {
|
| var mainUnit = checkFile('''
|
| class C {
|
| + List<T> f<T>(T g()) => <T>[g()];
|
| +}
|
| +var v = new C().f(
|
| + /*info:INFERRED_TYPE_CLOSURE,warning:UNSAFE_BLOCK_CLOSURE_INFERENCE*/() {
|
| + return 1;
|
| + });
|
| +''');
|
| + var v = mainUnit.topLevelVariables[0];
|
| + expect(v.name, 'v');
|
| + expect(v.type.toString(), 'List<int>');
|
| + }
|
| +
|
| + void test_unsafeBlockClosureInference_methodCall_implicitTypeParam_comment() {
|
| + var mainUnit = checkFile('''
|
| +class C {
|
| dynamic /*=List<T>*/ f/*<T>*/(dynamic/*=T*/ g()) => <T>[g()];
|
| }
|
| var v = new C().f(
|
| @@ -4611,6 +5355,37 @@ var v = new C().f(/*info:INFERRED_TYPE_CLOSURE*/() { return 1; });
|
|
|
| void test_voidReturnTypeSubtypesDynamic() {
|
| var unit = checkFile(r'''
|
| +T run<T>(T f()) {
|
| + print("running");
|
| + var t = f();
|
| + print("done running");
|
| + return t;
|
| +}
|
| +
|
| +
|
| +void printRunning() { print("running"); }
|
| +var x = run<dynamic>(printRunning);
|
| +var y = run(printRunning);
|
| +
|
| +main() {
|
| + void printRunning() { print("running"); }
|
| + var x = run<dynamic>(printRunning);
|
| + var y = run(printRunning);
|
| + x = 123;
|
| + x = 'hi';
|
| + y = 123;
|
| + y = 'hi';
|
| +}
|
| + ''');
|
| +
|
| + var x = unit.topLevelVariables[0];
|
| + var y = unit.topLevelVariables[1];
|
| + expect(x.type.toString(), 'dynamic');
|
| + expect(y.type.toString(), 'dynamic');
|
| + }
|
| +
|
| + void test_voidReturnTypeSubtypesDynamic_comment() {
|
| + var unit = checkFile(r'''
|
| /*=T*/ run/*<T>*/(/*=T*/ f()) {
|
| print("running");
|
| var t = f();
|
|
|