Skip to content

Commit b07fa76

Browse files
authored
Rollup merge of #136284 - oli-obk:push-zsxuwnzmonnl, r=lcnr
Allow using named consts in pattern types This required a refactoring first: I had to stop using `hir::Pat`in `hir::TyKind::Pat` and instead create a separate `TyPat` that has `ConstArg` for range ends instead of `PatExpr`. Within the type system we should be using `ConstArg` for all constants, as otherwise we'd be maintaining two separate const systems that could diverge. The big advantage of this PR is that we now inherit all the rules from const generics and don't have a separate system. While this makes things harder for users (const generic rules wrt what is allowed in those consts), it also means we don't accidentally allow some things like referring to assoc consts or doing math on generic consts.
2 parents a8ecb79 + fbcaa9b commit b07fa76

33 files changed

+474
-201
lines changed

compiler/rustc_ast_lowering/src/index.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -412,8 +412,12 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
412412
});
413413
}
414414

415-
fn visit_pattern_type_pattern(&mut self, p: &'hir hir::Pat<'hir>) {
416-
self.visit_pat(p)
415+
fn visit_pattern_type_pattern(&mut self, pat: &'hir hir::TyPat<'hir>) {
416+
self.insert(pat.span, pat.hir_id, Node::TyPat(pat));
417+
418+
self.with_parent(pat.hir_id, |this| {
419+
intravisit::walk_ty_pat(this, pat);
420+
});
417421
}
418422

419423
fn visit_precise_capturing_arg(

compiler/rustc_ast_lowering/src/lib.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -1377,7 +1377,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
13771377
}
13781378
}
13791379
}
1380-
TyKind::Pat(ty, pat) => hir::TyKind::Pat(self.lower_ty(ty, itctx), self.lower_pat(pat)),
1380+
TyKind::Pat(ty, pat) => {
1381+
hir::TyKind::Pat(self.lower_ty(ty, itctx), self.lower_ty_pat(pat))
1382+
}
13811383
TyKind::MacCall(_) => {
13821384
span_bug!(t.span, "`TyKind::MacCall` should have been expanded by now")
13831385
}

compiler/rustc_ast_lowering/src/pat.rs

+79-2
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@ use rustc_ast::ptr::P;
44
use rustc_ast::*;
55
use rustc_data_structures::stack::ensure_sufficient_stack;
66
use rustc_hir as hir;
7-
use rustc_hir::def::Res;
7+
use rustc_hir::def::{DefKind, Res};
88
use rustc_middle::span_bug;
99
use rustc_span::source_map::{Spanned, respan};
10-
use rustc_span::{Ident, Span};
10+
use rustc_span::{Ident, Span, kw};
1111

1212
use super::errors::{
1313
ArbitraryExpressionInPattern, ExtraDoubleDot, MisplacedDoubleDot, SubTupleBinding,
@@ -429,4 +429,81 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
429429
};
430430
self.arena.alloc(hir::PatExpr { hir_id: self.lower_node_id(expr.id), span, kind })
431431
}
432+
433+
pub(crate) fn lower_ty_pat(&mut self, pattern: &Pat) -> &'hir hir::TyPat<'hir> {
434+
self.arena.alloc(self.lower_ty_pat_mut(pattern))
435+
}
436+
437+
fn lower_ty_pat_mut(&mut self, mut pattern: &Pat) -> hir::TyPat<'hir> {
438+
// loop here to avoid recursion
439+
let pat_hir_id = self.lower_node_id(pattern.id);
440+
let node = loop {
441+
match &pattern.kind {
442+
PatKind::Range(e1, e2, Spanned { node: end, .. }) => {
443+
// FIXME(pattern_types): remove this closure and call `lower_const_arg` instead.
444+
// That requires first modifying the AST to have const args here.
445+
let mut lower_expr = |e: &Expr| -> &_ {
446+
if let ExprKind::Path(None, path) = &e.kind
447+
&& let Some(res) = self
448+
.resolver
449+
.get_partial_res(e.id)
450+
.and_then(|partial_res| partial_res.full_res())
451+
{
452+
self.lower_const_path_to_const_arg(path, res, e.id, e.span)
453+
} else {
454+
let node_id = self.next_node_id();
455+
let def_id = self.create_def(
456+
self.current_hir_id_owner.def_id,
457+
node_id,
458+
kw::Empty,
459+
DefKind::AnonConst,
460+
e.span,
461+
);
462+
let hir_id = self.lower_node_id(node_id);
463+
let ac = self.arena.alloc(hir::AnonConst {
464+
def_id,
465+
hir_id,
466+
body: self.lower_const_body(pattern.span, Some(e)),
467+
span: self.lower_span(pattern.span),
468+
});
469+
self.arena.alloc(hir::ConstArg {
470+
hir_id: self.next_id(),
471+
kind: hir::ConstArgKind::Anon(ac),
472+
})
473+
}
474+
};
475+
break hir::TyPatKind::Range(
476+
e1.as_deref().map(|e| lower_expr(e)),
477+
e2.as_deref().map(|e| lower_expr(e)),
478+
self.lower_range_end(end, e2.is_some()),
479+
);
480+
}
481+
// return inner to be processed in next loop
482+
PatKind::Paren(inner) => pattern = inner,
483+
PatKind::MacCall(_) => panic!("{:?} shouldn't exist here", pattern.span),
484+
PatKind::Err(guar) => break hir::TyPatKind::Err(*guar),
485+
PatKind::Deref(..)
486+
| PatKind::Box(..)
487+
| PatKind::Or(..)
488+
| PatKind::Struct(..)
489+
| PatKind::TupleStruct(..)
490+
| PatKind::Tuple(..)
491+
| PatKind::Ref(..)
492+
| PatKind::Expr(..)
493+
| PatKind::Guard(..)
494+
| PatKind::Slice(_)
495+
| PatKind::Ident(..)
496+
| PatKind::Path(..)
497+
| PatKind::Wild
498+
| PatKind::Never
499+
| PatKind::Rest => {
500+
break hir::TyPatKind::Err(
501+
self.dcx().span_err(pattern.span, "pattern not supported in pattern types"),
502+
);
503+
}
504+
}
505+
};
506+
507+
hir::TyPat { hir_id: pat_hir_id, kind: node, span: self.lower_span(pattern.span) }
508+
}
432509
}

