Skip to content

Commit cdddb85

Browse files
authored
Rollup merge of #150660 - Zalathar:pass-nodes, r=davidtwco
THIR pattern building: Pass HIR nodes instead of loose types/spans This should make it easier to keep track of where the types/spans came from. There should be no change to compiler output. --- In the future I would also like to make more of these lowering methods return `Box<thir::Pat>` instead of `thir::PatKind`, so that it becomes feasible to add more fields to `thir::Pat` (e.g. for #150498 (comment)). That will be easier if those methods have easy access to the corresponding HIR pattern node, from which they can obtain a type and span.
2 parents 18910b7 + de37724 commit cdddb85

1 file changed

Lines changed: 62 additions & 29 deletions

File tree

  • compiler/rustc_mir_build/src/thir/pattern

compiler/rustc_mir_build/src/thir/pattern/mod.rs

Lines changed: 62 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ mod check_match;
44
mod const_to_pat;
55
mod migration;
66

7+
use std::assert_matches::assert_matches;
78
use std::cmp::Ordering;
89
use std::sync::Arc;
910

@@ -21,7 +22,7 @@ use rustc_middle::ty::adjustment::{PatAdjust, PatAdjustment};
2122
use rustc_middle::ty::layout::IntegerExt;
2223
use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty, TyCtxt};
2324
use rustc_middle::{bug, span_bug};
24-
use rustc_span::{ErrorGuaranteed, Span};
25+
use rustc_span::ErrorGuaranteed;
2526
use tracing::{debug, instrument};
2627

