Auto merge of #120131 - oli-obk:pattern_types_syntax, r=compiler-errors

Implement minimal, internal-only pattern types in the type system

rebase of https://github.com/rust-lang/rust/pull/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 2db07f94f44f078daffe5823680d07d4fded883f)
* [x] add lots more tests
* [x] T-types MCP https://github.com/rust-lang/types-team/issues/126 to finish
* [x] some commit cleanup
* [x] full self-review
* [x] remove 61bd325da19a918cc3e02bbbdce97281a389c648, 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`
This commit is contained in:
bors 2024-04-08 16:25:23 +00:00
commit 537aab7a2e
126 changed files with 1499 additions and 66 deletions

View File

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

View File

@ -502,6 +502,10 @@ pub fn noop_visit_ty<T: MutVisitor>(ty: &mut P<Ty>, vis: &mut T) {
}
TyKind::Tup(tys) => visit_thin_vec(tys, |ty| vis.visit_ty(ty)),
TyKind::Paren(ty) => vis.visit_ty(ty),
TyKind::Pat(ty, pat) => {
vis.visit_ty(ty);
vis.visit_pat(pat);
}
TyKind::Path(qself, path) => {
vis.visit_qself(qself);
vis.visit_path(path);

View File

@ -446,6 +446,10 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) -> V::Result {
}
try_visit!(visitor.visit_path(path, typ.id));
}
TyKind::Pat(ty, pat) => {
try_visit!(visitor.visit_ty(ty));
try_visit!(visitor.visit_pat(pat));
}
TyKind::Array(ty, length) => {
try_visit!(visitor.visit_ty(ty));
try_visit!(visitor.visit_anon_const(length));

View File

@ -381,4 +381,8 @@ fn visit_array_length(&mut self, len: &'hir ArrayLen) {
ArrayLen::Body(..) => intravisit::walk_array_len(self, len),
}
}
fn visit_pattern_type_pattern(&mut self, p: &'hir hir::Pat<'hir>) {
self.visit_pat(p)
}
}

View File

@ -1463,7 +1463,10 @@ fn lower_ty_direct(&mut self, t: &Ty, itctx: ImplTraitContext) -> hir::Ty<'hir>
}
}
}
TyKind::MacCall(_) => panic!("`TyKind::MacCall` should have been expanded by now"),
TyKind::Pat(ty, pat) => hir::TyKind::Pat(self.lower_ty(ty, itctx), self.lower_pat(pat)),
TyKind::MacCall(_) => {
span_bug!(t.span, "`TyKind::MacCall` should have been expanded by now")
}
TyKind::CVarArgs => {
let guar = self.dcx().span_delayed_bug(
t.span,

View File

@ -332,6 +332,9 @@ fn visit_ty(&mut self, ty: &'a ast::Ty) {
ast::TyKind::Never => {
gate!(&self, never_type, ty.span, "the `!` type is experimental");
}
ast::TyKind::Pat(..) => {
gate!(&self, pattern_types, ty.span, "pattern types are unstable");
}
_ => {}
}
visit::walk_ty(self, ty)

View File

@ -1188,6 +1188,11 @@ pub fn print_type(&mut self, ty: &ast::Ty) {
ast::TyKind::CVarArgs => {
self.word("...");
}
ast::TyKind::Pat(ty, pat) => {
self.print_type(ty);
self.word(" is ");
self.print_pat(pat);
}
}
self.end();
}

View File

@ -1606,6 +1606,7 @@ fn check_movable_place(&mut self, location: Location, place: Place<'tcx>) {
| ty::Foreign(_)
| ty::Str
| ty::Array(_, _)
| ty::Pat(_, _)
| ty::Slice(_)
| ty::FnDef(_, _)
| ty::FnPtr(_)
@ -1648,6 +1649,7 @@ fn check_movable_place(&mut self, location: Location, place: Place<'tcx>) {
| ty::Foreign(_)
| ty::Str
| ty::Array(_, _)
| ty::Pat(_, _)
| ty::Slice(_)
| ty::RawPtr(_, _)
| ty::Ref(_, _, _)

View File

@ -46,6 +46,7 @@
mod format_foreign;
mod global_allocator;
mod log_syntax;
mod pattern_type;
mod source_util;
mod test;
mod trace_macros;
@ -95,6 +96,7 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) {
log_syntax: log_syntax::expand_log_syntax,
module_path: source_util::expand_mod,
option_env: env::expand_option_env,
pattern_type: pattern_type::expand,
std_panic: edition_panic::expand_panic,
stringify: source_util::expand_stringify,
trace_macros: trace_macros::expand_trace_macros,

View File

@ -0,0 +1,29 @@
use rustc_ast::{ast, ptr::P, tokenstream::TokenStream, Pat, Ty};
use rustc_errors::PResult;
use rustc_expand::base::{self, DummyResult, ExpandResult, ExtCtxt, MacroExpanderResult};
use rustc_span::{sym, Span};
pub fn expand<'cx>(
cx: &'cx mut ExtCtxt<'_>,
sp: Span,
tts: TokenStream,
) -> MacroExpanderResult<'cx> {
let (ty, pat) = match parse_pat_ty(cx, tts) {
Ok(parsed) => parsed,
Err(err) => {
return ExpandResult::Ready(DummyResult::any(sp, err.emit()));
}
};
ExpandResult::Ready(base::MacEager::ty(cx.ty(sp, ast::TyKind::Pat(ty, pat))))
}
fn parse_pat_ty<'a>(cx: &mut ExtCtxt<'a>, stream: TokenStream) -> PResult<'a, (P<Ty>, P<Pat>)> {
let mut parser = cx.new_parser_from_tts(stream);
let ty = parser.parse_ty()?;
parser.eat_keyword(sym::is);
let pat = parser.parse_pat_no_top_alt(None, None)?;
Ok((ty, pat))
}

View File

@ -202,6 +202,16 @@ fn push_debuginfo_type_name<'tcx>(
}
}
}
ty::Pat(inner_type, pat) => {
if cpp_like_debuginfo {
output.push_str("pat$<");
push_debuginfo_type_name(tcx, inner_type, true, output, visited);
// FIXME(wg-debugging): implement CPP like printing for patterns.
write!(output, ",{:?}>", pat).unwrap();
} else {
write!(output, "{:?}", t).unwrap();
}
}
ty::Slice(inner_type) => {
if cpp_like_debuginfo {
output.push_str("slice2$<");

View File

@ -1,3 +1,4 @@
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_middle::mir;
use rustc_middle::mir::interpret::{EvalToValTreeResult, GlobalId};
use rustc_middle::ty::layout::{LayoutCx, LayoutOf, TyAndLayout};
@ -98,6 +99,16 @@ fn const_to_valtree_inner<'tcx>(
Ok(ty::ValTree::Leaf(val.assert_int()))
}
ty::Pat(base, ..) => {
let mut place = place.clone();
// The valtree of the base type is the same as the valtree of the pattern type.
// Since the returned valtree does not contain the type or layout, we can just
// switch to the base type.
place.layout = ecx.layout_of(*base).unwrap();
ensure_sufficient_stack(|| const_to_valtree_inner(ecx, &place, num_nodes))
},
ty::RawPtr(_, _) => {
// Not all raw pointers are allowed, as we cannot properly test them for
// equality at compile-time (see `ptr_guaranteed_cmp`).
@ -273,7 +284,7 @@ pub fn valtree_to_const_value<'tcx>(
let (param_env, ty) = param_env_ty.into_parts();
match ty.kind() {
match *ty.kind() {
ty::FnDef(..) => {
assert!(valtree.unwrap_branch().is_empty());
mir::ConstValue::ZeroSized
@ -286,10 +297,11 @@ pub fn valtree_to_const_value<'tcx>(
),
}
}
ty::Pat(ty, _) => valtree_to_const_value(tcx, param_env.and(ty), valtree),
ty::Ref(_, inner_ty, _) => {
let mut ecx =
mk_eval_cx_to_read_const_val(tcx, DUMMY_SP, param_env, CanAccessMutGlobal::No);
let imm = valtree_to_ref(&mut ecx, valtree, *inner_ty);
let imm = valtree_to_ref(&mut ecx, valtree, inner_ty);
let imm = ImmTy::from_immediate(imm, tcx.layout_of(param_env_ty).unwrap());
op_to_const(&ecx, &imm.into(), /* for diagnostics */ false)
}

View File

@ -1060,6 +1060,8 @@ fn is_very_trivially_sized(ty: Ty<'_>) -> bool {
ty::Tuple(tys) => tys.last().iter().all(|ty| is_very_trivially_sized(**ty)),
ty::Pat(ty, ..) => is_very_trivially_sized(*ty),
// We don't want to do any queries, so there is not much we can do with ADTs.
ty::Adt(..) => false,

View File

@ -69,6 +69,10 @@ pub(crate) fn eval_nullary_intrinsic<'tcx>(
ty::Alias(..) | ty::Param(_) | ty::Placeholder(_) | ty::Infer(_) => {
throw_inval!(TooGeneric)
}
ty::Pat(_, pat) => match **pat {
ty::PatternKind::Range { .. } => ConstValue::from_target_usize(0u64, &tcx),
// Future pattern kinds may have more variants
},
ty::Bound(_, _) => bug!("bound ty during ctfe"),
ty::Bool
| ty::Char

View File

@ -640,6 +640,7 @@ fn try_visit_primitive(
| ty::Str
| ty::Dynamic(..)
| ty::Closure(..)
| ty::Pat(..)
| ty::CoroutineClosure(..)
| ty::Coroutine(..) => Ok(false),
// Some types only occur during typechecking, they have no layout.

View File

@ -31,6 +31,7 @@ fn print_type(&mut self, ty: Ty<'tcx>) -> Result<(), PrintError> {
| ty::Uint(_)
| ty::Float(_)
| ty::Str
| ty::Pat(_, _)
| ty::Array(_, _)
| ty::Slice(_)
| ty::RawPtr(_, _)

View File

@ -215,6 +215,8 @@ pub fn internal(&self, feature: Symbol) -> bool {
(internal, omit_gdb_pretty_printer_section, "1.5.0", None),
/// Set the maximum pattern complexity allowed (not limited by default).
(internal, pattern_complexity, "1.78.0", None),
/// Allows using pattern types.
(internal, pattern_types, "CURRENT_RUSTC_VERSION", Some(54882)),
/// Allows using `#[prelude_import]` on glob `use` items.
(internal, prelude_import, "1.2.0", None),
/// Used to identify crates that contain the profiler runtime.

