blob: 2747df33aeb1c473a59565cb43a0845baa36f373 [file] [log] [blame]
// Copyright (c) 2020, 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.
/// To avoid having tests for the cross product of declaration forms and control
/// flow constructs, the tests in this directory are split into tests that check
/// that each different kind of variable declaration is treated appropriately
/// with respect to errors and warnings for a single control flow construct; and
/// tests that check that a reasonable subset of the possible control flow
/// patterns produce the expected definite (un)-assignment behavior.
///
/// This test checks the the read component of the former. That is, it tests
/// errors associated with reads of local variables based on definite
/// assignment.
void use(Object? x) {}
/// Test that a read of a definitely unassigned variable gives the correct error
/// for each kind of variable.
void testDefinitelyUnassignedReads<T>() {
// It is a compile time error to read a local variable when the variable is
// **definitely unassigned** unless the variable is non-`final`, and
// non-`late`, and has nullable type.
// Ok: non-final and nullably typed.
{
var x;
use(x);
}
// Error: final.
{
final x;
use(x);
// ^
// [analyzer] unspecified
// [cfe] unspecified
}
// Error: not nullable.
{
int x;
use(x);
// ^
// [analyzer] unspecified
// [cfe] unspecified
}
// Ok: non-final and nullably typed.
{
int? x;
use(x);
}
// Error: final and not nullable.
{
final int x;
use(x);
// ^
// [analyzer] unspecified
// [cfe] unspecified
}
// Error: final.
{
final int? x;
use(x);
// ^
// [analyzer] unspecified
// [cfe] unspecified
}
// Error: final and not nullable.
{
final T x;
use(x);
// ^
// [analyzer] unspecified
// [cfe] unspecified
}
// Error: late
{
late var x;
use(x);
// ^
// [analyzer] unspecified
// [cfe] unspecified
}
// Error: late and not nullable
{
late int x;
use(x);
// ^
// [analyzer] unspecified
// [cfe] unspecified
}
// Error: late
{
late int? x;
use(x);
// ^
// [analyzer] unspecified
// [cfe] unspecified
}
// Error: late and not nullable
{
late T x;
use(x);
// ^
// [analyzer] unspecified
// [cfe] unspecified
}
// Error: late and final
{
late final x;
use(x);
// ^
// [analyzer] unspecified
// [cfe] unspecified
}
// Error: late and final and not nullable
{
late final int x;
use(x);
// ^
// [analyzer] unspecified
// [cfe] unspecified
}
// Error: late and final
{
late final int? x;
use(x);
// ^
// [analyzer] unspecified
// [cfe] unspecified
}
// Error: late and final and not nullable
{
late final T x;
use(x);
// ^
// [analyzer] unspecified
// [cfe] unspecified
}
}
/// Test that a read of a potentially unassigned variable gives the correct
/// error for each kind of variable.
void testPotentiallyUnassignedReads<T>(bool b, T t) {
// It is a compile time error to read a local variable when the variable is
// **potentially unassigned** unless the variable is non-final and has
// nullable type, or is `late`.
// Ok: non-final and nullable.
{
var x;
int y = 3;
if (b) {
x = y;
}
use(x);
}
// Error: final.
{
final x;
int y = 3;
if (b) {
x = y;
}
use(x);
// ^
// [analyzer] unspecified
// [cfe] unspecified
}
// Error: not nullable.
{
int x;
int y = 3;
if (b) {
x = y;
}
use(x);
// ^
// [analyzer] unspecified
// [cfe] unspecified
}
// Ok: non-final and nullable.
{
int? x;
int y = 3;
if (b) {
x = y;
}
use(x);
}
// Error: final and not nullable.
{
final int x;
int y = 3;
if (b) {
x = y;
}
use(x);
// ^
// [analyzer] unspecified
// [cfe] unspecified
}
// Error: final.
{
final int? x;
int y = 3;
if (b) {
x = y;
}
use(x);
// ^
// [analyzer] unspecified
// [cfe] unspecified
}
// Error: final and not nullable.
{
final T x;
T y = t;
if (b) {
x = y;
}
use(x);
// ^
// [analyzer] unspecified
// [cfe] unspecified
}
// Ok: late.
{
late var x;
int y = 3;
if (b) {
x = y;
}
use(x);
}
// Ok: late.
{
late int x;
int y = 3;
if (b) {
x = y;
}
use(x);
}
// Ok: late.
{
late int? x;
int y = 3;
if (b) {
x = y;
}
use(x);
}
// Ok: late.
{
late T x;
T y = t;
if (b) {
x = y;
}
use(x);
}
// Ok: late.
{
late final x;
int y = 3;
if (b) {
x = y;
}
use(x);
}
// Ok: late.
{
late final int x;
int y = 3;
if (b) {
x = y;
}
use(x);
}
// Ok: late.
{
late final int? x;
int y = 3;
if (b) {
x = y;
}
use(x);
}
// Ok: late.
{
late final T x;
T y = t;
if (b) {
x = y;
}
use(x);
}
}
/// Test that reading a definitely assigned variable is not an error.
void testDefinitelyAssignedReads<T>(T t) {
// It is never an error to read a definitely assigned variable.
{
var x;
int y = 3;
x = y;
use(x);
}
{
final x;
int y = 3;
x = y;
use(x);
}
{
int x;
int y = 3;
x = y;
use(x);
}
{
int? x;
int y = 3;
x = y;
use(x);
}
{
final int x;
int y = 3;
x = y;
use(x);
}
{
final int? x;
int y = 3;
x = y;
use(x);
}
{
final T x;
T y = t;
x = y;
use(x);
}
{
late var x;
int y = 3;
x = y;
use(x);
}
{
late int x;
int y = 3;
x = y;
use(x);
}
{
late int? x;
int y = 3;
x = y;
use(x);
}
{
late T x;
T y = t;
x = y;
use(x);
}
{
late final x;
int y = 3;
x = y;
use(x);
}
{
late final int x;
int y = 3;
x = y;
use(x);
}
{
late final int? x;
int y = 3;
x = y;
use(x);
}
{
late final T x;
T y = t;
x = y;
use(x);
}
}
/// Test that a read of a definitely unassigned variable gives the correct error
/// for a single choice of declaration form, across a range of read constructs.
///
/// These tests declare a `final` variable of type `dynamic` with no initializer
/// and no assignments, and test that it is an error to use the variable
/// in a variety of syntactic positions.
void testDefinitelyUnassignedReadForms() {
{
final dynamic x;
x;
// ^
// [analyzer] unspecified
// [cfe] unspecified
}
{
final dynamic x;
use(x);
// ^
// [analyzer] unspecified
// [cfe] unspecified
}
{
final dynamic x;
x(use);
// ^
// [analyzer] unspecified
// [cfe] unspecified
}
{
final dynamic x;
x.foo;
// ^
// [analyzer] unspecified
// [cfe] unspecified
}
{
final dynamic x;
x.foo();
// ^
// [analyzer] unspecified
// [cfe] unspecified
}
{
final dynamic x;
x.foo = 3;
// ^
// [analyzer] unspecified
// [cfe] unspecified
}
{
final dynamic x;
x?.foo;
// ^
// [analyzer] unspecified
// [cfe] unspecified
}
{
final dynamic x;
x..foo;
// ^
// [analyzer] unspecified
// [cfe] unspecified
}
{
final dynamic x;
x[0];
// ^
// [analyzer] unspecified
// [cfe] unspecified
}
{
final dynamic x;
([3])[x];
// ^
// [analyzer] unspecified
// [cfe] unspecified
}
{
final dynamic x;
(x as int);
// ^
// [analyzer] unspecified
// [cfe] unspecified
}
{
final dynamic x;
(x is int);
// ^
// [analyzer] unspecified
// [cfe] unspecified
}
{
final dynamic x;
(x == null);
// ^
// [analyzer] unspecified
// [cfe] unspecified
}
{
final dynamic x;
(null == x);
// ^
// [analyzer] unspecified
// [cfe] unspecified
}
{
final dynamic x;
(3 == x);
// ^
// [analyzer] unspecified
// [cfe] unspecified
}
{
final dynamic x;
(x == 3);
// ^
// [analyzer] unspecified
// [cfe] unspecified
}
{
final dynamic x;
(x == 3);
// ^
// [analyzer] unspecified
// [cfe] unspecified
}
{
final dynamic x;
x++;
// ^
// [analyzer] unspecified
// [cfe] unspecified
}
{
final dynamic x;
++x;
// ^
// [analyzer] unspecified
// [cfe] unspecified
}
{
final dynamic x;
-x;
// ^
// [analyzer] unspecified
// [cfe] unspecified
}
{
final dynamic x;
x += 3;
// ^
// [analyzer] unspecified
// [cfe] unspecified
}
{
final dynamic x;
x ??= 3;
// ^
// [analyzer] unspecified
// [cfe] unspecified
}
{
final dynamic x;
x ?? 3;
// ^
// [analyzer] unspecified
// [cfe] unspecified
}
{
final dynamic x;
3 ?? x;
// ^
// [analyzer] unspecified
// [cfe] unspecified
}
}
/// Test that a read of a potentially unassigned variable gives the correct
/// error for a single choice of declaration form, across a range of read
/// constructs.
///
/// These tests declare a `final` variable of type `dynamic` and assign to it in
/// one branch of a conditional such that the variable is potentially but not
/// definitely assigned. The test then checks that it is an error to use the
/// variable in a variety of syntactic positions.
void testPotentiallyUnassignedReadForms(bool b) {
{
final dynamic x;
if (b) {
x = 3;
}
x;
// ^
// [analyzer] unspecified
// [cfe] unspecified
}
{
final dynamic x;
if (b) {
x = 3;
}
use(x);
// ^
// [analyzer] unspecified
// [cfe] unspecified
}
{
final dynamic x;
if (b) {
x = 3;
}
x(use);
// ^
// [analyzer] unspecified
// [cfe] unspecified
}
{
final dynamic x;
if (b) {
x = 3;
}
x.foo;
// ^
// [analyzer] unspecified
// [cfe] unspecified
}
{
final dynamic x;
if (b) {
x = 3;
}
x.foo();
// ^
// [analyzer] unspecified
// [cfe] unspecified
}
{
final dynamic x;
if (b) {
x = 3;
}
x.foo = 3;
// ^
// [analyzer] unspecified
// [cfe] unspecified
}
{
final dynamic x;
if (b) {
x = 3;
}
x?.foo;
// ^
// [analyzer] unspecified
// [cfe] unspecified
}
{
final dynamic x;
if (b) {
x = 3;
}
x..foo;
// ^
// [analyzer] unspecified
// [cfe] unspecified
}
{
final dynamic x;
if (b) {
x = 3;
}
x[0];
// ^
// [analyzer] unspecified
// [cfe] unspecified
}
{
final dynamic x;
if (b) {
x = 3;
}
([3])[x];
// ^
// [analyzer] unspecified
// [cfe] unspecified
}
{
final dynamic x;
if (b) {
x = 3;
}
(x as int);
// ^
// [analyzer] unspecified
// [cfe] unspecified
}
{
final dynamic x;
if (b) {
x = 3;
}
(x is int);
// ^
// [analyzer] unspecified
// [cfe] unspecified
}
{
final dynamic x;
if (b) {
x = 3;
}
(x == null);
// ^
// [analyzer] unspecified
// [cfe] unspecified
}
{
final dynamic x;
if (b) {
x = 3;
}
(null == x);
// ^
// [analyzer] unspecified
// [cfe] unspecified
}
{
final dynamic x;
if (b) {
x = 3;
}
(3 == x);
// ^
// [analyzer] unspecified
// [cfe] unspecified
}
{
final dynamic x;
if (b) {
x = 3;
}
(x == 3);
// ^
// [analyzer] unspecified
// [cfe] unspecified
}
{
final dynamic x;
if (b) {
x = 3;
}
(x == 3);
// ^
// [analyzer] unspecified
// [cfe] unspecified
}
{
final dynamic x;
if (b) {
x = 3;
}
x++;
// ^
// [analyzer] unspecified
// [cfe] unspecified
}
{
final dynamic x;
if (b) {
x = 3;
}
++x;
// ^
// [analyzer] unspecified
// [cfe] unspecified
}
{
final dynamic x;
if (b) {
x = 3;
}
-x;
// ^
// [analyzer] unspecified
// [cfe] unspecified
}
{
final dynamic x;
if (b) {
x = 3;
}
x += 3;
// ^
// [analyzer] unspecified
// [cfe] unspecified
}
{
final dynamic x;
if (b) {
x = 3;
}
x ??= 3;
// ^
// [analyzer] unspecified
// [cfe] unspecified
}
{
final dynamic x;
if (b) {
x = 3;
}
x ?? 3;
// ^
// [analyzer] unspecified
// [cfe] unspecified
}
{
final dynamic x;
if (b) {
x = 3;
}
3 ?? x;
// ^
// [analyzer] unspecified
// [cfe] unspecified
}
}
/// Test that a read of a definitely assigned variable is not an error for a
/// single choice of declaration form, across a range of read constructs.
///
/// This test declares a final variable and then initializes it via an
/// assignment. The test then verifies that it is not an error to read the
/// variable in a variety of syntactic positions.
void testDefinitelyAssignedReadForms() {
{
final dynamic x;
x = 3;
x;
}
{
final dynamic x;
x = 3;
use(x);
}
{
final dynamic x;
x = 3;
x(use);
}
{
final dynamic x;
x = 3;
x.foo;
}
{
final dynamic x;
x = 3;
x.foo();
}
{
final dynamic x;
x = 3;
x.foo = 3;
}
{
final dynamic x;
x = 3;
x?.foo;
}
{
final dynamic x;
x = 3;
x..foo;
}
{
final dynamic x;
x = 3;
x[0];
}
{
final dynamic x;
x = 3;
([3])[x];
}
{
final dynamic x;
x = 3;
(x as int);
}
{
final dynamic x;
x = 3;
(x is int);
}
{
final dynamic x;
x = 3;
(x == null);
}
{
final dynamic x;
x = 3;
(null == x);
}
{
final dynamic x;
x = 3;
(3 == x);
}
{
final dynamic x;
x = 3;
(x == 3);
}
{
final dynamic x;
x = 3;
(x == 3);
}
{
final dynamic x;
x = 3;
x++;
// ^
// [analyzer] COMPILE_TIME_ERROR.ASSIGNMENT_TO_FINAL_LOCAL
// [cfe] Final variable 'x' might already be assigned at this point.
}
{
final dynamic x;
x = 3;
++x;
// ^
// [analyzer] COMPILE_TIME_ERROR.ASSIGNMENT_TO_FINAL_LOCAL
// [cfe] Final variable 'x' might already be assigned at this point.
}
{
final dynamic x;
x = 3;
-x;
}
{
final dynamic x;
x = 3;
x += 3;
// ^
// [analyzer] COMPILE_TIME_ERROR.ASSIGNMENT_TO_FINAL_LOCAL
// [cfe] Final variable 'x' might already be assigned at this point.
}
{
final dynamic x;
x = 3;
x ??= 3;
// ^
// [analyzer] COMPILE_TIME_ERROR.ASSIGNMENT_TO_FINAL_LOCAL
// [cfe] Final variable 'x' might already be assigned at this point.
}
{
final dynamic x;
x = 3;
x ?? 3;
}
{
final dynamic x;
x = 3;
3 ?? x;
// ^
// [cfe] Operand of null-aware operation '??' has type 'int' which excludes null.
// ^
// [analyzer] STATIC_WARNING.DEAD_NULL_AWARE_EXPRESSION
}
}
void main() {
testDefinitelyUnassignedReads<int>();
testPotentiallyUnassignedReads<int>(true, 0);
testDefinitelyAssignedReads<int>(0);
testDefinitelyUnassignedReadForms();
testPotentiallyUnassignedReadForms(true);
testDefinitelyAssignedReadForms();
}