Fix strict-inference for function expressions which can properly infer

Change-Id: I881476f78e9c76650cb576c321ecb0959dce5882
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/118909
Commit-Queue: Samuel Rawlins <srawlins@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
This commit is contained in:
Sam Rawlins 2019-09-26 02:53:12 +00:00 committed by commit-bot@chromium.org
parent c49d3c3486
commit 9c8de83ced
3 changed files with 66 additions and 33 deletions

View file

@ -272,6 +272,7 @@ class BestPracticesVerifier extends RecursiveAstVisitor<void> {
}
}
}
_checkStrictInferenceInParameters(node.parameters);
super.visitConstructorDeclaration(node);
}
@ -316,6 +317,7 @@ class BestPracticesVerifier extends RecursiveAstVisitor<void> {
if (node.parent is CompilationUnit) {
_checkStrictInferenceReturnType(node.returnType, node, node.name.name);
}
_checkStrictInferenceInParameters(node.functionExpression.parameters);
super.visitFunctionDeclaration(node);
} finally {
_inDeprecatedMember = wasInDeprecatedMember;
@ -334,6 +336,10 @@ class BestPracticesVerifier extends RecursiveAstVisitor<void> {
if (node.parent is! FunctionDeclaration) {
_checkForMissingReturn(null, node.body, node.declaredElement, node);
}
DartType functionType = InferenceContext.getContext(node);
if (functionType is! FunctionType) {
_checkStrictInferenceInParameters(node.parameters);
}
super.visitFunctionExpression(node);
}
@ -341,6 +347,7 @@ class BestPracticesVerifier extends RecursiveAstVisitor<void> {
void visitFunctionTypedFormalParameter(FunctionTypedFormalParameter node) {
_checkStrictInferenceReturnType(
node.returnType, node, node.identifier.name);
_checkStrictInferenceInParameters(node.parameters);
super.visitFunctionTypedFormalParameter(node);
}
@ -386,6 +393,7 @@ class BestPracticesVerifier extends RecursiveAstVisitor<void> {
_checkForMissingReturn(node.returnType, node.body, element, node);
_checkForUnnecessaryNoSuchMethod(node);
_checkStrictInferenceReturnType(node.returnType, node, node.name.name);
_checkStrictInferenceInParameters(node.parameters);
super.visitMethodDeclaration(node);
} finally {
_inDeprecatedMember = wasInDeprecatedMember;
@ -1136,7 +1144,35 @@ class BestPracticesVerifier extends RecursiveAstVisitor<void> {
}
}
/// In "strict-inference" mode, check that [returnNode]'s return type is specified.
/// In "strict-inference" mode, check that each of the [parameters]' type is
/// specified.
_checkStrictInferenceInParameters(FormalParameterList parameters) {
void checkParameterTypeIsKnown(SimpleFormalParameter parameter) {
if (parameter.type == null) {
ParameterElement element = parameter.declaredElement;
_errorReporter.reportTypeErrorForNode(
HintCode.INFERENCE_FAILURE_ON_UNTYPED_PARAMETER,
parameter,
[element.displayName],
);
}
}
if (_strictInference && parameters != null) {
for (FormalParameter parameter in parameters.parameters) {
if (parameter is SimpleFormalParameter) {
checkParameterTypeIsKnown(parameter);
} else if (parameter is DefaultFormalParameter) {
if (parameter.parameter is SimpleFormalParameter) {
checkParameterTypeIsKnown(parameter.parameter);
}
}
}
}
}
/// In "strict-inference" mode, check that [returnNode]'s return type is
/// specified.
void _checkStrictInferenceReturnType(
AstNode returnType, AstNode reportNode, String displayName) {
if (!_strictInference) {

View file

@ -117,8 +117,7 @@ class StaticTypeAnalyzer extends SimpleAstVisitor<void> {
/**
* Given a formal parameter list and a function type use the function type
* to infer types for any of the parameters which have implicit (missing)
* types. Only infers types in strong mode. Returns true if inference
* has occurred.
* types. Returns true if inference has occurred.
*/
bool inferFormalParameterList(
FormalParameterList node, DartType functionType) {
@ -525,34 +524,6 @@ class StaticTypeAnalyzer extends SimpleAstVisitor<void> {
_resolver.extensionResolver.resolveOverride(node);
}
/// No inference is performed here; just static checking for the
/// "strict-inference" static analysis mode.
@override
void visitFormalParameterList(FormalParameterList node) {
void checkParameterTypeIsKnown(SimpleFormalParameter parameter) {
ParameterElement element = parameter.declaredElement;
if (parameter.type == null) {
_resolver.errorReporter.reportTypeErrorForNode(
HintCode.INFERENCE_FAILURE_ON_UNTYPED_PARAMETER,
parameter,
[element.displayName],
);
}
}
if (_strictInference) {
for (FormalParameter parameter in node.parameters) {
if (parameter is SimpleFormalParameter) {
checkParameterTypeIsKnown(parameter);
} else if (parameter is DefaultFormalParameter) {
if (parameter.parameter is SimpleFormalParameter) {
checkParameterTypeIsKnown(parameter.parameter);
}
}
}
}
}
@override
void visitFunctionDeclaration(FunctionDeclaration node) {
FunctionExpression function = node.functionExpression;

View file

@ -32,13 +32,13 @@ class C {
''');
}
test_functionTypeParameter_withType() async {
test_functionTypedFormalParameter_withType() async {
await assertNoErrorsInCode(r'''
void fn(String cb(int x)) => print(cb(7));
''');
}
test_functionTypeParameter_withVar() async {
test_functionTypedFormalParameter_withVar() async {
await assertErrorsInCode(r'''
void fn(String cb(var x)) => print(cb(7));
''', [
@ -97,6 +97,24 @@ void fn() {
]);
}
test_parameter_inFunctionLiteral_inferredType() async {
await assertNoErrorsInCode(r'''
void fn() {
g((a, b) => print('$a$b'));
}
void g(void cb(int a, dynamic b)) => cb(7, "x");
''');
}
test_parameter_inFunctionLiteral_inferredType_viaReturn() async {
await assertNoErrorsInCode(r'''
void Function(int, dynamic) fn() {
return (a, b) => print('$a$b');
}
''');
}
test_parameter_inFunctionLiteral_withType() async {
await assertNoErrorsInCode(r'''
void fn() {
@ -191,6 +209,14 @@ typedef cb = void Function(int a);
''');
}
test_parameter_withoutKeyword() async {
await assertErrorsInCode(r'''
void fn(a) => print(a);
''', [
error(HintCode.INFERENCE_FAILURE_ON_UNTYPED_PARAMETER, 8, 1),
]);
}
test_parameter_withType() async {
await assertNoErrorsInCode(r'''
void fn(int a) => print(a);