OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 } |
OLD | NEW |