diff --git a/crates/hir-def/src/expr_store.rs b/crates/hir-def/src/expr_store.rs index 4dc72672314c..6d6e369cd685 100644 --- a/crates/hir-def/src/expr_store.rs +++ b/crates/hir-def/src/expr_store.rs @@ -616,7 +616,7 @@ impl ExpressionStore { visitor.on_expr_opt(*end); } Pat::Lit(expr) | Pat::ConstBlock(expr) | Pat::Expr(expr) => visitor.on_expr(*expr), - Pat::Path(_) | Pat::Wild | Pat::Missing | Pat::Rest => {} + Pat::Path(_) | Pat::Wild | Pat::Missing | Pat::Rest | Pat::NotNull => {} &Pat::Bind { subpat, id: _ } => visitor.on_pat_opt(subpat), Pat::Or(args) | Pat::Tuple { args, ellipsis: _ } => visitor.on_pats(args), Pat::TupleStruct { args, ellipsis: _, path } => { @@ -855,6 +855,10 @@ impl ExpressionStore { pub fn visit_type_ref_children(&self, type_ref: TypeRefId, mut visitor: impl StoreVisitor) { match &self[type_ref] { TypeRef::Never | TypeRef::Placeholder | TypeRef::TypeParam(_) | TypeRef::Error => {} + &TypeRef::PatternType(ty, pat) => { + visitor.on_type(ty); + visitor.on_pat(pat) + } TypeRef::Tuple(types) => visitor.on_types(types), TypeRef::Path(path) => visitor.on_path(path), TypeRef::RawPtr(inner, _) | TypeRef::Slice(inner) => visitor.on_type(*inner), diff --git a/crates/hir-def/src/expr_store/body.rs b/crates/hir-def/src/expr_store/body.rs index 2fb47e59c546..01423d5109d0 100644 --- a/crates/hir-def/src/expr_store/body.rs +++ b/crates/hir-def/src/expr_store/body.rs @@ -9,7 +9,7 @@ use syntax::ast; use triomphe::Arc; use crate::{ - DefWithBodyId, HasModule, + DefWithBodyId, ExpressionStoreOwnerId, HasModule, db::DefDatabase, expr_store::{ ExpressionStore, ExpressionStoreSourceMap, SelfParamPtr, lower::lower_body, pretty, @@ -160,12 +160,12 @@ impl Body { pub fn pretty_print_pat( &self, db: &dyn DefDatabase, - owner: DefWithBodyId, + owner: ExpressionStoreOwnerId, pat: PatId, oneline: bool, edition: Edition, ) -> String { - pretty::print_pat_hir(db, self, owner.into(), pat, oneline, edition) + pretty::print_pat_hir(db, self, owner, pat, oneline, edition) } } diff --git a/crates/hir-def/src/expr_store/lower.rs b/crates/hir-def/src/expr_store/lower.rs index 881809650024..76503ac97c1a 100644 --- a/crates/hir-def/src/expr_store/lower.rs +++ b/crates/hir-def/src/expr_store/lower.rs @@ -719,6 +719,10 @@ impl<'db> ExprCollector<'db> { ast::Type::DynTraitType(inner) => TypeRef::DynTrait( self.type_bounds_from_ast(inner.type_bound_list(), impl_trait_lower_fn), ), + ast::Type::PatternType(inner) => TypeRef::PatternType( + self.lower_type_ref_opt(inner.ty(), impl_trait_lower_fn), + self.collect_pat_top(inner.pat()), + ), ast::Type::MacroType(mt) => match mt.macro_call() { Some(mcall) => { let macro_ptr = AstPtr::new(&mcall); @@ -2782,6 +2786,7 @@ impl<'db> ExprCollector<'db> { let inner = self.collect_pat_opt(inner.pat(), binding_list); Pat::Deref { inner } } + ast::Pat::NotNull(_) => Pat::NotNull, ast::Pat::ConstBlockPat(const_block_pat) => { if let Some(block) = const_block_pat.block_expr() { let expr_id = self.with_label_rib(RibKind::Constant, |this| { diff --git a/crates/hir-def/src/expr_store/pretty.rs b/crates/hir-def/src/expr_store/pretty.rs index 34cedbd728f9..4dc7ebebbb1c 100644 --- a/crates/hir-def/src/expr_store/pretty.rs +++ b/crates/hir-def/src/expr_store/pretty.rs @@ -906,6 +906,7 @@ impl Printer<'_> { Pat::Missing => w!(self, "�"), Pat::Rest => w!(self, ".."), Pat::Wild => w!(self, "_"), + Pat::NotNull => w!(self, "!null"), Pat::Tuple { args, ellipsis } => { w!(self, "("); for (i, pat) in args.iter().enumerate() { @@ -1346,6 +1347,11 @@ impl Printer<'_> { w!(self, "dyn "); self.print_type_bounds(bounds); } + TypeRef::PatternType(ty, pat) => { + self.print_type_ref(*ty); + w!(self, " is "); + self.print_pat(*pat); + } } } diff --git a/crates/hir-def/src/hir.rs b/crates/hir-def/src/hir.rs index 6eba85926403..4c8d835ad7fc 100644 --- a/crates/hir-def/src/hir.rs +++ b/crates/hir-def/src/hir.rs @@ -717,6 +717,7 @@ pub enum Pat { Deref { inner: PatId, }, + NotNull, ConstBlock(ExprId), /// An expression inside a pattern. That can only occur inside assignments. /// @@ -734,7 +735,8 @@ impl Pat { | Pat::Wild | Pat::Missing | Pat::Rest - | Pat::Expr(_) => {} + | Pat::Expr(_) + | Pat::NotNull => {} Pat::Bind { subpat, .. } => { subpat.iter().copied().for_each(f); } diff --git a/crates/hir-def/src/hir/type_ref.rs b/crates/hir-def/src/hir/type_ref.rs index 43e29c1f5ffc..6cd8377b5fc6 100644 --- a/crates/hir-def/src/hir/type_ref.rs +++ b/crates/hir-def/src/hir/type_ref.rs @@ -9,7 +9,7 @@ use thin_vec::ThinVec; use crate::{ LifetimeParamId, TypeParamId, expr_store::{ExpressionStore, path::Path}, - hir::ExprId, + hir::{ExprId, PatId}, }; #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] @@ -139,6 +139,7 @@ pub enum TypeRef { ImplTrait(ThinVec), DynTrait(ThinVec), TypeParam(TypeParamId), + PatternType(TypeRefId, PatId), Error, } diff --git a/crates/hir-def/src/lib.rs b/crates/hir-def/src/lib.rs index 3aaf89102fab..f9d5fe12e8a2 100644 --- a/crates/hir-def/src/lib.rs +++ b/crates/hir-def/src/lib.rs @@ -837,6 +837,12 @@ impl From for ExpressionStoreOwnerId { } } +impl From for ExpressionStoreOwnerId { + fn from(id: ImplId) -> Self { + ExpressionStoreOwnerId::Signature(id.into()) + } +} + impl GenericDefId { pub fn file_id_and_params_of( self, diff --git a/crates/hir-expand/src/builtin/derive_macro.rs b/crates/hir-expand/src/builtin/derive_macro.rs index 8b031e364775..e8321cd8da72 100644 --- a/crates/hir-expand/src/builtin/derive_macro.rs +++ b/crates/hir-expand/src/builtin/derive_macro.rs @@ -1494,6 +1494,9 @@ fn coerce_pointee_expand( ast::Type::TupleType(ty) => any_long(ty.fields(), |ty| { substitute_type_in_bound(editor, ty, param_name, replacement) }), + ast::Type::PatternType(ty) => ty + .ty() + .is_some_and(|ty| substitute_type_in_bound(editor, ty, param_name, replacement)), ast::Type::InferType(_) | ast::Type::MacroType(_) | ast::Type::NeverType(_) => false, }; diff --git a/crates/hir-expand/src/builtin/fn_macro.rs b/crates/hir-expand/src/builtin/fn_macro.rs index eb7175c686a0..9181ad88b6cc 100644 --- a/crates/hir-expand/src/builtin/fn_macro.rs +++ b/crates/hir-expand/src/builtin/fn_macro.rs @@ -137,6 +137,7 @@ register_builtin! { (const_format_args, ConstFormatArgs) => format_args_expand, (format_args_nl, FormatArgsNl) => format_args_nl_expand, (quote, Quote) => quote_expand, + (pattern_type, PatternType) => pattern_type_expand, EagerExpander: (compile_error, CompileError) => compile_error_expand, @@ -994,3 +995,15 @@ fn unescape_str(s: &str) -> Cow<'_, str> { Cow::Borrowed(s) } } + +fn pattern_type_expand( + _db: &dyn ExpandDatabase, + _arg_id: MacroCallId, + tt: &tt::TopSubtree, + call_site: Span, +) -> ExpandResult { + let mut tt = tt.clone(); + tt.set_top_subtree_delimiter_kind(tt::DelimiterKind::Invisible); + let pound = mk_pound(call_site); + ExpandResult::ok(quote! {call_site => builtin #pound pattern_type ( #tt ) }) +} diff --git a/crates/hir-ty/src/diagnostics/unsafe_check.rs b/crates/hir-ty/src/diagnostics/unsafe_check.rs index c37a194d4757..3c69c6a44b12 100644 --- a/crates/hir-ty/src/diagnostics/unsafe_check.rs +++ b/crates/hir-ty/src/diagnostics/unsafe_check.rs @@ -255,9 +255,8 @@ impl<'db> UnsafeVisitor<'db> { | Pat::Box { .. } | Pat::Deref { .. } | Pat::Expr(..) - | Pat::ConstBlock(..) => { - self.on_unsafe_op(current.into(), UnsafetyReason::UnionField) - } + | Pat::ConstBlock(..) + | Pat::NotNull => self.on_unsafe_op(current.into(), UnsafetyReason::UnionField), // `Or` only wraps other patterns, and `Missing`/`Wild` do not constitute a read. Pat::Missing | Pat::Rest | Pat::Wild | Pat::Or(_) => {} } diff --git a/crates/hir-ty/src/display.rs b/crates/hir-ty/src/display.rs index 326f920b118e..c93e4a265787 100644 --- a/crates/hir-ty/src/display.rs +++ b/crates/hir-ty/src/display.rs @@ -15,7 +15,7 @@ use hir_def::{ expr_store::{ExpressionStore, path::Path}, find_path::{self, PrefixKind}, hir::{ - ClosureKind as HirClosureKind, CoroutineKind, + ClosureKind as HirClosureKind, CoroutineKind, PatId, generics::{GenericParams, TypeOrConstParamData, TypeParamProvenance, WherePredicate}, }, item_scope::ItemInNs, @@ -2362,39 +2362,58 @@ pub fn write_visibility<'db>( } pub trait HirDisplayWithExpressionStore<'db> { - fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>, store: &ExpressionStore) -> Result; + fn hir_fmt( + &self, + f: &mut HirFormatter<'_, 'db>, + owner: ExpressionStoreOwnerId, + store: &ExpressionStore, + ) -> Result; } impl<'db, T: ?Sized + HirDisplayWithExpressionStore<'db>> HirDisplayWithExpressionStore<'db> for &'_ T { - fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>, store: &ExpressionStore) -> Result { - T::hir_fmt(&**self, f, store) + fn hir_fmt( + &self, + f: &mut HirFormatter<'_, 'db>, + owner: ExpressionStoreOwnerId, + store: &ExpressionStore, + ) -> Result { + T::hir_fmt(&**self, f, owner, store) } } pub fn hir_display_with_store<'a, 'db, T: HirDisplayWithExpressionStore<'db> + 'a>( value: T, + owner: ExpressionStoreOwnerId, store: &'a ExpressionStore, ) -> impl HirDisplay<'db> + 'a { - ExpressionStoreAdapter(value, store) + ExpressionStoreAdapter(value, owner, store) } -struct ExpressionStoreAdapter<'a, T>(T, &'a ExpressionStore); +struct ExpressionStoreAdapter<'a, T>(T, ExpressionStoreOwnerId, &'a ExpressionStore); impl<'a, T> ExpressionStoreAdapter<'a, T> { - fn wrap(store: &'a ExpressionStore) -> impl Fn(T) -> ExpressionStoreAdapter<'a, T> { - move |value| ExpressionStoreAdapter(value, store) + fn wrap( + owner: ExpressionStoreOwnerId, + store: &'a ExpressionStore, + ) -> impl Fn(T) -> ExpressionStoreAdapter<'a, T> { + move |value| ExpressionStoreAdapter(value, owner, store) } } impl<'db, T: HirDisplayWithExpressionStore<'db>> HirDisplay<'db> for ExpressionStoreAdapter<'_, T> { fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result { - T::hir_fmt(&self.0, f, self.1) + T::hir_fmt(&self.0, f, self.1, self.2) } } impl<'db> HirDisplayWithExpressionStore<'db> for LifetimeRefId { - fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>, store: &ExpressionStore) -> Result { + fn hir_fmt( + &self, + f: &mut HirFormatter<'_, 'db>, + _owner: ExpressionStoreOwnerId, + store: &ExpressionStore, + ) -> Result { match &store[*self] { LifetimeRef::Named(name) => write!(f, "{}", name.display(f.db, f.edition())), LifetimeRef::Static => write!(f, "'static"), @@ -2413,7 +2432,12 @@ impl<'db> HirDisplayWithExpressionStore<'db> for LifetimeRefId { } impl<'db> HirDisplayWithExpressionStore<'db> for TypeRefId { - fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>, store: &ExpressionStore) -> Result { + fn hir_fmt( + &self, + f: &mut HirFormatter<'_, 'db>, + owner: ExpressionStoreOwnerId, + store: &ExpressionStore, + ) -> Result { match &store[*self] { TypeRef::Never => write!(f, "!")?, TypeRef::TypeParam(param) => { @@ -2438,7 +2462,7 @@ impl<'db> HirDisplayWithExpressionStore<'db> for TypeRefId { } _ => None, }) - .map(ExpressionStoreAdapter::wrap(store)), + .map(ExpressionStoreAdapter::wrap(owner, store)), " + ", )?; } @@ -2447,20 +2471,20 @@ impl<'db> HirDisplayWithExpressionStore<'db> for TypeRefId { TypeRef::Placeholder => write!(f, "_")?, TypeRef::Tuple(elems) => { write!(f, "(")?; - f.write_joined(elems.iter().map(ExpressionStoreAdapter::wrap(store)), ", ")?; + f.write_joined(elems.iter().map(ExpressionStoreAdapter::wrap(owner, store)), ", ")?; if elems.len() == 1 { write!(f, ",")?; } write!(f, ")")?; } - TypeRef::Path(path) => path.hir_fmt(f, store)?, + TypeRef::Path(path) => path.hir_fmt(f, owner, store)?, TypeRef::RawPtr(inner, mutability) => { let mutability = match mutability { hir_def::type_ref::Mutability::Shared => "*const ", hir_def::type_ref::Mutability::Mut => "*mut ", }; write!(f, "{mutability}")?; - inner.hir_fmt(f, store)?; + inner.hir_fmt(f, owner, store)?; } TypeRef::Reference(ref_) => { let mutability = match ref_.mutability { @@ -2469,22 +2493,22 @@ impl<'db> HirDisplayWithExpressionStore<'db> for TypeRefId { }; write!(f, "&")?; if let Some(lifetime) = &ref_.lifetime { - lifetime.hir_fmt(f, store)?; + lifetime.hir_fmt(f, owner, store)?; write!(f, " ")?; } write!(f, "{mutability}")?; - ref_.ty.hir_fmt(f, store)?; + ref_.ty.hir_fmt(f, owner, store)?; } TypeRef::Array(array) => { write!(f, "[")?; - array.ty.hir_fmt(f, store)?; + array.ty.hir_fmt(f, owner, store)?; write!(f, "; ")?; - array.len.hir_fmt(f, store)?; + array.len.hir_fmt(f, owner, store)?; write!(f, "]")?; } TypeRef::Slice(inner) => { write!(f, "[")?; - inner.hir_fmt(f, store)?; + inner.hir_fmt(f, owner, store)?; write!(f, "]")?; } TypeRef::Fn(fn_) => { @@ -2504,7 +2528,7 @@ impl<'db> HirDisplayWithExpressionStore<'db> for TypeRefId { write!(f, "{}: ", name.display(f.db, f.edition()))?; } - param_type.hir_fmt(f, store)?; + param_type.hir_fmt(f, owner, store)?; if index != function_parameters.len() - 1 { write!(f, ", ")?; @@ -2518,18 +2542,29 @@ impl<'db> HirDisplayWithExpressionStore<'db> for TypeRefId { TypeRef::Tuple(tup) if tup.is_empty() => {} _ => { write!(f, " -> ")?; - return_type.hir_fmt(f, store)?; + return_type.hir_fmt(f, owner, store)?; } } } } TypeRef::ImplTrait(bounds) => { write!(f, "impl ")?; - f.write_joined(bounds.iter().map(ExpressionStoreAdapter::wrap(store)), " + ")?; + f.write_joined( + bounds.iter().map(ExpressionStoreAdapter::wrap(owner, store)), + " + ", + )?; } TypeRef::DynTrait(bounds) => { write!(f, "dyn ")?; - f.write_joined(bounds.iter().map(ExpressionStoreAdapter::wrap(store)), " + ")?; + f.write_joined( + bounds.iter().map(ExpressionStoreAdapter::wrap(owner, store)), + " + ", + )?; + } + TypeRef::PatternType(ty, pat) => { + ty.hir_fmt(f, owner, store)?; + write!(f, " is ")?; + pat.hir_fmt(f, owner, store)?; } TypeRef::Error => write!(f, "{{error}}")?, } @@ -2538,7 +2573,12 @@ impl<'db> HirDisplayWithExpressionStore<'db> for TypeRefId { } impl<'db> HirDisplayWithExpressionStore<'db> for ConstRef { - fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>, _store: &ExpressionStore) -> Result { + fn hir_fmt( + &self, + f: &mut HirFormatter<'_, 'db>, + _owner: ExpressionStoreOwnerId, + _store: &ExpressionStore, + ) -> Result { // FIXME write!(f, "{{const}}")?; @@ -2546,17 +2586,45 @@ impl<'db> HirDisplayWithExpressionStore<'db> for ConstRef { } } +impl<'db> HirDisplayWithExpressionStore<'db> for PatId { + fn hir_fmt( + &self, + f: &mut HirFormatter<'_, 'db>, + owner: ExpressionStoreOwnerId, + store: &ExpressionStore, + ) -> Result { + write!( + f, + "{}", + hir_def::expr_store::pretty::print_pat_hir( + f.db, + store, + owner, + *self, + false, + f.edition() + ) + )?; + Ok(()) + } +} + impl<'db> HirDisplayWithExpressionStore<'db> for TypeBound { - fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>, store: &ExpressionStore) -> Result { + fn hir_fmt( + &self, + f: &mut HirFormatter<'_, 'db>, + owner: ExpressionStoreOwnerId, + store: &ExpressionStore, + ) -> Result { match self { &TypeBound::Path(path, modifier) => { match modifier { TraitBoundModifier::None => (), TraitBoundModifier::Maybe => write!(f, "?")?, } - store[path].hir_fmt(f, store) + store[path].hir_fmt(f, owner, store) } - TypeBound::Lifetime(lifetime) => lifetime.hir_fmt(f, store), + TypeBound::Lifetime(lifetime) => lifetime.hir_fmt(f, owner, store), TypeBound::ForLifetime(lifetimes, path) => { let edition = f.edition(); write!( @@ -2564,7 +2632,7 @@ impl<'db> HirDisplayWithExpressionStore<'db> for TypeBound { "for<{}> ", lifetimes.iter().map(|it| it.display(f.db, edition)).format(", ") )?; - store[*path].hir_fmt(f, store) + store[*path].hir_fmt(f, owner, store) } TypeBound::Use(args) => { write!(f, "use<")?; @@ -2572,7 +2640,7 @@ impl<'db> HirDisplayWithExpressionStore<'db> for TypeBound { let last = args.len().saturating_sub(1); for (idx, arg) in args.iter().enumerate() { match arg { - UseArgRef::Lifetime(lt) => lt.hir_fmt(f, store)?, + UseArgRef::Lifetime(lt) => lt.hir_fmt(f, owner, store)?, UseArgRef::Name(n) => write!(f, "{}", n.display(f.db, edition))?, } if idx != last { @@ -2587,11 +2655,16 @@ impl<'db> HirDisplayWithExpressionStore<'db> for TypeBound { } impl<'db> HirDisplayWithExpressionStore<'db> for Path { - fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>, store: &ExpressionStore) -> Result { + fn hir_fmt( + &self, + f: &mut HirFormatter<'_, 'db>, + owner: ExpressionStoreOwnerId, + store: &ExpressionStore, + ) -> Result { match (self.type_anchor(), self.kind()) { (Some(anchor), _) => { write!(f, "<")?; - anchor.hir_fmt(f, store)?; + anchor.hir_fmt(f, owner, store)?; write!(f, ">")?; } (_, PathKind::Plain) => {} @@ -2634,7 +2707,7 @@ impl<'db> HirDisplayWithExpressionStore<'db> for Path { }); if let Some(ty) = trait_self_ty { write!(f, "<")?; - ty.hir_fmt(f, store)?; + ty.hir_fmt(f, owner, store)?; write!(f, " as ")?; // Now format the path of the trait... } @@ -2664,17 +2737,17 @@ impl<'db> HirDisplayWithExpressionStore<'db> for Path { if let Some(v) = tuple { if v.len() == 1 { write!(f, "(")?; - v[0].hir_fmt(f, store)?; + v[0].hir_fmt(f, owner, store)?; write!(f, ")")?; } else { - generic_args.args[0].hir_fmt(f, store)?; + generic_args.args[0].hir_fmt(f, owner, store)?; } } if let Some(ret) = generic_args.bindings[0].type_ref && !matches!(&store[ret], TypeRef::Tuple(v) if v.is_empty()) { write!(f, " -> ")?; - ret.hir_fmt(f, store)?; + ret.hir_fmt(f, owner, store)?; } } hir_def::expr_store::path::GenericArgsParentheses::No => { @@ -2687,7 +2760,7 @@ impl<'db> HirDisplayWithExpressionStore<'db> for Path { } else { write!(f, ", ")?; } - arg.hir_fmt(f, store)?; + arg.hir_fmt(f, owner, store)?; } for binding in generic_args.bindings.iter() { if first { @@ -2700,7 +2773,7 @@ impl<'db> HirDisplayWithExpressionStore<'db> for Path { match &binding.type_ref { Some(ty) => { write!(f, " = ")?; - ty.hir_fmt(f, store)? + ty.hir_fmt(f, owner, store)? } None => { write!(f, ": ")?; @@ -2708,7 +2781,7 @@ impl<'db> HirDisplayWithExpressionStore<'db> for Path { binding .bounds .iter() - .map(ExpressionStoreAdapter::wrap(store)), + .map(ExpressionStoreAdapter::wrap(owner, store)), " + ", )?; } @@ -2735,14 +2808,21 @@ impl<'db> HirDisplayWithExpressionStore<'db> for Path { } impl<'db> HirDisplayWithExpressionStore<'db> for hir_def::expr_store::path::GenericArg { - fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>, store: &ExpressionStore) -> Result { + fn hir_fmt( + &self, + f: &mut HirFormatter<'_, 'db>, + owner: ExpressionStoreOwnerId, + store: &ExpressionStore, + ) -> Result { match self { - hir_def::expr_store::path::GenericArg::Type(ty) => ty.hir_fmt(f, store), + hir_def::expr_store::path::GenericArg::Type(ty) => ty.hir_fmt(f, owner, store), hir_def::expr_store::path::GenericArg::Const(_c) => { // write!(f, "{}", c.display(f.db, f.edition())) write!(f, "") } - hir_def::expr_store::path::GenericArg::Lifetime(lifetime) => lifetime.hir_fmt(f, store), + hir_def::expr_store::path::GenericArg::Lifetime(lifetime) => { + lifetime.hir_fmt(f, owner, store) + } } } } diff --git a/crates/hir-ty/src/infer/closure/analysis/expr_use_visitor.rs b/crates/hir-ty/src/infer/closure/analysis/expr_use_visitor.rs index deafff6b43e0..322f8d128f75 100644 --- a/crates/hir-ty/src/infer/closure/analysis/expr_use_visitor.rs +++ b/crates/hir-ty/src/infer/closure/analysis/expr_use_visitor.rs @@ -1023,6 +1023,7 @@ impl<'a, 'b, 'db, D: Delegate<'db>> ExprUseVisitor<'a, 'b, 'db, D> { | Pat::Tuple { .. } | Pat::Wild | Pat::Missing + | Pat::NotNull | Pat::Rest => { // If the PatKind is Or, Box, Ref, Guard, or Tuple, the relevant accesses // are made later as these patterns contains subpatterns. @@ -1696,6 +1697,7 @@ impl<'db, D: Delegate<'db>> ExprUseVisitor<'_, '_, 'db, D> { | Pat::Range { .. } | Pat::Missing | Pat::Rest + | Pat::NotNull | Pat::Wild => { // always ok } diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs index 0675b5e8578f..90ecfbd7e93d 100644 --- a/crates/hir-ty/src/infer/expr.rs +++ b/crates/hir-ty/src/infer/expr.rs @@ -201,6 +201,7 @@ impl<'db> InferenceContext<'_, 'db> { | Pat::Slice { .. } | Pat::ConstBlock(_) | Pat::Record { .. } + | Pat::NotNull | Pat::Missing => true, Pat::Expr(_) => unreachable!( "we don't call pat_guaranteed_to_constitute_read_for_never() with assignments" diff --git a/crates/hir-ty/src/infer/pat.rs b/crates/hir-ty/src/infer/pat.rs index f21438647c14..60957f4942be 100644 --- a/crates/hir-ty/src/infer/pat.rs +++ b/crates/hir-ty/src/infer/pat.rs @@ -448,7 +448,7 @@ impl<'a, 'db> InferenceContext<'a, 'db> { ) } Pat::Missing => self.types.types.error, - Pat::Wild | Pat::Rest => expected, + Pat::Wild | Pat::Rest | Pat::NotNull => expected, // We allow any type here; we ensure that the type is uninhabited during match checking. // Pat::Never => expected, Pat::Path(_) => { @@ -662,6 +662,8 @@ impl<'a, 'db> InferenceContext<'a, 'db> { Pat::Ref { .. } // No need to do anything on a missing pattern. | Pat::Missing + // No need to do anything on a `NotNull` pattern, they are only allowed in type contexts. + | Pat::NotNull // A `_`/`..` pattern works with any expected type, so there's no need to do anything. | Pat::Wild | Pat::Rest // Bindings also work with whatever the expected type is, diff --git a/crates/hir-ty/src/layout.rs b/crates/hir-ty/src/layout.rs index 3e569076ad9e..78df93311ef4 100644 --- a/crates/hir-ty/src/layout.rs +++ b/crates/hir-ty/src/layout.rs @@ -37,6 +37,9 @@ pub use self::{adt::layout_of_adt_query, target::target_data_layout_query}; pub(crate) mod adt; pub(crate) mod target; +#[cfg(test)] +mod tests; + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct RustcEnumVariantIdx(pub usize); @@ -341,12 +344,14 @@ pub fn layout_of_ty_query( return db .layout_of_ty(args.as_coroutine_closure().tupled_upvars_ty().store(), trait_env); } - TyKind::CoroutineWitness(_, _) => { return Err(LayoutError::NotImplemented); } - TyKind::Pat(_, _) | TyKind::UnsafeBinder(_) => { + TyKind::Pat(_ty, _pat) => { + return Err(LayoutError::NotImplemented); + } + TyKind::UnsafeBinder(_) => { return Err(LayoutError::NotImplemented); } @@ -411,6 +416,3 @@ fn field_ty<'a>( fn scalar_unit(dl: &TargetDataLayout, value: Primitive) -> Scalar { Scalar::Initialized { value, valid_range: WrappingRange::full(value.size(dl)) } } - -#[cfg(test)] -mod tests; diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs index 0cb1a2db2689..ec42b8a3493b 100644 --- a/crates/hir-ty/src/lower.rs +++ b/crates/hir-ty/src/lower.rs @@ -18,9 +18,12 @@ use hir_def::{ TypeAliasId, TypeOrConstParamId, TypeParamId, UnionId, VariantId, builtin_type::BuiltinType, expr_store::{ExpressionStore, path::Path}, - hir::generics::{ - GenericParamDataRef, GenericParams, LocalTypeOrConstParamId, TypeOrConstParamData, - TypeParamProvenance, WherePredicate, + hir::{ + ExprId, + generics::{ + GenericParamDataRef, GenericParams, LocalTypeOrConstParamId, TypeOrConstParamData, + TypeParamProvenance, WherePredicate, + }, }, item_tree::FieldsShape, lang_item::LangItems, @@ -60,10 +63,10 @@ use crate::{ next_solver::{ AliasTy, Binder, BoundExistentialPredicates, Clause, ClauseKind, Clauses, Const, ConstKind, DbInterner, DefaultAny, EarlyBinder, EarlyParamRegion, ErrorGuaranteed, FnSigKind, - FxIndexMap, GenericArg, GenericArgs, ParamConst, ParamEnv, PolyFnSig, Predicate, Region, - StoredClauses, StoredEarlyBinder, StoredGenericArg, StoredGenericArgs, StoredPolyFnSig, - StoredTraitRef, StoredTy, TraitPredicate, TraitRef, Ty, Tys, Unnormalized, abi::Safety, - util::BottomUpFolder, + FxIndexMap, GenericArg, GenericArgs, ParamConst, ParamEnv, Pattern, PolyFnSig, Predicate, + Region, StoredClauses, StoredEarlyBinder, StoredGenericArg, StoredGenericArgs, + StoredPolyFnSig, StoredTraitRef, StoredTy, TraitPredicate, TraitRef, Ty, Tys, Unnormalized, + abi::Safety, util::BottomUpFolder, }, }; @@ -357,6 +360,14 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { } pub(crate) fn lower_const(&mut self, const_ref: ConstRef, const_type: Ty<'db>) -> Const<'db> { + self.lower_expr_as_const(const_ref.expr, const_type) + } + + pub(crate) fn lower_expr_as_const( + &mut self, + expr_id: ExprId, + const_type: Ty<'db>, + ) -> Const<'db> { #[expect(clippy::manual_map, reason = "a `map()` here generates a borrowck error")] let create_var = match &mut self.infer_vars { Some(infer_vars) => Some( @@ -368,7 +379,7 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { self.interner, self.def, self.store, - const_ref.expr, + expr_id, self.resolver, const_type, &|| self.generics.get_or_init(|| generics(self.db, self.generic_def)), @@ -528,6 +539,24 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { } } } + &TypeRef::PatternType(ty, pat) => { + let ty = self.lower_ty(ty); + // FIXME: Properly do the lowering here + let pat_kind = match self.store[pat] { + hir_def::hir::Pat::Range { + start: Some(start), + end: Some(end), + range_type: _, + } => rustc_type_ir::PatternKind::Range { + start: self.lower_expr_as_const(start, ty), + end: self.lower_expr_as_const(end, ty), + }, + hir_def::hir::Pat::NotNull => rustc_type_ir::PatternKind::NotNull, + _ => rustc_type_ir::PatternKind::NotNull, + }; + let pat = Pattern::new(self.interner, pat_kind); + Ty::new_pat(self.interner, ty, pat) + } TypeRef::Error => self.types.types.error, }; (ty, res) diff --git a/crates/hir-ty/src/mir/lower.rs b/crates/hir-ty/src/mir/lower.rs index 3852db909e39..95939d458b26 100644 --- a/crates/hir-ty/src/mir/lower.rs +++ b/crates/hir-ty/src/mir/lower.rs @@ -276,10 +276,11 @@ impl MirLowerError { db: &dyn HirDatabase, p: &Path, display_target: DisplayTarget, + owner: ExpressionStoreOwnerId, store: &ExpressionStore, ) -> Self { Self::UnresolvedName( - hir_display_with_store(p, store).display(db, display_target).to_string(), + hir_display_with_store(p, owner, store).display(db, display_target).to_string(), ) } } @@ -517,6 +518,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { self.db, p, DisplayTarget::from_crate(self.db, self.krate()), + self.owner.expression_store_owner(self.db), self.store, ) })?; @@ -884,10 +886,12 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { }; let variant_id = self.infer.variant_resolution_for_expr(expr_id).ok_or_else(|| { - MirLowerError::UnresolvedName( - hir_display_with_store(path, self.store) - .display(self.db, self.display_target()) - .to_string(), + MirLowerError::unresolved_path( + self.db, + path, + self.display_target(), + self.owner.expression_store_owner(self.db), + self.store, ) })?; let subst = match self.expr_ty_without_adjust(expr_id).kind() { @@ -1432,6 +1436,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { self.db, c, DisplayTarget::from_crate(db, owner.krate(db)), + self.owner.expression_store_owner(self.db), self.store, ) }; diff --git a/crates/hir-ty/src/mir/lower/pattern_matching.rs b/crates/hir-ty/src/mir/lower/pattern_matching.rs index c924c5bdf0fd..2cb2143229ee 100644 --- a/crates/hir-ty/src/mir/lower/pattern_matching.rs +++ b/crates/hir-ty/src/mir/lower/pattern_matching.rs @@ -132,7 +132,9 @@ impl<'db> MirLowerCtx<'_, 'db> { .into(), ); Ok(match &self.store[pattern] { - Pat::Missing | Pat::Rest => return Err(MirLowerError::IncompletePattern), + Pat::Missing | Pat::Rest | Pat::NotNull => { + return Err(MirLowerError::IncompletePattern); + } Pat::Wild => (current, current_else), Pat::Tuple { args, ellipsis } => { let subst = match self.infer.pat_ty(pattern).kind() { @@ -376,6 +378,7 @@ impl<'db> MirLowerCtx<'_, 'db> { self.db, p, self.display_target(), + self.owner.expression_store_owner(self.db), self.store, ) }; diff --git a/crates/hir/src/display.rs b/crates/hir/src/display.rs index a71851ea8cef..c3af5fa7cef8 100644 --- a/crates/hir/src/display.rs +++ b/crates/hir/src/display.rs @@ -2,7 +2,8 @@ use either::Either; use hir_def::{ - AdtId, BuiltinDeriveImplId, FunctionId, GenericDefId, ImplId, ItemContainerId, + AdtId, BuiltinDeriveImplId, DefWithBodyId, ExpressionStoreOwnerId, FunctionId, GenericDefId, + ImplId, ItemContainerId, builtin_derive::BuiltinDeriveImplMethod, expr_store::{Body, ExpressionStore}, hir::generics::{GenericParams, TypeOrConstParamData, TypeParamProvenance, WherePredicate}, @@ -102,8 +103,11 @@ impl<'db> HirDisplay<'db> for Function { if f.show_container_bounds() && !params.is_empty() { write_trait_header(trait_.into(), f)?; f.write_char('\n')?; - has_disaplayable_predicates(f.db, params, params_store) - .then_some((params, params_store)) + has_disaplayable_predicates(f.db, params, params_store).then_some(( + params, + trait_.into(), + params_store, + )) } else { None } @@ -113,8 +117,11 @@ impl<'db> HirDisplay<'db> for Function { if f.show_container_bounds() && !params.is_empty() { write_impl_header(impl_, f)?; f.write_char('\n')?; - has_disaplayable_predicates(f.db, params, params_store) - .then_some((params, params_store)) + has_disaplayable_predicates(f.db, params, params_store).then_some(( + params, + impl_.into(), + params_store, + )) } else { None } @@ -125,7 +132,7 @@ impl<'db> HirDisplay<'db> for Function { // Write signature of the function let has_written_where = write_function(f, id)?; - if let Some((container_params, container_params_store)) = container_params { + if let Some((container_params, owner, container_params_store)) = container_params { if !has_written_where { f.write_str("\nwhere")?; } @@ -135,7 +142,12 @@ impl<'db> HirDisplay<'db> for Function { _ => unreachable!(), }; write!(f, "\n // Bounds from {container_name}:",)?; - write_where_predicates(container_params, container_params_store, f)?; + write_where_predicates( + container_params, + ExpressionStoreOwnerId::Signature(owner), + container_params_store, + f, + )?; } Ok(()) } @@ -197,6 +209,7 @@ fn write_function<'db>(f: &mut HirFormatter<'_, 'db>, func_id: FunctionId) -> Re let comma = if too_long_param { ",\n " } else { ", " }; // FIXME: Use resolved `param.ty` once we no longer discard lifetimes let body = Body::of(db, func_id.into()); + let owner = DefWithBodyId::FunctionId(func_id).into(); for (type_ref, param) in data.params.iter().zip(func.assoc_fn_params(db)).skip(skip_self) { if !first { f.write_str(comma)?; @@ -205,11 +218,11 @@ fn write_function<'db>(f: &mut HirFormatter<'_, 'db>, func_id: FunctionId) -> Re } let pat_id = body.params[param.idx - body.self_param().is_some() as usize]; - let pat_str = body.pretty_print_pat(db, func_id.into(), pat_id, true, f.edition()); + let pat_str = body.pretty_print_pat(db, owner, pat_id, true, f.edition()); f.write_str(&pat_str)?; f.write_str(": ")?; - type_ref.hir_fmt(f, &data.store)?; + type_ref.hir_fmt(f, owner, &data.store)?; } if data.is_varargs() { @@ -258,7 +271,7 @@ fn write_function<'db>(f: &mut HirFormatter<'_, 'db>, func_id: FunctionId) -> Re TypeRef::Tuple(tup) if tup.is_empty() => {} _ => { f.write_str(" -> ")?; - ret_type.hir_fmt(f, &data.store)?; + ret_type.hir_fmt(f, owner, &data.store)?; } } } @@ -278,7 +291,8 @@ fn write_impl_header<'db>(impl_: ImplId, f: &mut HirFormatter<'_, 'db>) -> Resul let impl_data = ImplSignature::of(db, impl_); if let Some(target_trait) = &impl_data.target_trait { f.write_char(' ')?; - hir_display_with_store(&impl_data.store[target_trait.path], &impl_data.store).hir_fmt(f)?; + hir_display_with_store(&impl_data.store[target_trait.path], impl_.into(), &impl_data.store) + .hir_fmt(f)?; f.write_str(" for")?; } @@ -306,13 +320,14 @@ impl<'db> HirDisplay<'db> for SelfParam { }; let data = FunctionSignature::of(f.db, func); let param = *data.params.first().unwrap(); + let owner = ExpressionStoreOwnerId::Body(func.into()); match &data.store[param] { TypeRef::Path(p) if p.is_self_type() => f.write_str("self"), TypeRef::Reference(ref_) if matches!(&data.store[ref_.ty], TypeRef::Path(p) if p.is_self_type()) => { f.write_char('&')?; if let Some(lifetime) = &ref_.lifetime { - lifetime.hir_fmt(f, &data.store)?; + lifetime.hir_fmt(f, owner, &data.store)?; f.write_char(' ')?; } if let hir_def::type_ref::Mutability::Mut = ref_.mutability { @@ -322,7 +337,7 @@ impl<'db> HirDisplay<'db> for SelfParam { } _ => { f.write_str("self: ")?; - param.hir_fmt(f, &data.store) + param.hir_fmt(f, owner, &data.store) } } } @@ -517,7 +532,11 @@ impl<'db> HirDisplay<'db> for EnumVariant { f.write_str(", ")?; } // Enum variant fields must be pub. - field.type_ref.hir_fmt(f, &data.store)?; + field.type_ref.hir_fmt( + f, + ExpressionStoreOwnerId::VariantFields(self.id.into()), + &data.store, + )?; } f.write_char(')')?; } @@ -666,6 +685,7 @@ fn write_generic_params_or_args<'db>( include_defaults: bool, ) -> Result { let (params, store) = GenericParams::with_store(f.db, def); + let owner = def.into(); if params.iter_lt().next().is_none() && params.iter_type_or_consts().all(|it| it.1.const_param().is_none()) && params @@ -701,17 +721,17 @@ fn write_generic_params_or_args<'db>( write!(f, "{}", name.display(f.db, f.edition()))?; if include_defaults && let Some(default) = &ty.default { f.write_str(" = ")?; - default.hir_fmt(f, store)?; + default.hir_fmt(f, owner, store)?; } } TypeOrConstParamData::ConstParamData(c) => { delim(f)?; write!(f, "const {}: ", name.display(f.db, f.edition()))?; - c.ty.hir_fmt(f, store)?; + c.ty.hir_fmt(f, owner, store)?; if include_defaults && let Some(default) = &c.default { f.write_str(" = ")?; - default.hir_fmt(f, store)?; + default.hir_fmt(f, owner, store)?; } } } @@ -729,7 +749,7 @@ fn write_where_clause<'db>(def: GenericDefId, f: &mut HirFormatter<'_, 'db>) -> } f.write_str("\nwhere")?; - write_where_predicates(params, store, f)?; + write_where_predicates(params, def.into(), store, f)?; Ok(true) } @@ -752,6 +772,7 @@ fn has_disaplayable_predicates( fn write_where_predicates<'db>( params: &GenericParams, + owner: ExpressionStoreOwnerId, store: &ExpressionStore, f: &mut HirFormatter<'_, 'db>, ) -> Result { @@ -783,29 +804,31 @@ fn write_where_predicates<'db>( f.write_str("\n ")?; match pred { TypeBound { target, bound } => { - target.hir_fmt(f, store)?; + target.hir_fmt(f, owner, store)?; f.write_str(": ")?; - bound.hir_fmt(f, store)?; + bound.hir_fmt(f, owner, store)?; } Lifetime { target, bound } => { - target.hir_fmt(f, store)?; + target.hir_fmt(f, owner, store)?; write!(f, ": ")?; - bound.hir_fmt(f, store)?; + bound.hir_fmt(f, owner, store)?; } ForLifetime { lifetimes, target, bound } => { let lifetimes = lifetimes.iter().map(|it| it.display(f.db, f.edition())).join(", "); write!(f, "for<{lifetimes}> ")?; - target.hir_fmt(f, store)?; + target.hir_fmt(f, owner, store)?; f.write_str(": ")?; - bound.hir_fmt(f, store)?; + bound.hir_fmt(f, owner, store)?; } } while let Some(nxt) = iter.next_if(|nxt| check_same_target(pred, nxt)) { f.write_str(" + ")?; match nxt { - TypeBound { bound, .. } | ForLifetime { bound, .. } => bound.hir_fmt(f, store)?, - Lifetime { bound, .. } => bound.hir_fmt(f, store)?, + TypeBound { bound, .. } | ForLifetime { bound, .. } => { + bound.hir_fmt(f, owner, store)? + } + Lifetime { bound, .. } => bound.hir_fmt(f, owner, store)?, } } f.write_str(",")?; @@ -830,7 +853,7 @@ impl<'db> HirDisplay<'db> for Const { Some(name) => write!(f, "{}: ", name.display(f.db, f.edition()))?, None => f.write_str("_: ")?, } - data.type_ref.hir_fmt(f, &data.store)?; + data.type_ref.hir_fmt(f, ExpressionStoreOwnerId::Signature(self.id.into()), &data.store)?; Ok(()) } } @@ -844,7 +867,7 @@ impl<'db> HirDisplay<'db> for Static { f.write_str("mut ")?; } write!(f, "{}: ", data.name.display(f.db, f.edition()))?; - data.type_ref.hir_fmt(f, &data.store)?; + data.type_ref.hir_fmt(f, ExpressionStoreOwnerId::Signature(self.id.into()), &data.store)?; Ok(()) } } @@ -925,13 +948,19 @@ impl<'db> HirDisplay<'db> for TypeAlias { if !data.bounds.is_empty() { f.write_str(": ")?; f.write_joined( - data.bounds.iter().map(|bound| hir_display_with_store(bound, &data.store)), + data.bounds.iter().map(|bound| { + hir_display_with_store( + bound, + ExpressionStoreOwnerId::Signature(self.id.into()), + &data.store, + ) + }), " + ", )?; } if let Some(ty) = data.ty { f.write_str(" = ")?; - ty.hir_fmt(f, &data.store)?; + ty.hir_fmt(f, ExpressionStoreOwnerId::Signature(self.id.into()), &data.store)?; } write_where_clause(def_id, f)?; Ok(()) diff --git a/crates/hir/src/symbols.rs b/crates/hir/src/symbols.rs index ff56544d82e0..4841de700068 100644 --- a/crates/hir/src/symbols.rs +++ b/crates/hir/src/symbols.rs @@ -401,7 +401,7 @@ impl<'a> SymbolCollector<'a> { fn collect_from_impl(&mut self, impl_id: ImplId) { let impl_data = ImplSignature::of(self.db, impl_id); let impl_name = Some( - hir_display_with_store(impl_data.self_ty, &impl_data.store) + hir_display_with_store(impl_data.self_ty, impl_id.into(), &impl_data.store) .display( self.db, crate::Impl::from(impl_id).krate(self.db).to_display_target(self.db), diff --git a/crates/ide-assists/src/handlers/convert_let_else_to_match.rs b/crates/ide-assists/src/handlers/convert_let_else_to_match.rs index 07e12f0320be..65c1c7cb70e7 100644 --- a/crates/ide-assists/src/handlers/convert_let_else_to_match.rs +++ b/crates/ide-assists/src/handlers/convert_let_else_to_match.rs @@ -229,6 +229,7 @@ fn remove_mut_and_collect_idents( | ast::Pat::LiteralPat(_) | ast::Pat::PathPat(_) | ast::Pat::WildcardPat(_) + | ast::Pat::NotNull(_) | ast::Pat::ConstBlockPat(_) => pat.clone(), // don't support macro pat yet ast::Pat::MacroPat(_) => return None, diff --git a/crates/ide-assists/src/utils.rs b/crates/ide-assists/src/utils.rs index 3ab4279b0add..33e0f476da5b 100644 --- a/crates/ide-assists/src/utils.rs +++ b/crates/ide-assists/src/utils.rs @@ -417,6 +417,7 @@ fn check_pat_variant_nested_or_literal_with_depth( | ast::Pat::PathPat(_) | ast::Pat::BoxPat(_) | ast::Pat::DerefPat(_) + | ast::Pat::NotNull(_) | ast::Pat::ConstBlockPat(_) => true, ast::Pat::IdentPat(ident_pat) => ident_pat.pat().is_some_and(|pat| { diff --git a/crates/intern/src/symbol/symbols.rs b/crates/intern/src/symbol/symbols.rs index ac6daaf00681..6ad8006d1844 100644 --- a/crates/intern/src/symbol/symbols.rs +++ b/crates/intern/src/symbol/symbols.rs @@ -475,6 +475,7 @@ define_symbols! { PartialOrd, CoercePointee, path, + pattern_type, Pending, phantom_data, pieces, diff --git a/crates/parser/src/grammar/patterns.rs b/crates/parser/src/grammar/patterns.rs index 5726f085a03e..29fa11720aca 100644 --- a/crates/parser/src/grammar/patterns.rs +++ b/crates/parser/src/grammar/patterns.rs @@ -12,6 +12,7 @@ pub(super) const PATTERN_FIRST: TokenSet = T![_], T![-], T![.], + T![!], ])); const PAT_TOP_FIRST: TokenSet = PATTERN_FIRST.union(TokenSet::new(&[T![|]])); @@ -256,6 +257,7 @@ fn atom_pat(p: &mut Parser<'_>, recovery_set: TokenSet) -> Option ref_pat(p), T!['('] => tuple_pat(p), T!['['] => slice_pat(p), + T![!] => not_null_pat(p), _ => { p.err_recover("expected pattern", recovery_set); @@ -435,6 +437,18 @@ fn ref_pat(p: &mut Parser<'_>) -> CompletedMarker { m.complete(p, REF_PAT) } +// test not_null_pat +// fn main() { +// let (!a | !&0) = (); +// } +fn not_null_pat(p: &mut Parser<'_>) -> CompletedMarker { + assert!(p.at(T![!])); + let m = p.start(); + p.bump(T![!]); + pattern_single(p); + m.complete(p, NOT_NULL) +} + // test tuple_pat // fn main() { // let (a, b, ..) = (); diff --git a/crates/parser/src/grammar/types.rs b/crates/parser/src/grammar/types.rs index 667bb68c649c..f92afde60de1 100644 --- a/crates/parser/src/grammar/types.rs +++ b/crates/parser/src/grammar/types.rs @@ -1,3 +1,5 @@ +use crate::grammar::entry::prefix::pat; + use super::*; pub(super) const TYPE_FIRST: TokenSet = paths::PATH_FIRST.union(TokenSet::new(&[ @@ -341,6 +343,10 @@ fn bare_dyn_trait_type(p: &mut Parser<'_>) { // type B = crate::foo!(); fn path_or_macro_type(p: &mut Parser<'_>, allow_bounds: bool) { assert!(paths::is_path_start(p)); + if p.at_contextual_kw(T![builtin]) && p.nth_at(1, T![#]) { + pattern_type(p); + return; + } let r = p.start(); let m = p.start(); @@ -411,3 +417,23 @@ pub(super) fn opt_type_bounds_as_dyn_trait_type( // Finally precede everything with DYN_TRAIT_TYPE m.precede(p).complete(p, DYN_TRAIT_TYPE) } + +// test pattern_type +// type T = builtin#pattern_type (u8 is 0..10); +fn pattern_type(p: &mut Parser<'_>) { + let m = p.start(); + p.bump_remap(T![builtin]); + p.bump(T![#]); + if p.eat_contextual_kw(T![pattern_type]) { + p.expect(T!['(']); + type_(p); + if !p.eat_contextual_kw(T![is]) { + p.error("expected `is`") + } + pat(p); + p.expect(T![')']); + m.complete(p, PATTERN_TYPE); + } else { + m.abandon(p); + } +} diff --git a/crates/parser/src/syntax_kind/generated.rs b/crates/parser/src/syntax_kind/generated.rs index b1867275cebf..dd675e083405 100644 --- a/crates/parser/src/syntax_kind/generated.rs +++ b/crates/parser/src/syntax_kind/generated.rs @@ -127,6 +127,7 @@ pub enum SyntaxKind { GLOBAL_ASM_KW, INLATEOUT_KW, INOUT_KW, + IS_KW, LABEL_KW, LATEOUT_KW, MACRO_RULES_KW, @@ -135,9 +136,11 @@ pub enum SyntaxKind { NOMEM_KW, NORETURN_KW, NOSTACK_KW, + NULL_KW, OFFSET_OF_KW, OPTIONS_KW, OUT_KW, + PATTERN_TYPE_KW, PRESERVES_FLAGS_KW, PURE_KW, RAW_KW, @@ -254,6 +257,7 @@ pub enum SyntaxKind { NAME, NAME_REF, NEVER_TYPE, + NOT_NULL, OFFSET_OF_EXPR, OR_PAT, PARAM, @@ -268,6 +272,7 @@ pub enum SyntaxKind { PATH_PAT, PATH_SEGMENT, PATH_TYPE, + PATTERN_TYPE, PREFIX_EXPR, PTR_TYPE, RANGE_EXPR, @@ -439,6 +444,7 @@ impl SyntaxKind { | NAME | NAME_REF | NEVER_TYPE + | NOT_NULL | OFFSET_OF_EXPR | OR_PAT | PARAM @@ -453,6 +459,7 @@ impl SyntaxKind { | PATH_PAT | PATH_SEGMENT | PATH_TYPE + | PATTERN_TYPE | PREFIX_EXPR | PTR_TYPE | RANGE_EXPR @@ -636,6 +643,7 @@ impl SyntaxKind { GLOBAL_ASM_KW => "global_asm", INLATEOUT_KW => "inlateout", INOUT_KW => "inout", + IS_KW => "is", LABEL_KW => "label", LATEOUT_KW => "lateout", MACRO_RULES_KW => "macro_rules", @@ -644,9 +652,11 @@ impl SyntaxKind { NOMEM_KW => "nomem", NORETURN_KW => "noreturn", NOSTACK_KW => "nostack", + NULL_KW => "null", OFFSET_OF_KW => "offset_of", OPTIONS_KW => "options", OUT_KW => "out", + PATTERN_TYPE_KW => "pattern_type", PRESERVES_FLAGS_KW => "preserves_flags", PURE_KW => "pure", RAW_KW => "raw", @@ -742,6 +752,7 @@ impl SyntaxKind { GLOBAL_ASM_KW => true, INLATEOUT_KW => true, INOUT_KW => true, + IS_KW => true, LABEL_KW => true, LATEOUT_KW => true, MACRO_RULES_KW => true, @@ -750,9 +761,11 @@ impl SyntaxKind { NOMEM_KW => true, NORETURN_KW => true, NOSTACK_KW => true, + NULL_KW => true, OFFSET_OF_KW => true, OPTIONS_KW => true, OUT_KW => true, + PATTERN_TYPE_KW => true, PRESERVES_FLAGS_KW => true, PURE_KW => true, RAW_KW => true, @@ -836,6 +849,7 @@ impl SyntaxKind { GLOBAL_ASM_KW => true, INLATEOUT_KW => true, INOUT_KW => true, + IS_KW => true, LABEL_KW => true, LATEOUT_KW => true, MACRO_RULES_KW => true, @@ -844,9 +858,11 @@ impl SyntaxKind { NOMEM_KW => true, NORETURN_KW => true, NOSTACK_KW => true, + NULL_KW => true, OFFSET_OF_KW => true, OPTIONS_KW => true, OUT_KW => true, + PATTERN_TYPE_KW => true, PRESERVES_FLAGS_KW => true, PURE_KW => true, RAW_KW => true, @@ -993,6 +1009,7 @@ impl SyntaxKind { "global_asm" => GLOBAL_ASM_KW, "inlateout" => INLATEOUT_KW, "inout" => INOUT_KW, + "is" => IS_KW, "label" => LABEL_KW, "lateout" => LATEOUT_KW, "macro_rules" => MACRO_RULES_KW, @@ -1001,9 +1018,11 @@ impl SyntaxKind { "nomem" => NOMEM_KW, "noreturn" => NORETURN_KW, "nostack" => NOSTACK_KW, + "null" => NULL_KW, "offset_of" => OFFSET_OF_KW, "options" => OPTIONS_KW, "out" => OUT_KW, + "pattern_type" => PATTERN_TYPE_KW, "preserves_flags" => PRESERVES_FLAGS_KW, "pure" => PURE_KW, "raw" => RAW_KW, @@ -1168,6 +1187,7 @@ macro_rules ! T_ { [global_asm] => { $ crate :: SyntaxKind :: GLOBAL_ASM_KW }; [inlateout] => { $ crate :: SyntaxKind :: INLATEOUT_KW }; [inout] => { $ crate :: SyntaxKind :: INOUT_KW }; + [is] => { $ crate :: SyntaxKind :: IS_KW }; [label] => { $ crate :: SyntaxKind :: LABEL_KW }; [lateout] => { $ crate :: SyntaxKind :: LATEOUT_KW }; [macro_rules] => { $ crate :: SyntaxKind :: MACRO_RULES_KW }; @@ -1176,9 +1196,11 @@ macro_rules ! T_ { [nomem] => { $ crate :: SyntaxKind :: NOMEM_KW }; [noreturn] => { $ crate :: SyntaxKind :: NORETURN_KW }; [nostack] => { $ crate :: SyntaxKind :: NOSTACK_KW }; + [null] => { $ crate :: SyntaxKind :: NULL_KW }; [offset_of] => { $ crate :: SyntaxKind :: OFFSET_OF_KW }; [options] => { $ crate :: SyntaxKind :: OPTIONS_KW }; [out] => { $ crate :: SyntaxKind :: OUT_KW }; + [pattern_type] => { $ crate :: SyntaxKind :: PATTERN_TYPE_KW }; [preserves_flags] => { $ crate :: SyntaxKind :: PRESERVES_FLAGS_KW }; [pure] => { $ crate :: SyntaxKind :: PURE_KW }; [raw] => { $ crate :: SyntaxKind :: RAW_KW }; diff --git a/crates/parser/test_data/generated/runner.rs b/crates/parser/test_data/generated/runner.rs index 7aaf270a77bf..ccf8b89be74a 100644 --- a/crates/parser/test_data/generated/runner.rs +++ b/crates/parser/test_data/generated/runner.rs @@ -474,6 +474,8 @@ mod ok { run_and_expect_no_errors("test_data/parser/inline/ok/nocontentexpr_after_item.rs"); } #[test] + fn not_null_pat() { run_and_expect_no_errors("test_data/parser/inline/ok/not_null_pat.rs"); } + #[test] fn offset_of_parens() { run_and_expect_no_errors("test_data/parser/inline/ok/offset_of_parens.rs"); } @@ -506,6 +508,8 @@ mod ok { run_and_expect_no_errors("test_data/parser/inline/ok/path_type_with_bounds.rs"); } #[test] + fn pattern_type() { run_and_expect_no_errors("test_data/parser/inline/ok/pattern_type.rs"); } + #[test] fn placeholder_pat() { run_and_expect_no_errors("test_data/parser/inline/ok/placeholder_pat.rs"); } diff --git a/crates/parser/test_data/parser/err/0032_match_arms_inner_attrs.rast b/crates/parser/test_data/parser/err/0032_match_arms_inner_attrs.rast index 2334b730e4cc..234070bcb135 100644 --- a/crates/parser/test_data/parser/err/0032_match_arms_inner_attrs.rast +++ b/crates/parser/test_data/parser/err/0032_match_arms_inner_attrs.rast @@ -37,27 +37,26 @@ SOURCE_FILE MATCH_ARM ATTR POUND "#" - ERROR + NOT_NULL BANG "!" - ARRAY_EXPR - L_BRACK "[" - CALL_EXPR - PATH_EXPR + SLICE_PAT + L_BRACK "[" + TUPLE_STRUCT_PAT PATH PATH_SEGMENT NAME_REF IDENT "doc" - ARG_LIST L_PAREN "(" - LITERAL - STRING "\"Not allowed here\"" + LITERAL_PAT + LITERAL + STRING "\"Not allowed here\"" R_PAREN ")" - R_BRACK "]" - WHITESPACE "\n " - MATCH_ARM - WILDCARD_PAT + R_BRACK "]" + WHITESPACE "\n " + UNDERSCORE_EXPR UNDERSCORE "_" - WHITESPACE " " + WHITESPACE " " + MATCH_ARM FAT_ARROW "=>" WHITESPACE " " TUPLE_EXPR @@ -103,22 +102,21 @@ SOURCE_FILE MATCH_ARM ATTR POUND "#" - ERROR + NOT_NULL BANG "!" - ARRAY_EXPR - L_BRACK "[" - CALL_EXPR - PATH_EXPR + SLICE_PAT + L_BRACK "[" + TUPLE_STRUCT_PAT PATH PATH_SEGMENT NAME_REF IDENT "doc" - ARG_LIST L_PAREN "(" - LITERAL - STRING "\"Nor here\"" + LITERAL_PAT + LITERAL + STRING "\"Nor here\"" R_PAREN ")" - R_BRACK "]" + R_BRACK "]" WHITESPACE "\n " R_CURLY "}" WHITESPACE "\n\n " @@ -146,27 +144,26 @@ SOURCE_FILE WHITESPACE "\n " ATTR POUND "#" - ERROR + NOT_NULL BANG "!" - ARRAY_EXPR - L_BRACK "[" - CALL_EXPR - PATH_EXPR + SLICE_PAT + L_BRACK "[" + TUPLE_STRUCT_PAT PATH PATH_SEGMENT NAME_REF IDENT "doc" - ARG_LIST L_PAREN "(" - LITERAL - STRING "\"Nor here\"" + LITERAL_PAT + LITERAL + STRING "\"Nor here\"" R_PAREN ")" - R_BRACK "]" - WHITESPACE "\n " - MATCH_ARM - WILDCARD_PAT + R_BRACK "]" + WHITESPACE "\n " + UNDERSCORE_EXPR UNDERSCORE "_" - WHITESPACE " " + WHITESPACE " " + MATCH_ARM FAT_ARROW "=>" WHITESPACE " " TUPLE_EXPR @@ -190,13 +187,13 @@ SOURCE_FILE R_CURLY "}" WHITESPACE "\n" error 52: expected L_BRACK -error 52: expected pattern -error 53: expected FAT_ARROW -error 78: expected `,` +error 78: expected FAT_ARROW +error 88: expected `,` +error 89: expected pattern error 161: expected L_BRACK -error 161: expected pattern -error 162: expected FAT_ARROW +error 179: expected FAT_ARROW +error 179: expected expression error 232: expected L_BRACK -error 232: expected pattern -error 233: expected FAT_ARROW -error 250: expected `,` +error 250: expected FAT_ARROW +error 260: expected `,` +error 261: expected pattern diff --git a/crates/parser/test_data/parser/inline/ok/not_null_pat.rast b/crates/parser/test_data/parser/inline/ok/not_null_pat.rast new file mode 100644 index 000000000000..7a2e655201b6 --- /dev/null +++ b/crates/parser/test_data/parser/inline/ok/not_null_pat.rast @@ -0,0 +1,46 @@ +SOURCE_FILE + FN + FN_KW "fn" + WHITESPACE " " + NAME + IDENT "main" + PARAM_LIST + L_PAREN "(" + R_PAREN ")" + WHITESPACE " " + BLOCK_EXPR + STMT_LIST + L_CURLY "{" + WHITESPACE "\n " + LET_STMT + LET_KW "let" + WHITESPACE " " + PAREN_PAT + L_PAREN "(" + OR_PAT + NOT_NULL + BANG "!" + IDENT_PAT + NAME + IDENT "a" + WHITESPACE " " + PIPE "|" + WHITESPACE " " + NOT_NULL + BANG "!" + REF_PAT + AMP "&" + LITERAL_PAT + LITERAL + INT_NUMBER "0" + R_PAREN ")" + WHITESPACE " " + EQ "=" + WHITESPACE " " + TUPLE_EXPR + L_PAREN "(" + R_PAREN ")" + SEMICOLON ";" + WHITESPACE "\n" + R_CURLY "}" + WHITESPACE "\n" diff --git a/crates/parser/test_data/parser/inline/ok/not_null_pat.rs b/crates/parser/test_data/parser/inline/ok/not_null_pat.rs new file mode 100644 index 000000000000..f44fae5a7734 --- /dev/null +++ b/crates/parser/test_data/parser/inline/ok/not_null_pat.rs @@ -0,0 +1,3 @@ +fn main() { + let (!a | !&0) = (); +} diff --git a/crates/parser/test_data/parser/inline/ok/pattern_type.rast b/crates/parser/test_data/parser/inline/ok/pattern_type.rast new file mode 100644 index 000000000000..c9caeb1f9b21 --- /dev/null +++ b/crates/parser/test_data/parser/inline/ok/pattern_type.rast @@ -0,0 +1,34 @@ +SOURCE_FILE + TYPE_ALIAS + TYPE_KW "type" + WHITESPACE " " + NAME + IDENT "T" + WHITESPACE " " + EQ "=" + WHITESPACE " " + PATTERN_TYPE + BUILTIN_KW "builtin" + POUND "#" + PATTERN_TYPE_KW "pattern_type" + WHITESPACE " " + L_PAREN "(" + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "u8" + WHITESPACE " " + IS_KW "is" + WHITESPACE " " + RANGE_PAT + LITERAL_PAT + LITERAL + INT_NUMBER "0" + DOT2 ".." + LITERAL_PAT + LITERAL + INT_NUMBER "10" + R_PAREN ")" + SEMICOLON ";" + WHITESPACE "\n" diff --git a/crates/parser/test_data/parser/inline/ok/pattern_type.rs b/crates/parser/test_data/parser/inline/ok/pattern_type.rs new file mode 100644 index 000000000000..c909c7b70805 --- /dev/null +++ b/crates/parser/test_data/parser/inline/ok/pattern_type.rs @@ -0,0 +1 @@ +type T = builtin#pattern_type (u8 is 0..10); diff --git a/crates/syntax/rust.ungram b/crates/syntax/rust.ungram index 6bcf8ba743bc..408f2f4b32c7 100644 --- a/crates/syntax/rust.ungram +++ b/crates/syntax/rust.ungram @@ -665,6 +665,7 @@ Type = | NeverType | ParenType | PathType +| PatternType | PtrType | RefType | SliceType @@ -706,6 +707,9 @@ FnPtrType = ForType = ForBinder Type +PatternType = + 'builtin' '#' 'pattern_type' '(' Type 'is' Pat ')' + ImplTraitType = 'impl' TypeBoundList @@ -749,6 +753,10 @@ Pat = | TupleStructPat | ConstBlockPat | DerefPat +| NotNull + +NotNull = + '!' 'null' DerefPat = 'builtin' '#' 'deref' '(' Pat ')' diff --git a/crates/syntax/src/ast/generated/nodes.rs b/crates/syntax/src/ast/generated/nodes.rs index e3e5c499d4ea..c18311bfa3ad 100644 --- a/crates/syntax/src/ast/generated/nodes.rs +++ b/crates/syntax/src/ast/generated/nodes.rs @@ -1186,6 +1186,15 @@ impl NeverType { #[inline] pub fn excl_token(&self) -> Option { support::token(&self.syntax, T![!]) } } +pub struct NotNull { + pub(crate) syntax: SyntaxNode, +} +impl NotNull { + #[inline] + pub fn excl_token(&self) -> Option { support::token(&self.syntax, T![!]) } + #[inline] + pub fn null_token(&self) -> Option { support::token(&self.syntax, T![null]) } +} pub struct OffsetOfExpr { pub(crate) syntax: SyntaxNode, } @@ -1357,6 +1366,29 @@ impl PathType { #[inline] pub fn path(&self) -> Option { support::child(&self.syntax) } } +pub struct PatternType { + pub(crate) syntax: SyntaxNode, +} +impl PatternType { + #[inline] + pub fn pat(&self) -> Option { support::child(&self.syntax) } + #[inline] + pub fn ty(&self) -> Option { support::child(&self.syntax) } + #[inline] + pub fn pound_token(&self) -> Option { support::token(&self.syntax, T![#]) } + #[inline] + pub fn l_paren_token(&self) -> Option { support::token(&self.syntax, T!['(']) } + #[inline] + pub fn r_paren_token(&self) -> Option { support::token(&self.syntax, T![')']) } + #[inline] + pub fn builtin_token(&self) -> Option { support::token(&self.syntax, T![builtin]) } + #[inline] + pub fn is_token(&self) -> Option { support::token(&self.syntax, T![is]) } + #[inline] + pub fn pattern_type_token(&self) -> Option { + support::token(&self.syntax, T![pattern_type]) + } +} pub struct PrefixExpr { pub(crate) syntax: SyntaxNode, } @@ -2275,6 +2307,7 @@ pub enum Pat { IdentPat(IdentPat), LiteralPat(LiteralPat), MacroPat(MacroPat), + NotNull(NotNull), OrPat(OrPat), ParenPat(ParenPat), PathPat(PathPat), @@ -2307,6 +2340,7 @@ pub enum Type { NeverType(NeverType), ParenType(ParenType), PathType(PathType), + PatternType(PatternType), PtrType(PtrType), RefType(RefType), SliceType(SliceType), @@ -5363,6 +5397,38 @@ impl fmt::Debug for NeverType { f.debug_struct("NeverType").field("syntax", &self.syntax).finish() } } +impl AstNode for NotNull { + #[inline] + fn kind() -> SyntaxKind + where + Self: Sized, + { + NOT_NULL + } + #[inline] + fn can_cast(kind: SyntaxKind) -> bool { kind == NOT_NULL } + #[inline] + fn cast(syntax: SyntaxNode) -> Option { + if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None } + } + #[inline] + fn syntax(&self) -> &SyntaxNode { &self.syntax } +} +impl hash::Hash for NotNull { + fn hash(&self, state: &mut H) { self.syntax.hash(state); } +} +impl Eq for NotNull {} +impl PartialEq for NotNull { + fn eq(&self, other: &Self) -> bool { self.syntax == other.syntax } +} +impl Clone for NotNull { + fn clone(&self) -> Self { Self { syntax: self.syntax.clone() } } +} +impl fmt::Debug for NotNull { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("NotNull").field("syntax", &self.syntax).finish() + } +} impl AstNode for OffsetOfExpr { #[inline] fn kind() -> SyntaxKind @@ -5811,6 +5877,38 @@ impl fmt::Debug for PathType { f.debug_struct("PathType").field("syntax", &self.syntax).finish() } } +impl AstNode for PatternType { + #[inline] + fn kind() -> SyntaxKind + where + Self: Sized, + { + PATTERN_TYPE + } + #[inline] + fn can_cast(kind: SyntaxKind) -> bool { kind == PATTERN_TYPE } + #[inline] + fn cast(syntax: SyntaxNode) -> Option { + if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None } + } + #[inline] + fn syntax(&self) -> &SyntaxNode { &self.syntax } +} +impl hash::Hash for PatternType { + fn hash(&self, state: &mut H) { self.syntax.hash(state); } +} +impl Eq for PatternType {} +impl PartialEq for PatternType { + fn eq(&self, other: &Self) -> bool { self.syntax == other.syntax } +} +impl Clone for PatternType { + fn clone(&self) -> Self { Self { syntax: self.syntax.clone() } } +} +impl fmt::Debug for PatternType { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("PatternType").field("syntax", &self.syntax).finish() + } +} impl AstNode for PrefixExpr { #[inline] fn kind() -> SyntaxKind @@ -8581,6 +8679,10 @@ impl From for Pat { #[inline] fn from(node: MacroPat) -> Pat { Pat::MacroPat(node) } } +impl From for Pat { + #[inline] + fn from(node: NotNull) -> Pat { Pat::NotNull(node) } +} impl From for Pat { #[inline] fn from(node: OrPat) -> Pat { Pat::OrPat(node) } @@ -8636,6 +8738,7 @@ impl AstNode for Pat { | IDENT_PAT | LITERAL_PAT | MACRO_PAT + | NOT_NULL | OR_PAT | PAREN_PAT | PATH_PAT @@ -8658,6 +8761,7 @@ impl AstNode for Pat { IDENT_PAT => Pat::IdentPat(IdentPat { syntax }), LITERAL_PAT => Pat::LiteralPat(LiteralPat { syntax }), MACRO_PAT => Pat::MacroPat(MacroPat { syntax }), + NOT_NULL => Pat::NotNull(NotNull { syntax }), OR_PAT => Pat::OrPat(OrPat { syntax }), PAREN_PAT => Pat::ParenPat(ParenPat { syntax }), PATH_PAT => Pat::PathPat(PathPat { syntax }), @@ -8682,6 +8786,7 @@ impl AstNode for Pat { Pat::IdentPat(it) => &it.syntax, Pat::LiteralPat(it) => &it.syntax, Pat::MacroPat(it) => &it.syntax, + Pat::NotNull(it) => &it.syntax, Pat::OrPat(it) => &it.syntax, Pat::ParenPat(it) => &it.syntax, Pat::PathPat(it) => &it.syntax, @@ -8748,6 +8853,10 @@ impl From for Type { #[inline] fn from(node: PathType) -> Type { Type::PathType(node) } } +impl From for Type { + #[inline] + fn from(node: PatternType) -> Type { Type::PatternType(node) } +} impl From for Type { #[inline] fn from(node: PtrType) -> Type { Type::PtrType(node) } @@ -8779,6 +8888,7 @@ impl AstNode for Type { | NEVER_TYPE | PAREN_TYPE | PATH_TYPE + | PATTERN_TYPE | PTR_TYPE | REF_TYPE | SLICE_TYPE @@ -8798,6 +8908,7 @@ impl AstNode for Type { NEVER_TYPE => Type::NeverType(NeverType { syntax }), PAREN_TYPE => Type::ParenType(ParenType { syntax }), PATH_TYPE => Type::PathType(PathType { syntax }), + PATTERN_TYPE => Type::PatternType(PatternType { syntax }), PTR_TYPE => Type::PtrType(PtrType { syntax }), REF_TYPE => Type::RefType(RefType { syntax }), SLICE_TYPE => Type::SliceType(SliceType { syntax }), @@ -8819,6 +8930,7 @@ impl AstNode for Type { Type::NeverType(it) => &it.syntax, Type::ParenType(it) => &it.syntax, Type::PathType(it) => &it.syntax, + Type::PatternType(it) => &it.syntax, Type::PtrType(it) => &it.syntax, Type::RefType(it) => &it.syntax, Type::SliceType(it) => &it.syntax, @@ -10453,6 +10565,11 @@ impl std::fmt::Display for NeverType { std::fmt::Display::fmt(self.syntax(), f) } } +impl std::fmt::Display for NotNull { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} impl std::fmt::Display for OffsetOfExpr { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) @@ -10523,6 +10640,11 @@ impl std::fmt::Display for PathType { std::fmt::Display::fmt(self.syntax(), f) } } +impl std::fmt::Display for PatternType { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} impl std::fmt::Display for PrefixExpr { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) diff --git a/crates/test-utils/src/minicore.rs b/crates/test-utils/src/minicore.rs index 8975fa56d727..ff531af638a9 100644 --- a/crates/test-utils/src/minicore.rs +++ b/crates/test-utils/src/minicore.rs @@ -55,10 +55,11 @@ //! manually_drop: drop //! matches: //! non_null: -//! non_zero: +//! non_zero: transmute, option //! option: panic //! ord: eq, option //! panic: fmt +//! pat: //! phantom_data: //! pin: //! pointee: copy, send, sync, ord, hash, unpin, phantom_data @@ -2278,6 +2279,33 @@ mod macros { // endregion:deref_pat } +// region:pat +pub mod pat { + #[macro_export] + #[rustc_builtin_macro(pattern_type)] + macro_rules! pattern_type { + ($($arg:tt)*) => { + /* compiler built-in */ + }; + } + + pub const trait RangePattern { + /// Trait version of the inherent `MIN` assoc const. + #[lang = "RangeMin"] + const MIN: Self; + + /// Trait version of the inherent `MIN` assoc const. + #[lang = "RangeMax"] + const MAX: Self; + + /// A compile-time helper to subtract 1 for exclusive ranges. + #[lang = "RangeSub"] + #[track_caller] + fn sub_one(self) -> Self; + } +} +// endregion:pat + // region:non_zero pub mod num { #[repr(transparent)] diff --git a/xtask/src/codegen/grammar/ast_src.rs b/xtask/src/codegen/grammar/ast_src.rs index 43462d1c6e04..49a625bdbd40 100644 --- a/xtask/src/codegen/grammar/ast_src.rs +++ b/xtask/src/codegen/grammar/ast_src.rs @@ -123,6 +123,7 @@ const CONTEXTUAL_KEYWORDS: &[&str] = &[ "bikeshed", "cfg_attr", "cfg", + "null", ]; // keywords we use for special macro expansions const CONTEXTUAL_BUILTIN_KEYWORDS: &[&str] = &[ @@ -151,6 +152,8 @@ const CONTEXTUAL_BUILTIN_KEYWORDS: &[&str] = &[ "readonly", "sym", "deref", + "pattern_type", + "is", ]; // keywords that are keywords depending on the edition