]> git.proxmox.com Git - rustc.git/blame - src/librustc/hir/map/blocks.rs
New upstream version 1.43.0+dfsg1
[rustc.git] / src / librustc / hir / map / blocks.rs
CommitLineData
1a4d82fc 1//! This module provides a simplified abstraction for working with
9fa01778 2//! code blocks identified by their integer `NodeId`. In particular,
1a4d82fc 3//! it captures a common set of attributes that all "function-like
9fa01778 4//! things" (represented by `FnLike` instances) share. For example,
1a4d82fc 5//! all `FnLike` instances have a type signature (be it explicit or
9fa01778 6//! inferred). And all `FnLike` instances have a body, i.e., the code
1a4d82fc
JJ
7//! that is run when the function-like thing it represents is invoked.
8//!
9//! With the above abstraction in place, one can treat the program
10//! text as a collection of blocks of code (and most such blocks are
11//! nested within a uniquely determined `FnLike`), and users can ask
12//! for the `Code` associated with a particular NodeId.
13
dfeec247 14use crate::hir::map::Map;
74b04a01 15use rustc_ast::ast::{Attribute, Ident};
dfeec247
XL
16use rustc_hir as hir;
17use rustc_hir::intravisit::FnKind;
18use rustc_hir::{Expr, FnDecl, Node};
19use rustc_span::Span;
1a4d82fc
JJ
20
21/// An FnLikeNode is a Node that is like a fn, in that it has a decl
22/// and a body (as well as a NodeId, a span, etc).
23///
24/// More specifically, it is one of either:
ff7c6d11 25///
1a4d82fc 26/// - A function item,
0731742a 27/// - A closure expr (i.e., an ExprKind::Closure), or
1a4d82fc
JJ
28/// - The default implementation for a trait method.
29///
30/// To construct one, use the `Code::from_node` function.
32a655c1 31#[derive(Copy, Clone, Debug)]
60c5eb7d
XL
32pub struct FnLikeNode<'a> {
33 node: Node<'a>,
34}
1a4d82fc
JJ
35
36/// MaybeFnLike wraps a method that indicates if an object
37/// corresponds to some FnLikeNode.
60c5eb7d
XL
38trait MaybeFnLike {
39 fn is_fn_like(&self) -> bool;
40}
1a4d82fc 41
dfeec247 42impl MaybeFnLike for hir::Item<'_> {
1a4d82fc 43 fn is_fn_like(&self) -> bool {
e74abb32 44 match self.kind {
dfeec247 45 hir::ItemKind::Fn(..) => true,
e74abb32
XL
46 _ => false,
47 }
8faf50e0
XL
48 }
49}
50
dfeec247 51impl MaybeFnLike for hir::ImplItem<'_> {
8faf50e0 52 fn is_fn_like(&self) -> bool {
e74abb32 53 match self.kind {
dfeec247 54 hir::ImplItemKind::Method(..) => true,
e74abb32
XL
55 _ => false,
56 }
1a4d82fc
JJ
57 }
58}
59
dfeec247 60impl MaybeFnLike for hir::TraitItem<'_> {
1a4d82fc 61 fn is_fn_like(&self) -> bool {
e74abb32 62 match self.kind {
dfeec247 63 hir::TraitItemKind::Method(_, hir::TraitMethod::Provided(_)) => true,
32a655c1
SL
64 _ => false,
65 }
1a4d82fc
JJ
66 }
67}
68
dfeec247 69impl MaybeFnLike for hir::Expr<'_> {
1a4d82fc 70 fn is_fn_like(&self) -> bool {
e74abb32 71 match self.kind {
dfeec247 72 hir::ExprKind::Closure(..) => true,
1a4d82fc
JJ
73 _ => false,
74 }
75 }
76}
77
476ff2be 78/// Carries either an FnLikeNode or a Expr, as these are the two
1a4d82fc
JJ
79/// constructs that correspond to "code" (as in, something from which
80/// we can construct a control-flow graph).
c34b1796 81#[derive(Copy, Clone)]
1a4d82fc 82pub enum Code<'a> {
476ff2be 83 FnLike(FnLikeNode<'a>),
dfeec247 84 Expr(&'a Expr<'a>),
1a4d82fc
JJ
85}
86
87impl<'a> Code<'a> {
dfeec247 88 pub fn id(&self) -> hir::HirId {
1a4d82fc 89 match *self {
476ff2be 90 Code::FnLike(node) => node.id(),
532ac7d7 91 Code::Expr(block) => block.hir_id,
1a4d82fc
JJ
92 }
93 }
94
476ff2be 95 /// Attempts to construct a Code from presumed FnLike or Expr node input.
dfeec247 96 pub fn from_node(map: &Map<'a>, id: hir::HirId) -> Option<Code<'a>> {
476ff2be 97 match map.get(id) {
dfeec247 98 Node::Block(_) => {
476ff2be
SL
99 // Use the parent, hopefully an expression node.
100 Code::from_node(map, map.get_parent_node(id))
101 }
dfeec247 102 Node::Expr(expr) => Some(Code::Expr(expr)),
60c5eb7d 103 node => FnLikeNode::from_node(node).map(Code::FnLike),
1a4d82fc
JJ
104 }
105 }
106}
107
108/// These are all the components one can extract from a fn item for
109/// use when implementing FnLikeNode operations.
110struct ItemFnParts<'a> {
60c5eb7d 111 ident: Ident,
dfeec247
XL
112 decl: &'a hir::FnDecl<'a>,
113 header: hir::FnHeader,
114 vis: &'a hir::Visibility<'a>,
115 generics: &'a hir::Generics<'a>,
116 body: hir::BodyId,
117 id: hir::HirId,
60c5eb7d
XL
118 span: Span,
119 attrs: &'a [Attribute],
1a4d82fc
JJ
120}
121
122/// These are all the components one can extract from a closure expr
123/// for use when implementing FnLikeNode operations.
124struct ClosureParts<'a> {
dfeec247
XL
125 decl: &'a FnDecl<'a>,
126 body: hir::BodyId,
127 id: hir::HirId,
54a0048b
SL
128 span: Span,
129 attrs: &'a [Attribute],
1a4d82fc
JJ
130}
131
132impl<'a> ClosureParts<'a> {
dfeec247
XL
133 fn new(
134 d: &'a FnDecl<'a>,
135 b: hir::BodyId,
136 id: hir::HirId,
137 s: Span,
138 attrs: &'a [Attribute],
139 ) -> Self {
60c5eb7d 140 ClosureParts { decl: d, body: b, id, span: s, attrs }
1a4d82fc
JJ
141 }
142}
143
144impl<'a> FnLikeNode<'a> {
62682a34 145 /// Attempts to construct a FnLikeNode from presumed FnLike node input.
0bf4aa26 146 pub fn from_node(node: Node<'_>) -> Option<FnLikeNode<'_>> {
62682a34 147 let fn_like = match node {
dfeec247
XL
148 Node::Item(item) => item.is_fn_like(),
149 Node::TraitItem(tm) => tm.is_fn_like(),
150 Node::ImplItem(it) => it.is_fn_like(),
151 Node::Expr(e) => e.is_fn_like(),
60c5eb7d 152 _ => false,
62682a34 153 };
60c5eb7d 154 fn_like.then_some(FnLikeNode { node })
62682a34
SL
155 }
156
dfeec247 157 pub fn body(self) -> hir::BodyId {
60c5eb7d
XL
158 self.handle(
159 |i: ItemFnParts<'a>| i.body,
dfeec247 160 |_, _, _: &'a hir::FnSig<'a>, _, body: hir::BodyId, _, _| body,
60c5eb7d
XL
161 |c: ClosureParts<'a>| c.body,
162 )
1a4d82fc
JJ
163 }
164
dfeec247 165 pub fn decl(self) -> &'a FnDecl<'a> {
60c5eb7d
XL
166 self.handle(
167 |i: ItemFnParts<'a>| &*i.decl,
dfeec247 168 |_, _, sig: &'a hir::FnSig<'a>, _, _, _, _| &sig.decl,
60c5eb7d
XL
169 |c: ClosureParts<'a>| c.decl,
170 )
1a4d82fc
JJ
171 }
172
173 pub fn span(self) -> Span {
60c5eb7d
XL
174 self.handle(
175 |i: ItemFnParts<'_>| i.span,
dfeec247 176 |_, _, _: &'a hir::FnSig<'a>, _, _, span, _| span,
60c5eb7d
XL
177 |c: ClosureParts<'_>| c.span,
178 )
1a4d82fc
JJ
179 }
180
dfeec247 181 pub fn id(self) -> hir::HirId {
60c5eb7d
XL
182 self.handle(
183 |i: ItemFnParts<'_>| i.id,
dfeec247 184 |id, _, _: &'a hir::FnSig<'a>, _, _, _, _| id,
60c5eb7d
XL
185 |c: ClosureParts<'_>| c.id,
186 )
1a4d82fc
JJ
187 }
188
dfeec247
XL
189 pub fn constness(self) -> hir::Constness {
190 self.kind().header().map_or(hir::Constness::NotConst, |header| header.constness)
476ff2be
SL
191 }
192
dfeec247
XL
193 pub fn asyncness(self) -> hir::IsAsync {
194 self.kind().header().map_or(hir::IsAsync::NotAsync, |header| header.asyncness)
8faf50e0
XL
195 }
196
dfeec247
XL
197 pub fn unsafety(self) -> hir::Unsafety {
198 self.kind().header().map_or(hir::Unsafety::Normal, |header| header.unsafety)
3b2f2976
XL
199 }
200
e9174d1e
SL
201 pub fn kind(self) -> FnKind<'a> {
202 let item = |p: ItemFnParts<'a>| -> FnKind<'a> {
0731742a 203 FnKind::ItemFn(p.ident, p.generics, p.header, p.vis, p.attrs)
1a4d82fc 204 };
60c5eb7d 205 let closure = |c: ClosureParts<'a>| FnKind::Closure(c.attrs);
dfeec247 206 let method = |_, ident: Ident, sig: &'a hir::FnSig<'a>, vis, _, _, attrs| {
8faf50e0 207 FnKind::Method(ident, sig, vis, attrs)
1a4d82fc
JJ
208 };
209 self.handle(item, method, closure)
210 }
211
60c5eb7d
XL
212 fn handle<A, I, M, C>(self, item_fn: I, method: M, closure: C) -> A
213 where
1a4d82fc 214 I: FnOnce(ItemFnParts<'a>) -> A,
60c5eb7d 215 M: FnOnce(
dfeec247 216 hir::HirId,
60c5eb7d 217 Ident,
dfeec247
XL
218 &'a hir::FnSig<'a>,
219 Option<&'a hir::Visibility<'a>>,
220 hir::BodyId,
60c5eb7d
XL
221 Span,
222 &'a [Attribute],
223 ) -> A,
1a4d82fc
JJ
224 C: FnOnce(ClosureParts<'a>) -> A,
225 {
226 match self.node {
dfeec247
XL
227 Node::Item(i) => match i.kind {
228 hir::ItemKind::Fn(ref sig, ref generics, block) => item_fn(ItemFnParts {
60c5eb7d
XL
229 id: i.hir_id,
230 ident: i.ident,
231 decl: &sig.decl,
232 body: block,
233 vis: &i.vis,
234 span: i.span,
235 attrs: &i.attrs,
236 header: sig.header,
237 generics,
238 }),
54a0048b 239 _ => bug!("item FnLikeNode that is not fn-like"),
1a4d82fc 240 },
dfeec247
XL
241 Node::TraitItem(ti) => match ti.kind {
242 hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Provided(body)) => {
532ac7d7 243 method(ti.hir_id, ti.ident, sig, None, body, ti.span, &ti.attrs)
c34b1796 244 }
54a0048b 245 _ => bug!("trait method FnLikeNode that is not fn-like"),
1a4d82fc 246 },
dfeec247
XL
247 Node::ImplItem(ii) => match ii.kind {
248 hir::ImplItemKind::Method(ref sig, body) => {
60c5eb7d 249 method(ii.hir_id, ii.ident, sig, Some(&ii.vis), body, ii.span, &ii.attrs)
1a4d82fc 250 }
60c5eb7d 251 _ => bug!("impl method FnLikeNode that is not fn-like"),
476ff2be 252 },
dfeec247
XL
253 Node::Expr(e) => match e.kind {
254 hir::ExprKind::Closure(_, ref decl, block, _fn_decl_span, _gen) => {
60c5eb7d
XL
255 closure(ClosureParts::new(&decl, block, e.hir_id, e.span, &e.attrs))
256 }
54a0048b 257 _ => bug!("expr FnLikeNode that is not fn-like"),
1a4d82fc 258 },
54a0048b 259 _ => bug!("other FnLikeNode that is not fn-like"),
1a4d82fc
JJ
260 }
261 }
262}