Chromium Code Reviews| 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 663ee78c3cde942090a4776e3015e8d81a952595..46e44000f1a001a2e7eca8f4ed2d2447786bc8e7 100644 |
| --- a/pkg/analyzer/test/src/task/strong/inferred_type_test.dart |
| +++ b/pkg/analyzer/test/src/task/strong/inferred_type_test.dart |
| @@ -1491,6 +1491,75 @@ main() { |
| '''); |
| }); |
| + test('downwards inference on generic function expressions', () { |
| + checkFile(''' |
| + void main () { |
| + { |
| + String f/*<S>*/(int x) => null; |
| + var v = f; |
| + v = /*info:INFERRED_TYPE_CLOSURE*//*<T>*/(int x) => null; |
|
Jennifer Messerly
2016/02/08 21:54:27
this was rather broken before -- not just the impl
|
| + v = /*<T>*/(int x) => "hello"; |
| + v = /*severe:STATIC_TYPE_ERROR*//*<T>*/(String x) => "hello"; |
| + v = /*severe:STATIC_TYPE_ERROR*//*<T>*/(int x) => 3; |
| + v = /*info:INFERRED_TYPE_CLOSURE*//*<T>*/(int x) {return /*severe:STATIC_TYPE_ERROR*/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, severe:STATIC_TYPE_ERROR*//*<T>*/(x) => 3; |
| + v = /*info:INFERRED_TYPE_CLOSURE, info:INFERRED_TYPE_CLOSURE*//*<T>*/(x) {return /*severe:STATIC_TYPE_ERROR*/3;}; |
| + v = /*info:INFERRED_TYPE_CLOSURE, info:INFERRED_TYPE_CLOSURE*//*<T>*/(x) {return /*severe:STATIC_TYPE_ERROR*/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 = /*severe:STATIC_TYPE_ERROR*//*<T>*/(String x) => /*info:INFERRED_TYPE_LITERAL*/["hello"]; |
| + v = /*<T>*/(int x) => /*info:INFERRED_TYPE_LITERAL*/[/*severe:STATIC_TYPE_ERROR*/3]; |
| + v = /*info:INFERRED_TYPE_CLOSURE*//*<T>*/(int x) {return /*info:INFERRED_TYPE_LITERAL*/[/*severe:STATIC_TYPE_ERROR*/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, severe:STATIC_TYPE_ERROR*//*<T>*/(x) => x; |
| + y = /*info:INFERRED_TYPE_CLOSURE, info:INFERRED_TYPE_CLOSURE*//*<T>*/(x) => /*info:DYNAMIC_CAST, info:DYNAMIC_INVOKE*/x.substring(3); |
| + var z = string2String; |
| + z = /*info:INFERRED_TYPE_CLOSURE*//*<T>*/(x) => x.substring(3); |
| + } |
| + } |
| + '''); |
| + }); |
| + |
| + test('downwards inference on function<T> using the T', () { |
| + 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); |
| + } |
| + } |
| + '''); |
| + }); |
| + |
| test('downwards inference initializing formal, default formal', () { |
| checkFile(''' |
| typedef T Function2<S, T>([S x]); |
| @@ -1500,7 +1569,7 @@ main() { |
| Foo.named([List<int> x = /*info:INFERRED_TYPE_LITERAL*/const [1]]); |
| } |
| void f([List<int> l = /*info:INFERRED_TYPE_LITERAL*/const [1]]) {} |
| -// We do this inference in an early task but don't preserve the infos. |
| + // We do this inference in an early task but don't preserve the infos. |
| Function2<List<int>, String> g = /*pass should be info:INFERRED_TYPE_CLOSURE*/([llll = /*info:INFERRED_TYPE_LITERAL*/const [1]]) => "hello"; |
| '''); |
| }); |
| @@ -1696,14 +1765,23 @@ main() { |
| takeIIO(new C().m); |
| takeDDO(new C().m); |
| - takeOOI(/*severe:STATIC_TYPE_ERROR*/new C().m); |
| - takeIDI(/*severe:STATIC_TYPE_ERROR*/new C().m); |
| - takeDID(/*severe:STATIC_TYPE_ERROR*/new C().m); |
| - |
| // Note: this is a warning because a downcast of a method tear-off could work |
| - // (derived method can be a subtype). |
| + // (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(/*warning:DOWN_CAST_COMPOSITE*/new C().m); |
| takeOOO(/*warning:DOWN_CAST_COMPOSITE*/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(/*warning:DOWN_CAST_COMPOSITE*/new C().m); |
| + takeIDI(/*warning:DOWN_CAST_COMPOSITE*/new C().m); |
| + takeDID(/*warning:DOWN_CAST_COMPOSITE*/new C().m); |
| } |
| void takeIII(int fn(int a, int b)) {} |