Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-def/src/expr_store.rs')
-rw-r--r--crates/hir-def/src/expr_store.rs291
1 files changed, 210 insertions, 81 deletions
diff --git a/crates/hir-def/src/expr_store.rs b/crates/hir-def/src/expr_store.rs
index c195106498..4dc7267231 100644
--- a/crates/hir-def/src/expr_store.rs
+++ b/crates/hir-def/src/expr_store.rs
@@ -28,14 +28,18 @@ use tt::TextRange;
use crate::{
AdtId, BlockId, ExpressionStoreOwnerId, GenericDefId, SyntheticSyntax,
db::DefDatabase,
- expr_store::path::Path,
+ expr_store::path::{AssociatedTypeBinding, GenericArg, GenericArgs, NormalPath, Path},
hir::{
Array, AsmOperand, Binding, BindingId, Expr, ExprId, ExprOrPatId, InlineAsm, Label,
- LabelId, MatchArm, Pat, PatId, RecordFieldPat, RecordLitField, RecordSpread, Statement,
+ LabelId, MatchArm, OffsetOf, Pat, PatId, RecordFieldPat, RecordLitField, RecordSpread,
+ Statement,
},
nameres::{DefMap, block_def_map},
signatures::VariantFields,
- type_ref::{LifetimeRef, LifetimeRefId, PathId, TypeRef, TypeRefId},
+ type_ref::{
+ ArrayType, ConstRef, FnType, LifetimeRef, LifetimeRefId, PathId, RefType, TypeBound,
+ TypeRef, TypeRefId, UseArgRef,
+ },
};
pub use self::body::{Body, BodySourceMap};
@@ -602,38 +606,46 @@ impl ExpressionStore {
});
}
- pub fn walk_pats_shallow(&self, pat_id: PatId, mut f: impl FnMut(PatId)) {
+ pub fn visit_pat_children(&self, pat_id: PatId, mut visitor: impl StoreVisitor) {
// Do not use `..` patterns or field accesses here, only destructuring, to ensure we cover all cases
// (we've had multiple bugs with this in the past).
let pat = &self[pat_id];
match pat {
- Pat::Range { start: _, end: _, range_type: _ }
- | Pat::Lit(_)
- | Pat::Path(_)
- | Pat::ConstBlock(_)
- | Pat::Wild
- | Pat::Missing
- | Pat::Rest
- | Pat::Expr(_) => {}
- &Pat::Bind { subpat, id: _ } => {
- if let Some(subpat) = subpat {
- f(subpat);
- }
+ Pat::Range { start, end, range_type: _ } => {
+ visitor.on_expr_opt(*start);
+ visitor.on_expr_opt(*end);
}
- Pat::Or(args)
- | Pat::Tuple { args, ellipsis: _ }
- | Pat::TupleStruct { args, ellipsis: _, path: _ } => {
- args.iter().copied().for_each(f);
+ Pat::Lit(expr) | Pat::ConstBlock(expr) | Pat::Expr(expr) => visitor.on_expr(*expr),
+ Pat::Path(_) | Pat::Wild | Pat::Missing | Pat::Rest => {}
+ &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 } => {
+ visitor.on_pats(args);
+ visitor.on_path(path);
}
- Pat::Ref { pat, mutability: _ } => f(*pat),
+ Pat::Ref { pat, mutability: _ } => visitor.on_pat(*pat),
Pat::Slice { prefix, slice, suffix } => {
- let total_iter = prefix.iter().chain(slice.iter()).chain(suffix.iter());
- total_iter.copied().for_each(f);
+ visitor.on_pats(prefix);
+ visitor.on_pat_opt(*slice);
+ visitor.on_pats(suffix);
}
- Pat::Record { args, ellipsis: _, path: _ } => {
- args.iter().for_each(|RecordFieldPat { pat, name: _ }| f(*pat));
+ Pat::Record { args, ellipsis: _, path } => {
+ args.iter().for_each(|RecordFieldPat { pat, name: _ }| visitor.on_pat(*pat));
+ visitor.on_path(path);
+ }
+ Pat::Box { inner } | Pat::Deref { inner } => visitor.on_pat(*inner),
+ }
+ }
+
+ pub fn walk_pats_shallow(&self, pat_id: PatId, f: impl FnMut(PatId)) {
+ return self.visit_pat_children(pat_id, Visitor(f));
+
+ struct Visitor<F>(F);
+
+ impl<F: FnMut(PatId)> StoreVisitor for Visitor<F> {
+ fn on_pat(&mut self, pat: PatId) {
+ (self.0)(pat);
}
- Pat::Box { inner } | Pat::Deref { inner } => f(*inner),
}
}
@@ -659,16 +671,13 @@ impl ExpressionStore {
self.expr_only.as_ref()?.binding_owners.get(&id).copied()
}
- fn walk_child_exprs_impl(&self, expr_id: ExprId, mut visitor: impl ExprVisitor) {
+ pub fn visit_expr_children(&self, expr_id: ExprId, mut visitor: impl StoreVisitor) {
// Do not use `..` patterns or field accesses here, only destructuring, to ensure we cover all cases
// (we've had multiple bugs with this in the past).
match &self[expr_id] {
- Expr::Continue { label: _ }
- | Expr::Missing
- | Expr::Path(_)
- | Expr::OffsetOf(_)
- | Expr::Literal(_)
- | Expr::Underscore => {}
+ Expr::OffsetOf(OffsetOf { container, fields: _ }) => visitor.on_type(*container),
+ Expr::Path(path) => visitor.on_path(path),
+ Expr::Continue { label: _ } | Expr::Missing | Expr::Literal(_) | Expr::Underscore => {}
Expr::InlineAsm(InlineAsm { operands, options: _, kind: _ }) => {
operands.iter().for_each(|(_, op)| match op {
AsmOperand::In { expr, reg: _ }
@@ -696,10 +705,11 @@ impl ExpressionStore {
| Expr::Unsafe { statements, tail, id: _ } => {
for stmt in statements {
match stmt {
- Statement::Let { initializer, else_branch, pat, type_ref: _ } => {
+ Statement::Let { initializer, else_branch, pat, type_ref } => {
visitor.on_expr_opt(*initializer);
visitor.on_expr_opt(*else_branch);
visitor.on_pat(*pat);
+ visitor.on_type_opt(*type_ref);
}
Statement::Expr { expr: expression, has_semi: _ } => {
visitor.on_expr(*expression)
@@ -714,9 +724,10 @@ impl ExpressionStore {
visitor.on_expr(*callee);
visitor.on_exprs(args);
}
- Expr::MethodCall { receiver, args, generic_args: _, method_name: _ } => {
+ Expr::MethodCall { receiver, args, generic_args, method_name: _ } => {
visitor.on_expr(*receiver);
visitor.on_exprs(args);
+ visitor.on_generic_args_opt(generic_args);
}
Expr::Match { expr, arms } => {
visitor.on_expr(*expr);
@@ -731,7 +742,7 @@ impl ExpressionStore {
| Expr::Yield { expr }
| Expr::Yeet { expr } => visitor.on_expr_opt(*expr),
Expr::Become { expr } => visitor.on_expr(*expr),
- Expr::RecordLit { fields, spread, path: _ } => {
+ Expr::RecordLit { fields, spread, path } => {
for RecordLitField { name: _, expr } in fields.iter() {
visitor.on_expr(*expr);
}
@@ -739,17 +750,13 @@ impl ExpressionStore {
RecordSpread::Expr(expr) => visitor.on_expr(*expr),
RecordSpread::None | RecordSpread::FieldDefaults => {}
}
+ visitor.on_path(path);
}
- Expr::Closure {
- body,
- args,
- arg_types: _,
- capture_by: _,
- closure_kind: _,
- ret_type: _,
- } => {
+ Expr::Closure { body, args, arg_types, ret_type, capture_by: _, closure_kind: _ } => {
visitor.on_expr(*body);
visitor.on_pats(args);
+ arg_types.iter().for_each(|arg_type| visitor.on_type_opt(*arg_type));
+ visitor.on_type_opt(*ret_type);
}
Expr::BinaryOp { lhs, rhs, op: _ } => {
visitor.on_expr(*lhs);
@@ -763,9 +770,12 @@ impl ExpressionStore {
visitor.on_expr(*base);
visitor.on_expr(*index);
}
+ Expr::Cast { expr, type_ref } => {
+ visitor.on_expr(*expr);
+ visitor.on_type(*type_ref);
+ }
Expr::Field { expr, name: _ }
| Expr::Await { expr }
- | Expr::Cast { expr, type_ref: _ }
| Expr::Ref { expr, mutability: _, rawness: _ }
| Expr::UnaryOp { expr, op: _ }
| Expr::Box { expr }
@@ -777,7 +787,7 @@ impl ExpressionStore {
Array::ElementList { elements } => visitor.on_exprs(elements),
Array::Repeat { initializer, repeat } => {
visitor.on_expr(*initializer);
- visitor.on_expr(*repeat)
+ visitor.on_anon_const_expr(*repeat)
}
},
&Expr::Assignment { target, value } => {
@@ -789,14 +799,14 @@ impl ExpressionStore {
/// Walks the immediate children expressions and calls `f` for each child expression.
pub fn walk_child_exprs(&self, expr_id: ExprId, callback: impl FnMut(ExprId)) {
- return self.walk_child_exprs_impl(expr_id, Visitor { callback, store: self });
+ return self.visit_expr_children(expr_id, Visitor { callback, store: self });
struct Visitor<'a, F> {
callback: F,
store: &'a ExpressionStore,
}
- impl<F: FnMut(ExprId)> ExprVisitor for Visitor<'_, F> {
+ impl<F: FnMut(ExprId)> StoreVisitor for Visitor<'_, F> {
fn on_expr(&mut self, expr: ExprId) {
(self.callback)(expr);
}
@@ -810,48 +820,61 @@ impl ExpressionStore {
/// Walks the immediate children expressions and calls `f` for each child expression but does
/// not walk expressions within patterns.
pub fn walk_child_exprs_without_pats(&self, expr_id: ExprId, callback: impl FnMut(ExprId)) {
- return self.walk_child_exprs_impl(expr_id, Visitor { callback });
+ return self.visit_expr_children(expr_id, Visitor { callback });
struct Visitor<F> {
callback: F,
}
- impl<F: FnMut(ExprId)> ExprVisitor for Visitor<F> {
+ impl<F: FnMut(ExprId)> StoreVisitor for Visitor<F> {
fn on_expr(&mut self, expr: ExprId) {
(self.callback)(expr);
}
+ }
+ }
- fn on_pat(&mut self, _pat: PatId) {}
+ pub fn walk_exprs_in_pat(&self, pat_id: PatId, callback: impl FnMut(ExprId)) {
+ return Visitor { callback, store: self }.on_pat(pat_id);
+
+ struct Visitor<'a, F> {
+ callback: F,
+ store: &'a ExpressionStore,
+ }
+
+ impl<F: FnMut(ExprId)> StoreVisitor for Visitor<'_, F> {
+ fn on_expr(&mut self, expr: ExprId) {
+ (self.callback)(expr);
+ }
+
+ fn on_pat(&mut self, pat: PatId) {
+ self.store.visit_pat_children(pat, self);
+ }
}
}
- pub fn walk_exprs_in_pat(&self, pat_id: PatId, mut f: impl FnMut(ExprId)) {
- self.walk_pats(pat_id, &mut |pat| match self[pat] {
- Pat::Expr(expr) | Pat::ConstBlock(expr) | Pat::Lit(expr) => {
- f(expr);
+ 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::Tuple(types) => visitor.on_types(types),
+ TypeRef::Path(path) => visitor.on_path(path),
+ TypeRef::RawPtr(inner, _) | TypeRef::Slice(inner) => visitor.on_type(*inner),
+ TypeRef::Reference(ref_type) => {
+ let RefType { ty, lifetime, mutability: _ } = &**ref_type;
+ visitor.on_type(*ty);
+ visitor.on_lifetime_opt(*lifetime);
}
- Pat::Range { start, end, range_type: _ } => {
- if let Some(start) = start {
- f(start);
- }
- if let Some(end) = end {
- f(end);
- }
+ TypeRef::Array(ArrayType { ty, len: ConstRef { expr: len } }) => {
+ visitor.on_type(*ty);
+ visitor.on_anon_const_expr(*len);
}
- Pat::Missing
- | Pat::Rest
- | Pat::Wild
- | Pat::Tuple { .. }
- | Pat::Or(_)
- | Pat::Record { .. }
- | Pat::Slice { .. }
- | Pat::Path(_)
- | Pat::Bind { .. }
- | Pat::TupleStruct { .. }
- | Pat::Ref { .. }
- | Pat::Box { .. }
- | Pat::Deref { .. } => {}
- });
+ TypeRef::Fn(fn_type) => {
+ let FnType { params, is_varargs: _, is_unsafe: _, abi: _ } = &**fn_type;
+ params.iter().for_each(|(_, param_ty)| visitor.on_type(*param_ty));
+ }
+ TypeRef::ImplTrait(bounds) | TypeRef::DynTrait(bounds) => {
+ visitor.on_type_bounds(bounds)
+ }
+ }
}
#[inline]
@@ -918,21 +941,127 @@ impl ExpressionStore {
}
}
-trait ExprVisitor {
- fn on_expr(&mut self, expr: ExprId);
- fn on_pat(&mut self, pat: PatId);
+pub trait StoreVisitor {
+ fn on_expr(&mut self, expr: ExprId) {
+ let _ = expr;
+ }
+ fn on_anon_const_expr(&mut self, expr: ExprId) {
+ self.on_expr(expr);
+ }
+ fn on_pat(&mut self, pat: PatId) {
+ let _ = pat;
+ }
+ fn on_type(&mut self, ty: TypeRefId) {
+ let _ = ty;
+ }
+ fn on_lifetime(&mut self, lifetime: LifetimeRefId) {
+ let _ = lifetime;
+ }
+}
+
+impl<V: StoreVisitor> StoreVisitor for &mut V {
+ fn on_expr(&mut self, expr: ExprId) {
+ V::on_expr(self, expr);
+ }
+ fn on_anon_const_expr(&mut self, expr: ExprId) {
+ V::on_anon_const_expr(self, expr);
+ }
+ fn on_pat(&mut self, pat: PatId) {
+ V::on_pat(self, pat);
+ }
+ fn on_type(&mut self, ty: TypeRefId) {
+ V::on_type(self, ty);
+ }
+ fn on_lifetime(&mut self, lifetime: LifetimeRefId) {
+ V::on_lifetime(self, lifetime);
+ }
+}
+
+trait StoreVisitorExt: StoreVisitor {
+ fn on_generic_args(&mut self, args: &GenericArgs) {
+ let GenericArgs { args, bindings, parenthesized: _, has_self_type: _ } = args;
+ for arg in args {
+ match arg {
+ GenericArg::Type(arg) => self.on_type(*arg),
+ GenericArg::Const(ConstRef { expr }) => self.on_anon_const_expr(*expr),
+ GenericArg::Lifetime(arg) => self.on_lifetime(*arg),
+ }
+ }
+ for AssociatedTypeBinding { name: _, args, type_ref, bounds } in bindings {
+ self.on_generic_args_opt(args);
+ self.on_type_opt(*type_ref);
+ self.on_type_bounds(bounds);
+ }
+ }
+
+ fn on_type_bound(&mut self, bound: &TypeBound) {
+ match bound {
+ TypeBound::Path(path_id, _) => self.on_type(path_id.type_ref()),
+ TypeBound::ForLifetime(_, path_id) => self.on_type(path_id.type_ref()),
+ TypeBound::Lifetime(lifetime) => self.on_lifetime(*lifetime),
+ TypeBound::Use(args) => {
+ for arg in args {
+ match arg {
+ UseArgRef::Lifetime(lifetime) => self.on_lifetime(*lifetime),
+ UseArgRef::Name(_) => {}
+ }
+ }
+ }
+ TypeBound::Error => {}
+ }
+ }
+
+ fn on_path(&mut self, path: &Path) {
+ match path {
+ Path::Normal(path) => {
+ let NormalPath { generic_args, type_anchor, mod_path: _ } = &**path;
+ generic_args.iter().for_each(|generic_arg| self.on_generic_args_opt(generic_arg));
+ self.on_type_opt(*type_anchor);
+ }
+ Path::BarePath(_) | Path::LangItem(..) => {}
+ }
+ }
+
fn on_expr_opt(&mut self, expr: Option<ExprId>) {
if let Some(expr) = expr {
self.on_expr(expr);
}
}
+ fn on_pat_opt(&mut self, pat: Option<PatId>) {
+ if let Some(pat) = pat {
+ self.on_pat(pat);
+ }
+ }
+ fn on_type_opt(&mut self, ty: Option<TypeRefId>) {
+ if let Some(ty) = ty {
+ self.on_type(ty);
+ }
+ }
+ fn on_lifetime_opt(&mut self, lifetime: Option<LifetimeRefId>) {
+ if let Some(lifetime) = lifetime {
+ self.on_lifetime(lifetime);
+ }
+ }
+ fn on_generic_args_opt(&mut self, args: &Option<impl Borrow<GenericArgs>>) {
+ if let Some(args) = args {
+ self.on_generic_args(args.borrow());
+ }
+ }
+
fn on_exprs(&mut self, exprs: impl IntoIterator<Item: Borrow<ExprId>>) {
exprs.into_iter().for_each(|expr| self.on_expr(*expr.borrow()));
}
- fn on_pats(&mut self, exprs: impl IntoIterator<Item: Borrow<PatId>>) {
- exprs.into_iter().for_each(|expr| self.on_pat(*expr.borrow()));
+ fn on_pats(&mut self, pats: impl IntoIterator<Item: Borrow<PatId>>) {
+ pats.into_iter().for_each(|pat| self.on_pat(*pat.borrow()));
+ }
+ fn on_types(&mut self, types: impl IntoIterator<Item: Borrow<TypeRefId>>) {
+ types.into_iter().for_each(|ty| self.on_type(*ty.borrow()));
+ }
+ fn on_type_bounds(&mut self, bounds: impl IntoIterator<Item: Borrow<TypeBound>>) {
+ bounds.into_iter().for_each(|bound| self.on_type_bound(bound.borrow()));
}
}
+impl<V: StoreVisitor> StoreVisitorExt for V {}
impl Index<ExprId> for ExpressionStore {
type Output = Expr;