mirror of
https://github.com/dart-lang/sdk
synced 2024-09-16 00:19:48 +00:00
872ef163f1
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>
120 lines
6.6 KiB
Dart
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() {}
|