Skip to content

Commit d083646

Browse files
committed
Special case Into suggestion to look for From impls
When we encounter a blanket `<Ty as Into<Other>` `impl`, look at the `From` `impl`s so that we can suggest the appropriate `Other`: ``` error[E0284]: type annotations needed --> $DIR/issue-70082.rs:7:33 | LL | let y: f64 = 0.01f64 * 1i16.into(); | - ^^^^ | | | type must be known at this point | = note: cannot satisfy `<f64 as Mul<_>>::Output == f64` help: try using a fully qualified path to specify the expected types | LL | let y: f64 = 0.01f64 * <i16 as Into<i32>>::into(1i16); | +++++++++++++++++++++++++ ~ help: try using a fully qualified path to specify the expected types | LL | let y: f64 = 0.01f64 * <i16 as Into<i64>>::into(1i16); | +++++++++++++++++++++++++ ~ help: try using a fully qualified path to specify the expected types | LL | let y: f64 = 0.01f64 * <i16 as Into<i128>>::into(1i16); | ++++++++++++++++++++++++++ ~ help: try using a fully qualified path to specify the expected types | LL | let y: f64 = 0.01f64 * <i16 as Into<isize>>::into(1i16); | +++++++++++++++++++++++++++ ~ help: try using a fully qualified path to specify the expected types | LL | let y: f64 = 0.01f64 * <i16 as Into<f32>>::into(1i16); | +++++++++++++++++++++++++ ~ help: try using a fully qualified path to specify the expected types | LL | let y: f64 = 0.01f64 * <i16 as Into<f64>>::into(1i16); | +++++++++++++++++++++++++ ~ help: try using a fully qualified path to specify the expected types | LL | let y: f64 = 0.01f64 * <i16 as Into<AtomicI16>>::into(1i16); | +++++++++++++++++++++++++++++++ ~ ```
1 parent d697d63 commit d083646

File tree

8 files changed

+119
-8
lines changed

8 files changed

+119
-8
lines changed

compiler/rustc_span/src/symbol.rs

+1
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,7 @@ symbols! {
493493
bitxor,
494494
bitxor_assign,
495495
black_box,
496+
blanket_into_impl,
496497
block,
497498
bool,
498499
borrowck_graphviz_format,

compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs

+31
Original file line numberDiff line numberDiff line change
@@ -583,6 +583,37 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
583583
}
584584
let assocs = self.infcx.tcx.associated_items(impl_def_id);
585585

