Fix RETURN_OF_INVALID_TYPE for anonymous closures

The displayName of an anonymous closure is a blank String, resulting in messages like:

    [error] The return type 'String' is not a 'int', as defined by the method ''.

After this change, an error might instead look like:

$ xcodebuild/ReleaseX64/dart-sdk/bin/dartanalyzer --strong 26056.dart
Analyzing 26056.dart...
  error • The return type 'String' isn't a 'int', as defined by anonymouse closure at 26056.dart:6:28 • return_of_invalid_type
  1 error found.

Bug: https://github.com/dart-lang/sdk/issues/26056
Change-Id: I4003eea22cb23e0b06479482c06d5ce8a936c756
Reviewed-on: https://dart-review.googlesource.com/28382
Commit-Queue: Samuel Rawlins <srawlins@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
This commit is contained in:
Sam Rawlins 2017-12-18 15:33:06 +00:00 committed by commit-bot@chromium.org
parent ad9ea873c7
commit b50319ca9f
5 changed files with 43 additions and 18 deletions

View file

@ -512,6 +512,7 @@ const List<ErrorCode> errorCodeValues = const [
StaticTypeWarningCode.NON_NULLABLE_FIELD_NOT_INITIALIZED,
StaticTypeWarningCode.NON_TYPE_AS_TYPE_ARGUMENT,
StaticTypeWarningCode.RETURN_OF_INVALID_TYPE,
StaticTypeWarningCode.RETURN_OF_INVALID_TYPE_FROM_CLOSURE,
StaticTypeWarningCode.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS,
StaticTypeWarningCode.TYPE_PARAMETER_SUPERTYPE_OF_ITS_BOUND,
StaticTypeWarningCode.UNDEFINED_ENUM_CONSTANT,

View file

@ -2864,6 +2864,19 @@ class StaticTypeWarningCode extends ErrorCode {
const StaticTypeWarningCode('RETURN_OF_INVALID_TYPE',
"The return type '{0}' isn't a '{1}', as defined by the method '{2}'.");
/**
* 13.11 Return: It is a static type warning if the type of <i>e</i> may not
* be assigned to the declared return type of the immediately enclosing
* function.
*
* Parameters:
* 0: the return type as declared in the return statement
* 1: the expected return type as defined by the method
*/
static const StaticTypeWarningCode RETURN_OF_INVALID_TYPE_FROM_CLOSURE =
const StaticTypeWarningCode('RETURN_OF_INVALID_TYPE_FROM_CLOSURE',
"The return type '{0}' isn't a '{1}', as defined by anonymous closure.");
/**
* 12.11 Instance Creation: It is a static type warning if any of the type
* arguments to a constructor of a generic type <i>G</i> invoked by a new

View file

@ -5632,6 +5632,17 @@ class ErrorVerifier extends RecursiveAstVisitor<Object> {
return;
}
DartType staticReturnType = _computeReturnTypeForMethod(returnExpression);
String displayName = _enclosingFunction.displayName;
void reportTypeError() => _errorReporter.reportTypeErrorForNode(
StaticTypeWarningCode.RETURN_OF_INVALID_TYPE,
returnExpression,
[staticReturnType, expectedReturnType, displayName]);
void reportTypeErrorFromClosure() => _errorReporter.reportTypeErrorForNode(
StaticTypeWarningCode.RETURN_OF_INVALID_TYPE_FROM_CLOSURE,
returnExpression,
[staticReturnType, expectedReturnType]);
if (expectedReturnType.isVoid) {
if (isArrowFunction) {
// "void f(..) => e" admits all types for "e".
@ -5643,22 +5654,22 @@ class ErrorVerifier extends RecursiveAstVisitor<Object> {
staticReturnType.isDartCoreNull) {
return;
}
_errorReporter.reportTypeErrorForNode(
StaticTypeWarningCode.RETURN_OF_INVALID_TYPE, returnExpression, [
staticReturnType,
expectedReturnType,
_enclosingFunction.displayName
]);
if (displayName.isEmpty) {
reportTypeErrorFromClosure();
} else {
reportTypeError();
}
return;
}
if (_expressionIsAssignableAtType(
returnExpression, staticReturnType, expectedReturnType)) {
return;
}
_errorReporter.reportTypeErrorForNode(
StaticTypeWarningCode.RETURN_OF_INVALID_TYPE,
returnExpression,
[staticReturnType, expectedReturnType, _enclosingFunction.displayName]);
if (displayName.isEmpty) {
reportTypeErrorFromClosure();
} else {
reportTypeError();
}
// TODO(brianwilkerson) Define a hint corresponding to the warning and
// report it if appropriate.

View file

@ -203,7 +203,7 @@ test1() {
main() {
String f() => null;
var g = f;
g = /*info:INFERRED_TYPE_CLOSURE*/() { return /*error:RETURN_OF_INVALID_TYPE*/1; };
g = /*info:INFERRED_TYPE_CLOSURE*/() { return /*error:RETURN_OF_INVALID_TYPE_FROM_CLOSURE*/1; };
}
''');
var g = findLocalVariable(unit, 'g');
@ -1016,14 +1016,14 @@ void main () {
Function2<int, String> l1 = (int x) => "hello";
Function2<int, String> l2 = /*error:INVALID_ASSIGNMENT*/(String x) => "hello";
Function2<int, String> l3 = /*error:INVALID_ASSIGNMENT*/(int x) => 3;
Function2<int, String> l4 = /*info:INFERRED_TYPE_CLOSURE*/(int x) {return /*error:RETURN_OF_INVALID_TYPE*/3;};
Function2<int, String> l4 = /*info:INFERRED_TYPE_CLOSURE*/(int x) {return /*error:RETURN_OF_INVALID_TYPE_FROM_CLOSURE*/3;};
}
{
Function2<int, String> l0 = /*info:INFERRED_TYPE_CLOSURE*/(x) => null;
Function2<int, String> l1 = /*info:INFERRED_TYPE_CLOSURE*/(x) => "hello";
Function2<int, String> l2 = /*info:INFERRED_TYPE_CLOSURE, error:INVALID_ASSIGNMENT*/(x) => 3;
Function2<int, String> l3 = /*info:INFERRED_TYPE_CLOSURE*/(x) {return /*error:RETURN_OF_INVALID_TYPE*/3;};
Function2<int, String> l4 = /*info:INFERRED_TYPE_CLOSURE*/(x) {return /*error:RETURN_OF_INVALID_TYPE*/x;};
Function2<int, String> l3 = /*info:INFERRED_TYPE_CLOSURE*/(x) {return /*error:RETURN_OF_INVALID_TYPE_FROM_CLOSURE*/3;};
Function2<int, String> l4 = /*info:INFERRED_TYPE_CLOSURE*/(x) {return /*error:RETURN_OF_INVALID_TYPE_FROM_CLOSURE*/x;};
}
{
Function2<int, List<String>> l0 = /*info:INFERRED_TYPE_CLOSURE*/(int x) => null;
@ -1151,7 +1151,7 @@ void main () {
v = <T>(int x) => "hello";
v = /*error:INVALID_ASSIGNMENT*/<T>(String x) => "hello";
v = /*error:INVALID_ASSIGNMENT*/<T>(int x) => 3;
v = /*info:INFERRED_TYPE_CLOSURE*/<T>(int x) {return /*error:RETURN_OF_INVALID_TYPE*/3;};
v = /*info:INFERRED_TYPE_CLOSURE*/<T>(int x) {return /*error:RETURN_OF_INVALID_TYPE_FROM_CLOSURE*/3;};
}
{
String f<S>(int x) => null;
@ -1159,8 +1159,8 @@ void main () {
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, error:INVALID_ASSIGNMENT*/<T>(x) => 3;
v = /*info:INFERRED_TYPE_CLOSURE, info:INFERRED_TYPE_CLOSURE*/<T>(x) {return /*error:RETURN_OF_INVALID_TYPE*/3;};
v = /*info:INFERRED_TYPE_CLOSURE, info:INFERRED_TYPE_CLOSURE*/<T>(x) {return /*error:RETURN_OF_INVALID_TYPE*/x;};
v = /*info:INFERRED_TYPE_CLOSURE, info:INFERRED_TYPE_CLOSURE*/<T>(x) {return /*error:RETURN_OF_INVALID_TYPE_FROM_CLOSURE*/3;};
v = /*info:INFERRED_TYPE_CLOSURE, info:INFERRED_TYPE_CLOSURE*/<T>(x) {return /*error:RETURN_OF_INVALID_TYPE_FROM_CLOSURE*/x;};
}
{
List<String> f<S>(int x) => null;

View file

@ -24,7 +24,7 @@ Future<CodeBuffer> compileAll(SourceFile sourceFile) {
// emitter.
full.Emitter fullEmitter = backend.emitter.emitter;
// CodeOutput isn't assignable to CodeBuffer.
// ignore: RETURN_OF_INVALID_TYPE
// ignore: RETURN_OF_INVALID_TYPE_FROM_CLOSURE
return fullEmitter
.outputBuffers[compiler.backend.outputUnitData.mainOutputUnit];
});