View File

@ -2624,6 +2624,8 @@ pub enum TyKind<'hir> {
Infer,
/// Placeholder for a type that has failed to be defined.
Err(rustc_span::ErrorGuaranteed),
/// Pattern types (`pattern_type!(u32 is 1..)`)
Pat(&'hir Ty<'hir>, &'hir Pat<'hir>),
}
#[derive(Debug, Clone, Copy, HashStable_Generic)]

View File

@ -356,6 +356,11 @@ fn visit_expr_field(&mut self, field: &'v ExprField<'v>) -> Self::Result {
fn visit_ty(&mut self, t: &'v Ty<'v>) -> Self::Result {
walk_ty(self, t)
}
fn visit_pattern_type_pattern(&mut self, _p: &'v Pat<'v>) {
// Do nothing. Only a few visitors need to know the details of the pattern type,
// and they opt into it. All other visitors will just choke on our fake patterns
// because they aren't in a body.
}
fn visit_generic_param(&mut self, p: &'v GenericParam<'v>) -> Self::Result {
walk_generic_param(self, p)
}
@ -882,6 +887,10 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) -> V::Resul
TyKind::AnonAdt(item_id) => {
try_visit!(visitor.visit_nested_item(item_id));
}
TyKind::Pat(ty, pat) => {
try_visit!(visitor.visit_ty(ty));
try_visit!(visitor.visit_pattern_type_pattern(pat));
}
}
V::Result::output()
}

View File

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

View File

@ -144,7 +144,12 @@ fn check_item(&mut self, id: hir::ItemId) -> Result<(), ErrorGuaranteed> {
let id = id.owner_id.def_id;
let item_span = self.tcx.def_span(id);
let self_ty = self.tcx.type_of(id).instantiate_identity();
let self_ty = self.tcx.peel_off_weak_alias_tys(self_ty);
let mut self_ty = self.tcx.peel_off_weak_alias_tys(self_ty);
// We allow impls on pattern types exactly when we allow impls on the base type.
// FIXME(pattern_types): Figure out the exact coherence rules we want here.
while let ty::Pat(base, _) = *self_ty.kind() {
self_ty = base;
}
match *self_ty.kind() {
ty::Adt(def, _) => self.check_def_id(id, self_ty, def.did()),
ty::Foreign(did) => self.check_def_id(id, self_ty, did),
@ -154,6 +159,7 @@ fn check_item(&mut self, id: hir::ItemId) -> Result<(), ErrorGuaranteed> {
ty::Dynamic(..) => {
Err(self.tcx.dcx().emit_err(errors::InherentDyn { span: item_span }))
}
ty::Pat(_, _) => unreachable!(),
ty::Bool
| ty::Char
| ty::Int(_)

View File

@ -206,6 +206,11 @@ enum NonlocalImpl {
(LocalImpl::Disallow { problematic_kind }, NonlocalImpl::DisallowOther)
}
ty::Pat(..) => (
LocalImpl::Disallow { problematic_kind: "pattern type" },
NonlocalImpl::DisallowOther,
),
ty::Bool
| ty::Char
| ty::Int(..)

View File

@ -7,6 +7,8 @@
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
use rustc_middle::ty::Ty;
use rustc_span::{symbol::Ident, Span, Symbol};
mod pattern_types;
pub use pattern_types::*;
#[derive(Diagnostic)]
#[diag(hir_analysis_ambiguous_assoc_item)]
@ -1629,3 +1631,10 @@ pub struct OpaqueCapturesHigherRankedLifetime {
pub decl_span: Span,
pub bad_place: &'static str,
}
#[derive(Diagnostic)]
#[diag(hir_analysis_pattern_type_non_const_range)]
pub struct NonConstRange {
#[primary_span]
pub span: Span,
}

View File

@ -0,0 +1,9 @@
use rustc_macros::Diagnostic;
use rustc_span::Span;
#[derive(Diagnostic)]
#[diag(hir_analysis_pattern_type_wild_pat)]
pub struct WildPatTy {
#[primary_span]
pub span: Span,
}

View File

@ -21,7 +21,7 @@
use crate::bounds::Bounds;
use crate::collect::HirPlaceholderCollector;
use crate::errors::AmbiguousLifetimeBound;
use crate::errors::{AmbiguousLifetimeBound, WildPatTy};
use crate::hir_ty_lowering::errors::{prohibit_assoc_item_binding, GenericsArgsErrExtend};
use crate::hir_ty_lowering::generics::{check_generic_arg_count, lower_generic_args};
use crate::middle::resolve_bound_vars as rbv;
@ -39,6 +39,7 @@
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
use rustc_infer::traits::ObligationCause;
use rustc_middle::middle::stability::AllowUnstable;
use rustc_middle::mir::interpret::{LitToConstError, LitToConstInput};
use rustc_middle::ty::{
self, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, ParamEnv, Ty, TyCtxt,
TypeVisitableExt,
@ -2195,6 +2196,64 @@ fn lower_ty_common(&self, hir_ty: &hir::Ty<'tcx>, borrowed: bool, in_path: bool)
// handled specially and will not descend into this routine.
self.ty_infer(None, hir_ty.span)
}
hir::TyKind::Pat(ty, pat) => {
let ty = self.lower_ty(ty);
let pat_ty = match pat.kind {
hir::PatKind::Wild => {
let err = tcx.dcx().emit_err(WildPatTy { span: pat.span });
Ty::new_error(tcx, err)
}
hir::PatKind::Range(start, end, include_end) => {
let expr_to_const = |expr: &'tcx hir::Expr<'tcx>| -> ty::Const<'tcx> {
let (expr, neg) = match expr.kind {
hir::ExprKind::Unary(hir::UnOp::Neg, negated) => {
(negated, Some((expr.hir_id, expr.span)))
}
_ => (expr, None),
};
let c = match &expr.kind {
hir::ExprKind::Lit(lit) => {
let lit_input =
LitToConstInput { lit: &lit.node, ty, neg: neg.is_some() };
match tcx.lit_to_const(lit_input) {
Ok(c) => c,
Err(LitToConstError::Reported(err)) => {
ty::Const::new_error(tcx, err, ty)
}
Err(LitToConstError::TypeError) => todo!(),
}
}
_ => {
let err = tcx
.dcx()
.emit_err(crate::errors::NonConstRange { span: expr.span });
ty::Const::new_error(tcx, err, ty)
}
};
self.record_ty(expr.hir_id, c.ty(), expr.span);
if let Some((id, span)) = neg {
self.record_ty(id, c.ty(), span);
}
c
};
let start = start.map(expr_to_const);
let end = end.map(expr_to_const);
let include_end = match include_end {
hir::RangeEnd::Included => true,
hir::RangeEnd::Excluded => false,
};
let pat = tcx.mk_pat(ty::PatternKind::Range { start, end, include_end });
Ty::new_pat(tcx, ty, pat)
}
hir::PatKind::Err(e) => Ty::new_error(tcx, e),
_ => span_bug!(pat.span, "unsupported pattern for pattern type: {pat:#?}"),
};
self.record_ty(pat.hir_id, ty, pat.span);
pat_ty
}
hir::TyKind::Err(guar) => Ty::new_error(tcx, *guar),
};

View File

@ -249,6 +249,20 @@ fn add_constraints_from_ty(
self.add_constraints_from_ty(current, typ, variance);
}
ty::Pat(typ, pat) => {
match *pat {
ty::PatternKind::Range { start, end, include_end: _ } => {
if let Some(start) = start {
self.add_constraints_from_const(current, start, variance);
}
if let Some(end) = end {
self.add_constraints_from_const(current, end, variance);
}
}
}
self.add_constraints_from_ty(current, typ, variance);
}
ty::Slice(typ) => {
self.add_constraints_from_ty(current, typ, variance);
}

View File

@ -330,6 +330,11 @@ fn print_type(&mut self, ty: &hir::Ty<'_>) {
self.word("_");
}
hir::TyKind::AnonAdt(..) => self.word("/* anonymous adt */"),
hir::TyKind::Pat(ty, pat) => {
self.print_type(ty);
self.word(" is ");
self.print_pat(pat);
}
}
self.end()
}

View File