586+
if self
587+
.infcx
588+
.tcx
589+
.is_diagnostic_item(sym::blanket_into_impl, impl_def_id)
590+
&& let Some(did) = self.infcx.tcx.get_diagnostic_item(sym::From)
591+
{
592+
let mut found = false;
593+
self.infcx.tcx.for_each_impl(did, |impl_def_id| {
594+
// We had an `<A as Into<B>::into` and we've hit the blanket
595+
// impl for `From<A>`. So we try and look for the right `From`
596+
// impls that *would* apply. We *could* do this in a generalized
597+
// version by evaluating the `where` clauses, but that would be
598+
// way too involved to implement. Instead we special case the
599+
// arguably most common case of `expr.into()`.
600+
let Some(header) =
601+
self.infcx.tcx.impl_trait_header(impl_def_id)
602+
else {
603+
return;
604+
};
605+
let target = header.trait_ref.skip_binder().args.type_at(0);
606+
let ty = header.trait_ref.skip_binder().args.type_at(1);
607+
if ty == args.type_at(0) {
608+
paths.push(format!("<{ty} as Into<{target}>>::into"));
609+
found = true;
610+
}
611+
});
612+
if found {
613+
return;
614+
}
615+
}
616+
586617
// We're at the `impl` level, but we want to get the same method we
587618
// called *on this `impl`*, in order to get the right DefId and args.
588619
let Some(assoc) = assocs.filter_by_name_unhygienic(name).next() else {

library/core/src/convert/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -745,6 +745,7 @@ where
745745

746746
// From implies Into
747747
#[stable(feature = "rust1", since = "1.0.0")]
748+
#[rustc_diagnostic_item = "blanket_into_impl"]
748749
impl<T, U> Into<U> for T
749750
where
750751
U: From<T>,

tests/ui/inference/issue-70082.rs

+6
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,10 @@ fn main() {
77
let y: f64 = 0.01f64 * 1i16.into();
88
//~^ ERROR type annotations needed
99
//~| HELP try using a fully qualified path
10+
//~| HELP try using a fully qualified path
11+
//~| HELP try using a fully qualified path
12+
//~| HELP try using a fully qualified path
13+
//~| HELP try using a fully qualified path
14+
//~| HELP try using a fully qualified path
15+
//~| HELP try using a fully qualified path
1016
}

tests/ui/inference/issue-70082.stderr

+26-2
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,32 @@ LL | let y: f64 = 0.01f64 * 1i16.into();
99
= note: cannot satisfy `<f64 as Mul<_>>::Output == f64`
1010
help: try using a fully qualified path to specify the expected types
1111
|
12-
LL | let y: f64 = 0.01f64 * <_ as Into<_>>::into(1i16);
13-
| +++++++++++++++++++++ ~
12+
LL | let y: f64 = 0.01f64 * <i16 as Into<i32>>::into(1i16);
13+
| +++++++++++++++++++++++++ ~
14+
help: try using a fully qualified path to specify the expected types
15+
|
16+
LL | let y: f64 = 0.01f64 * <i16 as Into<i64>>::into(1i16);
17+
| +++++++++++++++++++++++++ ~
18+
help: try using a fully qualified path to specify the expected types
19+
|
20+
LL | let y: f64 = 0.01f64 * <i16 as Into<i128>>::into(1i16);
21+
| ++++++++++++++++++++++++++ ~
22+
help: try using a fully qualified path to specify the expected types
23+
|
24+
LL | let y: f64 = 0.01f64 * <i16 as Into<isize>>::into(1i16);
25+
| +++++++++++++++++++++++++++ ~
26+
help: try using a fully qualified path to specify the expected types
27+
|
28+
LL | let y: f64 = 0.01f64 * <i16 as Into<f32>>::into(1i16);
29+
| +++++++++++++++++++++++++ ~
30+
help: try using a fully qualified path to specify the expected types
31+
|
32+
LL | let y: f64 = 0.01f64 * <i16 as Into<f64>>::into(1i16);
33+
| +++++++++++++++++++++++++ ~
34+
help: try using a fully qualified path to specify the expected types
35+
|
36+
LL | let y: f64 = 0.01f64 * <i16 as Into<AtomicI16>>::into(1i16);
37+
| +++++++++++++++++++++++++++++++ ~
1438

1539
error: aborting due to 1 previous error
1640

tests/ui/inference/issue-71584.stderr

+26-2
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,32 @@ LL | d = d % n.into();
99
= note: cannot satisfy `<u64 as Rem<_>>::Output == u64`
1010
help: try using a fully qualified path to specify the expected types
1111
|
12-
LL | d = d % <_ as Into<_>>::into(n);
13-
| +++++++++++++++++++++ ~
12+
LL | d = d % <u32 as Into<u64>>::into(n);
13+
| +++++++++++++++++++++++++ ~
14+
help: try using a fully qualified path to specify the expected types
15+
|
16+
LL | d = d % <u32 as Into<u128>>::into(n);
17+
| ++++++++++++++++++++++++++ ~
18+
help: try using a fully qualified path to specify the expected types
19+
|
20+
LL | d = d % <u32 as Into<i64>>::into(n);
21+
| +++++++++++++++++++++++++ ~
22+
help: try using a fully qualified path to specify the expected types
23+
|
24+
LL | d = d % <u32 as Into<i128>>::into(n);
25+
| ++++++++++++++++++++++++++ ~
26+
help: try using a fully qualified path to specify the expected types
27+
|
28+
LL | d = d % <u32 as Into<f64>>::into(n);
29+
| +++++++++++++++++++++++++ ~
30+
help: try using a fully qualified path to specify the expected types
31+
|
32+
LL | d = d % <u32 as Into<Ipv4Addr>>::into(n);
33+
| ++++++++++++++++++++++++++++++ ~
34+
help: try using a fully qualified path to specify the expected types
35+
|
36+
LL | d = d % <u32 as Into<AtomicU32>>::into(n);
37+
| +++++++++++++++++++++++++++++++ ~
1438

1539
error: aborting due to 1 previous error
1640

tests/ui/trait-bounds/argument-with-unnecessary-method-call.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ LL | fn qux(_: impl From<Bar>) {}
1414
| ^^^^^^^^^ required by this bound in `qux`
1515
help: try using a fully qualified path to specify the expected types
1616
|
17-
LL | qux(<_ as Into<_>>::into(Bar));
18-
| +++++++++++++++++++++ ~
17+
LL | qux(<Bar as Into<Foo>>::into(Bar));
18+
| +++++++++++++++++++++++++ ~
1919
help: consider removing this method call, as the receiver has type `Bar` and `Bar: From<Bar>` trivially holds
2020
|
2121
LL - qux(Bar.into());

tests/ui/traits/issue-77982.stderr

+26-2
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,32 @@ LL | let ips: Vec<_> = (0..100_000).map(|_| u32::from(0u32.into())).collect(
5252
- impl From<u8> for u32;
5353
help: try using a fully qualified path to specify the expected types
5454
|
55-
LL | let ips: Vec<_> = (0..100_000).map(|_| u32::from(<_ as Into<_>>::into(0u32))).collect();
56-
| +++++++++++++++++++++ ~
55+
LL | let ips: Vec<_> = (0..100_000).map(|_| u32::from(<u32 as Into<u64>>::into(0u32))).collect();
56+
| +++++++++++++++++++++++++ ~
57+
help: try using a fully qualified path to specify the expected types
58+
|
59+
LL | let ips: Vec<_> = (0..100_000).map(|_| u32::from(<u32 as Into<u128>>::into(0u32))).collect();
60+
| ++++++++++++++++++++++++++ ~
61+
help: try using a fully qualified path to specify the expected types
62+
|
63+
LL | let ips: Vec<_> = (0..100_000).map(|_| u32::from(<u32 as Into<i64>>::into(0u32))).collect();
64+
| +++++++++++++++++++++++++ ~
65+
help: try using a fully qualified path to specify the expected types
66+
|
67+
LL | let ips: Vec<_> = (0..100_000).map(|_| u32::from(<u32 as Into<i128>>::into(0u32))).collect();
68+
| ++++++++++++++++++++++++++ ~
69+
help: try using a fully qualified path to specify the expected types
70+
|
71+
LL | let ips: Vec<_> = (0..100_000).map(|_| u32::from(<u32 as Into<f64>>::into(0u32))).collect();
72+
| +++++++++++++++++++++++++ ~
73+
help: try using a fully qualified path to specify the expected types
74+
|
75+
LL | let ips: Vec<_> = (0..100_000).map(|_| u32::from(<u32 as Into<Ipv4Addr>>::into(0u32))).collect();
76+
| ++++++++++++++++++++++++++++++ ~
77+
help: try using a fully qualified path to specify the expected types
78+
|
79+
LL | let ips: Vec<_> = (0..100_000).map(|_| u32::from(<u32 as Into<AtomicU32>>::into(0u32))).collect();
80+
| +++++++++++++++++++++++++++++++ ~
5781

5882
error[E0283]: type annotations needed for `Box<_>`
5983
--> $DIR/issue-77982.rs:37:9

0 commit comments

Comments
 (0)