hir_def/expr_store/
body.rs

1//! Defines `Body`: a lowered representation of functions, statics and
2//! consts.
3use std::ops;
4
5use hir_expand::{InFile, Lookup};
6use span::Edition;
7use syntax::ast;
8use triomphe::Arc;
9
10use crate::{
11    DefWithBodyId, HasModule,
12    db::DefDatabase,
13    expr_store::{
14        ExpressionStore, ExpressionStoreSourceMap, SelfParamPtr, lower::lower_body, pretty,
15    },
16    hir::{BindingId, ExprId, PatId},
17    src::HasSource,
18};
19
20/// The body of an item (function, const etc.).
21#[derive(Debug, Eq, PartialEq)]
22pub struct Body {
23    pub store: ExpressionStore,
24    /// The patterns for the function's parameters. While the parameter types are
25    /// part of the function signature, the patterns are not (they don't change
26    /// the external type of the function).
27    ///
28    /// If this `Body` is for the body of a constant, this will just be
29    /// empty.
30    pub params: Box<[PatId]>,
31    pub self_param: Option<BindingId>,
32    /// The `ExprId` of the actual body expression.
33    pub body_expr: ExprId,
34}
35
36impl ops::Deref for Body {
37    type Target = ExpressionStore;
38
39    #[inline]
40    fn deref(&self) -> &Self::Target {
41        &self.store
42    }
43}
44
45/// An item body together with the mapping from syntax nodes to HIR expression
46/// IDs. This is needed to go from e.g. a position in a file to the HIR
47/// expression containing it; but for type inference etc., we want to operate on
48/// a structure that is agnostic to the actual positions of expressions in the
49/// file, so that we don't recompute types whenever some whitespace is typed.
50///
51/// One complication here is that, due to macro expansion, a single `Body` might
52/// be spread across several files. So, for each ExprId and PatId, we record
53/// both the HirFileId and the position inside the file. However, we only store
54/// AST -> ExprId mapping for non-macro files, as it is not clear how to handle
55/// this properly for macros.
56#[derive(Default, Debug, Eq, PartialEq)]
57pub struct BodySourceMap {
58    pub self_param: Option<InFile<SelfParamPtr>>,
59    pub store: ExpressionStoreSourceMap,
60}
61
62impl ops::Deref for BodySourceMap {
63    type Target = ExpressionStoreSourceMap;
64
65    #[inline]
66    fn deref(&self) -> &Self::Target {
67        &self.store
68    }
69}
70
71impl Body {
72    pub(crate) fn body_with_source_map_query(
73        db: &dyn DefDatabase,
74        def: DefWithBodyId,
75    ) -> (Arc<Body>, Arc<BodySourceMap>) {
76        let _p = tracing::info_span!("body_with_source_map_query").entered();
77        let mut params = None;
78
79        let mut is_async_fn = false;
80        let InFile { file_id, value: body } = {
81            match def {
82                DefWithBodyId::FunctionId(f) => {
83                    let f = f.lookup(db);
84                    let src = f.source(db);
85                    params = src.value.param_list();
86                    is_async_fn = src.value.async_token().is_some();
87                    src.map(|it| it.body().map(ast::Expr::from))
88                }
89                DefWithBodyId::ConstId(c) => {
90                    let c = c.lookup(db);
91                    let src = c.source(db);
92                    src.map(|it| it.body())
93                }
94                DefWithBodyId::StaticId(s) => {
95                    let s = s.lookup(db);
96                    let src = s.source(db);
97                    src.map(|it| it.body())
98                }
99                DefWithBodyId::VariantId(v) => {
100                    let s = v.lookup(db);
101                    let src = s.source(db);
102                    src.map(|it| it.expr())
103                }
104            }
105        };
106        let module = def.module(db);
107        let (body, source_map) = lower_body(db, def, file_id, module, params, body, is_async_fn);
108
109        (Arc::new(body), Arc::new(source_map))
110    }
111
112    pub(crate) fn body_query(db: &dyn DefDatabase, def: DefWithBodyId) -> Arc<Body> {
113        db.body_with_source_map(def).0
114    }
115
116    pub fn pretty_print(
117        &self,
118        db: &dyn DefDatabase,
119        owner: DefWithBodyId,
120        edition: Edition,
121    ) -> String {
122        pretty::print_body_hir(db, self, owner, edition)
123    }
124
125    pub fn pretty_print_expr(
126        &self,
127        db: &dyn DefDatabase,
128        owner: DefWithBodyId,
129        expr: ExprId,
130        edition: Edition,
131    ) -> String {
132        pretty::print_expr_hir(db, self, owner, expr, edition)
133    }
134
135    pub fn pretty_print_pat(
136        &self,
137        db: &dyn DefDatabase,
138        owner: DefWithBodyId,
139        pat: PatId,
140        oneline: bool,
141        edition: Edition,
142    ) -> String {
143        pretty::print_pat_hir(db, self, owner, pat, oneline, edition)
144    }
145}
146
147impl BodySourceMap {
148    pub fn self_param_syntax(&self) -> Option<InFile<SelfParamPtr>> {
149        self.self_param
150    }
151}