Skip to content

Commit 79049f1

Browse files
Match ergonomics 2024: migration lint
1 parent 659b70e commit 79049f1

16 files changed

+408
-193
lines changed

Cargo.lock

+1
Original file line numberDiff line numberDiff line change
@@ -4286,6 +4286,7 @@ dependencies = [
42864286
"rustc_hir",
42874287
"rustc_index",
42884288
"rustc_infer",
4289+
"rustc_lint",
42894290
"rustc_macros",
42904291
"rustc_middle",
42914292
"rustc_pattern_analysis",

compiler/rustc_hir_typeck/messages.ftl

-4
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,6 @@ hir_typeck_ctor_is_private = tuple struct constructor `{$def}` is private
4646
4747
hir_typeck_deref_is_empty = this expression `Deref`s to `{$deref_ty}` which implements `is_empty`
4848
49-
hir_typeck_dereferencing_mut_binding = dereferencing `mut` binding
50-
.label = `mut` dereferences the type of this binding
51-
.help = this will change in edition 2024
52-
5349
hir_typeck_expected_default_return_type = expected `()` because of default return type
5450
5551
hir_typeck_expected_return_type = expected `{$expected}` because of return type

compiler/rustc_hir_typeck/src/errors.rs

-8
Original file line numberDiff line numberDiff line change
@@ -632,11 +632,3 @@ pub enum SuggestBoxingForReturnImplTrait {
632632
ends: Vec<Span>,
633633
},
634634
}
635-
636-
#[derive(LintDiagnostic)]
637-
#[diag(hir_typeck_dereferencing_mut_binding)]
638-
pub struct DereferencingMutBinding {
639-
#[label]
640-
#[help]
641-
pub span: Span,
642-
}

compiler/rustc_hir_typeck/src/pat.rs

+97-94
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ use rustc_hir::pat_util::EnumerateAndAdjustIterator;
1010
use rustc_hir::{self as hir, BindingMode, ByRef, HirId, Mutability, Pat, PatKind};
1111
use rustc_infer::infer;
1212
use rustc_infer::infer::type_variable::TypeVariableOrigin;
13-
use rustc_lint as lint;
1413
use rustc_middle::mir::interpret::ErrorHandled;
1514
use rustc_middle::ty::{self, Ty, TypeVisitableExt};
1615
use rustc_session::lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS;
@@ -75,21 +74,23 @@ struct TopInfo<'tcx> {
7574
/// found type `std::result::Result<_, _>`
7675
/// ```
7776
span: Option<Span>,
77+
/// The [`HirId`] of the top-level pattern.
78+
hir_id: HirId,
7879
}
7980

8081
#[derive(Copy, Clone)]
8182
struct PatInfo<'tcx, 'a> {
8283
binding_mode: ByRef,
8384
max_ref_mutbl: MutblCap,
84-
top_info: TopInfo<'tcx>,
85-
decl_origin: Option<DeclOrigin<'a>>,
85+
top_info: &'a TopInfo<'tcx>,
86+
decl_origin: Option<DeclOrigin<'tcx>>,
8687

8788
/// The depth of current pattern
8889
current_depth: u32,
8990
}
9091

