suggest adding/removing ref
for binding patterns
This commit is contained in:
parent
3ae03e027a
commit
c0a22a0209
@ -617,7 +617,7 @@ fn check_pat_ident(
|
||||
// If there are multiple arms, make sure they all agree on
|
||||
// what the type of the binding `x` ought to be.
|
||||
if var_id != pat.hir_id {
|
||||
self.check_binding_alt_eq_ty(pat.span, var_id, local_ty, ti);
|
||||
self.check_binding_alt_eq_ty(ba, pat.span, var_id, local_ty, ti);
|
||||
}
|
||||
|
||||
if let Some(p) = sub {
|
||||
@ -627,7 +627,14 @@ fn check_pat_ident(
|
||||
local_ty
|
||||
}
|
||||
|
||||
fn check_binding_alt_eq_ty(&self, span: Span, var_id: HirId, ty: Ty<'tcx>, ti: TopInfo<'tcx>) {
|
||||
fn check_binding_alt_eq_ty(
|
||||
&self,
|
||||
ba: hir::BindingAnnotation,
|
||||
span: Span,
|
||||
var_id: HirId,
|
||||
ty: Ty<'tcx>,
|
||||
ti: TopInfo<'tcx>,
|
||||
) {
|
||||
let var_ty = self.local_ty(span, var_id).decl_ty;
|
||||
if let Some(mut err) = self.demand_eqtype_pat_diag(span, var_ty, ty, ti) {
|
||||
let hir = self.tcx.hir();
|
||||
@ -645,12 +652,50 @@ fn check_binding_alt_eq_ty(&self, span: Span, var_id: HirId, ty: Ty<'tcx>, ti: T
|
||||
});
|
||||
let pre = if in_match { "in the same arm, " } else { "" };
|
||||
err.note(&format!("{}a binding must have the same type in all alternatives", pre));
|
||||
// FIXME: check if `var_ty` and `ty` can be made the same type by adding or removing
|
||||
// `ref` or `&` to the pattern.
|
||||
self.suggest_adding_missing_ref_or_removing_ref(
|
||||
&mut err,
|
||||
span,
|
||||
var_ty,
|
||||
self.resolve_vars_with_obligations(ty),
|
||||
ba,
|
||||
);
|
||||
err.emit();
|
||||
}
|
||||
}
|
||||
|
||||
fn suggest_adding_missing_ref_or_removing_ref(
|
||||
&self,
|
||||
err: &mut Diagnostic,
|
||||
span: Span,
|
||||
expected: Ty<'tcx>,
|
||||
actual: Ty<'tcx>,
|
||||
ba: hir::BindingAnnotation,
|
||||
) {
|
||||
match (expected.kind(), actual.kind(), ba) {
|
||||
(ty::Ref(_, inner_ty, _), _, hir::BindingAnnotation::Unannotated)
|
||||
if self.can_eq(self.param_env, *inner_ty, actual).is_ok() =>
|
||||
{
|
||||
err.span_suggestion_verbose(
|
||||
span.shrink_to_lo(),
|
||||
"consider adding `ref`",
|
||||
"ref ",
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
(_, ty::Ref(_, inner_ty, _), hir::BindingAnnotation::Ref)
|
||||
if self.can_eq(self.param_env, expected, *inner_ty).is_ok() =>
|
||||
{
|
||||
err.span_suggestion_verbose(
|
||||
span.with_hi(span.lo() + BytePos(4)),
|
||||
"consider removing `ref`",
|
||||
"",
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
// Precondition: pat is a Ref(_) pattern
|
||||
fn borrow_pat_suggestion(&self, err: &mut Diagnostic, pat: &Pat<'_>) {
|
||||
let tcx = self.tcx;
|
||||
|
@ -17,6 +17,10 @@ LL | (0, ref y) | (y, 0) => {}
|
||||
| first introduced with type `&{integer}` here
|
||||
|
|
||||
= note: in the same arm, a binding must have the same type in all alternatives
|
||||
help: consider adding `ref`
|
||||
|
|
||||
LL | (0, ref y) | (ref y, 0) => {}
|
||||
| +++
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
@ -0,0 +1,21 @@
|
||||
// run-rustfix
|
||||
#![allow(dead_code, unused_variables)]
|
||||
|
||||
fn main() {
|
||||
enum Blah {
|
||||
A(isize, isize, usize),
|
||||
B(isize, usize),
|
||||
}
|
||||
|
||||
match Blah::A(1, 1, 2) {
|
||||
Blah::A(_, x, ref y) | Blah::B(x, ref y) => {}
|
||||
//~^ ERROR mismatched types
|
||||
//~| ERROR variable `y` is bound inconsistently across alternatives separated by `|`
|
||||
}
|
||||
|
||||
match Blah::A(1, 1, 2) {
|
||||
Blah::A(_, x, y) | Blah::B(x, y) => {}
|
||||
//~^ ERROR mismatched types
|
||||
//~| variable `y` is bound inconsistently across alternatives separated by `|`
|
||||
}
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
// run-rustfix
|
||||
#![allow(dead_code, unused_variables)]
|
||||
|
||||
fn main() {
|
||||
enum Blah {
|
||||
A(isize, isize, usize),
|
||||
B(isize, usize),
|
||||
}
|
||||
|
||||
match Blah::A(1, 1, 2) {
|
||||
Blah::A(_, x, ref y) | Blah::B(x, y) => {}
|
||||
//~^ ERROR mismatched types
|
||||
//~| ERROR variable `y` is bound inconsistently across alternatives separated by `|`
|
||||
}
|
||||
|
||||
match Blah::A(1, 1, 2) {
|
||||
Blah::A(_, x, y) | Blah::B(x, ref y) => {}
|
||||
//~^ ERROR mismatched types
|
||||
//~| variable `y` is bound inconsistently across alternatives separated by `|`
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
error[E0409]: variable `y` is bound inconsistently across alternatives separated by `|`
|
||||
--> $DIR/suggest-adding-or-removing-ref-for-binding-pattern.rs:11:43
|
||||
|
|
||||
LL | Blah::A(_, x, ref y) | Blah::B(x, y) => {}
|
||||
| - first binding ^ bound in different ways
|
||||
|
||||
error[E0409]: variable `y` is bound inconsistently across alternatives separated by `|`
|
||||
--> $DIR/suggest-adding-or-removing-ref-for-binding-pattern.rs:17:43
|
||||
|
|
||||
LL | Blah::A(_, x, y) | Blah::B(x, ref y) => {}
|
||||
| - first binding ^ bound in different ways
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/suggest-adding-or-removing-ref-for-binding-pattern.rs:11:43
|
||||
|
|
||||
LL | match Blah::A(1, 1, 2) {
|
||||
| ---------------- this expression has type `Blah`
|
||||
LL | Blah::A(_, x, ref y) | Blah::B(x, y) => {}
|
||||
| ----- ^ expected `&usize`, found `usize`
|
||||
| |
|
||||
| first introduced with type `&usize` here
|
||||
|
|
||||
= note: in the same arm, a binding must have the same type in all alternatives
|
||||
help: consider adding `ref`
|
||||
|
|
||||
LL | Blah::A(_, x, ref y) | Blah::B(x, ref y) => {}
|
||||
| +++
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/suggest-adding-or-removing-ref-for-binding-pattern.rs:17:39
|
||||
|
|
||||
LL | match Blah::A(1, 1, 2) {
|
||||
| ---------------- this expression has type `Blah`
|
||||
LL | Blah::A(_, x, y) | Blah::B(x, ref y) => {}
|
||||
| - ^^^^^ expected `usize`, found `&usize`
|
||||
| |
|
||||
| first introduced with type `usize` here
|
||||
|
|
||||
= note: in the same arm, a binding must have the same type in all alternatives
|
||||
help: consider removing `ref`
|
||||
|
|
||||
LL - Blah::A(_, x, y) | Blah::B(x, ref y) => {}
|
||||
LL + Blah::A(_, x, y) | Blah::B(x, y) => {}
|
||||
|
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0308, E0409.
|
||||
For more information about an error, try `rustc --explain E0308`.
|
@ -31,6 +31,10 @@ LL | Opts::A(ref i) | Opts::B(i) => {}
|
||||
| first introduced with type `&isize` here
|
||||
|
|
||||
= note: in the same arm, a binding must have the same type in all alternatives
|
||||
help: consider adding `ref`
|
||||
|
|
||||
LL | Opts::A(ref i) | Opts::B(ref i) => {}
|
||||
| +++
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/resolve-inconsistent-binding-mode.rs:18:34
|
||||
@ -43,6 +47,10 @@ LL | Opts::A(ref i) | Opts::B(i) => {}
|
||||
| first introduced with type `&isize` here
|
||||
|
|
||||
= note: in the same arm, a binding must have the same type in all alternatives
|
||||
help: consider adding `ref`
|
||||
|
|
||||
LL | Opts::A(ref i) | Opts::B(ref i) => {}
|
||||
| +++
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/resolve-inconsistent-binding-mode.rs:27:38
|
||||
|
@ -23,6 +23,7 @@ fn main() {
|
||||
//~| ERROR mismatched types
|
||||
//~| ERROR variable `c` is not bound in all patterns
|
||||
//~| HELP if you meant to match on unit variant `E::A`, use the full path in the pattern
|
||||
//~| HELP consider removing `ref`
|
||||
}
|
||||
|
||||
let z = (10, 20);
|
||||
|
@ -55,7 +55,7 @@ LL | (A, B) | (ref B, c) | (c, A) => ()
|
||||
| first binding
|
||||
|
||||
error[E0408]: variable `CONST1` is not bound in all patterns
|
||||
--> $DIR/resolve-inconsistent-names.rs:30:23
|
||||
--> $DIR/resolve-inconsistent-names.rs:31:23
|
||||
|
|
||||
LL | (CONST1, _) | (_, Const2) => ()
|
||||
| ------ ^^^^^^^^^^^ pattern doesn't bind `CONST1`
|
||||
@ -69,7 +69,7 @@ LL | const CONST1: usize = 10;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ not accessible
|
||||
|
||||
error[E0408]: variable `Const2` is not bound in all patterns
|
||||
--> $DIR/resolve-inconsistent-names.rs:30:9
|
||||
--> $DIR/resolve-inconsistent-names.rs:31:9
|
||||
|
|
||||
LL | (CONST1, _) | (_, Const2) => ()
|
||||
| ^^^^^^^^^^^ ------ variable not in all patterns
|
||||
@ -92,6 +92,11 @@ LL | (A, B) | (ref B, c) | (c, A) => ()
|
||||
| first introduced with type `E` here
|
||||
|
|
||||
= note: in the same arm, a binding must have the same type in all alternatives
|
||||
help: consider removing `ref`
|
||||
|
|
||||
LL - (A, B) | (ref B, c) | (c, A) => ()
|
||||
LL + (A, B) | (B, c) | (c, A) => ()
|
||||
|
|
||||
|
||||
error: aborting due to 9 previous errors
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user