Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[pigeon] Improve casting and nullability-handling in generated code#11163

Open
srawlins wants to merge 8 commits intoflutter:mainfrom
srawlins:nullabiliteee
Open

[pigeon] Improve casting and nullability-handling in generated code#11163
srawlins wants to merge 8 commits intoflutter:mainfrom
srawlins:nullabiliteee

Conversation

@srawlins
Copy link
Contributor

@srawlins srawlins commented Mar 2, 2026

There are a number of positions where we attempt to cast a nullable expression to a non-nullable type with something like the following (foo as List<Object?>?)!. This successfully performs the cast and avoids a lint rule which recommends not casting a nullable expression to a non-nullable type. But it can be done more simply. Here are some examples of the improved code:

- data: (result[3] as Map<Object?, Object?>?)!.cast<String, String>(),
+ data: (result[3]! as Map<Object?, Object?>).cast<String, String>(),

- final List<Object?> args = (message as List<Object?>?)!;
+ final List<Object?> args = message! as List<Object?>;

- stringList: (result[13] as List<Object?>?)!.cast<String>(),
+ stringList: (result[13]! as List<Object?>).cast<String>(),

Since we are expecting these values to be non-null, we first null-assert them (!), and then cast the expression with as.

There was previously a helper, _makeGenericCastCall, which generated the String representation for a call to cast, like .cast<Object?>(), which was called in three places. This change consoldiates the surrounding code to those call sites into a new helper, _castValue, which instead returns the complete String of casting a value to a type, possibly null-asserting the value and possibly calling .cast().

Combining all of the casting code into one function also allows us to avoid unnecessary parentheses:

- final String? arg_aString = (args[0] as String?);
+ final String? arg_aString = args[0] as String?;

Improving the nullability-handling allows us to remove the _addGenericTypes helper, and rename the addGenericTypesNullable to just addGenericTypes, since the helper should always print an appropriate nullability suffix.

One prominent change made to the generated code is the removal of "assert foo is not null" statements. These are redundant with the null-asserts (!), although they might offer more information in the assertion message, though I honestly don't think so. The exception thrown by ! has the relevant information in the stack trace.

Fixes flutter/flutter#116972

Pre-Review Checklist

  • I read the [Contributor Guide] and followed the process outlined there for submitting PRs.
  • I read the [Tree Hygiene] page, which explains my responsibilities.
  • I read and followed the [relevant style guides] and ran [the auto-formatter].
  • I signed the [CLA].
  • The title of the PR starts with the name of the package surrounded by square brackets, e.g. [shared_preferences]
  • I [linked to at least one issue that this PR fixes] in the description above.
  • I followed [the version and CHANGELOG instructions], using [semantic versioning] and the [repository CHANGELOG style], or I have commented below to indicate which documented exception this PR falls under[^1].
  • I updated/added any relevant documentation (doc comments with ///).
  • I added new tests to check the change I am making, or I have commented below to indicate which [test exemption] this PR falls under[^1].
  • All existing and new tests are passing.

srawlins added 5 commits March 2, 2026 11:54
There are a number of positions where we attempt to cast a nullable expression
to a non-nullable type with something like the following
`foo as List<Object?>?)!`. This successfully performs the cast and avoids a
lint rule which recommends not casting a nullable expression to a non-nullable
type. But it can be done more simply. Here are some examples of the improved
code:

```diff
- data: (result[3] as Map<Object?, Object?>?)!.cast<String, String>(),
+ data: (result[3]! as Map<Object?, Object?>).cast<String, String>(),

- final List<Object?> args = (message as List<Object?>?)!;
+ final List<Object?> args = message! as List<Object?>;

- stringList: (result[13] as List<Object?>?)!.cast<String>(),
+ stringList: (result[13]! as List<Object?>).cast<String>(),
```

Since we are expecting these values to be non-null, we first null-assert them
(`!`), and then cast the expression with `as`.

There was previously a helper, `_makeGenericCastCall`, which generated the
String representation for a call to `cast`, like `.cast<Object?>()`, which was
called in three places. This change consoldiates the surrounding code to those
call sites into a new helper, `_castValue`, which instead returns the complete
String of casting a value to a type, possibly null-asserting the value and
possibly calling `.cast()`.

Combining all of the casting code into one function also allows us to avoid
unnecessary parentheses:

```diff
- final String? arg_aString = (args[0] as String?);
+ final String? arg_aString = args[0] as String?;
```

Improving the nullability-handling allows us to remove the `_addGenericTypes`
helper, and rename the `addGenericTypesNullable` to just `addGenericTypes`,
since the helper should always print an appropriate nullability suffix.

One prominent change made to the generated code is the removal of "assert foo
is not null" statements. These are redundant with the null-asserts (`!`),
although they _might_ offer more information in the assertion message, though I
honestly don't think so. The exception thrown by `!` has the relevant
information in the stack trace.
Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request refactors the nullability handling in the generated Dart code, resulting in simpler and more idiomatic casting logic. The introduction of the _castValue helper centralizes casting operations, and the removal of redundant null checks and parentheses improves code clarity. The changes across the generated files are consistent with these improvements. I've found one minor issue in a documentation comment.

Note: Security Review is unavailable for this PR.

@srawlins srawlins changed the title [pigeon] Improve casting nullability-handling in generated code [pigeon] Improve casting and nullability-handling in generated code Mar 2, 2026
@tarrinneal
Copy link
Contributor

One prominent change made to the generated code is the removal of "assert foo is not null" statements. These are redundant with the null-asserts (!), although they might offer more information in the assertion message, though I honestly don't think so. The exception thrown by ! has the relevant information in the stack trace.

Man, I thought I'd gotten rid of all of these years ago...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[pigeon] remove runtime type/nullability checks in deserialization in all generators

2 participants