compiler/rustc_driver_impl/src/pretty.rs

+4
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,10 @@ impl<'tcx> pprust_hir::PpAnn for HirIdentifiedAnn<'tcx> {
101101
s.s.space();
102102
s.synth_comment(format!("pat hir_id: {}", pat.hir_id));
103103
}
104+
pprust_hir::AnnNode::TyPat(pat) => {
105+
s.s.space();
106+
s.synth_comment(format!("ty pat hir_id: {}", pat.hir_id));
107+
}
104108
pprust_hir::AnnNode::Arm(arm) => {
105109
s.s.space();
106110
s.synth_comment(format!("arm hir_id: {}", arm.hir_id));

compiler/rustc_hir/src/hir.rs

+20-1
Original file line numberDiff line numberDiff line change
@@ -1418,6 +1418,14 @@ impl<'hir> Block<'hir> {
14181418
}
14191419
}
14201420

1421+
#[derive(Debug, Clone, Copy, HashStable_Generic)]
1422+
pub struct TyPat<'hir> {
1423+
#[stable_hasher(ignore)]
1424+
pub hir_id: HirId,
1425+
pub kind: TyPatKind<'hir>,
1426+
pub span: Span,
1427+
}
1428+
14211429
#[derive(Debug, Clone, Copy, HashStable_Generic)]
14221430
pub struct Pat<'hir> {
14231431
#[stable_hasher(ignore)]
@@ -1591,6 +1599,15 @@ pub enum PatExprKind<'hir> {
15911599
Path(QPath<'hir>),
15921600
}
15931601

