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 85a1085bef0fc6b253a86b6854b5c9315a60e496..77368a28f9d4e14861c0d6098e6ae7135983a68b 100644 |
| --- a/pkg/analyzer/test/src/task/strong/inferred_type_test.dart |
| +++ b/pkg/analyzer/test/src/task/strong/inferred_type_test.dart |
| @@ -1862,8 +1862,10 @@ main() { |
| void foo(int f(Object _)) {} |
| main() { |
| - var f = (x) => null; |
| - f = (x) => 'hello'; |
| + var f = (Object x) => null; |
| + String y = /*info:DYNAMIC_CAST*/f(42); |
| + |
| + f = /*info:INFERRED_TYPE_CLOSURE*/(x) => 'hello'; |
| var g = null; |
| g = 'hello'; |
| @@ -1919,4 +1921,233 @@ test2() { |
| } |
| '''); |
| }); |
| + |
| + |
|
Leaf
2016/02/24 15:38:40
Great tests, thanks!
|
| + group('block bodied lambdas', () { |
| + // Original feature request: https://github.com/dart-lang/sdk/issues/25487 |
| + |
| + test('basic', () { |
| + checkFile(r''' |
| + test1() { |
| + List<int> o; |
| + var y = o.map(/*info:INFERRED_TYPE_CLOSURE,info:INFERRED_TYPE_CLOSURE*/(x) { return x + 1; }); |
| + Iterable<int> z = y; |
| + } |
| + '''); |
| + }); |
| + |
| + test('no return', () { |
| + var mainUnit = checkFile(r''' |
| + test1() { |
| + List<int> o; |
| + var y = o.map(/*info:INFERRED_TYPE_CLOSURE*/(x) { }); |
| + Iterable<int> z = /*warning:DOWN_CAST_COMPOSITE*/y; |
| + } |
| + '''); |
| + var f = mainUnit.element.functions[0].localVariables[1]; |
| + expect(f.type.toString(), 'Iterable<dynamic>'); |
| + }); |
| + |
| + test('LUB', () { |
| + checkFile(r''' |
| + import 'dart:math' show Random; |
| + test2() { |
| + List<num> o; |
| + var y = o.map(/*info:INFERRED_TYPE_CLOSURE,info:INFERRED_TYPE_CLOSURE*/(x) { |
| + if (new Random().nextBool()) { |
| + return x.toInt() + 1; |
| + } else { |
| + return x.toDouble(); |
| + } |
| + }); |
| + Iterable<num> w = y; |
| + Iterable<int> z = /*info:ASSIGNMENT_CAST*/y; |
| + } |
| + '''); |
| + }); |
| + |
| + group('does not infer bottom', () { |
| + test('sync', () { |
| + var mainUnit = checkFile(r''' |
| + var h = null; |
| + void foo(int f(Object _)) {} |
| + |
| + main() { |
| + var f = (Object x) { return null; }; |
| + String y = /*info:DYNAMIC_CAST*/f(42); |
| + |
| + f = /*info:INFERRED_TYPE_CLOSURE*/(x) => 'hello'; |
| + |
| + foo(/*info:INFERRED_TYPE_CLOSURE,info:INFERRED_TYPE_CLOSURE*/(x) { return null; }); |
| + foo(/*info:INFERRED_TYPE_CLOSURE,info:INFERRED_TYPE_CLOSURE*/(x) { throw "not implemented"; }); |
| + } |
| + '''); |
| + |
| + var f = mainUnit.element.functions[1].localVariables[0]; |
| + expect(f.type.toString(), '(Object) → dynamic'); |
| + }); |
| + |
| + test('sync*', () { |
| + var mainUnit = checkFile(r''' |
| + main() { |
| + var f = () sync* { yield null; }; |
| + Iterable y = f(); |
| + Iterable<String> z = /*warning:DOWN_CAST_COMPOSITE*/f(); |
| + String s = /*info:DYNAMIC_CAST*/f().first; |
| + } |
| + '''); |
| + |
| + var f = mainUnit.element.functions[0].localVariables[0]; |
| + expect(f.type.toString(), '() → Iterable<dynamic>'); |
| + }); |
| + |
| + test('async', () { |
| + var mainUnit = checkFile(r''' |
| + import 'dart:async'; |
| + main() async { |
| + var f = () async { return null; }; |
| + Future y = f(); |
| + Future<String> z = /*warning:DOWN_CAST_COMPOSITE*/f(); |
| + String s = /*info:DYNAMIC_CAST*/await f(); |
| + } |
| + '''); |
| + |
| + var f = mainUnit.element.functions[0].localVariables[0]; |
| + expect(f.type.toString(), '() → Future<dynamic>'); |
| + }); |
| + |
| + test('async*', () { |
| + var mainUnit = checkFile(r''' |
| + import 'dart:async'; |
| + main() async { |
| + var f = () async* { yield null; }; |
| + Stream y = f(); |
| + Stream<String> z = /*warning:DOWN_CAST_COMPOSITE*/f(); |
| + String s = /*info:DYNAMIC_CAST*/await f().first; |
| + } |
| + '''); |
| + |
| + var f = mainUnit.element.functions[0].localVariables[0]; |
| + expect(f.type.toString(), '() → Stream<dynamic>'); |
| + }); |
| + }); |
| + |
| + group('async', () { |
| + test('all returns are values', () { |
| + var mainUnit = checkFile(r''' |
| + import 'dart:async'; |
| + import 'dart:math' show Random; |
| + main() { |
| + var f = /*info:INFERRED_TYPE_CLOSURE*/() async { |
| + if (new Random().nextBool()) { |
| + return 1; |
| + } else { |
| + return 2.0; |
| + } |
| + }; |
| + Future<num> g = f(); |
| + Future<int> h = /*info:ASSIGNMENT_CAST*/f(); |
| + } |
| + '''); |
| + var f = mainUnit.element.functions[0].localVariables[0]; |
| + expect(f.type.toString(), '() → Future<num>'); |
| + }); |
| + |
| + test('all returns are futures', () { |
| + var mainUnit = checkFile(r''' |
| + import 'dart:async'; |
| + import 'dart:math' show Random; |
| + main() { |
| + var f = /*info:INFERRED_TYPE_CLOSURE*/() async { |
| + if (new Random().nextBool()) { |
| + return new Future<int>.value(1); |
| + } else { |
| + return new Future<double>.value(2.0); |
| + } |
| + }; |
| + Future<num> g = f(); |
| + Future<int> h = /*info:ASSIGNMENT_CAST*/f(); |
| + } |
| + '''); |
| + var f = mainUnit.element.functions[0].localVariables[0]; |
| + expect(f.type.toString(), '() → Future<num>'); |
| + }); |
| + |
| + test('mix of values and futures', () { |
| + var mainUnit = checkFile(r''' |
| + import 'dart:async'; |
| + import 'dart:math' show Random; |
| + main() { |
| + var f = /*info:INFERRED_TYPE_CLOSURE*/() async { |
| + if (new Random().nextBool()) { |
| + return new Future<int>.value(1); |
| + } else { |
| + return 2.0; |
| + } |
| + }; |
| + Future<num> g = f(); |
| + Future<int> h = /*info:ASSIGNMENT_CAST*/f(); |
| + } |
| + '''); |
| + var f = mainUnit.element.functions[0].localVariables[0]; |
| + expect(f.type.toString(), '() → Future<num>'); |
| + }); |
| + }); |
| + |
| + test('sync*', () { |
| + var mainUnit = checkFile(r''' |
| + main() { |
| + var f = /*info:INFERRED_TYPE_CLOSURE*/() sync* { |
| + yield 1; |
| + yield* [3, 4.0]; |
| + }; |
| + Iterable<num> g = f(); |
| + Iterable<int> h = /*info:ASSIGNMENT_CAST*/f(); |
| + } |
| + '''); |
| + var f = mainUnit.element.functions[0].localVariables[0]; |
| + expect(f.type.toString(), '() → Iterable<num>'); |
| + }); |
| + |
| + test('async*', () { |
| + var mainUnit = checkFile(r''' |
| + import 'dart:async'; |
| + main() { |
| + var f = /*info:INFERRED_TYPE_CLOSURE*/() async* { |
| + yield 1; |
| + Stream<double> s; |
| + yield* s; |
| + }; |
| + Stream<num> g = f(); |
| + Stream<int> h = /*info:ASSIGNMENT_CAST*/f(); |
| + } |
| + '''); |
| + var f = mainUnit.element.functions[0].localVariables[0]; |
| + expect(f.type.toString(), '() → Stream<num>'); |
| + }); |
| + |
| + test('downwards incompatible with upwards inference', () { |
| + var mainUnit = checkFile(r''' |
| + main() { |
| + String f() => null; |
| + var g = f; |
| + g = /*info:INFERRED_TYPE_CLOSURE*/() { return /*severe:STATIC_TYPE_ERROR*/1; }; |
| + } |
| + '''); |
| + var f = mainUnit.element.functions[0].localVariables[0]; |
| + expect(f.type.toString(), '() → String'); |
| + }); |
| + |
| + test('nested lambdas', () { |
| + var mainUnit = checkFile(r''' |
| + main() { |
| + var f = /*info:INFERRED_TYPE_CLOSURE*/() { |
| + return /*info:INFERRED_TYPE_CLOSURE*/(int x) { return 2.0 * x; }; |
| + }; |
| + } |
| + '''); |
| + var f = mainUnit.element.functions[0].localVariables[0]; |
| + expect(f.type.toString(), '() → (int) → num'); |
| + }); |
| + }); |
| } |