Replace AscribeUserType and ExpandedConstant with per-node data

This commit is contained in:
Zalathar
2026-01-06 18:30:20 +11:00
parent bd77048303
commit 8516c64115
12 changed files with 68 additions and 211 deletions
-20
View File
@@ -778,11 +778,6 @@ pub enum PatKind<'tcx> {
/// A wildcard pattern: `_`.
Wild,
AscribeUserType {
ascription: Ascription<'tcx>,
subpattern: Box<Pat<'tcx>>,
},
/// `x`, `ref x`, `x @ P`, etc.
Binding {
name: Symbol,
@@ -847,21 +842,6 @@ pub enum PatKind<'tcx> {
value: ty::Value<'tcx>,
},
/// Wrapper node representing a named constant that was lowered to a pattern
/// using `const_to_pat`.
///
/// This is used by some diagnostics for non-exhaustive matches, to map
/// the pattern node back to the `DefId` of its original constant.
///
/// FIXME(#150498): Can we make this an `Option<DefId>` field on `Pat`
/// instead, so that non-diagnostic code can ignore it more easily?
ExpandedConstant {
/// [DefId] of the constant item.
def_id: DefId,
/// The pattern that the constant lowered to.
subpattern: Box<Pat<'tcx>>,
},
Range(Arc<PatRange<'tcx>>),
/// Matches against a slice, checking the length and extracting elements.
+2 -4
View File
@@ -269,11 +269,9 @@ pub(crate) fn for_each_immediate_subpat<'a, 'tcx>(
| PatKind::Never
| PatKind::Error(_) => {}
PatKind::AscribeUserType { subpattern, .. }
| PatKind::Binding { subpattern: Some(subpattern), .. }
PatKind::Binding { subpattern: Some(subpattern), .. }
| PatKind::Deref { subpattern }
| PatKind::DerefPattern { subpattern, .. }
| PatKind::ExpandedConstant { subpattern, .. } => callback(subpattern),
| PatKind::DerefPattern { subpattern, .. } => callback(subpattern),
PatKind::Variant { subpatterns, .. } | PatKind::Leaf { subpatterns } => {
for field_pat in subpatterns {
@@ -287,22 +287,14 @@ fn parse_let_statement(&mut self, stmt_id: StmtId) -> PResult<(LocalVarId, Ty<'t
self.parse_var(pattern)
}
fn parse_var(&mut self, mut pat: &Pat<'tcx>) -> PResult<(LocalVarId, Ty<'tcx>, Span)> {
// Make sure we throw out any `AscribeUserType` we find
loop {
match &pat.kind {
PatKind::Binding { var, ty, .. } => break Ok((*var, *ty, pat.span)),
PatKind::AscribeUserType { subpattern, .. } => {
pat = subpattern;
}
_ => {
break Err(ParseError {
span: pat.span,
item_description: format!("{:?}", pat.kind),
expected: "local".to_string(),
});
}
}
fn parse_var(&mut self, pat: &Pat<'tcx>) -> PResult<(LocalVarId, Ty<'tcx>, Span)> {
match &pat.kind {
PatKind::Binding { var, ty, .. } => Ok((*var, *ty, pat.span)),
_ => Err(ParseError {
span: pat.span,
item_description: format!("{:?}", pat.kind),
expected: "local".to_string(),
}),
}
}
@@ -144,11 +144,6 @@ fn parse_match(&self, arms: &[ArmId], span: Span) -> PResult<SwitchTargets> {
let arm = &self.thir[*arm];
let value = match arm.pattern.kind {
PatKind::Constant { value } => value,
PatKind::ExpandedConstant { ref subpattern, def_id: _ }
if let PatKind::Constant { value } = subpattern.kind =>
{
value
}
_ => {
return Err(ParseError {
span: arm.pattern.span,
@@ -133,6 +133,20 @@ pub(super) fn for_pattern(
}
let place = place_builder.try_to_place(cx);
// Apply any type ascriptions to the value at `match_pair.place`.
if let Some(place) = place
&& let Some(extra) = &pattern.extra
{
for &Ascription { ref annotation, variance } in &extra.ascriptions {
extra_data.ascriptions.push(super::Ascription {
source: place,
annotation: annotation.clone(),
variance,
});
}
}
let mut subpairs = Vec::new();
let testable_case = match pattern.kind {
PatKind::Missing | PatKind::Wild | PatKind::Error(_) => None,
@@ -195,28 +209,6 @@ pub(super) fn for_pattern(
Some(TestableCase::Constant { value, kind: const_kind })
}
PatKind::AscribeUserType {
ascription: Ascription { ref annotation, variance },
ref subpattern,
..
} => {
MatchPairTree::for_pattern(
place_builder,
subpattern,
cx,
&mut subpairs,
extra_data,
);
// Apply the type ascription to the value at `match_pair.place`
if let Some(source) = place {
let annotation = annotation.clone();
extra_data.ascriptions.push(super::Ascription { source, annotation, variance });
}
None
}
PatKind::Binding { mode, var, is_shorthand, ref subpattern, .. } => {
// In order to please the borrow checker, when lowering a pattern
// like `x @ subpat` we must establish any bindings in `subpat`
@@ -263,11 +255,6 @@ pub(super) fn for_pattern(
None
}
PatKind::ExpandedConstant { subpattern: ref pattern, .. } => {
MatchPairTree::for_pattern(place_builder, pattern, cx, &mut subpairs, extra_data);
None
}
PatKind::Array { ref prefix, ref slice, ref suffix } => {
cx.prefix_slice_suffix(
&mut subpairs,
@@ -576,7 +576,8 @@ pub(super) fn expr_into_pattern(
initializer_id: ExprId,
) -> BlockAnd<()> {
match irrefutable_pat.kind {
// Optimize the case of `let x = ...` to write directly into `x`
// Optimize `let x = ...` and `let x: T = ...` to write directly into `x`,
// and then require that `T == typeof(x)` if present.
PatKind::Binding { mode: BindingMode(ByRef::No, _), var, subpattern: None, .. } => {
let place = self.storage_live_binding(
block,
@@ -592,43 +593,14 @@ pub(super) fn expr_into_pattern(
let source_info = self.source_info(irrefutable_pat.span);
self.cfg.push_fake_read(block, source_info, FakeReadCause::ForLet(None), place);
self.schedule_drop_for_binding(var, irrefutable_pat.span, OutsideGuard);
block.unit()
}
let ascriptions: &[_] =
try { irrefutable_pat.extra.as_deref()?.ascriptions.as_slice() }
.unwrap_or_default();
for thir::Ascription { annotation, variance: _ } in ascriptions {
let ty_source_info = self.source_info(annotation.span);
// Optimize the case of `let x: T = ...` to write directly
// into `x` and then require that `T == typeof(x)`.
PatKind::AscribeUserType {
ref subpattern,
ascription: thir::Ascription { ref annotation, variance: _ },
} if let PatKind::Binding {
mode: BindingMode(ByRef::No, _),
var,
subpattern: None,
..
} = subpattern.kind =>
{
let place = self.storage_live_binding(
block,
var,
irrefutable_pat.span,
false,
OutsideGuard,
ScheduleDrops::Yes,
);
block = self.expr_into_dest(place, block, initializer_id).into_block();
// Inject a fake read, see comments on `FakeReadCause::ForLet`.
let pattern_source_info = self.source_info(irrefutable_pat.span);
let cause_let = FakeReadCause::ForLet(None);
self.cfg.push_fake_read(block, pattern_source_info, cause_let, place);
let ty_source_info = self.source_info(annotation.span);
let base = self.canonical_user_type_annotations.push(annotation.clone());
self.cfg.push(
block,
Statement::new(
let base = self.canonical_user_type_annotations.push(annotation.clone());
let stmt = Statement::new(
ty_source_info,
StatementKind::AscribeUserType(
Box::new((place, UserTypeProjection { base, projs: Vec::new() })),
@@ -648,8 +620,9 @@ pub(super) fn expr_into_pattern(
// `<expr>`.
ty::Invariant,
),
),
);
);
self.cfg.push(block, stmt);
}
self.schedule_drop_for_binding(var, irrefutable_pat.span, OutsideGuard);
block.unit()
@@ -884,9 +857,10 @@ fn visit_primary_bindings_special(
// Caution: Pushing user types here is load-bearing even for
// patterns containing no bindings, to ensure that the type ends
// up represented in MIR _somewhere_.
let user_tys = match pattern.kind {
PatKind::AscribeUserType { ref ascription, .. } => {
let base_user_tys = std::iter::once(ascription)
let user_tys = match pattern.extra.as_deref() {
Some(PatExtra { ascriptions, .. }) if !ascriptions.is_empty() => {
let base_user_tys = ascriptions
.iter()
.map(|thir::Ascription { annotation, variance: _ }| {
// Note that the variance doesn't apply here, as we are tracking the effect
// of user types on any bindings contained with subpattern.
@@ -943,15 +917,6 @@ fn visit_primary_bindings_special(
visit_subpat(self, subpattern, &ProjectedUserTypesNode::None, f);
}
PatKind::AscribeUserType { ref subpattern, ascription: _ } => {
// The ascription was already handled above, so just recurse to the subpattern.
visit_subpat(self, subpattern, user_tys, f)
}
PatKind::ExpandedConstant { ref subpattern, .. } => {
visit_subpat(self, subpattern, user_tys, f)
}
PatKind::Leaf { ref subpatterns } => {
for subpattern in subpatterns {
let subpattern_user_tys = user_tys.leaf(subpattern.field);
@@ -342,8 +342,6 @@ fn visit_pat(&mut self, pat: &'a Pat<'tcx>) {
PatKind::Wild |
// these just wrap other patterns, which we recurse on below.
PatKind::Or { .. } |
PatKind::ExpandedConstant { .. } |
PatKind::AscribeUserType { .. } |
PatKind::Error(_) => {}
}
};
@@ -680,20 +680,13 @@ fn check_binding_is_irrefutable(
let mut interpreted_as_const = None;
let mut interpreted_as_const_sugg = None;
// These next few matches want to peek through `AscribeUserType` to see
// the underlying pattern.
let mut unpeeled_pat = pat;
while let PatKind::AscribeUserType { ref subpattern, .. } = unpeeled_pat.kind {
unpeeled_pat = subpattern;
}
if let Some(def_id) = is_const_pat_that_looks_like_binding(self.tcx, unpeeled_pat) {
if let Some(def_id) = is_const_pat_that_looks_like_binding(self.tcx, pat) {
let span = self.tcx.def_span(def_id);
let variable = self.tcx.item_name(def_id).to_string();
// When we encounter a constant as the binding name, point at the `const` definition.
interpreted_as_const = Some(InterpretedAsConst { span, variable: variable.clone() });
interpreted_as_const_sugg = Some(InterpretedAsConstSugg { span: pat.span, variable });
} else if let PatKind::Constant { .. } = unpeeled_pat.kind
} else if let PatKind::Constant { .. } = pat.kind
&& let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(pat.span)
{
// If the pattern to match is an integer literal:
@@ -1213,7 +1206,7 @@ fn is_const_pat_that_looks_like_binding<'tcx>(tcx: TyCtxt<'tcx>, pat: &Pat<'tcx>
// The pattern must be a named constant, and the name that appears in
// the pattern's source text must resemble a plain identifier without any
// `::` namespace separators or other non-identifier characters.
if let PatKind::ExpandedConstant { def_id, .. } = pat.kind
if let Some(def_id) = try { pat.extra.as_deref()?.expanded_const? }
&& matches!(tcx.def_kind(def_id), DefKind::Const)
&& let Ok(snippet) = tcx.sess.source_map().span_to_snippet(pat.span)
&& snippet.chars().all(|c| c.is_alphanumeric() || c == '_')
@@ -186,14 +186,9 @@ fn unevaluated_to_pat(
}
}
// Wrap the pattern in a marker node to indicate that it is the result of lowering a
// Mark the pattern to indicate that it is the result of lowering a named
// constant. This is used for diagnostics.
thir_pat = Box::new(Pat {
ty: thir_pat.ty,
span: thir_pat.span,
kind: PatKind::ExpandedConstant { def_id: uv.def, subpattern: thir_pat },
extra: None,
});
thir_pat.extra.get_or_insert_default().expanded_const = Some(uv.def);
thir_pat
}
@@ -71,15 +71,11 @@ pub(super) fn pat_from_hir<'tcx>(
span: let_stmt_type.span,
inferred_ty: typeck_results.node_type(let_stmt_type.hir_id),
};
thir_pat = Box::new(Pat {
ty: thir_pat.ty,
span: thir_pat.span,
kind: PatKind::AscribeUserType {
ascription: Ascription { annotation, variance: ty::Covariant },
subpattern: thir_pat,
},
extra: None,
});
thir_pat
.extra
.get_or_insert_default()
.ascriptions
.push(Ascription { annotation, variance: ty::Covariant });
}
if let Some(m) = pcx.rust_2024_migration {
@@ -171,23 +167,11 @@ fn lower_pattern_range_endpoint(
// Lower the endpoint into a temporary `thir::Pat` that will then be
// deconstructed to obtain the constant value and other data.
let endpoint_pat: Box<Pat<'tcx>> = self.lower_pat_expr(pat, expr);
let box Pat { mut kind, .. } = endpoint_pat;
let box Pat { ref kind, extra, .. } = endpoint_pat;
// Unpeel any ascription or inline-const wrapper nodes.
loop {
match kind {
PatKind::AscribeUserType { ascription, subpattern } => {
ascriptions.push(ascription);
kind = subpattern.kind;
}
PatKind::ExpandedConstant { def_id: _, subpattern } => {
// Expanded-constant nodes are currently only needed by
// diagnostics that don't apply to range patterns, so we
// can just discard them here.
kind = subpattern.kind;
}
_ => break,
}
// Preserve any ascriptions from endpoint constants.
if let Some(extra) = extra {
ascriptions.extend(extra.ascriptions);
}
// The unpeeled kind should now be a constant, giving us the endpoint value.
@@ -313,15 +297,8 @@ fn lower_pattern_range(
// 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 ascriptions {
thir_pat = Box::new(Pat {
ty,
span,
kind: PatKind::AscribeUserType { ascription, subpattern: thir_pat },
extra: None,
});
}
// `PatKind::ExpandedConstant` wrappers from range endpoints used to
thir_pat.extra.get_or_insert_default().ascriptions.extend(ascriptions);
// IDs of expanded constants from range endpoints used to
// also be preserved here, but that was only needed for unsafeck of
// inline `const { .. }` patterns, which were removed by
// <https://github.com/rust-lang/rust/pull/138492>.
@@ -619,15 +596,11 @@ fn lower_variant_or_leaf(
span,
inferred_ty: self.typeck_results.node_type(hir_id),
};
thir_pat = Box::new(Pat {
ty,
span,
kind: PatKind::AscribeUserType {
subpattern: thir_pat,
ascription: Ascription { annotation, variance: ty::Covariant },
},
extra: None,
});
thir_pat
.extra
.get_or_insert_default()
.ascriptions
.push(Ascription { annotation, variance: ty::Covariant });
}
thir_pat
@@ -684,16 +657,13 @@ fn lower_path(
span,
inferred_ty: self.typeck_results.node_type(id),
};
let kind = PatKind::AscribeUserType {
subpattern: pattern,
ascription: Ascription {
annotation,
// Note that we use `Contravariant` here. See the
// `variance` field documentation for details.
variance: ty::Contravariant,
},
};
pattern = Box::new(Pat { span, kind, ty, extra: None });
// Note that we use `Contravariant` here. See the
// `variance` field documentation for details.
pattern
.extra
.get_or_insert_default()
.ascriptions
.push(Ascription { annotation, variance: ty::Contravariant });
}
pattern
@@ -725,13 +725,6 @@ fn print_pat_kind(&mut self, pat_kind: &PatKind<'tcx>, depth_lvl: usize) {
PatKind::Never => {
print_indented!(self, "Never", depth_lvl + 1);
}
PatKind::AscribeUserType { ascription, subpattern } => {
print_indented!(self, "AscribeUserType: {", depth_lvl + 1);
print_indented!(self, format!("ascription: {:?}", ascription), depth_lvl + 2);
print_indented!(self, "subpattern: ", depth_lvl + 2);
self.print_pat(subpattern, depth_lvl + 3);
print_indented!(self, "}", depth_lvl + 1);
}
PatKind::Binding { name, mode, var, ty, subpattern, is_primary, is_shorthand } => {
print_indented!(self, "Binding {", depth_lvl + 1);
print_indented!(self, format!("name: {:?}", name), depth_lvl + 2);
@@ -796,13 +789,6 @@ fn print_pat_kind(&mut self, pat_kind: &PatKind<'tcx>, depth_lvl: usize) {
print_indented!(self, format!("value: {}", value), depth_lvl + 2);
print_indented!(self, "}", depth_lvl + 1);
}
PatKind::ExpandedConstant { def_id, subpattern } => {
print_indented!(self, "ExpandedConstant {", depth_lvl + 1);
print_indented!(self, format!("def_id: {def_id:?}"), depth_lvl + 2);
print_indented!(self, "subpattern:", depth_lvl + 2);
self.print_pat(subpattern, depth_lvl + 2);
print_indented!(self, "}", depth_lvl + 1);
}
PatKind::Range(pat_range) => {
print_indented!(self, format!("Range ( {:?} )", pat_range), depth_lvl + 1);
}
@@ -462,8 +462,6 @@ pub fn lower_pat(&self, pat: &'p Pat<'tcx>) -> DeconstructedPat<'p, 'tcx> {
let arity;
let fields: Vec<_>;
match &pat.kind {
PatKind::AscribeUserType { subpattern, .. }
| PatKind::ExpandedConstant { subpattern, .. } => return self.lower_pat(subpattern),
PatKind::Binding { subpattern: Some(subpat), .. } => return self.lower_pat(subpat),
PatKind::Missing | PatKind::Binding { subpattern: None, .. } | PatKind::Wild => {
ctor = Wildcard;