From f0308938ba39bc3377f22f7479654ba32e9c233f Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 7 Jan 2025 10:24:16 +0000 Subject: [PATCH 1/2] Use a different hir type for patterns in pattern types than we use in match patterns --- compiler/rustc_ast_lowering/src/index.rs | 8 +- compiler/rustc_ast_lowering/src/lib.rs | 4 +- compiler/rustc_ast_lowering/src/pat.rs | 80 ++++++++++++++++++- compiler/rustc_driver_impl/src/pretty.rs | 4 + compiler/rustc_hir/src/hir.rs | 21 ++++- compiler/rustc_hir/src/intravisit.rs | 18 ++++- compiler/rustc_hir_analysis/messages.ftl | 3 - .../src/collect/resolve_bound_vars.rs | 4 +- .../rustc_hir_analysis/src/collect/type_of.rs | 21 +++-- compiler/rustc_hir_analysis/src/errors.rs | 7 -- .../src/errors/pattern_types.rs | 7 -- .../src/hir_ty_lowering/mod.rs | 65 ++------------- compiler/rustc_hir_pretty/src/lib.rs | 51 +++++++++--- compiler/rustc_hir_typeck/src/expr.rs | 2 +- compiler/rustc_middle/src/hir/map/mod.rs | 2 + compiler/rustc_passes/src/hir_id_validator.rs | 4 +- .../clippy/clippy_utils/src/hir_utils.rs | 20 ++++- .../bad_const_generics_args_on_const_param.rs | 1 + ..._const_generics_args_on_const_param.stderr | 10 ++- tests/ui/type/pattern_types/bad_pat.rs | 2 +- tests/ui/type/pattern_types/bad_pat.stderr | 2 +- tests/ui/type/pattern_types/nested.rs | 4 + tests/ui/type/pattern_types/nested.stderr | 52 +++++++++--- .../pattern_types/pattern_type_mismatch.rs | 12 +-- .../pattern_type_mismatch.stderr | 44 +++++----- .../type/pattern_types/unimplemented_pat.rs | 8 +- .../pattern_types/unimplemented_pat.stderr | 21 ++--- 27 files changed, 310 insertions(+), 167 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs index f8fb21d5cd093..d1e23bf252229 100644 --- a/compiler/rustc_ast_lowering/src/index.rs +++ b/compiler/rustc_ast_lowering/src/index.rs @@ -412,8 +412,12 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { }); } - fn visit_pattern_type_pattern(&mut self, p: &'hir hir::Pat<'hir>) { - self.visit_pat(p) + fn visit_pattern_type_pattern(&mut self, pat: &'hir hir::TyPat<'hir>) { + self.insert(pat.span, pat.hir_id, Node::TyPat(pat)); + + self.with_parent(pat.hir_id, |this| { + intravisit::walk_ty_pat(this, pat); + }); } fn visit_precise_capturing_arg( diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 893da93085533..8728af9997a1a 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1377,7 +1377,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } } } - TyKind::Pat(ty, pat) => hir::TyKind::Pat(self.lower_ty(ty, itctx), self.lower_pat(pat)), + TyKind::Pat(ty, pat) => { + hir::TyKind::Pat(self.lower_ty(ty, itctx), self.lower_ty_pat(pat)) + } TyKind::MacCall(_) => { span_bug!(t.span, "`TyKind::MacCall` should have been expanded by now") } diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index cde8ddbfe03cc..57f15f99760aa 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -4,10 +4,10 @@ use rustc_ast::ptr::P; use rustc_ast::*; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir as hir; -use rustc_hir::def::Res; +use rustc_hir::def::{DefKind, Res}; use rustc_middle::span_bug; use rustc_span::source_map::{Spanned, respan}; -use rustc_span::{Ident, Span}; +use rustc_span::{Ident, Span, kw}; use super::errors::{ ArbitraryExpressionInPattern, ExtraDoubleDot, MisplacedDoubleDot, SubTupleBinding, @@ -429,4 +429,80 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { }; self.arena.alloc(hir::PatExpr { hir_id: self.lower_node_id(expr.id), span, kind }) } + + pub(crate) fn lower_ty_pat(&mut self, pattern: &Pat) -> &'hir hir::TyPat<'hir> { + self.arena.alloc(self.lower_ty_pat_mut(pattern)) + } + + fn lower_ty_pat_mut(&mut self, mut pattern: &Pat) -> hir::TyPat<'hir> { + // loop here to avoid recursion + let pat_hir_id = self.lower_node_id(pattern.id); + let node = loop { + match &pattern.kind { + PatKind::Range(e1, e2, Spanned { node: end, .. }) => { + let mut lower_expr = |e: &Expr| -> &_ { + let kind = if let ExprKind::Path(qself, path) = &e.kind { + hir::ConstArgKind::Path(self.lower_qpath( + e.id, + qself, + path, + ParamMode::Optional, + AllowReturnTypeNotation::No, + ImplTraitContext::Disallowed(ImplTraitPosition::Path), + None, + )) + } else { + let node_id = self.next_node_id(); + let def_id = self.create_def( + self.current_hir_id_owner.def_id, + node_id, + kw::Empty, + DefKind::AnonConst, + e.span, + ); + let hir_id = self.lower_node_id(node_id); + let ac = self.arena.alloc(hir::AnonConst { + def_id, + hir_id, + body: self.lower_const_body(pattern.span, Some(e)), + span: self.lower_span(pattern.span), + }); + hir::ConstArgKind::Anon(ac) + }; + self.arena.alloc(hir::ConstArg { hir_id: self.next_id(), kind }) + }; + break hir::TyPatKind::Range( + e1.as_deref().map(|e| lower_expr(e)), + e2.as_deref().map(|e| lower_expr(e)), + self.lower_range_end(end, e2.is_some()), + ); + } + // return inner to be processed in next loop + PatKind::Paren(inner) => pattern = inner, + PatKind::MacCall(_) => panic!("{:?} shouldn't exist here", pattern.span), + PatKind::Err(guar) => break hir::TyPatKind::Err(*guar), + PatKind::Deref(..) + | PatKind::Box(..) + | PatKind::Or(..) + | PatKind::Struct(..) + | PatKind::TupleStruct(..) + | PatKind::Tuple(..) + | PatKind::Ref(..) + | PatKind::Expr(..) + | PatKind::Guard(..) + | PatKind::Slice(_) + | PatKind::Ident(..) + | PatKind::Path(..) + | PatKind::Wild + | PatKind::Never + | PatKind::Rest => { + break hir::TyPatKind::Err( + self.dcx().span_err(pattern.span, "pattern not supported in pattern types"), + ); + } + } + }; + + hir::TyPat { hir_id: pat_hir_id, kind: node, span: self.lower_span(pattern.span) } + } } diff --git a/compiler/rustc_driver_impl/src/pretty.rs b/compiler/rustc_driver_impl/src/pretty.rs index 9ace486fa56f7..576b1c76823fa 100644 --- a/compiler/rustc_driver_impl/src/pretty.rs +++ b/compiler/rustc_driver_impl/src/pretty.rs @@ -101,6 +101,10 @@ impl<'tcx> pprust_hir::PpAnn for HirIdentifiedAnn<'tcx> { s.s.space(); s.synth_comment(format!("pat hir_id: {}", pat.hir_id)); } + pprust_hir::AnnNode::TyPat(pat) => { + s.s.space(); + s.synth_comment(format!("ty pat hir_id: {}", pat.hir_id)); + } pprust_hir::AnnNode::Arm(arm) => { s.s.space(); s.synth_comment(format!("arm hir_id: {}", arm.hir_id)); diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index af2f86b67e007..4113c7ed4bbef 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1418,6 +1418,14 @@ impl<'hir> Block<'hir> { } } +#[derive(Debug, Clone, Copy, HashStable_Generic)] +pub struct TyPat<'hir> { + #[stable_hasher(ignore)] + pub hir_id: HirId, + pub kind: TyPatKind<'hir>, + pub span: Span, +} + #[derive(Debug, Clone, Copy, HashStable_Generic)] pub struct Pat<'hir> { #[stable_hasher(ignore)] @@ -1591,6 +1599,15 @@ pub enum PatExprKind<'hir> { Path(QPath<'hir>), } +#[derive(Debug, Clone, Copy, HashStable_Generic)] +pub enum TyPatKind<'hir> { + /// A range pattern (e.g., `1..=2` or `1..2`). + Range(Option<&'hir ConstArg<'hir>>, Option<&'hir ConstArg<'hir>>, RangeEnd), + + /// A placeholder for a pattern that wasn't well formed in some way. + Err(ErrorGuaranteed), +} + #[derive(Debug, Clone, Copy, HashStable_Generic)] pub enum PatKind<'hir> { /// Represents a wildcard pattern (i.e., `_`). @@ -3345,7 +3362,7 @@ pub enum TyKind<'hir, Unambig = ()> { /// 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>), + Pat(&'hir Ty<'hir>, &'hir TyPat<'hir>), /// `TyKind::Infer` means the type should be inferred instead of it having been /// specified. This can appear anywhere in a type. /// @@ -4331,6 +4348,7 @@ pub enum Node<'hir> { AssocItemConstraint(&'hir AssocItemConstraint<'hir>), TraitRef(&'hir TraitRef<'hir>), OpaqueTy(&'hir OpaqueTy<'hir>), + TyPat(&'hir TyPat<'hir>), Pat(&'hir Pat<'hir>), PatField(&'hir PatField<'hir>), /// Needed as its own node with its own HirId for tracking @@ -4393,6 +4411,7 @@ impl<'hir> Node<'hir> { | Node::Block(..) | Node::Ctor(..) | Node::Pat(..) + | Node::TyPat(..) | Node::PatExpr(..) | Node::Arm(..) | Node::LetStmt(..) diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 31764ab120949..6519552d6046b 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -393,10 +393,8 @@ pub trait Visitor<'v>: Sized { fn visit_expr_field(&mut self, field: &'v ExprField<'v>) -> Self::Result { walk_expr_field(self, field) } - 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_pattern_type_pattern(&mut self, p: &'v TyPat<'v>) -> Self::Result { + walk_ty_pat(self, p) } fn visit_generic_param(&mut self, p: &'v GenericParam<'v>) -> Self::Result { walk_generic_param(self, p) @@ -702,6 +700,18 @@ pub fn walk_arm<'v, V: Visitor<'v>>(visitor: &mut V, arm: &'v Arm<'v>) -> V::Res visitor.visit_expr(arm.body) } +pub fn walk_ty_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v TyPat<'v>) -> V::Result { + try_visit!(visitor.visit_id(pattern.hir_id)); + match pattern.kind { + TyPatKind::Range(lower_bound, upper_bound, _) => { + visit_opt!(visitor, visit_const_arg_unambig, lower_bound); + visit_opt!(visitor, visit_const_arg_unambig, upper_bound); + } + TyPatKind::Err(_) => (), + } + V::Result::output() +} + pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat<'v>) -> V::Result { try_visit!(visitor.visit_id(pattern.hir_id)); match pattern.kind { diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index a4b5a87361ef3..c28c1afcfe66c 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -436,9 +436,6 @@ hir_analysis_paren_sugar_attribute = the `#[rustc_paren_sugar]` attribute is a t hir_analysis_parenthesized_fn_trait_expansion = parenthesized trait syntax expands to `{$expanded_type}` -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 hir_analysis_precise_capture_self_alias = `Self` can't be captured in `use<...>` precise captures list, since it is an alias diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index d67b9d3359601..76006354717e1 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -831,8 +831,8 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { } #[instrument(level = "debug", skip(self))] - fn visit_pattern_type_pattern(&mut self, p: &'tcx hir::Pat<'tcx>) { - intravisit::walk_pat(self, p) + fn visit_pattern_type_pattern(&mut self, p: &'tcx hir::TyPat<'tcx>) { + intravisit::walk_ty_pat(self, p) } #[instrument(level = "debug", skip(self))] diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index 348d4d708b57a..4e12db190fd04 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -18,9 +18,10 @@ use crate::hir_ty_lowering::HirTyLowerer; mod opaque; -fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { +fn anon_const_type_of<'tcx>(icx: &ItemCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { use hir::*; use rustc_middle::ty::Ty; + let tcx = icx.tcx; let hir_id = tcx.local_def_id_to_hir_id(def_id); let node = tcx.hir_node(hir_id); @@ -54,7 +55,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { hir_id: arg_hir_id, kind: ConstArgKind::Anon(&AnonConst { hir_id: anon_hir_id, .. }), .. - }) if anon_hir_id == hir_id => const_arg_anon_type_of(tcx, arg_hir_id, span), + }) if anon_hir_id == hir_id => const_arg_anon_type_of(icx, arg_hir_id, span), // Anon consts outside the type system. Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. }) @@ -138,10 +139,12 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { } } -fn const_arg_anon_type_of<'tcx>(tcx: TyCtxt<'tcx>, arg_hir_id: HirId, span: Span) -> Ty<'tcx> { +fn const_arg_anon_type_of<'tcx>(icx: &ItemCtxt<'tcx>, arg_hir_id: HirId, span: Span) -> Ty<'tcx> { use hir::*; use rustc_middle::ty::Ty; + let tcx = icx.tcx; + match tcx.parent_hir_node(arg_hir_id) { // Array length const arguments do not have `type_of` fed as there is never a corresponding // generic parameter definition. @@ -149,7 +152,15 @@ fn const_arg_anon_type_of<'tcx>(tcx: TyCtxt<'tcx>, arg_hir_id: HirId, span: Span | Node::Expr(&Expr { kind: ExprKind::Repeat(_, ref constant), .. }) if constant.hir_id == arg_hir_id => { - return tcx.types.usize; + tcx.types.usize + } + + Node::TyPat(pat) => { + let hir::TyKind::Pat(ty, p) = tcx.parent_hir_node(pat.hir_id).expect_ty().kind else { + bug!() + }; + assert_eq!(p.hir_id, pat.hir_id); + icx.lower_ty(ty) } // This is not a `bug!` as const arguments in path segments that did not resolve to anything @@ -344,7 +355,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_ tcx.typeck(def_id).node_type(hir_id) } - Node::AnonConst(_) => anon_const_type_of(tcx, def_id), + Node::AnonConst(_) => anon_const_type_of(&icx, def_id), Node::ConstBlock(_) => { let args = ty::GenericArgs::identity_for_item(tcx, def_id.to_def_id()); diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 1dcea5d033537..9769be302264d 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -1605,13 +1605,6 @@ pub(crate) struct OpaqueCapturesHigherRankedLifetime { pub bad_place: &'static str, } -#[derive(Diagnostic)] -#[diag(hir_analysis_pattern_type_non_const_range)] -pub(crate) struct NonConstRange { - #[primary_span] - pub span: Span, -} - #[derive(Subdiagnostic)] pub(crate) enum InvalidReceiverTyHint { #[note(hir_analysis_invalid_receiver_ty_help_weak_note)] diff --git a/compiler/rustc_hir_analysis/src/errors/pattern_types.rs b/compiler/rustc_hir_analysis/src/errors/pattern_types.rs index 272edbe841b96..ec7b3aaa1c14c 100644 --- a/compiler/rustc_hir_analysis/src/errors/pattern_types.rs +++ b/compiler/rustc_hir_analysis/src/errors/pattern_types.rs @@ -2,13 +2,6 @@ use rustc_macros::Diagnostic; use rustc_middle::ty::Ty; use rustc_span::Span; -#[derive(Diagnostic)] -#[diag(hir_analysis_pattern_type_wild_pat)] -pub(crate) struct WildPatTy { - #[primary_span] - pub span: Span, -} - #[derive(Diagnostic)] #[diag(hir_analysis_invalid_base_type)] pub(crate) struct InvalidBaseType<'tcx> { 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 5813fdeae7645..079e892162792 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -53,7 +53,7 @@ use tracing::{debug, instrument}; use crate::bounds::Bounds; use crate::check::check_abi_fn_ptr; -use crate::errors::{AmbiguousLifetimeBound, BadReturnTypeNotation, InvalidBaseType, WildPatTy}; +use crate::errors::{AmbiguousLifetimeBound, BadReturnTypeNotation, InvalidBaseType}; use crate::hir_ty_lowering::errors::{GenericsArgsErrExtend, prohibit_assoc_item_constraint}; use crate::hir_ty_lowering::generics::{check_generic_arg_count, lower_generic_args}; use crate::middle::resolve_bound_vars as rbv; @@ -2435,11 +2435,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let ty_span = ty.span; let ty = self.lower_ty(ty); let pat_ty = match pat.kind { - hir::PatKind::Wild => { - let err = self.dcx().emit_err(WildPatTy { span: pat.span }); - Ty::new_error(tcx, err) - } - hir::PatKind::Range(start, end, include_end) => { + hir::TyPatKind::Range(start, end, include_end) => { let ty = match ty.kind() { ty::Int(_) | ty::Uint(_) | ty::Char => ty, _ => Ty::new_error( @@ -2452,54 +2448,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { }), ), }; - let expr_to_const = |expr: &'tcx hir::PatExpr<'tcx>| -> ty::Const<'tcx> { - let (c, c_ty) = match expr.kind { - hir::PatExprKind::Lit { lit, negated } => { - let lit_input = - LitToConstInput { lit: &lit.node, ty, neg: negated }; - let ct = tcx.lit_to_const(lit_input); - (ct, ty) - } - - hir::PatExprKind::Path(hir::QPath::Resolved( - _, - path @ &hir::Path { - res: Res::Def(DefKind::ConstParam, def_id), - .. - }, - )) => { - match self.prohibit_generic_args( - path.segments.iter(), - GenericsArgsErrExtend::Param(def_id), - ) { - Ok(()) => { - let ty = tcx - .type_of(def_id) - .no_bound_vars() - .expect("const parameter types cannot be generic"); - let ct = self.lower_const_param(def_id, expr.hir_id); - (ct, ty) - } - Err(guar) => ( - ty::Const::new_error(tcx, guar), - Ty::new_error(tcx, guar), - ), - } - } - - _ => { - let err = tcx - .dcx() - .emit_err(crate::errors::NonConstRange { span: expr.span }); - (ty::Const::new_error(tcx, err), Ty::new_error(tcx, err)) - } - }; - self.record_ty(expr.hir_id, c_ty, expr.span); - c - }; - - let start = start.map(expr_to_const); - let end = end.map(expr_to_const); + let start = start.map(|expr| self.lower_const_arg(expr, FeedConstTy::No)); + let end = end.map(|expr| self.lower_const_arg(expr, FeedConstTy::No)); let include_end = match include_end { hir::RangeEnd::Included => true, @@ -2509,12 +2459,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { 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), - _ => Ty::new_error_with_message( - tcx, - pat.span, - format!("unsupported pattern for pattern type: {pat:#?}"), - ), + hir::TyPatKind::Err(e) => Ty::new_error(tcx, e), }; self.record_ty(pat.hir_id, ty, pat.span); pat_ty diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index a91afa51230d1..3b163d0bc2050 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -18,7 +18,7 @@ use rustc_ast_pretty::pprust::state::MacHeader; use rustc_ast_pretty::pprust::{Comments, PrintState}; use rustc_hir::{ BindingMode, ByRef, ConstArgKind, GenericArg, GenericBound, GenericParam, GenericParamKind, - HirId, LifetimeParamKind, Node, PatKind, PreciseCapturingArg, RangeEnd, Term, + HirId, LifetimeParamKind, Node, PatKind, PreciseCapturingArg, RangeEnd, Term, TyPatKind, }; use rustc_span::source_map::SourceMap; use rustc_span::{FileName, Ident, Span, Symbol, kw}; @@ -35,6 +35,7 @@ pub enum AnnNode<'a> { SubItem(HirId), Expr(&'a hir::Expr<'a>), Pat(&'a hir::Pat<'a>), + TyPat(&'a hir::TyPat<'a>), Arm(&'a hir::Arm<'a>), } @@ -198,6 +199,7 @@ impl<'a> State<'a> { Node::TraitRef(a) => self.print_trait_ref(a), Node::OpaqueTy(o) => self.print_opaque_ty(o), Node::Pat(a) => self.print_pat(a), + Node::TyPat(a) => self.print_ty_pat(a), Node::PatField(a) => self.print_patfield(a), Node::PatExpr(a) => self.print_pat_expr(a), Node::Arm(a) => self.print_arm(a), @@ -224,6 +226,16 @@ impl<'a> State<'a> { Node::Err(_) => self.word("/*ERROR*/"), } } + + fn print_generic_arg(&mut self, generic_arg: &GenericArg<'_>, elide_lifetimes: bool) { + match generic_arg { + GenericArg::Lifetime(lt) if !elide_lifetimes => self.print_lifetime(lt), + GenericArg::Lifetime(_) => {} + GenericArg::Type(ty) => self.print_type(ty.as_unambig_ty()), + GenericArg::Const(ct) => self.print_const_arg(ct.as_unambig_ct()), + GenericArg::Infer(_inf) => self.word("_"), + } + } } impl std::ops::Deref for State<'_> { @@ -448,7 +460,7 @@ impl<'a> State<'a> { hir::TyKind::Pat(ty, pat) => { self.print_type(ty); self.word(" is "); - self.print_pat(pat); + self.print_ty_pat(pat); } } self.end() @@ -1797,13 +1809,7 @@ impl<'a> State<'a> { if nonelided_generic_args { start_or_comma(self); self.commasep(Inconsistent, generic_args.args, |s, generic_arg| { - match generic_arg { - GenericArg::Lifetime(lt) if !elide_lifetimes => s.print_lifetime(lt), - GenericArg::Lifetime(_) => {} - GenericArg::Type(ty) => s.print_type(ty.as_unambig_ty()), - GenericArg::Const(ct) => s.print_const_arg(ct.as_unambig_ct()), - GenericArg::Infer(_inf) => s.word("_"), - } + s.print_generic_arg(generic_arg, elide_lifetimes) }); } @@ -1864,6 +1870,33 @@ impl<'a> State<'a> { } } + fn print_ty_pat(&mut self, pat: &hir::TyPat<'_>) { + self.maybe_print_comment(pat.span.lo()); + self.ann.pre(self, AnnNode::TyPat(pat)); + // Pat isn't normalized, but the beauty of it + // is that it doesn't matter + match pat.kind { + TyPatKind::Range(begin, end, end_kind) => { + if let Some(expr) = begin { + self.print_const_arg(expr); + } + match end_kind { + RangeEnd::Included => self.word("..."), + RangeEnd::Excluded => self.word(".."), + } + if let Some(expr) = end { + self.print_const_arg(expr); + } + } + TyPatKind::Err(_) => { + self.popen(); + self.word("/*ERROR*/"); + self.pclose(); + } + } + self.ann.post(self, AnnNode::TyPat(pat)) + } + fn print_pat(&mut self, pat: &hir::Pat<'_>) { self.maybe_print_comment(pat.span.lo()); self.ann.pre(self, AnnNode::Pat(pat)); diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index a519e177fbccd..838cd1e03f980 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -412,7 +412,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }) | hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Const(..), .. }) => true, - hir::Node::Pat(_) => { + hir::Node::TyPat(_) | hir::Node::Pat(_) => { self.dcx().span_delayed_bug(expr.span, "place expr not allowed in pattern"); true } diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 926760b84aaeb..4df4624971df1 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -937,6 +937,7 @@ impl<'hir> Map<'hir> { Node::TraitRef(tr) => tr.path.span, Node::OpaqueTy(op) => op.span, Node::Pat(pat) => pat.span, + Node::TyPat(pat) => pat.span, Node::PatField(field) => field.span, Node::PatExpr(lit) => lit.span, Node::Arm(arm) => arm.span, @@ -1212,6 +1213,7 @@ fn hir_id_to_string(map: Map<'_>, id: HirId) -> String { Node::TraitRef(_) => node_str("trait ref"), Node::OpaqueTy(_) => node_str("opaque type"), Node::Pat(_) => node_str("pat"), + Node::TyPat(_) => node_str("pat ty"), Node::PatField(_) => node_str("pattern field"), Node::PatExpr(_) => node_str("pattern literal"), Node::Param(_) => node_str("param"), diff --git a/compiler/rustc_passes/src/hir_id_validator.rs b/compiler/rustc_passes/src/hir_id_validator.rs index f6b70d9389bb9..74038b24dccd3 100644 --- a/compiler/rustc_passes/src/hir_id_validator.rs +++ b/compiler/rustc_passes/src/hir_id_validator.rs @@ -162,7 +162,7 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for HirIdValidator<'a, 'hir> { 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) + fn visit_pattern_type_pattern(&mut self, p: &'hir hir::TyPat<'hir>) { + intravisit::walk_ty_pat(self, p) } } diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index d0eb5318e645b..4bbf28115a681 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -10,7 +10,7 @@ use rustc_hir::{ AssocItemConstraint, BinOpKind, BindingMode, Block, BodyId, Closure, ConstArg, ConstArgKind, Expr, ExprField, ExprKind, FnRetTy, GenericArg, GenericArgs, HirId, HirIdMap, InlineAsmOperand, LetExpr, Lifetime, LifetimeName, Pat, PatExpr, PatExprKind, PatField, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, StructTailExpr, - TraitBoundModifiers, Ty, TyKind, + TraitBoundModifiers, Ty, TyKind, TyPat, TyPatKind, }; use rustc_lexer::{TokenKind, tokenize}; use rustc_lint::LateContext; @@ -1102,6 +1102,22 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { } } + pub fn hash_ty_pat(&mut self, pat: &TyPat<'_>) { + std::mem::discriminant(&pat.kind).hash(&mut self.s); + match pat.kind { + TyPatKind::Range(s, e, i) => { + if let Some(s) = s { + self.hash_const_arg(s); + } + if let Some(e) = e { + self.hash_const_arg(e); + } + std::mem::discriminant(&i).hash(&mut self.s); + }, + TyPatKind::Err(_) => {}, + } + } + pub fn hash_pat(&mut self, pat: &Pat<'_>) { std::mem::discriminant(&pat.kind).hash(&mut self.s); match pat.kind { @@ -1247,7 +1263,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { }, TyKind::Pat(ty, pat) => { self.hash_ty(ty); - self.hash_pat(pat); + self.hash_ty_pat(pat); }, TyKind::Ptr(mut_ty) => { self.hash_ty(mut_ty.ty); diff --git a/tests/ui/type/pattern_types/bad_const_generics_args_on_const_param.rs b/tests/ui/type/pattern_types/bad_const_generics_args_on_const_param.rs index c5f8b2764ecb0..05e308de7b1e8 100644 --- a/tests/ui/type/pattern_types/bad_const_generics_args_on_const_param.rs +++ b/tests/ui/type/pattern_types/bad_const_generics_args_on_const_param.rs @@ -6,5 +6,6 @@ type Pat = //~^ ERROR type and const arguments are not allowed on const parameter `START` //~| ERROR generic arguments are not allowed on const parameter `END` //~| ERROR associated item constraints are not allowed here +//~| ERROR `_` is not allowed within types on item signatures for type aliases fn main() {} diff --git a/tests/ui/type/pattern_types/bad_const_generics_args_on_const_param.stderr b/tests/ui/type/pattern_types/bad_const_generics_args_on_const_param.stderr index f31809bf397c8..c4ba89de3f36e 100644 --- a/tests/ui/type/pattern_types/bad_const_generics_args_on_const_param.stderr +++ b/tests/ui/type/pattern_types/bad_const_generics_args_on_const_param.stderr @@ -32,7 +32,13 @@ error[E0229]: associated item constraints are not allowed here LL | std::pat::pattern_type!(u32 is START::<(), i32, 2>..=END::<_, Assoc = ()>); | ^^^^^^^^^^ associated item constraint not allowed here -error: aborting due to 3 previous errors +error[E0121]: the placeholder `_` is not allowed within types on item signatures for type aliases + --> $DIR/bad_const_generics_args_on_const_param.rs:5:64 + | +LL | std::pat::pattern_type!(u32 is START::<(), i32, 2>..=END::<_, Assoc = ()>); + | ^ not allowed in type signatures + +error: aborting due to 4 previous errors -Some errors have detailed explanations: E0109, E0229. +Some errors have detailed explanations: E0109, E0121, E0229. For more information about an error, try `rustc --explain E0109`. diff --git a/tests/ui/type/pattern_types/bad_pat.rs b/tests/ui/type/pattern_types/bad_pat.rs index 6cb2a0f1f8e74..549b0d11dd187 100644 --- a/tests/ui/type/pattern_types/bad_pat.rs +++ b/tests/ui/type/pattern_types/bad_pat.rs @@ -8,6 +8,6 @@ type NonNullU32_2 = pattern_type!(u32 is 1..=); type Positive2 = pattern_type!(i32 is 0..=); //~^ ERROR: inclusive range with no end type Wild = pattern_type!(() is _); -//~^ ERROR: wildcard patterns are not permitted for pattern types +//~^ ERROR: pattern not supported in pattern types fn main() {} diff --git a/tests/ui/type/pattern_types/bad_pat.stderr b/tests/ui/type/pattern_types/bad_pat.stderr index c857cc3c3add9..d2a5a20bf89b6 100644 --- a/tests/ui/type/pattern_types/bad_pat.stderr +++ b/tests/ui/type/pattern_types/bad_pat.stderr @@ -24,7 +24,7 @@ LL - type Positive2 = pattern_type!(i32 is 0..=); LL + type Positive2 = pattern_type!(i32 is 0..); | -error: wildcard patterns are not permitted for pattern types +error: pattern not supported in pattern types --> $DIR/bad_pat.rs:10:33 | LL | type Wild = pattern_type!(() is _); diff --git a/tests/ui/type/pattern_types/nested.rs b/tests/ui/type/pattern_types/nested.rs index 519fb3f05b483..9ca9c7923dedd 100644 --- a/tests/ui/type/pattern_types/nested.rs +++ b/tests/ui/type/pattern_types/nested.rs @@ -9,16 +9,20 @@ use std::pat::pattern_type; // or still validate correctly. const BAD_NESTING: pattern_type!(pattern_type!(u32 is 1..) is 0..) = todo!(); //~^ ERROR: not a valid base type for range patterns +//~| ERROR: mismatched types // We want to get the most narrowest version that a pattern could be const BAD_NESTING2: pattern_type!(pattern_type!(i32 is 1..) is ..=-1) = todo!(); //~^ ERROR: not a valid base type for range patterns +//~| ERROR: mismatched types const BAD_NESTING3: pattern_type!(pattern_type!(i32 is 1..) is ..0) = todo!(); //~^ ERROR: not a valid base type for range patterns +//~| ERROR: mismatched types const BAD_NESTING4: pattern_type!(() is ..0) = todo!(); //~^ ERROR: not a valid base type for range patterns +//~| ERROR: mismatched types const BAD_NESTING5: pattern_type!(f32 is 1.0 .. 2.0) = todo!(); //~^ ERROR: not a valid base type for range patterns diff --git a/tests/ui/type/pattern_types/nested.stderr b/tests/ui/type/pattern_types/nested.stderr index 99d3979e98c49..b753b0a9c9baa 100644 --- a/tests/ui/type/pattern_types/nested.stderr +++ b/tests/ui/type/pattern_types/nested.stderr @@ -11,52 +11,86 @@ LL | const BAD_NESTING: pattern_type!(pattern_type!(u32 is 1..) is 0..) = todo!( | ^^^ error: `(i32) is 1..=` is not a valid base type for range patterns - --> $DIR/nested.rs:14:35 + --> $DIR/nested.rs:15:35 | LL | const BAD_NESTING2: pattern_type!(pattern_type!(i32 is 1..) is ..=-1) = todo!(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ | note: range patterns only support integers - --> $DIR/nested.rs:14:64 + --> $DIR/nested.rs:15:64 | LL | const BAD_NESTING2: pattern_type!(pattern_type!(i32 is 1..) is ..=-1) = todo!(); | ^^^^^ error: `(i32) is 1..=` is not a valid base type for range patterns - --> $DIR/nested.rs:17:35 + --> $DIR/nested.rs:19:35 | LL | const BAD_NESTING3: pattern_type!(pattern_type!(i32 is 1..) is ..0) = todo!(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ | note: range patterns only support integers - --> $DIR/nested.rs:17:64 + --> $DIR/nested.rs:19:64 | LL | const BAD_NESTING3: pattern_type!(pattern_type!(i32 is 1..) is ..0) = todo!(); | ^^^ error: `()` is not a valid base type for range patterns - --> $DIR/nested.rs:20:35 + --> $DIR/nested.rs:23:35 | LL | const BAD_NESTING4: pattern_type!(() is ..0) = todo!(); | ^^ | note: range patterns only support integers - --> $DIR/nested.rs:20:41 + --> $DIR/nested.rs:23:41 | LL | const BAD_NESTING4: pattern_type!(() is ..0) = todo!(); | ^^^ error: `f32` is not a valid base type for range patterns - --> $DIR/nested.rs:23:35 + --> $DIR/nested.rs:27:35 | LL | const BAD_NESTING5: pattern_type!(f32 is 1.0 .. 2.0) = todo!(); | ^^^ | note: range patterns only support integers - --> $DIR/nested.rs:23:42 + --> $DIR/nested.rs:27:42 | LL | const BAD_NESTING5: pattern_type!(f32 is 1.0 .. 2.0) = todo!(); | ^^^^^^^^^^ -error: aborting due to 5 previous errors +error[E0308]: mismatched types + --> $DIR/nested.rs:10:63 + | +LL | const BAD_NESTING: pattern_type!(pattern_type!(u32 is 1..) is 0..) = todo!(); + | ^ expected `(u32) is 1..=`, found integer + | + = note: expected pattern type `(u32) is 1..=` + found type `{integer}` + +error[E0308]: mismatched types + --> $DIR/nested.rs:15:67 + | +LL | const BAD_NESTING2: pattern_type!(pattern_type!(i32 is 1..) is ..=-1) = todo!(); + | ^^ expected `(i32) is 1..=`, found integer + | + = note: expected pattern type `(i32) is 1..=` + found type `{integer}` + +error[E0308]: mismatched types + --> $DIR/nested.rs:19:66 + | +LL | const BAD_NESTING3: pattern_type!(pattern_type!(i32 is 1..) is ..0) = todo!(); + | ^ expected `(i32) is 1..=`, found integer + | + = note: expected pattern type `(i32) is 1..=` + found type `{integer}` + +error[E0308]: mismatched types + --> $DIR/nested.rs:23:43 + | +LL | const BAD_NESTING4: pattern_type!(() is ..0) = todo!(); + | ^ expected `()`, found integer + +error: aborting due to 9 previous errors +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/type/pattern_types/pattern_type_mismatch.rs b/tests/ui/type/pattern_types/pattern_type_mismatch.rs index 8d375d7932bc6..0c88f27d83686 100644 --- a/tests/ui/type/pattern_types/pattern_type_mismatch.rs +++ b/tests/ui/type/pattern_types/pattern_type_mismatch.rs @@ -1,20 +1,16 @@ //! Check that pattern types patterns must be of the type of the base type -//@ known-bug: unknown -//@ failure-status: 101 -//@ normalize-stderr: "note: .*\n\n" -> "" -//@ normalize-stderr: "thread 'rustc' panicked.*\n" -> "" -//@ normalize-stderr: "(error: internal compiler error: [^:]+):\d+:\d+: " -> "$1:LL:CC: " -//@ normalize-stderr: "(delayed at compiler/rustc_mir_transform/src/lib.rs:)\d+:\d+" -> "$1:LL:CC" -//@ rustc-env:RUST_BACKTRACE=0 - #![feature(pattern_types)] #![feature(pattern_type_macro)] use std::pat::pattern_type; const BAD_NESTING4: pattern_type!(u8 is 'a'..='a') = todo!(); +//~^ ERROR: mismatched types +//~| ERROR: mismatched types const BAD_NESTING5: pattern_type!(char is 1..=1) = todo!(); +//~^ ERROR: mismatched types +//~| ERROR: mismatched types fn main() {} diff --git a/tests/ui/type/pattern_types/pattern_type_mismatch.stderr b/tests/ui/type/pattern_types/pattern_type_mismatch.stderr index ee413133ab317..19b0c1059c86f 100644 --- a/tests/ui/type/pattern_types/pattern_type_mismatch.stderr +++ b/tests/ui/type/pattern_types/pattern_type_mismatch.stderr @@ -1,31 +1,37 @@ -error: internal compiler error: ty::ConstKind::Error constructed but no error reported +error[E0308]: mismatched types + --> $DIR/pattern_type_mismatch.rs:8:41 | - = error: internal compiler error: ty::ConstKind::Error constructed but no error reported +LL | const BAD_NESTING4: pattern_type!(u8 is 'a'..='a') = todo!(); + | ^^^ expected `u8`, found `char` + | +help: if you meant to write a byte literal, prefix with `b` | - = note: delayed at compiler/rustc_mir_build/src/thir/constant.rs:72:21 - disabled backtrace - = error: internal compiler error: mir_const_qualif: MIR had errors - --> $DIR/pattern_type_mismatch.rs:16:1 +LL | const BAD_NESTING4: pattern_type!(u8 is b'a'..='a') = todo!(); + | ~~~~ + +error[E0308]: mismatched types + --> $DIR/pattern_type_mismatch.rs:8:47 | LL | const BAD_NESTING4: pattern_type!(u8 is 'a'..='a') = todo!(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^ expected `u8`, found `char` | -note: delayed at compiler/rustc_mir_transform/src/lib.rs::LL:CC - disabled backtrace - --> $DIR/pattern_type_mismatch.rs:16:1 +help: if you meant to write a byte literal, prefix with `b` | -LL | const BAD_NESTING4: pattern_type!(u8 is 'a'..='a') = todo!(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | const BAD_NESTING4: pattern_type!(u8 is 'a'..=b'a') = todo!(); + | ~~~~ -error: internal compiler error: mir_const_qualif: MIR had errors - --> $DIR/pattern_type_mismatch.rs:18:1 +error[E0308]: mismatched types + --> $DIR/pattern_type_mismatch.rs:12:43 | LL | const BAD_NESTING5: pattern_type!(char is 1..=1) = todo!(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: delayed at compiler/rustc_mir_transform/src/lib.rs::LL:CC - disabled backtrace - --> $DIR/pattern_type_mismatch.rs:18:1 + | ^ expected `char`, found `u8` + +error[E0308]: mismatched types + --> $DIR/pattern_type_mismatch.rs:12:47 | LL | const BAD_NESTING5: pattern_type!(char is 1..=1) = todo!(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^ expected `char`, found `u8` + +error: aborting due to 4 previous errors -query stack during panic: -end of query stack +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/type/pattern_types/unimplemented_pat.rs b/tests/ui/type/pattern_types/unimplemented_pat.rs index b2398cec7c9b5..44851ec1a1049 100644 --- a/tests/ui/type/pattern_types/unimplemented_pat.rs +++ b/tests/ui/type/pattern_types/unimplemented_pat.rs @@ -1,14 +1,14 @@ //! This test ensures we do not ICE for unimplemented -//! patterns unless the feature gate is enabled. +//! patterns even if the feature gate is enabled. -#![feature(pattern_type_macro)] +#![feature(pattern_type_macro, pattern_types)] use std::pat::pattern_type; type Always = pattern_type!(Option is Some(_)); -//~^ ERROR: pattern types are unstable +//~^ ERROR: pattern not supported type Binding = pattern_type!(Option is x); -//~^ ERROR: pattern types are unstable +//~^ ERROR: pattern not supported fn main() {} diff --git a/tests/ui/type/pattern_types/unimplemented_pat.stderr b/tests/ui/type/pattern_types/unimplemented_pat.stderr index 7b0f9cbaa6a96..a1e55ed02c45a 100644 --- a/tests/ui/type/pattern_types/unimplemented_pat.stderr +++ b/tests/ui/type/pattern_types/unimplemented_pat.stderr @@ -1,23 +1,14 @@ -error[E0658]: pattern types are unstable - --> $DIR/unimplemented_pat.rs:8:15 +error: pattern not supported in pattern types + --> $DIR/unimplemented_pat.rs:8:44 | LL | type Always = pattern_type!(Option is Some(_)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #123646 for more information - = help: add `#![feature(pattern_types)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + | ^^^^^^^ -error[E0658]: pattern types are unstable - --> $DIR/unimplemented_pat.rs:11:16 +error: pattern not supported in pattern types + --> $DIR/unimplemented_pat.rs:11:45 | LL | type Binding = pattern_type!(Option is x); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #123646 for more information - = help: add `#![feature(pattern_types)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + | ^ error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0658`. From fbcaa9b0a16cb3eed67cc3dc2429574f28dcac17 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 7 Jan 2025 16:39:30 +0000 Subject: [PATCH 2/2] Allow using named consts in pattern types --- compiler/rustc_ast_lowering/src/pat.rs | 27 +++---- .../src/collect/generics_of.rs | 1 + .../pattern_types/assoc_const.default.stderr | 36 ++++++++++ tests/ui/type/pattern_types/assoc_const.rs | 24 +++++++ .../bad_const_generics_args_on_const_param.rs | 11 +-- ..._const_generics_args_on_const_param.stderr | 48 +++---------- tests/ui/type/pattern_types/const_block.rs | 10 +++ .../ui/type/pattern_types/const_block.stderr | 72 +++++++++++++++++++ tests/ui/type/pattern_types/free_const.rs | 13 ++++ 9 files changed, 186 insertions(+), 56 deletions(-) create mode 100644 tests/ui/type/pattern_types/assoc_const.default.stderr create mode 100644 tests/ui/type/pattern_types/assoc_const.rs create mode 100644 tests/ui/type/pattern_types/const_block.rs create mode 100644 tests/ui/type/pattern_types/const_block.stderr create mode 100644 tests/ui/type/pattern_types/free_const.rs diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index 57f15f99760aa..bb9b2a13185ba 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -440,17 +440,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let node = loop { match &pattern.kind { PatKind::Range(e1, e2, Spanned { node: end, .. }) => { + // FIXME(pattern_types): remove this closure and call `lower_const_arg` instead. + // That requires first modifying the AST to have const args here. let mut lower_expr = |e: &Expr| -> &_ { - let kind = if let ExprKind::Path(qself, path) = &e.kind { - hir::ConstArgKind::Path(self.lower_qpath( - e.id, - qself, - path, - ParamMode::Optional, - AllowReturnTypeNotation::No, - ImplTraitContext::Disallowed(ImplTraitPosition::Path), - None, - )) + if let ExprKind::Path(None, path) = &e.kind + && let Some(res) = self + .resolver + .get_partial_res(e.id) + .and_then(|partial_res| partial_res.full_res()) + { + self.lower_const_path_to_const_arg(path, res, e.id, e.span) } else { let node_id = self.next_node_id(); let def_id = self.create_def( @@ -467,9 +466,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { body: self.lower_const_body(pattern.span, Some(e)), span: self.lower_span(pattern.span), }); - hir::ConstArgKind::Anon(ac) - }; - self.arena.alloc(hir::ConstArg { hir_id: self.next_id(), kind }) + self.arena.alloc(hir::ConstArg { + hir_id: self.next_id(), + kind: hir::ConstArgKind::Anon(ac), + }) + } }; break hir::TyPatKind::Range( e1.as_deref().map(|e| lower_expr(e)), diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index 2ac8acbd3a4bd..c0902398a54ae 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -198,6 +198,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { { Some(parent_did) } + Node::TyPat(_) => Some(parent_did), _ => None, } } diff --git a/tests/ui/type/pattern_types/assoc_const.default.stderr b/tests/ui/type/pattern_types/assoc_const.default.stderr new file mode 100644 index 0000000000000..abda40e468162 --- /dev/null +++ b/tests/ui/type/pattern_types/assoc_const.default.stderr @@ -0,0 +1,36 @@ +error: constant expression depends on a generic parameter + --> $DIR/assoc_const.rs:17:19 + | +LL | fn foo(_: pattern_type!(u32 is ::START..=::END)) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: constant expression depends on a generic parameter + --> $DIR/assoc_const.rs:17:19 + | +LL | fn foo(_: pattern_type!(u32 is ::START..=::END)) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this may fail depending on what value the parameter takes + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: constant expression depends on a generic parameter + --> $DIR/assoc_const.rs:20:19 + | +LL | fn bar(_: pattern_type!(u32 is T::START..=T::END)) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: constant expression depends on a generic parameter + --> $DIR/assoc_const.rs:20:19 + | +LL | fn bar(_: pattern_type!(u32 is T::START..=T::END)) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this may fail depending on what value the parameter takes + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 4 previous errors + diff --git a/tests/ui/type/pattern_types/assoc_const.rs b/tests/ui/type/pattern_types/assoc_const.rs new file mode 100644 index 0000000000000..af0f7e4cbf32f --- /dev/null +++ b/tests/ui/type/pattern_types/assoc_const.rs @@ -0,0 +1,24 @@ +#![feature(pattern_types)] +#![feature(pattern_type_macro)] +#![cfg_attr(const_arg, feature(generic_const_exprs))] +#![expect(incomplete_features)] + +//@ revisions: default const_arg + +//@[const_arg] check-pass + +use std::pat::pattern_type; + +trait Foo { + const START: u32; + const END: u32; +} + +fn foo(_: pattern_type!(u32 is ::START..=::END)) {} +//[default]~^ ERROR: constant expression depends on a generic parameter +//[default]~| ERROR: constant expression depends on a generic parameter +fn bar(_: pattern_type!(u32 is T::START..=T::END)) {} +//[default]~^ ERROR: constant expression depends on a generic parameter +//[default]~| ERROR: constant expression depends on a generic parameter + +fn main() {} diff --git a/tests/ui/type/pattern_types/bad_const_generics_args_on_const_param.rs b/tests/ui/type/pattern_types/bad_const_generics_args_on_const_param.rs index 05e308de7b1e8..0f10bf8ce627c 100644 --- a/tests/ui/type/pattern_types/bad_const_generics_args_on_const_param.rs +++ b/tests/ui/type/pattern_types/bad_const_generics_args_on_const_param.rs @@ -1,11 +1,14 @@ +//@known-bug: #127972 +//@ failure-status: 101 +//@ normalize-stderr: "note: .*\n\n" -> "" +//@ normalize-stderr: "thread 'rustc' panicked.*\n" -> "" +//@ normalize-stderr: "(error: internal compiler error: [^:]+):\d+:\d+: " -> "$1:LL:CC: " +//@ rustc-env:RUST_BACKTRACE=0 + #![feature(pattern_types, pattern_type_macro)] #![allow(internal_features)] type Pat = std::pat::pattern_type!(u32 is START::<(), i32, 2>..=END::<_, Assoc = ()>); -//~^ ERROR type and const arguments are not allowed on const parameter `START` -//~| ERROR generic arguments are not allowed on const parameter `END` -//~| ERROR associated item constraints are not allowed here -//~| ERROR `_` is not allowed within types on item signatures for type aliases fn main() {} diff --git a/tests/ui/type/pattern_types/bad_const_generics_args_on_const_param.stderr b/tests/ui/type/pattern_types/bad_const_generics_args_on_const_param.stderr index c4ba89de3f36e..fbe80a19863db 100644 --- a/tests/ui/type/pattern_types/bad_const_generics_args_on_const_param.stderr +++ b/tests/ui/type/pattern_types/bad_const_generics_args_on_const_param.stderr @@ -1,44 +1,14 @@ -error[E0109]: type and const arguments are not allowed on const parameter `START` - --> $DIR/bad_const_generics_args_on_const_param.rs:5:44 +error: internal compiler error: compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs:LL:CC: try_lower_anon_const_lit: received const param which shouldn't be possible + --> $DIR/bad_const_generics_args_on_const_param.rs:12:36 | LL | std::pat::pattern_type!(u32 is START::<(), i32, 2>..=END::<_, Assoc = ()>); - | ----- ^^ ^^^ ^ type and const arguments not allowed - | | - | not allowed on const parameter `START` - | -note: const parameter `START` defined here - --> $DIR/bad_const_generics_args_on_const_param.rs:4:16 - | -LL | type Pat = - | ^^^^^ - -error[E0109]: generic arguments are not allowed on const parameter `END` - --> $DIR/bad_const_generics_args_on_const_param.rs:5:64 - | -LL | std::pat::pattern_type!(u32 is START::<(), i32, 2>..=END::<_, Assoc = ()>); - | --- ^ generic argument not allowed - | | - | not allowed on const parameter `END` - | -note: const parameter `END` defined here - --> $DIR/bad_const_generics_args_on_const_param.rs:4:34 - | -LL | type Pat = - | ^^^ - -error[E0229]: associated item constraints are not allowed here - --> $DIR/bad_const_generics_args_on_const_param.rs:5:67 - | -LL | std::pat::pattern_type!(u32 is START::<(), i32, 2>..=END::<_, Assoc = ()>); - | ^^^^^^^^^^ associated item constraint not allowed here + | ^^^^^^^^^^^^^^^^^^^ -error[E0121]: the placeholder `_` is not allowed within types on item signatures for type aliases - --> $DIR/bad_const_generics_args_on_const_param.rs:5:64 - | -LL | std::pat::pattern_type!(u32 is START::<(), i32, 2>..=END::<_, Assoc = ()>); - | ^ not allowed in type signatures -error: aborting due to 4 previous errors +Box +query stack during panic: +#0 [type_of] expanding type alias `Pat` +#1 [check_well_formed] checking that `Pat` is well-formed +... and 2 other queries... use `env RUST_BACKTRACE=1` to see the full query stack +error: aborting due to 1 previous error -Some errors have detailed explanations: E0109, E0121, E0229. -For more information about an error, try `rustc --explain E0109`. diff --git a/tests/ui/type/pattern_types/const_block.rs b/tests/ui/type/pattern_types/const_block.rs new file mode 100644 index 0000000000000..49c87f4fa0d65 --- /dev/null +++ b/tests/ui/type/pattern_types/const_block.rs @@ -0,0 +1,10 @@ +#![feature(pattern_types)] +#![feature(pattern_type_macro)] +#![feature(inline_const_pat)] + +use std::pat::pattern_type; + +fn bar(x: pattern_type!(u32 is 0..=const{ 5 + 5 })) {} +//~^ ERROR: cycle + +fn main() {} diff --git a/tests/ui/type/pattern_types/const_block.stderr b/tests/ui/type/pattern_types/const_block.stderr new file mode 100644 index 0000000000000..82b616105afa7 --- /dev/null +++ b/tests/ui/type/pattern_types/const_block.stderr @@ -0,0 +1,72 @@ +error[E0391]: cycle detected when evaluating type-level constant + --> $DIR/const_block.rs:7:36 + | +LL | fn bar(x: pattern_type!(u32 is 0..=const{ 5 + 5 })) {} + | ^^^^^^^^^^^^^^ + | +note: ...which requires const-evaluating + checking `bar::{constant#2}`... + --> $DIR/const_block.rs:7:36 + | +LL | fn bar(x: pattern_type!(u32 is 0..=const{ 5 + 5 })) {} + | ^^^^^^^^^^^^^^ +note: ...which requires caching mir of `bar::{constant#2}` for CTFE... + --> $DIR/const_block.rs:7:36 + | +LL | fn bar(x: pattern_type!(u32 is 0..=const{ 5 + 5 })) {} + | ^^^^^^^^^^^^^^ +note: ...which requires elaborating drops for `bar::{constant#2}`... + --> $DIR/const_block.rs:7:36 + | +LL | fn bar(x: pattern_type!(u32 is 0..=const{ 5 + 5 })) {} + | ^^^^^^^^^^^^^^ +note: ...which requires borrow-checking `bar::{constant#2}`... + --> $DIR/const_block.rs:7:36 + | +LL | fn bar(x: pattern_type!(u32 is 0..=const{ 5 + 5 })) {} + | ^^^^^^^^^^^^^^ +note: ...which requires borrow-checking `bar::{constant#0}`... + --> $DIR/const_block.rs:7:41 + | +LL | fn bar(x: pattern_type!(u32 is 0..=const{ 5 + 5 })) {} + | ^^^^^^^^^ +note: ...which requires promoting constants in MIR for `bar::{constant#0}`... + --> $DIR/const_block.rs:7:41 + | +LL | fn bar(x: pattern_type!(u32 is 0..=const{ 5 + 5 })) {} + | ^^^^^^^^^ +note: ...which requires const checking `bar::{constant#0}`... + --> $DIR/const_block.rs:7:41 + | +LL | fn bar(x: pattern_type!(u32 is 0..=const{ 5 + 5 })) {} + | ^^^^^^^^^ +note: ...which requires building MIR for `bar::{constant#0}`... + --> $DIR/const_block.rs:7:41 + | +LL | fn bar(x: pattern_type!(u32 is 0..=const{ 5 + 5 })) {} + | ^^^^^^^^^ +note: ...which requires match-checking `bar::{constant#0}`... + --> $DIR/const_block.rs:7:41 + | +LL | fn bar(x: pattern_type!(u32 is 0..=const{ 5 + 5 })) {} + | ^^^^^^^^^ +note: ...which requires type-checking `bar::{constant#0}`... + --> $DIR/const_block.rs:7:41 + | +LL | fn bar(x: pattern_type!(u32 is 0..=const{ 5 + 5 })) {} + | ^^^^^^^^^ +note: ...which requires type-checking `bar`... + --> $DIR/const_block.rs:7:1 + | +LL | fn bar(x: pattern_type!(u32 is 0..=const{ 5 + 5 })) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: ...which again requires evaluating type-level constant, completing the cycle +note: cycle used when checking that `bar` is well-formed + --> $DIR/const_block.rs:7:1 + | +LL | fn bar(x: pattern_type!(u32 is 0..=const{ 5 + 5 })) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/type/pattern_types/free_const.rs b/tests/ui/type/pattern_types/free_const.rs new file mode 100644 index 0000000000000..2e29fce237970 --- /dev/null +++ b/tests/ui/type/pattern_types/free_const.rs @@ -0,0 +1,13 @@ +//@ check-pass + +#![feature(pattern_types)] +#![feature(pattern_type_macro)] + +use std::pat::pattern_type; + +const START: u32 = 0; +const END: u32 = 10; + +fn foo(_: pattern_type!(u32 is START..=END)) {} + +fn main() {}