Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--crates/hir-def/src/expr_store.rs6
-rw-r--r--crates/hir-def/src/expr_store/body.rs6
-rw-r--r--crates/hir-def/src/expr_store/lower.rs5
-rw-r--r--crates/hir-def/src/expr_store/pretty.rs6
-rw-r--r--crates/hir-def/src/hir.rs4
-rw-r--r--crates/hir-def/src/hir/type_ref.rs3
-rw-r--r--crates/hir-def/src/lib.rs6
-rw-r--r--crates/hir-expand/src/builtin/derive_macro.rs3
-rw-r--r--crates/hir-expand/src/builtin/fn_macro.rs13
-rw-r--r--crates/hir-ty/src/diagnostics/unsafe_check.rs5
-rw-r--r--crates/hir-ty/src/display.rs164
-rw-r--r--crates/hir-ty/src/infer/closure/analysis/expr_use_visitor.rs2
-rw-r--r--crates/hir-ty/src/infer/expr.rs1
-rw-r--r--crates/hir-ty/src/infer/pat.rs4
-rw-r--r--crates/hir-ty/src/layout.rs12
-rw-r--r--crates/hir-ty/src/lower.rs45
-rw-r--r--crates/hir-ty/src/mir/lower.rs15
-rw-r--r--crates/hir-ty/src/mir/lower/pattern_matching.rs5
-rw-r--r--crates/hir/src/display.rs89
-rw-r--r--crates/hir/src/symbols.rs2
-rw-r--r--crates/ide-assists/src/handlers/convert_let_else_to_match.rs1
-rw-r--r--crates/ide-assists/src/utils.rs1
-rw-r--r--crates/intern/src/symbol/symbols.rs1
-rw-r--r--crates/parser/src/grammar/patterns.rs14
-rw-r--r--crates/parser/src/grammar/types.rs26
-rw-r--r--crates/parser/src/syntax_kind/generated.rs22
-rw-r--r--crates/parser/test_data/generated/runner.rs4
-rw-r--r--crates/parser/test_data/parser/err/0032_match_arms_inner_attrs.rast83
-rw-r--r--crates/parser/test_data/parser/inline/ok/not_null_pat.rast46
-rw-r--r--crates/parser/test_data/parser/inline/ok/not_null_pat.rs3
-rw-r--r--crates/parser/test_data/parser/inline/ok/pattern_type.rast34
-rw-r--r--crates/parser/test_data/parser/inline/ok/pattern_type.rs1
-rw-r--r--crates/syntax/rust.ungram8
-rw-r--r--crates/syntax/src/ast/generated/nodes.rs122
-rw-r--r--crates/test-utils/src/minicore.rs30
-rw-r--r--xtask/src/codegen/grammar/ast_src.rs3
36 files changed, 649 insertions, 146 deletions
diff --git a/crates/hir-def/src/expr_store.rs b/crates/hir-def/src/expr_store.rs
index 4dc7267231..6d6e369cd6 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 2fb47e59c5..01423d5109 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 8818096500..76503ac97c 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 34cedbd728..4dc7ebebbb 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 6eba859264..4c8d835ad7 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 43e29c1f5f..6cd8377b5f 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<TypeBound>),
DynTrait(ThinVec<TypeBound>),
TypeParam(TypeParamId),
+ PatternType(TypeRefId, PatId),
Error,
}
diff --git a/crates/hir-def/src/lib.rs b/crates/hir-def/src/lib.rs
index 7b7d046581..73cdc4a9d0 100644
--- a/crates/hir-def/src/lib.rs
+++ b/crates/hir-def/src/lib.rs
@@ -852,6 +852,12 @@ impl From<VariantId> for ExpressionStoreOwnerId {
}
}
+impl From<ImplId> 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 8b031e3647..e8321cd8da 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 eb7175c686..9181ad88b6 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<tt::TopSubtree> {
+ 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 c37a194d47..3c69c6a44b 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 03d0e15fec..0acf6e63d7 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,
@@ -2350,39 +2350,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"),
@@ -2401,7 +2420,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) => {
@@ -2426,7 +2450,7 @@ impl<'db> HirDisplayWithExpressionStore<'db> for TypeRefId {
}
_ => None,
})
- .map(ExpressionStoreAdapter::wrap(store)),
+ .map(ExpressionStoreAdapter::wrap(owner, store)),
" + ",
)?;
}
@@ -2435,20 +2459,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 {
@@ -2457,22 +2481,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_) => {
@@ -2492,7 +2516,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, ", ")?;
@@ -2506,18 +2530,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}}")?,
}
@@ -2526,7 +2561,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}}")?;
@@ -2534,17 +2574,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!(
@@ -2552,7 +2620,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<")?;
@@ -2560,7 +2628,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 {
@@ -2575,11 +2643,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) => {}
@@ -2622,7 +2695,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...
}
@@ -2652,17 +2725,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 => {
@@ -2675,7 +2748,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 {
@@ -2688,7 +2761,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, ": ")?;
@@ -2696,7 +2769,7 @@ impl<'db> HirDisplayWithExpressionStore<'db> for Path {
binding
.bounds
.iter()
- .map(ExpressionStoreAdapter::wrap(store)),
+ .map(ExpressionStoreAdapter::wrap(owner, store)),
" + ",
)?;
}
@@ -2723,14 +2796,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, "<expr>")
}
- 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 e7e97df48e..2642844e38 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 0675b5e857..90ecfbd7e9 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 a42d00786e..300c0cf214 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 3e569076ad..78df93311e 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 0cb1a2db26..ec42b8a349 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 27efc5cfd5..025aff9307 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 c924c5bdf0..2cb2143229 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 a71851ea8c..c3af5fa7ce 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 e9cfb63a12..a00c3219b2 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 07e12f0320..65c1c7cb70 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 3ab4279b0a..33e0f476da 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 ac6daaf006..6ad8006d18 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 5726f085a0..29fa11720a 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<CompletedMarke
T![&] => 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 667bb68c64..f92afde60d 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 b1867275ce..dd675e0834 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 7aaf270a77..ccf8b89be7 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 2334b730e4..234070bcb1 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 0000000000..7a2e655201
--- /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 0000000000..f44fae5a77
--- /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 0000000000..c9caeb1f9b
--- /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 0000000000..c909c7b708
--- /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 6bcf8ba743..408f2f4b32 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 e3e5c499d4..c18311bfa3 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<SyntaxToken> { support::token(&self.syntax, T![!]) }
}
+pub struct NotNull {
+ pub(crate) syntax: SyntaxNode,
+}
+impl NotNull {
+ #[inline]
+ pub fn excl_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![!]) }
+ #[inline]
+ pub fn null_token(&self) -> Option<SyntaxToken> { 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<Path> { support::child(&self.syntax) }
}
+pub struct PatternType {
+ pub(crate) syntax: SyntaxNode,
+}
+impl PatternType {
+ #[inline]
+ pub fn pat(&self) -> Option<Pat> { support::child(&self.syntax) }
+ #[inline]
+ pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
+ #[inline]
+ pub fn pound_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![#]) }
+ #[inline]
+ pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) }
+ #[inline]
+ pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
+ #[inline]
+ pub fn builtin_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![builtin]) }
+ #[inline]
+ pub fn is_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![is]) }
+ #[inline]
+ pub fn pattern_type_token(&self) -> Option<SyntaxToken> {
+ 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<Self> {
+ 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<H: hash::Hasher>(&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<Self> {
+ 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<H: hash::Hasher>(&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<MacroPat> for Pat {
#[inline]
fn from(node: MacroPat) -> Pat { Pat::MacroPat(node) }
}
+impl From<NotNull> for Pat {
+ #[inline]
+ fn from(node: NotNull) -> Pat { Pat::NotNull(node) }
+}
impl From<OrPat> 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<PathType> for Type {
#[inline]
fn from(node: PathType) -> Type { Type::PathType(node) }
}
+impl From<PatternType> for Type {
+ #[inline]
+ fn from(node: PatternType) -> Type { Type::PatternType(node) }
+}
impl From<PtrType> 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 8439573980..190c59170f 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
@@ -2315,6 +2316,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 43462d1c6e..49a625bdbd 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