]> git.proxmox.com Git - rustc.git/blame - src/librustc/hir/map/blocks.rs
New upstream version 1.31.0~beta.4+dfsg1
[rustc.git] / src / librustc / hir / map / blocks.rs
CommitLineData
1a4d82fc
JJ
1// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2// file at the top-level directory of this distribution and at
3// http://rust-lang.org/COPYRIGHT.
4//
5// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8// option. This file may not be copied, modified, or distributed
9// except according to those terms.
10
11//! This module provides a simplified abstraction for working with
12//! code blocks identified by their integer node-id. In particular,
13//! it captures a common set of attributes that all "function-like
14//! things" (represented by `FnLike` instances) share. For example,
15//! all `FnLike` instances have a type signature (be it explicit or
16//! inferred). And all `FnLike` instances have a body, i.e. the code
17//! that is run when the function-like thing it represents is invoked.
18//!
19//! With the above abstraction in place, one can treat the program
20//! text as a collection of blocks of code (and most such blocks are
21//! nested within a uniquely determined `FnLike`), and users can ask
22//! for the `Code` associated with a particular NodeId.
23
9e0c209e 24use hir as ast;
b7449926
XL
25use hir::map;
26use hir::{Expr, FnDecl, Node};
9e0c209e 27use hir::intravisit::FnKind;
8faf50e0 28use syntax::ast::{Attribute, Ident, Name, NodeId};
3157f602 29use syntax_pos::Span;
1a4d82fc
JJ
30
31/// An FnLikeNode is a Node that is like a fn, in that it has a decl
32/// and a body (as well as a NodeId, a span, etc).
33///
34/// More specifically, it is one of either:
ff7c6d11 35///
1a4d82fc 36/// - A function item,
8faf50e0 37/// - A closure expr (i.e. an ExprKind::Closure), or
1a4d82fc
JJ
38/// - The default implementation for a trait method.
39///
40/// To construct one, use the `Code::from_node` function.
32a655c1 41#[derive(Copy, Clone, Debug)]
b7449926 42pub struct FnLikeNode<'a> { node: Node<'a> }
1a4d82fc
JJ
43
44/// MaybeFnLike wraps a method that indicates if an object
45/// corresponds to some FnLikeNode.
46pub trait MaybeFnLike { fn is_fn_like(&self) -> bool; }
47
1a4d82fc
JJ
48impl MaybeFnLike for ast::Item {
49 fn is_fn_like(&self) -> bool {
8faf50e0
XL
50 match self.node { ast::ItemKind::Fn(..) => true, _ => false, }
51 }
52}
53
54impl MaybeFnLike for ast::ImplItem {
55 fn is_fn_like(&self) -> bool {
56 match self.node { ast::ImplItemKind::Method(..) => true, _ => false, }
1a4d82fc
JJ
57 }
58}
59
60impl MaybeFnLike for ast::TraitItem {
61 fn is_fn_like(&self) -> bool {
32a655c1
SL
62 match self.node {
63 ast::TraitItemKind::Method(_, ast::TraitMethod::Provided(_)) => true,
64 _ => false,
65 }
1a4d82fc
JJ
66 }
67}
68
69impl MaybeFnLike for ast::Expr {
70 fn is_fn_like(&self) -> bool {
71 match self.node {
8faf50e0 72 ast::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
SL
83 FnLike(FnLikeNode<'a>),
84 Expr(&'a Expr),
1a4d82fc
JJ
85}
86
87impl<'a> Code<'a> {
e9174d1e 88 pub fn id(&self) -> NodeId {
1a4d82fc 89 match *self {
476ff2be
SL
90 Code::FnLike(node) => node.id(),
91 Code::Expr(block) => block.id,
1a4d82fc
JJ
92 }
93 }
94
476ff2be
SL
95 /// Attempts to construct a Code from presumed FnLike or Expr node input.
96 pub fn from_node(map: &map::Map<'a>, id: NodeId) -> Option<Code<'a>> {
97 match map.get(id) {
b7449926 98 map::Node::Block(_) => {
476ff2be
SL
99 // Use the parent, hopefully an expression node.
100 Code::from_node(map, map.get_parent_node(id))
101 }
b7449926 102 map::Node::Expr(expr) => Some(Code::Expr(expr)),
476ff2be 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> {
b039eaaf 111 name: Name,
1a4d82fc 112 decl: &'a ast::FnDecl,
8faf50e0 113 header: ast::FnHeader,
54a0048b 114 vis: &'a ast::Visibility,
1a4d82fc 115 generics: &'a ast::Generics,
32a655c1 116 body: ast::BodyId,
e9174d1e 117 id: NodeId,
54a0048b
SL
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> {
125 decl: &'a FnDecl,
32a655c1 126 body: ast::BodyId,
1a4d82fc 127 id: NodeId,
54a0048b
SL
128 span: Span,
129 attrs: &'a [Attribute],
1a4d82fc
JJ
130}
131
132impl<'a> ClosureParts<'a> {
32a655c1 133 fn new(d: &'a FnDecl, b: ast::BodyId, id: NodeId, s: Span, attrs: &'a [Attribute]) -> Self {
a7813a04
XL
134 ClosureParts {
135 decl: d,
136 body: b,
041b39d2 137 id,
a7813a04 138 span: s,
041b39d2 139 attrs,
a7813a04 140 }
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 {
b7449926
XL
148 map::Node::Item(item) => item.is_fn_like(),
149 map::Node::TraitItem(tm) => tm.is_fn_like(),
150 map::Node::ImplItem(it) => it.is_fn_like(),
151 map::Node::Expr(e) => e.is_fn_like(),
62682a34
SL
152 _ => false
153 };
154 if fn_like {
155 Some(FnLikeNode {
041b39d2 156 node,
62682a34
SL
157 })
158 } else {
159 None
160 }
161 }
162
32a655c1 163 pub fn body(self) -> ast::BodyId {
b7449926
XL
164 self.handle(|i: ItemFnParts<'a>| i.body,
165 |_, _, _: &'a ast::MethodSig, _, body: ast::BodyId, _, _| body,
1a4d82fc
JJ
166 |c: ClosureParts<'a>| c.body)
167 }
168
169 pub fn decl(self) -> &'a FnDecl {
b7449926
XL
170 self.handle(|i: ItemFnParts<'a>| &*i.decl,
171 |_, _, sig: &'a ast::MethodSig, _, _, _, _| &sig.decl,
1a4d82fc
JJ
172 |c: ClosureParts<'a>| c.decl)
173 }
174
175 pub fn span(self) -> Span {
0bf4aa26 176 self.handle(|i: ItemFnParts<'_>| i.span,
54a0048b 177 |_, _, _: &'a ast::MethodSig, _, _, span, _| span,
0bf4aa26 178 |c: ClosureParts<'_>| c.span)
1a4d82fc
JJ
179 }
180
181 pub fn id(self) -> NodeId {
0bf4aa26 182 self.handle(|i: ItemFnParts<'_>| i.id,
54a0048b 183 |id, _, _: &'a ast::MethodSig, _, _, _, _| id,
0bf4aa26 184 |c: ClosureParts<'_>| c.id)
1a4d82fc
JJ
185 }
186
476ff2be
SL
187 pub fn constness(self) -> ast::Constness {
188 match self.kind() {
8faf50e0
XL
189 FnKind::ItemFn(_, _, header, ..) => header.constness,
190 FnKind::Method(_, m, ..) => m.header.constness,
476ff2be
SL
191 _ => ast::Constness::NotConst
192 }
193 }
194
8faf50e0
XL
195 pub fn asyncness(self) -> ast::IsAsync {
196 match self.kind() {
197 FnKind::ItemFn(_, _, header, ..) => header.asyncness,
198 FnKind::Method(_, m, ..) => m.header.asyncness,
199 _ => ast::IsAsync::NotAsync
200 }
201 }
202
3b2f2976
XL
203 pub fn unsafety(self) -> ast::Unsafety {
204 match self.kind() {
8faf50e0
XL
205 FnKind::ItemFn(_, _, header, ..) => header.unsafety,
206 FnKind::Method(_, m, ..) => m.header.unsafety,
3b2f2976
XL
207 _ => ast::Unsafety::Normal
208 }
209 }
210
e9174d1e
SL
211 pub fn kind(self) -> FnKind<'a> {
212 let item = |p: ItemFnParts<'a>| -> FnKind<'a> {
8faf50e0 213 FnKind::ItemFn(p.name, p.generics, p.header, p.vis, p.attrs)
1a4d82fc 214 };
54a0048b
SL
215 let closure = |c: ClosureParts<'a>| {
216 FnKind::Closure(c.attrs)
1a4d82fc 217 };
8faf50e0
XL
218 let method = |_, ident: Ident, sig: &'a ast::MethodSig, vis, _, _, attrs| {
219 FnKind::Method(ident, sig, vis, attrs)
1a4d82fc
JJ
220 };
221 self.handle(item, method, closure)
222 }
223
224 fn handle<A, I, M, C>(self, item_fn: I, method: M, closure: C) -> A where
225 I: FnOnce(ItemFnParts<'a>) -> A,
9346a6ac 226 M: FnOnce(NodeId,
8faf50e0 227 Ident,
9346a6ac 228 &'a ast::MethodSig,
54a0048b 229 Option<&'a ast::Visibility>,
32a655c1 230 ast::BodyId,
54a0048b
SL
231 Span,
232 &'a [Attribute])
9346a6ac 233 -> A,
1a4d82fc
JJ
234 C: FnOnce(ClosureParts<'a>) -> A,
235 {
236 match self.node {
b7449926 237 map::Node::Item(i) => match i.node {
8faf50e0 238 ast::ItemKind::Fn(ref decl, header, ref generics, block) =>
62682a34
SL
239 item_fn(ItemFnParts {
240 id: i.id,
b039eaaf 241 name: i.name,
7453a54e 242 decl: &decl,
476ff2be 243 body: block,
54a0048b 244 vis: &i.vis,
54a0048b
SL
245 span: i.span,
246 attrs: &i.attrs,
8faf50e0
XL
247 header,
248 generics,
1a4d82fc 249 }),
54a0048b 250 _ => bug!("item FnLikeNode that is not fn-like"),
1a4d82fc 251 },
b7449926 252 map::Node::TraitItem(ti) => match ti.node {
32a655c1 253 ast::TraitItemKind::Method(ref sig, ast::TraitMethod::Provided(body)) => {
8faf50e0 254 method(ti.id, ti.ident, sig, None, body, ti.span, &ti.attrs)
c34b1796 255 }
54a0048b 256 _ => bug!("trait method FnLikeNode that is not fn-like"),
1a4d82fc 257 },
b7449926 258 map::Node::ImplItem(ii) => {
c34b1796 259 match ii.node {
476ff2be 260 ast::ImplItemKind::Method(ref sig, body) => {
8faf50e0 261 method(ii.id, ii.ident, sig, Some(&ii.vis), body, ii.span, &ii.attrs)
c34b1796 262 }
b7449926 263 _ => bug!("impl method FnLikeNode that is not fn-like")
1a4d82fc 264 }
476ff2be 265 },
b7449926 266 map::Node::Expr(e) => match e.node {
8faf50e0 267 ast::ExprKind::Closure(_, ref decl, block, _fn_decl_span, _gen) =>
476ff2be 268 closure(ClosureParts::new(&decl, block, e.id, e.span, &e.attrs)),
54a0048b 269 _ => bug!("expr FnLikeNode that is not fn-like"),
1a4d82fc 270 },
54a0048b 271 _ => bug!("other FnLikeNode that is not fn-like"),
1a4d82fc
JJ
272 }
273 }
274}