// 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. import '../../static_type_helper.dart'; /// Test that the type of a local variable is treated as a "type of interest" /// for the variable, and that for non-final variables, the initialization (if /// any) is treated as an assignment for the purposes of promotion. /// Verify that the declared type of a local variable is a type of interest. void declaredTypeIsATypeOfInterest() { // Check that a variable declared with a non-nullable type can be assignment // demoted back to its declared type after being promoted. { num x = 3; x.expectStaticType>(); // Promote x to int if (x is int) { x.expectStaticType>(); // Verify that demotion back to num works x = 3.5; x.expectStaticType>(); } x.expectStaticType>(); } // Check that a variable declared with a nullable type can be assignment // promoted to the non-nullable variant of its type, and demoted back to both // the non-nullable variant and the declared type after being promoted. { num? x = (3 as num?); x.expectStaticType>(); // This should promote to num, since num and num? should both be types of // interest. x = 3; x.expectStaticType>(); // Promote x to int if (x is int) { x.expectStaticType>(); // Verify that demotion back to num works x = 3.5; x.expectStaticType>(); } x.expectStaticType>(); // Verify that demotion back to num? works x = null; x.expectStaticType>(); } // Check that a late variable declared with a non-nullable type can be // assignment demoted back to its declared type after being promoted. { late num x = 3; x.expectStaticType>(); // Promote x to int if (x is int) { x.expectStaticType>(); // Verify that demotion back to num works x = 3.5; x.expectStaticType>(); } x.expectStaticType>(); } // Check that a late variable declared with a nullable type can be assignment // promoted to the non-nullable variant of its type, and demoted back to both // the non-nullable variant and the declared type after being promoted. { late num? x = (3 as num?); x.expectStaticType>(); // This should promote to num, since num and num? should both be types of // interest. x = 3; x.expectStaticType>(); // Promote x to int if (x is int) { x.expectStaticType>(); // Verify that demotion back to num works x = 3.5; x.expectStaticType>(); } x.expectStaticType>(); // Verify that demotion back to num? works x = null; x.expectStaticType>(); } // Final variables are not re-assignable, but can still be subject to // to assignment based promotion and demotion in a few situations. // Check that a late final variable declared with a non-nullable type can be // assignment demoted back to its declared type after being promoted. { late final num x; // Make x potentially assigned, and initialize it if (num == num) { x = 3.5; } // Branch will not be taken to avoid a double initialization error if (x is int) { x.expectStaticType>(); x = 3.5; // Demote to num. x.expectStaticType>(); } } // Check that a final variable declared with a non-nullable type can be // assignment promoted to the non-nullable variant of its type. { final num? x; // Promote to num, since num is a type of interest x = 3; // Verify that we have promoted to num x.expectStaticType>(); } // Check that a late final variable declared with a non-nullable type can be // assignment promoted to the non-nullable variant of its type. { late final num? x; // Promote to num, since num is a type of interest x = 3; // Verify that we have promoted to num x.expectStaticType>(); } } /// Verify that the inferred type of a local variable is a type of interest. void inferredTypeIsATypeOfInterest() { // Check that a variable inferred with a non-nullable type can be // assignment demoted back to its declared type after being promoted. { var x = (3 as num); x.expectStaticType>(); // Promote x to int if (x is int) { x.expectStaticType>(); // Verify that demotion back to num works x = 3.5; x.expectStaticType>(); } x.expectStaticType>(); } // Check that a variable inferred to have a nullable type can be assignment // promoted to the non-nullable variant of its type, and demoted back to both // the non-nullable variant and the declared type after being promoted. { var x = (3 as num?); x.expectStaticType>(); // This should promote to num, since num and num? should both be types of // interest. x = 3; x.expectStaticType>(); // Promote x to int if (x is int) { x.expectStaticType>(); // Verify that demotion back to num works x = 3.5; x.expectStaticType>(); } x.expectStaticType>(); // Verify that demotion back to num? works x = null; x.expectStaticType>(); } // Check that a variable inferred with a non-nullable type can be // assignment demoted back to its declared type after being promoted. { late var x = (3 as num); x.expectStaticType>(); // Promote x to int if (x is int) { x.expectStaticType>(); // Verify that demotion back to num works x = 3.5; x.expectStaticType>(); } x.expectStaticType>(); } // Check that a late variable inferred to have a nullable type can be // assignment promoted to the non-nullable variant of its type, and demoted // back to both the non-nullable variant and the declared type after being // promoted. { late var x = (3 as num?); x.expectStaticType>(); // This should promote to num, since num and num? should both be types of // interest. x = 3; x.expectStaticType>(); // Promote x to int if (x is int) { x.expectStaticType>(); // Verify that demotion back to num works x = 3.5; x.expectStaticType>(); } x.expectStaticType>(); // Verify that demotion back to num? works x = null; x.expectStaticType>(); } } /// Verify that the initializer on a mutable variable is treated as if it were /// an assignment for the purposes of promotion, and therefore assigning a /// non-nullable value can promote to a non-nullable variant of the declared /// type. void initializersOnVarPromote() { // Check that a variable declared to have a nullable type can be promoted on // initialization to the non-nullable variant of its type, demoted back to the // declared type, and assignment promoted to the non-nullable variant of the // declared type. { num? x = 3; // Verify that we have promoted to num x.expectStaticType>(); // Verify that num? is a type of interest by demoting to it x = null; x.expectStaticType>(); // Verify that num is a type of interest by promoting to it. x = 3; x.expectStaticType>(); } // Check that a late variable declared to have a nullable type can be promoted // on initialization to the non-nullable variant of its type, demoted back to // the declared type, and assignment promoted to the non-nullable variant of // the declared type. { late num? x = 3; // Verify that we have promoted to num x.expectStaticType>(); // Verify that num? is a type of interest by demoting to it x = null; x.expectStaticType>(); // Verify that num is a type of interest by promoting to it. x = 3; x.expectStaticType>(); } } /// Verify that the initializer on a final variable is not treated as if it were /// an assignment for the purposes of promotion, and therefore assigning a /// non-nullable value does not promote to a non-nullable variant of the /// declared type. void initializersOnFinalDoNotPromote() { // Check that a final nullable variable initialized with a non-nullable value // does not get promoted by the initializer to the non-nullable variant of the // type. { final num? x = 3; // Verify that we have not promoted to num x.expectStaticType>(); } // Check that a late final nullable variable initialized with a non-nullable // value does not get promoted by the initializer to the non-nullable variant // of the type. { late final num? x = 3; // Verify that we have not promoted to num x.expectStaticType>(); } } /// Check that when an initializer is a promoted type variable `X & T`, the /// inferred type of the variable is `X`, but that the variable is immediately /// promoted to `X & T`. void typeVariableTypedVariableInferencePromotes(T x0, T x1, bool b) { if (x0 is num) { // Promote `x0` to T & num { // Declare y, which should have inferred type T, and be promoted to T & // num var y = x0; // Check that y is assignable to z, and hence that y is still promoted to // T & num num z = y; // Check that y can be demoted to T, but do it conditionally so that T & // num remains a type of interest. if (b) y = x1; // T & num is still a type of interest, and hence this assignment should // promote to T & num. y = x0; // Check that y is assignable to z, and hence that y has been promoted T & // num z = y; } { // Declare y, which should have inferred type T, and be promoted to T & // num late var y = x0; // Check that y is assignable to z, and hence that y is still promoted to // T & num num z = y; // Check that y can be demoted to T, but do it conditionally so that T & // num remains a type of interest. if (b) y = x1; // T & num is still a type of interest, and hence this assignment should // promote to T & num. y = x0; // Check that y is assignable to z, and hence that y has been promoted T & // num z = y; } { // Declare y, which should have inferred type T, and be promoted to T & // num final y = x0; // Check that y is assignable to z, and hence that y is still promoted to // T & num num z = y; } { // Declare y, which should have inferred type T, and be promoted to T & // num late final y = x0; // Check that y is assignable to z, and hence that y is still promoted to // T & num num z = y; } } } void main() { declaredTypeIsATypeOfInterest(); inferredTypeIsATypeOfInterest(); initializersOnVarPromote(); initializersOnFinalDoNotPromote(); typeVariableTypedVariableInferencePromotes(3, 3.5, true); }