hir_def/expr_store/
body.rs1use std::ops;
4
5use base_db::SourceDatabase;
6use hir_expand::{InFile, Lookup};
7use span::Edition;
8use syntax::{SyntaxNodePtr, ast};
9use triomphe::Arc;
10
11use crate::{
12 DefWithBodyId, ExpressionStoreOwnerId, HasModule,
13 expr_store::{
14 ExpressionStore, ExpressionStoreSourceMap, SelfParamPtr, lower::lower_body, pretty,
15 },
16 hir::{BindingId, ExprId, PatId},
17 src::HasSource,
18};
19
20#[derive(Debug, Clone, Copy, PartialEq, Eq)]
21pub struct Param<Id> {
22 pub formal: Id,
25 pub user_written: Id,
30}
31
32impl<Id: Copy> Param<Id> {
33 pub(crate) fn new(id: Id) -> Self {
34 Self { formal: id, user_written: id }
35 }
36}
37
38#[derive(Debug, Eq, PartialEq)]
40pub struct Body {
41 pub store: ExpressionStore,
42 pub params: Box<[Param<PatId>]>,
49 pub self_param: Option<Param<BindingId>>,
50}
51
52impl ops::Deref for Body {
53 type Target = ExpressionStore;
54
55 #[inline]
56 fn deref(&self) -> &Self::Target {
57 &self.store
58 }
59}
60
61#[derive(Default, Debug, Eq, PartialEq)]
73pub struct BodySourceMap {
74 pub self_param: Option<InFile<SelfParamPtr>>,
75 pub store: ExpressionStoreSourceMap,
76}
77
78impl ops::Deref for BodySourceMap {
79 type Target = ExpressionStoreSourceMap;
80
81 #[inline]
82 fn deref(&self) -> &Self::Target {
83 &self.store
84 }
85}
86
87#[salsa::tracked]
88impl Body {
89 #[salsa::tracked(lru = 512, returns(ref))]
90 pub fn with_source_map(
91 db: &dyn SourceDatabase,
92 def: DefWithBodyId,
93 ) -> (Arc<Body>, BodySourceMap) {
94 let _p = tracing::info_span!("body_with_source_map_query").entered();
95 let mut params = None;
96
97 let mut is_async_fn = false;
98 let mut is_gen_fn = false;
99 let (InFile { file_id, value: body }, syntax_node) = {
100 match def {
101 DefWithBodyId::FunctionId(f) => {
102 let f = f.lookup(db);
103 let src = f.source(db);
104 params = src.value.param_list();
105 is_async_fn = src.value.async_token().is_some();
106 is_gen_fn = src.value.gen_token().is_some();
107 let syntax_node = SyntaxNodePtr::new(src.syntax().value);
108 (src.map(|it| it.body().map(ast::Expr::from)), syntax_node)
109 }
110 DefWithBodyId::ConstId(c) => {
111 let c = c.lookup(db);
112 let src = c.source(db);
113 let syntax_node = SyntaxNodePtr::new(src.syntax().value);
114 (src.map(|it| it.body()), syntax_node)
115 }
116 DefWithBodyId::StaticId(s) => {
117 let s = s.lookup(db);
118 let src = s.source(db);
119 let syntax_node = SyntaxNodePtr::new(src.syntax().value);
120 (src.map(|it| it.body()), syntax_node)
121 }
122 DefWithBodyId::VariantId(v) => {
123 let s = v.lookup(db);
124 let src = s.source(db);
125 let syntax_node = SyntaxNodePtr::new(src.syntax().value);
126 (src.map(|it| it.const_arg()?.expr()), syntax_node)
127 }
128 }
129 };
130 let module = def.module(db);
131 let (body, source_map) =
132 lower_body(db, def, syntax_node, file_id, module, params, body, is_async_fn, is_gen_fn);
133
134 (Arc::new(body), source_map)
135 }
136
137 #[salsa::tracked(returns(deref))]
138 pub fn of(db: &dyn SourceDatabase, def: DefWithBodyId) -> Arc<Body> {
139 Self::with_source_map(db, def).0.clone()
140 }
141}
142
143impl Body {
144 pub fn root_expr(&self) -> ExprId {
145 self.store.expr_roots().next_back().unwrap()
148 }
149
150 #[inline]
152 pub fn is_any_self_param(&self, binding: BindingId) -> bool {
153 self.self_param.is_some_and(|self_param| {
154 self_param.formal == binding || self_param.user_written == binding
155 })
156 }
157
158 pub fn pretty_print(
159 &self,
160 db: &dyn SourceDatabase,
161 owner: DefWithBodyId,
162 edition: Edition,
163 ) -> String {
164 pretty::print_body_hir(db, self, owner, edition)
165 }
166
167 pub fn pretty_print_expr(
168 &self,
169 db: &dyn SourceDatabase,
170 owner: DefWithBodyId,
171 expr: ExprId,
172 edition: Edition,
173 ) -> String {
174 pretty::print_expr_hir(db, self, owner.into(), expr, edition)
175 }
176
177 pub fn pretty_print_pat(
178 &self,
179 db: &dyn SourceDatabase,
180 owner: ExpressionStoreOwnerId,
181 pat: PatId,
182 oneline: bool,
183 edition: Edition,
184 ) -> String {
185 pretty::print_pat_hir(db, self, owner, pat, oneline, edition)
186 }
187}
188
189impl BodySourceMap {
190 pub fn self_param_syntax(&self) -> Option<InFile<SelfParamPtr>> {
191 self.self_param
192 }
193}