Skip to content

Assignment errors on complex Function/Record types are unreadable #60543

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

Open
rrousselGit opened this issue Apr 15, 2025 · 6 comments
Open

Assignment errors on complex Function/Record types are unreadable #60543

rrousselGit opened this issue Apr 15, 2025 · 6 comments
Labels
area-devexp For issues related to the analysis server, IDE support, linter, `dart fix`, and diagnostic messages. P3 A lower priority bug or feature request

Comments

@rrousselGit
Copy link

rrousselGit commented Apr 15, 2025

Here's an error I came across recently:

Image

Where the code is a tearOff:

Class(providerFactory: AnotherClass.new)

It goes to say that this error message is pretty much useless due to how much information overload there is.

The root of the issue IMO is: For Functions/Records, just logging the entire type isn't enough.

I think it would be massively helpful if:

  • The type was formatted to span over multiple lines (by respecting dart_style!)
  • Whatever causes the assignment error should be highlighted using diff or some special colour

Here's an example of what I think

Consider:

void fn(int a, {String? b, required int c, double? d, bool? e}) {}

void Function(
  int a, {
  String? b,
  int? c,
  double? d,
  bool? e,
  Object? f,
}) cb = fn;

The current error message is:

A value of type 'void Function(int, {String? b, int? c, double? d, bool? e})' can't be assigned to a variable of type 'void Function(int, {String? b, int c, double? d, bool? e, Object? f})'.
Try changing the type of the variable, or casting the right-hand type to 'void Function(int, {String? b, int c, double? d, bool? e, Object? f})'

I think it'd be more more readable if we instead had:

Invalid assignment error.

Expected:
void Function(int a, {String? b, int? c, double? d, bool? e})

But got:
void Function(
  int a, {
  String? b,
  required int c,
  double? d,
  bool? e,
  Object? f,
})

Where the difference is:
void Function(
  int a, {
  String? b,
- int? c,
+ required int c,
  double? d,
  bool? e,
+  Object? f,
})
@bwilkerson bwilkerson added P3 A lower priority bug or feature request area-devexp For issues related to the analysis server, IDE support, linter, `dart fix`, and diagnostic messages. labels Apr 15, 2025
@FMorschel
Copy link
Contributor

I'd also like to point out that no types added to the current diagnostic messages are highlighted. Nothing like the below definition for typedef as displayed on the screenshot above. Maybe we could think of a way to make this possible? I'm unsure if VS Code accepts this kind of formatting today without a markdown code block (CC @DanTup).

@rrousselGit
Copy link
Author

rrousselGit commented Apr 18, 2025

If we can't render diffs, there's always the option of having longer messages.

Like:

Invalid assignment error.

Expected:
void Function(int a, {String? b, int? c, double? d, bool? e})

But got:
void Function(
  int a, {
  String? b,
  int c,
  double? d,
  bool? e,
  Object? f,
})

Where the parameter `c` is required but but was expected to be optional, and `f` is present but none were expected.

This is similar to versioning conflicts when running pub get. They show a lengty message explaining in detail what the problem was.

@DanTup
Copy link
Collaborator

DanTup commented Apr 18, 2025

I'm unsure if VS Code accepts this kind of formatting today without a markdown code block (CC @DanTup).

Right now, VS Code/LSP don't support formatting/markdown for the diagnostic text - see microsoft/vscode#54272

@FMorschel
Copy link
Contributor

Today, I found a similar case where a simple typo in a field for a Record typedef lost me some minutes trying to understand the problem (issue to show typedef declaration).

I had something like:

typedef MyRecord = ({
  int foo,
  String bar,
  List<String> baz,
  Map<String, String> field, // Correctly spelled
});

void foo(MyRecord record) {}

void bar() {
  foo((
    foo: 1,
    bar: '',
    baz: [],
    filed: {}, // Typo, the `e` is in the wrong place
  ));
}

The start of the message is:

The argument type '({String bar, List<String> baz, Map<String, String> filed, int foo})' can't be assigned to the parameter type 'MyRecord'.

On the latest main, we also have more info which would have helped, but my production Flutter app is developed on Stable, so this part was still not showing:

Unexpected named argument `filed` with type `Map<String, String>`.

This info already helps a lot, but I wonder, since we have this info, couldn't we make this diagnostic show only in that field?

@DanTup
Copy link
Collaborator

DanTup commented Apr 24, 2025

This info already helps a lot, but I wonder, since we have this info, couldn't we make this diagnostic show only in that field?

It looks like the code for this is here:

additionalInfo.add(
'Unexpected named argument `${field.name}` with type `${field.type.getDisplayString()}`.',
);

It's in a loop, so my guess is that there could be multiple of these (eg. if you have two unexpected names). Diagnostics do support "context messages" which have locations see line 169) so maybe each field could be added as a context message with that field? I'm not sure exactly how it would appear though.

Edit: To clarify, the context messages show as additional lines, collapsed under a diagnostic in VS Code. I really meant I don't know how it would feel like there without trying it out.

@rrousselGit
Copy link
Author

This extra debug util looks nice but: It seems unique to Records.

Functions should get it too. Both Records and Functions are a form of Structural typing, so they have the same root issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-devexp For issues related to the analysis server, IDE support, linter, `dart fix`, and diagnostic messages. P3 A lower priority bug or feature request
Projects
None yet
Development

No branches or pull requests

4 participants