// 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 {
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();
});
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;
| 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
--- /dev/null
+// 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 `|`
+ }
+}
--- /dev/null
+// 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 `|`
+ }
+}
--- /dev/null
+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`.
| 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
| 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
//~| 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);
| 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`
| ^^^^^^^^^^^^^^^^^^^^^^^^^ 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
| 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