-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement inference_failure_on_function_invocation checks
The "inference failure" checks implemented here are long overdue. They are part of the strict-inference spec [1]. I think I caught most function invocation cases. All of the work done to determine which error to report and whether @optionalTypeArgs is annotated is done _after_ the check for whether strict-inference is enabled, so this should have no effect on code which does not opt in to that mode. [1] https://github.com/dart-lang/language/blob/master/resources/type-system/strict-inference.md#function-call Bug: #33749 and Change-Id: Ic1d4321fb289acb118e0dbddd48ff917ad39d69a #45371 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/201321 Reviewed-by: Brian Wilkerson <brianwilkerson@google.com> Reviewed-by: Konstantin Shcheglov <scheglov@google.com> Reviewed-by: Phil Quitslund <pquitslund@google.com> Commit-Queue: Samuel Rawlins <srawlins@google.com>
- Loading branch information
Showing
7 changed files
with
405 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
252 changes: 252 additions & 0 deletions
252
pkg/analyzer/test/src/diagnostics/inference_failure_on_function_invocation_test.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,252 @@ | ||
// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file | ||
// for details. All rights reserved. Use of this source code is governed by a | ||
// BSD-style license that can be found in the LICENSE file. | ||
|
||
import 'package:analyzer/src/error/codes.dart'; | ||
import 'package:test_reflective_loader/test_reflective_loader.dart'; | ||
|
||
import '../dart/resolution/context_collection_resolution.dart'; | ||
|
||
main() { | ||
defineReflectiveSuite(() { | ||
defineReflectiveTests(InferenceFailureOnFunctionInvocationTest); | ||
}); | ||
} | ||
|
||
/// Tests of HintCode.INFERENCE_FAILURE_ON_FUNCTION_INVOCATION with the | ||
/// "strict-inference" static analysis option. | ||
@reflectiveTest | ||
class InferenceFailureOnFunctionInvocationTest | ||
extends PubPackageResolutionTest { | ||
@override | ||
void setUp() { | ||
super.setUp(); | ||
writeTestPackageAnalysisOptionsFile( | ||
AnalysisOptionsFileConfig( | ||
strictInference: true, | ||
), | ||
); | ||
writeTestPackageConfigWithMeta(); | ||
} | ||
|
||
test_functionType_noInference() async { | ||
await assertErrorsInCode(''' | ||
void f(void Function<T>() m) { | ||
m(); | ||
} | ||
''', [ | ||
error(HintCode.INFERENCE_FAILURE_ON_FUNCTION_INVOCATION, 33, 1), | ||
]); | ||
} | ||
|
||
test_functionType_notGeneric() async { | ||
await assertNoErrorsInCode(''' | ||
void f(void Function() m) { | ||
m(); | ||
} | ||
'''); | ||
} | ||
|
||
test_functionType_optionalTypeArgs() async { | ||
await assertNoErrorsInCode(''' | ||
import 'package:meta/meta.dart'; | ||
void f(@optionalTypeArgs void Function<T>() m) { | ||
m(); | ||
} | ||
'''); | ||
} | ||
|
||
test_genericFunctionExpression_explicitTypeArg() async { | ||
await assertNoErrorsInCode(''' | ||
void f(void Function<T>()? m, void Function<T>() n) { | ||
(m ?? n)<int>(); | ||
} | ||
'''); | ||
} | ||
|
||
test_genericMethod_downwardsInference() async { | ||
await assertNoErrorsInCode(''' | ||
abstract class C { | ||
T m<T>(); | ||
} | ||
int f(C c) { | ||
return c.m(); | ||
} | ||
'''); | ||
} | ||
|
||
test_genericMethod_explicitTypeArgs() async { | ||
await assertNoErrorsInCode(''' | ||
abstract class C { | ||
void m<T>(); | ||
} | ||
void f(C c) { | ||
c.m<int>(); | ||
} | ||
'''); | ||
} | ||
|
||
test_genericMethod_immediatelyCast() async { | ||
await assertNoErrorsInCode(''' | ||
abstract class C { | ||
T m<T>(); | ||
} | ||
void f(C c) { | ||
c.m() as int; | ||
} | ||
'''); | ||
} | ||
|
||
test_genericMethod_noInference() async { | ||
await assertErrorsInCode(''' | ||
abstract class C { | ||
void m<T>(); | ||
} | ||
void f(C c) { | ||
c.m(); | ||
} | ||
''', [ | ||
error(HintCode.INFERENCE_FAILURE_ON_FUNCTION_INVOCATION, 55, 1), | ||
]); | ||
} | ||
|
||
test_genericMethod_optionalTypeArgs() async { | ||
await assertNoErrorsInCode(''' | ||
import 'package:meta/meta.dart'; | ||
abstract class C { | ||
@optionalTypeArgs | ||
void m<T>(); | ||
} | ||
void f(C c) { | ||
c.m(); | ||
} | ||
'''); | ||
} | ||
|
||
test_genericMethod_upwardsInference() async { | ||
await assertNoErrorsInCode(''' | ||
abstract class C { | ||
void m<T>(T a); | ||
} | ||
void f(C c) { | ||
c.m(7); | ||
} | ||
'''); | ||
} | ||
|
||
test_genericStaticMethod_noInference() async { | ||
await assertErrorsInCode(''' | ||
class C { | ||
static void m<T>() {} | ||
} | ||
void f() { | ||
C.m(); | ||
} | ||
''', [ | ||
error(HintCode.INFERENCE_FAILURE_ON_FUNCTION_INVOCATION, 52, 1), | ||
]); | ||
} | ||
|
||
test_genericTypedef_noInference() async { | ||
await assertErrorsInCode(''' | ||
typedef Fn = void Function<T>(); | ||
void g(Fn fn) { | ||
fn(); | ||
} | ||
''', [ | ||
error(HintCode.INFERENCE_FAILURE_ON_FUNCTION_INVOCATION, 51, 2), | ||
]); | ||
} | ||
|
||
test_genericTypedef_optionalTypeArgs() async { | ||
await assertNoErrorsInCode(''' | ||
import 'package:meta/meta.dart'; | ||
@optionalTypeArgs | ||
typedef Fn = void Function<T>(); | ||
void g(Fn fn) { | ||
fn(); | ||
} | ||
'''); | ||
} | ||
|
||
test_localFunction_noInference() async { | ||
await assertErrorsInCode(''' | ||
void f() { | ||
void g<T>() {} | ||
g(); | ||
} | ||
''', [ | ||
error(HintCode.INFERENCE_FAILURE_ON_FUNCTION_INVOCATION, 30, 1), | ||
]); | ||
} | ||
|
||
test_localFunctionVariable_noInference() async { | ||
await assertErrorsInCode(''' | ||
void f() { | ||
var m = <T>() {}; | ||
m(); | ||
} | ||
''', [ | ||
error(HintCode.INFERENCE_FAILURE_ON_FUNCTION_INVOCATION, 33, 1), | ||
]); | ||
} | ||
|
||
test_nonGenericMethod() async { | ||
await assertNoErrorsInCode(''' | ||
abstract class C { | ||
void m(); | ||
} | ||
void f(C c) { | ||
c.m(); | ||
} | ||
'''); | ||
} | ||
|
||
test_topLevelFunction_noInference() async { | ||
await assertErrorsInCode(''' | ||
void f<T>() {} | ||
void g() { | ||
f(); | ||
} | ||
''', [ | ||
error(HintCode.INFERENCE_FAILURE_ON_FUNCTION_INVOCATION, 29, 1), | ||
]); | ||
} | ||
|
||
test_topLevelFunction_withImportPrefix_noInference() async { | ||
newFile('$testPackageLibPath/a.dart', content: ''' | ||
void f<T>() {} | ||
'''); | ||
await assertErrorsInCode(''' | ||
import 'a.dart' as a; | ||
void g() { | ||
a.f(); | ||
} | ||
''', [ | ||
error(HintCode.INFERENCE_FAILURE_ON_FUNCTION_INVOCATION, 37, 1), | ||
]); | ||
} | ||
|
||
test_topLevelFunction_withImportPrefix_optionalTypeArgs() async { | ||
newFile('$testPackageLibPath/a.dart', content: ''' | ||
import 'package:meta/meta.dart'; | ||
@optionalTypeArgs | ||
void f<T>() {} | ||
'''); | ||
await assertNoErrorsInCode(''' | ||
import 'a.dart' as a; | ||
void g() { | ||
a.f(); | ||
} | ||
'''); | ||
} | ||
} |
Oops, something went wrong.