Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Invalid generated code when typedef refers to unimported file #1124

Open
mernen opened this issue Apr 2, 2022 · 4 comments
Open

Invalid generated code when typedef refers to unimported file #1124

mernen opened this issue Apr 2, 2022 · 4 comments

Comments

@mernen
Copy link

mernen commented Apr 2, 2022

When a field refers to a typedef'd type, the generated code uses the original type name rather than its alias. However, if the original type isn't currently imported, the generated code doesn't compile.

A minimal testcase project is provided at mernen/testcase_serialize_typedef.dart.

Basically, imagine a project with the following structure:

  • impl_details.dart contains a class called UserImpl, with a UserImpl.fromJson() constructor (may or may not use @JsonSerializable())
  • user.dart imports impl_details.dart (without exporting anything) and defines typedef User = UserImpl;
  • comment.dart imports user.dart, declares a class Comment that refers to User, and uses @JsonSerializable() to generate a fromJson() factory

After build_runner runs, comment.g.dart will attempt to use UserImpl.fromJson(...) to instantiate the User, but that name isn't imported!

Since part declarations can't themselves import anything, perhaps the only possible solution here (without the aid of the developer) would be to use the aliased name in this case.

Tested versions

  • json_serializable: 6.1.5
  • Dart SDK version: 2.16.2 (stable)
  • Flutter 2.10.4 • channel stable
mernen added a commit to mernen/testcase_serialize_typedef.dart that referenced this issue Apr 2, 2022
mernen added a commit to mernen/testcase_serialize_typedef.dart that referenced this issue Apr 2, 2022
@absar
Copy link

absar commented Jul 12, 2022

@kevmoo is it possible to use typedef aliases instead of original types in generated code, we now face above issue specially after #1136 which creates a generic converter in generated code _$JsonConverterToJson e.g.
generates 'id': _$JsonConverterToJson<dynamic, Uuid>(instance.id, const UniqueIdConverter().toJson)
instead of 'id': _$JsonConverterToJson<dynamic, UniqueId>(instance.id, const UniqueIdConverter().toJson)
which is breaking the code since Uuid is never directly referred or imported, rather it's type def UniqueId is used to not refer external library names directly

@kevmoo
Copy link
Collaborator

kevmoo commented Oct 4, 2022

Ha! This is likely gnarly.

I think the reference to the typedef is erased. The analyzer code I see doesn't know the referenced type is from a typedef.

I'd need to play a bit first to see for sure, though.

@kevmoo
Copy link
Collaborator

kevmoo commented Oct 4, 2022

Yup. The typedef is effectively erased. I can't go back to the typedef when I generate the code. Maybe @scheglov has an idea?

@scheglov
Copy link
Collaborator

scheglov commented Oct 4, 2022

We have in DartType:

  /// If this type is an instantiation of a type alias, information about
  /// the alias element, and the type arguments.
  /// Otherwise return `null`.
  InstantiatedTypeAliasElement? get alias;

where

/// Information about an instantiated [TypeAliasElement] and the type
/// arguments with which it is instantiated.
abstract class InstantiatedTypeAliasElement {
  /// The alias element that is instantiated to produce a [DartType].
  TypeAliasElement get element;

  /// The type arguments with which the [element] was instantiated.
  /// This list will be empty if the [element] is not generic.
  List<DartType> get typeArguments;
}

So, yes, typedef is transparent, but there are vestiges.

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

No branches or pull requests

4 participants