about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
authorEsteban Küber <esteban@kuber.com.ar>2024-01-22 20:53:41 +0000
committerEsteban Küber <esteban@kuber.com.ar>2024-01-22 20:53:41 +0000
commitac56a2b564a3e15b8377e72294a3d565a1c8c659 (patch)
treef42ae59254539e6d9319d666226c1c43740bb507 /compiler
parent390ef9ba0297ae5ba5aacdf0be0d0c47be8d166a (diff)
downloadrust-ac56a2b564a3e15b8377e72294a3d565a1c8c659.tar.gz
rust-ac56a2b564a3e15b8377e72294a3d565a1c8c659.zip
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.
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs32
1 files changed, 32 insertions, 0 deletions
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 afb3c5c1e56..a0dfaf33a6e 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<T> Trait<T> 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!(