@ -130,6 +130,7 @@ fn pointer_kind(
| ty::CoroutineWitness(..)
| ty::RawPtr(_, _)
| ty::Ref(..)
| ty::Pat(..)
| ty::FnDef(..)
| ty::FnPtr(..)
| ty::Closure(..)

View File

@ -440,6 +440,7 @@ fn fold_ty(&mut self, mut t: Ty<'tcx>) -> Ty<'tcx> {
| ty::Tuple(..)
| ty::Alias(..)
| ty::Foreign(..)
| ty::Pat(..)
| ty::Param(..) => {
if t.flags().intersects(self.needs_canonical_flags) {
t.super_fold_with(self)

View File

@ -93,6 +93,7 @@ fn compute_components<'tcx>(
}
}
ty::Pat(element, _) |
ty::Array(element, _) => {
// Don't look into the len const as it doesn't affect regions
compute_components(tcx, element, out, visited);

View File

@ -299,6 +299,9 @@ lint_improper_ctypes_only_phantomdata = composed only of `PhantomData`
lint_improper_ctypes_opaque = opaque types have no C equivalent
lint_improper_ctypes_pat_help = consider using the base type instead
lint_improper_ctypes_pat_reason = pattern types have no C equivalent
lint_improper_ctypes_slice_help = consider using a raw pointer instead
lint_improper_ctypes_slice_reason = slices have no C equivalent

View File

@ -157,6 +157,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
| TyKind::Never
| TyKind::Tup(_)
| TyKind::Path(_)
| TyKind::Pat(..)
| TyKind::AnonAdt(_)
| TyKind::OpaqueDef(_, _, _)
| TyKind::Typeof(_)

View File

@ -1379,6 +1379,12 @@ fn check_type_for_ffi(&self, cache: &mut FxHashSet<Ty<'tcx>>, ty: Ty<'tcx>) -> F
help: Some(fluent::lint_improper_ctypes_char_help),
},
ty::Pat(..) => FfiUnsafe {
ty,
reason: fluent::lint_improper_ctypes_pat_reason,
help: Some(fluent::lint_improper_ctypes_pat_help),
},
ty::Int(ty::IntTy::I128) | ty::Uint(ty::UintTy::U128) => {
FfiUnsafe { ty, reason: fluent::lint_improper_ctypes_128bit, help: None }
}

View File

@ -90,6 +90,7 @@ macro_rules! arena_types {
[decode] attribute: rustc_ast::Attribute,
[] name_set: rustc_data_structures::unord::UnordSet<rustc_span::symbol::Symbol>,
[] ordered_name_set: rustc_data_structures::fx::FxIndexSet<rustc_span::symbol::Symbol>,
[] pats: rustc_middle::ty::PatternKind<'tcx>,
// Note that this deliberately duplicates items in the `rustc_hir::arena`,
// since we need to allocate this type on both the `rustc_hir` arena

View File

@ -148,6 +148,12 @@ fn encode(&self, e: &mut E) {
}
}
impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for ty::Pattern<'tcx> {
fn encode(&self, e: &mut E) {
self.0.0.encode(e);
}
}
impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for ConstAllocation<'tcx> {
fn encode(&self, e: &mut E) {
self.inner().encode(e)
@ -364,6 +370,12 @@ fn decode(decoder: &mut D) -> Self {
}
}
impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for ty::Pattern<'tcx> {
fn decode(decoder: &mut D) -> Self {
decoder.interner().mk_pat(Decodable::decode(decoder))
}
}
impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> for [ty::ValTree<'tcx>] {
fn decode(decoder: &mut D) -> &'tcx Self {
decoder

View File

@ -26,9 +26,10 @@
};
use crate::ty::{
self, AdtDef, AdtDefData, AdtKind, Binder, Clause, Clauses, Const, ConstData,
GenericParamDefKind, ImplPolarity, List, ListWithCachedTypeInfo, ParamConst, ParamTy,
PolyExistentialPredicate, PolyFnSig, Predicate, PredicateKind, PredicatePolarity, Region,
RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyVid, TypeVisitable, Visibility,
GenericParamDefKind, ImplPolarity, List, ListWithCachedTypeInfo, ParamConst, ParamTy, Pattern,
PatternKind, PolyExistentialPredicate, PolyFnSig, Predicate, PredicateKind, PredicatePolarity,
Region, RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyVid, TypeVisitable,
Visibility,
};
use crate::ty::{GenericArg, GenericArgs, GenericArgsRef};
use rustc_ast::{self as ast, attr};
@ -95,6 +96,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
type CanonicalVars = CanonicalVarInfos<'tcx>;
type Ty = Ty<'tcx>;
type Pat = Pattern<'tcx>;
type Tys = &'tcx List<Ty<'tcx>>;
type AliasTy = ty::AliasTy<'tcx>;
type ParamTy = ParamTy;
@ -157,6 +159,7 @@ pub struct CtxtInterners<'tcx> {
projs: InternedSet<'tcx, List<ProjectionKind>>,
place_elems: InternedSet<'tcx, List<PlaceElem<'tcx>>>,
const_: InternedSet<'tcx, WithCachedTypeInfo<ConstData<'tcx>>>,
pat: InternedSet<'tcx, PatternKind<'tcx>>,
const_allocation: InternedSet<'tcx, Allocation>,
bound_variable_kinds: InternedSet<'tcx, List<ty::BoundVariableKind>>,
layout: InternedSet<'tcx, LayoutS<FieldIdx, VariantIdx>>,
@ -184,6 +187,7 @@ fn new(arena: &'tcx WorkerLocal<Arena<'tcx>>) -> CtxtInterners<'tcx> {
projs: Default::default(),
place_elems: Default::default(),
const_: Default::default(),
pat: Default::default(),
const_allocation: Default::default(),
bound_variable_kinds: Default::default(),
layout: Default::default(),
@ -1578,6 +1582,7 @@ fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
nop_lift! {type_; Ty<'a> => Ty<'tcx>}
nop_lift! {region; Region<'a> => Region<'tcx>}
nop_lift! {const_; Const<'a> => Const<'tcx>}
nop_lift! {pat; Pattern<'a> => Pattern<'tcx>}
nop_lift! {const_allocation; ConstAllocation<'a> => ConstAllocation<'tcx>}
nop_lift! {predicate; Predicate<'a> => Predicate<'tcx>}
nop_lift! {predicate; Clause<'a> => Clause<'tcx>}
@ -1715,6 +1720,7 @@ fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
Param,
Infer,
Alias,
Pat,
Foreign
)?;
@ -1866,6 +1872,7 @@ impl<'tcx> TyCtxt<'tcx> {
// crate only, and have a corresponding `mk_` function.
direct_interners! {
region: pub(crate) intern_region(RegionKind<'tcx>): Region -> Region<'tcx>,
pat: pub mk_pat(PatternKind<'tcx>): Pattern -> Pattern<'tcx>,
const_allocation: pub mk_const_alloc(Allocation): ConstAllocation -> ConstAllocation<'tcx>,
layout: pub mk_layout(LayoutS<FieldIdx, VariantIdx>): Layout -> Layout<'tcx>,
adt_def: pub mk_adt_def_from_data(AdtDefData): AdtDef -> AdtDef<'tcx>,

View File

@ -285,6 +285,7 @@ pub fn prefix_string(self, tcx: TyCtxt<'_>) -> Cow<'static, str> {
ty::Adt(def, _) => def.descr().into(),
ty::Foreign(_) => "extern type".into(),
ty::Array(..) => "array".into(),
ty::Pat(..) => "pattern type".into(),
ty::Slice(_) => "slice".into(),
ty::RawPtr(_, _) => "raw pointer".into(),
ty::Ref(.., mutbl) => match mutbl {

View File

@ -120,6 +120,7 @@ pub fn simplify_type<'tcx>(
ty::Str => Some(SimplifiedType::Str),
ty::Array(..) => Some(SimplifiedType::Array),
ty::Slice(..) => Some(SimplifiedType::Slice),
ty::Pat(ty, ..) => simplify_type(tcx, ty, treat_params),
ty::RawPtr(_, mutbl) => Some(SimplifiedType::Ptr(mutbl)),
ty::Dynamic(trait_info, ..) => match trait_info.principal_def_id() {
Some(principal_def_id) if !tcx.trait_is_auto(principal_def_id) => {
@ -231,6 +232,7 @@ pub fn types_may_unify<'tcx>(self, obligation_ty: Ty<'tcx>, impl_ty: Ty<'tcx>) -
| ty::Slice(..)
| ty::RawPtr(..)
| ty::Dynamic(..)
| ty::Pat(..)
| ty::Ref(..)
| ty::Never
| ty::Tuple(..)
@ -269,6 +271,10 @@ pub fn types_may_unify<'tcx>(self, obligation_ty: Ty<'tcx>, impl_ty: Ty<'tcx>) -
}
_ => false,
},
ty::Pat(obl_ty, _) => {
// FIXME(pattern_types): take pattern into account
matches!(k, &ty::Pat(impl_ty, _) if self.types_may_unify(obl_ty, impl_ty))
}
ty::Slice(obl_ty) => {
matches!(k, &ty::Slice(impl_ty) if self.types_may_unify(obl_ty, impl_ty))
}

View File

@ -218,6 +218,20 @@ fn add_kind(&mut self, kind: &ty::TyKind<'_>) {
self.add_const(len);
}
&ty::Pat(ty, pat) => {
self.add_ty(ty);
match *pat {
ty::PatternKind::Range { start, end, include_end: _ } => {
if let Some(start) = start {
self.add_const(start)
}
if let Some(end) = end {
self.add_const(end)
}
}
}
}
&ty::Slice(tt) => self.add_ty(tt),
&ty::RawPtr(ty, _) => {

View File

@ -316,11 +316,11 @@ pub fn has_impl_trait(&'tcx self) -> bool {
/// of this item, excluding `Self`.
///
/// **This should only be used for diagnostics purposes.**
pub fn own_args_no_defaults(
pub fn own_args_no_defaults<'a>(
&'tcx self,
tcx: TyCtxt<'tcx>,
args: &'tcx [ty::GenericArg<'tcx>],
) -> &'tcx [ty::GenericArg<'tcx>] {
args: &'a [ty::GenericArg<'tcx>],
) -> &'a [ty::GenericArg<'tcx>] {
let mut own_params = self.parent_count..self.count();
if self.has_self && self.parent.is_none() {
own_params.start = 1;

View File

@ -742,6 +742,7 @@ fn field_ty_or_layout<'tcx>(
| ty::FnDef(..)
| ty::CoroutineWitness(..)
| ty::Foreign(..)
| ty::Pat(_, _)
| ty::Dynamic(_, _, ty::Dyn) => {
bug!("TyAndLayout::field({:?}): not applicable", this)
}

View File

@ -91,6 +91,7 @@
pub use self::instance::{Instance, InstanceDef, ReifyReason, ShortInstance, UnusedGenericParams};
pub use self::list::{List, ListWithCachedTypeInfo};
pub use self::parameterized::ParameterizedOverTcx;
pub use self::pattern::{Pattern, PatternKind};
pub use self::predicate::{
Clause, ClauseKind, CoercePredicate, ExistentialPredicate, ExistentialProjection,
ExistentialTraitRef, NormalizesTo, OutlivesPredicate, PolyCoercePredicate,
@ -130,6 +131,7 @@
pub mod inhabitedness;
pub mod layout;
pub mod normalize_erasing_regions;
pub mod pattern;
pub mod print;
pub mod relate;
pub mod trait_def;

View File

@ -0,0 +1,48 @@
use std::fmt;
use crate::ty;
use rustc_data_structures::intern::Interned;
#[derive(Copy, Clone, PartialEq, Eq, Hash, HashStable)]
#[rustc_pass_by_value]
pub struct Pattern<'tcx>(pub Interned<'tcx, PatternKind<'tcx>>);
impl<'tcx> std::ops::Deref for Pattern<'tcx> {
type Target = PatternKind<'tcx>;
fn deref(&self) -> &Self::Target {
&*self.0
}
}
impl<'tcx> fmt::Debug for Pattern<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?}", **self)
}
}
impl<'tcx> fmt::Debug for PatternKind<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
PatternKind::Range { start, end, include_end } => {
if let Some(start) = start {
write!(f, "{start}")?;
}
write!(f, "..")?;
if include_end {
write!(f, "=")?;
}
if let Some(end) = end {
write!(f, "{end}")?;
}
Ok(())
}
}
}
}
#[derive(Clone, PartialEq, Eq, Hash)]
#[derive(HashStable, TyEncodable, TyDecodable, TypeVisitable, TypeFoldable)]
pub enum PatternKind<'tcx> {
Range { start: Option<ty::Const<'tcx>>, end: Option<ty::Const<'tcx>>, include_end: bool },
}

View File

@ -259,7 +259,7 @@ fn characteristic_def_id_of_type_cached<'a>(
ty::Dynamic(data, ..) => data.principal_def_id(),
ty::Array(subty, _) | ty::Slice(subty) => {
ty::Pat(subty, _) | ty::Array(subty, _) | ty::Slice(subty) => {
characteristic_def_id_of_type_cached(subty, visited)
}

View File

@ -667,6 +667,9 @@ fn pretty_print_type(&mut self, ty: Ty<'tcx>) -> Result<(), PrintError> {
ty::Int(t) => p!(write("{}", t.name_str())),
ty::Uint(t) => p!(write("{}", t.name_str())),
ty::Float(t) => p!(write("{}", t.name_str())),
ty::Pat(ty, pat) => {
p!("(", print(ty), ") is ", write("{pat:?}"))
}
ty::RawPtr(ty, mutbl) => {
p!(write(
"*{} ",

View File

@ -13,6 +13,8 @@
use rustc_target::spec::abi;
use std::iter;
use super::Pattern;
pub type RelateResult<'tcx, T> = Result<T, TypeError<'tcx>>;
pub trait TypeRelation<'tcx>: Sized {
@ -351,6 +353,36 @@ fn relate<R: TypeRelation<'tcx>>(
}
}
impl<'tcx> Relate<'tcx> for Pattern<'tcx> {
#[inline]
fn relate<R: TypeRelation<'tcx>>(
relation: &mut R,
a: Self,
b: Self,
) -> RelateResult<'tcx, Self> {
match (&*a, &*b) {
(
&ty::PatternKind::Range { start: start_a, end: end_a, include_end: inc_a },
&ty::PatternKind::Range { start: start_b, end: end_b, include_end: inc_b },
) => {
// FIXME(pattern_types): make equal patterns equal (`0..=` is the same as `..=`).
let mut relate_opt_const = |a, b| match (a, b) {
(None, None) => Ok(None),
(Some(a), Some(b)) => relation.relate(a, b).map(Some),
// FIXME(pattern_types): report a better error
_ => Err(TypeError::Mismatch),
};
let start = relate_opt_const(start_a, start_b)?;
let end = relate_opt_const(end_a, end_b)?;
if inc_a != inc_b {
todo!()
}
Ok(relation.tcx().mk_pat(ty::PatternKind::Range { start, end, include_end: inc_a }))
}
}
}
}
/// Relates `a` and `b` structurally, calling the relation for all nested values.
/// Any semantic equality, e.g. of projections, and inference variables have to be
/// handled by the caller.
@ -533,6 +565,12 @@ pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>(
Ok(Ty::new_alias(tcx, a_kind, alias_ty))
}
(&ty::Pat(a_ty, a_pat), &ty::Pat(b_ty, b_pat)) => {
let ty = relation.relate(a_ty, b_ty)?;
let pat = relation.relate(a_pat, b_pat)?;
Ok(Ty::new_pat(tcx, ty, pat))
}
_ => Err(TypeError::Sorts(expected_found(a, b))),
}
}

