Detect references to instance variables without declared type.

R=paulberry@google.com

Bug: https://github.com/dart-lang/sdk/issues/33976
Change-Id: Iea377061a784d73d41a4f77f10f74077f8797813
Reviewed-on: https://dart-review.googlesource.com/75623
Reviewed-by: Paul Berry <paulberry@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
This commit is contained in:
Konstantin Shcheglov 2018-09-19 22:40:03 +00:00 committed by commit-bot@chromium.org
parent a0776096b9
commit 41273507b2
5 changed files with 78 additions and 3 deletions

View file

@ -2352,6 +2352,17 @@ class FieldElementForLink_ClassField extends VariableElementForLink
@override
bool get isStatic => unlinkedVariable.isStatic;
@override
DartType get type {
if (declaredType != null) {
return declaredType;
}
if (Linker._isPerformingVariableTypeInference && !isStatic) {
return DynamicTypeImpl.instance;
}
return inferredType;
}
@override
void set type(DartType inferredType) {
assert(!isStatic);
@ -3585,6 +3596,11 @@ class Linker {
/// instance variables in that same cycle.
static LibraryCycleForLink _initializerTypeInferenceCycle;
/// If a top-level or an instance variable type inference is in progress,
/// this flag it set to `true`. It is used to prevent type inference for
/// other instance variables (when they don't have declared type).
static bool _isPerformingVariableTypeInference = false;
/// Callback to ask the client for a [LinkedLibrary] for a
/// dependency.
final GetDependencyCallback getDependency;
@ -4952,11 +4968,13 @@ abstract class VariableElementForLink
assert(Linker._initializerTypeInferenceCycle == null);
Linker._initializerTypeInferenceCycle =
compilationUnit.library.libraryCycleForLink;
Linker._isPerformingVariableTypeInference = true;
try {
new TypeInferenceDependencyWalker().walk(_typeInferenceNode);
assert(_inferredType != null);
} finally {
Linker._initializerTypeInferenceCycle = null;
Linker._isPerformingVariableTypeInference = false;
}
} else if (compilationUnit.isInBuildUnit) {
_inferredType = DynamicTypeImpl.instance;

View file

@ -15,6 +15,7 @@ import 'instance_member_inference_class_test.dart'
import 'instance_member_inference_mixin_test.dart'
as instance_member_inference_mixin_test;
import 'mixin_test.dart' as mixin_test;
import 'top_type_inference_test.dart' as top_type_inference_test;
main() {
defineReflectiveSuite(() {
@ -27,5 +28,6 @@ main() {
instance_member_inference_class_test.main();
instance_member_inference_mixin_test.main();
mixin_test.main();
top_type_inference_test.main();
}, name: 'resolution');
}

View file

@ -0,0 +1,55 @@
// 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.
import 'package:analyzer/src/error/codes.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
import 'driver_resolution.dart';
import 'resolution.dart';
import 'task_resolution.dart';
main() {
defineReflectiveSuite(() {
defineReflectiveTests(TopTypeInferenceDriverResolutionTest);
defineReflectiveTests(TopTypeInferenceTaskResolutionTest);
});
}
@reflectiveTest
class TopTypeInferenceDriverResolutionTest extends DriverResolutionTest
with TopTypeInstanceMixin {}
@reflectiveTest
class TopTypeInferenceTaskResolutionTest extends TaskResolutionTest
with TopTypeInstanceMixin {}
abstract class TopTypeInstanceMixin implements ResolutionTest {
test_referenceInstanceVariable_withDeclaredType() async {
addTestFile(r'''
class A {
final int a = b + 1;
}
final b = new A().a;
''');
await resolveTestFile();
assertNoTestErrors();
assertElementTypeString(findElement.field('a').type, 'int');
assertElementTypeString(findElement.topVar('b').type, 'int');
}
test_referenceInstanceVariable_withoutDeclaredType() async {
addTestFile(r'''
class A {
final a = b + 1;
}
final b = new A().a;
''');
await resolveTestFile();
assertTestErrors([StrongModeCode.TOP_LEVEL_INSTANCE_GETTER]);
assertElementTypeDynamic(findElement.field('a').type);
assertElementTypeDynamic(findElement.topVar('b').type);
}
}

View file

@ -527,7 +527,7 @@ var x = new C().f; // Inferred type: int
''');
LibraryElementForLink library = linker.getLibrary(testDartUri);
expect(_getVariable(library.getContainedName('x')).inferredType.toString(),
'int');
'dynamic');
}
void test_inferredTypeFromOutsideBuildUnit_instanceField_toInstanceField() {
@ -545,7 +545,7 @@ class D {
''');
LibraryElementForLink library = linker.getLibrary(testDartUri);
ClassElementForLink_Class classD = library.getContainedName('D');
expect(classD.fields[0].inferredType.toString(), 'int');
expect(classD.fields[0].inferredType.toString(), 'dynamic');
}
void test_inferredTypeFromOutsideBuildUnit_methodParamType_viaInheritance() {

View file

@ -697,7 +697,7 @@ var t1 = x;
''');
checkElementText(library, r'''
import 'a.dart';
int t1;
dynamic t1;
''');
}