The former is way more readable to someone who is not a compiler developer, at least to me.
The last two commits on the PR I linked to earlier shows what that would look like.
The whole {$::#}
thing is a weird symbol soup and doesn't correspond to any surface Rust syntax. Given fn foo() { <expr> }
where <expr>
has various types, we get:
2 | 42
| ^^ expected `()`, found integer
Okay.
2 | 42i32
| ^^ expected `()`, found `i32`
Also okay, though as a nitpick why does it underline just the "42" and not the entire literal?
2 | foo
| ^^^ expected `()`, found fn item
|
= note: expected unit type `()`
found fn item `fn() {foo}`
Fine, I guess, except that it's weird that the name is within the braces as if it were the body of the function. (Why not fn foo()
or fn foo() { ... }
or something?)
2 | || ()
| ^^^^^ expected `()`, found closure
|
= note: expected unit type `()`
found closure `{closure@src/lib.rs:2:5: 2:7}`
This is kind of weird. I guess the closure type has to have some name, but the note could just as well be omitted becase doesn't give the user any additional information that's not already included in the error message. The name sort of makes sense if the @
is taken to have the common meaning "at", though why "a:b: c:d" and not, say, "a:b..c:d"? Also, the span is not in fact the span of the closure but just the argument list!
And finally with -Zspan_free_formats=yes
:
= note: expected unit type `()`
found closure `{closure@foo::{closure#0}}`
Now we have the name of the containing function, but the symbol soup (and redundancy) has gotten way worse. Of course this is an unstable option so lack of polish is understandable.
If we keep the current RTN syntax, it would be understandable to interpret the former as the return type of fn foo
. (Not that I'm a fan of the current syntax.)
I'm afraid no descriptive name is really descriptive:
$ cat test.rs && rustc --edition 2024 test.rs
fn test_type_equal<T: Fn() -> i32>(_: T, _: T) {}
fn main() {
let a = || 1;
let b = a;
let a = || 1;
let c = a;
test_type_equal(b, c);
}
error[E0308]: mismatched types
--> test.rs:7:24
|
3 | let a = || 1;
| -- the expected closure
4 | let b = a;
5 | let a = || 1;
| -- the found closure
6 | let c = a;
7 | test_type_equal(b, c);
| --------------- - ^ expected closure, found a different closure
| | |
| | expected all arguments to be this closure type because they need to match the type of this parameter
| arguments to this function are incorrect
|
= note: expected closure `{closure@test.rs:3:13: 3:15}`
found closure `{closure@test.rs:5:13: 5:15}`
= note: no two closures, even if identical, have the same type
= help: consider boxing your closure and/or using it as a trait object
note: function defined here
--> test.rs:1:4
|
1 | fn test_type_equal<T: Fn() -> i32>(_: T, _: T) {}
| ^^^^^^^^^^^^^^^ - ---- ---- this parameter needs to match the closure type of parameter #1
| | |
| | parameter #2 needs to match the closure type of this parameter
| parameter #1 and parameter #2 both reference this parameter `T`
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0308`.
If you really insist "descriptive name", you may got errors like:
= note: expected closure `a`
found closure `a`
= note: no two closures, even if identical, have the same type
Compiler already handles scenarios if you have an instance of trait Foo
from crate bar
, and consumer requires an instance Foo
from a different version of crate bar
. I think it should be possible to implement similar logic for descriptive names.
Nope. I believe all you could do is replace one of the "closure" to its name.
= note: expected closure `{a@test.rs:3:13: 3:15}`
found closure `{a@test.rs:5:13: 5:15}`
Since you cannot define 2 traits with the same name in the same module, you could use the module name to describe which trait you want. But for closure, the only way to identify which closure you're using is that, using their defined location.
You could have {descriptive name (@source location)}
or something like that. Might be long and verbose.
what if the error messages printed the closures using a more closure-like syntax?
= note: expected closure `|| { test.rs:3:13..3:15 }`
For closures with arguments, the arguments have user-provided names which would make them less anonymous:
= note: expected closure `|key, value| { test.rs:3:13..3:15 }`
(and I mean this only for messages, it doesn't seem appropriate nor or backwards-compatible for symbols)