diff --git a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs index afb3c5c1e5656..a0dfaf33a6e85 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs @@ -330,6 +330,38 @@ impl Trait for 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!( diff --git a/tests/ui/typeck/suggest-box-on-divergent-if-else-arms.fixed b/tests/ui/typeck/suggest-box-on-divergent-if-else-arms.fixed index d8031083f6cf8..dfdf6b24bf7e0 100644 --- a/tests/ui/typeck/suggest-box-on-divergent-if-else-arms.fixed +++ b/tests/ui/typeck/suggest-box-on-divergent-if-else-arms.fixed @@ -6,6 +6,11 @@ fn foo() -> Box { Box::new(Struct) } fn main() { + let _ = if true { + Box::new(Struct) + } else { + foo() //~ ERROR E0308 + }; let _ = if true { foo() } else { diff --git a/tests/ui/typeck/suggest-box-on-divergent-if-else-arms.rs b/tests/ui/typeck/suggest-box-on-divergent-if-else-arms.rs index 53e718a56635b..e138ad9b33647 100644 --- a/tests/ui/typeck/suggest-box-on-divergent-if-else-arms.rs +++ b/tests/ui/typeck/suggest-box-on-divergent-if-else-arms.rs @@ -6,6 +6,11 @@ fn foo() -> Box { Box::new(Struct) } fn main() { + let _ = if true { + Struct + } else { + foo() //~ ERROR E0308 + }; let _ = if true { foo() } else { diff --git a/tests/ui/typeck/suggest-box-on-divergent-if-else-arms.stderr b/tests/ui/typeck/suggest-box-on-divergent-if-else-arms.stderr index 183f48ca1fb78..98c9d880f97aa 100644 --- a/tests/ui/typeck/suggest-box-on-divergent-if-else-arms.stderr +++ b/tests/ui/typeck/suggest-box-on-divergent-if-else-arms.stderr @@ -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` +LL | | }; + | |_____- `if` and `else` have incompatible types + | + = note: expected struct `Struct` + found struct `Box` +help: `Struct` implements `Trait` so you can box it to coerce to the trait object `Box` + | +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`.