Suggest boxing if then expr if that solves divergent arms
When encountering ```rust let _ = if true { Struct } else { foo() // -> Box<dyn Trait> }; ``` if `Struct` implements `Trait`, suggest boxing the then arm tail expression. Part of #102629.
This commit is contained in:
parent
390ef9ba02
commit
ac56a2b564
@ -330,6 +330,38 @@ fn foo(&self, x: T) -> T { x }
|
||||
);
|
||||
}
|
||||
}
|
||||
(ty::Adt(_, _), ty::Adt(def, args))
|
||||
if let ObligationCauseCode::IfExpression(cause) = cause.code()
|
||||
&& let hir::Node::Block(blk) = self.tcx.hir_node(cause.then_id)
|
||||
&& let Some(then) = blk.expr
|
||||
&& def.is_box()
|
||||
&& let boxed_ty = args.type_at(0)
|
||||
&& let ty::Dynamic(t, _, _) = boxed_ty.kind()
|
||||
&& let Some(def_id) = t.principal_def_id()
|
||||
&& let mut impl_def_ids = vec![]
|
||||
&& let _ =
|
||||
tcx.for_each_relevant_impl(def_id, values.expected, |did| {
|
||||
impl_def_ids.push(did)
|
||||
})
|
||||
&& let [_] = &impl_def_ids[..] =>
|
||||
{
|
||||
// We have divergent if/else arms where the expected value is a type that
|
||||
// implements the trait of the found boxed trait object.
|
||||
diag.multipart_suggestion(
|
||||
format!(
|
||||
"`{}` implements `{}` so you can box it to coerce to the trait \
|
||||
object `{}`",
|
||||
values.expected,
|
||||
tcx.item_name(def_id),
|
||||
values.found,
|
||||
),
|
||||
vec![
|
||||
(then.span.shrink_to_lo(), "Box::new(".to_string()),
|
||||
(then.span.shrink_to_hi(), ")".to_string()),
|
||||
],
|
||||
MachineApplicable,
|
||||
);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
debug!(
|
||||
|
@ -6,6 +6,11 @@ fn foo() -> Box<dyn Trait> {
|
||||
Box::new(Struct)
|
||||
}
|
||||
fn main() {
|
||||
let _ = if true {
|
||||
Box::new(Struct)
|
||||
} else {
|
||||
foo() //~ ERROR E0308
|
||||
};
|
||||
let _ = if true {
|
||||
foo()
|
||||
} else {
|
||||
|
@ -6,6 +6,11 @@ fn foo() -> Box<dyn Trait> {
|
||||
Box::new(Struct)
|
||||
}
|
||||
fn main() {
|
||||
let _ = if true {
|
||||
Struct
|
||||
} else {
|
||||
foo() //~ ERROR E0308
|
||||
};
|
||||
let _ = if true {
|
||||
foo()
|
||||
} else {
|
||||
|
@ -3,6 +3,26 @@ error[E0308]: `if` and `else` have incompatible types
|
||||
|
|
||||
LL | let _ = if true {
|
||||
| _____________-
|
||||
LL | | Struct
|
||||
| | ------ expected because of this
|
||||
LL | | } else {
|
||||
LL | | foo()
|
||||
| | ^^^^^ expected `Struct`, found `Box<dyn Trait>`
|
||||
LL | | };
|
||||
| |_____- `if` and `else` have incompatible types
|
||||
|
|
||||
= note: expected struct `Struct`
|
||||
found struct `Box<dyn Trait>`
|
||||
help: `Struct` implements `Trait` so you can box it to coerce to the trait object `Box<dyn Trait>`
|
||||
|
|
||||
LL | Box::new(Struct)
|
||||
| +++++++++ +
|
||||
|
||||
error[E0308]: `if` and `else` have incompatible types
|
||||
--> $DIR/suggest-box-on-divergent-if-else-arms.rs:17:9
|
||||
|
|
||||
LL | let _ = if true {
|
||||
| _____________-
|
||||
LL | | foo()
|
||||
| | ----- expected because of this
|
||||
LL | | } else {
|
||||
@ -19,6 +39,6 @@ help: store this in the heap by calling `Box::new`
|
||||
LL | Box::new(Struct)
|
||||
| +++++++++ +
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
||||
|
Loading…
Reference in New Issue
Block a user