Open Valloric opened 9 years ago
cc @eddyb
Another example, with Vector<T>
and [T]
. This works:
fn main() {
let x = vec![97u8];
assert_eq!(b"a", &x[..]);
}
But this fails to compile:
fn main() {
let x = vec![97u8];
assert_eq!(b"a", &x);
}
Output:
<std macros>:5:10: 5:35 error: the trait `core::cmp::PartialEq<collections::vec::Vec<u8>>` is not implemented for the type `[u8]` [E0277]
<std macros>:5 if ! ( ( * left_val == * right_val ) && ( * right_val == * left_val ) ) {
^~~~~~~~~~~~~~~~~~~~~~~~~
<std macros>:1:1: 9:39 note: in expansion of assert_eq!
<anon>:3:3: 3:24 note: expansion site
<std macros>:5:43: 5:68 error: the trait `core::cmp::PartialEq<[u8]>` is not implemented for the type `collections::vec::Vec<u8>` [E0277]
<std macros>:5 if ! ( ( * left_val == * right_val ) && ( * right_val == * left_val ) ) {
^~~~~~~~~~~~~~~~~~~~~~~~~
<std macros>:1:1: 9:39 note: in expansion of assert_eq!
<anon>:3:3: 3:24 note: expansion site
error: aborting due to 2 previous errors
playpen: application terminated with error code 101
I have tons of other examples in my codebase. Like, 30+.
(FWIW, that second example could be written as assert_eq!(b"a", vec![97u8])
because PartialEq
is implemented between &[u8]
and Vec<u8>
, no need for deref coercions nor slicing syntax)
The problem also appears here:
fn main()
{
let rs = "toto";
let s = rs.to_string();
// That works as expected, &s coerces s to type &str
fn titi(s:&str) { assert_eq!(s,"toto");};
titi(&s);
// That also works, same coercion happens
let cs:&str = &s;
assert_eq!(cs,rs);
// The following expression fails to run, as though the coercion did not happen
let cs = &s;
assert_eq!(cs,rs);
}
This is somewhat similar to https://github.com/rust-lang/rust/issues/16864.
I think @nrc was doing some work on coercions recently?
I can confirm the issue is still present on rustc 1.8.0-nightly (57c357d89 2016-02-16)
. My testcase still repros.
Both arrays and the expansion of assert_eq
fail to trigger coercions.
The former is easier to fix, try changing this call to be to check_expr_coercable_to_type
instead.
That should make it so the first array element with even a partially inferrable type triggers coercions on subsequent array elements.
The perfect solution would involve smarter unification such that &String
followed by &str
goes back and coerces the &String
(or @nikomatsakis' order-independent type-checking).
Interesting developments: the first test case I posted now compiles fine.
fn main() {
let x = "a".to_string();
// Doesn't work
let y: String = ["b", &x, "c"].concat();
println!("{}", y);
}
But the second test case fails compilation:
fn main() {
let x = vec![97u8];
assert_eq!(b"a", &x);
}
Here's the error message:
error[E0277]: the trait bound `[u8; 1]: std::cmp::PartialEq<std::vec::Vec<u8>>` is not satisfied
--> <std macros>:5:6
|
5 | if ! ( * left_val == * right_val ) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
foo.rs:3:3: 3:24 note: in this expansion of assert_eq! (defined in <std macros>)
|
= help: the following implementations were found:
= help: <[A; 0] as std::cmp::PartialEq<[B; 0]>>
= help: <[A; 0] as std::cmp::PartialEq<[B]>>
= help: <[B] as std::cmp::PartialEq<[A; 0]>>
= help: <[A; 0] as std::cmp::PartialEq<&'b [B]>>
= help: and 228 others
= note: required because of the requirements on the impl of `std::cmp::PartialEq<&std::vec::Vec<u8>>` for `&[u8; 1]`
error: aborting due to previous error
rustc version: rustc 1.12.0 (3191fbae9 2016-09-23)
.
such that
&String
followed by&str
goes back and coerces the&String
FWIW this is what was implemented and why the array case works now.
Here is another case with a trait, wich fails to compile:
fn main() {
concat("nice", "cooel");
concat("nice".to_string(), "cooel");
let yop = "nice".to_string();
concat(&yop, "cooel"); // need to add manually "as &str"
}
pub fn concat<S: Into<String>>(path: S, suffix: &str) -> String {
path.into() + suffix
}
Also ran into this, in a very simple case:
works:
fn prompt_and_validate(msg: &str, options: &[&str]) {
let reply = prompt(msg);
let r: &str = &reply;
if options.contains(&r) {
}
}
doesn't work:
fn prompt_and_validate(msg: &str, options: &[&str]) {
let reply = prompt(msg);
let r = &reply;
if options.contains(&r) {
}
}
or in other words, double deref is not working automatically:
fn prompt_and_validate(msg: &str, options: &[&str]) {
let reply = prompt(msg);
if options.contains(&&reply) {
}
}
with
mismatched types
expected str, found struct `std::string::String`
note: expected type `&&str`
found type `&&std::string::String`
(workaround is &reply.as_str()
)
This still seems to fail today in Rust 1.55:
fn main() {
let cmd = "some command".split_whitespace().collect::<Vec<_>>();
match &cmd {
["some", sub] => println!("some {}", sub),
["quit"] => println!("bye!"),
_ => println!("oops"),
}
}
with:
error[E0529]: expected an array or slice, found `Vec<&str>`
--> src/main.rs:13:9
|
13 | ["some", sub] => println!("some {}", sub),
| ^^^^^^^^^^^^^ pattern cannot match with input type `Vec<&str>`
error[E0529]: expected an array or slice, found `Vec<&str>`
--> src/main.rs:14:9
|
14 | ["quit"] => println!("bye!"),
| ^^^^^^^^ pattern cannot match with input type `Vec<&str>`
For more information about this error, try `rustc --explain E0529`.
error: could not compile `playground` due to 2 previous errors
Exchanging &cmd
for &*cmd
or &cmd[..]
makes it work.
Is this intended or really a bug that the coercion does not trigger here?
It's a missing feature: we could try to figure out some kind of "type skeleton" from the patterns, before type-checking the expression being match
ed, but we don't today.
That is, today the information flows only the other way around: from the expression to the patterns.
we could try to figure out some kind of "type skeleton" from the patterns, before type-checking the expression being matched, but we don't today
@eddyb Is this still something we might want to do?
This code compiles fine:
but this code doesn't
error output:
I'd expect to not have to sometimes write
&foo[..]
and sometimes&foo
to get a&str
out aString
. The longer form is too verbose, and the inconsistency of having to sometimes use one over the other seems like a needless user mental model cost, especially because it's not obvious to me at all when I should use one form over the other.rustc version:
rustc 1.0.0-nightly (522d09dfe 2015-02-19) (built 2015-02-21)