blob: c4bbfff90dc7e7b9f30d5fe9341cbc012e288d78 [file] [log] [blame]
// Copyright (c) 2023, 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:expect/static_type_helper.dart";
test() {
{
// A pattern assignment can demote an assigned variable.
var x = expr<int?>();
x!;
x.expectStaticType<Exactly<int>>();
(x) = expr<int?>();
x.expectStaticType<Exactly<int?>>();
}
{
// But it won't demote an assigned variable if it's not necessary.
var x = expr<num?>();
x!;
x.expectStaticType<Exactly<num>>();
(x) = expr<int>();
x.expectStaticType<Exactly<num>>();
}
{
// Inside a pattern assignment, the type schema of a reference to an
// unpromoted variable is that variable's unpromoted type.
var x = expr<int?>();
(x) = contextType(expr<int>())..expectStaticType<Exactly<int?>>();
}
{
// But the type schema of a reference to a promoted variable is that
// variable's promoted type.
var x = expr<int?>();
x!;
x.expectStaticType<Exactly<int>>();
(x) = contextType(expr<int>())..expectStaticType<Exactly<int>>();
}
{
// A pattern assignment can promote a variable to a type of interest.
var x = expr<num>();
if (x is int) {}
x.expectStaticType<Exactly<num>>();
(x) = expr<int>();
x.expectStaticType<Exactly<int>>();
}
{
// But it won't promote a variable to a type that is not a type of interest.
var x = expr<num>();
(x) = expr<int>();
x.expectStaticType<Exactly<num>>();
}
{
// Assignment to a variable promotes the matched value, in the same way that
// matching a variable pattern promotes the matched value. In this example,
// assignment to `x` promotes the matched value from `dynamic` to `int`,
// therefore attempting to also assign the matched value to the double `y`
// produces an error.
int x;
double y;
(x && y) = expr<dynamic>();
// ^
// [analyzer] COMPILE_TIME_ERROR.PATTERN_TYPE_MISMATCH_IN_IRREFUTABLE_CONTEXT
// [cfe] The matched value of type 'int' isn't assignable to the required type 'double'.
}
{
// Assignment to a variable doesn't promote the RHS.
int x;
var y = expr<dynamic>();
(x) = y;
y.expectStaticType<Exactly<dynamic>>();
}
{
// Assignment to a variable makes it definitely assigned.
int x;
x; // Definitely not assigned
// [error column 5, length 1]
// [analyzer] COMPILE_TIME_ERROR.NOT_ASSIGNED_POTENTIALLY_NON_NULLABLE_LOCAL_VARIABLE
// [cfe] Non-nullable variable 'x' must be assigned before it can be used.
(x) = expr<int>();
x; // Definitely assigned
}
{
// A pattern assignment that assigns to a boolean variable can capture
// promotions of other variables (just as an ordinary assignment can).
var x = expr<int?>();
bool b;
(b) = x != null;
if (b) {
x.expectStaticType<Exactly<int>>();
}
}
{
// But assignment to a boolean variable in a subpattern does not capture
// promotions (since this would be unsound).
var x = expr<int?>();
bool b;
bool(foo: b) = x != null;
if (b) {
x.expectStaticType<Exactly<int?>>();
}
}
{
// Inside a record pattern, if a record's field is assigned to a variable,
// and the type of the variable is a subtype of the record's field type, the
// record's field type is promoted (but only within the match; the RHS is
// not promoted).
var x = expr<(dynamic,)>();
int y;
var z = expr<Object?>();
z as (int,);
z.expectStaticType<Exactly<(int,)>>();
((y,) && z) = x;
x.expectStaticType<Exactly<(dynamic,)>>();
// Assignment to `y` demonstrated that the matched value had type `int`, so
// `z` was not demoted
z.expectStaticType<Exactly<(int,)>>();
}
{
// If a record's field is assigned to a variable and the type of the
// variable is a supertype of the record's field type, the record's field
// type is unchanged.
var x = expr<(int,)>();
num y;
var z = expr<Object?>();
z as (int,);
((y,) && z) = x;
x.expectStaticType<Exactly<(int,)>>();
// Assignment to `y` demonstrated that the matched value had type `int`, so
// `z` was not demoted
z.expectStaticType<Exactly<(int,)>>();
}
{
// A simple case to verify that pattern assignments don't promote the RHS.
var x = expr<num>();
(_ as int) = x;
x.expectStaticType<Exactly<num>>();
}
}
T expr<T>() => throw UnimplementedError();
extension on bool {
bool get foo => throw UnimplementedError();
}
main() {}