1 // Copyright 2015 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.
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.
11 // Lowers the AST to the HIR.
13 // Since the AST and HIR are fairly similar, this is mostly a simple procedure,
14 // much like a fold. Where lowering involves a bit more work things get more
15 // interesting and there are some invariants you should know about. These mostly
16 // concern spans and ids.
18 // Spans are assigned to AST nodes during parsing and then are modified during
19 // expansion to indicate the origin of a node and the process it went through
20 // being expanded. Ids are assigned to AST nodes just before lowering.
22 // For the simpler lowering steps, ids and spans should be preserved. Unlike
23 // expansion we do not preserve the process of lowering in the spans, so spans
24 // should not be modified here. When creating a new node (as opposed to
25 // 'folding' an existing one), then you create a new id using `next_id()`.
27 // You must ensure that ids are unique. That means that you should only use the
28 // id from an AST node in a single HIR node (you can assume that AST node ids
29 // are unique). Every new node must have a unique id. Avoid cloning HIR nodes.
30 // If you do, you must then set the new node's id to a fresh one.
32 // Lowering must be reproducable (the compiler only lowers once, but tools and
33 // custom lints may lower an AST node to a HIR node to interact with the
34 // compiler). The most interesting bit of this is ids - if you lower an AST node
35 // and create new HIR nodes with fresh ids, when re-lowering the same node, you
36 // must ensure you get the same ids! To do this, we keep track of the next id
37 // when we translate a node which requires new ids. By checking this cache and
38 // using node ids starting with the cached id, we ensure ids are reproducible.
39 // To use this system, you just need to hold on to a CachedIdSetter object
40 // whilst lowering. This is an RAII object that takes care of setting and
41 // restoring the cached id, etc.
43 // This whole system relies on node ids being incremented one at a time and
44 // all increments being for lowering. This means that you should not call any
45 // non-lowering function which will use new node ids.
47 // We must also cache gensym'ed Idents to ensure that we get the same Ident
48 // every time we lower a node with gensym'ed names. One consequence of this is
49 // that you can only gensym a name once in a lowering (you don't need to worry
50 // about nested lowering though). That's because we cache based on the name and
51 // the currently cached node id, which is unique per lowered node.
53 // Spans are used for error messages and for tools to map semantics back to
54 // source code. It is therefore not as important with spans as ids to be strict
55 // about use (you can't break the compiler by screwing up a span). Obviously, a
56 // HIR node can only have a single span. But multiple nodes can have the same
57 // span and spans don't need to be kept in order, etc. Where code is preserved
58 // by lowering, it should have the same span as in the AST. Where HIR nodes are
59 // new it is probably best to give a span for the whole AST node being lowered.
60 // All nodes should have real spans, don't use dummy spans. Tools are likely to
61 // get confused if the spans from leaf AST nodes occur in multiple places
62 // in the HIR, especially for multiple identifiers.
66 use std::collections::BTreeMap;
67 use std::collections::HashMap;
69 use syntax::attr::{ThinAttributes, ThinAttributesExt};
70 use syntax::ext::mtwt;
72 use syntax::codemap::{respan, Spanned, Span};
73 use syntax::parse::token;
74 use syntax::std_inject;
75 use syntax::visit::{self, Visitor};
77 use std::cell::{Cell, RefCell};
79 pub struct LoweringContext<'a> {
80 crate_root: Option<&'static str>,
81 // Map AST ids to ids used for expanded nodes.
82 id_cache: RefCell<HashMap<NodeId, NodeId>>,
83 // Use if there are no cached ids for the current node.
84 id_assigner: &'a NodeIdAssigner,
85 // 0 == no cached id. Must be incremented to align with previous id
88 // Keep track of gensym'ed idents.
89 gensym_cache: RefCell<HashMap<(NodeId, &'static str), hir::Ident>>,
90 // A copy of cached_id, but is also set to an id while a node is lowered for
92 gensym_key: Cell<u32>,
95 impl<'a, 'hir> LoweringContext<'a> {
96 pub fn new(id_assigner: &'a NodeIdAssigner, c: Option<&Crate>) -> LoweringContext<'a> {
97 let crate_root = c.and_then(|c| {
98 if std_inject::no_core(c) {
100 } else if std_inject::no_std(c) {
108 crate_root: crate_root,
109 id_cache: RefCell::new(HashMap::new()),
110 id_assigner: id_assigner,
111 cached_id: Cell::new(0),
112 gensym_cache: RefCell::new(HashMap::new()),
113 gensym_key: Cell::new(0),
117 fn next_id(&self) -> NodeId {
118 let cached_id = self.cached_id.get();
120 return self.id_assigner.next_node_id();
123 self.cached_id.set(cached_id + 1);
127 fn str_to_ident(&self, s: &'static str) -> hir::Ident {
128 let gensym_key = self.gensym_key.get();
130 return hir::Ident::from_name(token::gensym(s));
133 let cached = self.gensym_cache.borrow().contains_key(&(gensym_key, s));
135 self.gensym_cache.borrow()[&(gensym_key, s)]
137 let result = hir::Ident::from_name(token::gensym(s));
138 self.gensym_cache.borrow_mut().insert((gensym_key, s), result);
144 // Utility fn for setting and unsetting the cached id.
145 fn cache_ids<'a, OP, R>(lctx: &LoweringContext, expr_id: NodeId, op: OP) -> R
146 where OP: FnOnce(&LoweringContext) -> R
148 // Only reset the id if it was previously 0, i.e., was not cached.
149 // If it was cached, we are in a nested node, but our id count will
150 // still count towards the parent's count.
151 let reset_cached_id = lctx.cached_id.get() == 0;
152 // We always reset gensym_key so that if we use the same name in a nested
153 // node and after that node, they get different values.
154 let old_gensym_key = lctx.gensym_key.get();
157 let id_cache: &mut HashMap<_, _> = &mut lctx.id_cache.borrow_mut();
159 if id_cache.contains_key(&expr_id) {
160 let cached_id = lctx.cached_id.get();
162 // We're entering a node where we need to track ids, but are not
164 lctx.cached_id.set(id_cache[&expr_id]);
166 // We're already tracking - check that the tracked id is the same
167 // as the expected id.
168 assert!(cached_id == id_cache[&expr_id], "id mismatch");
170 lctx.gensym_key.set(id_cache[&expr_id]);
172 // We've never lowered this node before, remember it for next time.
173 let next_id = lctx.id_assigner.peek_node_id();
174 id_cache.insert(expr_id, next_id);
175 lctx.gensym_key.set(next_id);
176 // self.cached_id is not set when we lower a node for the first time,
177 // only on re-lowering.
181 let result = op(lctx);
184 lctx.cached_id.set(0);
186 lctx.gensym_key.set(old_gensym_key);
191 pub fn lower_ident(_lctx: &LoweringContext, ident: Ident) -> hir::Ident {
193 name: mtwt::resolve(ident),
194 unhygienic_name: ident.name,
198 pub fn lower_attrs(_lctx: &LoweringContext, attrs: &Vec<Attribute>) -> hir::HirVec<Attribute> {
202 pub fn lower_view_path(lctx: &LoweringContext, view_path: &ViewPath) -> P<hir::ViewPath> {
204 node: match view_path.node {
205 ViewPathSimple(ident, ref path) => {
206 hir::ViewPathSimple(ident.name, lower_path(lctx, path))
208 ViewPathGlob(ref path) => {
209 hir::ViewPathGlob(lower_path(lctx, path))
211 ViewPathList(ref path, ref path_list_idents) => {
212 hir::ViewPathList(lower_path(lctx, path),
213 path_list_idents.iter()
214 .map(|path_list_ident| {
216 node: match path_list_ident.node {
217 PathListIdent { id, name, rename } =>
221 rename: rename.map(|x| x.name),
223 PathListMod { id, rename } =>
226 rename: rename.map(|x| x.name),
229 span: path_list_ident.span,
235 span: view_path.span,
239 pub fn lower_arm(lctx: &LoweringContext, arm: &Arm) -> hir::Arm {
241 attrs: lower_attrs(lctx, &arm.attrs),
242 pats: arm.pats.iter().map(|x| lower_pat(lctx, x)).collect(),
243 guard: arm.guard.as_ref().map(|ref x| lower_expr(lctx, x)),
244 body: lower_expr(lctx, &arm.body),
248 pub fn lower_decl(lctx: &LoweringContext, d: &Decl) -> P<hir::Decl> {
250 DeclLocal(ref l) => P(Spanned {
251 node: hir::DeclLocal(lower_local(lctx, l)),
254 DeclItem(ref it) => P(Spanned {
255 node: hir::DeclItem(lower_item_id(lctx, it)),
261 pub fn lower_ty_binding(lctx: &LoweringContext, b: &TypeBinding) -> hir::TypeBinding {
265 ty: lower_ty(lctx, &b.ty),
270 pub fn lower_ty(lctx: &LoweringContext, t: &Ty) -> P<hir::Ty> {
274 TyInfer => hir::TyInfer,
275 TyVec(ref ty) => hir::TyVec(lower_ty(lctx, ty)),
276 TyPtr(ref mt) => hir::TyPtr(lower_mt(lctx, mt)),
277 TyRptr(ref region, ref mt) => {
278 hir::TyRptr(lower_opt_lifetime(lctx, region), lower_mt(lctx, mt))
281 hir::TyBareFn(P(hir::BareFnTy {
282 lifetimes: lower_lifetime_defs(lctx, &f.lifetimes),
283 unsafety: lower_unsafety(lctx, f.unsafety),
285 decl: lower_fn_decl(lctx, &f.decl),
288 TyTup(ref tys) => hir::TyTup(tys.iter().map(|ty| lower_ty(lctx, ty)).collect()),
290 return lower_ty(lctx, ty);
292 TyPath(ref qself, ref path) => {
293 let qself = qself.as_ref().map(|&QSelf { ref ty, position }| {
295 ty: lower_ty(lctx, ty),
299 hir::TyPath(qself, lower_path(lctx, path))
301 TyObjectSum(ref ty, ref bounds) => {
302 hir::TyObjectSum(lower_ty(lctx, ty), lower_bounds(lctx, bounds))
304 TyFixedLengthVec(ref ty, ref e) => {
305 hir::TyFixedLengthVec(lower_ty(lctx, ty), lower_expr(lctx, e))
307 TyTypeof(ref expr) => {
308 hir::TyTypeof(lower_expr(lctx, expr))
310 TyPolyTraitRef(ref bounds) => {
311 hir::TyPolyTraitRef(bounds.iter().map(|b| lower_ty_param_bound(lctx, b)).collect())
313 TyMac(_) => panic!("TyMac should have been expanded by now."),
319 pub fn lower_foreign_mod(lctx: &LoweringContext, fm: &ForeignMod) -> hir::ForeignMod {
322 items: fm.items.iter().map(|x| lower_foreign_item(lctx, x)).collect(),
326 pub fn lower_variant(lctx: &LoweringContext, v: &Variant) -> hir::Variant {
328 node: hir::Variant_ {
329 name: v.node.name.name,
330 attrs: lower_attrs(lctx, &v.node.attrs),
331 data: lower_variant_data(lctx, &v.node.data),
332 disr_expr: v.node.disr_expr.as_ref().map(|e| lower_expr(lctx, e)),
338 // Path segments are usually unhygienic, hygienic path segments can occur only in
339 // identifier-like paths originating from `ExprPath`.
340 // Make life simpler for rustc_resolve by renaming only such segments.
341 pub fn lower_path_full(lctx: &LoweringContext, p: &Path, maybe_hygienic: bool) -> hir::Path {
342 let maybe_hygienic = maybe_hygienic && !p.global && p.segments.len() == 1;
347 .map(|&PathSegment { identifier, ref parameters }| {
349 identifier: if maybe_hygienic {
350 lower_ident(lctx, identifier)
352 hir::Ident::from_name(identifier.name)
354 parameters: lower_path_parameters(lctx, parameters),
362 pub fn lower_path(lctx: &LoweringContext, p: &Path) -> hir::Path {
363 lower_path_full(lctx, p, false)
366 pub fn lower_path_parameters(lctx: &LoweringContext,
367 path_parameters: &PathParameters)
368 -> hir::PathParameters {
369 match *path_parameters {
370 PathParameters::AngleBracketed(ref data) =>
371 hir::AngleBracketedParameters(lower_angle_bracketed_parameter_data(lctx, data)),
372 PathParameters::Parenthesized(ref data) =>
373 hir::ParenthesizedParameters(lower_parenthesized_parameter_data(lctx, data)),
377 pub fn lower_angle_bracketed_parameter_data(lctx: &LoweringContext,
378 data: &AngleBracketedParameterData)
379 -> hir::AngleBracketedParameterData {
380 let &AngleBracketedParameterData { ref lifetimes, ref types, ref bindings } = data;
381 hir::AngleBracketedParameterData {
382 lifetimes: lower_lifetimes(lctx, lifetimes),
383 types: types.iter().map(|ty| lower_ty(lctx, ty)).collect(),
384 bindings: bindings.iter().map(|b| lower_ty_binding(lctx, b)).collect(),
388 pub fn lower_parenthesized_parameter_data(lctx: &LoweringContext,
389 data: &ParenthesizedParameterData)
390 -> hir::ParenthesizedParameterData {
391 let &ParenthesizedParameterData { ref inputs, ref output, span } = data;
392 hir::ParenthesizedParameterData {
393 inputs: inputs.iter().map(|ty| lower_ty(lctx, ty)).collect(),
394 output: output.as_ref().map(|ty| lower_ty(lctx, ty)),
399 pub fn lower_local(lctx: &LoweringContext, l: &Local) -> P<hir::Local> {
402 ty: l.ty.as_ref().map(|t| lower_ty(lctx, t)),
403 pat: lower_pat(lctx, &l.pat),
404 init: l.init.as_ref().map(|e| lower_expr(lctx, e)),
406 attrs: l.attrs.clone(),
410 pub fn lower_explicit_self_underscore(lctx: &LoweringContext,
412 -> hir::ExplicitSelf_ {
414 SelfStatic => hir::SelfStatic,
415 SelfValue(v) => hir::SelfValue(v.name),
416 SelfRegion(ref lifetime, m, ident) => {
417 hir::SelfRegion(lower_opt_lifetime(lctx, lifetime),
418 lower_mutability(lctx, m),
421 SelfExplicit(ref typ, ident) => {
422 hir::SelfExplicit(lower_ty(lctx, typ), ident.name)
427 pub fn lower_mutability(_lctx: &LoweringContext, m: Mutability) -> hir::Mutability {
429 MutMutable => hir::MutMutable,
430 MutImmutable => hir::MutImmutable,
434 pub fn lower_explicit_self(lctx: &LoweringContext, s: &ExplicitSelf) -> hir::ExplicitSelf {
436 node: lower_explicit_self_underscore(lctx, &s.node),
441 pub fn lower_arg(lctx: &LoweringContext, arg: &Arg) -> hir::Arg {
444 pat: lower_pat(lctx, &arg.pat),
445 ty: lower_ty(lctx, &arg.ty),
449 pub fn lower_fn_decl(lctx: &LoweringContext, decl: &FnDecl) -> P<hir::FnDecl> {
451 inputs: decl.inputs.iter().map(|x| lower_arg(lctx, x)).collect(),
452 output: match decl.output {
453 Return(ref ty) => hir::Return(lower_ty(lctx, ty)),
454 DefaultReturn(span) => hir::DefaultReturn(span),
455 NoReturn(span) => hir::NoReturn(span),
457 variadic: decl.variadic,
461 pub fn lower_ty_param_bound(lctx: &LoweringContext, tpb: &TyParamBound) -> hir::TyParamBound {
463 TraitTyParamBound(ref ty, modifier) => {
464 hir::TraitTyParamBound(lower_poly_trait_ref(lctx, ty),
465 lower_trait_bound_modifier(lctx, modifier))
467 RegionTyParamBound(ref lifetime) => {
468 hir::RegionTyParamBound(lower_lifetime(lctx, lifetime))
473 pub fn lower_ty_param(lctx: &LoweringContext, tp: &TyParam) -> hir::TyParam {
477 bounds: lower_bounds(lctx, &tp.bounds),
478 default: tp.default.as_ref().map(|x| lower_ty(lctx, x)),
483 pub fn lower_ty_params(lctx: &LoweringContext,
485 -> hir::HirVec<hir::TyParam> {
486 tps.iter().map(|tp| lower_ty_param(lctx, tp)).collect()
489 pub fn lower_lifetime(_lctx: &LoweringContext, l: &Lifetime) -> hir::Lifetime {
497 pub fn lower_lifetime_def(lctx: &LoweringContext, l: &LifetimeDef) -> hir::LifetimeDef {
499 lifetime: lower_lifetime(lctx, &l.lifetime),
500 bounds: lower_lifetimes(lctx, &l.bounds),
504 pub fn lower_lifetimes(lctx: &LoweringContext, lts: &Vec<Lifetime>) -> hir::HirVec<hir::Lifetime> {
505 lts.iter().map(|l| lower_lifetime(lctx, l)).collect()
508 pub fn lower_lifetime_defs(lctx: &LoweringContext,
509 lts: &Vec<LifetimeDef>)
510 -> hir::HirVec<hir::LifetimeDef> {
511 lts.iter().map(|l| lower_lifetime_def(lctx, l)).collect()
514 pub fn lower_opt_lifetime(lctx: &LoweringContext,
515 o_lt: &Option<Lifetime>)
516 -> Option<hir::Lifetime> {
517 o_lt.as_ref().map(|lt| lower_lifetime(lctx, lt))
520 pub fn lower_generics(lctx: &LoweringContext, g: &Generics) -> hir::Generics {
522 ty_params: lower_ty_params(lctx, &g.ty_params),
523 lifetimes: lower_lifetime_defs(lctx, &g.lifetimes),
524 where_clause: lower_where_clause(lctx, &g.where_clause),
528 pub fn lower_where_clause(lctx: &LoweringContext, wc: &WhereClause) -> hir::WhereClause {
531 predicates: wc.predicates
533 .map(|predicate| lower_where_predicate(lctx, predicate))
538 pub fn lower_where_predicate(lctx: &LoweringContext,
539 pred: &WherePredicate)
540 -> hir::WherePredicate {
542 WherePredicate::BoundPredicate(WhereBoundPredicate{ ref bound_lifetimes,
546 hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate {
547 bound_lifetimes: lower_lifetime_defs(lctx, bound_lifetimes),
548 bounded_ty: lower_ty(lctx, bounded_ty),
549 bounds: bounds.iter().map(|x| lower_ty_param_bound(lctx, x)).collect(),
553 WherePredicate::RegionPredicate(WhereRegionPredicate{ ref lifetime,
556 hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate {
558 lifetime: lower_lifetime(lctx, lifetime),
559 bounds: bounds.iter().map(|bound| lower_lifetime(lctx, bound)).collect(),
562 WherePredicate::EqPredicate(WhereEqPredicate{ id,
566 hir::WherePredicate::EqPredicate(hir::WhereEqPredicate {
568 path: lower_path(lctx, path),
569 ty: lower_ty(lctx, ty),
576 pub fn lower_variant_data(lctx: &LoweringContext, vdata: &VariantData) -> hir::VariantData {
578 VariantData::Struct(ref fields, id) => {
579 hir::VariantData::Struct(fields.iter()
580 .map(|f| lower_struct_field(lctx, f))
584 VariantData::Tuple(ref fields, id) => {
585 hir::VariantData::Tuple(fields.iter()
586 .map(|f| lower_struct_field(lctx, f))
590 VariantData::Unit(id) => hir::VariantData::Unit(id),
594 pub fn lower_trait_ref(lctx: &LoweringContext, p: &TraitRef) -> hir::TraitRef {
596 path: lower_path(lctx, &p.path),
601 pub fn lower_poly_trait_ref(lctx: &LoweringContext, p: &PolyTraitRef) -> hir::PolyTraitRef {
603 bound_lifetimes: lower_lifetime_defs(lctx, &p.bound_lifetimes),
604 trait_ref: lower_trait_ref(lctx, &p.trait_ref),
609 pub fn lower_struct_field(lctx: &LoweringContext, f: &StructField) -> hir::StructField {
611 node: hir::StructField_ {
613 kind: lower_struct_field_kind(lctx, &f.node.kind),
614 ty: lower_ty(lctx, &f.node.ty),
615 attrs: lower_attrs(lctx, &f.node.attrs),
621 pub fn lower_field(lctx: &LoweringContext, f: &Field) -> hir::Field {
623 name: respan(f.ident.span, f.ident.node.name),
624 expr: lower_expr(lctx, &f.expr),
629 pub fn lower_mt(lctx: &LoweringContext, mt: &MutTy) -> hir::MutTy {
631 ty: lower_ty(lctx, &mt.ty),
632 mutbl: lower_mutability(lctx, mt.mutbl),
636 pub fn lower_opt_bounds(lctx: &LoweringContext,
637 b: &Option<TyParamBounds>)
638 -> Option<hir::TyParamBounds> {
639 b.as_ref().map(|ref bounds| lower_bounds(lctx, bounds))
642 fn lower_bounds(lctx: &LoweringContext, bounds: &TyParamBounds) -> hir::TyParamBounds {
643 bounds.iter().map(|bound| lower_ty_param_bound(lctx, bound)).collect()
646 pub fn lower_block(lctx: &LoweringContext, b: &Block) -> P<hir::Block> {
649 stmts: b.stmts.iter().map(|s| lower_stmt(lctx, s)).collect(),
650 expr: b.expr.as_ref().map(|ref x| lower_expr(lctx, x)),
651 rules: lower_block_check_mode(lctx, &b.rules),
656 pub fn lower_item_underscore(lctx: &LoweringContext, i: &Item_) -> hir::Item_ {
658 ItemExternCrate(string) => hir::ItemExternCrate(string),
659 ItemUse(ref view_path) => {
660 hir::ItemUse(lower_view_path(lctx, view_path))
662 ItemStatic(ref t, m, ref e) => {
663 hir::ItemStatic(lower_ty(lctx, t),
664 lower_mutability(lctx, m),
667 ItemConst(ref t, ref e) => {
668 hir::ItemConst(lower_ty(lctx, t), lower_expr(lctx, e))
670 ItemFn(ref decl, unsafety, constness, abi, ref generics, ref body) => {
671 hir::ItemFn(lower_fn_decl(lctx, decl),
672 lower_unsafety(lctx, unsafety),
673 lower_constness(lctx, constness),
675 lower_generics(lctx, generics),
676 lower_block(lctx, body))
678 ItemMod(ref m) => hir::ItemMod(lower_mod(lctx, m)),
679 ItemForeignMod(ref nm) => hir::ItemForeignMod(lower_foreign_mod(lctx, nm)),
680 ItemTy(ref t, ref generics) => {
681 hir::ItemTy(lower_ty(lctx, t), lower_generics(lctx, generics))
683 ItemEnum(ref enum_definition, ref generics) => {
684 hir::ItemEnum(hir::EnumDef {
685 variants: enum_definition.variants
687 .map(|x| lower_variant(lctx, x))
690 lower_generics(lctx, generics))
692 ItemStruct(ref struct_def, ref generics) => {
693 let struct_def = lower_variant_data(lctx, struct_def);
694 hir::ItemStruct(struct_def, lower_generics(lctx, generics))
696 ItemDefaultImpl(unsafety, ref trait_ref) => {
697 hir::ItemDefaultImpl(lower_unsafety(lctx, unsafety),
698 lower_trait_ref(lctx, trait_ref))
700 ItemImpl(unsafety, polarity, ref generics, ref ifce, ref ty, ref impl_items) => {
701 let new_impl_items = impl_items.iter()
702 .map(|item| lower_impl_item(lctx, item))
704 let ifce = ifce.as_ref().map(|trait_ref| lower_trait_ref(lctx, trait_ref));
705 hir::ItemImpl(lower_unsafety(lctx, unsafety),
706 lower_impl_polarity(lctx, polarity),
707 lower_generics(lctx, generics),
712 ItemTrait(unsafety, ref generics, ref bounds, ref items) => {
713 let bounds = lower_bounds(lctx, bounds);
714 let items = items.iter().map(|item| lower_trait_item(lctx, item)).collect();
715 hir::ItemTrait(lower_unsafety(lctx, unsafety),
716 lower_generics(lctx, generics),
720 ItemMac(_) => panic!("Shouldn't still be around"),
724 pub fn lower_trait_item(lctx: &LoweringContext, i: &TraitItem) -> hir::TraitItem {
728 attrs: lower_attrs(lctx, &i.attrs),
730 ConstTraitItem(ref ty, ref default) => {
731 hir::ConstTraitItem(lower_ty(lctx, ty),
732 default.as_ref().map(|x| lower_expr(lctx, x)))
734 MethodTraitItem(ref sig, ref body) => {
735 hir::MethodTraitItem(lower_method_sig(lctx, sig),
736 body.as_ref().map(|x| lower_block(lctx, x)))
738 TypeTraitItem(ref bounds, ref default) => {
739 hir::TypeTraitItem(lower_bounds(lctx, bounds),
740 default.as_ref().map(|x| lower_ty(lctx, x)))
747 pub fn lower_impl_item(lctx: &LoweringContext, i: &ImplItem) -> hir::ImplItem {
751 attrs: lower_attrs(lctx, &i.attrs),
752 vis: lower_visibility(lctx, i.vis),
754 ImplItemKind::Const(ref ty, ref expr) => {
755 hir::ImplItemKind::Const(lower_ty(lctx, ty), lower_expr(lctx, expr))
757 ImplItemKind::Method(ref sig, ref body) => {
758 hir::ImplItemKind::Method(lower_method_sig(lctx, sig), lower_block(lctx, body))
760 ImplItemKind::Type(ref ty) => hir::ImplItemKind::Type(lower_ty(lctx, ty)),
761 ImplItemKind::Macro(..) => panic!("Shouldn't exist any more"),
767 pub fn lower_mod(lctx: &LoweringContext, m: &Mod) -> hir::Mod {
770 item_ids: m.items.iter().map(|x| lower_item_id(lctx, x)).collect(),
774 struct ItemLowerer<'lcx, 'interner: 'lcx> {
775 items: BTreeMap<NodeId, hir::Item>,
776 lctx: &'lcx LoweringContext<'interner>,
779 impl<'lcx, 'interner> Visitor<'lcx> for ItemLowerer<'lcx, 'interner> {
780 fn visit_item(&mut self, item: &'lcx Item) {
781 self.items.insert(item.id, lower_item(self.lctx, item));
782 visit::walk_item(self, item);
786 pub fn lower_crate(lctx: &LoweringContext, c: &Crate) -> hir::Crate {
788 let mut item_lowerer = ItemLowerer { items: BTreeMap::new(), lctx: lctx };
789 visit::walk_crate(&mut item_lowerer, c);
794 module: lower_mod(lctx, &c.module),
795 attrs: lower_attrs(lctx, &c.attrs),
796 config: c.config.clone().into(),
798 exported_macros: c.exported_macros.iter().map(|m| lower_macro_def(lctx, m)).collect(),
803 pub fn lower_macro_def(lctx: &LoweringContext, m: &MacroDef) -> hir::MacroDef {
806 attrs: lower_attrs(lctx, &m.attrs),
809 imported_from: m.imported_from.map(|x| x.name),
811 use_locally: m.use_locally,
812 allow_internal_unstable: m.allow_internal_unstable,
813 body: m.body.clone().into(),
817 pub fn lower_item_id(_lctx: &LoweringContext, i: &Item) -> hir::ItemId {
818 hir::ItemId { id: i.id }
821 pub fn lower_item(lctx: &LoweringContext, i: &Item) -> hir::Item {
822 let node = lower_item_underscore(lctx, &i.node);
827 attrs: lower_attrs(lctx, &i.attrs),
829 vis: lower_visibility(lctx, i.vis),
834 pub fn lower_foreign_item(lctx: &LoweringContext, i: &ForeignItem) -> hir::ForeignItem {
838 attrs: lower_attrs(lctx, &i.attrs),
840 ForeignItemFn(ref fdec, ref generics) => {
841 hir::ForeignItemFn(lower_fn_decl(lctx, fdec), lower_generics(lctx, generics))
843 ForeignItemStatic(ref t, m) => {
844 hir::ForeignItemStatic(lower_ty(lctx, t), m)
847 vis: lower_visibility(lctx, i.vis),
852 pub fn lower_method_sig(lctx: &LoweringContext, sig: &MethodSig) -> hir::MethodSig {
854 generics: lower_generics(lctx, &sig.generics),
856 explicit_self: lower_explicit_self(lctx, &sig.explicit_self),
857 unsafety: lower_unsafety(lctx, sig.unsafety),
858 constness: lower_constness(lctx, sig.constness),
859 decl: lower_fn_decl(lctx, &sig.decl),
863 pub fn lower_unsafety(_lctx: &LoweringContext, u: Unsafety) -> hir::Unsafety {
865 Unsafety::Unsafe => hir::Unsafety::Unsafe,
866 Unsafety::Normal => hir::Unsafety::Normal,
870 pub fn lower_constness(_lctx: &LoweringContext, c: Constness) -> hir::Constness {
872 Constness::Const => hir::Constness::Const,
873 Constness::NotConst => hir::Constness::NotConst,
877 pub fn lower_unop(_lctx: &LoweringContext, u: UnOp) -> hir::UnOp {
879 UnDeref => hir::UnDeref,
885 pub fn lower_binop(_lctx: &LoweringContext, b: BinOp) -> hir::BinOp {
895 BiBitXor => hir::BiBitXor,
896 BiBitAnd => hir::BiBitAnd,
897 BiBitOr => hir::BiBitOr,
911 pub fn lower_pat(lctx: &LoweringContext, p: &Pat) -> P<hir::Pat> {
915 PatWild => hir::PatWild,
916 PatIdent(ref binding_mode, pth1, ref sub) => {
917 hir::PatIdent(lower_binding_mode(lctx, binding_mode),
918 respan(pth1.span, lower_ident(lctx, pth1.node)),
919 sub.as_ref().map(|x| lower_pat(lctx, x)))
921 PatLit(ref e) => hir::PatLit(lower_expr(lctx, e)),
922 PatEnum(ref pth, ref pats) => {
923 hir::PatEnum(lower_path(lctx, pth),
925 .map(|pats| pats.iter().map(|x| lower_pat(lctx, x)).collect()))
927 PatQPath(ref qself, ref pth) => {
928 let qself = hir::QSelf {
929 ty: lower_ty(lctx, &qself.ty),
930 position: qself.position,
932 hir::PatQPath(qself, lower_path(lctx, pth))
934 PatStruct(ref pth, ref fields, etc) => {
935 let pth = lower_path(lctx, pth);
936 let fs = fields.iter()
940 node: hir::FieldPat {
941 name: f.node.ident.name,
942 pat: lower_pat(lctx, &f.node.pat),
943 is_shorthand: f.node.is_shorthand,
948 hir::PatStruct(pth, fs, etc)
950 PatTup(ref elts) => hir::PatTup(elts.iter().map(|x| lower_pat(lctx, x)).collect()),
951 PatBox(ref inner) => hir::PatBox(lower_pat(lctx, inner)),
952 PatRegion(ref inner, mutbl) => {
953 hir::PatRegion(lower_pat(lctx, inner), lower_mutability(lctx, mutbl))
955 PatRange(ref e1, ref e2) => {
956 hir::PatRange(lower_expr(lctx, e1), lower_expr(lctx, e2))
958 PatVec(ref before, ref slice, ref after) => {
959 hir::PatVec(before.iter().map(|x| lower_pat(lctx, x)).collect(),
960 slice.as_ref().map(|x| lower_pat(lctx, x)),
961 after.iter().map(|x| lower_pat(lctx, x)).collect())
963 PatMac(_) => panic!("Shouldn't exist here"),
969 pub fn lower_expr(lctx: &LoweringContext, e: &Expr) -> P<hir::Expr> {
974 // Eventually a desugaring for `box EXPR`
975 // (similar to the desugaring above for `in PLACE BLOCK`)
976 // should go here, desugaring
980 // let mut place = BoxPlace::make_place();
981 // let raw_place = Place::pointer(&mut place);
982 // let value = $value;
984 // ::std::ptr::write(raw_place, value);
985 // Boxed::finalize(place)
988 // But for now there are type-inference issues doing that.
990 hir::ExprBox(lower_expr(lctx, e))
993 // Desugar ExprBox: `in (PLACE) EXPR`
994 ExprInPlace(ref placer, ref value_expr) => {
998 // let mut place = Placer::make_place(p);
999 // let raw_place = Place::pointer(&mut place);
1001 // std::intrinsics::move_val_init(raw_place, pop_unsafe!( EXPR ));
1002 // InPlace::finalize(place)
1004 return cache_ids(lctx, e.id, |lctx| {
1005 let placer_expr = lower_expr(lctx, placer);
1006 let value_expr = lower_expr(lctx, value_expr);
1008 let placer_ident = lctx.str_to_ident("placer");
1009 let place_ident = lctx.str_to_ident("place");
1010 let p_ptr_ident = lctx.str_to_ident("p_ptr");
1012 let make_place = ["ops", "Placer", "make_place"];
1013 let place_pointer = ["ops", "Place", "pointer"];
1014 let move_val_init = ["intrinsics", "move_val_init"];
1015 let inplace_finalize = ["ops", "InPlace", "finalize"];
1017 let make_call = |lctx: &LoweringContext, p, args| {
1018 let path = core_path(lctx, e.span, p);
1019 let path = expr_path(lctx, path, None);
1020 expr_call(lctx, e.span, path, args, None)
1023 let mk_stmt_let = |lctx: &LoweringContext, bind, expr| {
1024 stmt_let(lctx, e.span, false, bind, expr, None)
1027 let mk_stmt_let_mut = |lctx: &LoweringContext, bind, expr| {
1028 stmt_let(lctx, e.span, true, bind, expr, None)
1031 // let placer = <placer_expr> ;
1033 let placer_expr = signal_block_expr(lctx,
1037 hir::PopUnstableBlock,
1039 mk_stmt_let(lctx, placer_ident, placer_expr)
1042 // let mut place = Placer::make_place(placer);
1044 let placer = expr_ident(lctx, e.span, placer_ident, None);
1045 let call = make_call(lctx, &make_place, hir_vec![placer]);
1046 mk_stmt_let_mut(lctx, place_ident, call)
1049 // let p_ptr = Place::pointer(&mut place);
1051 let agent = expr_ident(lctx, e.span, place_ident, None);
1052 let args = hir_vec![expr_mut_addr_of(lctx, e.span, agent, None)];
1053 let call = make_call(lctx, &place_pointer, args);
1054 mk_stmt_let(lctx, p_ptr_ident, call)
1057 // pop_unsafe!(EXPR));
1058 let pop_unsafe_expr = {
1059 let value_expr = signal_block_expr(lctx,
1063 hir::PopUnstableBlock,
1065 signal_block_expr(lctx,
1069 hir::PopUnsafeBlock(hir::CompilerGenerated), None)
1073 // std::intrinsics::move_val_init(raw_place, pop_unsafe!( EXPR ));
1074 // InPlace::finalize(place)
1077 let ptr = expr_ident(lctx, e.span, p_ptr_ident, None);
1078 let call_move_val_init =
1080 make_call(lctx, &move_val_init, hir_vec![ptr, pop_unsafe_expr]),
1082 let call_move_val_init = respan(e.span, call_move_val_init);
1084 let place = expr_ident(lctx, e.span, place_ident, None);
1085 let call = make_call(lctx, &inplace_finalize, hir_vec![place]);
1086 signal_block_expr(lctx,
1087 hir_vec![call_move_val_init],
1090 hir::PushUnsafeBlock(hir::CompilerGenerated), None)
1093 signal_block_expr(lctx,
1094 hir_vec![s1, s2, s3],
1097 hir::PushUnstableBlock,
1102 ExprVec(ref exprs) => {
1103 hir::ExprVec(exprs.iter().map(|x| lower_expr(lctx, x)).collect())
1105 ExprRepeat(ref expr, ref count) => {
1106 let expr = lower_expr(lctx, expr);
1107 let count = lower_expr(lctx, count);
1108 hir::ExprRepeat(expr, count)
1110 ExprTup(ref elts) => {
1111 hir::ExprTup(elts.iter().map(|x| lower_expr(lctx, x)).collect())
1113 ExprCall(ref f, ref args) => {
1114 let f = lower_expr(lctx, f);
1115 hir::ExprCall(f, args.iter().map(|x| lower_expr(lctx, x)).collect())
1117 ExprMethodCall(i, ref tps, ref args) => {
1118 let tps = tps.iter().map(|x| lower_ty(lctx, x)).collect();
1119 let args = args.iter().map(|x| lower_expr(lctx, x)).collect();
1120 hir::ExprMethodCall(respan(i.span, i.node.name), tps, args)
1122 ExprBinary(binop, ref lhs, ref rhs) => {
1123 let binop = lower_binop(lctx, binop);
1124 let lhs = lower_expr(lctx, lhs);
1125 let rhs = lower_expr(lctx, rhs);
1126 hir::ExprBinary(binop, lhs, rhs)
1128 ExprUnary(op, ref ohs) => {
1129 let op = lower_unop(lctx, op);
1130 let ohs = lower_expr(lctx, ohs);
1131 hir::ExprUnary(op, ohs)
1133 ExprLit(ref l) => hir::ExprLit(P((**l).clone())),
1134 ExprCast(ref expr, ref ty) => {
1135 let expr = lower_expr(lctx, expr);
1136 hir::ExprCast(expr, lower_ty(lctx, ty))
1138 ExprType(ref expr, ref ty) => {
1139 let expr = lower_expr(lctx, expr);
1140 hir::ExprType(expr, lower_ty(lctx, ty))
1142 ExprAddrOf(m, ref ohs) => {
1143 let m = lower_mutability(lctx, m);
1144 let ohs = lower_expr(lctx, ohs);
1145 hir::ExprAddrOf(m, ohs)
1147 // More complicated than you might expect because the else branch
1148 // might be `if let`.
1149 ExprIf(ref cond, ref blk, ref else_opt) => {
1150 let else_opt = else_opt.as_ref().map(|els| {
1153 cache_ids(lctx, e.id, |lctx| {
1154 // wrap the if-let expr in a block
1155 let span = els.span;
1156 let els = lower_expr(lctx, els);
1157 let id = lctx.next_id();
1158 let blk = P(hir::Block {
1162 rules: hir::DefaultBlock,
1165 expr_block(lctx, blk, None)
1168 _ => lower_expr(lctx, els),
1172 hir::ExprIf(lower_expr(lctx, cond), lower_block(lctx, blk), else_opt)
1174 ExprWhile(ref cond, ref body, opt_ident) => {
1175 hir::ExprWhile(lower_expr(lctx, cond), lower_block(lctx, body),
1176 opt_ident.map(|ident| lower_ident(lctx, ident)))
1178 ExprLoop(ref body, opt_ident) => {
1179 hir::ExprLoop(lower_block(lctx, body),
1180 opt_ident.map(|ident| lower_ident(lctx, ident)))
1182 ExprMatch(ref expr, ref arms) => {
1183 hir::ExprMatch(lower_expr(lctx, expr),
1184 arms.iter().map(|x| lower_arm(lctx, x)).collect(),
1185 hir::MatchSource::Normal)
1187 ExprClosure(capture_clause, ref decl, ref body) => {
1188 hir::ExprClosure(lower_capture_clause(lctx, capture_clause),
1189 lower_fn_decl(lctx, decl),
1190 lower_block(lctx, body))
1192 ExprBlock(ref blk) => hir::ExprBlock(lower_block(lctx, blk)),
1193 ExprAssign(ref el, ref er) => {
1194 hir::ExprAssign(lower_expr(lctx, el), lower_expr(lctx, er))
1196 ExprAssignOp(op, ref el, ref er) => {
1197 hir::ExprAssignOp(lower_binop(lctx, op),
1198 lower_expr(lctx, el),
1199 lower_expr(lctx, er))
1201 ExprField(ref el, ident) => {
1202 hir::ExprField(lower_expr(lctx, el), respan(ident.span, ident.node.name))
1204 ExprTupField(ref el, ident) => {
1205 hir::ExprTupField(lower_expr(lctx, el), ident)
1207 ExprIndex(ref el, ref er) => {
1208 hir::ExprIndex(lower_expr(lctx, el), lower_expr(lctx, er))
1210 ExprRange(ref e1, ref e2) => {
1211 hir::ExprRange(e1.as_ref().map(|x| lower_expr(lctx, x)),
1212 e2.as_ref().map(|x| lower_expr(lctx, x)))
1214 ExprPath(ref qself, ref path) => {
1215 let hir_qself = qself.as_ref().map(|&QSelf { ref ty, position }| {
1217 ty: lower_ty(lctx, ty),
1221 hir::ExprPath(hir_qself, lower_path_full(lctx, path, qself.is_none()))
1223 ExprBreak(opt_ident) => hir::ExprBreak(opt_ident.map(|sp_ident| {
1224 respan(sp_ident.span, lower_ident(lctx, sp_ident.node))
1226 ExprAgain(opt_ident) => hir::ExprAgain(opt_ident.map(|sp_ident| {
1227 respan(sp_ident.span, lower_ident(lctx, sp_ident.node))
1229 ExprRet(ref e) => hir::ExprRet(e.as_ref().map(|x| lower_expr(lctx, x))),
1230 ExprInlineAsm(InlineAsm {
1240 }) => hir::ExprInlineAsm(hir::InlineAsm {
1241 inputs: inputs.iter()
1242 .map(|&(ref c, ref input)| (c.clone(), lower_expr(lctx, input)))
1244 outputs: outputs.iter()
1246 hir::InlineAsmOutput {
1247 constraint: out.constraint.clone(),
1248 expr: lower_expr(lctx, &out.expr),
1250 is_indirect: out.is_indirect,
1255 asm_str_style: asm_str_style,
1256 clobbers: clobbers.clone().into(),
1258 alignstack: alignstack,
1262 ExprStruct(ref path, ref fields, ref maybe_expr) => {
1263 hir::ExprStruct(lower_path(lctx, path),
1264 fields.iter().map(|x| lower_field(lctx, x)).collect(),
1265 maybe_expr.as_ref().map(|x| lower_expr(lctx, x)))
1267 ExprParen(ref ex) => {
1268 // merge attributes into the inner expression.
1269 return lower_expr(lctx, ex).map(|mut ex| {
1270 ex.attrs.update(|attrs| {
1271 attrs.prepend(e.attrs.clone())
1277 // Desugar ExprIfLet
1278 // From: `if let <pat> = <sub_expr> <body> [<else_opt>]`
1279 ExprIfLet(ref pat, ref sub_expr, ref body, ref else_opt) => {
1282 // match <sub_expr> {
1284 // [_ if <else_opt_if_cond> => <else_opt_if_body>,]
1285 // _ => [<else_opt> | ()]
1288 return cache_ids(lctx, e.id, |lctx| {
1289 // `<pat> => <body>`
1291 let body = lower_block(lctx, body);
1292 let body_expr = expr_block(lctx, body, None);
1293 arm(hir_vec![lower_pat(lctx, pat)], body_expr)
1296 // `[_ if <else_opt_if_cond> => <else_opt_if_body>,]`
1297 let mut else_opt = else_opt.as_ref().map(|e| lower_expr(lctx, e));
1298 let else_if_arms = {
1299 let mut arms = vec![];
1301 let else_opt_continue = else_opt.and_then(|els| {
1302 els.and_then(|els| {
1305 hir::ExprIf(cond, then, else_opt) => {
1306 let pat_under = pat_wild(lctx, e.span);
1307 arms.push(hir::Arm {
1309 pats: hir_vec![pat_under],
1311 body: expr_block(lctx, then, None),
1313 else_opt.map(|else_opt| (else_opt, true))
1315 _ => Some((P(els), false)),
1319 match else_opt_continue {
1320 Some((e, true)) => {
1323 Some((e, false)) => {
1336 let contains_else_clause = else_opt.is_some();
1338 // `_ => [<else_opt> | ()]`
1340 let pat_under = pat_wild(lctx, e.span);
1342 else_opt.unwrap_or_else(
1343 || expr_tuple(lctx, e.span, hir_vec![], None));
1344 arm(hir_vec![pat_under], else_expr)
1347 let mut arms = Vec::with_capacity(else_if_arms.len() + 2);
1349 arms.extend(else_if_arms);
1350 arms.push(else_arm);
1352 let sub_expr = lower_expr(lctx, sub_expr);
1353 // add attributes to the outer returned expr node
1356 hir::ExprMatch(sub_expr,
1358 hir::MatchSource::IfLetDesugar {
1359 contains_else_clause: contains_else_clause,
1365 // Desugar ExprWhileLet
1366 // From: `[opt_ident]: while let <pat> = <sub_expr> <body>`
1367 ExprWhileLet(ref pat, ref sub_expr, ref body, opt_ident) => {
1370 // [opt_ident]: loop {
1371 // match <sub_expr> {
1377 return cache_ids(lctx, e.id, |lctx| {
1378 // `<pat> => <body>`
1380 let body = lower_block(lctx, body);
1381 let body_expr = expr_block(lctx, body, None);
1382 arm(hir_vec![lower_pat(lctx, pat)], body_expr)
1387 let pat_under = pat_wild(lctx, e.span);
1388 let break_expr = expr_break(lctx, e.span, None);
1389 arm(hir_vec![pat_under], break_expr)
1392 // `match <sub_expr> { ... }`
1393 let arms = hir_vec![pat_arm, break_arm];
1394 let sub_expr = lower_expr(lctx, sub_expr);
1395 let match_expr = expr(lctx,
1397 hir::ExprMatch(sub_expr,
1399 hir::MatchSource::WhileLetDesugar),
1402 // `[opt_ident]: loop { ... }`
1403 let loop_block = block_expr(lctx, match_expr);
1404 let loop_expr = hir::ExprLoop(loop_block,
1405 opt_ident.map(|ident| lower_ident(lctx, ident)));
1406 // add attributes to the outer returned expr node
1407 expr(lctx, e.span, loop_expr, e.attrs.clone())
1411 // Desugar ExprForLoop
1412 // From: `[opt_ident]: for <pat> in <head> <body>`
1413 ExprForLoop(ref pat, ref head, ref body, opt_ident) => {
1417 // let result = match ::std::iter::IntoIterator::into_iter(<head>) {
1419 // [opt_ident]: loop {
1420 // match ::std::iter::Iterator::next(&mut iter) {
1421 // ::std::option::Option::Some(<pat>) => <body>,
1422 // ::std::option::Option::None => break
1430 return cache_ids(lctx, e.id, |lctx| {
1432 let head = lower_expr(lctx, head);
1434 let iter = lctx.str_to_ident("iter");
1436 // `::std::option::Option::Some(<pat>) => <body>`
1438 let body_block = lower_block(lctx, body);
1439 let body_span = body_block.span;
1440 let body_expr = P(hir::Expr {
1442 node: hir::ExprBlock(body_block),
1446 let pat = lower_pat(lctx, pat);
1447 let some_pat = pat_some(lctx, e.span, pat);
1449 arm(hir_vec![some_pat], body_expr)
1452 // `::std::option::Option::None => break`
1454 let break_expr = expr_break(lctx, e.span, None);
1456 arm(hir_vec![pat_none(lctx, e.span)], break_expr)
1459 // `match ::std::iter::Iterator::next(&mut iter) { ... }`
1462 let strs = std_path(lctx, &["iter", "Iterator", "next"]);
1464 path_global(e.span, strs)
1466 let iter = expr_ident(lctx, e.span, iter, None);
1467 let ref_mut_iter = expr_mut_addr_of(lctx, e.span, iter, None);
1468 let next_path = expr_path(lctx, next_path, None);
1469 let next_expr = expr_call(lctx,
1472 hir_vec![ref_mut_iter],
1474 let arms = hir_vec![pat_arm, break_arm];
1478 hir::ExprMatch(next_expr, arms, hir::MatchSource::ForLoopDesugar),
1482 // `[opt_ident]: loop { ... }`
1483 let loop_block = block_expr(lctx, match_expr);
1484 let loop_expr = hir::ExprLoop(loop_block,
1485 opt_ident.map(|ident| lower_ident(lctx, ident)));
1486 let loop_expr = expr(lctx, e.span, loop_expr, None);
1488 // `mut iter => { ... }`
1490 let iter_pat = pat_ident_binding_mode(lctx,
1493 hir::BindByValue(hir::MutMutable));
1494 arm(hir_vec![iter_pat], loop_expr)
1497 // `match ::std::iter::IntoIterator::into_iter(<head>) { ... }`
1498 let into_iter_expr = {
1499 let into_iter_path = {
1500 let strs = std_path(lctx, &["iter", "IntoIterator", "into_iter"]);
1502 path_global(e.span, strs)
1505 let into_iter = expr_path(lctx, into_iter_path, None);
1506 expr_call(lctx, e.span, into_iter, hir_vec![head], None)
1509 let match_expr = expr_match(lctx,
1513 hir::MatchSource::ForLoopDesugar,
1516 // `{ let _result = ...; _result }`
1517 // underscore prevents an unused_variables lint if the head diverges
1518 let result_ident = lctx.str_to_ident("_result");
1519 let let_stmt = stmt_let(lctx, e.span, false, result_ident, match_expr, None);
1520 let result = expr_ident(lctx, e.span, result_ident, None);
1521 let block = block_all(lctx, e.span, hir_vec![let_stmt], Some(result));
1522 // add the attributes to the outer returned expr node
1523 expr_block(lctx, block, e.attrs.clone())
1527 ExprMac(_) => panic!("Shouldn't exist here"),
1530 attrs: e.attrs.clone(),
1534 pub fn lower_stmt(lctx: &LoweringContext, s: &Stmt) -> hir::Stmt {
1536 StmtDecl(ref d, id) => {
1538 node: hir::StmtDecl(lower_decl(lctx, d), id),
1542 StmtExpr(ref e, id) => {
1544 node: hir::StmtExpr(lower_expr(lctx, e), id),
1548 StmtSemi(ref e, id) => {
1550 node: hir::StmtSemi(lower_expr(lctx, e), id),
1554 StmtMac(..) => panic!("Shouldn't exist here"),
1558 pub fn lower_capture_clause(_lctx: &LoweringContext, c: CaptureClause) -> hir::CaptureClause {
1560 CaptureByValue => hir::CaptureByValue,
1561 CaptureByRef => hir::CaptureByRef,
1565 pub fn lower_visibility(_lctx: &LoweringContext, v: Visibility) -> hir::Visibility {
1567 Public => hir::Public,
1568 Inherited => hir::Inherited,
1572 pub fn lower_block_check_mode(lctx: &LoweringContext, b: &BlockCheckMode) -> hir::BlockCheckMode {
1574 DefaultBlock => hir::DefaultBlock,
1575 UnsafeBlock(u) => hir::UnsafeBlock(lower_unsafe_source(lctx, u)),
1579 pub fn lower_binding_mode(lctx: &LoweringContext, b: &BindingMode) -> hir::BindingMode {
1581 BindingMode::ByRef(m) => hir::BindByRef(lower_mutability(lctx, m)),
1582 BindingMode::ByValue(m) => hir::BindByValue(lower_mutability(lctx, m)),
1586 pub fn lower_struct_field_kind(lctx: &LoweringContext,
1587 s: &StructFieldKind)
1588 -> hir::StructFieldKind {
1590 NamedField(ident, vis) => hir::NamedField(ident.name, lower_visibility(lctx, vis)),
1591 UnnamedField(vis) => hir::UnnamedField(lower_visibility(lctx, vis)),
1595 pub fn lower_unsafe_source(_lctx: &LoweringContext, u: UnsafeSource) -> hir::UnsafeSource {
1597 CompilerGenerated => hir::CompilerGenerated,
1598 UserProvided => hir::UserProvided,
1602 pub fn lower_impl_polarity(_lctx: &LoweringContext, i: ImplPolarity) -> hir::ImplPolarity {
1604 ImplPolarity::Positive => hir::ImplPolarity::Positive,
1605 ImplPolarity::Negative => hir::ImplPolarity::Negative,
1609 pub fn lower_trait_bound_modifier(_lctx: &LoweringContext,
1610 f: TraitBoundModifier)
1611 -> hir::TraitBoundModifier {
1613 TraitBoundModifier::None => hir::TraitBoundModifier::None,
1614 TraitBoundModifier::Maybe => hir::TraitBoundModifier::Maybe,
1618 // Helper methods for building HIR.
1620 fn arm(pats: hir::HirVec<P<hir::Pat>>, expr: P<hir::Expr>) -> hir::Arm {
1629 fn expr_break(lctx: &LoweringContext, span: Span,
1630 attrs: ThinAttributes) -> P<hir::Expr> {
1631 expr(lctx, span, hir::ExprBreak(None), attrs)
1634 fn expr_call(lctx: &LoweringContext,
1637 args: hir::HirVec<P<hir::Expr>>,
1638 attrs: ThinAttributes)
1640 expr(lctx, span, hir::ExprCall(e, args), attrs)
1643 fn expr_ident(lctx: &LoweringContext, span: Span, id: hir::Ident,
1644 attrs: ThinAttributes) -> P<hir::Expr> {
1645 expr_path(lctx, path_ident(span, id), attrs)
1648 fn expr_mut_addr_of(lctx: &LoweringContext, span: Span, e: P<hir::Expr>,
1649 attrs: ThinAttributes) -> P<hir::Expr> {
1650 expr(lctx, span, hir::ExprAddrOf(hir::MutMutable, e), attrs)
1653 fn expr_path(lctx: &LoweringContext, path: hir::Path,
1654 attrs: ThinAttributes) -> P<hir::Expr> {
1655 expr(lctx, path.span, hir::ExprPath(None, path), attrs)
1658 fn expr_match(lctx: &LoweringContext,
1661 arms: hir::HirVec<hir::Arm>,
1662 source: hir::MatchSource,
1663 attrs: ThinAttributes)
1665 expr(lctx, span, hir::ExprMatch(arg, arms, source), attrs)
1668 fn expr_block(lctx: &LoweringContext, b: P<hir::Block>,
1669 attrs: ThinAttributes) -> P<hir::Expr> {
1670 expr(lctx, b.span, hir::ExprBlock(b), attrs)
1673 fn expr_tuple(lctx: &LoweringContext, sp: Span, exprs: hir::HirVec<P<hir::Expr>>,
1674 attrs: ThinAttributes) -> P<hir::Expr> {
1675 expr(lctx, sp, hir::ExprTup(exprs), attrs)
1678 fn expr(lctx: &LoweringContext, span: Span, node: hir::Expr_,
1679 attrs: ThinAttributes) -> P<hir::Expr> {
1688 fn stmt_let(lctx: &LoweringContext,
1693 attrs: ThinAttributes)
1695 let pat = if mutbl {
1696 pat_ident_binding_mode(lctx, sp, ident, hir::BindByValue(hir::MutMutable))
1698 pat_ident(lctx, sp, ident)
1700 let local = P(hir::Local {
1708 let decl = respan(sp, hir::DeclLocal(local));
1709 respan(sp, hir::StmtDecl(P(decl), lctx.next_id()))
1712 fn block_expr(lctx: &LoweringContext, expr: P<hir::Expr>) -> P<hir::Block> {
1713 block_all(lctx, expr.span, hir::HirVec::new(), Some(expr))
1716 fn block_all(lctx: &LoweringContext,
1718 stmts: hir::HirVec<hir::Stmt>,
1719 expr: Option<P<hir::Expr>>)
1725 rules: hir::DefaultBlock,
1730 fn pat_some(lctx: &LoweringContext, span: Span, pat: P<hir::Pat>) -> P<hir::Pat> {
1731 let some = std_path(lctx, &["option", "Option", "Some"]);
1732 let path = path_global(span, some);
1733 pat_enum(lctx, span, path, hir_vec![pat])
1736 fn pat_none(lctx: &LoweringContext, span: Span) -> P<hir::Pat> {
1737 let none = std_path(lctx, &["option", "Option", "None"]);
1738 let path = path_global(span, none);
1739 pat_enum(lctx, span, path, hir_vec![])
1742 fn pat_enum(lctx: &LoweringContext,
1745 subpats: hir::HirVec<P<hir::Pat>>)
1747 let pt = hir::PatEnum(path, Some(subpats));
1751 fn pat_ident(lctx: &LoweringContext, span: Span, ident: hir::Ident) -> P<hir::Pat> {
1752 pat_ident_binding_mode(lctx, span, ident, hir::BindByValue(hir::MutImmutable))
1755 fn pat_ident_binding_mode(lctx: &LoweringContext,
1758 bm: hir::BindingMode)
1760 let pat_ident = hir::PatIdent(bm,
1766 pat(lctx, span, pat_ident)
1769 fn pat_wild(lctx: &LoweringContext, span: Span) -> P<hir::Pat> {
1770 pat(lctx, span, hir::PatWild)
1773 fn pat(lctx: &LoweringContext, span: Span, pat: hir::Pat_) -> P<hir::Pat> {
1781 fn path_ident(span: Span, id: hir::Ident) -> hir::Path {
1782 path(span, vec![id])
1785 fn path(span: Span, strs: Vec<hir::Ident>) -> hir::Path {
1786 path_all(span, false, strs, hir::HirVec::new(), hir::HirVec::new(), hir::HirVec::new())
1789 fn path_global(span: Span, strs: Vec<hir::Ident>) -> hir::Path {
1790 path_all(span, true, strs, hir::HirVec::new(), hir::HirVec::new(), hir::HirVec::new())
1793 fn path_all(sp: Span,
1795 mut idents: Vec<hir::Ident>,
1796 lifetimes: hir::HirVec<hir::Lifetime>,
1797 types: hir::HirVec<P<hir::Ty>>,
1798 bindings: hir::HirVec<hir::TypeBinding>)
1800 let last_identifier = idents.pop().unwrap();
1801 let mut segments: Vec<hir::PathSegment> = idents.into_iter()
1805 parameters: hir::PathParameters::none(),
1809 segments.push(hir::PathSegment {
1810 identifier: last_identifier,
1811 parameters: hir::AngleBracketedParameters(hir::AngleBracketedParameterData {
1812 lifetimes: lifetimes,
1820 segments: segments.into(),
1824 fn std_path(lctx: &LoweringContext, components: &[&str]) -> Vec<hir::Ident> {
1825 let mut v = Vec::new();
1826 if let Some(s) = lctx.crate_root {
1827 v.push(hir::Ident::from_name(token::intern(s)));
1829 v.extend(components.iter().map(|s| hir::Ident::from_name(token::intern(s))));
1833 // Given suffix ["b","c","d"], returns path `::std::b::c::d` when
1834 // `fld.cx.use_std`, and `::core::b::c::d` otherwise.
1835 fn core_path(lctx: &LoweringContext, span: Span, components: &[&str]) -> hir::Path {
1836 let idents = std_path(lctx, components);
1837 path_global(span, idents)
1840 fn signal_block_expr(lctx: &LoweringContext,
1841 stmts: hir::HirVec<hir::Stmt>,
1844 rule: hir::BlockCheckMode,
1845 attrs: ThinAttributes)
1847 let id = lctx.next_id();
1864 use syntax::ast::{self, NodeId, NodeIdAssigner};
1865 use syntax::{parse, codemap};
1866 use syntax::fold::Folder;
1867 use std::cell::Cell;
1869 struct MockAssigner {
1870 next_id: Cell<NodeId>,
1874 fn new() -> MockAssigner {
1875 MockAssigner { next_id: Cell::new(0) }
1880 fn call_site(&self) -> codemap::Span;
1881 fn cfg(&self) -> ast::CrateConfig;
1882 fn ident_of(&self, st: &str) -> ast::Ident;
1883 fn name_of(&self, st: &str) -> ast::Name;
1884 fn parse_sess(&self) -> &parse::ParseSess;
1887 impl FakeExtCtxt for parse::ParseSess {
1888 fn call_site(&self) -> codemap::Span {
1890 lo: codemap::BytePos(0),
1891 hi: codemap::BytePos(0),
1892 expn_id: codemap::NO_EXPANSION,
1895 fn cfg(&self) -> ast::CrateConfig {
1898 fn ident_of(&self, st: &str) -> ast::Ident {
1899 parse::token::str_to_ident(st)
1901 fn name_of(&self, st: &str) -> ast::Name {
1902 parse::token::intern(st)
1904 fn parse_sess(&self) -> &parse::ParseSess {
1909 impl NodeIdAssigner for MockAssigner {
1910 fn next_node_id(&self) -> NodeId {
1911 let result = self.next_id.get();
1912 self.next_id.set(result + 1);
1916 fn peek_node_id(&self) -> NodeId {
1921 impl Folder for MockAssigner {
1922 fn new_id(&mut self, old_id: NodeId) -> NodeId {
1923 assert_eq!(old_id, ast::DUMMY_NODE_ID);
1929 fn test_preserves_ids() {
1930 let cx = parse::ParseSess::new();
1931 let mut assigner = MockAssigner::new();
1933 let ast_if_let = quote_expr!(&cx,
1934 if let Some(foo) = baz {
1937 let ast_if_let = assigner.fold_expr(ast_if_let);
1938 let ast_while_let = quote_expr!(&cx,
1939 while let Some(foo) = baz {
1942 let ast_while_let = assigner.fold_expr(ast_while_let);
1943 let ast_for = quote_expr!(&cx,
1949 let ast_for = assigner.fold_expr(ast_for);
1950 let ast_in = quote_expr!(&cx, in HEAP { foo() });
1951 let ast_in = assigner.fold_expr(ast_in);
1953 let lctx = LoweringContext::new(&assigner, None);
1954 let hir1 = lower_expr(&lctx, &ast_if_let);
1955 let hir2 = lower_expr(&lctx, &ast_if_let);
1956 assert!(hir1 == hir2);
1958 let hir1 = lower_expr(&lctx, &ast_while_let);
1959 let hir2 = lower_expr(&lctx, &ast_while_let);
1960 assert!(hir1 == hir2);
1962 let hir1 = lower_expr(&lctx, &ast_for);
1963 let hir2 = lower_expr(&lctx, &ast_for);
1964 assert!(hir1 == hir2);
1966 let hir1 = lower_expr(&lctx, &ast_in);
1967 let hir2 = lower_expr(&lctx, &ast_in);
1968 assert!(hir1 == hir2);