]> git.proxmox.com Git - rustc.git/blame - src/librustc/front/map/blocks.rs
Imported Upstream version 1.8.0+dfsg1
[rustc.git] / src / librustc / front / 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
24pub use self::Code::*;
25
e9174d1e 26use front::map::{self, Node};
62682a34 27use syntax::abi;
e9174d1e 28use rustc_front::hir::{Block, FnDecl};
b039eaaf 29use syntax::ast::{Name, NodeId};
e9174d1e 30use rustc_front::hir as ast;
62682a34 31use syntax::codemap::Span;
92a42be0 32use rustc_front::intravisit::FnKind;
1a4d82fc
JJ
33
34/// An FnLikeNode is a Node that is like a fn, in that it has a decl
35/// and a body (as well as a NodeId, a span, etc).
36///
37/// More specifically, it is one of either:
38/// - A function item,
39/// - A closure expr (i.e. an ExprClosure), or
40/// - The default implementation for a trait method.
41///
42/// To construct one, use the `Code::from_node` function.
c34b1796 43#[derive(Copy, Clone)]
e9174d1e 44pub struct FnLikeNode<'a> { node: map::Node<'a> }
1a4d82fc
JJ
45
46/// MaybeFnLike wraps a method that indicates if an object
47/// corresponds to some FnLikeNode.
48pub trait MaybeFnLike { fn is_fn_like(&self) -> bool; }
49
50/// Components shared by fn-like things (fn items, methods, closures).
51pub struct FnParts<'a> {
52 pub decl: &'a FnDecl,
53 pub body: &'a Block,
e9174d1e 54 pub kind: FnKind<'a>,
1a4d82fc
JJ
55 pub span: Span,
56 pub id: NodeId,
57}
58
59impl MaybeFnLike for ast::Item {
60 fn is_fn_like(&self) -> bool {
61 match self.node { ast::ItemFn(..) => true, _ => false, }
62 }
63}
64
65impl MaybeFnLike for ast::TraitItem {
66 fn is_fn_like(&self) -> bool {
c34b1796 67 match self.node { ast::MethodTraitItem(_, Some(_)) => true, _ => false, }
1a4d82fc
JJ
68 }
69}
70
71impl MaybeFnLike for ast::Expr {
72 fn is_fn_like(&self) -> bool {
73 match self.node {
74 ast::ExprClosure(..) => true,
75 _ => false,
76 }
77 }
78}
79
80/// Carries either an FnLikeNode or a Block, as these are the two
81/// constructs that correspond to "code" (as in, something from which
82/// we can construct a control-flow graph).
c34b1796 83#[derive(Copy, Clone)]
1a4d82fc
JJ
84pub enum Code<'a> {
85 FnLikeCode(FnLikeNode<'a>),
86 BlockCode(&'a Block),
87}
88
89impl<'a> Code<'a> {
e9174d1e 90 pub fn id(&self) -> NodeId {
1a4d82fc
JJ
91 match *self {
92 FnLikeCode(node) => node.id(),
93 BlockCode(block) => block.id,
94 }
95 }
96
97 /// Attempts to construct a Code from presumed FnLike or Block node input.
98 pub fn from_node(node: Node) -> Option<Code> {
e9174d1e 99 if let map::NodeBlock(block) = node {
62682a34
SL
100 Some(BlockCode(block))
101 } else {
102 FnLikeNode::from_node(node).map(|fn_like| FnLikeCode(fn_like))
1a4d82fc
JJ
103 }
104 }
105}
106
107/// These are all the components one can extract from a fn item for
108/// use when implementing FnLikeNode operations.
109struct ItemFnParts<'a> {
b039eaaf 110 name: Name,
1a4d82fc
JJ
111 decl: &'a ast::FnDecl,
112 unsafety: ast::Unsafety,
62682a34 113 constness: ast::Constness,
1a4d82fc 114 abi: abi::Abi,
9346a6ac 115 vis: ast::Visibility,
1a4d82fc
JJ
116 generics: &'a ast::Generics,
117 body: &'a Block,
e9174d1e 118 id: NodeId,
1a4d82fc
JJ
119 span: Span
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,
126 body: &'a Block,
127 id: NodeId,
128 span: Span
129}
130
131impl<'a> ClosureParts<'a> {
132 fn new(d: &'a FnDecl, b: &'a Block, id: NodeId, s: Span) -> ClosureParts<'a> {
133 ClosureParts { decl: d, body: b, id: id, span: s }
134 }
135}
136
137impl<'a> FnLikeNode<'a> {
62682a34
SL
138 /// Attempts to construct a FnLikeNode from presumed FnLike node input.
139 pub fn from_node(node: Node) -> Option<FnLikeNode> {
140 let fn_like = match node {
e9174d1e
SL
141 map::NodeItem(item) => item.is_fn_like(),
142 map::NodeTraitItem(tm) => tm.is_fn_like(),
143 map::NodeImplItem(_) => true,
144 map::NodeExpr(e) => e.is_fn_like(),
62682a34
SL
145 _ => false
146 };
147 if fn_like {
148 Some(FnLikeNode {
149 node: node
150 })
151 } else {
152 None
153 }
154 }
155
1a4d82fc
JJ
156 pub fn to_fn_parts(self) -> FnParts<'a> {
157 FnParts {
158 decl: self.decl(),
159 body: self.body(),
160 kind: self.kind(),
161 span: self.span(),
162 id: self.id(),
163 }
164 }
165
166 pub fn body(self) -> &'a Block {
167 self.handle(|i: ItemFnParts<'a>| &*i.body,
9346a6ac 168 |_, _, _: &'a ast::MethodSig, _, body: &'a ast::Block, _| body,
1a4d82fc
JJ
169 |c: ClosureParts<'a>| c.body)
170 }
171
172 pub fn decl(self) -> &'a FnDecl {
173 self.handle(|i: ItemFnParts<'a>| &*i.decl,
9346a6ac 174 |_, _, sig: &'a ast::MethodSig, _, _, _| &sig.decl,
1a4d82fc
JJ
175 |c: ClosureParts<'a>| c.decl)
176 }
177
178 pub fn span(self) -> Span {
179 self.handle(|i: ItemFnParts| i.span,
9346a6ac 180 |_, _, _: &'a ast::MethodSig, _, _, span| span,
1a4d82fc
JJ
181 |c: ClosureParts| c.span)
182 }
183
184 pub fn id(self) -> NodeId {
185 self.handle(|i: ItemFnParts| i.id,
9346a6ac 186 |id, _, _: &'a ast::MethodSig, _, _, _| id,
1a4d82fc
JJ
187 |c: ClosureParts| c.id)
188 }
189
e9174d1e
SL
190 pub fn kind(self) -> FnKind<'a> {
191 let item = |p: ItemFnParts<'a>| -> FnKind<'a> {
b039eaaf 192 FnKind::ItemFn(p.name, p.generics, p.unsafety, p.constness, p.abi, p.vis)
1a4d82fc 193 };
85aaf69f 194 let closure = |_: ClosureParts| {
e9174d1e 195 FnKind::Closure
1a4d82fc 196 };
b039eaaf
SL
197 let method = |_, name: Name, sig: &'a ast::MethodSig, vis, _, _| {
198 FnKind::Method(name, sig, vis)
1a4d82fc
JJ
199 };
200 self.handle(item, method, closure)
201 }
202
203 fn handle<A, I, M, C>(self, item_fn: I, method: M, closure: C) -> A where
204 I: FnOnce(ItemFnParts<'a>) -> A,
9346a6ac 205 M: FnOnce(NodeId,
b039eaaf 206 Name,
9346a6ac
AL
207 &'a ast::MethodSig,
208 Option<ast::Visibility>,
209 &'a ast::Block,
210 Span)
211 -> A,
1a4d82fc
JJ
212 C: FnOnce(ClosureParts<'a>) -> A,
213 {
214 match self.node {
e9174d1e 215 map::NodeItem(i) => match i.node {
62682a34
SL
216 ast::ItemFn(ref decl, unsafety, constness, abi, ref generics, ref block) =>
217 item_fn(ItemFnParts {
218 id: i.id,
b039eaaf 219 name: i.name,
7453a54e 220 decl: &decl,
62682a34 221 unsafety: unsafety,
7453a54e 222 body: &block,
62682a34
SL
223 generics: generics,
224 abi: abi,
225 vis: i.vis,
226 constness: constness,
227 span: i.span
1a4d82fc
JJ
228 }),
229 _ => panic!("item FnLikeNode that is not fn-like"),
230 },
e9174d1e 231 map::NodeTraitItem(ti) => match ti.node {
c34b1796 232 ast::MethodTraitItem(ref sig, Some(ref body)) => {
b039eaaf 233 method(ti.id, ti.name, sig, None, body, ti.span)
c34b1796 234 }
1a4d82fc
JJ
235 _ => panic!("trait method FnLikeNode that is not fn-like"),
236 },
e9174d1e 237 map::NodeImplItem(ii) => {
c34b1796 238 match ii.node {
92a42be0 239 ast::ImplItemKind::Method(ref sig, ref body) => {
b039eaaf 240 method(ii.id, ii.name, sig, Some(ii.vis), body, ii.span)
c34b1796 241 }
d9579d0f 242 _ => {
1a4d82fc
JJ
243 panic!("impl method FnLikeNode that is not fn-like")
244 }
245 }
246 }
e9174d1e 247 map::NodeExpr(e) => match e.node {
85aaf69f 248 ast::ExprClosure(_, ref decl, ref block) =>
7453a54e 249 closure(ClosureParts::new(&decl, &block, e.id, e.span)),
1a4d82fc
JJ
250 _ => panic!("expr FnLikeNode that is not fn-like"),
251 },
252 _ => panic!("other FnLikeNode that is not fn-like"),
253 }
254 }
255}