Description
For the following code:
abstract class X {
Future<String?> getNameOrNull(
String database,
String table,
);
Future<String> getName(String database, String table) async {
final name = (
await getNameOrNull(
database,
table,
), // (1)
);
if (name == null) { // (2)
throw Exception('Name is null');
} else {
return name; // (3)
}
}
}
The line marked (2)
has the warning The operand can't be null, so the condition is always 'false'.
The line marked (3)
has the warning A value of type '(String?)' can't be returned from the method 'getName' because it has a return type of 'Future<String>'
The type of name
is (String?)
, which looks deceptively like String?
, but it is actually a single-item record, because of the stray comma on line (1)
!
It took me a while to figure out what was going on here, because I assumed that the type (String?)
was in fact the same as the type String?
...
It is very easy to make this sort of mistake, because it is customary to put a trailing literally everywhere you can put one in Dart, especially in Flutter code, because then the formatter makes the structure of the code much clearer.
In my opinion, it shouldn't be possible to create single-item records. Actually, Dart wouldn't interpret (value)
as a record. But apparently it does recognize (value,)
as a record.
I think the best fix here would be to ignore the empty field at the end of a record definition that ends in a comma before the closing parenthesis, and proceed as if the comma weren't there. That would make (value,)
act the same as (value)
. Although the downside of this is that before record syntax existed, (value,)
would not have been valid syntax for a parenthesized expression...
Therefore, maybe the best thing to do here is simply give the user a warning if they try to declare a single-field record.
- Dart version and tooling diagnostic info (
dart info
):
$ dart info
If providing this information as part of reporting a bug, please review the information
below to ensure it only contains things you're comfortable posting publicly.
#### General info
- Dart 3.1.2 (stable) (Tue Sep 12 16:26:23 2023 +0000) on "linux_x64"
- on linux / Linux 6.4.12-200.fc38.x86_64 dart-lang/sdk#1 SMP PREEMPT_DYNAMIC Wed Aug 23 17:46:49 UTC 2023
- locale is en_US.utf8
#### Project info
- sdk constraint: '>=3.0.0 <4.0.0'
- dependencies: process_run
- dev_dependencies: lints
- elided dependencies: 2
#### Process info
| Memory | CPU | Elapsed time | Command line |
| ------: | ---: | -----------: | ------------------------------------------------------------------------------------------ |
| 447 MB | 0.0% | 1-05:03:59 | dart --enable-vm-service=0 --pause_isolates_on_start --disable-dart-dev -DSILENT_VM_SERVICE=true --write-service-info=file:<path>/vm.json --pause_isolates_on_exit --enable-asserts <path>/main.dart |
| 680 MB | 0.0% | 6-21:13:05 | dart ..<path>/serverpod_cli.dart generate --watch |
| 661 MB | 0.0% | 1-05:11:35 | dart ..<path>/serverpod_cli.dart generate --watch |
| 93 MB | 0.0% | 1-05:03:59 | dart debug_adapter |
| 72 MB | 0.0% | 29-08:17:43 | dart devtools --machine --try-ports 10 --allow-embedding |
| 77 MB | 0.0% | 29-08:17:24 | dart devtools --machine --try-ports 10 --allow-embedding |
| 77 MB | 0.0% | 29-07:48:17 | dart devtools --machine --try-ports 10 --allow-embedding |
| 77 MB | 0.0% | 28-04:43:12 | dart devtools --machine --try-ports 10 --allow-embedding |
| 76 MB | 0.0% | 1-05:33:23 | dart devtools --machine --try-ports 10 --allow-embedding |
| 907 MB | 0.0% | 4-23:04:24 | dart language-server --protocol=lsp --client-id=VS-Code --client-version=3.72.2 |
| 1281 MB | 0.2% | 1-05:33:23 | dart language-server --protocol=lsp --client-id=VS-Code --client-version=3.72.2 |
| 105 MB | 0.0% | 1-05:33:23 | flutter_tools.snapshot daemon |
- Whether you are using Windows, macOS, or Linux (if applicable): Linux