9192
impl<'tcx> FnCtxt<'_, 'tcx> {
92-
fn pattern_cause(&self, ti: TopInfo<'tcx>, cause_span: Span) -> ObligationCause<'tcx> {
93+
fn pattern_cause(&self, ti: &TopInfo<'tcx>, cause_span: Span) -> ObligationCause<'tcx> {
9394
let code =
9495
Pattern { span: ti.span, root_ty: ti.expected, origin_expr: ti.origin_expr.is_some() };
9596
self.cause(cause_span, code)
@@ -100,7 +101,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
100101
cause_span: Span,
101102
expected: Ty<'tcx>,
102103
actual: Ty<'tcx>,
103-
ti: TopInfo<'tcx>,
104+
ti: &TopInfo<'tcx>,
104105
) -> Option<Diag<'tcx>> {
105106
let mut diag =
106107
self.demand_eqtype_with_origin(&self.pattern_cause(ti, cause_span), expected, actual)?;
@@ -117,7 +118,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
117118
cause_span: Span,
118119
expected: Ty<'tcx>,
119120
actual: Ty<'tcx>,
120-
ti: TopInfo<'tcx>,
121+
ti: &TopInfo<'tcx>,
121122
) {
122123
if let Some(err) = self.demand_eqtype_pat_diag(cause_span, expected, actual, ti) {
123124
err.emit();
@@ -193,11 +194,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
193194
origin_expr: Option<&'tcx hir::Expr<'tcx>>,
194195
decl_origin: Option<DeclOrigin<'tcx>>,
195196
) {
196-
let info = TopInfo { expected, origin_expr, span };
197+
let info = TopInfo { expected, origin_expr, span, hir_id: pat.hir_id };
197198
let pat_info = PatInfo {
198199
binding_mode: ByRef::No,
199200
max_ref_mutbl: MutblCap::Mut,
200-
top_info: info,
201+
top_info: &info,
201202
decl_origin,
202203
current_depth: 0,
203204
};
@@ -222,7 +223,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
222223
};
223224
let adjust_mode = self.calc_adjust_mode(pat, path_res.map(|(res, ..)| res));
224225
let (expected, def_bm, max_ref_mutbl, ref_pattern_already_consumed) =
225-
self.calc_default_binding_mode(pat, expected, def_bm, adjust_mode, max_ref_mutbl);
226+
self.calc_default_binding_mode(pat, expected, def_bm, adjust_mode, max_ref_mutbl, ti);
226227
let pat_info = PatInfo {
227228
binding_mode: def_bm,
228229
max_ref_mutbl,
@@ -331,6 +332,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
331332
def_br: ByRef,
332333
adjust_mode: AdjustMode,
333334
max_ref_mutbl: MutblCap,
335+
top_info: &TopInfo<'tcx>,
334336
) -> (Ty<'tcx>, ByRef, MutblCap, bool) {
335337
if let ByRef::Yes(Mutability::Mut) = def_br {
336338
debug_assert!(max_ref_mutbl == MutblCap::Mut);
@@ -368,6 +370,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
368370
(new_ty, new_bm, max_ref_mutbl, false)
369371
}
370372
} else {
373+
if def_br != ByRef::No {
374+
self.typeck_results
375+
.borrow_mut()
376+
.rust_2024_migration_desugared_pats_mut()
377+
.insert(top_info.hir_id);
378+
}
371379
(expected, ByRef::No, max_ref_mutbl, mutbls_match)
372380
}
373381
}
@@ -513,7 +521,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
513521
span: Span,
514522
lt: &hir::Expr<'tcx>,
515523
expected: Ty<'tcx>,
516-
ti: TopInfo<'tcx>,
524+
ti: &TopInfo<'tcx>,
517525
) -> Ty<'tcx> {
518526
// We've already computed the type above (when checking for a non-ref pat),
519527
// so avoid computing it again.
@@ -583,7 +591,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
583591
lhs: Option<&'tcx hir::Expr<'tcx>>,
584592
rhs: Option<&'tcx hir::Expr<'tcx>>,
585593
expected: Ty<'tcx>,
586-
ti: TopInfo<'tcx>,
594+
ti: &TopInfo<'tcx>,
587595
) -> Ty<'tcx> {
588596
let calc_side = |opt_expr: Option<&'tcx hir::Expr<'tcx>>| match opt_expr {
589597
None => None,
@@ -721,18 +729,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
721729

722730
// Determine the binding mode...
723731
let bm = match explicit_ba {
732+
// `mut` resets binding mode on edition <= 2021
724733
BindingMode(ByRef::No, Mutability::Mut)
725734
if !(pat.span.at_least_rust_2024()
726735
&& self.tcx.features().mut_preserve_binding_mode_2024)
727736
&& matches!(def_br, ByRef::Yes(_)) =>
728737
{
729-
// `mut x` resets the binding mode in edition <= 2021.
730-
self.tcx.emit_node_span_lint(
731-
lint::builtin::DEREFERENCING_MUT_BINDING,
732-
pat.hir_id,
733-
pat.span,
734-
errors::DereferencingMutBinding { span: pat.span },
735-
);
738+
self.typeck_results
739+
.borrow_mut()
740+
.rust_2024_migration_desugared_pats_mut()
741+
.insert(pat_info.top_info.hir_id);
736742
BindingMode(ByRef::No, Mutability::Mut)
737743
}
738744
BindingMode(ByRef::No, mutbl) => BindingMode(def_br, mutbl),
@@ -796,7 +802,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
796802
span: Span,
797803
var_id: HirId,
798804
ty: Ty<'tcx>,
799-
ti: TopInfo<'tcx>,
805+
ti: &TopInfo<'tcx>,
800806
) {
801807
let var_ty = self.local_ty(span, var_id);
802808
if let Some(mut err) = self.demand_eqtype_pat_diag(span, var_ty, ty, ti) {
@@ -1038,7 +1044,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
10381044
qpath: &hir::QPath<'_>,
10391045
path_resolution: (Res, Option<LoweredTy<'tcx>>, &'tcx [hir::PathSegment<'tcx>]),
10401046
expected: Ty<'tcx>,
1041-
ti: TopInfo<'tcx>,
1047+
ti: &TopInfo<'tcx>,
10421048
) -> Ty<'tcx> {
10431049
let tcx = self.tcx;
10441050

@@ -2169,86 +2175,83 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
21692175
{
21702176
self.typeck_results.borrow_mut().skipped_ref_pats_mut().insert(pat.hir_id);
21712177
self.check_pat(inner, expected, pat_info);
2172-
expected
2173-
} else {
2174-
let tcx = self.tcx;
2175-
let expected = self.shallow_resolve(expected);
2176-
let (ref_ty, inner_ty, pat_info) = match self
2177-
.check_dereferenceable(pat.span, expected, inner)
2178-
{
2179-
Ok(()) => {
2180-
// `demand::subtype` would be good enough, but using `eqtype` turns
2181-
// out to be equally general. See (note_1) for details.
2182-
2183-
// Take region, inner-type from expected type if we can,
2184-
// to avoid creating needless variables. This also helps with
2185-
// the bad interactions of the given hack detailed in (note_1).
2186-
debug!("check_pat_ref: expected={:?}", expected);
2187-
match *expected.kind() {
2188-
ty::Ref(_, r_ty, r_mutbl) if r_mutbl == mutbl => (expected, r_ty, pat_info),
2189-
2190-
// `&` pattern eats `&mut` reference
2191-
ty::Ref(_, r_ty, Mutability::Mut)
2192-
if mutbl == Mutability::Not
2193-
&& ((pat.span.at_least_rust_2024()
2194-
&& self.tcx.features().ref_pat_eat_one_layer_2024)
2195-
|| self.tcx.features().ref_pat_everywhere) =>
2196-
{
2197-
(
2198-
expected,
2199-
r_ty,
2200-
PatInfo {
2201-
max_ref_mutbl: pat_info
2202-
.max_ref_mutbl
2203-
.cap_mutbl_to_not(Some(pat.span.until(inner.span))),
2204-
..pat_info
2205-
},
2206-
)
2207-
}
2178+
return expected;
2179+
}
22082180

2209-
_ if consumed_inherited_ref && self.tcx.features().ref_pat_everywhere => {
2210-
// We already matched against a match-ergonmics inserted reference,
2211-
// so we don't need to match against a reference from the original type.
2212-
// Save this infor for use in lowering later
2213-
self.typeck_results
2214-
.borrow_mut()
2215-
.skipped_ref_pats_mut()
2216-
.insert(pat.hir_id);
2217-
(expected, expected, pat_info)
2218-
}
2181+
let tcx = self.tcx;
2182+
let expected = self.shallow_resolve(expected);
2183+
let (ref_ty, inner_ty, pat_info) = match self
2184+
.check_dereferenceable(pat.span, expected, inner)
2185+
{
2186+
Ok(()) => {
2187+
// `demand::subtype` would be good enough, but using `eqtype` turns
2188+
// out to be equally general. See (note_1) for details.
2189+
2190+
// Take region, inner-type from expected type if we can,
2191+
// to avoid creating needless variables. This also helps with
2192+
// the bad interactions of the given hack detailed in (note_1).
2193+
debug!("check_pat_ref: expected={:?}", expected);
2194+
match *expected.kind() {
2195+
ty::Ref(_, r_ty, r_mutbl) if r_mutbl == mutbl => (expected, r_ty, pat_info),
2196+
2197+
// `&` pattern eats `&mut` reference
2198+
ty::Ref(_, r_ty, Mutability::Mut)
2199+
if mutbl == Mutability::Not
2200+
&& ((pat.span.at_least_rust_2024()
2201+
&& self.tcx.features().ref_pat_eat_one_layer_2024)
2202+
|| self.tcx.features().ref_pat_everywhere) =>
2203+
{
2204+
(
2205+
expected,
2206+
r_ty,
2207+
PatInfo {
2208+
max_ref_mutbl: pat_info
2209+
.max_ref_mutbl
2210+
.cap_mutbl_to_not(Some(pat.span.until(inner.span))),
2211+
..pat_info
2212+
},
2213+
)
2214+
}
22192215

2220-
_ => {
2221-
let inner_ty = self.next_ty_var(TypeVariableOrigin {
2222-
param_def_id: None,
2223-
span: inner.span,
2224-
});
2225-
let ref_ty = self.new_ref_ty(pat.span, mutbl, inner_ty);
2226-
debug!("check_pat_ref: demanding {:?} = {:?}", expected, ref_ty);
2227-
let err = self.demand_eqtype_pat_diag(
2228-
pat.span,
2229-
expected,
2230-
ref_ty,
2231-
pat_info.top_info,
2232-
);
2216+
_ if consumed_inherited_ref && self.tcx.features().ref_pat_everywhere => {
2217+
// We already matched against a match-ergonmics inserted reference,
2218+
// so we don't need to match against a reference from the original type.
2219+
// Save this infor for use in lowering later
2220+
self.typeck_results.borrow_mut().skipped_ref_pats_mut().insert(pat.hir_id);
2221+
(expected, expected, pat_info)
2222+
}
22332223

2234-
// Look for a case like `fn foo(&foo: u32)` and suggest
2235-
// `fn foo(foo: &u32)`
2236-
if let Some(mut err) = err {
2237-
self.borrow_pat_suggestion(&mut err, pat);
2238-
err.emit();
2239-
}
2240-
(ref_ty, inner_ty, pat_info)
2224+
_ => {
2225+
let inner_ty = self.next_ty_var(TypeVariableOrigin {
2226+
param_def_id: None,
2227+
span: inner.span,
2228+
});
2229+
let ref_ty = self.new_ref_ty(pat.span, mutbl, inner_ty);
2230+
debug!("check_pat_ref: demanding {:?} = {:?}", expected, ref_ty);
2231+
let err = self.demand_eqtype_pat_diag(
2232+
pat.span,
2233+
expected,
2234+
ref_ty,
2235+
pat_info.top_info,
2236+
);
2237+
2238+
// Look for a case like `fn foo(&foo: u32)` and suggest
2239+
// `fn foo(foo: &u32)`
2240+
if let Some(mut err) = err {
2241+
self.borrow_pat_suggestion(&mut err, pat);
2242+
err.emit();
22412243
}
2244+
(ref_ty, inner_ty, pat_info)
22422245
}
22432246
}
2244-
Err(guar) => {
2245-
let err = Ty::new_error(tcx, guar);
2246-
(err, err, pat_info)
2247-
}
2248-
};
2249-
self.check_pat(inner, inner_ty, pat_info);
2250-
ref_ty
2251-
}
2247+
}
2248+
Err(guar) => {
2249+
let err = Ty::new_error(tcx, guar);
2250+
(err, err, pat_info)
2251+
}
2252+
};
2253+
self.check_pat(inner, inner_ty, pat_info);
2254+
ref_ty
22522255
}
22532256

22542257
/// Create a reference type with a fresh region variable.

compiler/rustc_hir_typeck/src/writeback.rs

+17
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> {
346346
_ => {}
347347
};
348348

349+
self.visit_rust_2024_migration_desugared_pats(p.hir_id);
349350
self.visit_skipped_ref_pats(p.hir_id);
350351
self.visit_pat_adjustments(p.span, p.hir_id);
351352

@@ -655,6 +656,22 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
655656
}
656657
}
657658

659+
#[instrument(skip(self), level = "debug")]
660+
fn visit_rust_2024_migration_desugared_pats(&mut self, hir_id: hir::HirId) {
661+
if self
662+
.fcx
663+
.typeck_results
664+
.borrow_mut()
665+
.rust_2024_migration_desugared_pats_mut()
666+
.remove(hir_id)
667+
{
668+
debug!(
669+
"node is a pat whose match ergonomics are desugared by the Rust 2024 migration lint"
670+
);
671+
self.typeck_results.rust_2024_migration_desugared_pats_mut().insert(hir_id);
672+
}
673+
}
674+
658675
#[instrument(skip(self, span), level = "debug")]
659676
fn visit_pat_adjustments(&mut self, span: Span, hir_id: HirId) {
660677
let adjustment = self.fcx.typeck_results.borrow_mut().pat_adjustments_mut().remove(hir_id);

0 commit comments

Comments
 (0)