1602+
#[derive(Debug, Clone, Copy, HashStable_Generic)]
1603+
pub enum TyPatKind<'hir> {
1604+
/// A range pattern (e.g., `1..=2` or `1..2`).
1605+
Range(Option<&'hir ConstArg<'hir>>, Option<&'hir ConstArg<'hir>>, RangeEnd),
1606+
1607+
/// A placeholder for a pattern that wasn't well formed in some way.
1608+
Err(ErrorGuaranteed),
1609+
}
1610+
15941611
#[derive(Debug, Clone, Copy, HashStable_Generic)]
15951612
pub enum PatKind<'hir> {
15961613
/// Represents a wildcard pattern (i.e., `_`).
@@ -3384,7 +3401,7 @@ pub enum TyKind<'hir, Unambig = ()> {
33843401
/// Placeholder for a type that has failed to be defined.
33853402
Err(rustc_span::ErrorGuaranteed),
33863403
/// Pattern types (`pattern_type!(u32 is 1..)`)
3387-
Pat(&'hir Ty<'hir>, &'hir Pat<'hir>),
3404+
Pat(&'hir Ty<'hir>, &'hir TyPat<'hir>),
33883405
/// `TyKind::Infer` means the type should be inferred instead of it having been
33893406
/// specified. This can appear anywhere in a type.
33903407
///
@@ -4370,6 +4387,7 @@ pub enum Node<'hir> {
43704387
AssocItemConstraint(&'hir AssocItemConstraint<'hir>),
43714388
TraitRef(&'hir TraitRef<'hir>),
43724389
OpaqueTy(&'hir OpaqueTy<'hir>),
4390+
TyPat(&'hir TyPat<'hir>),
43734391
Pat(&'hir Pat<'hir>),
43744392
PatField(&'hir PatField<'hir>),
43754393
/// Needed as its own node with its own HirId for tracking
@@ -4432,6 +4450,7 @@ impl<'hir> Node<'hir> {
44324450
| Node::Block(..)
44334451
| Node::Ctor(..)
44344452
| Node::Pat(..)
4453+
| Node::TyPat(..)
44354454
| Node::PatExpr(..)
44364455
| Node::Arm(..)
44374456
| Node::LetStmt(..)

compiler/rustc_hir/src/intravisit.rs

+14-4
Original file line numberDiff line numberDiff line change
@@ -393,10 +393,8 @@ pub trait Visitor<'v>: Sized {
393393
fn visit_expr_field(&mut self, field: &'v ExprField<'v>) -> Self::Result {
394394
walk_expr_field(self, field)
395395
}
396-
fn visit_pattern_type_pattern(&mut self, _p: &'v Pat<'v>) {
397-
// Do nothing. Only a few visitors need to know the details of the pattern type,
398-
// and they opt into it. All other visitors will just choke on our fake patterns
399-
// because they aren't in a body.
396+
fn visit_pattern_type_pattern(&mut self, p: &'v TyPat<'v>) -> Self::Result {
397+
walk_ty_pat(self, p)
400398
}
401399
fn visit_generic_param(&mut self, p: &'v GenericParam<'v>) -> Self::Result {
402400
walk_generic_param(self, p)
@@ -702,6 +700,18 @@ pub fn walk_arm<'v, V: Visitor<'v>>(visitor: &mut V, arm: &'v Arm<'v>) -> V::Res
702700
visitor.visit_expr(arm.body)
703701
}
704702

703+
pub fn walk_ty_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v TyPat<'v>) -> V::Result {
704+
try_visit!(visitor.visit_id(pattern.hir_id));
705+
match pattern.kind {
706+
TyPatKind::Range(lower_bound, upper_bound, _) => {
707+
visit_opt!(visitor, visit_const_arg_unambig, lower_bound);
708+
visit_opt!(visitor, visit_const_arg_unambig, upper_bound);
709+
}
710+
TyPatKind::Err(_) => (),
711+
}
712+
V::Result::output()
713+
}
714+
705715
pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat<'v>) -> V::Result {
706716
try_visit!(visitor.visit_id(pattern.hir_id));
707717
match pattern.kind {

compiler/rustc_hir_analysis/messages.ftl

-3
Original file line numberDiff line numberDiff line change
@@ -436,9 +436,6 @@ hir_analysis_paren_sugar_attribute = the `#[rustc_paren_sugar]` attribute is a t
436436
hir_analysis_parenthesized_fn_trait_expansion =
437437
parenthesized trait syntax expands to `{$expanded_type}`
438438
439-
hir_analysis_pattern_type_non_const_range = range patterns must have constant range start and end
440-
hir_analysis_pattern_type_wild_pat = wildcard patterns are not permitted for pattern types
441-
.label = this type is the same as the inner type without a pattern
442439
hir_analysis_placeholder_not_allowed_item_signatures = the placeholder `_` is not allowed within types on item signatures for {$kind}
443440
.label = not allowed in type signatures
444441
hir_analysis_precise_capture_self_alias = `Self` can't be captured in `use<...>` precise captures list, since it is an alias

compiler/rustc_hir_analysis/src/collect/generics_of.rs

+1
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
198198
{
199199
Some(parent_did)
200200
}
201+
Node::TyPat(_) => Some(parent_did),
201202
_ => None,
202203
}
203204
}

compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -831,8 +831,8 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
831831
}
832832

833833
#[instrument(level = "debug", skip(self))]
834-
fn visit_pattern_type_pattern(&mut self, p: &'tcx hir::Pat<'tcx>) {
835-
intravisit::walk_pat(self, p)
834+
fn visit_pattern_type_pattern(&mut self, p: &'tcx hir::TyPat<'tcx>) {
835+
intravisit::walk_ty_pat(self, p)
836836
}
837837

838838
#[instrument(level = "debug", skip(self))]

compiler/rustc_hir_analysis/src/collect/type_of.rs

+16-5
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,10 @@ use crate::hir_ty_lowering::HirTyLowerer;
1818

1919
mod opaque;
2020

21-
fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
21+
fn anon_const_type_of<'tcx>(icx: &ItemCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
2222
use hir::*;
2323
use rustc_middle::ty::Ty;
24+
let tcx = icx.tcx;
2425
let hir_id = tcx.local_def_id_to_hir_id(def_id);
2526

2627
let node = tcx.hir_node(hir_id);
@@ -54,7 +55,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
5455
hir_id: arg_hir_id,
5556
kind: ConstArgKind::Anon(&AnonConst { hir_id: anon_hir_id, .. }),
5657
..
57-
}) if anon_hir_id == hir_id => const_arg_anon_type_of(tcx, arg_hir_id, span),
58+
}) if anon_hir_id == hir_id => const_arg_anon_type_of(icx, arg_hir_id, span),
5859

5960
// Anon consts outside the type system.
6061
Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. })
@@ -138,18 +139,28 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
138139
}
139140
}
140141

141-
fn const_arg_anon_type_of<'tcx>(tcx: TyCtxt<'tcx>, arg_hir_id: HirId, span: Span) -> Ty<'tcx> {
142+
fn const_arg_anon_type_of<'tcx>(icx: &ItemCtxt<'tcx>, arg_hir_id: HirId, span: Span) -> Ty<'tcx> {
142143
use hir::*;
143144
use rustc_middle::ty::Ty;
144145

146+
let tcx = icx.tcx;
147+
145148
match tcx.parent_hir_node(arg_hir_id) {
146149
// Array length const arguments do not have `type_of` fed as there is never a corresponding
147150
// generic parameter definition.
148151
Node::Ty(&hir::Ty { kind: TyKind::Array(_, ref constant), .. })
149152
| Node::Expr(&Expr { kind: ExprKind::Repeat(_, ref constant), .. })
150153
if constant.hir_id == arg_hir_id =>
151154
{
152-
return tcx.types.usize;
155+
tcx.types.usize
156+
}
157+
158+
Node::TyPat(pat) => {
159+
let hir::TyKind::Pat(ty, p) = tcx.parent_hir_node(pat.hir_id).expect_ty().kind else {
160+
bug!()
161+
};
162+
assert_eq!(p.hir_id, pat.hir_id);
163+
icx.lower_ty(ty)
153164
}
154165

155166
// This is not a `bug!` as const arguments in path segments that did not resolve to anything
@@ -344,7 +355,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_
344355
tcx.typeck(def_id).node_type(hir_id)
345356
}
346357

347-
Node::AnonConst(_) => anon_const_type_of(tcx, def_id),
358+
Node::AnonConst(_) => anon_const_type_of(&icx, def_id),
348359

349360
Node::ConstBlock(_) => {
350361
let args = ty::GenericArgs::identity_for_item(tcx, def_id.to_def_id());

compiler/rustc_hir_analysis/src/errors.rs

-7
Original file line numberDiff line numberDiff line change
@@ -1605,13 +1605,6 @@ pub(crate) struct OpaqueCapturesHigherRankedLifetime {
16051605
pub bad_place: &'static str,
16061606
}
16071607

1608-
#[derive(Diagnostic)]
1609-
#[diag(hir_analysis_pattern_type_non_const_range)]
1610-
pub(crate) struct NonConstRange {
1611-
#[primary_span]
1612-
pub span: Span,
1613-
}
1614-
16151608
#[derive(Subdiagnostic)]
16161609
pub(crate) enum InvalidReceiverTyHint {
16171610
#[note(hir_analysis_invalid_receiver_ty_help_weak_note)]

compiler/rustc_hir_analysis/src/errors/pattern_types.rs

-7
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,6 @@ use rustc_macros::Diagnostic;
22
use rustc_middle::ty::Ty;
33
use rustc_span::Span;
44

5-
#[derive(Diagnostic)]
6-
#[diag(hir_analysis_pattern_type_wild_pat)]
7-
pub(crate) struct WildPatTy {
8-
#[primary_span]
9-
pub span: Span,
10-
}
11-
125
#[derive(Diagnostic)]
136
#[diag(hir_analysis_invalid_base_type)]
147
pub(crate) struct InvalidBaseType<'tcx> {

0 commit comments

Comments
 (0)