summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_typeck/src/check/pat.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_typeck/src/check/pat.rs')
-rw-r--r--compiler/rustc_typeck/src/check/pat.rs67
1 files changed, 56 insertions, 11 deletions
diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs
index 837c32355..8906b622b 100644
--- a/compiler/rustc_typeck/src/check/pat.rs
+++ b/compiler/rustc_typeck/src/check/pat.rs
@@ -569,7 +569,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
) -> Ty<'tcx> {
// Determine the binding mode...
let bm = match ba {
- hir::BindingAnnotation::Unannotated => def_bm,
+ hir::BindingAnnotation::NONE => def_bm,
_ => BindingMode::convert(ba),
};
// ...and store it in a side table:
@@ -600,7 +600,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// 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 {
@@ -610,7 +610,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
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();
@@ -628,12 +635,50 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
});
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::NONE)
+ 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;
@@ -882,7 +927,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
),
);
match self.tcx.hir().get(self.tcx.hir().get_parent_node(pat.hir_id)) {
- hir::Node::Pat(Pat { kind: hir::PatKind::Struct(..), .. }) => {
+ hir::Node::PatField(..) => {
e.span_suggestion_verbose(
ident.span.shrink_to_hi(),
"bind the struct field to a different name instead",
@@ -936,7 +981,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pat: &'tcx Pat<'tcx>,
qpath: &'tcx hir::QPath<'tcx>,
subpats: &'tcx [Pat<'tcx>],
- ddpos: Option<usize>,
+ ddpos: hir::DotDotPos,
expected: Ty<'tcx>,
def_bm: BindingMode,
ti: TopInfo<'tcx>,
@@ -1021,7 +1066,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Type-check subpatterns.
if subpats.len() == variant.fields.len()
- || subpats.len() < variant.fields.len() && ddpos.is_some()
+ || subpats.len() < variant.fields.len() && ddpos.as_opt_usize().is_some()
{
let ty::Adt(_, substs) = pat_ty.kind() else {
bug!("unexpected pattern type {:?}", pat_ty);
@@ -1209,14 +1254,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&self,
span: Span,
elements: &'tcx [Pat<'tcx>],
- ddpos: Option<usize>,
+ ddpos: hir::DotDotPos,
expected: Ty<'tcx>,
def_bm: BindingMode,
ti: TopInfo<'tcx>,
) -> Ty<'tcx> {
let tcx = self.tcx;
let mut expected_len = elements.len();
- if ddpos.is_some() {
+ if ddpos.as_opt_usize().is_some() {
// Require known type only when `..` is present.
if let ty::Tuple(tys) = self.structurally_resolved_type(span, expected).kind() {
expected_len = tys.len();
@@ -1352,7 +1397,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.iter()
.copied()
.filter(|(field, _)| {
- field.vis.is_accessible_from(tcx.parent_module(pat.hir_id).to_def_id(), tcx)
+ field.vis.is_accessible_from(tcx.parent_module(pat.hir_id), tcx)
&& !matches!(
tcx.eval_stability(field.did, None, DUMMY_SP, None),
EvalResult::Deny { .. }