blob: 497f0bb4748e3cee322fa0fca332cc80d21758f4 [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.
// Tests that language operators and constructrs requiring non-nullable values
// will not accept an operand with a nullable static type.
// See: https://github.com/dart-lang/language/issues/298
main() {
nonNullable();
potentiallyNonNullable<bool>();
nullable();
potentiallyNullable();
}
dynamic nonNullable() {
// Check that a nullable expression is not allowed where a non-nullable
// value is required.
bool? bq = maybeNullable(true); // Prevent promotion.
bool b = true;
dynamic _;
_ = bq && b;
// ^^
// [analyzer] unspecified
// [cfe] A value of type 'bool?' can't be assigned to a variable of type 'bool' because 'bool?' is nullable and 'bool' isn't.
_ = b && bq;
// ^^
// [analyzer] unspecified
// [cfe] A value of type 'bool?' can't be assigned to a variable of type 'bool' because 'bool?' is nullable and 'bool' isn't.
_ = bq || b;
// ^^
// [analyzer] unspecified
// [cfe] A value of type 'bool?' can't be assigned to a variable of type 'bool' because 'bool?' is nullable and 'bool' isn't.
_ = b || bq;
// ^^
// [analyzer] unspecified
// [cfe] A value of type 'bool?' can't be assigned to a variable of type 'bool' because 'bool?' is nullable and 'bool' isn't.
_ = !bq;
// ^^
// [analyzer] unspecified
// [cfe] A value of type 'bool?' can't be assigned to a variable of type 'bool' because 'bool?' is nullable and 'bool' isn't.
_ = bq ? "a" : "b";
// ^^
// [analyzer] unspecified
// [cfe] A value of type 'bool?' can't be assigned to a variable of type 'bool' because 'bool?' is nullable and 'bool' isn't.
if (bq) {}
// ^^
// [analyzer] unspecified
// [cfe] A value of type 'bool?' can't be assigned to a variable of type 'bool' because 'bool?' is nullable and 'bool' isn't.
while (bq) {}
// ^^
// [analyzer] unspecified
// [cfe] A value of type 'bool?' can't be assigned to a variable of type 'bool' because 'bool?' is nullable and 'bool' isn't.
do {} while (bq);
// ^^
// [analyzer] unspecified
// [cfe] A value of type 'bool?' can't be assigned to a variable of type 'bool' because 'bool?' is nullable and 'bool' isn't.
for (; bq;) {}
// ^^
// [analyzer] unspecified
// [cfe] A value of type 'bool?' can't be assigned to a variable of type 'bool' because 'bool?' is nullable and 'bool' isn't.
try {
throw bq;
// ^^
// [analyzer] unspecified
// [cfe] Can't throw a value of 'bool?' since it is neither dynamic nor non-nullable.
} catch (e) {}
assert(bq);
// ^^
// [analyzer] unspecified
// [cfe] A value of type 'bool?' can't be assigned to a variable of type 'bool' because 'bool?' is nullable and 'bool' isn't.
_ = [if (bq) 1];
// ^^
// [analyzer] unspecified
// [cfe] A value of type 'bool?' can't be assigned to a variable of type 'bool' because 'bool?' is nullable and 'bool' isn't.
_ = [for (; bq;) 1];
// ^^
// [analyzer] unspecified
// ^
// [cfe] A value of type 'bool?' can't be assigned to a variable of type 'bool' because 'bool?' is nullable and 'bool' isn't.
Iterable<int>? iq = maybeNullable([1]);
for (var v in iq) {}
// ^^
// [analyzer] unspecified
// [cfe] The type 'Iterable<int>?' used in the 'for' loop must implement 'Iterable<dynamic>' because 'Iterable<int>?' is nullable and 'Iterable<dynamic>' isn't.
_ = [...iq];
// ^
// [cfe] An expression whose value can be 'null' must be null-checked before it can be dereferenced.
// ^^
// [analyzer] unspecified
Stream<Object?> foo() async* {
Stream<int>? sq = maybeNullable(Stream<int>.fromIterable([1]));
await for (var v in sq) {}
// ^^
// [analyzer] unspecified
// [cfe] The type 'Stream<int>?' used in the 'for' loop must implement 'Stream<dynamic>' because 'Stream<int>?' is nullable and 'Stream<dynamic>' isn't.
yield* sq;
// ^^
// [analyzer] unspecified
// [cfe] A value of type 'Stream<int>?' can't be assigned to a variable of type 'Stream<Object?>' because 'Stream<int>?' is nullable and 'Stream<Object?>' isn't.
}
foo().toList();
C.factory();
return _;
}
dynamic potentiallyNonNullable<BQ extends bool?>() {
// Check that a potentially nullable expression is not allowed where
// a non-null value is required.
BQ bq = maybeNotNullable<BQ>(true);
bool b = true;
dynamic _;
_ = bq && b;
// ^^
// [analyzer] unspecified
// [cfe] A value of type 'BQ' can't be assigned to a variable of type 'bool' because 'bool?' is nullable and 'bool' isn't.
_ = b && bq;
// ^^
// [analyzer] unspecified
// [cfe] A value of type 'BQ' can't be assigned to a variable of type 'bool' because 'bool?' is nullable and 'bool' isn't.
_ = bq || b;
// ^^
// [analyzer] unspecified
// [cfe] A value of type 'BQ' can't be assigned to a variable of type 'bool' because 'bool?' is nullable and 'bool' isn't.
_ = b || bq;
// ^^
// [analyzer] unspecified
// [cfe] A value of type 'BQ' can't be assigned to a variable of type 'bool' because 'bool?' is nullable and 'bool' isn't.
_ = !bq;
// ^^
// [analyzer] unspecified
// [cfe] A value of type 'BQ' can't be assigned to a variable of type 'bool' because 'bool?' is nullable and 'bool' isn't.
_ = bq ? "a" : "b";
// ^^
// [analyzer] unspecified
// [cfe] A value of type 'BQ' can't be assigned to a variable of type 'bool' because 'bool?' is nullable and 'bool' isn't.
if (bq) {}
// ^^
// [analyzer] unspecified
// [cfe] A value of type 'BQ' can't be assigned to a variable of type 'bool' because 'bool?' is nullable and 'bool' isn't.
while (bq) {}
// ^^
// [analyzer] unspecified
// [cfe] A value of type 'BQ' can't be assigned to a variable of type 'bool' because 'bool?' is nullable and 'bool' isn't.
do {} while (bq);
// ^^
// [analyzer] unspecified
// [cfe] A value of type 'BQ' can't be assigned to a variable of type 'bool' because 'bool?' is nullable and 'bool' isn't.
for (; bq;) {}
// ^^
// [analyzer] unspecified
// [cfe] A value of type 'BQ' can't be assigned to a variable of type 'bool' because 'bool?' is nullable and 'bool' isn't.
try {
throw bq;
// ^^
// [analyzer] unspecified
// [cfe] Can't throw a value of 'BQ' since it is neither dynamic nor non-nullable.
} catch (e) {}
assert(bq);
// ^^
// [analyzer] unspecified
// [cfe] A value of type 'BQ' can't be assigned to a variable of type 'bool' because 'bool?' is nullable and 'bool' isn't.
_ = [if (bq) 1];
// ^^
// [analyzer] unspecified
// [cfe] A value of type 'BQ' can't be assigned to a variable of type 'bool' because 'bool?' is nullable and 'bool' isn't.
_ = [for (; bq;) 1];
// ^^
// [analyzer] unspecified
// ^
// [cfe] A value of type 'BQ' can't be assigned to a variable of type 'bool' because 'bool?' is nullable and 'bool' isn't.
Iterable<int>? iq = maybeNullable([1]);
for (var v in iq) {}
// ^^
// [analyzer] unspecified
// [cfe] The type 'Iterable<int>?' used in the 'for' loop must implement 'Iterable<dynamic>' because 'Iterable<int>?' is nullable and 'Iterable<dynamic>' isn't.
_ = [...iq];
// ^^
// [analyzer] unspecified
// [cfe] An expression whose value can be 'null' must be null-checked before it can be dereferenced.
Stream<Object?> foo<SQ extends Stream<Object?>?>() async* {
SQ sq = maybeNotNullable<SQ>(Stream<int>.fromIterable([1]));
await for (var v in sq) {}
// ^^
// [analyzer] unspecified
// [cfe] The type 'Stream<Object?>?' used in the 'for' loop must implement 'Stream<dynamic>' because 'Stream<Object?>?' is nullable and 'Stream<dynamic>' isn't.
yield* sq;
// ^^
// [analyzer] unspecified
// [cfe] A value of type 'SQ' can't be assigned to a variable of type 'Stream<Object?>' because 'Stream<Object?>?' is nullable and 'Stream<Object?>' isn't.
}
foo<Stream<Object?>>().toList();
C.factory();
return _;
}
T? maybeNullable<T>(Object value) =>
identical(value, Object()) ? null : value as T;
T maybeNotNullable<T>(Object value) => value as T;
class C {
C();
factory C.factory() {
C? cq = maybeNullable(C());
// A factory constructor must not return `null`.
return cq;
// ^^
// [analyzer] unspecified
// [cfe] A value of type 'C?' can't be returned from a function with return type 'C' because 'C?' is nullable and 'C' isn't.
}
}
dynamic nullable() {
// Check places where the operand type must be *nullable*.
// This should only generate *warnings*, not errors.
// This is generally null-aware operations.
int nn = 0;
dynamic _;
_ = nn ?? 1;
// ^^
// [analyzer] unspecified
// [cfe] Operand of null-aware operation '??' has type 'int' which excludes null.
_ = nn ??= 1;
// ^^
// [analyzer] unspecified
// [cfe] Operand of null-aware operation '??=' has type 'int' which excludes null.
_ = nn?.toRadixString(16);
// ^^
// [analyzer] unspecified
// [cfe] Operand of null-aware operation '?.' has type 'int' which excludes null.
_ = nn?..toRadixString(16);
// ^^
// [analyzer] unspecified
// [cfe] Operand of null-aware operation '?..' has type 'int' which excludes null.
_ = nn!;
// ^^
// [analyzer] unspecified
// [cfe] Operand of null-aware operation '!' has type 'int' which excludes null.
List<int> nni = [1];
_ = [...?nni];
// ^^^
// [analyzer] unspecified
// [cfe] Operand of null-aware operation '...?' has type 'List<int>' which excludes null.
_ = nni?[0];
// ^^^
// [analyzer] unspecified
// [cfe] Operand of null-aware operation '?.' has type 'List<int>' which excludes null.
return _;
}
void potentiallyNullable<NN extends int?, NNI extends List<int>?>() {
// Check places where the operand type must not be *non-nullable*.
// See that it does allow *potentially* nullable expression.
// This allows a potentially nullable value to be implicitly used as
// nullable (which is a safe approximation, since it might be one,
// and if not, it's just not null).
NN nn = maybeNotNullable<NN>(0);
nn ?? 1;
nn ??= maybeNotNullable<NN>(1);
nn?.toRadixString(16);
nn?..toRadixString(16);
nn!;
NNI nni = maybeNotNullable<NNI>(<int>[1]);
[...?nni];
nni?[0];
}