// 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 write component of the former. That is, it tests /// errors associated with writes of local variables based on definite /// assignment. void use(Object? x) {} /// Test that it is never an error to write to a definitely unassigned local /// variable. void testDefinitelyUnassignedWrites(T t) { { var x; x = 3; } { final x; x = 3; } { int x; x = 3; } { int? x; x = 3; } { final int x; x = 3; } { final int? x; x = 3; } { final T x; x = t; } { late var x; x = 3; } { late int x; x = 3; } { late int? x; x = 3; } { late T x; x = t; } { late final x; x = 3; } { late final int x; x = 3; } { late final int? x; x = 3; } { late final T x; x = t; } } /// Test that writing to a potentially unassigned variable gives the correct /// error for each kind of variable. void testPotentiallyUnassignedWrites(bool b, T t) { // It is a compile time error to assign a value to a `final`, non-`late` local // variable which is **potentially assigned**. Thus, it is *not* a compile // time error to assign to a **definitely unassigned** `final` local variable. // Ok: not final. { var x; int y = 3; if (b) { x = y; } x = 3; } // Error: final. { final x; int y = 3; if (b) { x = y; } x = y; // ^ // [analyzer] unspecified // [cfe] unspecified } // Ok: not final. { int x; int y = 3; if (b) { x = y; } x = y; } // Ok: not final. { int? x; int y = 3; if (b) { x = y; } x = y; } // Error: final. { final int x; int y = 3; if (b) { x = y; } x = y; // ^ // [analyzer] unspecified // [cfe] unspecified } // Error: final. { final int? x; int y = 3; if (b) { x = y; } x = y; // ^ // [analyzer] unspecified // [cfe] unspecified } // Error: final. { final T x; T y = t; if (b) { x = y; } x = y; // ^ // [analyzer] unspecified // [cfe] unspecified } // Ok: late. { late var x; int y = 3; if (b) { x = y; } x = y; } // Ok: late. { late int x; int y = 3; if (b) { x = y; } x = y; } // Ok: late. { late int? x; int y = 3; if (b) { x = y; } x = y; } // Ok: late. { late T x; T y = t; if (b) { x = y; } x = y; } // Ok: late. { late final x; int y = 3; if (b) { x = y; } x = y; } // Ok: late. { late final int x; int y = 3; if (b) { x = y; } x = y; } // Ok: late. { late final int? x; int y = 3; if (b) { x = y; } x = y; } // Ok: late. { late final T x; T y = t; if (b) { x = y; } x = y; } } /// Test that writing to a definitely assigned variable gives the correct /// error for each kind of variable. void testDefinitelyAssignedWrites(T t) { // It is a compile time error to assign a value to a `final`, non-`late` local // variable which is **potentially assigned**. Thus, it is *not* a compile // time error to assign to a **definitely unassigned** `final` local variable. // It is a compile time error to assign a value to a `final`, `late` local // variable if it is **definitely assigned**. Thus, it is *not* a compile time // error to assign to a **potentially unassigned** `final`, `late` local // variable. // Ok: not final, not late. { var x; int y = 3; x = y; x = y; } // Error: final. { final x; int y = 3; x = y; x = y; // ^ // [analyzer] unspecified // [cfe] unspecified } // Ok: not final, not late. { int x; int y = 3; x = y; x = y; } // Ok: not final, not late. { int? x; int y = 3; x = y; x = y; } // Error: final. { final int x; int y = 3; x = y; x = y; // ^ // [analyzer] unspecified // [cfe] unspecified } // Error: final. { final int? x; int y = 3; x = y; x = y; // ^ // [analyzer] unspecified // [cfe] unspecified } // Error: final. { final T x; T y = t; x = y; x = y; // ^ // [analyzer] unspecified // [cfe] unspecified } // Ok: not final. { late var x; int y = 3; x = y; x = y; } // Ok: not final. { late int x; int y = 3; x = y; x = y; } // Ok: not final. { late int? x; int y = 3; x = y; x = y; } // Ok: not final. { late T x; T y = t; x = y; x = y; } // Error: final and late. { late final x; int y = 3; x = y; x = y; // ^ // [analyzer] unspecified // [cfe] unspecified } // Error: final and late. { late final int x; int y = 3; x = y; x = y; // ^ // [analyzer] unspecified // [cfe] unspecified } // Error: final and late. { late final int? x; int y = 3; x = y; x = y; // ^ // [analyzer] unspecified // [cfe] unspecified } // Error: final and late. { late final T x; T y = t; x = y; x = y; // ^ // [analyzer] unspecified // [cfe] unspecified } } /// Test that a write to a definitely unassigned variable gives no error for a /// single choice of declaration form, across a range of write constructs. Note /// that some constructs in this test also involve reads, and hence may generate /// read errors. The expectations should reflect this. void testDefinitelyUnassignedWriteForms() { { final dynamic x; x = 3; } { final dynamic x; use(x = 3); } { final dynamic x; // Should be a read error only x++; // ^ // [analyzer] unspecified // [cfe] unspecified } { final dynamic x; // Should be a read error only ++x; // ^ // [analyzer] unspecified // [cfe] unspecified } { final dynamic x; // Should be a read error only x += 3; // ^ // [analyzer] unspecified // [cfe] unspecified } { final dynamic x; // Should be a read error only x ??= 3; // ^ // [analyzer] unspecified // [cfe] unspecified } } /// Test that a write to a potentially unassigned variable gives the correct /// error for a single choice of declaration form, across a range of write /// constructs. void testPotentiallyUnassignedWriteForms(bool b) { { final dynamic x; if (b) { x = 3; } x = 3; // ^ // [analyzer] unspecified // [cfe] unspecified } { final dynamic x; if (b) { x = 3; } use(x = 3); // ^ // [analyzer] unspecified // [cfe] unspecified } { final dynamic x; if (b) { x = 3; } // Expect both a read and write error x++; // ^ // [analyzer] unspecified // [cfe] unspecified } { final dynamic x; if (b) { x = 3; } // Expect both a read and write error ++x; // ^ // [analyzer] unspecified // [cfe] unspecified } { final dynamic x; if (b) { x = 3; } // Expect both a read and write error x += 3; // ^ // [analyzer] unspecified // [cfe] unspecified } { final dynamic x; if (b) { x = 3; } // Expect both a read and write error x ??= 3; // ^ // [analyzer] unspecified // [cfe] unspecified } } /// Test that a write to a definitely assigned variable gives the correct /// error for a single choice of declaration form, across a range of write /// constructs. void testDefinitelyAssignedWriteForms() { { final dynamic x; x = 3; x = 3; // ^ // [analyzer] unspecified // [cfe] unspecified } { final dynamic x; x = 3; use(x = 3); // ^ // [analyzer] unspecified // [cfe] unspecified } { final dynamic x; x = 3; x++; // ^ // [analyzer] unspecified // [cfe] unspecified } { final dynamic x; x = 3; ++x; // ^ // [analyzer] unspecified // [cfe] unspecified } { final dynamic x; x = 3; x += 3; // ^ // [analyzer] unspecified // [cfe] unspecified } { final dynamic x; x = 3; x ??= 3; // ^ // [analyzer] unspecified // [cfe] unspecified } } void main() { testDefinitelyUnassignedWrites(0); testPotentiallyUnassignedWrites(true, 0); testDefinitelyAssignedWrites(0); testDefinitelyUnassignedWriteForms(); testPotentiallyUnassignedWriteForms(true); testDefinitelyAssignedWriteForms(); }