2728
pub(crate) use self::check_match::check_match;
@@ -129,15 +130,20 @@ impl<'tcx> PatCtxt<'tcx> {
129130

130131
fn lower_pattern_range_endpoint(
131132
&mut self,
133+
pat: &'tcx hir::Pat<'tcx>, // Range pattern containing the endpoint
132134
expr: Option<&'tcx hir::PatExpr<'tcx>>,
133135
// Out-parameter collecting extra data to be reapplied by the caller
134136
ascriptions: &mut Vec<Ascription<'tcx>>,
135137
) -> Result<Option<PatRangeBoundary<'tcx>>, ErrorGuaranteed> {
138+
assert_matches!(pat.kind, hir::PatKind::Range(..));
139+
140+
// For partly-bounded ranges like `X..` or `..X`, an endpoint will be absent.
141+
// Return None in that case; the caller will use NegInfinity or PosInfinity instead.
136142
let Some(expr) = expr else { return Ok(None) };
137143

138144
// Lower the endpoint into a temporary `PatKind` that will then be
139145
// deconstructed to obtain the constant value and other data.
140-
let mut kind: PatKind<'tcx> = self.lower_pat_expr(expr, None);
146+
let mut kind: PatKind<'tcx> = self.lower_pat_expr(pat, expr);
141147

142148
// Unpeel any ascription or inline-const wrapper nodes.
143149
loop {
@@ -214,20 +220,23 @@ impl<'tcx> PatCtxt<'tcx> {
214220

215221
fn lower_pattern_range(
216222
&mut self,
223+
pat: &'tcx hir::Pat<'tcx>,
217224
lo_expr: Option<&'tcx hir::PatExpr<'tcx>>,
218225
hi_expr: Option<&'tcx hir::PatExpr<'tcx>>,
219226
end: RangeEnd,
220-
ty: Ty<'tcx>,
221-
span: Span,
222227
) -> Result<PatKind<'tcx>, ErrorGuaranteed> {
228+
let ty = self.typeck_results.node_type(pat.hir_id);
229+
let span = pat.span;
230+
223231
if lo_expr.is_none() && hi_expr.is_none() {
224232
let msg = "found twice-open range pattern (`..`) outside of error recovery";
225233
self.tcx.dcx().span_bug(span, msg);
226234
}
227235

228236
// Collect extra data while lowering the endpoints, to be reapplied later.
229237
let mut ascriptions = vec![];
230-
let mut lower_endpoint = |expr| self.lower_pattern_range_endpoint(expr, &mut ascriptions);
238+
let mut lower_endpoint =
239+
|expr| self.lower_pattern_range_endpoint(pat, expr, &mut ascriptions);
231240

232241
let lo = lower_endpoint(lo_expr)?.unwrap_or(PatRangeBoundary::NegInfinity);
233242
let hi = lower_endpoint(hi_expr)?.unwrap_or(PatRangeBoundary::PosInfinity);
@@ -299,12 +308,10 @@ impl<'tcx> PatCtxt<'tcx> {
299308

300309
hir::PatKind::Never => PatKind::Never,
301310

302-
hir::PatKind::Expr(value) => self.lower_pat_expr(value, Some(ty)),
311+
hir::PatKind::Expr(value) => self.lower_pat_expr(pat, value),
303312

304-
hir::PatKind::Range(ref lo_expr, ref hi_expr, end) => {
305-
let (lo_expr, hi_expr) = (lo_expr.as_deref(), hi_expr.as_deref());
306-
self.lower_pattern_range(lo_expr, hi_expr, end, ty, span)
307-
.unwrap_or_else(PatKind::Error)
313+
hir::PatKind::Range(lo_expr, hi_expr, end) => {
314+
self.lower_pattern_range(pat, lo_expr, hi_expr, end).unwrap_or_else(PatKind::Error)
308315
}
309316

310317
hir::PatKind::Deref(subpattern) => {
@@ -327,7 +334,7 @@ impl<'tcx> PatCtxt<'tcx> {
327334
},
328335

329336
hir::PatKind::Slice(prefix, slice, suffix) => {
330-
self.slice_or_array_pattern(pat.span, ty, prefix, slice, suffix)
337+
self.slice_or_array_pattern(pat, prefix, slice, suffix)
331338
}
332339

333340
hir::PatKind::Tuple(pats, ddpos) => {
@@ -389,7 +396,7 @@ impl<'tcx> PatCtxt<'tcx> {
389396
};
390397
let variant_def = adt_def.variant_of_res(res);
391398
let subpatterns = self.lower_tuple_subpats(pats, variant_def.fields.len(), ddpos);
392-
self.lower_variant_or_leaf(res, pat.hir_id, pat.span, ty, subpatterns)
399+
self.lower_variant_or_leaf(pat, None, res, subpatterns)
393400
}
394401

395402
hir::PatKind::Struct(ref qpath, fields, _) => {
@@ -406,7 +413,7 @@ impl<'tcx> PatCtxt<'tcx> {
406413
})
407414
.collect();
408415

409-
self.lower_variant_or_leaf(res, pat.hir_id, pat.span, ty, subpatterns)
416+
self.lower_variant_or_leaf(pat, None, res, subpatterns)
410417
}
411418

412419
hir::PatKind::Or(pats) => PatKind::Or { pats: self.lower_patterns(pats) },
@@ -445,12 +452,13 @@ impl<'tcx> PatCtxt<'tcx> {
445452

446453
fn slice_or_array_pattern(
447454
&mut self,
448-
span: Span,
449-
ty: Ty<'tcx>,
455+
pat: &'tcx hir::Pat<'tcx>,
450456
prefix: &'tcx [hir::Pat<'tcx>],
451457
slice: Option<&'tcx hir::Pat<'tcx>>,
452458
suffix: &'tcx [hir::Pat<'tcx>],
453459
) -> PatKind<'tcx> {
460+
let ty = self.typeck_results.node_type(pat.hir_id);
461+
454462
let prefix = self.lower_patterns(prefix);
455463
let slice = self.lower_opt_pattern(slice);
456464
let suffix = self.lower_patterns(suffix);
@@ -465,18 +473,32 @@ impl<'tcx> PatCtxt<'tcx> {
465473
assert!(len >= prefix.len() as u64 + suffix.len() as u64);
466474
PatKind::Array { prefix, slice, suffix }
467475
}
468-
_ => span_bug!(span, "bad slice pattern type {:?}", ty),
476+
_ => span_bug!(pat.span, "bad slice pattern type {ty:?}"),
469477
}
470478
}
471479

472480
fn lower_variant_or_leaf(
473481
&mut self,
482+
pat: &'tcx hir::Pat<'tcx>,
483+
expr: Option<&'tcx hir::PatExpr<'tcx>>,
474484
res: Res,
475-
hir_id: hir::HirId,
476-
span: Span,
477-
ty: Ty<'tcx>,
478485
subpatterns: Vec<FieldPat<'tcx>>,
479486
) -> PatKind<'tcx> {
487+
// Check whether the caller should have provided an `expr` for this pattern kind.
488+
assert_matches!(
489+
(pat.kind, expr),
490+
(hir::PatKind::Expr(..) | hir::PatKind::Range(..), Some(_))
491+
| (hir::PatKind::Struct(..) | hir::PatKind::TupleStruct(..), None)
492+
);
493+
494+
// Use the id/span of the `hir::PatExpr`, if provided.
495+
// Otherwise, use the id/span of the `hir::Pat`.
496+
let (hir_id, span) = match expr {
497+
Some(expr) => (expr.hir_id, expr.span),
498+
None => (pat.hir_id, pat.span),
499+
};
500+
let ty = self.typeck_results.node_type(hir_id);
501+
480502
let res = match res {
481503
Res::Def(DefKind::Ctor(CtorOf::Variant, ..), variant_ctor_id) => {
482504
let variant_id = self.tcx.parent(variant_ctor_id);
@@ -563,7 +585,16 @@ impl<'tcx> PatCtxt<'tcx> {
563585
/// it to `const_to_pat`. Any other path (like enum variants without fields)
564586
/// is converted to the corresponding pattern via `lower_variant_or_leaf`.
565587
#[instrument(skip(self), level = "debug")]
566-
fn lower_path(&mut self, qpath: &hir::QPath<'_>, id: hir::HirId, span: Span) -> Box<Pat<'tcx>> {
588+
fn lower_path(
589+
&mut self,
590+
pat: &'tcx hir::Pat<'tcx>, // Pattern that directly contains `expr`
591+
expr: &'tcx hir::PatExpr<'tcx>,
592+
qpath: &hir::QPath<'_>,
593+
) -> Box<Pat<'tcx>> {
594+
assert_matches!(pat.kind, hir::PatKind::Expr(..) | hir::PatKind::Range(..));
595+
596+
let id = expr.hir_id;
597+
let span = expr.span;
567598
let ty = self.typeck_results.node_type(id);
568599
let res = self.typeck_results.qpath_res(qpath, id);
569600

@@ -575,7 +606,7 @@ impl<'tcx> PatCtxt<'tcx> {
575606
_ => {
576607
// The path isn't the name of a constant, so it must actually
577608
// be a unit struct or unit variant (e.g. `Option::None`).
578-
let kind = self.lower_variant_or_leaf(res, id, span, ty, vec![]);
609+
let kind = self.lower_variant_or_leaf(pat, Some(expr), res, vec![]);
579610
return Box::new(Pat { span, ty, kind });
580611
}
581612
};
@@ -615,24 +646,26 @@ impl<'tcx> PatCtxt<'tcx> {
615646
/// - Literals, possibly negated (e.g. `-128u8`, `"hello"`)
616647
fn lower_pat_expr(
617648
&mut self,
649+
pat: &'tcx hir::Pat<'tcx>, // Pattern that directly contains `expr`
618650
expr: &'tcx hir::PatExpr<'tcx>,
619-
pat_ty: Option<Ty<'tcx>>,
620651
) -> PatKind<'tcx> {
652+
assert_matches!(pat.kind, hir::PatKind::Expr(..) | hir::PatKind::Range(..));
621653
match &expr.kind {
622-
hir::PatExprKind::Path(qpath) => self.lower_path(qpath, expr.hir_id, expr.span).kind,
654+
hir::PatExprKind::Path(qpath) => self.lower_path(pat, expr, qpath).kind,
623655
hir::PatExprKind::Lit { lit, negated } => {
624656
// We handle byte string literal patterns by using the pattern's type instead of the
625657
// literal's type in `const_to_pat`: if the literal `b"..."` matches on a slice reference,
626658
// the pattern's type will be `&[u8]` whereas the literal's type is `&[u8; 3]`; using the
627659
// pattern's type means we'll properly translate it to a slice reference pattern. This works
628660
// because slices and arrays have the same valtree representation.
629-
let ct_ty = match pat_ty {
630-
Some(pat_ty) => pat_ty,
631-
None => self.typeck_results.node_type(expr.hir_id),
632-
};
633-
let lit_input = LitToConstInput { lit: lit.node, ty: ct_ty, neg: *negated };
661+
//
662+
// Under `feature(deref_patterns)`, this adjustment can also convert string literal
663+
// patterns to `str`, and byte-string literal patterns to `[u8; N]` or `[u8]`.
664+
665+
let pat_ty = self.typeck_results.node_type(pat.hir_id);
666+
let lit_input = LitToConstInput { lit: lit.node, ty: pat_ty, neg: *negated };
634667
let constant = self.tcx.at(expr.span).lit_to_const(lit_input);
635-
self.const_to_pat(constant, ct_ty, expr.hir_id, lit.span).kind
668+
self.const_to_pat(constant, pat_ty, expr.hir_id, lit.span).kind
636669
}
637670
}
638671
}

0 commit comments

Comments
 (0)