View File

@ -20,6 +20,8 @@
use super::print::PrettyPrinter;
use super::{GenericArg, GenericArgKind, Region};
use super::Pattern;
impl fmt::Debug for ty::TraitDef {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
ty::tls::with(|tcx| {
@ -210,6 +212,22 @@ fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>(
}
}
impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for Pattern<'tcx> {
fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>(
this: WithInfcx<'_, Infcx, &Self>,
f: &mut core::fmt::Formatter<'_>,
) -> core::fmt::Result {
match &**this.data {
ty::PatternKind::Range { start, end, include_end } => f
.debug_struct("Pattern::Range")
.field("start", start)
.field("end", end)
.field("include_end", include_end)
.finish(),
}
}
}
impl<'tcx> fmt::Debug for ty::consts::Expr<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
WithInfcx::with_no_infcx(self).fmt(f)
@ -541,6 +559,22 @@ fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>(
}
}
impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for Pattern<'tcx> {
fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>(
self,
folder: &mut F,
) -> Result<Self, F::Error> {
let pat = (*self).clone().try_fold_with(folder)?;
Ok(if pat == *self { self } else { folder.interner().mk_pat(pat) })
}
}
impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for Pattern<'tcx> {
fn visit_with<V: TypeVisitor<TyCtxt<'tcx>>>(&self, visitor: &mut V) -> V::Result {
(**self).visit_with(visitor)
}
}
impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for Ty<'tcx> {
fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>(
self,
@ -586,6 +620,7 @@ fn try_super_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>(
ty::CoroutineClosure(did, args.try_fold_with(folder)?)
}
ty::Alias(kind, data) => ty::Alias(kind, data.try_fold_with(folder)?),
ty::Pat(ty, pat) => ty::Pat(ty.try_fold_with(folder)?, pat.try_fold_with(folder)?),
ty::Bool
| ty::Char
@ -633,6 +668,11 @@ fn super_visit_with<V: TypeVisitor<TyCtxt<'tcx>>>(&self, visitor: &mut V) -> V::
ty::CoroutineClosure(_did, ref args) => args.visit_with(visitor),
ty::Alias(_, ref data) => data.visit_with(visitor),
ty::Pat(ty, pat) => {
try_visit!(ty.visit_with(visitor));
pat.visit_with(visitor)
}
ty::Bool
| ty::Char
| ty::Str

View File

@ -1522,6 +1522,11 @@ pub fn new_alias(
Ty::new(tcx, Alias(kind, alias_ty))
}
#[inline]
pub fn new_pat(tcx: TyCtxt<'tcx>, base: Ty<'tcx>, pat: ty::Pattern<'tcx>) -> Ty<'tcx> {
Ty::new(tcx, Pat(base, pat))
}
#[inline]
pub fn new_opaque(tcx: TyCtxt<'tcx>, def_id: DefId, args: GenericArgsRef<'tcx>) -> Ty<'tcx> {
Ty::new_alias(tcx, ty::Opaque, AliasTy::new(tcx, def_id, args))
@ -2278,6 +2283,8 @@ pub fn discriminant_ty(self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
Ty::new_projection(tcx, assoc_items[0], tcx.mk_args(&[self.into()]))
}
ty::Pat(ty, _) => ty.discriminant_ty(tcx),
ty::Bool
| ty::Char
| ty::Int(_)
@ -2359,6 +2366,7 @@ pub fn ptr_metadata_ty_or_tail(
ty::Param(_) | ty::Alias(..) => Err(tail),
ty::Infer(ty::TyVar(_))
| ty::Pat(..)
| ty::Bound(..)
| ty::Placeholder(..)
| ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => bug!(
@ -2495,6 +2503,7 @@ pub fn is_trivially_sized(self, tcx: TyCtxt<'tcx>) -> bool {
| ty::Coroutine(..)
| ty::CoroutineWitness(..)
| ty::Array(..)
| ty::Pat(..)
| ty::Closure(..)
| ty::CoroutineClosure(..)
| ty::Never
@ -2549,6 +2558,8 @@ pub fn is_trivially_pure_clone_copy(self) -> bool {
field_tys.len() <= 3 && field_tys.iter().all(Self::is_trivially_pure_clone_copy)
}
ty::Pat(ty, _) => ty.is_trivially_pure_clone_copy(),
// Sometimes traits aren't implemented for every ABI or arity,
// because we can't be generic over everything yet.
ty::FnPtr(..) => false,
@ -2630,6 +2641,7 @@ pub fn is_known_rigid(self) -> bool {
| Foreign(_)
| Str
| Array(_, _)
| Pat(_, _)
| Slice(_)
| RawPtr(_, _)
| Ref(_, _, _)

View File

@ -245,6 +245,11 @@ pub fn struct_tail_with_normalize(
ty::Tuple(_) => break,
ty::Pat(inner, _) => {
f();
ty = inner;
}
ty::Alias(..) => {
let normalized = normalize(ty);
if ty == normalized {
@ -1242,7 +1247,7 @@ fn is_trivially_freeze(self) -> bool {
| ty::Error(_)
| ty::FnPtr(_) => true,
ty::Tuple(fields) => fields.iter().all(Self::is_trivially_freeze),
ty::Slice(elem_ty) | ty::Array(elem_ty, _) => elem_ty.is_trivially_freeze(),
ty::Pat(ty, _) | ty::Slice(ty) | ty::Array(ty, _) => ty.is_trivially_freeze(),
ty::Adt(..)
| ty::Bound(..)
| ty::Closure(..)
@ -1282,7 +1287,7 @@ fn is_trivially_unpin(self) -> bool {
| ty::Error(_)
| ty::FnPtr(_) => true,
ty::Tuple(fields) => fields.iter().all(Self::is_trivially_unpin),
ty::Slice(elem_ty) | ty::Array(elem_ty, _) => elem_ty.is_trivially_unpin(),
ty::Pat(ty, _) | ty::Slice(ty) | ty::Array(ty, _) => ty.is_trivially_unpin(),
ty::Adt(..)
| ty::Bound(..)
| ty::Closure(..)
@ -1398,7 +1403,7 @@ pub fn is_structural_eq_shallow(self, tcx: TyCtxt<'tcx>) -> bool {
//
// Because this function is "shallow", we return `true` for these composites regardless
// of the type(s) contained within.
ty::Ref(..) | ty::Array(..) | ty::Slice(_) | ty::Tuple(..) => true,
ty::Pat(..) | ty::Ref(..) | ty::Array(..) | ty::Slice(_) | ty::Tuple(..) => true,
// Raw pointers use bitwise comparison.
ty::RawPtr(_, _) | ty::FnPtr(_) => true,
@ -1528,7 +1533,7 @@ pub fn needs_drop_components<'tcx>(
ty::Dynamic(..) | ty::Error(_) => Err(AlwaysRequiresDrop),
ty::Slice(ty) => needs_drop_components(tcx, ty),
ty::Pat(ty, _) | ty::Slice(ty) => needs_drop_components(tcx, ty),
ty::Array(elem_ty, size) => {
match needs_drop_components(tcx, elem_ty) {
Ok(v) if v.is_empty() => Ok(v),
@ -1597,7 +1602,7 @@ pub fn is_trivially_const_drop(ty: Ty<'_>) -> bool {
| ty::CoroutineWitness(..)
| ty::Adt(..) => false,
ty::Array(ty, _) | ty::Slice(ty) => is_trivially_const_drop(ty),
ty::Array(ty, _) | ty::Slice(ty) | ty::Pat(ty, _) => is_trivially_const_drop(ty),
ty::Tuple(tys) => tys.iter().all(|ty| is_trivially_const_drop(ty)),
}

View File

@ -151,6 +151,15 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>)
| ty::Bound(..)
| ty::Foreign(..) => {}
ty::Pat(ty, pat) => {
match *pat {
ty::PatternKind::Range { start, end, include_end: _ } => {
stack.extend(end.map(Into::into));
stack.extend(start.map(Into::into));
}
}
stack.push(ty.into());
}
ty::Array(ty, len) => {
stack.push(len.into());
stack.push(ty.into());

View File

@ -457,7 +457,7 @@ fn recur(
PatKind::Constant { value: mir::Const::Ty(ty::Const::new_value(tcx, cv, ty)) }
}
}
ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::RawPtr(..) => {
ty::Pat(..) | ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::RawPtr(..) => {
// The raw pointers we see here have been "vetted" by valtree construction to be
// just integers, so we simply allow them.
PatKind::Constant { value: mir::Const::Ty(ty::Const::new_value(tcx, cv, ty)) }

View File

@ -153,6 +153,7 @@ fn move_path_for(&mut self, place: Place<'tcx>) -> MovePathResult {
| ty::Foreign(_)
| ty::Str
| ty::Array(_, _)
| ty::Pat(_, _)
| ty::Slice(_)
| ty::FnDef(_, _)
| ty::FnPtr(_)
@ -193,6 +194,7 @@ fn move_path_for(&mut self, place: Place<'tcx>) -> MovePathResult {
| ty::Foreign(_)
| ty::Str
| ty::Array(_, _)
| ty::Pat(_, _)
| ty::Slice(_)
| ty::RawPtr(_, _)
| ty::Ref(_, _, _)

View File

@ -684,6 +684,7 @@ fn try_write_constant<'tcx>(
// Unsupported for now.
ty::Array(_, _)
| ty::Pat(_, _)
// Do not attempt to support indirection in constants.
| ty::Ref(..) | ty::RawPtr(..) | ty::FnPtr(..) | ty::Str | ty::Slice(_)

View File

@ -349,6 +349,7 @@ fn fold_ty(&mut self, t: I::Ty) -> I::Ty {
| ty::Slice(_)
| ty::RawPtr(_, _)
| ty::Ref(_, _, _)
| ty::Pat(_, _)
| ty::FnDef(_, _)
| ty::FnPtr(_)
| ty::Dynamic(_, _, _)

View File

@ -161,4 +161,8 @@ fn visit_impl_item(&mut self, i: &'hir hir::ImplItem<'hir>) {
let mut inner_visitor = self.new_visitor(self.tcx);
inner_visitor.check(i.owner_id, |this| intravisit::walk_impl_item(this, i));
}
fn visit_pattern_type_pattern(&mut self, p: &'hir hir::Pat<'hir>) {
self.visit_pat(p)
}
}

View File

@ -352,6 +352,7 @@ fn visit_ty(&mut self, t: &'v hir::Ty<'v>) {
TraitObject,
Typeof,
Infer,
Pat,
Err
]
);
@ -611,6 +612,7 @@ fn visit_ty(&mut self, t: &'v ast::Ty) {
AnonStruct,
AnonUnion,
Path,
Pat,
TraitObject,
ImplTrait,
Paren,

View File

@ -399,6 +399,7 @@ pub fn ctors_for_ty(
| ty::RawPtr(_, _)
| ty::FnDef(_, _)
| ty::FnPtr(_)
| ty::Pat(_, _)
| ty::Dynamic(_, _, _)
| ty::Closure(..)
| ty::CoroutineClosure(..)

View File

@ -276,6 +276,7 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
| ty::Tuple(..)
| ty::RawPtr(..)
| ty::Ref(..)
| ty::Pat(..)
| ty::FnPtr(..)
| ty::Param(..)
| ty::Bound(..)

View File

@ -14,8 +14,8 @@
use stable_mir::ty::{
Abi, AdtDef, Binder, BoundRegionKind, BoundTyKind, BoundVariableKind, ClosureKind, Const,
DynKind, ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, FloatTy, FnSig,
GenericArgKind, GenericArgs, IndexedVal, IntTy, Movability, Region, RigidTy, Span, TermKind,
TraitRef, Ty, UintTy, VariantDef, VariantIdx,
GenericArgKind, GenericArgs, IndexedVal, IntTy, Movability, Pattern, Region, RigidTy, Span,
TermKind, TraitRef, Ty, UintTy, VariantDef, VariantIdx,
};
use stable_mir::{CrateItem, CrateNum, DefId};
@ -76,6 +76,19 @@ fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<
}
}
impl RustcInternal for Pattern {
type T<'tcx> = rustc_ty::Pattern<'tcx>;
fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> {
tcx.mk_pat(match self {
Pattern::Range { start, end, include_end } => rustc_ty::PatternKind::Range {
start: start.as_ref().map(|c| ty_const(c, tables, tcx)),
end: end.as_ref().map(|c| ty_const(c, tables, tcx)),
include_end: *include_end,
},
})
}
}
impl RustcInternal for RigidTy {
type T<'tcx> = rustc_ty::TyKind<'tcx>;
@ -90,6 +103,9 @@ fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<
RigidTy::Array(ty, cnst) => {
rustc_ty::TyKind::Array(ty.internal(tables, tcx), ty_const(cnst, tables, tcx))
}
RigidTy::Pat(ty, pat) => {
rustc_ty::TyKind::Pat(ty.internal(tables, tcx), pat.internal(tables, tcx))
}
RigidTy::Adt(def, args) => {
rustc_ty::TyKind::Adt(def.internal(tables, tcx), args.internal(tables, tcx))
}

View File

@ -330,6 +330,9 @@ fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
ty::Array(ty, constant) => {
TyKind::RigidTy(RigidTy::Array(ty.stable(tables), constant.stable(tables)))
}
ty::Pat(ty, pat) => {
TyKind::RigidTy(RigidTy::Pat(ty.stable(tables), pat.stable(tables)))
}
ty::Slice(ty) => TyKind::RigidTy(RigidTy::Slice(ty.stable(tables))),
ty::RawPtr(ty, mutbl) => {
TyKind::RigidTy(RigidTy::RawPtr(ty.stable(tables), mutbl.stable(tables)))
@ -385,6 +388,20 @@ fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
}
}
impl<'tcx> Stable<'tcx> for ty::Pattern<'tcx> {
type T = stable_mir::ty::Pattern;
fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
match **self {
ty::PatternKind::Range { start, end, include_end } => stable_mir::ty::Pattern::Range {
start: start.stable(tables),
end: end.stable(tables),
include_end,
},
}
}
}
impl<'tcx> Stable<'tcx> for ty::Const<'tcx> {
type T = stable_mir::ty::Const;

View File

@ -1009,6 +1009,7 @@
io_stderr,
io_stdout,
irrefutable_let_patterns,
is,
is_val_statically_known,
isa_attribute,
isize,
@ -1347,6 +1348,8 @@
path,
pattern_complexity,
pattern_parentheses,
pattern_type,
pattern_types,
phantom_data,
pic,
pie,

View File

@ -533,6 +533,16 @@ fn encode_ty<'tcx>(
typeid.push_str(&s);
}
ty::Pat(ty0, pat) => {
// u3patI<element-type><pattern>E as vendor extended type
let mut s = String::from("u3patI");
s.push_str(&encode_ty(tcx, *ty0, dict, options));
write!(s, "{:?}", **pat).unwrap();
s.push('E');
compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
typeid.push_str(&s);
}
ty::Slice(ty0) => {
// u5sliceI<element-type>E as vendor extended type
let mut s = String::from("u5sliceI");
@ -782,6 +792,7 @@ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
| ty::Foreign(..)
| ty::Never
| ty::Slice(..)
| ty::Pat(..)
| ty::Str
| ty::Tuple(..) => t.super_fold_with(self),

View File

@ -371,6 +371,25 @@ fn print_type(&mut self, ty: Ty<'tcx>) -> Result<(), PrintError> {
ty.print(self)?;
}
ty::Pat(ty, pat) => match *pat {
ty::PatternKind::Range { start, end, include_end } => {
let consts = [
start.unwrap_or(self.tcx.consts.unit),
end.unwrap_or(self.tcx.consts.unit),
ty::Const::from_bool(self.tcx, include_end).into(),
];
// HACK: Represent as tuple until we have something better.
// HACK: constants are used in arrays, even if the types don't match.
self.push("T");
ty.print(self)?;
for ct in consts {
Ty::new_array_with_const_len(self.tcx, self.tcx.types.unit, ct)
.print(self)?;
}
self.push("E");
}
},
ty::Array(ty, len) => {
self.push("A");
ty.print(self)?;

View File

@ -363,6 +363,7 @@ fn assemble_non_blanket_impl_candidates<G: GoalKind<'tcx>>(
| ty::Foreign(_)
| ty::Str
| ty::Array(_, _)
| ty::Pat(_, _)
| ty::Slice(_)
| ty::RawPtr(_, _)
| ty::Ref(_, _, _)
@ -596,6 +597,7 @@ fn assemble_alias_bound_candidates_recur<G: GoalKind<'tcx>>(
| ty::Foreign(_)
| ty::Str
| ty::Array(_, _)
| ty::Pat(_, _)
| ty::Slice(_)
| ty::RawPtr(_, _)
| ty::Ref(_, _, _)
@ -684,6 +686,7 @@ fn assemble_object_bound_candidates<G: GoalKind<'tcx>>(
| ty::Foreign(_)
| ty::Str
| ty::Array(_, _)
| ty::Pat(_, _)
| ty::Slice(_)
| ty::RawPtr(_, _)
| ty::Ref(_, _, _)

View File

@ -50,7 +50,9 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>(
Ok(vec![ty::Binder::dummy(element_ty)])
}
ty::Array(element_ty, _) | ty::Slice(element_ty) => Ok(vec![ty::Binder::dummy(element_ty)]),
ty::Pat(element_ty, _) | ty::Array(element_ty, _) | ty::Slice(element_ty) => {
Ok(vec![ty::Binder::dummy(element_ty)])
}
ty::Tuple(tys) => {
// (T1, ..., Tn) -- meets any bound that all of T1...Tn meet
@ -114,6 +116,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait<'tcx>(
| ty::Coroutine(..)
| ty::CoroutineWitness(..)
| ty::Array(..)
| ty::Pat(..)
| ty::Closure(..)
| ty::CoroutineClosure(..)
| ty::Never
@ -177,6 +180,10 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>(
| ty::Ref(_, _, Mutability::Not)
| ty::Array(..) => Err(NoSolution),
// Cannot implement in core, as we can't be generic over patterns yet,
// so we'd have to list all patterns and type combinations.
ty::Pat(ty, ..) => Ok(vec![ty::Binder::dummy(ty)]),
ty::Dynamic(..)
| ty::Str
| ty::Slice(_)
@ -347,6 +354,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<'tcx>(
| ty::CoroutineWitness(..)
| ty::Never
| ty::Tuple(_)
| ty::Pat(_, _)
| ty::Alias(_, _)
| ty::Param(_)
| ty::Placeholder(..)
@ -526,6 +534,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc
| ty::Foreign(_)
| ty::Str
| ty::Array(_, _)
| ty::Pat(_, _)
| ty::Slice(_)
| ty::RawPtr(_, _)
| ty::Ref(_, _, _)

View File

@ -533,6 +533,7 @@ fn consider_builtin_pointee_candidate(
| ty::Uint(..)
| ty::Float(..)
| ty::Array(..)
| ty::Pat(..)
| ty::RawPtr(..)
| ty::Ref(..)
| ty::FnDef(..)
@ -768,6 +769,7 @@ fn consider_builtin_discriminant_kind_candidate(
| ty::Uint(..)
| ty::Float(..)
| ty::Array(..)
| ty::Pat(..)
| ty::RawPtr(..)
| ty::Ref(..)
| ty::FnDef(..)

View File

@ -1051,6 +1051,7 @@ fn disqualify_auto_trait_candidate_due_to_possible_impl(
| ty::Float(_)
| ty::Str
| ty::Array(_, _)
| ty::Pat(_, _)
| ty::Slice(_)
| ty::RawPtr(_, _)
| ty::Ref(_, _, _)

View File

@ -883,6 +883,7 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
| ty::Float(..)
| ty::Str
| ty::FnDef(..)
| ty::Pat(..)
| ty::FnPtr(_)
| ty::Array(..)
| ty::Slice(..)

View File

@ -1804,6 +1804,7 @@ fn type_category(tcx: TyCtxt<'_>, t: Ty<'_>) -> Option<u32> {
ty::Foreign(..) => Some(19),
ty::CoroutineWitness(..) => Some(20),
ty::CoroutineClosure(..) => Some(21),
ty::Pat(..) => Some(22),
ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error(_) => None,
}
}

View File

@ -1048,6 +1048,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
| ty::Foreign(_)
| ty::Str
| ty::Array(..)
| ty::Pat(..)
| ty::Slice(_)
| ty::RawPtr(..)
| ty::Ref(..)
@ -1099,6 +1100,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
| ty::Float(_)
| ty::Str
| ty::Array(..)
| ty::Pat(..)
| ty::Slice(_)
| ty::RawPtr(..)
| ty::Ref(..)

View File

@ -42,8 +42,8 @@ pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
| ty::Foreign(..)
| ty::Error(_) => true,
// [T; N] and [T] have same properties as T.
ty::Array(ty, _) | ty::Slice(ty) => trivial_dropck_outlives(tcx, *ty),
// `T is PAT`, `[T; N]`, and `[T]` have same properties as T.
ty::Pat(ty, _) | ty::Array(ty, _) | ty::Slice(ty) => trivial_dropck_outlives(tcx, *ty),
// (T1..Tn) and closures have same properties as T1..Tn --
// check if *all* of them are trivial.
@ -222,7 +222,7 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>(
// these types never have a destructor
}
ty::Array(ety, _) | ty::Slice(ety) => {
ty::Pat(ety, _) | ty::Array(ety, _) | ty::Slice(ety) => {
// single-element containers, behave like their element
rustc_data_structures::stack::ensure_sufficient_stack(|| {
dtorck_constraint_for_ty_inner(tcx, param_env, span, depth + 1, *ety, constraints)

View File

@ -670,6 +670,7 @@ fn reject_fn_ptr_impls(
| ty::Foreign(_)
| ty::Str
| ty::Array(_, _)
| ty::Pat(_, _)
| ty::Slice(_)
| ty::RawPtr(_, _)
| ty::Ref(_, _, _)
@ -803,6 +804,7 @@ fn assemble_candidates_from_auto_impls(
| ty::Float(_)
| ty::Str
| ty::Array(_, _)
| ty::Pat(_, _)
| ty::Slice(_)
| ty::Adt(..)
| ty::RawPtr(_, _)
@ -1193,6 +1195,7 @@ fn assemble_const_destruct_candidates(
| ty::Never
| ty::Foreign(_)
| ty::Array(..)
| ty::Pat(..)
| ty::Slice(_)
| ty::Closure(..)
| ty::CoroutineClosure(..)
@ -1270,6 +1273,7 @@ fn assemble_candidate_for_tuple(
| ty::RawPtr(_, _)
| ty::Ref(_, _, _)
| ty::FnDef(_, _)
| ty::Pat(_, _)
| ty::FnPtr(_)
| ty::Dynamic(_, _, _)
| ty::Closure(..)
@ -1329,6 +1333,7 @@ fn assemble_candidates_for_fn_ptr_trait(
| ty::Foreign(..)
| ty::Str
| ty::Array(..)
| ty::Pat(..)
| ty::Slice(_)
| ty::RawPtr(_, _)
| ty::Ref(..)

View File

@ -1417,7 +1417,7 @@ fn confirm_const_destruct_candidate(
// These types are built-in, so we can fast-track by registering
// nested predicates for their constituent type(s)
ty::Array(ty, _) | ty::Slice(ty) => {
ty::Array(ty, _) | ty::Slice(ty) | ty::Pat(ty, _) => {
stack.push(ty);
}
ty::Tuple(tys) => {
@ -1469,7 +1469,15 @@ fn confirm_const_destruct_candidate(
// If we have any other type (e.g. an ADT), just register a nested obligation
// since it's either not `const Drop` (and we raise an error during selection),
// or it's an ADT (and we need to check for a custom impl during selection)
_ => {
ty::Error(_)
| ty::Dynamic(..)
| ty::CoroutineClosure(..)
| ty::Param(_)
| ty::Bound(..)
| ty::Adt(..)
| ty::Alias(ty::Opaque | ty::Weak, _)
| ty::Infer(_)
| ty::Placeholder(_) => {
let predicate = self_ty.rebind(ty::TraitPredicate {
trait_ref: ty::TraitRef::from_lang_item(
self.tcx(),

View File

@ -2142,6 +2142,8 @@ fn sized_conditions(
obligation.predicate.rebind(tys.last().map_or_else(Vec::new, |&last| vec![last])),
),
ty::Pat(ty, _) => Where(obligation.predicate.rebind(vec![*ty])),
ty::Adt(def, args) => {
if let Some(sized_crit) = def.sized_constraint(self.tcx()) {
// (*) binder moved here
@ -2202,6 +2204,11 @@ fn copy_clone_conditions(
Where(obligation.predicate.rebind(tys.iter().collect()))
}
ty::Pat(ty, _) => {
// (*) binder moved here
Where(obligation.predicate.rebind(vec![ty]))
}
ty::Coroutine(coroutine_def_id, args) => {
match self.tcx().coroutine_movability(coroutine_def_id) {
hir::Movability::Static => None,
@ -2340,7 +2347,7 @@ fn constituent_types_for_ty(
ty::RawPtr(element_ty, _) | ty::Ref(_, element_ty, _) => t.rebind(vec![element_ty]),
ty::Array(element_ty, _) | ty::Slice(element_ty) => t.rebind(vec![element_ty]),
ty::Pat(ty, _) | ty::Array(ty, _) | ty::Slice(ty) => t.rebind(vec![ty]),
ty::Tuple(tys) => {
// (T1, ..., Tn) -- meets any bound that all of T1...Tn meet

View File

@ -126,7 +126,7 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
return ControlFlow::Continue(());
}
ty::Array(..) | ty::Slice(_) | ty::Ref(..) | ty::Tuple(..) => {
ty::Pat(..) | ty::Array(..) | ty::Slice(_) | ty::Ref(..) | ty::Tuple(..) => {
// First check all contained types and then tell the caller to continue searching.
return ty.super_visit_with(self);
}

View File

@ -681,6 +681,10 @@ fn visit_ty(&mut self, t: <TyCtxt<'tcx> as ty::Interner>::Ty) -> Self::Result {
// Note that we handle the len is implicitly checked while walking `arg`.
}
ty::Pat(subty, _) => {
self.require_sized(subty, traits::MiscObligation);
}
ty::Tuple(tys) => {
if let Some((_last, rest)) = tys.split_last() {
for &elem in rest {

View File

@ -126,6 +126,39 @@ fn layout_of_uncached<'tcx>(
debug_assert!(!ty.has_non_region_infer());
Ok(match *ty.kind() {
ty::Pat(ty, pat) => {
let layout = cx.layout_of(ty)?.layout;
let mut layout = LayoutS::clone(&layout.0);
match *pat {
ty::PatternKind::Range { start, end, include_end } => {
if let Abi::Scalar(scalar) | Abi::ScalarPair(scalar, _) = &mut layout.abi {
if let Some(start) = start {
scalar.valid_range_mut().start = start.eval_bits(tcx, param_env);
}
if let Some(end) = end {
let mut end = end.eval_bits(tcx, param_env);
if !include_end {
end = end.wrapping_sub(1);
}
scalar.valid_range_mut().end = end;
}
let niche = Niche {
offset: Size::ZERO,
value: scalar.primitive(),
valid_range: scalar.valid_range(cx),
};
layout.largest_niche = Some(niche);
tcx.mk_layout(layout)
} else {
bug!("pattern type with range but not scalar layout: {ty:?}, {layout:?}")
}
}
}
}
// Basic scalars.
ty::Bool => tcx.mk_layout(LayoutS::scalar(
cx,

View File

@ -221,6 +221,7 @@ fn next(&mut self) -> Option<NeedsDropResult<Ty<'tcx>>> {
| ty::Ref(..)
| ty::RawPtr(..)
| ty::FnDef(..)
| ty::Pat(..)
| ty::FnPtr(..)
| ty::Tuple(_)
| ty::Bound(..)

View File

@ -36,6 +36,8 @@ fn sized_constraint_for_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'
// these are never sized
Str | Slice(..) | Dynamic(_, _, ty::Dyn) | Foreign(..) => Some(ty),
Pat(ty, _) => sized_constraint_for_ty(tcx, *ty),
Tuple(tys) => tys.last().and_then(|&ty| sized_constraint_for_ty(tcx, ty)),
// recursive case

View File

@ -49,6 +49,7 @@ pub trait Interner: Sized + Copy {
type BoundExistentialPredicates: Copy + DebugWithInfcx<Self> + Hash + Eq;
type PolyFnSig: Copy + DebugWithInfcx<Self> + Hash + Eq;
type AllocId: Copy + Debug + Hash + Eq;
type Pat: Copy + Debug + Hash + Eq + DebugWithInfcx<Self>;
// Kinds of consts
type Const: Copy

View File

@ -100,6 +100,13 @@ pub enum TyKind<I: Interner> {
/// An array with the given length. Written as `[T; N]`.
Array(I::Ty, I::Const),
/// A pattern newtype. Takes any type and restricts its valid values to its pattern.
/// This will also change the layout to take advantage of this restriction.
/// Only `Copy` and `Clone` will automatically get implemented for pattern types.
/// Auto-traits treat this as if it were an aggregate with a single nested type.
/// Only supports integer range patterns for now.
Pat(I::Ty, I::Pat),
/// The pointee of an array slice. Written as `[T]`.
Slice(I::Ty),
@ -273,12 +280,13 @@ const fn tykind_discriminant<I: Interner>(value: &TyKind<I>) -> usize {
CoroutineWitness(_, _) => 18,
Never => 19,
Tuple(_) => 20,
Alias(_, _) => 21,
Param(_) => 22,
Bound(_, _) => 23,
Placeholder(_) => 24,
Infer(_) => 25,
Error(_) => 26,
Pat(_, _) => 21,
Alias(_, _) => 22,
Param(_) => 23,
Bound(_, _) => 24,
Placeholder(_) => 25,
Infer(_) => 26,
Error(_) => 27,
}
}
@ -299,6 +307,7 @@ fn eq(&self, other: &TyKind<I>) -> bool {
(Adt(a_d, a_s), Adt(b_d, b_s)) => a_d == b_d && a_s == b_s,
(Foreign(a_d), Foreign(b_d)) => a_d == b_d,
(Array(a_t, a_c), Array(b_t, b_c)) => a_t == b_t && a_c == b_c,
(Pat(a_t, a_c), Pat(b_t, b_c)) => a_t == b_t && a_c == b_c,
(Slice(a_t), Slice(b_t)) => a_t == b_t,
(RawPtr(a_t, a_m), RawPtr(b_t, b_m)) => a_t == b_t && a_m == b_m,
(Ref(a_r, a_t, a_m), Ref(b_r, b_t, b_m)) => a_r == b_r && a_t == b_t && a_m == b_m,
@ -322,7 +331,7 @@ fn eq(&self, other: &TyKind<I>) -> bool {
_ => {
debug_assert!(
tykind_discriminant(self) != tykind_discriminant(other),
"This branch must be unreachable, maybe the match is missing an arm? self = self = {self:?}, other = {other:?}"
"This branch must be unreachable, maybe the match is missing an arm? self = {self:?}, other = {other:?}"
);
false
}
@ -362,6 +371,7 @@ fn fmt<Infcx: InferCtxtLike<Interner = I>>(
Foreign(d) => f.debug_tuple("Foreign").field(d).finish(),
Str => write!(f, "str"),
Array(t, c) => write!(f, "[{:?}; {:?}]", &this.wrap(t), &this.wrap(c)),
Pat(t, p) => write!(f, "pattern_type!({:?} is {:?})", &this.wrap(t), &this.wrap(p)),
Slice(t) => write!(f, "[{:?}]", &this.wrap(t)),
RawPtr(ty, mutbl) => {
match mutbl {

View File

@ -99,6 +99,12 @@ pub fn kind(&self) -> TyKind {
}
}
/// Represents a pattern in the type system
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum Pattern {
Range { start: Option<Const>, end: Option<Const>, include_end: bool },
}
/// Represents a constant in MIR or from the Type system.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Const {
@ -481,6 +487,7 @@ pub enum RigidTy {
Foreign(ForeignDef),
Str,
Array(Ty, Const),
Pat(Ty, Pattern),
Slice(Ty),
RawPtr(Ty, Mutability),
Ref(Region, Ty, Mutability),

View File

@ -139,6 +139,7 @@ fn super_visit<V: Visitor>(&self, visitor: &mut V) -> ControlFlow<V::Break> {
t.visit(visitor)?;
c.visit(visitor)
}
RigidTy::Pat(t, _p) => t.visit(visitor),
RigidTy::Slice(inner) => inner.visit(visitor),
RigidTy::RawPtr(ty, _) => ty.visit(visitor),
RigidTy::Ref(reg, ty, _) => {

View File

@ -396,6 +396,9 @@ pub mod assert_matches {
pub mod option;
pub mod panic;
pub mod panicking;
#[cfg(not(bootstrap))]
#[unstable(feature = "core_pattern_types", issue = "none")]
pub mod pat;
pub mod pin;
pub mod result;
pub mod sync;

14
library/core/src/pat.rs Normal file
View File

@ -0,0 +1,14 @@
//! Helper module for exporting the `pattern_type` macro
/// Creates a pattern type.
/// ```ignore (cannot test this from within core yet)
/// type Positive = std::pat::pattern_type!(i32 is 1..);
/// ```
#[macro_export]
#[rustc_builtin_macro(pattern_type)]
#[unstable(feature = "core_pattern_type", issue = "none")]
macro_rules! pattern_type {
($($arg:tt)*) => {
/* compiler built-in */
};
}

View File

@ -576,6 +576,9 @@
pub mod num;
pub mod os;
pub mod panic;
#[cfg(not(bootstrap))]
#[unstable(feature = "core_pattern_types", issue = "none")]
pub mod pat;
pub mod path;
pub mod process;
pub mod sync;

3
library/std/src/pat.rs Normal file
View File

@ -0,0 +1,3 @@
//! Helper module for exporting the `pattern_type` macro
pub use core::pattern_type;

View File

@ -1782,6 +1782,7 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T
BorrowedRef { lifetime, mutability: m.mutbl, type_: Box::new(clean_ty(m.ty, cx)) }
}
TyKind::Slice(ty) => Slice(Box::new(clean_ty(ty, cx))),
TyKind::Pat(ty, pat) => Type::Pat(Box::new(clean_ty(ty, cx)), format!("{pat:?}").into()),
TyKind::Array(ty, ref length) => {
let length = match length {
hir::ArrayLen::Infer(..) => "_".to_string(),
@ -2008,6 +2009,10 @@ pub(crate) fn clean_middle_ty<'tcx>(
ty::Float(float_ty) => Primitive(float_ty.into()),
ty::Str => Primitive(PrimitiveType::Str),
ty::Slice(ty) => Slice(Box::new(clean_middle_ty(bound_ty.rebind(ty), cx, None, None))),
ty::Pat(ty, pat) => Type::Pat(
Box::new(clean_middle_ty(bound_ty.rebind(ty), cx, None, None)),
format!("{pat:?}").into_boxed_str(),
),
ty::Array(ty, mut n) => {
n = n.normalize(cx.tcx, ty::ParamEnv::reveal_all());
let n = print_const(cx, n);

View File

@ -1483,7 +1483,9 @@ pub(crate) enum Type {
///
/// This is mostly Rustdoc's version of [`hir::Path`].
/// It has to be different because Rustdoc's [`PathSegment`] can contain cleaned generics.
Path { path: Path },
Path {
path: Path,
},
/// A `dyn Trait` object: `dyn for<'a> Trait<'a> + Send + 'static`
DynTrait(Vec<PolyTrait>, Option<Lifetime>),
/// A type parameter.
@ -1500,10 +1502,15 @@ pub(crate) enum Type {
///
/// The `String` field is a stringified version of the array's length parameter.
Array(Box<Type>, Box<str>),
Pat(Box<Type>, Box<str>),
/// A raw pointer type: `*const i32`, `*mut i32`
RawPointer(Mutability, Box<Type>),
/// A reference type: `&i32`, `&'a mut Foo`
BorrowedRef { lifetime: Option<Lifetime>, mutability: Mutability, type_: Box<Type> },
BorrowedRef {
lifetime: Option<Lifetime>,
mutability: Mutability,
type_: Box<Type>,
},
/// A qualified path to an associated item: `<Type as Trait>::Name`
QPath(Box<QPathData>),
@ -1700,6 +1707,7 @@ fn inner_def_id(&self, cache: Option<&Cache>) -> Option<DefId> {
BareFunction(..) => PrimitiveType::Fn,
Slice(..) => PrimitiveType::Slice,
Array(..) => PrimitiveType::Array,
Type::Pat(..) => PrimitiveType::Pat,
RawPointer(..) => PrimitiveType::RawPointer,
QPath(box QPathData { ref self_type, .. }) => return self_type.inner_def_id(cache),
Generic(_) | Infer | ImplTrait(_) => return None,
@ -1753,6 +1761,7 @@ pub(crate) enum PrimitiveType {
Str,
Slice,
Array,
Pat,
Tuple,
Unit,
RawPointer,
@ -1907,6 +1916,7 @@ pub(crate) fn as_sym(&self) -> Symbol {
Bool => sym::bool,
Char => sym::char,
Array => sym::array,
Pat => sym::pat,
Slice => sym::slice,
Tuple => sym::tuple,
Unit => sym::unit,

View File

@ -1071,6 +1071,10 @@ fn fmt_type<'cx>(
write!(f, "]")
}
},
clean::Type::Pat(ref t, ref pat) => {
fmt::Display::fmt(&t.print(cx), f)?;
write!(f, " is {pat}")
}
clean::Array(ref t, ref n) => match **t {
clean::Generic(name) if !f.alternate() => primitive_link(
f,

View File

@ -668,7 +668,7 @@ fn get_index_type_id(
}
}
// Not supported yet
clean::Generic(_) | clean::ImplTrait(_) | clean::Infer => None,
clean::Type::Pat(..) | clean::Generic(_) | clean::ImplTrait(_) | clean::Infer => None,
}
}

View File

@ -573,6 +573,10 @@ fn from_tcx(ty: clean::Type, tcx: TyCtxt<'_>) -> Self {
Tuple(t) => Type::Tuple(t.into_tcx(tcx)),
Slice(t) => Type::Slice(Box::new((*t).into_tcx(tcx))),
Array(t, s) => Type::Array { type_: Box::new((*t).into_tcx(tcx)), len: s.to_string() },
clean::Type::Pat(t, p) => Type::Pat {
type_: Box::new((*t).into_tcx(tcx)),
__pat_unstable_do_not_use: p.to_string(),
},
ImplTrait(g) => Type::ImplTrait(g.into_tcx(tcx)),
Infer => Type::Infer,
RawPointer(mutability, type_) => Type::RawPointer {

View File

@ -491,6 +491,7 @@ fn def_id_to_res(&self, ty_id: DefId) -> Option<Res> {
ty::Str => Res::Primitive(Str),
ty::Tuple(tys) if tys.is_empty() => Res::Primitive(Unit),
ty::Tuple(_) => Res::Primitive(Tuple),
ty::Pat(..) => Res::Primitive(Pat),
ty::Array(..) => Res::Primitive(Array),
ty::Slice(_) => Res::Primitive(Slice),
ty::RawPtr(_, _) => Res::Primitive(RawPointer),

View File

@ -8,7 +8,7 @@
use std::path::PathBuf;
/// rustdoc format-version.
pub const FORMAT_VERSION: u32 = 28;
pub const FORMAT_VERSION: u32 = 29;
/// A `Crate` is the root of the emitted JSON blob. It contains all type/documentation information
/// about the language items in the local crate, as well as info about external items to allow
@ -562,6 +562,13 @@ pub enum Type {
type_: Box<Type>,
len: String,
},
/// `u32 is 1..`
Pat {
#[serde(rename = "type")]
type_: Box<Type>,
#[doc(hidden)]
__pat_unstable_do_not_use: String,
},
/// `impl TraitA + TraitB + ...`
ImplTrait(Vec<GenericBound>),
/// `_`

View File

@ -821,6 +821,7 @@ fn for_hir_ty<'tcx>(ty: &'tcx hir::Ty<'tcx>) -> Self {
| TyKind::Array(..)
| TyKind::Ptr(_)
| TyKind::BareFn(_)
| TyKind::Pat(..)
| TyKind::Never
| TyKind::Tup(_)
| TyKind::Path(_) => Self::Deref,
@ -869,6 +870,7 @@ fn for_mir_ty<'tcx>(tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ty: Ty<'tcx>,
| ty::Int(_)
| ty::Uint(_)
| ty::Array(..)
| ty::Pat(..)
| ty::Float(_)
| ty::RawPtr(..)
| ty::FnPtr(_)

View File

@ -1068,6 +1068,10 @@ pub fn hash_tykind(&mut self, ty: &TyKind<'_>) {
self.hash_ty(ty);
self.hash_array_length(len);
},
TyKind::Pat(ty, pat) => {
self.hash_ty(ty);
self.hash_pat(pat);
},
TyKind::Ptr(ref mut_ty) => {
self.hash_ty(mut_ty.ty);
mut_ty.mutbl.hash(&mut self.s);

View File

@ -262,6 +262,7 @@ fn check_type(&mut self, x: &'a Type) {
Type::DynTrait(dyn_trait) => self.check_dyn_trait(dyn_trait),
Type::Generic(_) => {}
Type::Primitive(_) => {}
Type::Pat { type_, __pat_unstable_do_not_use: _ } => self.check_type(type_),
Type::FunctionPointer(fp) => self.check_function_pointer(&**fp),
Type::Tuple(tys) => tys.iter().for_each(|ty| self.check_type(ty)),
Type::Slice(inner) => self.check_type(&**inner),

View File

@ -867,6 +867,11 @@ fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String>
self.span,
shape,
),
ast::TyKind::Pat(ref ty, ref pat) => {
let ty = ty.rewrite(context, shape)?;
let pat = pat.rewrite(context, shape)?;
Some(format!("{ty} is {pat}"))
}
}
}
}

View File

@ -0,0 +1,23 @@
//! Check that symbol names with pattern types in them are
//! different from the same symbol with the base type
//@ compile-flags: -Csymbol-mangling-version=v0 -Copt-level=0 --crate-type=lib
#![feature(pattern_types)]
#![feature(core_pattern_types)]
#![feature(core_pattern_type)]
use std::pat::pattern_type;
type NanoU32 = crate::pattern_type!(u32 is 0..=999_999_999);
fn foo<T>() {}
pub fn bar() {
// CHECK: call pattern_type_symbols::foo::<u32>
// CHECK: call void @_RINvCs3QvG2ESzx2Q_20pattern_type_symbols3foomEB2_
foo::<u32>();
// CHECK: call pattern_type_symbols::foo::<(u32, [(); 0], [(); 999999999], [(); true])>
// CHECK: call void @_RINvCs3QvG2ESzx2Q_20pattern_type_symbols3fooTmAum0_Aum3b9ac9ff_Aub1_EEB2_
foo::<NanoU32>();
}

View File

@ -22,6 +22,7 @@ fn main() {
TyKind::Foreign(..) => (), //~ ERROR usage of `ty::TyKind::<kind>`
TyKind::Str => (), //~ ERROR usage of `ty::TyKind::<kind>`
TyKind::Array(..) => (), //~ ERROR usage of `ty::TyKind::<kind>`
TyKind::Pat(..) => (), //~ ERROR usage of `ty::TyKind::<kind>`
TyKind::Slice(..) => (), //~ ERROR usage of `ty::TyKind::<kind>`
TyKind::RawPtr(..) => (), //~ ERROR usage of `ty::TyKind::<kind>`
TyKind::Ref(..) => (), //~ ERROR usage of `ty::TyKind::<kind>`

Some files were not shown because too many files have changed in this diff Show More