about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/mod.rs81
1 files changed, 42 insertions, 39 deletions
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index 20a728d6d5b..0aa61152330 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -155,42 +155,41 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
     fn lower_pattern_range_endpoint(
         &mut self,
         expr: Option<&'tcx hir::PatExpr<'tcx>>,
-    ) -> Result<
-        (Option<PatRangeBoundary<'tcx>>, Option<Ascription<'tcx>>, Option<LocalDefId>),
-        ErrorGuaranteed,
-    > {
-        match expr {
-            None => Ok((None, None, None)),
-            Some(expr) => {
-                let (kind, ascr, inline_const) = match self.lower_lit(expr) {
-                    PatKind::ExpandedConstant { subpattern, def_id, is_inline: true } => {
-                        (subpattern.kind, None, def_id.as_local())
-                    }
-                    PatKind::ExpandedConstant { subpattern, is_inline: false, .. } => {
-                        (subpattern.kind, None, None)
-                    }
-                    PatKind::AscribeUserType { ascription, subpattern: box Pat { kind, .. } } => {
-                        (kind, Some(ascription), None)
-                    }
-                    kind => (kind, None, None),
-                };
-                let value = match kind {
-                    PatKind::Constant { value } => value,
-                    PatKind::ExpandedConstant { subpattern, .. }
-                        if let PatKind::Constant { value } = subpattern.kind =>
-                    {
-                        value
-                    }
-                    _ => {
-                        let msg = format!(
-                            "found bad range pattern endpoint `{expr:?}` outside of error recovery"
-                        );
-                        return Err(self.tcx.dcx().span_delayed_bug(expr.span, msg));
+        // Out-parameters collecting extra data to be reapplied by the caller
+        ascriptions: &mut Vec<Ascription<'tcx>>,
+        inline_consts: &mut Vec<LocalDefId>,
+    ) -> Result<Option<PatRangeBoundary<'tcx>>, ErrorGuaranteed> {
+        let Some(expr) = expr else { return Ok(None) };
+
+        // Lower the endpoint into a temporary `PatKind` that will then be
+        // deconstructed to obtain the constant value and other data.
+        let mut kind: PatKind<'tcx> = self.lower_lit(expr);
+
+        // Unpeel any ascription or inline-const wrapper nodes.
+        loop {
+            match kind {
+                PatKind::AscribeUserType { ascription, subpattern } => {
+                    ascriptions.push(ascription);
+                    kind = subpattern.kind;
+                }
+                PatKind::ExpandedConstant { is_inline, def_id, subpattern } => {
+                    if is_inline {
+                        inline_consts.extend(def_id.as_local());
                     }
-                };
-                Ok((Some(PatRangeBoundary::Finite(value)), ascr, inline_const))
+                    kind = subpattern.kind;
+                }
+                _ => break,
             }
         }
+
+        // The unpeeled kind should now be a constant, giving us the endpoint value.
+        let PatKind::Constant { value } = kind else {
+            let msg =
+                format!("found bad range pattern endpoint `{expr:?}` outside of error recovery");
+            return Err(self.tcx.dcx().span_delayed_bug(expr.span, msg));
+        };
+
+        Ok(Some(PatRangeBoundary::Finite(value)))
     }
 
     /// Overflowing literals are linted against in a late pass. This is mostly fine, except when we
@@ -253,11 +252,15 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
             self.tcx.dcx().span_bug(span, msg);
         }
 
-        let (lo, lo_ascr, lo_inline) = self.lower_pattern_range_endpoint(lo_expr)?;
-        let (hi, hi_ascr, hi_inline) = self.lower_pattern_range_endpoint(hi_expr)?;
+        // Collect extra data while lowering the endpoints, to be reapplied later.
+        let mut ascriptions = vec![];
+        let mut inline_consts = vec![];
+
+        let mut lower_endpoint =
+            |expr| self.lower_pattern_range_endpoint(expr, &mut ascriptions, &mut inline_consts);
 
-        let lo = lo.unwrap_or(PatRangeBoundary::NegInfinity);
-        let hi = hi.unwrap_or(PatRangeBoundary::PosInfinity);
+        let lo = lower_endpoint(lo_expr)?.unwrap_or(PatRangeBoundary::NegInfinity);
+        let hi = lower_endpoint(hi_expr)?.unwrap_or(PatRangeBoundary::PosInfinity);
 
         let cmp = lo.compare_with(hi, ty, self.tcx, self.typing_env);
         let mut kind = PatKind::Range(Box::new(PatRange { lo, hi, end, ty }));
@@ -298,13 +301,13 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
         // If we are handling a range with associated constants (e.g.
         // `Foo::<'a>::A..=Foo::B`), we need to put the ascriptions for the associated
         // constants somewhere. Have them on the range pattern.
-        for ascription in [lo_ascr, hi_ascr].into_iter().flatten() {
+        for ascription in ascriptions {
             kind = PatKind::AscribeUserType {
                 ascription,
                 subpattern: Box::new(Pat { span, ty, kind }),
             };
         }
-        for def in [lo_inline, hi_inline].into_iter().flatten() {
+        for def in inline_consts {
             kind = PatKind::ExpandedConstant {
                 def_id: def.to_def_id(),
                 is_inline: true,