1 //! Defines `Body`: a lowered representation of bodies of functions, statics and 2 //! consts. 3 mod lower; 4 #[cfg(test)] 5 mod tests; 6 pub mod scope; 7 mod pretty; 8 9 use std::ops::Index; 10 11 use base_db::CrateId; 12 use cfg::{CfgExpr, CfgOptions}; 13 use either::Either; 14 use hir_expand::{name::Name, HirFileId, InFile}; 15 use la_arena::{Arena, ArenaMap}; 16 use profile::Count; 17 use rustc_hash::FxHashMap; 18 use syntax::{ast, AstPtr, SyntaxNodePtr}; 19 use triomphe::Arc; 20 21 use crate::{ 22 db::DefDatabase, 23 expander::Expander, 24 hir::{ 25 dummy_expr_id, Binding, BindingId, Expr, ExprId, Label, LabelId, Pat, PatId, RecordFieldPat, 26 }, 27 nameres::DefMap, 28 path::{ModPath, Path}, 29 src::{HasChildSource, HasSource}, 30 BlockId, DefWithBodyId, HasModule, Lookup, 31 }; 32 33 /// The body of an item (function, const etc.). 34 #[derive(Debug, Eq, PartialEq)] 35 pub struct Body { 36 pub exprs: Arena<Expr>, 37 pub pats: Arena<Pat>, 38 pub bindings: Arena<Binding>, 39 pub labels: Arena<Label>, 40 /// Id of the closure/generator that owns the corresponding binding. If a binding is owned by the 41 /// top level expression, it will not be listed in here. 42 pub binding_owners: FxHashMap<BindingId, ExprId>, 43 /// The patterns for the function's parameters. While the parameter types are 44 /// part of the function signature, the patterns are not (they don't change 45 /// the external type of the function). 46 /// 47 /// If this `Body` is for the body of a constant, this will just be 48 /// empty. 49 pub params: Vec<PatId>, 50 /// The `ExprId` of the actual body expression. 51 pub body_expr: ExprId, 52 /// Block expressions in this body that may contain inner items. 53 block_scopes: Vec<BlockId>, 54 _c: Count<Self>, 55 } 56 57 pub type ExprPtr = AstPtr<ast::Expr>; 58 pub type ExprSource = InFile<ExprPtr>; 59 60 pub type PatPtr = Either<AstPtr<ast::Pat>, AstPtr<ast::SelfParam>>; 61 pub type PatSource = InFile<PatPtr>; 62 63 pub type LabelPtr = AstPtr<ast::Label>; 64 pub type LabelSource = InFile<LabelPtr>; 65 66 pub type FieldPtr = AstPtr<ast::RecordExprField>; 67 pub type FieldSource = InFile<FieldPtr>; 68 69 /// An item body together with the mapping from syntax nodes to HIR expression 70 /// IDs. This is needed to go from e.g. a position in a file to the HIR 71 /// expression containing it; but for type inference etc., we want to operate on 72 /// a structure that is agnostic to the actual positions of expressions in the 73 /// file, so that we don't recompute types whenever some whitespace is typed. 74 /// 75 /// One complication here is that, due to macro expansion, a single `Body` might 76 /// be spread across several files. So, for each ExprId and PatId, we record 77 /// both the HirFileId and the position inside the file. However, we only store 78 /// AST -> ExprId mapping for non-macro files, as it is not clear how to handle 79 /// this properly for macros. 80 #[derive(Default, Debug, Eq, PartialEq)] 81 pub struct BodySourceMap { 82 expr_map: FxHashMap<ExprSource, ExprId>, 83 expr_map_back: ArenaMap<ExprId, ExprSource>, 84 85 pat_map: FxHashMap<PatSource, PatId>, 86 pat_map_back: ArenaMap<PatId, PatSource>, 87 88 label_map: FxHashMap<LabelSource, LabelId>, 89 label_map_back: ArenaMap<LabelId, LabelSource>, 90 91 /// We don't create explicit nodes for record fields (`S { record_field: 92 }`). 92 /// Instead, we use id of expression (`92`) to identify the field. 93 field_map: FxHashMap<FieldSource, ExprId>, 94 field_map_back: FxHashMap<ExprId, FieldSource>, 95 96 expansions: FxHashMap<InFile<AstPtr<ast::MacroCall>>, HirFileId>, 97 98 /// Diagnostics accumulated during body lowering. These contain `AstPtr`s and so are stored in 99 /// the source map (since they're just as volatile). 100 diagnostics: Vec<BodyDiagnostic>, 101 } 102 103 #[derive(Default, Debug, Eq, PartialEq, Clone, Copy)] 104 pub struct SyntheticSyntax; 105 106 #[derive(Debug, Eq, PartialEq)] 107 pub enum BodyDiagnostic { 108 InactiveCode { node: InFile<SyntaxNodePtr>, cfg: CfgExpr, opts: CfgOptions }, 109 MacroError { node: InFile<AstPtr<ast::MacroCall>>, message: String }, 110 UnresolvedProcMacro { node: InFile<AstPtr<ast::MacroCall>>, krate: CrateId }, 111 UnresolvedMacroCall { node: InFile<AstPtr<ast::MacroCall>>, path: ModPath }, 112 UnreachableLabel { node: InFile<AstPtr<ast::Lifetime>>, name: Name }, 113 UndeclaredLabel { node: InFile<AstPtr<ast::Lifetime>>, name: Name }, 114 } 115 116 impl Body { body_with_source_map_query( db: &dyn DefDatabase, def: DefWithBodyId, ) -> (Arc<Body>, Arc<BodySourceMap>)117 pub(crate) fn body_with_source_map_query( 118 db: &dyn DefDatabase, 119 def: DefWithBodyId, 120 ) -> (Arc<Body>, Arc<BodySourceMap>) { 121 let _p = profile::span("body_with_source_map_query"); 122 let mut params = None; 123 124 let mut is_async_fn = false; 125 let InFile { file_id, value: body } = { 126 match def { 127 DefWithBodyId::FunctionId(f) => { 128 let data = db.function_data(f); 129 let f = f.lookup(db); 130 let src = f.source(db); 131 params = src.value.param_list().map(|param_list| { 132 let item_tree = f.id.item_tree(db); 133 let func = &item_tree[f.id.value]; 134 let krate = f.container.module(db).krate; 135 let crate_graph = db.crate_graph(); 136 ( 137 param_list, 138 func.params.clone().map(move |param| { 139 item_tree 140 .attrs(db, krate, param.into()) 141 .is_cfg_enabled(&crate_graph[krate].cfg_options) 142 }), 143 ) 144 }); 145 is_async_fn = data.has_async_kw(); 146 src.map(|it| it.body().map(ast::Expr::from)) 147 } 148 DefWithBodyId::ConstId(c) => { 149 let c = c.lookup(db); 150 let src = c.source(db); 151 src.map(|it| it.body()) 152 } 153 DefWithBodyId::StaticId(s) => { 154 let s = s.lookup(db); 155 let src = s.source(db); 156 src.map(|it| it.body()) 157 } 158 DefWithBodyId::VariantId(v) => { 159 let src = v.parent.child_source(db); 160 src.map(|it| it[v.local_id].expr()) 161 } 162 DefWithBodyId::InTypeConstId(c) => c.lookup(db).id.map(|_| c.source(db).expr()), 163 } 164 }; 165 let module = def.module(db); 166 let expander = Expander::new(db, file_id, module); 167 let (mut body, source_map) = 168 Body::new(db, def, expander, params, body, module.krate, is_async_fn); 169 body.shrink_to_fit(); 170 171 (Arc::new(body), Arc::new(source_map)) 172 } 173 body_query(db: &dyn DefDatabase, def: DefWithBodyId) -> Arc<Body>174 pub(crate) fn body_query(db: &dyn DefDatabase, def: DefWithBodyId) -> Arc<Body> { 175 db.body_with_source_map(def).0 176 } 177 178 /// Returns an iterator over all block expressions in this body that define inner items. blocks<'a>( &'a self, db: &'a dyn DefDatabase, ) -> impl Iterator<Item = (BlockId, Arc<DefMap>)> + '_179 pub fn blocks<'a>( 180 &'a self, 181 db: &'a dyn DefDatabase, 182 ) -> impl Iterator<Item = (BlockId, Arc<DefMap>)> + '_ { 183 self.block_scopes.iter().map(move |&block| (block, db.block_def_map(block))) 184 } 185 pretty_print(&self, db: &dyn DefDatabase, owner: DefWithBodyId) -> String186 pub fn pretty_print(&self, db: &dyn DefDatabase, owner: DefWithBodyId) -> String { 187 pretty::print_body_hir(db, self, owner) 188 } 189 pretty_print_expr( &self, db: &dyn DefDatabase, owner: DefWithBodyId, expr: ExprId, ) -> String190 pub fn pretty_print_expr( 191 &self, 192 db: &dyn DefDatabase, 193 owner: DefWithBodyId, 194 expr: ExprId, 195 ) -> String { 196 pretty::print_expr_hir(db, self, owner, expr) 197 } 198 new( db: &dyn DefDatabase, owner: DefWithBodyId, expander: Expander, params: Option<(ast::ParamList, impl Iterator<Item = bool>)>, body: Option<ast::Expr>, krate: CrateId, is_async_fn: bool, ) -> (Body, BodySourceMap)199 fn new( 200 db: &dyn DefDatabase, 201 owner: DefWithBodyId, 202 expander: Expander, 203 params: Option<(ast::ParamList, impl Iterator<Item = bool>)>, 204 body: Option<ast::Expr>, 205 krate: CrateId, 206 is_async_fn: bool, 207 ) -> (Body, BodySourceMap) { 208 lower::lower(db, owner, expander, params, body, krate, is_async_fn) 209 } 210 shrink_to_fit(&mut self)211 fn shrink_to_fit(&mut self) { 212 let Self { 213 _c: _, 214 body_expr: _, 215 block_scopes, 216 exprs, 217 labels, 218 params, 219 pats, 220 bindings, 221 binding_owners, 222 } = self; 223 block_scopes.shrink_to_fit(); 224 exprs.shrink_to_fit(); 225 labels.shrink_to_fit(); 226 params.shrink_to_fit(); 227 pats.shrink_to_fit(); 228 bindings.shrink_to_fit(); 229 binding_owners.shrink_to_fit(); 230 } 231 walk_bindings_in_pat(&self, pat_id: PatId, mut f: impl FnMut(BindingId))232 pub fn walk_bindings_in_pat(&self, pat_id: PatId, mut f: impl FnMut(BindingId)) { 233 self.walk_pats(pat_id, &mut |pat| { 234 if let Pat::Bind { id, .. } = &self[pat] { 235 f(*id); 236 } 237 }); 238 } 239 walk_pats_shallow(&self, pat_id: PatId, mut f: impl FnMut(PatId))240 pub fn walk_pats_shallow(&self, pat_id: PatId, mut f: impl FnMut(PatId)) { 241 let pat = &self[pat_id]; 242 match pat { 243 Pat::Range { .. } 244 | Pat::Lit(..) 245 | Pat::Path(..) 246 | Pat::ConstBlock(..) 247 | Pat::Wild 248 | Pat::Missing => {} 249 &Pat::Bind { subpat, .. } => { 250 if let Some(subpat) = subpat { 251 f(subpat); 252 } 253 } 254 Pat::Or(args) | Pat::Tuple { args, .. } | Pat::TupleStruct { args, .. } => { 255 args.iter().copied().for_each(|p| f(p)); 256 } 257 Pat::Ref { pat, .. } => f(*pat), 258 Pat::Slice { prefix, slice, suffix } => { 259 let total_iter = prefix.iter().chain(slice.iter()).chain(suffix.iter()); 260 total_iter.copied().for_each(|p| f(p)); 261 } 262 Pat::Record { args, .. } => { 263 args.iter().for_each(|RecordFieldPat { pat, .. }| f(*pat)); 264 } 265 Pat::Box { inner } => f(*inner), 266 } 267 } 268 walk_pats(&self, pat_id: PatId, f: &mut impl FnMut(PatId))269 pub fn walk_pats(&self, pat_id: PatId, f: &mut impl FnMut(PatId)) { 270 f(pat_id); 271 self.walk_pats_shallow(pat_id, |p| self.walk_pats(p, f)); 272 } 273 is_binding_upvar(&self, binding: BindingId, relative_to: ExprId) -> bool274 pub fn is_binding_upvar(&self, binding: BindingId, relative_to: ExprId) -> bool { 275 match self.binding_owners.get(&binding) { 276 Some(x) => { 277 // We assign expression ids in a way that outer closures will receive 278 // a lower id 279 x.into_raw() < relative_to.into_raw() 280 } 281 None => true, 282 } 283 } 284 } 285 286 impl Default for Body { default() -> Self287 fn default() -> Self { 288 Self { 289 body_expr: dummy_expr_id(), 290 exprs: Default::default(), 291 pats: Default::default(), 292 bindings: Default::default(), 293 labels: Default::default(), 294 params: Default::default(), 295 block_scopes: Default::default(), 296 binding_owners: Default::default(), 297 _c: Default::default(), 298 } 299 } 300 } 301 302 impl Index<ExprId> for Body { 303 type Output = Expr; 304 index(&self, expr: ExprId) -> &Expr305 fn index(&self, expr: ExprId) -> &Expr { 306 &self.exprs[expr] 307 } 308 } 309 310 impl Index<PatId> for Body { 311 type Output = Pat; 312 index(&self, pat: PatId) -> &Pat313 fn index(&self, pat: PatId) -> &Pat { 314 &self.pats[pat] 315 } 316 } 317 318 impl Index<LabelId> for Body { 319 type Output = Label; 320 index(&self, label: LabelId) -> &Label321 fn index(&self, label: LabelId) -> &Label { 322 &self.labels[label] 323 } 324 } 325 326 impl Index<BindingId> for Body { 327 type Output = Binding; 328 index(&self, b: BindingId) -> &Binding329 fn index(&self, b: BindingId) -> &Binding { 330 &self.bindings[b] 331 } 332 } 333 334 // FIXME: Change `node_` prefix to something more reasonable. 335 // Perhaps `expr_syntax` and `expr_id`? 336 impl BodySourceMap { expr_syntax(&self, expr: ExprId) -> Result<ExprSource, SyntheticSyntax>337 pub fn expr_syntax(&self, expr: ExprId) -> Result<ExprSource, SyntheticSyntax> { 338 self.expr_map_back.get(expr).cloned().ok_or(SyntheticSyntax) 339 } 340 node_expr(&self, node: InFile<&ast::Expr>) -> Option<ExprId>341 pub fn node_expr(&self, node: InFile<&ast::Expr>) -> Option<ExprId> { 342 let src = node.map(AstPtr::new); 343 self.expr_map.get(&src).cloned() 344 } 345 node_macro_file(&self, node: InFile<&ast::MacroCall>) -> Option<HirFileId>346 pub fn node_macro_file(&self, node: InFile<&ast::MacroCall>) -> Option<HirFileId> { 347 let src = node.map(AstPtr::new); 348 self.expansions.get(&src).cloned() 349 } 350 pat_syntax(&self, pat: PatId) -> Result<PatSource, SyntheticSyntax>351 pub fn pat_syntax(&self, pat: PatId) -> Result<PatSource, SyntheticSyntax> { 352 self.pat_map_back.get(pat).cloned().ok_or(SyntheticSyntax) 353 } 354 node_pat(&self, node: InFile<&ast::Pat>) -> Option<PatId>355 pub fn node_pat(&self, node: InFile<&ast::Pat>) -> Option<PatId> { 356 let src = node.map(|it| Either::Left(AstPtr::new(it))); 357 self.pat_map.get(&src).cloned() 358 } 359 node_self_param(&self, node: InFile<&ast::SelfParam>) -> Option<PatId>360 pub fn node_self_param(&self, node: InFile<&ast::SelfParam>) -> Option<PatId> { 361 let src = node.map(|it| Either::Right(AstPtr::new(it))); 362 self.pat_map.get(&src).cloned() 363 } 364 label_syntax(&self, label: LabelId) -> LabelSource365 pub fn label_syntax(&self, label: LabelId) -> LabelSource { 366 self.label_map_back[label].clone() 367 } 368 node_label(&self, node: InFile<&ast::Label>) -> Option<LabelId>369 pub fn node_label(&self, node: InFile<&ast::Label>) -> Option<LabelId> { 370 let src = node.map(AstPtr::new); 371 self.label_map.get(&src).cloned() 372 } 373 field_syntax(&self, expr: ExprId) -> FieldSource374 pub fn field_syntax(&self, expr: ExprId) -> FieldSource { 375 self.field_map_back[&expr].clone() 376 } 377 node_field(&self, node: InFile<&ast::RecordExprField>) -> Option<ExprId>378 pub fn node_field(&self, node: InFile<&ast::RecordExprField>) -> Option<ExprId> { 379 let src = node.map(AstPtr::new); 380 self.field_map.get(&src).cloned() 381 } 382 macro_expansion_expr(&self, node: InFile<&ast::MacroExpr>) -> Option<ExprId>383 pub fn macro_expansion_expr(&self, node: InFile<&ast::MacroExpr>) -> Option<ExprId> { 384 let src = node.map(AstPtr::new).map(AstPtr::upcast::<ast::MacroExpr>).map(AstPtr::upcast); 385 self.expr_map.get(&src).copied() 386 } 387 388 /// Get a reference to the body source map's diagnostics. diagnostics(&self) -> &[BodyDiagnostic]389 pub fn diagnostics(&self) -> &[BodyDiagnostic] { 390 &self.diagnostics 391 } 392 } 393