mirror of
https://github.com/dart-lang/sdk
synced 2024-10-06 12:47:14 +00:00
Issue a warning if top-level inference depends on an implicitly typed instance getter.
If an implicitly typed top level variable or field depends on an implicitly typed instance getter or instance field, the analyzer implementation of type inference isn't guaranteed to infer the depended-upon field first, therefore the type might be inferred incorrectly. The new front end doesn't have this problem, so the user's code will execute correctly at runtime, but they might get confusing results from the analyzer. To alert users of this problem, we issue a compile-time warning whenever an implicitly typed top level variable or field depends on an implicitly typed instance getter or instance field. Change-Id: I100bcbe1a76472bcb7d493eb12e4a3e2d0605e79 Reviewed-on: https://dart-review.googlesource.com/35385 Reviewed-by: Konstantin Shcheglov <scheglov@google.com> Commit-Queue: Paul Berry <paulberry@google.com>
This commit is contained in:
parent
2e5264ddea
commit
23cba1d438
|
@ -5052,10 +5052,11 @@ class StrongModeCode extends ErrorCode {
|
|||
"Try adding an explicit type to either the variable '{0}' or the variable '{1}'.");
|
||||
|
||||
static const StrongModeCode TOP_LEVEL_INSTANCE_GETTER = const StrongModeCode(
|
||||
ErrorType.HINT,
|
||||
ErrorType.STATIC_WARNING,
|
||||
'TOP_LEVEL_INSTANCE_GETTER',
|
||||
"The type of '{0}' can't be inferred because of the use of the instance getter '{1}'.",
|
||||
"Try removing the use of the instance getter {1}, or add an explicit type for '{0}'.");
|
||||
"The type of '{0}' can't be inferred because it refers to an instance "
|
||||
"getter, '{1}', which has an implicit type.",
|
||||
"Add an explicit type for either '{0}' or '{1}'.");
|
||||
|
||||
static const StrongModeCode TOP_LEVEL_TYPE_ARGUMENTS = const StrongModeCode(
|
||||
ErrorType.HINT,
|
||||
|
|
|
@ -1312,8 +1312,20 @@ class CodeChecker extends RecursiveAstVisitor {
|
|||
return;
|
||||
}
|
||||
|
||||
if (e is PropertyAccessorElement) {
|
||||
validateHasType(e);
|
||||
Element enclosing = e.enclosingElement;
|
||||
if (enclosing is CompilationUnitElement) {
|
||||
if (e is PropertyAccessorElement) {
|
||||
validateHasType(e);
|
||||
}
|
||||
} else if (enclosing is ClassElement) {
|
||||
if (e is PropertyAccessorElement) {
|
||||
if (e.isStatic) {
|
||||
validateHasType(e);
|
||||
} else if (e.hasImplicitReturnType) {
|
||||
_recordMessage(
|
||||
n, StrongModeCode.TOP_LEVEL_INSTANCE_GETTER, [name, e.name]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1391,6 +1403,7 @@ class CodeChecker extends RecursiveAstVisitor {
|
|||
} else if (n is FunctionExpressionInvocation) {
|
||||
_validateTopLevelInitializer(name, n.function);
|
||||
} else if (n is MethodInvocation) {
|
||||
_validateTopLevelInitializer(name, n.methodName);
|
||||
_validateTopLevelInitializer(name, n.target);
|
||||
} else if (n is CascadeExpression) {
|
||||
_validateTopLevelInitializer(name, n.target);
|
||||
|
|
|
@ -2859,8 +2859,15 @@ class A {
|
|||
final y = x;
|
||||
}''');
|
||||
await computeAnalysisResult(source);
|
||||
assertErrors(
|
||||
source, [CompileTimeErrorCode.IMPLICIT_THIS_REFERENCE_IN_INITIALIZER]);
|
||||
if (enableKernelDriver) {
|
||||
assertErrors(source,
|
||||
[CompileTimeErrorCode.IMPLICIT_THIS_REFERENCE_IN_INITIALIZER]);
|
||||
} else {
|
||||
assertErrors(source, [
|
||||
CompileTimeErrorCode.IMPLICIT_THIS_REFERENCE_IN_INITIALIZER,
|
||||
StrongModeCode.TOP_LEVEL_INSTANCE_GETTER
|
||||
]);
|
||||
}
|
||||
verify([source]);
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
library analyzer.test.generated.hint_code_test;
|
||||
|
||||
import 'package:analyzer/dart/ast/ast.dart';
|
||||
import 'package:analyzer/error/error.dart';
|
||||
import 'package:analyzer/src/error/codes.dart';
|
||||
import 'package:analyzer/src/generated/engine.dart';
|
||||
|
@ -2898,6 +2899,206 @@ main() {
|
|||
verify([source]);
|
||||
}
|
||||
|
||||
test_strongMode_topLevelInstanceGetter() async {
|
||||
resetWith(options: new AnalysisOptionsImpl()..strongMode = true);
|
||||
Source source = addSource('''
|
||||
class A {
|
||||
int get g => 0;
|
||||
}
|
||||
var b = new A().g;
|
||||
''');
|
||||
var analysisResult = await computeAnalysisResult(source);
|
||||
assertNoErrors(source);
|
||||
TopLevelVariableDeclaration b = analysisResult.unit.declarations[1];
|
||||
expect(b.variables.variables[0].element.type.toString(), 'int');
|
||||
verify([source]);
|
||||
}
|
||||
|
||||
test_strongMode_topLevelInstanceGetter_call() async {
|
||||
resetWith(options: new AnalysisOptionsImpl()..strongMode = true);
|
||||
Source source = addSource('''
|
||||
class A {
|
||||
int Function() get g => () => 0;
|
||||
}
|
||||
var a = new A();
|
||||
var b = a.g();
|
||||
''');
|
||||
var analysisResult = await computeAnalysisResult(source);
|
||||
assertNoErrors(source);
|
||||
TopLevelVariableDeclaration b = analysisResult.unit.declarations[2];
|
||||
expect(b.variables.variables[0].element.type.toString(), 'int');
|
||||
verify([source]);
|
||||
}
|
||||
|
||||
test_strongMode_topLevelInstanceGetter_field() async {
|
||||
resetWith(options: new AnalysisOptionsImpl()..strongMode = true);
|
||||
Source source = addSource('''
|
||||
class A {
|
||||
int g;
|
||||
}
|
||||
var b = new A().g;
|
||||
''');
|
||||
var analysisResult = await computeAnalysisResult(source);
|
||||
assertNoErrors(source);
|
||||
TopLevelVariableDeclaration b = analysisResult.unit.declarations[1];
|
||||
expect(b.variables.variables[0].element.type.toString(), 'int');
|
||||
verify([source]);
|
||||
}
|
||||
|
||||
test_strongMode_topLevelInstanceGetter_field_call() async {
|
||||
resetWith(options: new AnalysisOptionsImpl()..strongMode = true);
|
||||
Source source = addSource('''
|
||||
class A {
|
||||
int Function() g;
|
||||
}
|
||||
var a = new A();
|
||||
var b = a.g();
|
||||
''');
|
||||
var analysisResult = await computeAnalysisResult(source);
|
||||
assertNoErrors(source);
|
||||
TopLevelVariableDeclaration b = analysisResult.unit.declarations[2];
|
||||
expect(b.variables.variables[0].element.type.toString(), 'int');
|
||||
verify([source]);
|
||||
}
|
||||
|
||||
test_strongMode_topLevelInstanceGetter_field_prefixedIdentifier() async {
|
||||
resetWith(options: new AnalysisOptionsImpl()..strongMode = true);
|
||||
Source source = addSource('''
|
||||
class A {
|
||||
int g;
|
||||
}
|
||||
var a = new A();
|
||||
var b = a.g;
|
||||
''');
|
||||
var analysisResult = await computeAnalysisResult(source);
|
||||
assertNoErrors(source);
|
||||
TopLevelVariableDeclaration b = analysisResult.unit.declarations[2];
|
||||
expect(b.variables.variables[0].element.type.toString(), 'int');
|
||||
verify([source]);
|
||||
}
|
||||
|
||||
test_strongMode_topLevelInstanceGetter_implicitlyTyped() async {
|
||||
resetWith(options: new AnalysisOptionsImpl()..strongMode = true);
|
||||
Source source = addSource('''
|
||||
class A {
|
||||
get g => 0;
|
||||
}
|
||||
var b = new A().g;
|
||||
''');
|
||||
await computeAnalysisResult(source);
|
||||
if (enableKernelDriver) {
|
||||
assertNoErrors(source);
|
||||
} else {
|
||||
assertErrors(source, [StrongModeCode.TOP_LEVEL_INSTANCE_GETTER]);
|
||||
}
|
||||
verify([source]);
|
||||
}
|
||||
|
||||
test_strongMode_topLevelInstanceGetter_implicitlyTyped_call() async {
|
||||
resetWith(options: new AnalysisOptionsImpl()..strongMode = true);
|
||||
Source source = addSource('''
|
||||
class A {
|
||||
get g => () => 0;
|
||||
}
|
||||
var a = new A();
|
||||
var b = a.g();
|
||||
''');
|
||||
await computeAnalysisResult(source);
|
||||
if (enableKernelDriver) {
|
||||
assertNoErrors(source);
|
||||
} else {
|
||||
assertErrors(source, [StrongModeCode.TOP_LEVEL_INSTANCE_GETTER]);
|
||||
}
|
||||
verify([source]);
|
||||
}
|
||||
|
||||
test_strongMode_topLevelInstanceGetter_implicitlyTyped_field() async {
|
||||
resetWith(options: new AnalysisOptionsImpl()..strongMode = true);
|
||||
Source source = addSource('''
|
||||
class A {
|
||||
var g = 0;
|
||||
}
|
||||
var b = new A().g;
|
||||
''');
|
||||
await computeAnalysisResult(source);
|
||||
if (enableKernelDriver) {
|
||||
assertNoErrors(source);
|
||||
} else {
|
||||
assertErrors(source, [StrongModeCode.TOP_LEVEL_INSTANCE_GETTER]);
|
||||
}
|
||||
verify([source]);
|
||||
}
|
||||
|
||||
test_strongMode_topLevelInstanceGetter_implicitlyTyped_field_call() async {
|
||||
resetWith(options: new AnalysisOptionsImpl()..strongMode = true);
|
||||
Source source = addSource('''
|
||||
class A {
|
||||
var g = () => 0;
|
||||
}
|
||||
var a = new A();
|
||||
var b = a.g();
|
||||
''');
|
||||
await computeAnalysisResult(source);
|
||||
if (enableKernelDriver) {
|
||||
assertNoErrors(source);
|
||||
} else {
|
||||
assertErrors(source, [StrongModeCode.TOP_LEVEL_INSTANCE_GETTER]);
|
||||
}
|
||||
verify([source]);
|
||||
}
|
||||
|
||||
test_strongMode_topLevelInstanceGetter_implicitlyTyped_field_prefixedIdentifier() async {
|
||||
resetWith(options: new AnalysisOptionsImpl()..strongMode = true);
|
||||
Source source = addSource('''
|
||||
class A {
|
||||
var g = 0;
|
||||
}
|
||||
var a = new A();
|
||||
var b = a.g;
|
||||
''');
|
||||
await computeAnalysisResult(source);
|
||||
if (enableKernelDriver) {
|
||||
assertNoErrors(source);
|
||||
} else {
|
||||
assertErrors(source, [StrongModeCode.TOP_LEVEL_INSTANCE_GETTER]);
|
||||
}
|
||||
verify([source]);
|
||||
}
|
||||
|
||||
test_strongMode_topLevelInstanceGetter_implicitlyTyped_prefixedIdentifier() async {
|
||||
resetWith(options: new AnalysisOptionsImpl()..strongMode = true);
|
||||
Source source = addSource('''
|
||||
class A {
|
||||
get g => 0;
|
||||
}
|
||||
var a = new A();
|
||||
var b = a.g;
|
||||
''');
|
||||
await computeAnalysisResult(source);
|
||||
if (enableKernelDriver) {
|
||||
assertNoErrors(source);
|
||||
} else {
|
||||
assertErrors(source, [StrongModeCode.TOP_LEVEL_INSTANCE_GETTER]);
|
||||
}
|
||||
verify([source]);
|
||||
}
|
||||
|
||||
test_strongMode_topLevelInstanceGetter_prefixedIdentifier() async {
|
||||
resetWith(options: new AnalysisOptionsImpl()..strongMode = true);
|
||||
Source source = addSource('''
|
||||
class A {
|
||||
int get g => 0;
|
||||
}
|
||||
var a = new A();
|
||||
var b = a.g;
|
||||
''');
|
||||
var analysisResult = await computeAnalysisResult(source);
|
||||
assertNoErrors(source);
|
||||
TopLevelVariableDeclaration b = analysisResult.unit.declarations[2];
|
||||
expect(b.variables.variables[0].element.type.toString(), 'int');
|
||||
verify([source]);
|
||||
}
|
||||
|
||||
test_typeCheck_type_is_Null() async {
|
||||
Source source = addSource(r'''
|
||||
m(i) {
|
||||
|
|
|
@ -1152,7 +1152,9 @@ abstract class AbstractResynthesizeTest extends AbstractSingleUnitTest {
|
|||
void compareVariableElements(
|
||||
VariableElement resynthesized, VariableElement original, String desc) {
|
||||
compareElements(resynthesized, original, desc);
|
||||
compareTypes(resynthesized.type, original.type, '$desc.type');
|
||||
if ((resynthesized as VariableElementImpl).typeInferenceError == null) {
|
||||
compareTypes(resynthesized.type, original.type, '$desc.type');
|
||||
}
|
||||
VariableElementImpl resynthesizedActual =
|
||||
getActualElement(resynthesized, desc);
|
||||
VariableElementImpl originalActual = getActualElement(original, desc);
|
||||
|
|
|
@ -1120,6 +1120,7 @@ string_unicode4_negative_test: CompileTimeError
|
|||
super_bound_closure_test/none: CompileTimeError
|
||||
super_setter_test: StaticWarning # Issue 28823
|
||||
switch_case_test/none: CompileTimeError
|
||||
type_inference_accessor_ref_test/06: MissingCompileTimeError
|
||||
type_inference_circularity_test: MissingCompileTimeError
|
||||
type_promotion_functions_test/01: Pass
|
||||
type_promotion_functions_test/05: Pass
|
||||
|
@ -1570,6 +1571,8 @@ transitive_private_library_access_test: MissingCompileTimeError
|
|||
try_catch_on_syntax_test/07: MissingCompileTimeError
|
||||
try_catch_syntax_test/08: MissingCompileTimeError
|
||||
type_checks_in_factory_method_test/01: MissingCompileTimeError
|
||||
type_inference_accessor_ref_test/03: MissingCompileTimeError
|
||||
type_inference_accessor_ref_test/06: MissingCompileTimeError
|
||||
type_inference_circularity_test: MissingCompileTimeError
|
||||
type_promotion_functions_test/01: MissingCompileTimeError
|
||||
type_promotion_functions_test/05: MissingCompileTimeError
|
||||
|
|
|
@ -1627,6 +1627,8 @@ library_env_test/has_no_mirror_support: Pass
|
|||
object_has_no_call_method_test/02: MissingCompileTimeError
|
||||
object_has_no_call_method_test/05: MissingCompileTimeError
|
||||
object_has_no_call_method_test/08: MissingCompileTimeError
|
||||
type_inference_accessor_ref_test/03: MissingCompileTimeError
|
||||
type_inference_accessor_ref_test/06: MissingCompileTimeError
|
||||
type_inference_circularity_test: MissingCompileTimeError
|
||||
type_inference_inconsistent_inheritance_test: MissingCompileTimeError
|
||||
|
||||
|
@ -3732,6 +3734,8 @@ stacktrace_test: Pass, RuntimeError # # Issue 12698
|
|||
truncdiv_test: RuntimeError # Issue 15246
|
||||
try_catch_on_syntax_test/10: Fail # Issue 19823
|
||||
try_catch_on_syntax_test/11: Fail # Issue 19823
|
||||
type_inference_accessor_ref_test/03: MissingCompileTimeError
|
||||
type_inference_accessor_ref_test/06: MissingCompileTimeError
|
||||
type_inference_circularity_test: MissingCompileTimeError
|
||||
type_inference_inconsistent_inheritance_test: MissingCompileTimeError
|
||||
type_variable_conflict_test/01: Fail # Issue 13702
|
||||
|
|
|
@ -884,6 +884,8 @@ try_catch_on_syntax_test/10: MissingCompileTimeError
|
|||
try_catch_on_syntax_test/11: MissingCompileTimeError
|
||||
try_catch_syntax_test/08: MissingCompileTimeError
|
||||
type_checks_in_factory_method_test/01: MissingCompileTimeError
|
||||
type_inference_accessor_ref_test/03: MissingCompileTimeError
|
||||
type_inference_accessor_ref_test/06: MissingCompileTimeError
|
||||
type_inference_circularity_test: MissingCompileTimeError
|
||||
type_inference_inconsistent_inheritance_test: MissingCompileTimeError
|
||||
type_parameter_test/05: MissingCompileTimeError
|
||||
|
|
|
@ -842,6 +842,8 @@ try_catch_on_syntax_test/10: MissingCompileTimeError
|
|||
try_catch_on_syntax_test/11: MissingCompileTimeError
|
||||
try_catch_syntax_test/08: MissingCompileTimeError
|
||||
type_checks_in_factory_method_test/01: MissingCompileTimeError
|
||||
type_inference_accessor_ref_test/03: MissingCompileTimeError
|
||||
type_inference_accessor_ref_test/06: MissingCompileTimeError
|
||||
type_inference_circularity_test: MissingCompileTimeError
|
||||
type_inference_inconsistent_inheritance_test: MissingCompileTimeError
|
||||
type_promotion_functions_test/01: MissingCompileTimeError
|
||||
|
|
42
tests/language_2/type_inference_accessor_ref_test.dart
Normal file
42
tests/language_2/type_inference_accessor_ref_test.dart
Normal file
|
@ -0,0 +1,42 @@
|
|||
// Copyright (c) 2018, 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.
|
||||
|
||||
/*@testedFeatures=inference*/
|
||||
library test;
|
||||
|
||||
class A {
|
||||
B b;
|
||||
}
|
||||
|
||||
class B {
|
||||
C get c => null;
|
||||
void set c(C value) {}
|
||||
}
|
||||
|
||||
class C {}
|
||||
|
||||
class D extends C {}
|
||||
|
||||
class E extends C {}
|
||||
|
||||
// Inferred type: A
|
||||
var a = new A();
|
||||
|
||||
// Inferred type: C
|
||||
var x = a.b.c;
|
||||
|
||||
// Inferred type: C
|
||||
var y = a.b.c ??= new D();
|
||||
|
||||
test() {
|
||||
// Verify the types of x and y by trying to assign to them.
|
||||
x = new C(); //# 01: ok
|
||||
x = new E(); //# 02: ok
|
||||
x = new B(); //# 03: compile-time error
|
||||
y = new C(); //# 04: ok
|
||||
y = new E(); //# 05: ok
|
||||
y = new B(); //# 06: compile-time error
|
||||
}
|
||||
|
||||
main() {}
|
Loading…
Reference in a new issue