diff options
Diffstat (limited to 'compiler')
83 files changed, 635 insertions, 35 deletions
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index e29ef591bcb..63ce6685e43 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -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. diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 7337b969242..da57def263d 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -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); diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 18986fb7504..9e9ae52962d 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -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)); diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs index 1c34fd0afbb..4c552289a81 100644 --- a/compiler/rustc_ast_lowering/src/index.rs +++ b/compiler/rustc_ast_lowering/src/index.rs @@ -381,4 +381,8 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { ArrayLen::Body(..) => intravisit::walk_array_len(self, len), } } + + fn visit_pattern_type_pattern(&mut self, p: &'hir hir::Pat<'hir>) { + self.visit_pat(p) + } } diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 8cf347bfa96..5005c22d4cc 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1463,7 +1463,10 @@ impl<'a, 'hir> LoweringContext<'a, '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, diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 5912dd3f931..d7cd3efe408 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -332,6 +332,9 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { 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) diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 3ea182c5867..51ccfe89fbd 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -1188,6 +1188,11 @@ impl<'a> State<'a> { ast::TyKind::CVarArgs => { self.word("..."); } + ast::TyKind::Pat(ty, pat) => { + self.print_type(ty); + self.word(" is "); + self.print_pat(pat); + } } self.end(); } diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 4a5ba441878..9c23c2f9e01 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -1606,6 +1606,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { | ty::Foreign(_) | ty::Str | ty::Array(_, _) + | ty::Pat(_, _) | ty::Slice(_) | ty::FnDef(_, _) | ty::FnPtr(_) @@ -1648,6 +1649,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { | ty::Foreign(_) | ty::Str | ty::Array(_, _) + | ty::Pat(_, _) | ty::Slice(_) | ty::RawPtr(_, _) | ty::Ref(_, _, _) diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index 554dac0852f..1b4c6041294 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -46,6 +46,7 @@ mod format; 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, diff --git a/compiler/rustc_builtin_macros/src/pattern_type.rs b/compiler/rustc_builtin_macros/src/pattern_type.rs new file mode 100644 index 00000000000..54039c2c538 --- /dev/null +++ b/compiler/rustc_builtin_macros/src/pattern_type.rs @@ -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)) +} diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs index 64448441acb..5f0dcf9510f 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs @@ -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$<"); diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs index d91ad3fcab1..dcfce4e35e0 100644 --- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs +++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs @@ -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) } diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index 3283bcc4c45..62d169db628 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -1060,6 +1060,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { 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, diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index a8478f721c7..63c709d8aed 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -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 diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index d18600ce7d7..9911c59d4b8 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -640,6 +640,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' | ty::Str | ty::Dynamic(..) | ty::Closure(..) + | ty::Pat(..) | ty::CoroutineClosure(..) | ty::Coroutine(..) => Ok(false), // Some types only occur during typechecking, they have no layout. diff --git a/compiler/rustc_const_eval/src/util/type_name.rs b/compiler/rustc_const_eval/src/util/type_name.rs index f3db7d4cd42..e474b952938 100644 --- a/compiler/rustc_const_eval/src/util/type_name.rs +++ b/compiler/rustc_const_eval/src/util/type_name.rs @@ -31,6 +31,7 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> { | ty::Uint(_) | ty::Float(_) | ty::Str + | ty::Pat(_, _) | ty::Array(_, _) | ty::Slice(_) | ty::RawPtr(_, _) diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index a9f206d9e34..129ce1d3109 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -215,6 +215,8 @@ declare_features! ( (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. diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index f21cd653f96..c6e3ad31f01 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -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)] diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 8c44f21a57b..5da9d4444da 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -356,6 +356,11 @@ pub trait Visitor<'v>: Sized { 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() } diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index d8a90d62dac..e66a834ab9e 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -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 diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs index 067878091a7..4a85e9983f4 100644 --- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs +++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs @@ -144,7 +144,12 @@ impl<'tcx> InherentCollect<'tcx> { 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 @@ impl<'tcx> InherentCollect<'tcx> { ty::Dynamic(..) => { Err(self.tcx.dcx().emit_err(errors::InherentDyn { span: item_span })) } + ty::Pat(_, _) => unreachable!(), ty::Bool | ty::Char | ty::Int(_) diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs index 1770f7b4e91..5585d2e069c 100644 --- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs +++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs @@ -206,6 +206,11 @@ pub(crate) fn orphan_check_impl( (LocalImpl::Disallow { problematic_kind }, NonlocalImpl::DisallowOther) } + ty::Pat(..) => ( + LocalImpl::Disallow { problematic_kind: "pattern type" }, + NonlocalImpl::DisallowOther, + ), + ty::Bool | ty::Char | ty::Int(..) diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 2d4742fa1dc..d129614e0e1 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -7,6 +7,8 @@ use rustc_errors::{ 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, +} diff --git a/compiler/rustc_hir_analysis/src/errors/pattern_types.rs b/compiler/rustc_hir_analysis/src/errors/pattern_types.rs new file mode 100644 index 00000000000..008d2698989 --- /dev/null +++ b/compiler/rustc_hir_analysis/src/errors/pattern_types.rs @@ -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, +} diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index f726f2a7b89..ebfccd27d17 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -21,7 +21,7 @@ mod object_safety; 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_hir::{GenericArg, GenericArgs}; 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 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // 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), }; diff --git a/compiler/rustc_hir_analysis/src/variance/constraints.rs b/compiler/rustc_hir_analysis/src/variance/constraints.rs index 28c86d8019e..20e4110e137 100644 --- a/compiler/rustc_hir_analysis/src/variance/constraints.rs +++ b/compiler/rustc_hir_analysis/src/variance/constraints.rs @@ -249,6 +249,20 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { 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); } diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index bd528432e70..a590c648d20 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -330,6 +330,11 @@ impl<'a> State<'a> { 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() } diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index 07d64918e8b..92f74281ab9 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -130,6 +130,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | ty::CoroutineWitness(..) | ty::RawPtr(_, _) | ty::Ref(..) + | ty::Pat(..) | ty::FnDef(..) | ty::FnPtr(..) | ty::Closure(..) diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs index 9f70fee993d..6421a3f038c 100644 --- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs +++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs @@ -440,6 +440,7 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> { | ty::Tuple(..) | ty::Alias(..) | ty::Foreign(..) + | ty::Pat(..) | ty::Param(..) => { if t.flags().intersects(self.needs_canonical_flags) { t.super_fold_with(self) diff --git a/compiler/rustc_infer/src/infer/outlives/components.rs b/compiler/rustc_infer/src/infer/outlives/components.rs index 7dd1ec32542..6bab3ad6ba3 100644 --- a/compiler/rustc_infer/src/infer/outlives/components.rs +++ b/compiler/rustc_infer/src/infer/outlives/components.rs @@ -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); diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 797c0df4d73..82b90e1660a 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -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 diff --git a/compiler/rustc_lint/src/non_local_def.rs b/compiler/rustc_lint/src/non_local_def.rs index 1e9c60a540d..870e198d70a 100644 --- a/compiler/rustc_lint/src/non_local_def.rs +++ b/compiler/rustc_lint/src/non_local_def.rs @@ -157,6 +157,7 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions { | TyKind::Never | TyKind::Tup(_) | TyKind::Path(_) + | TyKind::Pat(..) | TyKind::AnonAdt(_) | TyKind::OpaqueDef(_, _, _) | TyKind::Typeof(_) diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 534eb60eeb0..e982842f536 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -1379,6 +1379,12 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { 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 } } diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index bd11b3eb04c..13719268737 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -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 diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs index 9068961d736..0209c2dcc98 100644 --- a/compiler/rustc_middle/src/ty/codec.rs +++ b/compiler/rustc_middle/src/ty/codec.rs @@ -148,6 +148,12 @@ impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for ty::Const<'tcx> { } } +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 @@ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for ty::Const<'tcx> { } } +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 diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 1db9bce73a6..2a6449a5246 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -26,9 +26,10 @@ use crate::traits::solve::{ }; 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 @@ impl<'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 @@ macro_rules! nop_list_lift { 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 @@ impl<'tcx> TyCtxt<'tcx> { Param, Infer, Alias, + Pat, Foreign )?; @@ -1866,6 +1872,7 @@ macro_rules! direct_interners { // 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>, diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index 09586a95f1c..ce85c28ece8 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -285,6 +285,7 @@ impl<'tcx> Ty<'tcx> { 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 { diff --git a/compiler/rustc_middle/src/ty/fast_reject.rs b/compiler/rustc_middle/src/ty/fast_reject.rs index 5b257cdfd86..7c925d5fbb6 100644 --- a/compiler/rustc_middle/src/ty/fast_reject.rs +++ b/compiler/rustc_middle/src/ty/fast_reject.rs @@ -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 @@ impl DeepRejectCtxt { | ty::Slice(..) | ty::RawPtr(..) | ty::Dynamic(..) + | ty::Pat(..) | ty::Ref(..) | ty::Never | ty::Tuple(..) @@ -269,6 +271,10 @@ impl DeepRejectCtxt { } _ => 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)) } diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs index 5feb6ef76d5..0dc835671d5 100644 --- a/compiler/rustc_middle/src/ty/flags.rs +++ b/compiler/rustc_middle/src/ty/flags.rs @@ -218,6 +218,20 @@ impl FlagComputation { 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, _) => { diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs index 2630b96869b..e984f543701 100644 --- a/compiler/rustc_middle/src/ty/generics.rs +++ b/compiler/rustc_middle/src/ty/generics.rs @@ -316,11 +316,11 @@ impl<'tcx> Generics { /// 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; diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 66078663098..50e68bfdbe7 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -742,6 +742,7 @@ where | ty::FnDef(..) | ty::CoroutineWitness(..) | ty::Foreign(..) + | ty::Pat(_, _) | ty::Dynamic(_, _, ty::Dyn) => { bug!("TyAndLayout::field({:?}): not applicable", this) } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 9bf5205edaa..ee4dc9744ac 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -91,6 +91,7 @@ pub use self::context::{ 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 fold; pub mod inhabitedness; pub mod layout; pub mod normalize_erasing_regions; +pub mod pattern; pub mod print; pub mod relate; pub mod trait_def; diff --git a/compiler/rustc_middle/src/ty/pattern.rs b/compiler/rustc_middle/src/ty/pattern.rs new file mode 100644 index 00000000000..8a41ba257ec --- /dev/null +++ b/compiler/rustc_middle/src/ty/pattern.rs @@ -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 }, +} diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs index d9aa7f9e5c4..9d0e1123e43 100644 --- a/compiler/rustc_middle/src/ty/print/mod.rs +++ b/compiler/rustc_middle/src/ty/print/mod.rs @@ -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) } diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 2a898430ce9..20ebd87c3d4 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -667,6 +667,9 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { 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( "*{} ", diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index cf7caafcebb..3c1dea1d9f2 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -13,6 +13,8 @@ use rustc_hir::def_id::DefId; 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 @@ impl<'tcx> Relate<'tcx> for Ty<'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))), } } diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 8231c0214cb..90c68e7ddfc 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -20,6 +20,8 @@ use std::fmt::{self, Debug}; 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 @@ impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for AliasTy<'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 @@ impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for &'tcx ty::List<ty::Const<'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 @@ impl<'tcx> TypeSuperFoldable<TyCtxt<'tcx>> for Ty<'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 @@ impl<'tcx> TypeSuperVisitable<TyCtxt<'tcx>> for Ty<'tcx> { 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 diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 2ab63f01e7c..d9e99bf07af 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1523,6 +1523,11 @@ impl<'tcx> Ty<'tcx> { } #[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 @@ impl<'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 @@ impl<'tcx> Ty<'tcx> { 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 @@ impl<'tcx> Ty<'tcx> { | ty::Coroutine(..) | ty::CoroutineWitness(..) | ty::Array(..) + | ty::Pat(..) | ty::Closure(..) | ty::CoroutineClosure(..) | ty::Never @@ -2549,6 +2558,8 @@ impl<'tcx> Ty<'tcx> { 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 @@ impl<'tcx> Ty<'tcx> { | Foreign(_) | Str | Array(_, _) + | Pat(_, _) | Slice(_) | RawPtr(_, _) | Ref(_, _, _) diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index cef15b29a85..e422fb0d020 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -245,6 +245,11 @@ impl<'tcx> TyCtxt<'tcx> { ty::Tuple(_) => break, + ty::Pat(inner, _) => { + f(); + ty = inner; + } + ty::Alias(..) => { let normalized = normalize(ty); if ty == normalized { @@ -1242,7 +1247,7 @@ impl<'tcx> Ty<'tcx> { | 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 @@ impl<'tcx> Ty<'tcx> { | 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 @@ impl<'tcx> Ty<'tcx> { // // 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)), } diff --git a/compiler/rustc_middle/src/ty/walk.rs b/compiler/rustc_middle/src/ty/walk.rs index 9e7bf980237..7069bdcbcb9 100644 --- a/compiler/rustc_middle/src/ty/walk.rs +++ b/compiler/rustc_middle/src/ty/walk.rs @@ -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()); diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index ce39aff69cb..65c53be8ddd 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -457,7 +457,7 @@ impl<'tcx> ConstToPat<'tcx> { 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)) } diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs index e73d945e0bb..d7477309400 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs @@ -153,6 +153,7 @@ impl<'b, 'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> Gatherer<'b, 'a, 'tcx, F> { | ty::Foreign(_) | ty::Str | ty::Array(_, _) + | ty::Pat(_, _) | ty::Slice(_) | ty::FnDef(_, _) | ty::FnPtr(_) @@ -193,6 +194,7 @@ impl<'b, 'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> Gatherer<'b, 'a, 'tcx, F> { | ty::Foreign(_) | ty::Str | ty::Array(_, _) + | ty::Pat(_, _) | ty::Slice(_) | ty::RawPtr(_, _) | ty::Ref(_, _, _) diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index 3e9c1459f1c..d0f6ec8f21f 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -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(_) diff --git a/compiler/rustc_next_trait_solver/src/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonicalizer.rs index 1899517c0e2..30c8fc5798f 100644 --- a/compiler/rustc_next_trait_solver/src/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonicalizer.rs @@ -349,6 +349,7 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> TypeFolder<I> | ty::Slice(_) | ty::RawPtr(_, _) | ty::Ref(_, _, _) + | ty::Pat(_, _) | ty::FnDef(_, _) | ty::FnPtr(_) | ty::Dynamic(_, _, _) diff --git a/compiler/rustc_passes/src/hir_id_validator.rs b/compiler/rustc_passes/src/hir_id_validator.rs index dd6c1166957..51a69809c7a 100644 --- a/compiler/rustc_passes/src/hir_id_validator.rs +++ b/compiler/rustc_passes/src/hir_id_validator.rs @@ -161,4 +161,8 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for HirIdValidator<'a, '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) + } } diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs index e6e52648d6f..72c6a714e4d 100644 --- a/compiler/rustc_passes/src/hir_stats.rs +++ b/compiler/rustc_passes/src/hir_stats.rs @@ -352,6 +352,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { TraitObject, Typeof, Infer, + Pat, Err ] ); @@ -611,6 +612,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> { AnonStruct, AnonUnion, Path, + Pat, TraitObject, ImplTrait, Paren, diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index 467f09e4c29..548a7b43005 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -399,6 +399,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { | ty::RawPtr(_, _) | ty::FnDef(_, _) | ty::FnPtr(_) + | ty::Pat(_, _) | ty::Dynamic(_, _, _) | ty::Closure(..) | ty::CoroutineClosure(..) diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 41d63407418..2039e994aaa 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -276,6 +276,7 @@ where | ty::Tuple(..) | ty::RawPtr(..) | ty::Ref(..) + | ty::Pat(..) | ty::FnPtr(..) | ty::Param(..) | ty::Bound(..) diff --git a/compiler/rustc_smir/src/rustc_internal/internal.rs b/compiler/rustc_smir/src/rustc_internal/internal.rs index e8cc41cc886..a904cd10041 100644 --- a/compiler/rustc_smir/src/rustc_internal/internal.rs +++ b/compiler/rustc_smir/src/rustc_internal/internal.rs @@ -14,8 +14,8 @@ use stable_mir::mir::{Mutability, Place, ProjectionElem, Safety}; 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 @@ impl RustcInternal for Ty { } } +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 @@ impl RustcInternal for RigidTy { 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)) } diff --git a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs index 2ad8f350f10..112e44f674e 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs @@ -330,6 +330,9 @@ impl<'tcx> Stable<'tcx> for ty::TyKind<'tcx> { 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 @@ impl<'tcx> Stable<'tcx> for ty::TyKind<'tcx> { } } +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; diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 7a5647e979a..bfd0f77c237 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1009,6 +1009,7 @@ symbols! { io_stderr, io_stdout, irrefutable_let_patterns, + is, is_val_statically_known, isa_attribute, isize, @@ -1347,6 +1348,8 @@ symbols! { path, pattern_complexity, pattern_parentheses, + pattern_type, + pattern_types, phantom_data, pic, pie, diff --git a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs index a3a18fb768f..6078d901711 100644 --- a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs +++ b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs @@ -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 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for TransformTy<'tcx> { | ty::Foreign(..) | ty::Never | ty::Slice(..) + | ty::Pat(..) | ty::Str | ty::Tuple(..) => t.super_fold_with(self), diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 8cb5370bb4a..0199e225c5f 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -371,6 +371,25 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> { 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)?; diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs index 35f7d1d7151..8b5c029428c 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs @@ -363,6 +363,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { | ty::Foreign(_) | ty::Str | ty::Array(_, _) + | ty::Pat(_, _) | ty::Slice(_) | ty::RawPtr(_, _) | ty::Ref(_, _, _) @@ -596,6 +597,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { | ty::Foreign(_) | ty::Str | ty::Array(_, _) + | ty::Pat(_, _) | ty::Slice(_) | ty::RawPtr(_, _) | ty::Ref(_, _, _) @@ -684,6 +686,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { | ty::Foreign(_) | ty::Str | ty::Array(_, _) + | ty::Pat(_, _) | ty::Slice(_) | ty::RawPtr(_, _) | ty::Ref(_, _, _) diff --git a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs index 00cd4b48797..8a96d810134 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs @@ -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(_, _, _) diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs index fb296d55100..befde8f768a 100644 --- a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs @@ -533,6 +533,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { | ty::Uint(..) | ty::Float(..) | ty::Array(..) + | ty::Pat(..) | ty::RawPtr(..) | ty::Ref(..) | ty::FnDef(..) @@ -768,6 +769,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { | ty::Uint(..) | ty::Float(..) | ty::Array(..) + | ty::Pat(..) | ty::RawPtr(..) | ty::Ref(..) | ty::FnDef(..) diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index eb3ad0aa782..371668bf617 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -1051,6 +1051,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { | ty::Float(_) | ty::Str | ty::Array(_, _) + | ty::Pat(_, _) | ty::Slice(_) | ty::RawPtr(_, _) | ty::Ref(_, _, _) diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index 8625ad378f7..77eaa4fd03e 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -883,6 +883,7 @@ where | ty::Float(..) | ty::Str | ty::FnDef(..) + | ty::Pat(..) | ty::FnPtr(_) | ty::Array(..) | ty::Slice(..) diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs index 144971b63c0..afdc2c5a7f7 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs @@ -1804,6 +1804,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { 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, } } diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 56b25b0fe6c..8d04fd45940 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -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(..) diff --git a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs index aaa38d14d6e..326c68e01db 100644 --- a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs +++ b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs @@ -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) diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index c6ea596b819..c1f340dfc7c 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -670,6 +670,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::Foreign(_) | ty::Str | ty::Array(_, _) + | ty::Pat(_, _) | ty::Slice(_) | ty::RawPtr(_, _) | ty::Ref(_, _, _) @@ -803,6 +804,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::Float(_) | ty::Str | ty::Array(_, _) + | ty::Pat(_, _) | ty::Slice(_) | ty::Adt(..) | ty::RawPtr(_, _) @@ -1193,6 +1195,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::Never | ty::Foreign(_) | ty::Array(..) + | ty::Pat(..) | ty::Slice(_) | ty::Closure(..) | ty::CoroutineClosure(..) @@ -1270,6 +1273,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::RawPtr(_, _) | ty::Ref(_, _, _) | ty::FnDef(_, _) + | ty::Pat(_, _) | ty::FnPtr(_) | ty::Dynamic(_, _, _) | ty::Closure(..) @@ -1329,6 +1333,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::Foreign(..) | ty::Str | ty::Array(..) + | ty::Pat(..) | ty::Slice(_) | ty::RawPtr(_, _) | ty::Ref(..) diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 0459246553b..f98a1714a3f 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -1417,7 +1417,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // 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 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // 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(), diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 5e9a28b5cce..e363119393a 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -2142,6 +2142,8 @@ impl<'tcx> SelectionContext<'_, 'tcx> { 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 @@ impl<'tcx> SelectionContext<'_, 'tcx> { 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 @@ impl<'tcx> SelectionContext<'_, 'tcx> { 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 diff --git a/compiler/rustc_trait_selection/src/traits/structural_match.rs b/compiler/rustc_trait_selection/src/traits/structural_match.rs index b89406ca023..6778ac81aea 100644 --- a/compiler/rustc_trait_selection/src/traits/structural_match.rs +++ b/compiler/rustc_trait_selection/src/traits/structural_match.rs @@ -126,7 +126,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for Search<'tcx> { 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); } diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index a44a5ae0e6b..5553490542b 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -681,6 +681,10 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> { // 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 { diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index 509727cdeab..77cd4662ae5 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -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, diff --git a/compiler/rustc_ty_utils/src/needs_drop.rs b/compiler/rustc_ty_utils/src/needs_drop.rs index 48339e6120a..ee930a78e77 100644 --- a/compiler/rustc_ty_utils/src/needs_drop.rs +++ b/compiler/rustc_ty_utils/src/needs_drop.rs @@ -221,6 +221,7 @@ where | ty::Ref(..) | ty::RawPtr(..) | ty::FnDef(..) + | ty::Pat(..) | ty::FnPtr(..) | ty::Tuple(_) | ty::Bound(..) diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index 547a3cb5a8c..f33234122c9 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -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 diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index 7d6862726f0..27d9215f8d4 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -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 diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs index fad67fe3cbb..8813955f2af 100644 --- a/compiler/rustc_type_ir/src/ty_kind.rs +++ b/compiler/rustc_type_ir/src/ty_kind.rs @@ -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 @@ impl<I: Interner> PartialEq for TyKind<I> { (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 @@ impl<I: Interner> PartialEq for TyKind<I> { _ => { 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 @@ impl<I: Interner> DebugWithInfcx<I> for TyKind<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 { diff --git a/compiler/stable_mir/src/ty.rs b/compiler/stable_mir/src/ty.rs index 3e8d186b97e..bc6fb34493a 100644 --- a/compiler/stable_mir/src/ty.rs +++ b/compiler/stable_mir/src/ty.rs @@ -99,6 +99,12 @@ impl Ty { } } +/// 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), diff --git a/compiler/stable_mir/src/visitor.rs b/compiler/stable_mir/src/visitor.rs index 65e42879d61..2d7159f87fe 100644 --- a/compiler/stable_mir/src/visitor.rs +++ b/compiler/stable_mir/src/visitor.rs @@ -139,6 +139,7 @@ impl Visitable for RigidTy { 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, _) => { |
