Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(345)

Side by Side Diff: pkg/analyzer/test/src/task/strong/inferred_type_test.dart

Issue 2260313002: Extend Future.then inference to subclasses (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: rebase Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « pkg/analyzer/test/src/summary/resynthesize_ast_test.dart ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 // TODO(jmesserly): this file needs to be refactored, it's a port from 5 // TODO(jmesserly): this file needs to be refactored, it's a port from
6 // package:dev_compiler's tests 6 // package:dev_compiler's tests
7 /// Tests for type inference. 7 /// Tests for type inference.
8 library analyzer.test.src.task.strong.inferred_type_test; 8 library analyzer.test.src.task.strong.inferred_type_test;
9 9
10 import 'package:analyzer/dart/element/element.dart'; 10 import 'package:analyzer/dart/element/element.dart';
(...skipping 1502 matching lines...) Expand 10 before | Expand all | Expand 10 after
1513 class C { 1513 class C {
1514 final x = y; 1514 final x = y;
1515 } 1515 }
1516 int get y => null; 1516 int get y => null;
1517 '''); 1517 ''');
1518 var x = mainUnit.types[0].fields[0]; 1518 var x = mainUnit.types[0].fields[0];
1519 expect(x.type.toString(), 'int'); 1519 expect(x.type.toString(), 'int');
1520 } 1520 }
1521 1521
1522 void test_futureThen() { 1522 void test_futureThen() {
1523 checkFile(''' 1523 String build({String declared, String downwards, String upwards}) => '''
1524 import 'dart:async'; 1524 import 'dart:async';
1525 Future f; 1525 class MyFuture<T> implements Future<T> {
1526 Future<int> t1 = f.then((_) async => await new Future<int>.value(3)); 1526 MyFuture() {}
1527 Future<int> t2 = f.then(/*info:INFERRED_TYPE_CLOSURE*/(_) async {return await ne w Future<int>.value(3);}); 1527 MyFuture.value(T x) {}
1528 Future<int> t3 = f.then((_) async => 3); 1528 dynamic noSuchMethod(invocation);
1529 Future<int> t4 = f.then(/*info:INFERRED_TYPE_CLOSURE*/(_) async {return 3;}); 1529 MyFuture/*<S>*/ then/*<S>*/(dynamic f(T x), {Function onError}) => null;
1530 Future<int> t5 = f.then((_) => new Future<int>.value(3)); 1530 }
1531 Future<int> t6 = f.then(/*info:INFERRED_TYPE_CLOSURE*/(_) {return new Future<int >.value(3);}); 1531
1532 Future<int> t7 = f.then((_) async => new Future<int>.value(3)); 1532 void main() {
1533 Future<int> t8 = f.then(/*info:INFERRED_TYPE_CLOSURE*/(_) async {return new Futu re<int>.value(3);}); 1533 $declared f;
1534 '''); 1534 $downwards<int> t1 = f.then((_) async => await new $upwards<int>.value(3));
1535 $downwards<int> t2 = f.then(/*info:INFERRED_TYPE_CLOSURE*/(_) async {
1536 return await new $upwards<int>.value(3);});
1537 $downwards<int> t3 = f.then((_) async => 3);
1538 $downwards<int> t4 = f.then(/*info:INFERRED_TYPE_CLOSURE*/(_) async {
1539 return 3;});
1540 $downwards<int> t5 = f.then((_) => new $upwards<int>.value(3));
1541 $downwards<int> t6 = f.then(/*info:INFERRED_TYPE_CLOSURE*/(_) {return new $upw ards<int>.value(3);});
1542 $downwards<int> t7 = f.then((_) async => new $upwards<int>.value(3));
1543 $downwards<int> t8 = f.then(/*info:INFERRED_TYPE_CLOSURE*/(_) async {
1544 return new $upwards<int>.value(3);});
1545 }
1546 ''';
1547
1548 checkFile(
1549 build(declared: "MyFuture", downwards: "Future", upwards: "Future"));
1550 checkFile(
1551 build(declared: "MyFuture", downwards: "Future", upwards: "MyFuture"));
1552 checkFile(
1553 build(declared: "MyFuture", downwards: "MyFuture", upwards: "Future"));
1554 checkFile(build(
1555 declared: "MyFuture", downwards: "MyFuture", upwards: "MyFuture"));
1556 checkFile(
1557 build(declared: "Future", downwards: "Future", upwards: "MyFuture"));
1558 checkFile(
1559 build(declared: "Future", downwards: "Future", upwards: "Future"));
1535 } 1560 }
1536 1561
1537 void test_futureThen_conditional() { 1562 void test_futureThen_conditional() {
1538 checkFile(''' 1563 String build({String declared, String downwards, String upwards}) => '''
1539 import 'dart:async'; 1564 import 'dart:async';
1540 Future<bool> f; 1565 class MyFuture<T> implements Future<T> {
1541 Future<int> t1 = f.then((x) async => x ? 2 : await new Future<int>.value(3)); 1566 MyFuture() {}
1542 Future<int> t2 = f.then(/*info:INFERRED_TYPE_CLOSURE*/(x) async {return await x ? 2 : new Future<int>.value(3);}); 1567 MyFuture.value(T x) {}
1543 Future<int> t5 = f.then((x) => x ? 2 : new Future<int>.value(3)); 1568 dynamic noSuchMethod(invocation);
1544 Future<int> t6 = f.then((x) {return x ? 2 : new Future<int>.value(3);}); 1569 MyFuture/*<S>*/ then/*<S>*/(dynamic f(T x), {Function onError}) => null;
1545 '''); 1570 }
1571
1572 void main() {
1573 $declared<bool> f;
1574 $downwards<int> t1 = f.then(/*info:INFERRED_TYPE_CLOSURE*/
1575 (x) async => x ? 2 : await new $upwards<int>.value(3));
1576 $downwards<int> t2 = f.then(/*info:INFERRED_TYPE_CLOSURE,info:INFERRED_TYPE_CL OSURE*/(x) async { // TODO(leafp): Why the duplicate here?
1577 return await x ? 2 : new $upwards<int>.value(3);});
1578 $downwards<int> t5 = f.then(/*info:INFERRED_TYPE_CLOSURE*/
1579 (x) => x ? 2 : new $upwards<int>.value(3));
1580 $downwards<int> t6 = f.then(/*info:INFERRED_TYPE_CLOSURE*/
1581 (x) {return x ? 2 : new $upwards<int>.value(3);});
1582 }
1583 ''';
1584 checkFile(
1585 build(declared: "MyFuture", downwards: "Future", upwards: "Future"));
1586 checkFile(
1587 build(declared: "MyFuture", downwards: "Future", upwards: "MyFuture"));
1588 checkFile(
1589 build(declared: "MyFuture", downwards: "MyFuture", upwards: "Future"));
1590 checkFile(build(
1591 declared: "MyFuture", downwards: "MyFuture", upwards: "MyFuture"));
1592 checkFile(
1593 build(declared: "Future", downwards: "Future", upwards: "MyFuture"));
1594 checkFile(
1595 build(declared: "Future", downwards: "Future", upwards: "Future"));
1546 } 1596 }
1547 1597
1548 void test_futureThen_downwardsMethodTarget() { 1598 void test_futureThen_downwardsMethodTarget() {
1549 // Not working yet, see: https://github.com/dart-lang/sdk/issues/27114 1599 // Not working yet, see: https://github.com/dart-lang/sdk/issues/27114
1550 checkFile(r''' 1600 checkFile(r'''
1551 import 'dart:async'; 1601 import 'dart:async';
1552 main() { 1602 main() {
1553 Future<int> f; 1603 Future<int> f;
1554 Future<List<int>> b = /*info:ASSIGNMENT_CAST should be pass*/f 1604 Future<List<int>> b = /*info:ASSIGNMENT_CAST should be pass*/f
1555 .then(/*info:INFERRED_TYPE_CLOSURE*/(x) => []) 1605 .then(/*info:INFERRED_TYPE_CLOSURE*/(x) => [])
1556 .whenComplete(/*pass should be info:INFERRED_TYPE_LITERAL*/() {}); 1606 .whenComplete(/*pass should be info:INFERRED_TYPE_LITERAL*/() {});
1557 b = f.then(/*info:INFERRED_TYPE_CLOSURE*/(x) => /*info:INFERRED_TYPE_LITERAL*/ []); 1607 b = f.then(/*info:INFERRED_TYPE_CLOSURE*/(x) => /*info:INFERRED_TYPE_LITERAL*/ []);
1558 } 1608 }
1559 '''); 1609 ''');
1560 } 1610 }
1561 1611
1562 void test_futureThen_upwards() { 1612 void test_futureThen_upwards() {
1563 // Regression test for https://github.com/dart-lang/sdk/issues/27088. 1613 // Regression test for https://github.com/dart-lang/sdk/issues/27088.
1564 checkFile(r''' 1614 String build({String declared, String downwards, String upwards}) => '''
1565 import 'dart:async'; 1615 import 'dart:async';
1566 main() { 1616 class MyFuture<T> implements Future<T> {
1617 MyFuture() {}
1618 MyFuture.value(T x) {}
1619 dynamic noSuchMethod(invocation);
1620 MyFuture/*<S>*/ then/*<S>*/(dynamic f(T x), {Function onError}) => null;
1621 }
1622
1623 void main() {
1567 var f = foo().then((_) => 2.3); 1624 var f = foo().then((_) => 2.3);
1568 Future<int> f2 = /*error:INVALID_ASSIGNMENT*/f; 1625 $downwards<int> f2 = /*error:INVALID_ASSIGNMENT*/f;
1569 1626
1570 // The unnecessary cast is to illustrate that we inferred <double> for 1627 // The unnecessary cast is to illustrate that we inferred <double> for
1571 // the generic type args, even though we had a return type context. 1628 // the generic type args, even though we had a return type context.
1572 Future<num> f3 = /*info:UNNECESSARY_CAST*/foo().then((_) => 2.3) as Future<dou ble>; 1629 $downwards<num> f3 = /*info:UNNECESSARY_CAST*/foo().then(
1630 (_) => 2.3) as $upwards<double>;
1573 } 1631 }
1574 Future foo() async => 1; 1632 $declared foo() => new $declared<int>.value(1);
1575 '''); 1633 ''';
1634 checkFile(
1635 build(declared: "MyFuture", downwards: "Future", upwards: "Future"));
1636 checkFile(build(
1637 declared: "MyFuture", downwards: "MyFuture", upwards: "MyFuture"));
1638 checkFile(
1639 build(declared: "Future", downwards: "Future", upwards: "Future"));
1576 } 1640 }
1577 1641
1578 void test_futureThen_upwardsFromBlock() { 1642 void test_futureThen_upwardsFromBlock() {
1579 // Regression test for https://github.com/dart-lang/sdk/issues/27113. 1643 // Regression test for https://github.com/dart-lang/sdk/issues/27113.
1580 checkFile(r''' 1644 checkFile(r'''
1581 import 'dart:async'; 1645 import 'dart:async';
1582 main() { 1646 main() {
1583 Future<int> base; 1647 Future<int> base;
1584 var f = base.then(/*info:INFERRED_TYPE_CLOSURE,info:INFERRED_TYPE_CLOSURE*/(x) { return x == 0; }); 1648 var f = base.then(/*info:INFERRED_TYPE_CLOSURE,info:INFERRED_TYPE_CLOSURE*/(x) { return x == 0; });
1585 var g = base.then(/*info:INFERRED_TYPE_CLOSURE*/(x) => x == 0); 1649 var g = base.then(/*info:INFERRED_TYPE_CLOSURE*/(x) => x == 0);
1586 Future<bool> b = f; 1650 Future<bool> b = f;
1587 b = g; 1651 b = g;
1588 } 1652 }
1589 '''); 1653 ''');
1590 } 1654 }
1591 1655
1592 void test_futureUnion_asyncConditional() { 1656 void test_futureUnion_asyncConditional() {
1593 checkFile(''' 1657 String build({String declared, String downwards, String upwards}) => '''
1594 import 'dart:async'; 1658 import 'dart:async';
1659 class MyFuture<T> implements Future<T> {
1660 MyFuture() {}
1661 MyFuture.value(T x) {}
1662 dynamic noSuchMethod(invocation);
1663 MyFuture/*<S>*/ then/*<S>*/(dynamic f(T x), {Function onError}) => null;
1664 }
1595 1665
1596 Future<int> g1(bool x) async { return x ? 42 : /*info:INFERRED_TYPE_ALLOCATION*/ new Future.value(42); } 1666 $downwards<int> g1(bool x) async {
1597 Future<int> g2(bool x) async => x ? 42 : /*info:INFERRED_TYPE_ALLOCATION*/new Fu ture.value(42); 1667 return x ? 42 : /*info:INFERRED_TYPE_ALLOCATION*/new $upwards.value(42); }
1598 1668 $downwards<int> g2(bool x) async =>
1599 Future<int> g3(bool x) async { 1669 x ? 42 : /*info:INFERRED_TYPE_ALLOCATION*/new $upwards.value(42);
1600 var y = x ? 42 : /*info:INFERRED_TYPE_ALLOCATION*/new Future.value(42); 1670 $downwards<int> g3(bool x) async {
1671 var y = x ? 42 : /*info:INFERRED_TYPE_ALLOCATION*/new $upwards.value(42);
1601 return y; 1672 return y;
1602 } 1673 }
1603 '''); 1674 ''';
1675 checkFile(build(downwards: "Future", upwards: "Future"));
1676 checkFile(build(downwards: "Future", upwards: "MyFuture"));
1604 } 1677 }
1605 1678
1606 void test_futureUnion_downwards() { 1679 void test_futureUnion_downwards() {
1607 checkFile(''' 1680 String build({String declared, String downwards, String upwards}) {
1681 // TODO(leafp): The use of matchTypes in visitInstanceCreationExpression
1682 // in the resolver visitor isn't powerful enough to catch this for the
1683 // subclass. See the TODO there.
1684 var allocInfo =
1685 (upwards == "Future") ? "/*info:INFERRED_TYPE_ALLOCATION*/" : "";
1686 return '''
1608 import 'dart:async'; 1687 import 'dart:async';
1609 Future f; 1688 class MyFuture<T> implements Future<T> {
1689 MyFuture() {}
1690 MyFuture.value([T x]) {}
1691 dynamic noSuchMethod(invocation);
1692 MyFuture/*<S>*/ then/*<S>*/(dynamic f(T x), {Function onError}) => null;
1693 }
1694
1695 $declared f;
1610 // Instantiates Future<int> 1696 // Instantiates Future<int>
1611 Future<int> t1 = f.then((_) => /*info:INFERRED_TYPE_ALLOCATION*/new Future.value (/*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/'hi')); 1697 $downwards<int> t1 = f.then((_) =>
1698 ${allocInfo}new $upwards.value(
1699 /*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/'hi'));
1612 1700
1613 // Instantiates List<int> 1701 // Instantiates List<int>
1614 Future<List<int>> t2 = f.then((_) => /*info:INFERRED_TYPE_LITERAL*/[3]); 1702 $downwards<List<int>> t2 = f.then((_) => /*info:INFERRED_TYPE_LITERAL*/[3]);
1615 Future<List<int>> g2() async { return /*info:INFERRED_TYPE_LITERAL*/[3]; } 1703 $downwards<List<int>> g2() async { return /*info:INFERRED_TYPE_LITERAL*/[3]; }
1616 Future<List<int>> g3() async { return /*info:INFERRED_TYPE_ALLOCATION*/new Futur e.value(/*info:INFERRED_TYPE_LITERAL*/[3]); } 1704 $downwards<List<int>> g3() async {
1617 '''); 1705 return /*info:INFERRED_TYPE_ALLOCATION*/new $upwards.value(
1706 /*info:INFERRED_TYPE_LITERAL*/[3]); }
1707 ''';
1708 }
1709
1710 ;
1711 checkFile(
1712 build(declared: "MyFuture", downwards: "Future", upwards: "Future"));
1713 checkFile(
1714 build(declared: "MyFuture", downwards: "Future", upwards: "MyFuture"));
1715 checkFile(
1716 build(declared: "Future", downwards: "Future", upwards: "Future"));
1717 checkFile(
1718 build(declared: "Future", downwards: "Future", upwards: "MyFuture"));
1618 } 1719 }
1619 1720
1620 void test_genericMethods_basicDownwardInference() { 1721 void test_genericMethods_basicDownwardInference() {
1621 checkFile(r''' 1722 checkFile(r'''
1622 /*=T*/ f/*<S, T>*/(/*=S*/ s) => null; 1723 /*=T*/ f/*<S, T>*/(/*=S*/ s) => null;
1623 main() { 1724 main() {
1624 String x = f(42); 1725 String x = f(42);
1625 String y = (f)(42); 1726 String y = (f)(42);
1626 } 1727 }
1627 '''); 1728 ''');
(...skipping 1009 matching lines...) Expand 10 before | Expand all | Expand 10 after
2637 expect(fns[5].type.toString(), '() → Stream<int>'); 2738 expect(fns[5].type.toString(), '() → Stream<int>');
2638 2739
2639 expect(fns[6].type.toString(), '() → num'); 2740 expect(fns[6].type.toString(), '() → num');
2640 2741
2641 // Recursive cases: these infer in declaration order. 2742 // Recursive cases: these infer in declaration order.
2642 expect(fns[7].type.toString(), '() → dynamic'); 2743 expect(fns[7].type.toString(), '() → dynamic');
2643 expect(fns[8].type.toString(), '() → dynamic'); 2744 expect(fns[8].type.toString(), '() → dynamic');
2644 expect(fns[9].type.toString(), '() → Stream<int>'); 2745 expect(fns[9].type.toString(), '() → Stream<int>');
2645 } 2746 }
2646 2747
2647 void test_inferReturnOfStatementLambda() {
2648 // Regression test for https://github.com/dart-lang/sdk/issues/26139
2649 checkFile(r'''
2650 List<String> strings() {
2651 var stuff = [].expand(/*info:INFERRED_TYPE_CLOSURE*/(i) {
2652 return <String>[];
2653 });
2654 return stuff.toList();
2655 }
2656 ''');
2657 }
2658
2659 void test_inferred_nonstatic_field_depends_on_static_field_complex() { 2748 void test_inferred_nonstatic_field_depends_on_static_field_complex() {
2660 var mainUnit = checkFile(''' 2749 var mainUnit = checkFile('''
2661 class C { 2750 class C {
2662 static var x = 'x'; 2751 static var x = 'x';
2663 var y = /*info:INFERRED_TYPE_LITERAL*/{ 2752 var y = /*info:INFERRED_TYPE_LITERAL*/{
2664 'a': /*info:INFERRED_TYPE_LITERAL*/{'b': 'c'}, 2753 'a': /*info:INFERRED_TYPE_LITERAL*/{'b': 'c'},
2665 'd': /*info:INFERRED_TYPE_LITERAL*/{'e': x} 2754 'd': /*info:INFERRED_TYPE_LITERAL*/{'e': x}
2666 }; 2755 };
2667 } 2756 }
2668 '''); 2757 ''');
(...skipping 362 matching lines...) Expand 10 before | Expand all | Expand 10 after
3031 var f = mainUnit.getType('C').fields[0]; 3120 var f = mainUnit.getType('C').fields[0];
3032 expect(f.type.toString(), '(bool) → int'); 3121 expect(f.type.toString(), '(bool) → int');
3033 } 3122 }
3034 3123
3035 void test_inferredType_viaClosure_typeIndependentOfArgs_topLevel() { 3124 void test_inferredType_viaClosure_typeIndependentOfArgs_topLevel() {
3036 var mainUnit = checkFile('final f = (bool b) => 1;'); 3125 var mainUnit = checkFile('final f = (bool b) => 1;');
3037 var f = mainUnit.topLevelVariables[0]; 3126 var f = mainUnit.topLevelVariables[0];
3038 expect(f.type.toString(), '(bool) → int'); 3127 expect(f.type.toString(), '(bool) → int');
3039 } 3128 }
3040 3129
3130 void test_inferReturnOfStatementLambda() {
3131 // Regression test for https://github.com/dart-lang/sdk/issues/26139
3132 checkFile(r'''
3133 List<String> strings() {
3134 var stuff = [].expand(/*info:INFERRED_TYPE_CLOSURE*/(i) {
3135 return <String>[];
3136 });
3137 return stuff.toList();
3138 }
3139 ''');
3140 }
3141
3041 void test_inferStaticsTransitively() { 3142 void test_inferStaticsTransitively() {
3042 addFile( 3143 addFile(
3043 ''' 3144 '''
3044 final b1 = 2; 3145 final b1 = 2;
3045 ''', 3146 ''',
3046 name: '/b.dart'); 3147 name: '/b.dart');
3047 addFile( 3148 addFile(
3048 ''' 3149 '''
3049 import 'main.dart'; 3150 import 'main.dart';
3050 import 'b.dart'; 3151 import 'b.dart';
(...skipping 1340 matching lines...) Expand 10 before | Expand all | Expand 10 after
4391 } 4492 }
4392 4493
4393 /// Adds a file using [helper.addFile] and calls [helper.check]. 4494 /// Adds a file using [helper.addFile] and calls [helper.check].
4394 /// 4495 ///
4395 /// Also returns the resolved compilation unit. 4496 /// Also returns the resolved compilation unit.
4396 @override 4497 @override
4397 CompilationUnitElement checkFile(String content) { 4498 CompilationUnitElement checkFile(String content) {
4398 return helper.checkFile(content).element; 4499 return helper.checkFile(content).element;
4399 } 4500 }
4400 } 4501 }
OLDNEW
« no previous file with comments | « pkg/analyzer/test/src/summary/resynthesize_ast_test.dart ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698