Suggest dereference of Box when inner type is expected

For example:

    enum Ty {
        Unit,
        List(Box<Ty>),
    }

    fn foo(x: Ty) -> Ty {
        match x {
            Ty::Unit => Ty::Unit,
            Ty::List(elem) => foo(elem),
        }
    }

Before, the only suggestion was to rewrap `elem` with `Ty::List`,
which is unhelpful and confusing:

    error[E0308]: mismatched types
     --> src/test/ui/suggestions/boxed-variant-field.rs:9:31
      |
    9 |         Ty::List(elem) => foo(elem),
      |                               ^^^^
      |                               |
      |                               expected enum `Ty`, found struct `Box`
      |                               help: try using a variant of the expected enum: `Ty::List(elem)`
      |
      = note: expected enum `Ty`
               found struct `Box<Ty>`

Now, rustc will first suggest dereferencing the `Box`, which is most
likely what the user intended:

    error[E0308]: mismatched types
     --> src/test/ui/suggestions/boxed-variant-field.rs:9:31
      |
    9 |         Ty::List(elem) => foo(elem),
      |                               ^^^^ expected enum `Ty`, found struct `Box`
      |
      = note: expected enum `Ty`
               found struct `Box<Ty>`
    help: try dereferencing the `Box`
      |
    9 |         Ty::List(elem) => foo(*elem),
      |                               +
    help: try using a variant of the expected enum
      |
    9 |         Ty::List(elem) => foo(Ty::List(elem)),
      |                               ~~~~~~~~~~~~~~
This commit is contained in:
Noah Lev 2021-11-04 23:25:16 -07:00
parent 2cff30b17a
commit d93f7f93c4
4 changed files with 58 additions and 0 deletions

View file

@ -29,6 +29,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
) {
self.annotate_expected_due_to_let_ty(err, expr);
self.suggest_box_deref(err, expr, expected, expr_ty);
self.suggest_compatible_variants(err, expr, expected, expr_ty);
self.suggest_deref_ref_or_into(err, expr, expected, expr_ty, expected_ty_expr);
if self.suggest_calling_boxed_future_when_appropriate(err, expr, expected, expr_ty) {
@ -167,6 +168,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
fn suggest_box_deref(
&self,
err: &mut DiagnosticBuilder<'_>,
expr: &hir::Expr<'_>,
expected: Ty<'tcx>,
expr_ty: Ty<'tcx>,
) {
if expr_ty.is_box() && expr_ty.boxed_ty() == expected {
err.span_suggestion_verbose(
expr.span.shrink_to_lo(),
"try dereferencing the `Box`",
"*".to_string(),
Applicability::MachineApplicable,
);
}
}
/// If the expected type is an enum (Issue #55250) with any variants whose
/// sole field is of the found type, suggest such variants. (Issue #42764)
fn suggest_compatible_variants(

View file

@ -0,0 +1,16 @@
enum Ty {
Unit,
List(Box<Ty>),
}
fn foo(x: Ty) -> Ty {
match x {
Ty::Unit => Ty::Unit,
Ty::List(elem) => foo(elem),
//~^ ERROR mismatched types
//~| HELP try dereferencing the `Box`
//~| HELP try using a variant of the expected enum
}
}
fn main() {}

View file

@ -0,0 +1,20 @@
error[E0308]: mismatched types
--> $DIR/boxed-variant-field.rs:9:31
|
LL | Ty::List(elem) => foo(elem),
| ^^^^ expected enum `Ty`, found struct `Box`
|
= note: expected enum `Ty`
found struct `Box<Ty>`
help: try dereferencing the `Box`
|
LL | Ty::List(elem) => foo(*elem),
| +
help: try using a variant of the expected enum
|
LL | Ty::List(elem) => foo(Ty::List(elem)),
| ~~~~~~~~~~~~~~
error: aborting due to previous error
For more information about this error, try `rustc --explain E0308`.

View file

@ -6,6 +6,10 @@ LL | want_foo(b);
|
= note: expected struct `Foo`
found struct `Box<Foo>`
help: try dereferencing the `Box`
|
LL | want_foo(*b);
| +
error: aborting due to previous error