blob: 78d947a96b2dcc49c7e3d9ccf50e02d424f9c2da [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.
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<Exactly<num>>();
// Promote x to int
if (x is int) {
x.expectStaticType<Exactly<int>>();
// Verify that demotion back to num works
x = 3.5;
x.expectStaticType<Exactly<num>>();
}
x.expectStaticType<Exactly<num>>();
}
// 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<Exactly<num?>>();
// This should promote to num, since num and num? should both be types of
// interest.
x = 3;
x.expectStaticType<Exactly<num>>();
// Promote x to int
if (x is int) {
x.expectStaticType<Exactly<int>>();
// Verify that demotion back to num works
x = 3.5;
x.expectStaticType<Exactly<num>>();
}
x.expectStaticType<Exactly<num>>();
// Verify that demotion back to num? works
x = null;
x.expectStaticType<Exactly<num?>>();
}
// 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<Exactly<num>>();
// Promote x to int
if (x is int) {
x.expectStaticType<Exactly<int>>();
// Verify that demotion back to num works
x = 3.5;
x.expectStaticType<Exactly<num>>();
}
x.expectStaticType<Exactly<num>>();
}
// 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<Exactly<num?>>();
// This should promote to num, since num and num? should both be types of
// interest.
x = 3;
x.expectStaticType<Exactly<num>>();
// Promote x to int
if (x is int) {
x.expectStaticType<Exactly<int>>();
// Verify that demotion back to num works
x = 3.5;
x.expectStaticType<Exactly<num>>();
}
x.expectStaticType<Exactly<num>>();
// Verify that demotion back to num? works
x = null;
x.expectStaticType<Exactly<num?>>();
}
// 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<Exactly<int>>();
x = 3.5; // Demote to num.
x.expectStaticType<Exactly<num>>();
}
}
// 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<Exactly<num>>();
}
// 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<Exactly<num>>();
}
}
/// 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<Exactly<num>>();
// Promote x to int
if (x is int) {
x.expectStaticType<Exactly<int>>();
// Verify that demotion back to num works
x = 3.5;
x.expectStaticType<Exactly<num>>();
}
x.expectStaticType<Exactly<num>>();
}
// 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<Exactly<num?>>();
// This should promote to num, since num and num? should both be types of
// interest.
x = 3;
x.expectStaticType<Exactly<num>>();
// Promote x to int
if (x is int) {
x.expectStaticType<Exactly<int>>();
// Verify that demotion back to num works
x = 3.5;
x.expectStaticType<Exactly<num>>();
}
x.expectStaticType<Exactly<num>>();
// Verify that demotion back to num? works
x = null;
x.expectStaticType<Exactly<num?>>();
}
// 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<Exactly<num>>();
// Promote x to int
if (x is int) {
x.expectStaticType<Exactly<int>>();
// Verify that demotion back to num works
x = 3.5;
x.expectStaticType<Exactly<num>>();
}
x.expectStaticType<Exactly<num>>();
}
// 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<Exactly<num?>>();
// This should promote to num, since num and num? should both be types of
// interest.
x = 3;
x.expectStaticType<Exactly<num>>();
// Promote x to int
if (x is int) {
x.expectStaticType<Exactly<int>>();
// Verify that demotion back to num works
x = 3.5;
x.expectStaticType<Exactly<num>>();
}
x.expectStaticType<Exactly<num>>();
// Verify that demotion back to num? works
x = null;
x.expectStaticType<Exactly<num?>>();
}
}
/// 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<Exactly<num>>();
// Verify that num? is a type of interest by demoting to it
x = null;
x.expectStaticType<Exactly<num?>>();
// Verify that num is a type of interest by promoting to it.
x = 3;
x.expectStaticType<Exactly<num>>();
}
// 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<Exactly<num>>();
// Verify that num? is a type of interest by demoting to it
x = null;
x.expectStaticType<Exactly<num?>>();
// Verify that num is a type of interest by promoting to it.
x = 3;
x.expectStaticType<Exactly<num>>();
}
}
/// 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<Exactly<num?>>();
}
// 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<Exactly<num?>>();
}
}
/// 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>(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<num>(3, 3.5, true);
}