Skip to content

Comments

Only generate dynamic calls when class has generic params#1388

Merged
davidmorgan merged 1 commit intogoogle:masterfrom
jiahaog:generate-dynamic-final
Feb 20, 2026
Merged

Only generate dynamic calls when class has generic params#1388
davidmorgan merged 1 commit intogoogle:masterfrom
jiahaog:generate-dynamic-final

Conversation

@jiahaog
Copy link
Member

@jiahaog jiahaog commented Feb 20, 2026

Currently, a dynamic call is generated when a field is a function (previously added back in 2018). Without the dynamic call, this test fails. The error message is:

00:00 +9 -1: GenericFunction can be compared [E]                                                   │
  type '(int) => Null' is not a subtype of type '(dynamic) => dynamic'                             │
  package:end_to_end_test/generics.g.dart 1726:58  _$GenericFunction.==                            │
  test/generics_test.dart 77:63                    main.<fn>.<fn>

In this commit, only use dynamic calls when the enclosing class has generic parameters. This should eliminate a significant number of dynamic call generation in cases that don't need it.

Ideally we would only generate the dynamic call when the field is a function and uses type parameters from the enclosing class, but my understanding is that is much more complex and requires deeper integration with the analyzer.

The *.g.dart files were regenerated by locally modifying the pubspec of end_to_end_test to use dependency_overrides to point to the local repo (not sure if this is the right approach).

Motivation: Dynamic modules do not support dynamic calls and the current generation of dynamic calls makes using built_value in dynamic modules problematic. See b/481568738 for details.

Tested: Running the tests, and also doing an internal global presubmit with this change.

Currently, a dynamic call is generated when a field is a function
(previously added [back in 2018](google#498)). Without the dynamic call, [this test](https://github.com/google/built_value.dart/blob/f20857b873aa6c77395b75aa18a4c03b80f18017/end_to_end_test/test/generics_test.dart#L71-L81)
fails. The error message is:

```
00:00 +9 -1: GenericFunction can be compared [E]                                                   │
  type '(int) => Null' is not a subtype of type '(dynamic) => dynamic'                             │
  package:end_to_end_test/generics.g.dart 1726:58  _$GenericFunction.==                            │
  test/generics_test.dart 77:63                    main.<fn>.<fn>
```

In this commit, only use dynamic calls when the enclosing class has
generic parameters. This should eliminate a significant number of
dynamic call generation in cases that don't need it.

Ideally we would only generate the dynamic call when the *field* is a
function and uses type parameters from the enclosing class, but my
understanding is that is much more complex and requires deeper
integration with the analyzer.

The *.g.dart files were regenerated by locally modifying the pubspec of
end_to_end_test to use dependency_overrides to point to the local repo
(not sure if this is the right approach).

Motivation: Dynamic modules do not support dynamic calls and the
current generation of dynamic calls makes using built_value in dynamic
modules problematic. See b/481568738 for details.

Tested: Running the tests, and also doing an internal global presubmit
with this change.
@jiahaog
Copy link
Member Author

jiahaog commented Feb 20, 2026

@davidmorgan would you be able to take a look if this is right :)

@davidmorgan
Copy link
Collaborator

Thanks!

I asked about the cast problem with functions, it's possible to make it work for functions by generating a getter/method that avoids doing the cast

class F<T> {
  void Function(T) function;

  Object _functionAsObject => function;
}

but we would still have the problem of detecting when to do this, as you observed.

Since nobody is actually asking for functions in generic types to work I think this workaround is fine.

Normally I would insist on putting a test of the new functionality in end_to_end_tests, but I don't see a way to check that no dynamic call happens, so the unit test looks fine.

LGTM, thanks! I'll merge + roll into google3.

@davidmorgan davidmorgan merged commit 4ffea12 into google:master Feb 20, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants