Skip to content

Commit a4f2c97

Browse files
committed
Auto merge of rust-lang#120131 - oli-obk:pattern_types_syntax, r=compiler-errors
Implement minimal, internal-only pattern types in the type system rebase of rust-lang#107606 You can create pattern types with `std::pat::pattern_type!(ty is pat)`. The feature is incomplete and will panic on you if you use any pattern other than integral range patterns. The only way to create or deconstruct a pattern type is via `transmute`. This PR's implementation differs from the MCP's text. Specifically > This means you could implement different traits for different pattern types with the same base type. Thus, we just forbid implementing any traits for pattern types. is violated in this PR. The reason is that we do need impls after all in order to make them usable as fields. constants of type `std::time::Nanoseconds` struct are used in patterns, so the type must be structural-eq, which it only can be if you derive several traits on it. It doesn't need to be structural-eq recursively, so we can just manually implement the relevant traits on the pattern type and use the pattern type as a private field. Waiting on: * [x] move all unrelated commits into their own PRs. * [x] fix niche computation (see 2db07f9) * [x] add lots more tests * [x] T-types MCP rust-lang/types-team#126 to finish * [x] some commit cleanup * [x] full self-review * [x] remove 61bd325, it's not necessary anymore I think. * [ ] ~~make sure we never accidentally leak pattern types to user code (add stability checks or feature gate checks and appopriate tests)~~ we don't even do this for the new float primitives * [x] get approval that [the scope expansion to trait impls](https://rust-lang.zulipchat.com/#narrow/stream/326866-t-types.2Fnominated/topic/Pattern.20types.20types-team.23126/near/427670099) is ok r? `@BoxyUwU`
2 parents 0e5f520 + 90e88aa commit a4f2c97

File tree

126 files changed

+1498
-66
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

126 files changed

+1498
-66
lines changed

compiler/rustc_ast/src/ast.rs

+3
Original file line numberDiff line numberDiff line change
@@ -2152,6 +2152,9 @@ pub enum TyKind {
21522152
MacCall(P<MacCall>),
21532153
/// Placeholder for a `va_list`.
21542154
CVarArgs,
2155+
/// Pattern types like `pattern_type!(u32 is 1..=)`, which is the same as `NonZeroU32`,
2156+
/// just as part of the type system.
2157+
Pat(P<Ty>, P<Pat>),
21552158
/// Sometimes we need a dummy value when no error has occurred.
21562159
Dummy,
21572160
/// Placeholder for a kind that has failed to be defined.

compiler/rustc_ast/src/mut_visit.rs

+4
Original file line numberDiff line numberDiff line change
@@ -502,6 +502,10 @@ pub fn noop_visit_ty<T: MutVisitor>(ty: &mut P<Ty>, vis: &mut T) {
502502
}
503503
TyKind::Tup(tys) => visit_thin_vec(tys, |ty| vis.visit_ty(ty)),
504504
TyKind::Paren(ty) => vis.visit_ty(ty),
505+
TyKind::Pat(ty, pat) => {
506+
vis.visit_ty(ty);
507+
vis.visit_pat(pat);
508+
}
505509
TyKind::Path(qself, path) => {
506510
vis.visit_qself(qself);
507511
vis.visit_path(path);

compiler/rustc_ast/src/visit.rs

+4
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,10 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) -> V::Result {
446446
}
447447
try_visit!(visitor.visit_path(path, typ.id));
448448
}
449+
TyKind::Pat(ty, pat) => {
450+
try_visit!(visitor.visit_ty(ty));
451+
try_visit!(visitor.visit_pat(pat));
452+
}
449453
TyKind::Array(ty, length) => {
450454
try_visit!(visitor.visit_ty(ty));
451455
try_visit!(visitor.visit_anon_const(length));

compiler/rustc_ast_lowering/src/index.rs

+4
Original file line numberDiff line numberDiff line change
@@ -381,4 +381,8 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
381381
ArrayLen::Body(..) => intravisit::walk_array_len(self, len),
382382
}
383383
}
384+
385+
fn visit_pattern_type_pattern(&mut self, p: &'hir hir::Pat<'hir>) {
386+
self.visit_pat(p)
387+
}
384388
}

compiler/rustc_ast_lowering/src/lib.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -1463,7 +1463,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
14631463
}
14641464
}
14651465
}
1466-
TyKind::MacCall(_) => panic!("`TyKind::MacCall` should have been expanded by now"),
1466+
TyKind::Pat(ty, pat) => hir::TyKind::Pat(self.lower_ty(ty, itctx), self.lower_pat(pat)),
1467+
TyKind::MacCall(_) => {
1468+
span_bug!(t.span, "`TyKind::MacCall` should have been expanded by now")
1469+
}
14671470
TyKind::CVarArgs => {
14681471
let guar = self.dcx().span_delayed_bug(
14691472
t.span,

compiler/rustc_ast_passes/src/feature_gate.rs

+3
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,9 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
332332
ast::TyKind::Never => {
333333
gate!(&self, never_type, ty.span, "the `!` type is experimental");
334334
}
335+
ast::TyKind::Pat(..) => {
336+
gate!(&self, pattern_types, ty.span, "pattern types are unstable");
337+
}
335338
_ => {}
336339
}
337340
visit::walk_ty(self, ty)

compiler/rustc_ast_pretty/src/pprust/state.rs

+5
Original file line numberDiff line numberDiff line change
@@ -1188,6 +1188,11 @@ impl<'a> State<'a> {
11881188
ast::TyKind::CVarArgs => {
11891189
self.word("...");
11901190
}
1191+
ast::TyKind::Pat(ty, pat) => {
1192+
self.print_type(ty);
1193+
self.word(" is ");
1194+
self.print_pat(pat);
1195+
}
11911196
}
11921197
self.end();
11931198
}

compiler/rustc_borrowck/src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1606,6 +1606,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
16061606
| ty::Foreign(_)
16071607
| ty::Str
16081608
| ty::Array(_, _)
1609+
| ty::Pat(_, _)
16091610
| ty::Slice(_)
16101611
| ty::FnDef(_, _)
16111612
| ty::FnPtr(_)
@@ -1648,6 +1649,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
16481649
| ty::Foreign(_)
16491650
| ty::Str
16501651
| ty::Array(_, _)
1652+
| ty::Pat(_, _)
16511653
| ty::Slice(_)
16521654
| ty::RawPtr(_, _)
16531655
| ty::Ref(_, _, _)

compiler/rustc_builtin_macros/src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ mod format;
4646
mod format_foreign;
4747
mod global_allocator;
4848
mod log_syntax;
49+
mod pattern_type;
4950
mod source_util;
5051
mod test;
5152
mod trace_macros;
@@ -95,6 +96,7 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) {
9596
log_syntax: log_syntax::expand_log_syntax,
9697
module_path: source_util::expand_mod,
9798
option_env: env::expand_option_env,
99+
pattern_type: pattern_type::expand,
98100
std_panic: edition_panic::expand_panic,
99101
stringify: source_util::expand_stringify,
100102
trace_macros: trace_macros::expand_trace_macros,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
use rustc_ast::{ast, ptr::P, tokenstream::TokenStream, Pat, Ty};
2+
use rustc_errors::PResult;
3+
use rustc_expand::base::{self, DummyResult, ExpandResult, ExtCtxt, MacroExpanderResult};
4+
use rustc_span::{sym, Span};
5+
6+
pub fn expand<'cx>(
7+
cx: &'cx mut ExtCtxt<'_>,
8+
sp: Span,
9+
tts: TokenStream,
10+
) -> MacroExpanderResult<'cx> {
11+
let (ty, pat) = match parse_pat_ty(cx, tts) {
12+
Ok(parsed) => parsed,
13+
Err(err) => {
14+
return ExpandResult::Ready(DummyResult::any(sp, err.emit()));
15+
}
16+
};
17+
18+
ExpandResult::Ready(base::MacEager::ty(cx.ty(sp, ast::TyKind::Pat(ty, pat))))
19+
}
20+
21+
fn parse_pat_ty<'a>(cx: &mut ExtCtxt<'a>, stream: TokenStream) -> PResult<'a, (P<Ty>, P<Pat>)> {
22+
let mut parser = cx.new_parser_from_tts(stream);
23+
24+
let ty = parser.parse_ty()?;
25+
parser.eat_keyword(sym::is);
26+
let pat = parser.parse_pat_no_top_alt(None, None)?;
27+
28+
Ok((ty, pat))
29+
}

compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs

+10
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,16 @@ fn push_debuginfo_type_name<'tcx>(
202202
}
203203
}
204204
}
205+
ty::Pat(inner_type, pat) => {
206+
if cpp_like_debuginfo {
207+
output.push_str("pat$<");
208+
push_debuginfo_type_name(tcx, inner_type, true, output, visited);
209+
// FIXME(wg-debugging): implement CPP like printing for patterns.
210+
write!(output, ",{:?}>", pat).unwrap();
211+
} else {
212+
write!(output, "{:?}", t).unwrap();
213+
}
214+
}
205215
ty::Slice(inner_type) => {
206216
if cpp_like_debuginfo {
207217
output.push_str("slice2$<");

compiler/rustc_const_eval/src/const_eval/valtrees.rs

+14-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use rustc_data_structures::stack::ensure_sufficient_stack;
12
use rustc_middle::mir;
23
use rustc_middle::mir::interpret::{EvalToValTreeResult, GlobalId};
34
use rustc_middle::ty::layout::{LayoutCx, LayoutOf, TyAndLayout};
@@ -98,6 +99,16 @@ fn const_to_valtree_inner<'tcx>(
9899
Ok(ty::ValTree::Leaf(val.assert_int()))
99100
}
100101

102+
ty::Pat(base, ..) => {
103+
let mut place = place.clone();
104+
// The valtree of the base type is the same as the valtree of the pattern type.
105+
// Since the returned valtree does not contain the type or layout, we can just
106+
// switch to the base type.
107+
place.layout = ecx.layout_of(*base).unwrap();
108+
ensure_sufficient_stack(|| const_to_valtree_inner(ecx, &place, num_nodes))
109+
},
110+
111+
101112
ty::RawPtr(_, _) => {
102113
// Not all raw pointers are allowed, as we cannot properly test them for
103114
// equality at compile-time (see `ptr_guaranteed_cmp`).
@@ -273,7 +284,7 @@ pub fn valtree_to_const_value<'tcx>(
273284

274285
let (param_env, ty) = param_env_ty.into_parts();
275286

276-
match ty.kind() {
287+
match *ty.kind() {
277288
ty::FnDef(..) => {
278289
assert!(valtree.unwrap_branch().is_empty());
279290
mir::ConstValue::ZeroSized
@@ -286,10 +297,11 @@ pub fn valtree_to_const_value<'tcx>(
286297
),
287298
}
288299
}
300+
ty::Pat(ty, _) => valtree_to_const_value(tcx, param_env.and(ty), valtree),
289301
ty::Ref(_, inner_ty, _) => {
290302
let mut ecx =
291303
mk_eval_cx_to_read_const_val(tcx, DUMMY_SP, param_env, CanAccessMutGlobal::No);
292-
let imm = valtree_to_ref(&mut ecx, valtree, *inner_ty);
304+
let imm = valtree_to_ref(&mut ecx, valtree, inner_ty);
293305
let imm = ImmTy::from_immediate(imm, tcx.layout_of(param_env_ty).unwrap());
294306
op_to_const(&ecx, &imm.into(), /* for diagnostics */ false)
295307
}

compiler/rustc_const_eval/src/interpret/eval_context.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1060,6 +1060,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
10601060

10611061
ty::Tuple(tys) => tys.last().iter().all(|ty| is_very_trivially_sized(**ty)),
10621062

1063+
ty::Pat(ty, ..) => is_very_trivially_sized(*ty),
1064+
10631065
// We don't want to do any queries, so there is not much we can do with ADTs.
10641066
ty::Adt(..) => false,
10651067

compiler/rustc_const_eval/src/interpret/intrinsics.rs

+4
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,10 @@ pub(crate) fn eval_nullary_intrinsic<'tcx>(
6969
ty::Alias(..) | ty::Param(_) | ty::Placeholder(_) | ty::Infer(_) => {
7070
throw_inval!(TooGeneric)
7171
}
72+
ty::Pat(_, pat) => match **pat {
73+
ty::PatternKind::Range { .. } => ConstValue::from_target_usize(0u64, &tcx),
74+
// Future pattern kinds may have more variants
75+
},
7276
ty::Bound(_, _) => bug!("bound ty during ctfe"),
7377
ty::Bool
7478
| ty::Char

compiler/rustc_const_eval/src/interpret/validity.rs

+1
Original file line numberDiff line numberDiff line change
@@ -640,6 +640,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
640640
| ty::Str
641641
| ty::Dynamic(..)
642642
| ty::Closure(..)
643+
| ty::Pat(..)
643644
| ty::CoroutineClosure(..)
644645
| ty::Coroutine(..) => Ok(false),
645646
// Some types only occur during typechecking, they have no layout.

compiler/rustc_const_eval/src/util/type_name.rs

+1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> {
3131
| ty::Uint(_)
3232
| ty::Float(_)
3333
| ty::Str
34+
| ty::Pat(_, _)
3435
| ty::Array(_, _)
3536
| ty::Slice(_)
3637
| ty::RawPtr(_, _)

compiler/rustc_feature/src/unstable.rs

+2
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,8 @@ declare_features! (
215215
(internal, omit_gdb_pretty_printer_section, "1.5.0", None),
216216
/// Set the maximum pattern complexity allowed (not limited by default).
217217
(internal, pattern_complexity, "1.78.0", None),
218+
/// Allows using pattern types.
219+
(internal, pattern_types, "CURRENT_RUSTC_VERSION", Some(54882)),
218220
/// Allows using `#[prelude_import]` on glob `use` items.
219221
(internal, prelude_import, "1.2.0", None),
220222
/// Used to identify crates that contain the profiler runtime.

compiler/rustc_hir/src/hir.rs

+2
Original file line numberDiff line numberDiff line change
@@ -2624,6 +2624,8 @@ pub enum TyKind<'hir> {
26242624
Infer,
26252625
/// Placeholder for a type that has failed to be defined.
26262626
Err(rustc_span::ErrorGuaranteed),
2627+
/// Pattern types (`pattern_type!(u32 is 1..)`)
2628+
Pat(&'hir Ty<'hir>, &'hir Pat<'hir>),
26272629
}
26282630

26292631
#[derive(Debug, Clone, Copy, HashStable_Generic)]

compiler/rustc_hir/src/intravisit.rs

+9
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,11 @@ pub trait Visitor<'v>: Sized {
356356
fn visit_ty(&mut self, t: &'v Ty<'v>) -> Self::Result {
357357
walk_ty(self, t)
358358
}
359+
fn visit_pattern_type_pattern(&mut self, _p: &'v Pat<'v>) {
360+
// Do nothing. Only a few visitors need to know the details of the pattern type,
361+
// and they opt into it. All other visitors will just choke on our fake patterns
362+
// because they aren't in a body.
363+
}
359364
fn visit_generic_param(&mut self, p: &'v GenericParam<'v>) -> Self::Result {
360365
walk_generic_param(self, p)
361366
}
@@ -882,6 +887,10 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) -> V::Resul
882887
TyKind::AnonAdt(item_id) => {
883888
try_visit!(visitor.visit_nested_item(item_id));
884889
}
890+
TyKind::Pat(ty, pat) => {
891+
try_visit!(visitor.visit_ty(ty));
892+
try_visit!(visitor.visit_pattern_type_pattern(pat));
893+
}
885894
}
886895
V::Result::output()
887896
}

compiler/rustc_hir_analysis/messages.ftl

+3
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,9 @@ hir_analysis_pass_to_variadic_function = can't pass `{$ty}` to variadic function
349349
.suggestion = cast the value to `{$cast_ty}`
350350
.help = cast the value to `{$cast_ty}`
351351
352+
hir_analysis_pattern_type_non_const_range = "range patterns must have constant range start and end"
353+
hir_analysis_pattern_type_wild_pat = "wildcard patterns are not permitted for pattern types"
354+
.label = "this type is the same as the inner type without a pattern"
352355
hir_analysis_placeholder_not_allowed_item_signatures = the placeholder `_` is not allowed within types on item signatures for {$kind}
353356
.label = not allowed in type signatures
354357

compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,12 @@ impl<'tcx> InherentCollect<'tcx> {
144144
let id = id.owner_id.def_id;
145145
let item_span = self.tcx.def_span(id);
146146
let self_ty = self.tcx.type_of(id).instantiate_identity();
147-
let self_ty = self.tcx.peel_off_weak_alias_tys(self_ty);
147+
let mut self_ty = self.tcx.peel_off_weak_alias_tys(self_ty);
148+
// We allow impls on pattern types exactly when we allow impls on the base type.
149+
// FIXME(pattern_types): Figure out the exact coherence rules we want here.
150+
while let ty::Pat(base, _) = *self_ty.kind() {
151+
self_ty = base;
152+
}
148153
match *self_ty.kind() {
149154
ty::Adt(def, _) => self.check_def_id(id, self_ty, def.did()),
150155
ty::Foreign(did) => self.check_def_id(id, self_ty, did),
@@ -154,6 +159,7 @@ impl<'tcx> InherentCollect<'tcx> {
154159
ty::Dynamic(..) => {
155160
Err(self.tcx.dcx().emit_err(errors::InherentDyn { span: item_span }))
156161
}
162+
ty::Pat(_, _) => unreachable!(),
157163
ty::Bool
158164
| ty::Char
159165
| ty::Int(_)

compiler/rustc_hir_analysis/src/coherence/orphan.rs

+5
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,11 @@ pub(crate) fn orphan_check_impl(
206206
(LocalImpl::Disallow { problematic_kind }, NonlocalImpl::DisallowOther)
207207
}
208208

209+
ty::Pat(..) => (
210+
LocalImpl::Disallow { problematic_kind: "pattern type" },
211+
NonlocalImpl::DisallowOther,
212+
),
213+
209214
ty::Bool
210215
| ty::Char
211216
| ty::Int(..)

compiler/rustc_hir_analysis/src/errors.rs

+9
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ use rustc_errors::{
77
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
88
use rustc_middle::ty::Ty;
99
use rustc_span::{symbol::Ident, Span, Symbol};
10+
mod pattern_types;
11+
pub use pattern_types::*;
1012

1113
#[derive(Diagnostic)]
1214
#[diag(hir_analysis_ambiguous_assoc_item)]
@@ -1629,3 +1631,10 @@ pub struct OpaqueCapturesHigherRankedLifetime {
16291631
pub decl_span: Span,
16301632
pub bad_place: &'static str,
16311633
}
1634+
1635+
#[derive(Diagnostic)]
1636+
#[diag(hir_analysis_pattern_type_non_const_range)]
1637+
pub struct NonConstRange {
1638+
#[primary_span]
1639+
pub span: Span,
1640+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
use rustc_macros::Diagnostic;
2+
use rustc_span::Span;
3+
4+
#[derive(Diagnostic)]
5+
#[diag(hir_analysis_pattern_type_wild_pat)]
6+
pub struct WildPatTy {
7+
#[primary_span]
8+
pub span: Span,
9+
}

0 commit comments

Comments
 (0)