fix #26414, infer return types of local functions

R=leafp@google.com

Review URL: https://codereview.chromium.org/2209293002 .
This commit is contained in:
John Messerly 2016-08-05 07:25:14 -07:00
parent 8026c9509c
commit 1bb6da7937
5 changed files with 81 additions and 2 deletions

View file

@ -7,6 +7,31 @@
on Mac. Was already non-blocking on all other platforms.
* Report a better error when a bind fails because of a bad source address.
### Analyzer
* Strong mode breaking change - infer generic type arguments from the
constructor invocation arguments
(SDK issue [25220](https://github.com/dart-lang/sdk/issues/25220))
```dart
var map = new Map<String, String>();
// infer: Map<String, String>
var otherMap = new Map.from(map);
```
* Strong mode breaking change - infer local function return type
(SDK issue [26414](https://github.com/dart-lang/sdk/issues/26414))
```dart
void main() {
// infer: return type is int
f() { return 40; }
int y = f() + 2; // type checks
print(y);
}
```
### Tool Changes
* `dartfmt` - upgraded to v0.2.9

View file

@ -441,6 +441,10 @@ class StaticTypeAnalyzer extends SimpleAstVisitor<Object> {
if (node.parent is FunctionDeclarationStatement) {
// TypeResolverVisitor sets the return type for top-level functions, so
// we only need to handle local functions.
if (_strongMode && node.returnType == null) {
_inferLocalFunctionReturnType(node.functionExpression);
return null;
}
functionElement.returnType =
_computeStaticReturnTypeOfFunctionDeclaration(node);
_recordPropagatedTypeOfFunction(functionElement, function.body);
@ -486,6 +490,15 @@ class StaticTypeAnalyzer extends SimpleAstVisitor<Object> {
// node.
return null;
}
_inferLocalFunctionReturnType(node);
return null;
}
/**
* Infers the return type of a local function, either a lambda or
* (in strong mode) a local function declaration.
*/
void _inferLocalFunctionReturnType(FunctionExpression node) {
bool recordInference = false;
ExecutableElementImpl functionElement =
node.element as ExecutableElementImpl;
@ -517,7 +530,6 @@ class StaticTypeAnalyzer extends SimpleAstVisitor<Object> {
if (recordInference) {
_resolver.inferenceContext.recordInference(node, functionElement.type);
}
return null;
}
/**

View file

@ -1745,7 +1745,7 @@ class C<T> {
}
''');
expectIdentifierType('f', '<S>(S) → S');
expectIdentifierType('g', '<S>(S) → dynamic');
expectIdentifierType('g', '<S>(S) → <S>(S) → S');
}
void test_genericMethod_override() {

View file

@ -565,6 +565,12 @@ var b = a.m();
super.test_inferenceInCyclesIsDeterministic();
}
@override
@failingTest
void test_inferLocalFunctionReturnType() {
super.test_inferLocalFunctionReturnType();
}
@override
@failingTest
void test_inferredType_opAssignToProperty_prefixedIdentifier() {

View file

@ -2518,6 +2518,42 @@ main() {
''');
}
void test_inferLocalFunctionReturnType() {
// Regression test for https://github.com/dart-lang/sdk/issues/26414
var unit = checkFile(r'''
main() {
f0() => 42;
f1() async => 42;
f2 /*info:INFERRED_TYPE_CLOSURE*/() { return 42; }
f3 /*info:INFERRED_TYPE_CLOSURE*/() async { return 42; }
f4 /*info:INFERRED_TYPE_CLOSURE*/() sync* { yield 42; }
f5 /*info:INFERRED_TYPE_CLOSURE*/() async* { yield 42; }
num f6() => 42;
f7() => f7();
f8() => /*error:REFERENCED_BEFORE_DECLARATION*/f9();
f9() => f5();
}
''');
var fns = unit.functions[0].functions;
expect(fns[0].type.toString(), '() → int');
expect(fns[1].type.toString(), '() → Future<int>');
expect(fns[2].type.toString(), '() → int');
expect(fns[3].type.toString(), '() → Future<int>');
expect(fns[4].type.toString(), '() → Iterable<int>');
expect(fns[5].type.toString(), '() → Stream<int>');
expect(fns[6].type.toString(), '() → num');
// Recursive cases: these infer in declaration order.
expect(fns[7].type.toString(), '() → dynamic');
expect(fns[8].type.toString(), '() → dynamic');
expect(fns[9].type.toString(), '() → Stream<int>');
}
void test_inferred_nonstatic_field_depends_on_static_field_complex() {
var mainUnit = checkFile('''
class C {