dart-sdk/tests/language/patterns/for_in_nullable_error_test.dart
Paul Berry 872ef163f1 Fix missing analyzer error when pattern for-in iterable is nullable.
This was a mistake in the shared logic implementation during the
implementation of patterns; instead of verifying that the for-in
expression is a subtype of `Iterable<dynamic>` (or `Stream<dynamic>`
in the case of an `await for`), it merely verifies that it's a subtype
of `Iterable<dynamic>?` (or `Stream<dynamic>?`). At some point, the
requisite error checking was added to the front end, but not to the
analyzer.

In an ideal world, the solution would be to remove the error check
from the front end and add it to the shared logic; however, doing so
is not easy, because what needs to be done is an assignability check
(as well as insertion of implicit downcasts and other coercions). The
shared logic doesn't currently have a good hook for doing that. So,
for now, this CL simply adds the requisite check to the analyzer. I
plan to try to find a clean way to share some of this logic in a
follow-up CL.

Fixes https://github.com/dart-lang/sdk/issues/54671.

Change-Id: Ib2fa8bce758dfe12401d85850666674ca1317e3f
Bug: https://github.com/dart-lang/sdk/issues/54671
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/347360
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Reviewed-by: Samuel Rawlins <srawlins@google.com>
Commit-Queue: Paul Berry <paulberry@google.com>
2024-01-24 22:23:09 +00:00

120 lines
6.6 KiB
Dart

// Copyright (c) 2024, 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.
/// Test that pattern for-in statements do not accept a nullable iterable
/// expression (https://github.com/dart-lang/sdk/issues/54671).
void statement_sync_nullable(Iterable<int>? x) {
for (var (y) in x) {}
// ^
// [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
// [cfe] The type 'Iterable<int>?' used in the 'for' loop must implement 'Iterable<dynamic>' because 'Iterable<int>?' is nullable and 'Iterable<dynamic>' isn't.
}
void statement_sync_potentiallyNullable<T extends Iterable<int>?>(T x) {
for (var (y) in x) {}
// ^
// [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
// [cfe] The type 'T' used in the 'for' loop must implement 'Iterable<dynamic>' because 'Iterable<int>?' is nullable and 'Iterable<dynamic>' isn't.
// [cfe] The type 'T' used in the 'for' loop must implement 'Iterable<dynamic>'.
}
Future<void> statement_async_nullable(Stream<int>? x) async {
await for (var (y) in x) {}
// ^
// [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
// [cfe] The type 'Stream<int>?' used in the 'for' loop must implement 'Stream<dynamic>' because 'Stream<int>?' is nullable and 'Stream<dynamic>' isn't.
}
Future<void> statement_async_potentiallyNullable<T extends Stream<int>?>(
T x) async {
await for (var (y) in x) {}
// ^
// [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
// [cfe] The type 'T' used in the 'for' loop must implement 'Iterable<dynamic>'.
// [cfe] The type 'T' used in the 'for' loop must implement 'Stream<dynamic>' because 'Stream<int>?' is nullable and 'Stream<dynamic>' isn't.
}
List<int> listElement_sync_nullable(Iterable<int>? x) => [for (var (y) in x) y];
// ^
// [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
// [cfe] The type 'Iterable<int>?' used in the 'for' loop must implement 'Iterable<dynamic>' because 'Iterable<int>?' is nullable and 'Iterable<dynamic>' isn't.
List<int> listElement_sync_potentiallyNullable<T extends Iterable<int>?>(T x) =>
[for (var (y) in x) y];
// ^
// [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
// [cfe] The type 'T' used in the 'for' loop must implement 'Iterable<dynamic>' because 'Iterable<int>?' is nullable and 'Iterable<dynamic>' isn't.
// [cfe] The type 'T' used in the 'for' loop must implement 'Iterable<dynamic>'.
Future<List<int>> listElement_async_nullable(Stream<int>? x) async =>
[await for (var (y) in x) y];
// ^
// [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
// [cfe] The type 'Stream<int>?' used in the 'for' loop must implement 'Stream<dynamic>' because 'Stream<int>?' is nullable and 'Stream<dynamic>' isn't.
Future<List<int>> listElement_async_potentiallyNullable<T extends Stream<int>?>(
T x) async =>
[await for (var (y) in x) y];
// ^
// [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
// [cfe] The type 'T' used in the 'for' loop must implement 'Iterable<dynamic>'.
// [cfe] The type 'T' used in the 'for' loop must implement 'Stream<dynamic>' because 'Stream<int>?' is nullable and 'Stream<dynamic>' isn't.
Set<int> setElement_sync_nullable(Iterable<int>? x) => {for (var (y) in x) y};
// ^
// [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
// [cfe] The type 'Iterable<int>?' used in the 'for' loop must implement 'Iterable<dynamic>' because 'Iterable<int>?' is nullable and 'Iterable<dynamic>' isn't.
Set<int> setElement_sync_potentiallyNullable<T extends Iterable<int>?>(T x) =>
{for (var (y) in x) y};
// ^
// [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
// [cfe] The type 'T' used in the 'for' loop must implement 'Iterable<dynamic>' because 'Iterable<int>?' is nullable and 'Iterable<dynamic>' isn't.
// [cfe] The type 'T' used in the 'for' loop must implement 'Iterable<dynamic>'.
Future<Set<int>> setElement_async_nullable(Stream<int>? x) async =>
{await for (var (y) in x) y};
// ^
// [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
// [cfe] The type 'Stream<int>?' used in the 'for' loop must implement 'Stream<dynamic>' because 'Stream<int>?' is nullable and 'Stream<dynamic>' isn't.
Future<Set<int>> setElement_async_potentiallyNullable<T extends Stream<int>?>(
T x) async =>
{await for (var (y) in x) y};
// ^
// [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
// [cfe] The type 'T' used in the 'for' loop must implement 'Iterable<dynamic>'.
// [cfe] The type 'T' used in the 'for' loop must implement 'Stream<dynamic>' because 'Stream<int>?' is nullable and 'Stream<dynamic>' isn't.
Map<int, int> mapElement_sync_nullable(Iterable<int>? x) =>
{for (var (y) in x) y: y};
// ^
// [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
// [cfe] The type 'Iterable<int>?' used in the 'for' loop must implement 'Iterable<dynamic>' because 'Iterable<int>?' is nullable and 'Iterable<dynamic>' isn't.
Map<int, int> mapElement_sync_potentiallyNullable<T extends Iterable<int>?>(
T x) =>
{for (var (y) in x) y: y};
// ^
// [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
// [cfe] The type 'T' used in the 'for' loop must implement 'Iterable<dynamic>' because 'Iterable<int>?' is nullable and 'Iterable<dynamic>' isn't.
// [cfe] The type 'T' used in the 'for' loop must implement 'Iterable<dynamic>'.
Future<Map<int, int>> mapElement_async_nullable(Stream<int>? x) async =>
{await for (var (y) in x) y: y};
// ^
// [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
// [cfe] The type 'Stream<int>?' used in the 'for' loop must implement 'Stream<dynamic>' because 'Stream<int>?' is nullable and 'Stream<dynamic>' isn't.
Future<Map<int, int>>
mapElement_async_potentiallyNullable<T extends Stream<int>?>(T x) async =>
{await for (var (y) in x) y: y};
// ^
// [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
// [cfe] The type 'T' used in the 'for' loop must implement 'Iterable<dynamic>'.
// [cfe] The type 'T' used in the 'for' loop must implement 'Stream<dynamic>' because 'Stream<int>?' is nullable and 'Stream<dynamic>' isn't.
main() {}