Skip to content

Commit 9955b76

Browse files
authored
Rollup merge of #139108 - Nadrieril:simplify-expandedconstant, r=oli-obk
Simplify `thir::PatKind::ExpandedConstant` I made it a bit less ad-hoc. In particular, I removed `is_inline: bool` that was just caching the output of `tcx.def_kind(def_id)`. This makes inline consts a tiny bit less special in patterns. r? `@oli-obk` cc `@Zalathar`
2 parents 82df622 + d912c03 commit 9955b76

File tree

8 files changed

+95
-124
lines changed

8 files changed

+95
-124
lines changed

compiler/rustc_middle/src/thir.rs

+8-14
Original file line numberDiff line numberDiff line change
@@ -815,23 +815,17 @@ pub enum PatKind<'tcx> {
815815
},
816816

817817
/// Pattern obtained by converting a constant (inline or named) to its pattern
818-
/// representation using `const_to_pat`.
818+
/// representation using `const_to_pat`. This is used for unsafety checking.
819819
ExpandedConstant {
820-
/// [DefId] of the constant, we need this so that we have a
821-
/// reference that can be used by unsafety checking to visit nested
822-
/// unevaluated constants and for diagnostics. If the `DefId` doesn't
823-
/// correspond to a local crate, it points at the `const` item.
820+
/// [DefId] of the constant item.
824821
def_id: DefId,
825-
/// If `false`, then `def_id` points at a `const` item, otherwise it
826-
/// corresponds to a local inline const.
827-
is_inline: bool,
828-
/// If the inline constant is used in a range pattern, this subpattern
829-
/// represents the range (if both ends are inline constants, there will
830-
/// be multiple InlineConstant wrappers).
822+
/// The pattern that the constant lowered to.
831823
///
832-
/// Otherwise, the actual pattern that the constant lowered to. As with
833-
/// other constants, inline constants are matched structurally where
834-
/// possible.
824+
/// HACK: we need to keep the `DefId` of inline constants around for unsafety checking;
825+
/// therefore when a range pattern contains inline constants, we re-wrap the range pattern
826+
/// with the `ExpandedConstant` nodes that correspond to the range endpoints. Hence
827+
/// `subpattern` may actually be a range pattern, and `def_id` be the constant for one of
828+
/// its endpoints.
835829
subpattern: Box<Pat<'tcx>>,
836830
},
837831

compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ impl<'a, 'tcx> ParseCtxt<'a, 'tcx> {
145145
let arm = &self.thir[*arm];
146146
let value = match arm.pattern.kind {
147147
PatKind::Constant { value } => value,
148-
PatKind::ExpandedConstant { ref subpattern, def_id: _, is_inline: false }
148+
PatKind::ExpandedConstant { ref subpattern, def_id: _ }
149149
if let PatKind::Constant { value } = subpattern.kind =>
150150
{
151151
value

compiler/rustc_mir_build/src/builder/matches/match_pair.rs

+1-30
Original file line numberDiff line numberDiff line change
@@ -201,39 +201,10 @@ impl<'tcx> MatchPairTree<'tcx> {
201201
None
202202
}
203203

204-
PatKind::ExpandedConstant { subpattern: ref pattern, def_id: _, is_inline: false } => {
204+
PatKind::ExpandedConstant { subpattern: ref pattern, .. } => {
205205
MatchPairTree::for_pattern(place_builder, pattern, cx, &mut subpairs, extra_data);
206206
None
207207
}
208-
PatKind::ExpandedConstant { subpattern: ref pattern, def_id, is_inline: true } => {
209-
MatchPairTree::for_pattern(place_builder, pattern, cx, &mut subpairs, extra_data);
210-
211-
// Apply a type ascription for the inline constant to the value at `match_pair.place`
212-
if let Some(source) = place {
213-
let span = pattern.span;
214-
let parent_id = cx.tcx.typeck_root_def_id(cx.def_id.to_def_id());
215-
let args = ty::InlineConstArgs::new(
216-
cx.tcx,
217-
ty::InlineConstArgsParts {
218-
parent_args: ty::GenericArgs::identity_for_item(cx.tcx, parent_id),
219-
ty: cx.infcx.next_ty_var(span),
220-
},
221-
)
222-
.args;
223-
let user_ty = cx.infcx.canonicalize_user_type_annotation(ty::UserType::new(
224-
ty::UserTypeKind::TypeOf(def_id, ty::UserArgs { args, user_self_ty: None }),
225-
));
226-
let annotation = ty::CanonicalUserTypeAnnotation {
227-
inferred_ty: pattern.ty,
228-
span,
229-
user_ty: Box::new(user_ty),
230-
};
231-
let variance = ty::Contravariant;
232-
extra_data.ascriptions.push(super::Ascription { annotation, source, variance });
233-
}
234-
235-
None
236-
}
237208

238209
PatKind::Array { ref prefix, ref slice, ref suffix } => {
239210
cx.prefix_slice_suffix(

compiler/rustc_mir_build/src/check_unsafety.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -404,9 +404,9 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
404404
visit::walk_pat(self, pat);
405405
self.inside_adt = old_inside_adt;
406406
}
407-
PatKind::ExpandedConstant { def_id, is_inline, .. } => {
407+
PatKind::ExpandedConstant { def_id, .. } => {
408408
if let Some(def) = def_id.as_local()
409-
&& *is_inline
409+
&& matches!(self.tcx.def_kind(def_id), DefKind::InlineConst)
410410
{
411411
self.visit_inner_body(def);
412412
}

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

+3-2
Original file line numberDiff line numberDiff line change
@@ -676,7 +676,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
676676
unpeeled_pat = subpattern;
677677
}
678678

679-
if let PatKind::ExpandedConstant { def_id, is_inline: false, .. } = unpeeled_pat.kind
679+
if let PatKind::ExpandedConstant { def_id, .. } = unpeeled_pat.kind
680680
&& let DefKind::Const = self.tcx.def_kind(def_id)
681681
&& let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(pat.span)
682682
// We filter out paths with multiple path::segments.
@@ -1296,7 +1296,8 @@ fn report_non_exhaustive_match<'p, 'tcx>(
12961296

12971297
for &arm in arms {
12981298
let arm = &thir.arms[arm];
1299-
if let PatKind::ExpandedConstant { def_id, is_inline: false, .. } = arm.pattern.kind
1299+
if let PatKind::ExpandedConstant { def_id, .. } = arm.pattern.kind
1300+
&& !matches!(cx.tcx.def_kind(def_id), DefKind::InlineConst)
13001301
&& let Ok(snippet) = cx.tcx.sess.source_map().span_to_snippet(arm.pattern.span)
13011302
// We filter out paths with multiple path::segments.
13021303
&& snippet.chars().all(|c| c.is_alphanumeric() || c == '_')

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

+4-1
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,10 @@ impl<'tcx> ConstToPat<'tcx> {
182182
}
183183
}
184184

185-
inlined_const_as_pat
185+
// Wrap the pattern in a marker node to indicate that it is the result of lowering a
186+
// constant. This is used for diagnostics, and for unsafety checking of inline const blocks.
187+
let kind = PatKind::ExpandedConstant { subpattern: inlined_const_as_pat, def_id: uv.def };
188+
Box::new(Pat { kind, ty, span: self.span })
186189
}
187190

188191
fn field_pats(

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

+75-72
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,15 @@ use rustc_hir::def::{CtorOf, DefKind, Res};
1313
use rustc_hir::pat_util::EnumerateAndAdjustIterator;
1414
use rustc_hir::{self as hir, LangItem, RangeEnd};
1515
use rustc_index::Idx;
16+
use rustc_infer::infer::TyCtxtInferExt;
1617
use rustc_middle::mir::interpret::LitToConstInput;
1718
use rustc_middle::thir::{
1819
Ascription, FieldPat, LocalVarId, Pat, PatKind, PatRange, PatRangeBoundary,
1920
};
2021
use rustc_middle::ty::layout::IntegerExt;
21-
use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty, TyCtxt, TypeVisitableExt};
22+
use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty, TyCtxt, TypingMode};
2223
use rustc_middle::{bug, span_bug};
23-
use rustc_span::def_id::LocalDefId;
24+
use rustc_span::def_id::DefId;
2425
use rustc_span::{ErrorGuaranteed, Span};
2526
use tracing::{debug, instrument};
2627

@@ -124,7 +125,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
124125
expr: Option<&'tcx hir::PatExpr<'tcx>>,
125126
// Out-parameters collecting extra data to be reapplied by the caller
126127
ascriptions: &mut Vec<Ascription<'tcx>>,
127-
inline_consts: &mut Vec<LocalDefId>,
128+
expanded_consts: &mut Vec<DefId>,
128129
) -> Result<Option<PatRangeBoundary<'tcx>>, ErrorGuaranteed> {
129130
let Some(expr) = expr else { return Ok(None) };
130131

@@ -139,10 +140,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
139140
ascriptions.push(ascription);
140141
kind = subpattern.kind;
141142
}
142-
PatKind::ExpandedConstant { is_inline, def_id, subpattern } => {
143-
if is_inline {
144-
inline_consts.extend(def_id.as_local());
145-
}
143+
PatKind::ExpandedConstant { def_id, subpattern } => {
144+
expanded_consts.push(def_id);
146145
kind = subpattern.kind;
147146
}
148147
_ => break,
@@ -221,10 +220,10 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
221220

222221
// Collect extra data while lowering the endpoints, to be reapplied later.
223222
let mut ascriptions = vec![];
224-
let mut inline_consts = vec![];
223+
let mut expanded_consts = vec![];
225224

226225
let mut lower_endpoint =
227-
|expr| self.lower_pattern_range_endpoint(expr, &mut ascriptions, &mut inline_consts);
226+
|expr| self.lower_pattern_range_endpoint(expr, &mut ascriptions, &mut expanded_consts);
228227

229228
let lo = lower_endpoint(lo_expr)?.unwrap_or(PatRangeBoundary::NegInfinity);
230229
let hi = lower_endpoint(hi_expr)?.unwrap_or(PatRangeBoundary::PosInfinity);
@@ -269,17 +268,12 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
269268
// `Foo::<'a>::A..=Foo::B`), we need to put the ascriptions for the associated
270269
// constants somewhere. Have them on the range pattern.
271270
for ascription in ascriptions {
272-
kind = PatKind::AscribeUserType {
273-
ascription,
274-
subpattern: Box::new(Pat { span, ty, kind }),
275-
};
271+
let subpattern = Box::new(Pat { span, ty, kind });
272+
kind = PatKind::AscribeUserType { ascription, subpattern };
276273
}
277-
for def in inline_consts {
278-
kind = PatKind::ExpandedConstant {
279-
def_id: def.to_def_id(),
280-
is_inline: true,
281-
subpattern: Box::new(Pat { span, ty, kind }),
282-
};
274+
for def_id in expanded_consts {
275+
let subpattern = Box::new(Pat { span, ty, kind });
276+
kind = PatKind::ExpandedConstant { def_id, subpattern };
283277
}
284278
Ok(kind)
285279
}
@@ -569,15 +563,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
569563
// Lower the named constant to a THIR pattern.
570564
let args = self.typeck_results.node_args(id);
571565
let c = ty::Const::new_unevaluated(self.tcx, ty::UnevaluatedConst { def: def_id, args });
572-
let subpattern = self.const_to_pat(c, ty, id, span);
573-
574-
// Wrap the pattern in a marker node to indicate that it is the result
575-
// of lowering a named constant. This marker is used for improved
576-
// diagnostics in some situations, but has no effect at runtime.
577-
let mut pattern = {
578-
let kind = PatKind::ExpandedConstant { subpattern, def_id, is_inline: false };
579-
Box::new(Pat { span, ty, kind })
580-
};
566+
let mut pattern = self.const_to_pat(c, ty, id, span);
581567

582568
// If this is an associated constant with an explicit user-written
583569
// type, add an ascription node (e.g. `<Foo<'a> as MyTrait>::CONST`).
@@ -614,18 +600,37 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
614600
let ty = tcx.typeck(def_id).node_type(block.hir_id);
615601

616602
let typeck_root_def_id = tcx.typeck_root_def_id(def_id.to_def_id());
617-
let parent_args =
618-
tcx.erase_regions(ty::GenericArgs::identity_for_item(tcx, typeck_root_def_id));
603+
let parent_args = ty::GenericArgs::identity_for_item(tcx, typeck_root_def_id);
619604
let args = ty::InlineConstArgs::new(tcx, ty::InlineConstArgsParts { parent_args, ty }).args;
620605

621-
debug_assert!(!args.has_free_regions());
622-
623606
let ct = ty::UnevaluatedConst { def: def_id.to_def_id(), args };
624-
let subpattern = self.const_to_pat(ty::Const::new_unevaluated(self.tcx, ct), ty, id, span);
625-
626-
// Wrap the pattern in a marker node to indicate that it is the result
627-
// of lowering an inline const block.
628-
PatKind::ExpandedConstant { subpattern, def_id: def_id.to_def_id(), is_inline: true }
607+
let c = ty::Const::new_unevaluated(self.tcx, ct);
608+
let pattern = self.const_to_pat(c, ty, id, span);
609+
610+
// Apply a type ascription for the inline constant.
611+
let annotation = {
612+
let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
613+
let args = ty::InlineConstArgs::new(
614+
tcx,
615+
ty::InlineConstArgsParts { parent_args, ty: infcx.next_ty_var(span) },
616+
)
617+
.args;
618+
infcx.canonicalize_user_type_annotation(ty::UserType::new(ty::UserTypeKind::TypeOf(
619+
def_id.to_def_id(),
620+
ty::UserArgs { args, user_self_ty: None },
621+
)))
622+
};
623+
let annotation =
624+
CanonicalUserTypeAnnotation { user_ty: Box::new(annotation), span, inferred_ty: ty };
625+
PatKind::AscribeUserType {
626+
subpattern: pattern,
627+
ascription: Ascription {
628+
annotation,
629+
// Note that we use `Contravariant` here. See the `variance` field documentation
630+
// for details.
631+
variance: ty::Contravariant,
632+
},
633+
}
629634
}
630635

631636
/// Lowers the kinds of "expression" that can appear in a HIR pattern:
@@ -637,43 +642,41 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
637642
expr: &'tcx hir::PatExpr<'tcx>,
638643
pat_ty: Option<Ty<'tcx>>,
639644
) -> PatKind<'tcx> {
640-
let (lit, neg) = match &expr.kind {
641-
hir::PatExprKind::Path(qpath) => {
642-
return self.lower_path(qpath, expr.hir_id, expr.span).kind;
643-
}
645+
match &expr.kind {
646+
hir::PatExprKind::Path(qpath) => self.lower_path(qpath, expr.hir_id, expr.span).kind,
644647
hir::PatExprKind::ConstBlock(anon_const) => {
645-
return self.lower_inline_const(anon_const, expr.hir_id, expr.span);
648+
self.lower_inline_const(anon_const, expr.hir_id, expr.span)
646649
}
647-
hir::PatExprKind::Lit { lit, negated } => (lit, *negated),
648-
};
649-
650-
// We handle byte string literal patterns by using the pattern's type instead of the
651-
// literal's type in `const_to_pat`: if the literal `b"..."` matches on a slice reference,
652-
// the pattern's type will be `&[u8]` whereas the literal's type is `&[u8; 3]`; using the
653-
// pattern's type means we'll properly translate it to a slice reference pattern. This works
654-
// because slices and arrays have the same valtree representation.
655-
// HACK: As an exception, use the literal's type if `pat_ty` is `String`; this can happen if
656-
// `string_deref_patterns` is enabled. There's a special case for that when lowering to MIR.
657-
// FIXME(deref_patterns): This hack won't be necessary once `string_deref_patterns` is
658-
// superseded by a more general implementation of deref patterns.
659-
let ct_ty = match pat_ty {
660-
Some(pat_ty)
661-
if let ty::Adt(def, _) = *pat_ty.kind()
662-
&& self.tcx.is_lang_item(def.did(), LangItem::String) =>
663-
{
664-
if !self.tcx.features().string_deref_patterns() {
665-
span_bug!(
666-
expr.span,
667-
"matching on `String` went through without enabling string_deref_patterns"
668-
);
669-
}
670-
self.typeck_results.node_type(expr.hir_id)
650+
hir::PatExprKind::Lit { lit, negated } => {
651+
// We handle byte string literal patterns by using the pattern's type instead of the
652+
// literal's type in `const_to_pat`: if the literal `b"..."` matches on a slice reference,
653+
// the pattern's type will be `&[u8]` whereas the literal's type is `&[u8; 3]`; using the
654+
// pattern's type means we'll properly translate it to a slice reference pattern. This works
655+
// because slices and arrays have the same valtree representation.
656+
// HACK: As an exception, use the literal's type if `pat_ty` is `String`; this can happen if
657+
// `string_deref_patterns` is enabled. There's a special case for that when lowering to MIR.
658+
// FIXME(deref_patterns): This hack won't be necessary once `string_deref_patterns` is
659+
// superseded by a more general implementation of deref patterns.
660+
let ct_ty = match pat_ty {
661+
Some(pat_ty)
662+
if let ty::Adt(def, _) = *pat_ty.kind()
663+
&& self.tcx.is_lang_item(def.did(), LangItem::String) =>
664+
{
665+
if !self.tcx.features().string_deref_patterns() {
666+
span_bug!(
667+
expr.span,
668+
"matching on `String` went through without enabling string_deref_patterns"
669+
);
670+
}
671+
self.typeck_results.node_type(expr.hir_id)
672+
}
673+
Some(pat_ty) => pat_ty,
674+
None => self.typeck_results.node_type(expr.hir_id),
675+
};
676+
let lit_input = LitToConstInput { lit: &lit.node, ty: ct_ty, neg: *negated };
677+
let constant = self.tcx.at(expr.span).lit_to_const(lit_input);
678+
self.const_to_pat(constant, ct_ty, expr.hir_id, lit.span).kind
671679
}
672-
Some(pat_ty) => pat_ty,
673-
None => self.typeck_results.node_type(expr.hir_id),
674-
};
675-
let lit_input = LitToConstInput { lit: &lit.node, ty: ct_ty, neg };
676-
let constant = self.tcx.at(expr.span).lit_to_const(lit_input);
677-
self.const_to_pat(constant, ct_ty, expr.hir_id, lit.span).kind
680+
}
678681
}
679682
}

compiler/rustc_mir_build/src/thir/print.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -741,10 +741,9 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> {
741741
print_indented!(self, format!("value: {:?}", value), depth_lvl + 2);
742742
print_indented!(self, "}", depth_lvl + 1);
743743
}
744-
PatKind::ExpandedConstant { def_id, is_inline, subpattern } => {
744+
PatKind::ExpandedConstant { def_id, subpattern } => {
745745
print_indented!(self, "ExpandedConstant {", depth_lvl + 1);
746746
print_indented!(self, format!("def_id: {def_id:?}"), depth_lvl + 2);
747-
print_indented!(self, format!("is_inline: {is_inline:?}"), depth_lvl + 2);
748747
print_indented!(self, "subpattern:", depth_lvl + 2);
749748
self.print_pat(subpattern, depth_lvl + 2);
750749
print_indented!(self, "}", depth_lvl + 1);

0 commit comments

Comments
 (0)