rust/src/librustc/hir/lowering.rs

4329 lines
170 KiB
Rust
Raw Normal View History

2015-07-31 00:04:06 -07:00
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Lowers the AST to the HIR.
//!
//! Since the AST and HIR are fairly similar, this is mostly a simple procedure,
//! much like a fold. Where lowering involves a bit more work things get more
//! interesting and there are some invariants you should know about. These mostly
//! concern spans and ids.
//!
//! Spans are assigned to AST nodes during parsing and then are modified during
//! expansion to indicate the origin of a node and the process it went through
//! being expanded. Ids are assigned to AST nodes just before lowering.
//!
//! For the simpler lowering steps, ids and spans should be preserved. Unlike
//! expansion we do not preserve the process of lowering in the spans, so spans
//! should not be modified here. When creating a new node (as opposed to
//! 'folding' an existing one), then you create a new id using `next_id()`.
//!
//! You must ensure that ids are unique. That means that you should only use the
//! id from an AST node in a single HIR node (you can assume that AST node ids
//! are unique). Every new node must have a unique id. Avoid cloning HIR nodes.
//! If you do, you must then set the new node's id to a fresh one.
//!
//! Spans are used for error messages and for tools to map semantics back to
//! source code. It is therefore not as important with spans as ids to be strict
//! about use (you can't break the compiler by screwing up a span). Obviously, a
//! HIR node can only have a single span. But multiple nodes can have the same
//! span and spans don't need to be kept in order, etc. Where code is preserved
//! by lowering, it should have the same span as in the AST. Where HIR nodes are
//! new it is probably best to give a span for the whole AST node being lowered.
//! All nodes should have real spans, don't use dummy spans. Tools are likely to
//! get confused if the spans from leaf AST nodes occur in multiple places
//! in the HIR, especially for multiple identifiers.
2015-07-31 00:04:06 -07:00
use dep_graph::DepGraph;
2015-07-31 00:04:06 -07:00
use hir;
use hir::HirVec;
2018-03-21 04:24:27 -04:00
use hir::map::{DefKey, DefPathData, Definitions};
use hir::def_id::{DefId, DefIndex, DefIndexAddressSpace, CRATE_DEF_INDEX};
use hir::def::{Def, PathResolution, PerNS};
use hir::GenericArg;
2018-02-22 22:44:44 -08:00
use lint::builtin::{self, PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES};
use middle::cstore::CrateStore;
use rustc_data_structures::indexed_vec::IndexVec;
use session::Session;
use util::common::FN_OUTPUT_NAME;
2017-03-24 23:03:15 +00:00
use util::nodemap::{DefIdMap, FxHashMap, NodeMap};
2015-07-31 00:04:06 -07:00
use std::collections::{BTreeMap, HashSet};
use std::fmt::Debug;
use std::iter;
2017-02-15 14:52:27 -08:00
use std::mem;
use syntax::attr;
2018-02-23 17:48:54 +00:00
use syntax::ast;
2015-07-31 00:04:06 -07:00
use syntax::ast::*;
use syntax::errors;
2017-03-17 04:04:41 +00:00
use syntax::ext::hygiene::{Mark, SyntaxContext};
2017-12-15 12:27:20 -08:00
use syntax::print::pprust;
2015-07-31 00:04:06 -07:00
use syntax::ptr::P;
2018-03-21 04:24:27 -04:00
use syntax::codemap::{self, respan, CompilerDesugaringKind, Spanned};
2015-09-28 15:00:15 +13:00
use syntax::std_inject;
2018-03-21 04:24:27 -04:00
use syntax::symbol::{keywords, Symbol};
use syntax::tokenstream::{Delimited, TokenStream, TokenTree};
use syntax::parse::token::Token;
use syntax::util::small_vector::SmallVector;
use syntax::visit::{self, Visitor};
use syntax_pos::Span;
2015-07-31 00:04:06 -07:00
const HIR_ID_COUNTER_LOCKED: u32 = 0xFFFFFFFF;
pub struct LoweringContext<'a> {
2015-09-28 15:00:15 +13:00
crate_root: Option<&'static str>,
2017-06-04 18:15:42 +02:00
// Use to assign ids to hir nodes that do not directly correspond to an ast node
sess: &'a Session,
2017-06-04 18:15:42 +02:00
2018-03-21 04:24:27 -04:00
cstore: &'a CrateStore,
2018-03-21 04:24:27 -04:00
resolver: &'a mut Resolver,
2017-03-24 23:03:15 +00:00
name_map: FxHashMap<Ident, Name>,
/// The items being lowered are collected here.
items: BTreeMap<NodeId, hir::Item>,
trait_items: BTreeMap<hir::TraitItemId, hir::TraitItem>,
impl_items: BTreeMap<hir::ImplItemId, hir::ImplItem>,
2017-02-21 10:55:40 -05:00
bodies: BTreeMap<hir::BodyId, hir::Body>,
exported_macros: Vec<hir::MacroDef>,
trait_impls: BTreeMap<DefId, Vec<NodeId>>,
trait_auto_impl: BTreeMap<DefId, NodeId>,
is_generator: bool,
2016-12-26 14:34:03 +01:00
catch_scopes: Vec<NodeId>,
2017-02-15 14:52:27 -08:00
loop_scopes: Vec<NodeId>,
is_in_loop_condition: bool,
is_in_trait_impl: bool,
2017-02-15 14:52:27 -08:00
/// What to do when we encounter either an "anonymous lifetime
/// reference". The term "anonymous" is meant to encompass both
/// `'_` lifetimes as well as fully elided cases where nothing is
/// written at all (e.g., `&T` or `std::cell::Ref<T>`).
anonymous_lifetime_mode: AnonymousLifetimeMode,
2017-12-15 12:27:20 -08:00
// This is a list of in-band type definitions being generated by
// Argument-position `impl Trait`.
// When traversing a signature such as `fn foo(x: impl Trait)`,
// we record `impl Trait` as a new type parameter, then later
// add it on to `foo`s generics.
2018-05-26 00:27:54 +01:00
in_band_ty_params: Vec<hir::GenericParam>,
2017-12-15 12:27:20 -08:00
2017-11-16 22:59:45 -08:00
// Used to create lifetime definitions from in-band lifetime usages.
// e.g. `fn foo(x: &'x u8) -> &'x u8` to `fn foo<'x>(x: &'x u8) -> &'x u8`
// When a named lifetime is encountered in a function or impl header and
// has not been defined
// (i.e. it doesn't appear in the in_scope_lifetimes list), it is added
// to this list. The results of this list are then added to the list of
// lifetime definitions in the corresponding impl or function generics.
lifetimes_to_define: Vec<(Span, hir::LifetimeName)>,
2017-11-16 22:59:45 -08:00
// Whether or not in-band lifetimes are being collected. This is used to
// indicate whether or not we're in a place where new lifetimes will result
// in in-band lifetime definitions, such a function or an impl header.
// This will always be false unless the `in_band_lifetimes` feature is
// enabled.
is_collecting_in_band_lifetimes: bool,
2017-11-16 22:59:45 -08:00
// Currently in-scope lifetimes defined in impl headers, fn headers, or HRTB.
// When `is_collectin_in_band_lifetimes` is true, each lifetime is checked
// against this list to see if it is already in-scope, or if a definition
// needs to be created for it.
in_scope_lifetimes: Vec<Name>,
type_def_lifetime_params: DefIdMap<usize>,
current_hir_id_owner: Vec<(DefIndex, u32)>,
item_local_id_counters: NodeMap<u32>,
node_id_to_hir_id: IndexVec<NodeId, hir::HirId>,
}
pub trait Resolver {
/// Resolve a hir path generated by the lowerer when expanding `for`, `if let`, etc.
2016-11-25 06:07:21 +00:00
fn resolve_hir_path(&mut self, path: &mut hir::Path, is_value: bool);
/// Obtain the resolution for a node id
fn get_resolution(&mut self, id: NodeId) -> Option<PathResolution>;
/// Obtain the possible resolutions for the given `use` statement.
fn get_import(&mut self, id: NodeId) -> PerNS<Option<PathResolution>>;
/// We must keep the set of definitions up to date as we add nodes that weren't in the AST.
/// This should only return `None` during testing.
fn definitions(&mut self) -> &mut Definitions;
2017-12-25 11:37:55 +05:30
2017-12-28 10:52:40 -06:00
/// Given suffix ["b","c","d"], creates a HIR path for `[::crate_root]::b::c::d` and resolves
/// it based on `is_value`.
2018-03-21 04:24:27 -04:00
fn resolve_str_path(
&mut self,
span: Span,
crate_root: Option<&str>,
components: &[&str],
is_value: bool,
) -> hir::Path;
2015-09-25 16:03:28 +12:00
}
#[derive(Clone, Copy, Debug)]
enum ImplTraitContext {
/// Treat `impl Trait` as shorthand for a new universal generic parameter.
/// Example: `fn foo(x: impl Debug)`, where `impl Debug` is conceptually
/// equivalent to a fresh universal parameter like `fn foo<T: Debug>(x: T)`.
///
/// We store a DefId here so we can look up necessary information later
Universal(DefId),
/// Treat `impl Trait` as shorthand for a new universal existential parameter.
/// Example: `fn foo() -> impl Debug`, where `impl Debug` is conceptually
/// equivalent to a fresh existential parameter like `abstract type T; fn foo() -> T`.
2018-05-22 14:31:56 +02:00
///
/// We store a DefId here so we can look up necessary information later
Existential(DefId),
/// `impl Trait` is not accepted in this position.
Disallowed,
}
2018-03-21 04:24:27 -04:00
pub fn lower_crate(
sess: &Session,
cstore: &CrateStore,
dep_graph: &DepGraph,
krate: &Crate,
resolver: &mut Resolver,
) -> hir::Crate {
// We're constructing the HIR here; we don't care what we will
// read, since we haven't even constructed the *input* to
// incr. comp. yet.
dep_graph.assert_ignored();
2016-05-10 05:29:13 +00:00
LoweringContext {
crate_root: std_inject::injected_crate_name(),
sess,
cstore,
resolver,
2017-03-24 23:03:15 +00:00
name_map: FxHashMap(),
items: BTreeMap::new(),
trait_items: BTreeMap::new(),
impl_items: BTreeMap::new(),
2017-02-21 10:55:40 -05:00
bodies: BTreeMap::new(),
trait_impls: BTreeMap::new(),
trait_auto_impl: BTreeMap::new(),
exported_macros: Vec::new(),
catch_scopes: Vec::new(),
2017-02-15 14:52:27 -08:00
loop_scopes: Vec::new(),
is_in_loop_condition: false,
anonymous_lifetime_mode: AnonymousLifetimeMode::PassThrough,
type_def_lifetime_params: DefIdMap(),
current_hir_id_owner: vec![(CRATE_DEF_INDEX, 0)],
item_local_id_counters: NodeMap(),
node_id_to_hir_id: IndexVec::new(),
is_generator: false,
is_in_trait_impl: false,
2017-12-15 12:27:20 -08:00
in_band_ty_params: Vec::new(),
2017-11-16 22:59:45 -08:00
lifetimes_to_define: Vec::new(),
is_collecting_in_band_lifetimes: false,
in_scope_lifetimes: Vec::new(),
2016-05-10 05:29:13 +00:00
}.lower_crate(krate)
}
2015-09-28 15:00:15 +13:00
#[derive(Copy, Clone, PartialEq, Eq)]
enum ParamMode {
/// Any path in a type context.
Explicit,
/// The `module::Type` in `module::Type::method` in an expression.
2018-03-21 04:24:27 -04:00
Optional,
}
2018-05-22 14:31:56 +02:00
#[derive(Debug)]
struct LoweredNodeId {
node_id: NodeId,
hir_id: hir::HirId,
}
enum ParenthesizedGenericArgs {
Ok,
Warn,
Err,
}
/// What to do when we encounter an **anonymous** lifetime
/// reference. Anonymous lifetime references come in two flavors. You
/// have implicit, or fully elided, references to lifetimes, like the
/// one in `&T` or `Ref<T>`, and you have `'_` lifetimes, like `&'_ T`
/// or `Ref<'_, T>`. These often behave the same, but not always:
///
/// - certain usages of implicit references are deprecated, like
/// `Ref<T>`, and we sometimes just give hard errors in those cases
/// as well.
/// - for object bounds there is a difference: `Box<dyn Foo>` is not
/// the same as `Box<dyn Foo + '_>`.
///
/// We describe the effects of the various modes in terms of three cases:
///
/// - **Modern** -- includes all uses of `'_`, but also the lifetime arg
/// of a `&` (e.g., the missing lifetime in something like `&T`)
/// - **Dyn Bound** -- if you have something like `Box<dyn Foo>`,
/// there is an elided lifetime bound (`Box<dyn Foo + 'X>`). These
/// elided bounds follow special rules. Note that this only covers
/// cases where *nothing* is written; the `'_` in `Box<dyn Foo +
/// '_>` is a case of "modern" elision.
/// - **Deprecated** -- this coverse cases like `Ref<T>`, where the lifetime
/// parameter to ref is completely elided. `Ref<'_, T>` would be the modern,
/// non-deprecated equivalent.
///
/// Currently, the handling of lifetime elision is somewhat spread out
/// between HIR lowering and -- as described below -- the
/// `resolve_lifetime` module. Often we "fallthrough" to that code by generating
/// an "elided" or "underscore" lifetime name. In the future, we probably want to move
/// everything into HIR lowering.
#[derive(Copy, Clone)]
enum AnonymousLifetimeMode {
/// For **Modern** cases, create a new anonymous region parameter
/// and reference that.
///
/// For **Dyn Bound** cases, pass responsibility to
/// `resolve_lifetime` code.
///
/// For **Deprecated** cases, report an error.
CreateParameter,
/// Pass responsibility to `resolve_lifetime` code for all cases.
PassThrough,
}
2016-05-10 05:29:13 +00:00
impl<'a> LoweringContext<'a> {
fn lower_crate(mut self, c: &Crate) -> hir::Crate {
/// Full-crate AST visitor that inserts into a fresh
/// `LoweringContext` any information that may be
/// needed from arbitrary locations in the crate.
/// E.g. The number of lifetime generic parameters
/// declared for every type and trait definition.
struct MiscCollector<'lcx, 'interner: 'lcx> {
lctx: &'lcx mut LoweringContext<'interner>,
}
impl<'lcx, 'interner> Visitor<'lcx> for MiscCollector<'lcx, 'interner> {
fn visit_item(&mut self, item: &'lcx Item) {
self.lctx.allocate_hir_id_counter(item.id, item);
match item.node {
2018-03-21 04:24:27 -04:00
ItemKind::Struct(_, ref generics)
| ItemKind::Union(_, ref generics)
| ItemKind::Enum(_, ref generics)
| ItemKind::Ty(_, ref generics)
| ItemKind::Trait(_, _, ref generics, ..) => {
let def_id = self.lctx.resolver.definitions().local_def_id(item.id);
2018-03-21 04:24:27 -04:00
let count = generics
.params
.iter()
.filter(|param| param.is_lifetime_param())
.count();
self.lctx.type_def_lifetime_params.insert(def_id, count);
}
_ => {}
}
visit::walk_item(self, item);
}
fn visit_trait_item(&mut self, item: &'lcx TraitItem) {
self.lctx.allocate_hir_id_counter(item.id, item);
visit::walk_trait_item(self, item);
}
fn visit_impl_item(&mut self, item: &'lcx ImplItem) {
self.lctx.allocate_hir_id_counter(item.id, item);
visit::walk_impl_item(self, item);
}
}
struct ItemLowerer<'lcx, 'interner: 'lcx> {
lctx: &'lcx mut LoweringContext<'interner>,
}
impl<'lcx, 'interner> ItemLowerer<'lcx, 'interner> {
fn with_trait_impl_ref<F>(&mut self, trait_impl_ref: &Option<TraitRef>, f: F)
2018-03-21 04:24:27 -04:00
where
F: FnOnce(&mut Self),
{
let old = self.lctx.is_in_trait_impl;
self.lctx.is_in_trait_impl = if let &None = trait_impl_ref {
false
} else {
true
};
f(self);
self.lctx.is_in_trait_impl = old;
}
}
impl<'lcx, 'interner> Visitor<'lcx> for ItemLowerer<'lcx, 'interner> {
fn visit_item(&mut self, item: &'lcx Item) {
let mut item_lowered = true;
self.lctx.with_hir_id_owner(item.id, |lctx| {
if let Some(hir_item) = lctx.lower_item(item) {
lctx.items.insert(item.id, hir_item);
} else {
item_lowered = false;
}
});
if item_lowered {
2017-11-16 22:59:45 -08:00
let item_lifetimes = match self.lctx.items.get(&item.id).unwrap().node {
2018-05-10 23:02:41 +01:00
hir::Item_::ItemImpl(_, _, _, ref generics, ..)
| hir::Item_::ItemTrait(_, _, ref generics, ..) => {
generics.params
.iter()
.filter_map(|param| match param.kind {
hir::GenericParamKind::Lifetime { .. } => {
Some(param.clone())
}
_ => None,
})
.collect::<Vec<_>>()
2018-03-21 04:24:27 -04:00
}
_ => Vec::new(),
2017-11-16 22:59:45 -08:00
};
self.lctx.with_parent_impl_lifetime_defs(&item_lifetimes, |this| {
let this = &mut ItemLowerer { lctx: this };
if let ItemKind::Impl(_, _, _, _, ref opt_trait_ref, _, _) = item.node {
this.with_trait_impl_ref(opt_trait_ref, |this| {
visit::walk_item(this, item)
});
} else {
visit::walk_item(this, item);
}
});
}
}
fn visit_trait_item(&mut self, item: &'lcx TraitItem) {
self.lctx.with_hir_id_owner(item.id, |lctx| {
let id = hir::TraitItemId { node_id: item.id };
let hir_item = lctx.lower_trait_item(item);
lctx.trait_items.insert(id, hir_item);
});
visit::walk_trait_item(self, item);
}
fn visit_impl_item(&mut self, item: &'lcx ImplItem) {
self.lctx.with_hir_id_owner(item.id, |lctx| {
let id = hir::ImplItemId { node_id: item.id };
let hir_item = lctx.lower_impl_item(item);
lctx.impl_items.insert(id, hir_item);
});
visit::walk_impl_item(self, item);
}
}
self.lower_node_id(CRATE_NODE_ID);
debug_assert!(self.node_id_to_hir_id[CRATE_NODE_ID] == hir::CRATE_HIR_ID);
visit::walk_crate(&mut MiscCollector { lctx: &mut self }, c);
visit::walk_crate(&mut ItemLowerer { lctx: &mut self }, c);
let module = self.lower_mod(&c.module);
let attrs = self.lower_attrs(&c.attrs);
2017-02-21 12:23:47 -05:00
let body_ids = body_ids(&self.bodies);
self.resolver
.definitions()
.init_node_id_to_hir_id_mapping(self.node_id_to_hir_id);
hir::Crate {
module,
attrs,
span: c.span,
exported_macros: hir::HirVec::from(self.exported_macros),
items: self.items,
trait_items: self.trait_items,
impl_items: self.impl_items,
bodies: self.bodies,
body_ids,
trait_impls: self.trait_impls,
trait_auto_impl: self.trait_auto_impl,
}
}
2018-03-21 04:24:27 -04:00
fn allocate_hir_id_counter<T: Debug>(&mut self, owner: NodeId, debug: &T) {
if self.item_local_id_counters.insert(owner, 0).is_some() {
2018-03-21 04:24:27 -04:00
bug!(
"Tried to allocate item_local_id_counter for {:?} twice",
debug
);
}
// Always allocate the first HirId for the owner itself
self.lower_node_id_with_owner(owner, owner);
}
2018-03-21 04:24:27 -04:00
fn lower_node_id_generic<F>(&mut self, ast_node_id: NodeId, alloc_hir_id: F) -> LoweredNodeId
where
F: FnOnce(&mut Self) -> hir::HirId,
{
if ast_node_id == DUMMY_NODE_ID {
return LoweredNodeId {
node_id: DUMMY_NODE_ID,
hir_id: hir::DUMMY_HIR_ID,
2018-03-21 04:24:27 -04:00
};
}
let min_size = ast_node_id.as_usize() + 1;
if min_size > self.node_id_to_hir_id.len() {
self.node_id_to_hir_id.resize(min_size, hir::DUMMY_HIR_ID);
}
let existing_hir_id = self.node_id_to_hir_id[ast_node_id];
if existing_hir_id == hir::DUMMY_HIR_ID {
// Generate a new HirId
let hir_id = alloc_hir_id(self);
self.node_id_to_hir_id[ast_node_id] = hir_id;
LoweredNodeId {
node_id: ast_node_id,
hir_id,
}
} else {
LoweredNodeId {
node_id: ast_node_id,
hir_id: existing_hir_id,
}
}
}
2018-05-22 14:31:56 +02:00
fn with_hir_id_owner<F, T>(&mut self, owner: NodeId, f: F) -> T
2018-03-21 04:24:27 -04:00
where
2018-05-22 14:31:56 +02:00
F: FnOnce(&mut Self) -> T,
{
let counter = self.item_local_id_counters
2018-03-21 04:24:27 -04:00
.insert(owner, HIR_ID_COUNTER_LOCKED)
.unwrap();
let def_index = self.resolver.definitions().opt_def_index(owner).unwrap();
self.current_hir_id_owner.push((def_index, counter));
2018-05-22 14:31:56 +02:00
let ret = f(self);
let (new_def_index, new_counter) = self.current_hir_id_owner.pop().unwrap();
debug_assert!(def_index == new_def_index);
debug_assert!(new_counter >= counter);
2018-03-21 04:24:27 -04:00
let prev = self.item_local_id_counters
.insert(owner, new_counter)
.unwrap();
debug_assert!(prev == HIR_ID_COUNTER_LOCKED);
2018-05-22 14:31:56 +02:00
ret
}
/// This method allocates a new HirId for the given NodeId and stores it in
/// the LoweringContext's NodeId => HirId map.
/// Take care not to call this method if the resulting HirId is then not
/// actually used in the HIR, as that would trigger an assertion in the
/// HirIdValidator later on, which makes sure that all NodeIds got mapped
/// properly. Calling the method twice with the same NodeId is fine though.
fn lower_node_id(&mut self, ast_node_id: NodeId) -> LoweredNodeId {
self.lower_node_id_generic(ast_node_id, |this| {
2018-03-21 04:24:27 -04:00
let &mut (def_index, ref mut local_id_counter) =
this.current_hir_id_owner.last_mut().unwrap();
let local_id = *local_id_counter;
*local_id_counter += 1;
hir::HirId {
owner: def_index,
local_id: hir::ItemLocalId(local_id),
}
})
}
2018-03-21 04:24:27 -04:00
fn lower_node_id_with_owner(&mut self, ast_node_id: NodeId, owner: NodeId) -> LoweredNodeId {
self.lower_node_id_generic(ast_node_id, |this| {
2018-05-22 14:31:56 +02:00
let local_id_counter = this
.item_local_id_counters
.get_mut(&owner)
.expect("called lower_node_id_with_owner before allocate_hir_id_counter");
let local_id = *local_id_counter;
// We want to be sure not to modify the counter in the map while it
// is also on the stack. Otherwise we'll get lost updates when writing
// back from the stack to the map.
debug_assert!(local_id != HIR_ID_COUNTER_LOCKED);
*local_id_counter += 1;
2018-05-22 14:31:56 +02:00
let def_index = this
.resolver
.definitions()
.opt_def_index(owner)
.expect("You forgot to call `create_def_with_parent` or are lowering node ids \
that do not belong to the current owner");
hir::HirId {
owner: def_index,
local_id: hir::ItemLocalId(local_id),
}
})
}
2018-03-21 04:24:27 -04:00
fn record_body(&mut self, value: hir::Expr, decl: Option<&FnDecl>) -> hir::BodyId {
let body = hir::Body {
arguments: decl.map_or(hir_vec![], |decl| {
decl.inputs.iter().map(|x| self.lower_arg(x)).collect()
}),
is_generator: self.is_generator,
value,
};
let id = body.id();
self.bodies.insert(id, body);
id
}
fn next_id(&mut self) -> LoweredNodeId {
self.lower_node_id(self.sess.next_node_id())
}
fn expect_full_def(&mut self, id: NodeId) -> Def {
self.resolver.get_resolution(id).map_or(Def::Err, |pr| {
if pr.unresolved_segments() != 0 {
bug!("path not fully resolved: {:?}", pr);
}
pr.base_def()
})
}
fn expect_full_def_from_use(&mut self, id: NodeId) -> impl Iterator<Item=Def> {
self.resolver.get_import(id).present_items().map(|pr| {
if pr.unresolved_segments() != 0 {
bug!("path not fully resolved: {:?}", pr);
}
pr.base_def()
})
}
fn diagnostic(&self) -> &errors::Handler {
self.sess.diagnostic()
2015-09-28 15:00:15 +13:00
}
2015-10-07 08:26:22 +13:00
2016-03-06 15:54:44 +03:00
fn str_to_ident(&self, s: &'static str) -> Name {
Symbol::gensym(s)
2015-10-07 08:26:22 +13:00
}
2018-03-21 04:24:27 -04:00
fn allow_internal_unstable(&self, reason: CompilerDesugaringKind, span: Span) -> Span {
2017-03-22 08:39:51 +00:00
let mark = Mark::fresh(Mark::root());
2017-03-17 04:04:41 +00:00
mark.set_expn_info(codemap::ExpnInfo {
call_site: span,
callee: codemap::NameAndSpan {
2017-08-12 19:43:43 -05:00
format: codemap::CompilerDesugaring(reason),
span: Some(span),
allow_internal_unstable: true,
allow_internal_unsafe: false,
2018-04-28 02:08:16 +03:00
edition: codemap::hygiene::default_edition(),
},
});
2017-07-31 23:04:34 +03:00
span.with_ctxt(SyntaxContext::empty().apply_mark(mark))
}
fn with_anonymous_lifetime_mode<R>(
&mut self,
anonymous_lifetime_mode: AnonymousLifetimeMode,
op: impl FnOnce(&mut Self) -> R,
) -> R {
let old_anonymous_lifetime_mode = self.anonymous_lifetime_mode;
self.anonymous_lifetime_mode = anonymous_lifetime_mode;
let result = op(self);
self.anonymous_lifetime_mode = old_anonymous_lifetime_mode;
result
}
/// Creates a new hir::GenericParam for every new lifetime and
/// type parameter encountered while evaluating `f`. Definitions
/// are created with the parent provided. If no `parent_id` is
/// provided, no definitions will be returned.
///
/// Presuming that in-band lifetimes are enabled, then
/// `self.anonymous_lifetime_mode` will be updated to match the
/// argument while `f` is running (and restored afterwards).
fn collect_in_band_defs<T, F>(
&mut self,
parent_id: DefId,
anonymous_lifetime_mode: AnonymousLifetimeMode,
f: F,
) -> (Vec<hir::GenericParam>, T)
2018-03-21 04:24:27 -04:00
where
F: FnOnce(&mut LoweringContext) -> T,
2017-11-16 22:59:45 -08:00
{
assert!(!self.is_collecting_in_band_lifetimes);
assert!(self.lifetimes_to_define.is_empty());
let old_anonymous_lifetime_mode = self.anonymous_lifetime_mode;
2018-02-14 16:11:02 +01:00
self.is_collecting_in_band_lifetimes = self.sess.features_untracked().in_band_lifetimes;
if self.is_collecting_in_band_lifetimes {
self.anonymous_lifetime_mode = anonymous_lifetime_mode;
}
2017-11-16 22:59:45 -08:00
2017-12-15 12:27:20 -08:00
assert!(self.in_band_ty_params.is_empty());
2017-11-16 22:59:45 -08:00
let res = f(self);
self.is_collecting_in_band_lifetimes = false;
self.anonymous_lifetime_mode = old_anonymous_lifetime_mode;
2017-11-16 22:59:45 -08:00
2017-12-15 12:27:20 -08:00
let in_band_ty_params = self.in_band_ty_params.split_off(0);
2017-11-16 22:59:45 -08:00
let lifetimes_to_define = self.lifetimes_to_define.split_off(0);
let params = lifetimes_to_define
.into_iter()
.map(|(span, hir_name)| {
let def_node_id = self.next_id().node_id;
// Get the name we'll use to make the def-path. Note
// that collisions are ok here and this shouldn't
// really show up for end-user.
let str_name = match hir_name {
hir::LifetimeName::Name(n) => n.as_str(),
hir::LifetimeName::Fresh(_) => keywords::UnderscoreLifetime.name().as_str(),
hir::LifetimeName::Implicit
| hir::LifetimeName::Underscore
| hir::LifetimeName::Static => {
span_bug!(span, "unexpected in-band lifetime name: {:?}", hir_name)
}
};
// Add a definition for the in-band lifetime def
self.resolver.definitions().create_def_with_parent(
parent_id.index,
def_node_id,
DefPathData::LifetimeDef(str_name.as_interned_str()),
DefIndexAddressSpace::High,
Mark::root(),
span,
);
2017-11-16 22:59:45 -08:00
2018-05-26 00:27:54 +01:00
hir::GenericParam {
id: def_node_id,
span,
pure_wrt_drop: false,
2018-05-26 00:27:54 +01:00
kind: hir::GenericParamKind::Lifetime {
name: hir_name,
bounds: vec![].into(),
in_band: true,
lifetime_deprecated: hir::Lifetime {
id: def_node_id,
span,
name: hir_name,
}
}
}
})
2018-05-26 00:27:54 +01:00
.chain(in_band_ty_params.into_iter())
.collect();
(params, res)
2017-11-16 22:59:45 -08:00
}
/// When there is a reference to some lifetime `'a`, and in-band
/// lifetimes are enabled, then we want to push that lifetime into
/// the vector of names to define later. In that case, it will get
/// added to the appropriate generics.
fn maybe_collect_in_band_lifetime(&mut self, span: Span, name: Name) {
if !self.is_collecting_in_band_lifetimes {
return;
}
if self.in_scope_lifetimes.contains(&name) {
return;
}
let hir_name = hir::LifetimeName::Name(name);
if self.lifetimes_to_define
.iter()
.any(|(_, lt_name)| *lt_name == hir_name)
{
return;
}
self.lifetimes_to_define.push((span, hir_name));
}
/// When we have either an elided or `'_` lifetime in an impl
/// header, we convert it to
fn collect_fresh_in_band_lifetime(&mut self, span: Span) -> hir::LifetimeName {
assert!(self.is_collecting_in_band_lifetimes);
let index = self.lifetimes_to_define.len();
let hir_name = hir::LifetimeName::Fresh(index);
self.lifetimes_to_define.push((span, hir_name));
hir_name
}
2018-05-26 19:16:21 +01:00
// Evaluates `f` with the lifetimes in `params` in-scope.
2017-11-16 22:59:45 -08:00
// This is used to track which lifetimes have already been defined, and
// which are new in-band lifetimes that need to have a definition created
// for them.
fn with_in_scope_lifetime_defs<'l, T, F>(
&mut self,
2018-05-26 19:16:21 +01:00
params: impl Iterator<Item = &'l GenericParamAST>,
f: F,
) -> T
2018-03-21 04:24:27 -04:00
where
F: FnOnce(&mut LoweringContext) -> T,
2017-11-16 22:59:45 -08:00
{
let old_len = self.in_scope_lifetimes.len();
2018-05-26 19:16:21 +01:00
let lt_def_names = params.map(|param| param.ident.name);
2017-11-16 22:59:45 -08:00
self.in_scope_lifetimes.extend(lt_def_names);
let res = f(self);
self.in_scope_lifetimes.truncate(old_len);
res
}
2018-05-26 19:16:21 +01:00
// Same as the method above, but accepts `hir::GenericParam`s
// instead of `ast::GenericParam`s.
2017-11-16 22:59:45 -08:00
// This should only be used with generics that have already had their
// in-band lifetimes added. In practice, this means that this function is
// only used when lowering a child item of a trait or impl.
2018-05-26 00:27:54 +01:00
fn with_parent_impl_lifetime_defs<T, F>(&mut self, params: &[hir::GenericParam], f: F) -> T
2018-03-21 04:24:27 -04:00
where
F: FnOnce(&mut LoweringContext) -> T,
2017-11-16 22:59:45 -08:00
{
let old_len = self.in_scope_lifetimes.len();
2018-05-26 00:27:54 +01:00
let lt_def_names = params.iter().map(|param| param.name());
2017-11-16 22:59:45 -08:00
self.in_scope_lifetimes.extend(lt_def_names);
let res = f(self);
self.in_scope_lifetimes.truncate(old_len);
res
}
/// Appends in-band lifetime defs and argument-position `impl
/// Trait` defs to the existing set of generics.
///
/// Presuming that in-band lifetimes are enabled, then
/// `self.anonymous_lifetime_mode` will be updated to match the
/// argument while `f` is running (and restored afterwards).
2017-12-15 12:27:20 -08:00
fn add_in_band_defs<F, T>(
2017-11-16 22:59:45 -08:00
&mut self,
generics: &Generics,
parent_id: DefId,
anonymous_lifetime_mode: AnonymousLifetimeMode,
2018-03-21 04:24:27 -04:00
f: F,
2017-11-16 22:59:45 -08:00
) -> (hir::Generics, T)
2018-03-21 04:24:27 -04:00
where
F: FnOnce(&mut LoweringContext) -> T,
2017-11-16 22:59:45 -08:00
{
2018-03-21 04:24:27 -04:00
let (in_band_defs, (mut lowered_generics, res)) = self.with_in_scope_lifetime_defs(
2018-05-26 19:16:21 +01:00
generics.params.iter().filter_map(|param| match param.kind {
GenericParamKindAST::Lifetime { .. } => Some(param),
_ => None,
}),
2018-03-21 04:24:27 -04:00
|this| {
let itctx = ImplTraitContext::Universal(parent_id);
this.collect_in_band_defs(parent_id, anonymous_lifetime_mode, |this| {
(this.lower_generics(generics, itctx), f(this))
2018-03-21 04:24:27 -04:00
})
},
);
2017-12-15 12:27:20 -08:00
2018-03-21 04:24:27 -04:00
lowered_generics.params = lowered_generics
.params
.iter()
.cloned()
.chain(in_band_defs)
.collect();
2017-11-16 22:59:45 -08:00
(lowered_generics, res)
}
fn with_catch_scope<T, F>(&mut self, catch_id: NodeId, f: F) -> T
2018-03-21 04:24:27 -04:00
where
F: FnOnce(&mut LoweringContext) -> T,
{
let len = self.catch_scopes.len();
self.catch_scopes.push(catch_id);
let result = f(self);
2018-03-21 04:24:27 -04:00
assert_eq!(
len + 1,
self.catch_scopes.len(),
"catch scopes should be added and removed in stack order"
);
self.catch_scopes.pop().unwrap();
result
}
2016-12-26 14:34:03 +01:00
fn lower_body<F>(&mut self, decl: Option<&FnDecl>, f: F) -> hir::BodyId
2018-03-21 04:24:27 -04:00
where
F: FnOnce(&mut LoweringContext) -> hir::Expr,
2016-12-26 14:34:03 +01:00
{
let prev = mem::replace(&mut self.is_generator, false);
2016-12-26 14:34:03 +01:00
let result = f(self);
let r = self.record_body(result, decl);
2017-07-11 12:57:05 -07:00
self.is_generator = prev;
2018-03-21 04:24:27 -04:00
return r;
2016-12-26 14:34:03 +01:00
}
2017-02-15 14:52:27 -08:00
fn with_loop_scope<T, F>(&mut self, loop_id: NodeId, f: F) -> T
2018-03-21 04:24:27 -04:00
where
F: FnOnce(&mut LoweringContext) -> T,
2017-02-15 14:52:27 -08:00
{
// We're no longer in the base loop's condition; we're in another loop.
let was_in_loop_condition = self.is_in_loop_condition;
self.is_in_loop_condition = false;
2017-02-15 14:52:27 -08:00
let len = self.loop_scopes.len();
self.loop_scopes.push(loop_id);
2017-02-15 14:52:27 -08:00
let result = f(self);
2018-03-21 04:24:27 -04:00
assert_eq!(
len + 1,
self.loop_scopes.len(),
"Loop scopes should be added and removed in stack order"
);
2017-02-15 14:52:27 -08:00
self.loop_scopes.pop().unwrap();
self.is_in_loop_condition = was_in_loop_condition;
result
}
fn with_loop_condition_scope<T, F>(&mut self, f: F) -> T
2018-03-21 04:24:27 -04:00
where
F: FnOnce(&mut LoweringContext) -> T,
{
let was_in_loop_condition = self.is_in_loop_condition;
self.is_in_loop_condition = true;
let result = f(self);
self.is_in_loop_condition = was_in_loop_condition;
2017-02-15 14:52:27 -08:00
result
}
fn with_new_scopes<T, F>(&mut self, f: F) -> T
2018-03-21 04:24:27 -04:00
where
F: FnOnce(&mut LoweringContext) -> T,
2017-02-15 14:52:27 -08:00
{
let was_in_loop_condition = self.is_in_loop_condition;
self.is_in_loop_condition = false;
let catch_scopes = mem::replace(&mut self.catch_scopes, Vec::new());
2017-02-15 14:52:27 -08:00
let loop_scopes = mem::replace(&mut self.loop_scopes, Vec::new());
let result = f(self);
self.catch_scopes = catch_scopes;
self.loop_scopes = loop_scopes;
self.is_in_loop_condition = was_in_loop_condition;
2017-02-15 14:52:27 -08:00
result
}
fn def_key(&mut self, id: DefId) -> DefKey {
if id.is_local() {
self.resolver.definitions().def_key(id.index)
} else {
self.cstore.def_key(id)
}
}
2017-03-24 23:03:15 +00:00
fn lower_ident(&mut self, ident: Ident) -> Name {
let ident = ident.modern();
if ident.span.ctxt() == SyntaxContext::empty() {
2017-03-24 23:03:15 +00:00
return ident.name;
}
2018-03-21 04:24:27 -04:00
*self.name_map
.entry(ident)
.or_insert_with(|| Symbol::from_ident(ident))
2017-03-24 23:03:15 +00:00
}
fn lower_label(&mut self, label: Option<Label>) -> Option<hir::Label> {
2018-03-21 04:24:27 -04:00
label.map(|label| hir::Label {
name: label.ident.name,
2018-03-19 03:54:56 +03:00
span: label.ident.span,
2018-03-21 04:24:27 -04:00
})
}
2018-03-21 04:24:27 -04:00
fn lower_loop_destination(&mut self, destination: Option<(NodeId, Label)>) -> hir::Destination {
2017-02-17 18:55:28 -08:00
match destination {
Some((id, label)) => {
let target_id = if let Def::Label(loop_id) = self.expect_full_def(id) {
Ok(self.lower_node_id(loop_id).node_id)
} else {
Err(hir::LoopIdError::UnresolvedLabel)
};
hir::Destination {
label: self.lower_label(Some(label)),
target_id,
}
2018-03-21 04:24:27 -04:00
}
None => {
let target_id = self.loop_scopes
2018-03-21 04:24:27 -04:00
.last()
.map(|innermost_loop_id| *innermost_loop_id)
.map(|id| Ok(self.lower_node_id(id).node_id))
.unwrap_or(Err(hir::LoopIdError::OutsideLoopScope))
.into();
hir::Destination {
label: None,
target_id,
}
}
2017-02-15 14:52:27 -08:00
}
}
2018-03-21 23:11:27 +01:00
fn lower_attrs(&mut self, attrs: &[Attribute]) -> hir::HirVec<Attribute> {
2018-03-21 04:24:27 -04:00
attrs
.iter()
.map(|a| self.lower_attr(a))
.collect::<Vec<_>>()
.into()
rustc: Forbid interpolated tokens in the HIR Right now the HIR contains raw `syntax::ast::Attribute` structure but nowadays these can contain arbitrary tokens. One variant of the `Token` enum is an "interpolated" token which basically means to shove all the tokens for a nonterminal in this position. A "nonterminal" in this case is roughly analagous to a macro argument: macro_rules! foo { ($a:expr) => { // $a is a nonterminal as an expression } } Currently nonterminals contain namely items and expressions, and this poses a problem for incremental compilation! With incremental we want a stable hash of all HIR items, but this means we may transitively need a stable hash *of the entire AST*, which is certainly not stable w/ node ids and whatnot. Hence today there's a "bug" where the "stable hash" of an AST is just the raw hash value of the AST, and this only arises with interpolated nonterminals. The downside of this approach, however, is that a bunch of errors get spewed out during compilation about how this isn't a great idea. This PR is focused at fixing these warnings, basically deleting them from the compiler. The implementation here is to alter attributes as they're lowered from the AST to HIR, expanding all nonterminals in-place as we see them. This code for expanding a nonterminal to a token stream already exists for the `proc_macro` crate, so we basically just reuse the same implementation there. After this PR it's considered a bug to have an `Interpolated` token and hence the stable hash implementation simply uses `bug!` in this location. Closes #40946
2017-09-15 08:28:34 -07:00
}
fn lower_attr(&mut self, attr: &Attribute) -> Attribute {
Attribute {
id: attr.id,
style: attr.style,
path: attr.path.clone(),
tokens: self.lower_token_stream(attr.tokens.clone()),
is_sugared_doc: attr.is_sugared_doc,
span: attr.span,
}
}
fn lower_token_stream(&mut self, tokens: TokenStream) -> TokenStream {
2018-03-21 04:24:27 -04:00
tokens
.into_trees()
.flat_map(|tree| self.lower_token_tree(tree).into_trees())
.collect()
rustc: Forbid interpolated tokens in the HIR Right now the HIR contains raw `syntax::ast::Attribute` structure but nowadays these can contain arbitrary tokens. One variant of the `Token` enum is an "interpolated" token which basically means to shove all the tokens for a nonterminal in this position. A "nonterminal" in this case is roughly analagous to a macro argument: macro_rules! foo { ($a:expr) => { // $a is a nonterminal as an expression } } Currently nonterminals contain namely items and expressions, and this poses a problem for incremental compilation! With incremental we want a stable hash of all HIR items, but this means we may transitively need a stable hash *of the entire AST*, which is certainly not stable w/ node ids and whatnot. Hence today there's a "bug" where the "stable hash" of an AST is just the raw hash value of the AST, and this only arises with interpolated nonterminals. The downside of this approach, however, is that a bunch of errors get spewed out during compilation about how this isn't a great idea. This PR is focused at fixing these warnings, basically deleting them from the compiler. The implementation here is to alter attributes as they're lowered from the AST to HIR, expanding all nonterminals in-place as we see them. This code for expanding a nonterminal to a token stream already exists for the `proc_macro` crate, so we basically just reuse the same implementation there. After this PR it's considered a bug to have an `Interpolated` token and hence the stable hash implementation simply uses `bug!` in this location. Closes #40946
2017-09-15 08:28:34 -07:00
}
fn lower_token_tree(&mut self, tree: TokenTree) -> TokenStream {
rustc: Forbid interpolated tokens in the HIR Right now the HIR contains raw `syntax::ast::Attribute` structure but nowadays these can contain arbitrary tokens. One variant of the `Token` enum is an "interpolated" token which basically means to shove all the tokens for a nonterminal in this position. A "nonterminal" in this case is roughly analagous to a macro argument: macro_rules! foo { ($a:expr) => { // $a is a nonterminal as an expression } } Currently nonterminals contain namely items and expressions, and this poses a problem for incremental compilation! With incremental we want a stable hash of all HIR items, but this means we may transitively need a stable hash *of the entire AST*, which is certainly not stable w/ node ids and whatnot. Hence today there's a "bug" where the "stable hash" of an AST is just the raw hash value of the AST, and this only arises with interpolated nonterminals. The downside of this approach, however, is that a bunch of errors get spewed out during compilation about how this isn't a great idea. This PR is focused at fixing these warnings, basically deleting them from the compiler. The implementation here is to alter attributes as they're lowered from the AST to HIR, expanding all nonterminals in-place as we see them. This code for expanding a nonterminal to a token stream already exists for the `proc_macro` crate, so we basically just reuse the same implementation there. After this PR it's considered a bug to have an `Interpolated` token and hence the stable hash implementation simply uses `bug!` in this location. Closes #40946
2017-09-15 08:28:34 -07:00
match tree {
2018-03-21 04:24:27 -04:00
TokenTree::Token(span, token) => self.lower_token(token, span),
TokenTree::Delimited(span, delimited) => TokenTree::Delimited(
span,
Delimited {
rustc: Forbid interpolated tokens in the HIR Right now the HIR contains raw `syntax::ast::Attribute` structure but nowadays these can contain arbitrary tokens. One variant of the `Token` enum is an "interpolated" token which basically means to shove all the tokens for a nonterminal in this position. A "nonterminal" in this case is roughly analagous to a macro argument: macro_rules! foo { ($a:expr) => { // $a is a nonterminal as an expression } } Currently nonterminals contain namely items and expressions, and this poses a problem for incremental compilation! With incremental we want a stable hash of all HIR items, but this means we may transitively need a stable hash *of the entire AST*, which is certainly not stable w/ node ids and whatnot. Hence today there's a "bug" where the "stable hash" of an AST is just the raw hash value of the AST, and this only arises with interpolated nonterminals. The downside of this approach, however, is that a bunch of errors get spewed out during compilation about how this isn't a great idea. This PR is focused at fixing these warnings, basically deleting them from the compiler. The implementation here is to alter attributes as they're lowered from the AST to HIR, expanding all nonterminals in-place as we see them. This code for expanding a nonterminal to a token stream already exists for the `proc_macro` crate, so we basically just reuse the same implementation there. After this PR it's considered a bug to have an `Interpolated` token and hence the stable hash implementation simply uses `bug!` in this location. Closes #40946
2017-09-15 08:28:34 -07:00
delim: delimited.delim,
tts: self.lower_token_stream(delimited.tts.into()).into(),
2018-03-21 04:24:27 -04:00
},
).into(),
rustc: Forbid interpolated tokens in the HIR Right now the HIR contains raw `syntax::ast::Attribute` structure but nowadays these can contain arbitrary tokens. One variant of the `Token` enum is an "interpolated" token which basically means to shove all the tokens for a nonterminal in this position. A "nonterminal" in this case is roughly analagous to a macro argument: macro_rules! foo { ($a:expr) => { // $a is a nonterminal as an expression } } Currently nonterminals contain namely items and expressions, and this poses a problem for incremental compilation! With incremental we want a stable hash of all HIR items, but this means we may transitively need a stable hash *of the entire AST*, which is certainly not stable w/ node ids and whatnot. Hence today there's a "bug" where the "stable hash" of an AST is just the raw hash value of the AST, and this only arises with interpolated nonterminals. The downside of this approach, however, is that a bunch of errors get spewed out during compilation about how this isn't a great idea. This PR is focused at fixing these warnings, basically deleting them from the compiler. The implementation here is to alter attributes as they're lowered from the AST to HIR, expanding all nonterminals in-place as we see them. This code for expanding a nonterminal to a token stream already exists for the `proc_macro` crate, so we basically just reuse the same implementation there. After this PR it's considered a bug to have an `Interpolated` token and hence the stable hash implementation simply uses `bug!` in this location. Closes #40946
2017-09-15 08:28:34 -07:00
}
}
fn lower_token(&mut self, token: Token, span: Span) -> TokenStream {
rustc: Forbid interpolated tokens in the HIR Right now the HIR contains raw `syntax::ast::Attribute` structure but nowadays these can contain arbitrary tokens. One variant of the `Token` enum is an "interpolated" token which basically means to shove all the tokens for a nonterminal in this position. A "nonterminal" in this case is roughly analagous to a macro argument: macro_rules! foo { ($a:expr) => { // $a is a nonterminal as an expression } } Currently nonterminals contain namely items and expressions, and this poses a problem for incremental compilation! With incremental we want a stable hash of all HIR items, but this means we may transitively need a stable hash *of the entire AST*, which is certainly not stable w/ node ids and whatnot. Hence today there's a "bug" where the "stable hash" of an AST is just the raw hash value of the AST, and this only arises with interpolated nonterminals. The downside of this approach, however, is that a bunch of errors get spewed out during compilation about how this isn't a great idea. This PR is focused at fixing these warnings, basically deleting them from the compiler. The implementation here is to alter attributes as they're lowered from the AST to HIR, expanding all nonterminals in-place as we see them. This code for expanding a nonterminal to a token stream already exists for the `proc_macro` crate, so we basically just reuse the same implementation there. After this PR it's considered a bug to have an `Interpolated` token and hence the stable hash implementation simply uses `bug!` in this location. Closes #40946
2017-09-15 08:28:34 -07:00
match token {
Token::Interpolated(_) => {}
other => return TokenTree::Token(span, other).into(),
rustc: Forbid interpolated tokens in the HIR Right now the HIR contains raw `syntax::ast::Attribute` structure but nowadays these can contain arbitrary tokens. One variant of the `Token` enum is an "interpolated" token which basically means to shove all the tokens for a nonterminal in this position. A "nonterminal" in this case is roughly analagous to a macro argument: macro_rules! foo { ($a:expr) => { // $a is a nonterminal as an expression } } Currently nonterminals contain namely items and expressions, and this poses a problem for incremental compilation! With incremental we want a stable hash of all HIR items, but this means we may transitively need a stable hash *of the entire AST*, which is certainly not stable w/ node ids and whatnot. Hence today there's a "bug" where the "stable hash" of an AST is just the raw hash value of the AST, and this only arises with interpolated nonterminals. The downside of this approach, however, is that a bunch of errors get spewed out during compilation about how this isn't a great idea. This PR is focused at fixing these warnings, basically deleting them from the compiler. The implementation here is to alter attributes as they're lowered from the AST to HIR, expanding all nonterminals in-place as we see them. This code for expanding a nonterminal to a token stream already exists for the `proc_macro` crate, so we basically just reuse the same implementation there. After this PR it's considered a bug to have an `Interpolated` token and hence the stable hash implementation simply uses `bug!` in this location. Closes #40946
2017-09-15 08:28:34 -07:00
}
let tts = token.interpolated_to_tokenstream(&self.sess.parse_sess, span);
self.lower_token_stream(tts)
}
2015-07-31 00:04:06 -07:00
fn lower_arm(&mut self, arm: &Arm) -> hir::Arm {
hir::Arm {
attrs: self.lower_attrs(&arm.attrs),
pats: arm.pats.iter().map(|x| self.lower_pat(x)).collect(),
guard: arm.guard.as_ref().map(|ref x| P(self.lower_expr(x))),
body: P(self.lower_expr(&arm.body)),
}
2015-07-31 00:04:06 -07:00
}
fn lower_ty_binding(&mut self, b: &TypeBinding, itctx: ImplTraitContext) -> hir::TypeBinding {
hir::TypeBinding {
id: self.lower_node_id(b.id).node_id,
2017-03-24 23:03:15 +00:00
name: self.lower_ident(b.ident),
ty: self.lower_ty(&b.ty, itctx),
span: b.span,
}
2015-07-31 00:04:06 -07:00
}
fn lower_generic_arg(&mut self,
p: &ast::GenericArgAST,
2018-02-12 21:44:05 +00:00
itctx: ImplTraitContext)
2018-02-23 17:48:54 +00:00
-> hir::GenericArg {
match p {
ast::GenericArgAST::Lifetime(lt) => {
GenericArg::Lifetime(self.lower_lifetime(&lt))
}
ast::GenericArgAST::Type(ty) => {
GenericArg::Type(self.lower_ty(&ty, itctx))
}
}
}
fn lower_ty(&mut self, t: &Ty, itctx: ImplTraitContext) -> P<hir::Ty> {
let kind = match t.node {
TyKind::Infer => hir::TyInfer,
TyKind::Err => hir::TyErr,
TyKind::Slice(ref ty) => hir::TySlice(self.lower_ty(ty, itctx)),
TyKind::Ptr(ref mt) => hir::TyPtr(self.lower_mt(mt, itctx)),
TyKind::Rptr(ref region, ref mt) => {
let span = t.span.shrink_to_lo();
let lifetime = match *region {
Some(ref lt) => self.lower_lifetime(lt),
None => self.elided_ref_lifetime(span),
};
hir::TyRptr(lifetime, self.lower_mt(mt, itctx))
}
2018-03-21 04:24:27 -04:00
TyKind::BareFn(ref f) => self.with_in_scope_lifetime_defs(
2018-05-26 19:16:21 +01:00
f.generic_params.iter().filter_map(|param| match param.kind {
GenericParamKindAST::Lifetime { .. } => Some(param),
_ => None,
}),
2018-03-21 04:24:27 -04:00
|this| {
this.with_anonymous_lifetime_mode(
AnonymousLifetimeMode::PassThrough,
|this| {
hir::TyBareFn(P(hir::BareFnTy {
generic_params: this.lower_generic_params(
&f.generic_params,
&NodeMap(),
ImplTraitContext::Disallowed,
),
unsafety: this.lower_unsafety(f.unsafety),
abi: f.abi,
decl: this.lower_fn_decl(&f.decl, None, false),
arg_names: this.lower_fn_args_to_names(&f.decl),
}))
},
)
2018-03-21 04:24:27 -04:00
},
),
TyKind::Never => hir::TyNever,
TyKind::Tup(ref tys) => {
hir::TyTup(tys.iter().map(|ty| self.lower_ty(ty, itctx)).collect())
}
TyKind::Paren(ref ty) => {
return self.lower_ty(ty, itctx);
}
TyKind::Path(ref qself, ref path) => {
2017-09-13 18:29:59 +03:00
let id = self.lower_node_id(t.id);
let qpath = self.lower_qpath(t.id, qself, path, ParamMode::Explicit, itctx);
2018-02-22 22:44:44 -08:00
let ty = self.ty_path(id, t.span, qpath);
if let hir::TyTraitObject(..) = ty.node {
self.maybe_lint_bare_trait(t.span, t.id, qself.is_none() && path.is_global());
2018-02-22 22:44:44 -08:00
}
return ty;
}
2018-03-21 04:24:27 -04:00
TyKind::ImplicitSelf => hir::TyPath(hir::QPath::Resolved(
None,
P(hir::Path {
def: self.expect_full_def(t.id),
2018-03-21 04:24:27 -04:00
segments: hir_vec![hir::PathSegment::from_name(keywords::SelfType.name())],
span: t.span,
2018-03-21 04:24:27 -04:00
}),
)),
TyKind::Array(ref ty, ref length) => {
hir::TyArray(self.lower_ty(ty, itctx), self.lower_anon_const(length))
}
TyKind::Typeof(ref expr) => {
hir::TyTypeof(self.lower_anon_const(expr))
}
2018-02-22 22:44:44 -08:00
TyKind::TraitObject(ref bounds, kind) => {
let mut lifetime_bound = None;
2018-03-21 04:24:27 -04:00
let bounds = bounds
.iter()
.filter_map(|bound| match *bound {
TraitTyParamBound(ref ty, TraitBoundModifier::None) => {
Some(self.lower_poly_trait_ref(ty, itctx))
}
TraitTyParamBound(_, TraitBoundModifier::Maybe) => None,
RegionTyParamBound(ref lifetime) => {
if lifetime_bound.is_none() {
lifetime_bound = Some(self.lower_lifetime(lifetime));
}
None
}
2018-03-21 04:24:27 -04:00
})
.collect();
let lifetime_bound =
lifetime_bound.unwrap_or_else(|| self.elided_dyn_bound(t.span));
2018-02-22 22:44:44 -08:00
if kind != TraitObjectSyntax::Dyn {
self.maybe_lint_bare_trait(t.span, t.id, false);
2018-02-22 22:44:44 -08:00
}
hir::TyTraitObject(bounds, lifetime_bound)
}
TyKind::ImplTrait(ref bounds) => {
2017-12-15 12:27:20 -08:00
let span = t.span;
match itctx {
2018-05-22 14:31:56 +02:00
ImplTraitContext::Existential(fn_def_id) => {
// We need to manually repeat the code of `next_id` because the lowering
// needs to happen while the owner_id is pointing to the item itself,
// because items are their own owners
let exist_ty_node_id = self.sess.next_node_id();
// Make sure we know that some funky desugaring has been going on here.
// This is a first: there is code in other places like for loop
// desugaring that explicitly states that we don't want to track that.
// Not tracking it makes lints in rustc and clippy very fragile as
// frequently opened issues show.
let exist_ty_span = self.allow_internal_unstable(
CompilerDesugaringKind::ExistentialReturnType,
t.span,
);
// Pull a new definition from the ether
let exist_ty_def_index = self
.resolver
.definitions()
.create_def_with_parent(
fn_def_id.index,
exist_ty_node_id,
DefPathData::ExistentialImplTrait,
DefIndexAddressSpace::High,
Mark::root(),
exist_ty_span,
);
// the `t` is just for printing debug messages
self.allocate_hir_id_counter(exist_ty_node_id, t);
let hir_bounds = self.with_hir_id_owner(exist_ty_node_id, |lctx| {
lctx.lower_bounds(bounds, itctx)
});
2018-05-22 14:31:56 +02:00
let (lifetimes, lifetime_defs) = self.lifetimes_from_impl_trait_bounds(
exist_ty_node_id,
exist_ty_def_index,
&hir_bounds,
);
self.with_hir_id_owner(exist_ty_node_id, |lctx| {
let exist_ty_item_kind = hir::ItemExistential(hir::ExistTy {
2018-03-21 04:24:27 -04:00
generics: hir::Generics {
params: lifetime_defs,
where_clause: hir::WhereClause {
2018-05-22 14:31:56 +02:00
id: lctx.next_id().node_id,
2018-03-21 04:24:27 -04:00
predicates: Vec::new().into(),
},
span,
},
2018-03-21 04:24:27 -04:00
bounds: hir_bounds,
2018-05-22 14:31:56 +02:00
impl_trait_fn: Some(fn_def_id),
});
let exist_ty_id = lctx.lower_node_id(exist_ty_node_id);
// Generate an `existential type Foo: Trait;` declaration
trace!("creating existential type with id {:#?}", exist_ty_id);
// Set the name to `impl Bound1 + Bound2`
let exist_ty_name = Symbol::intern(&pprust::ty_to_string(t));
trace!("exist ty def index: {:#?}", exist_ty_def_index);
let exist_ty_item = hir::Item {
id: exist_ty_id.node_id,
hir_id: exist_ty_id.hir_id,
name: exist_ty_name,
attrs: Default::default(),
node: exist_ty_item_kind,
vis: hir::Visibility::Inherited,
span: exist_ty_span,
};
// Insert the item into the global list. This usually happens
// automatically for all AST items. But this existential type item
// does not actually exist in the AST.
lctx.items.insert(exist_ty_id.node_id, exist_ty_item);
// `impl Trait` now just becomes `Foo<'a, 'b, ..>`
hir::TyImplTraitExistential(
hir::ItemId {
id: exist_ty_id.node_id
},
DefId::local(exist_ty_def_index),
lifetimes,
)
})
2018-03-21 04:24:27 -04:00
}
ImplTraitContext::Universal(def_id) => {
2017-12-15 12:27:20 -08:00
let def_node_id = self.next_id().node_id;
// Add a definition for the in-band TyParam
let def_index = self.resolver.definitions().create_def_with_parent(
def_id.index,
def_node_id,
2018-05-22 14:31:56 +02:00
DefPathData::UniversalImplTrait,
2017-12-15 12:27:20 -08:00
DefIndexAddressSpace::High,
Mark::root(),
2018-03-21 04:24:27 -04:00
span,
2017-12-15 12:27:20 -08:00
);
let hir_bounds = self.lower_bounds(bounds, itctx);
2017-12-30 22:18:39 -05:00
// Set the name to `impl Bound1 + Bound2`
let name = Symbol::intern(&pprust::ty_to_string(t));
2018-05-26 00:27:54 +01:00
self.in_band_ty_params.push(hir::GenericParam {
2017-12-15 12:27:20 -08:00
id: def_node_id,
span,
pure_wrt_drop: false,
2018-05-26 00:27:54 +01:00
kind: hir::GenericParamKind::Type {
name,
bounds: hir_bounds,
default: None,
synthetic: Some(hir::SyntheticTyParamKind::ImplTrait),
attrs: P::new(),
}
2017-12-15 12:27:20 -08:00
});
2018-03-21 04:24:27 -04:00
hir::TyPath(hir::QPath::Resolved(
None,
P(hir::Path {
span,
def: Def::TyParam(DefId::local(def_index)),
segments: hir_vec![hir::PathSegment::from_name(name)],
}),
))
}
ImplTraitContext::Disallowed => {
2018-03-21 04:24:27 -04:00
span_err!(
self.sess,
t.span,
E0562,
"`impl Trait` not allowed outside of function \
and inherent method return types"
);
hir::TyErr
}
}
}
TyKind::Mac(_) => panic!("TyMac should have been expanded by now."),
};
2017-09-13 18:29:59 +03:00
let LoweredNodeId { node_id, hir_id } = self.lower_node_id(t.id);
P(hir::Ty {
2017-09-13 18:29:59 +03:00
id: node_id,
node: kind,
span: t.span,
2017-09-13 18:29:59 +03:00
hir_id,
})
}
2015-07-31 00:04:06 -07:00
fn lifetimes_from_impl_trait_bounds(
&mut self,
2018-05-22 14:31:56 +02:00
exist_ty_id: NodeId,
parent_index: DefIndex,
2018-03-21 04:24:27 -04:00
bounds: &hir::TyParamBounds,
) -> (HirVec<hir::Lifetime>, HirVec<hir::GenericParam>) {
// This visitor walks over impl trait bounds and creates defs for all lifetimes which
// appear in the bounds, excluding lifetimes that are created within the bounds.
// e.g. 'a, 'b, but not 'c in `impl for<'c> SomeTrait<'a, 'b, 'c>`
struct ImplTraitLifetimeCollector<'r, 'a: 'r> {
context: &'r mut LoweringContext<'a>,
parent: DefIndex,
2018-05-22 14:31:56 +02:00
exist_ty_id: NodeId,
2017-12-09 21:54:58 -08:00
collect_elided_lifetimes: bool,
currently_bound_lifetimes: Vec<hir::LifetimeName>,
already_defined_lifetimes: HashSet<hir::LifetimeName>,
output_lifetimes: Vec<hir::Lifetime>,
output_lifetime_params: Vec<hir::GenericParam>,
}
impl<'r, 'a: 'r, 'v> hir::intravisit::Visitor<'v> for ImplTraitLifetimeCollector<'r, 'a> {
2018-03-21 04:24:27 -04:00
fn nested_visit_map<'this>(
&'this mut self,
) -> hir::intravisit::NestedVisitorMap<'this, 'v> {
hir::intravisit::NestedVisitorMap::None
}
fn visit_generic_args(&mut self, span: Span, parameters: &'v hir::GenericArgs) {
2017-12-09 21:54:58 -08:00
// Don't collect elided lifetimes used inside of `Fn()` syntax.
if parameters.parenthesized {
let old_collect_elided_lifetimes = self.collect_elided_lifetimes;
self.collect_elided_lifetimes = false;
hir::intravisit::walk_generic_args(self, span, parameters);
2017-12-09 21:54:58 -08:00
self.collect_elided_lifetimes = old_collect_elided_lifetimes;
} else {
hir::intravisit::walk_generic_args(self, span, parameters);
2017-12-09 21:54:58 -08:00
}
}
fn visit_ty(&mut self, t: &'v hir::Ty) {
// Don't collect elided lifetimes used inside of `fn()` syntax
if let &hir::Ty_::TyBareFn(_) = &t.node {
let old_collect_elided_lifetimes = self.collect_elided_lifetimes;
self.collect_elided_lifetimes = false;
// Record the "stack height" of `for<'a>` lifetime bindings
// to be able to later fully undo their introduction.
let old_len = self.currently_bound_lifetimes.len();
2017-12-09 21:54:58 -08:00
hir::intravisit::walk_ty(self, t);
self.currently_bound_lifetimes.truncate(old_len);
2017-12-09 21:54:58 -08:00
self.collect_elided_lifetimes = old_collect_elided_lifetimes;
} else {
hir::intravisit::walk_ty(self, t);
}
}
2018-03-21 04:24:27 -04:00
fn visit_poly_trait_ref(
&mut self,
trait_ref: &'v hir::PolyTraitRef,
modifier: hir::TraitBoundModifier,
2018-03-21 04:24:27 -04:00
) {
// Record the "stack height" of `for<'a>` lifetime bindings
// to be able to later fully undo their introduction.
let old_len = self.currently_bound_lifetimes.len();
hir::intravisit::walk_poly_trait_ref(self, trait_ref, modifier);
self.currently_bound_lifetimes.truncate(old_len);
}
fn visit_generic_param(&mut self, param: &'v hir::GenericParam) {
// Record the introduction of 'a in `for<'a> ...`
2018-05-26 00:27:54 +01:00
if let hir::GenericParamKind::Lifetime { name, .. } = param.kind {
// Introduce lifetimes one at a time so that we can handle
// cases like `fn foo<'d>() -> impl for<'a, 'b: 'a, 'c: 'b + 'd>`
2018-05-26 00:27:54 +01:00
self.currently_bound_lifetimes.push(name);
}
hir::intravisit::walk_generic_param(self, param);
}
fn visit_lifetime(&mut self, lifetime: &'v hir::Lifetime) {
2017-12-09 21:54:58 -08:00
let name = match lifetime.name {
2018-03-21 04:24:27 -04:00
hir::LifetimeName::Implicit | hir::LifetimeName::Underscore => {
2017-12-09 21:54:58 -08:00
if self.collect_elided_lifetimes {
// Use `'_` for both implicit and underscore lifetimes in
// `abstract type Foo<'_>: SomeTrait<'_>;`
hir::LifetimeName::Underscore
} else {
2018-03-21 04:24:27 -04:00
return;
2017-12-09 21:54:58 -08:00
}
2018-03-21 04:24:27 -04:00
}
name @ hir::LifetimeName::Fresh(_) => name,
2017-12-09 21:54:58 -08:00
name @ hir::LifetimeName::Name(_) => name,
hir::LifetimeName::Static => return,
};
2018-03-21 04:24:27 -04:00
if !self.currently_bound_lifetimes.contains(&name)
&& !self.already_defined_lifetimes.contains(&name)
2017-12-09 21:54:58 -08:00
{
self.already_defined_lifetimes.insert(name);
self.output_lifetimes.push(hir::Lifetime {
id: self.context.next_id().node_id,
span: lifetime.span,
name,
});
2018-05-22 14:31:56 +02:00
// We need to manually create the ids here, because the
// definitions will go into the explicit `existential type`
// declaration and thus need to have their owner set to that item
let def_node_id = self.context.sess.next_node_id();
let _ = self.context.lower_node_id_with_owner(def_node_id, self.exist_ty_id);
2017-12-09 21:54:58 -08:00
self.context.resolver.definitions().create_def_with_parent(
self.parent,
def_node_id,
DefPathData::LifetimeDef(name.name().as_interned_str()),
2017-12-09 21:54:58 -08:00
DefIndexAddressSpace::High,
Mark::root(),
2018-03-21 04:24:27 -04:00
lifetime.span,
2017-12-09 21:54:58 -08:00
);
2018-05-26 00:27:54 +01:00
self.output_lifetime_params.push(hir::GenericParam {
2017-12-09 21:54:58 -08:00
id: def_node_id,
span: lifetime.span,
2018-05-26 00:27:54 +01:00
pure_wrt_drop: false,
kind: hir::GenericParamKind::Lifetime {
name,
bounds: vec![].into(),
2018-03-21 04:24:27 -04:00
in_band: false,
2018-05-26 00:27:54 +01:00
lifetime_deprecated: hir::Lifetime {
id: def_node_id,
span: lifetime.span,
name,
}
}
});
}
}
}
let mut lifetime_collector = ImplTraitLifetimeCollector {
context: self,
parent: parent_index,
2018-05-22 14:31:56 +02:00
exist_ty_id,
2017-12-09 21:54:58 -08:00
collect_elided_lifetimes: true,
currently_bound_lifetimes: Vec::new(),
already_defined_lifetimes: HashSet::new(),
output_lifetimes: Vec::new(),
output_lifetime_params: Vec::new(),
};
for bound in bounds {
hir::intravisit::walk_ty_param_bound(&mut lifetime_collector, &bound);
}
(
lifetime_collector.output_lifetimes.into(),
2018-03-21 04:24:27 -04:00
lifetime_collector.output_lifetime_params.into(),
)
}
fn lower_foreign_mod(&mut self, fm: &ForeignMod) -> hir::ForeignMod {
hir::ForeignMod {
abi: fm.abi,
2018-03-21 04:24:27 -04:00
items: fm.items
.iter()
.map(|x| self.lower_foreign_item(x))
.collect(),
}
2015-07-31 00:04:06 -07:00
}
2017-03-15 21:27:40 -05:00
fn lower_global_asm(&mut self, ga: &GlobalAsm) -> P<hir::GlobalAsm> {
P(hir::GlobalAsm {
asm: ga.asm,
ctxt: ga.ctxt,
})
}
fn lower_variant(&mut self, v: &Variant) -> hir::Variant {
Spanned {
node: hir::Variant_ {
name: v.node.ident.name,
attrs: self.lower_attrs(&v.node.attrs),
data: self.lower_variant_data(&v.node.data),
disr_expr: v.node.disr_expr.as_ref().map(|e| self.lower_anon_const(e)),
},
span: v.span,
}
2015-07-31 00:04:06 -07:00
}
2018-03-21 04:24:27 -04:00
fn lower_qpath(
&mut self,
id: NodeId,
qself: &Option<QSelf>,
p: &Path,
param_mode: ParamMode,
itctx: ImplTraitContext,
) -> hir::QPath {
let qself_position = qself.as_ref().map(|q| q.position);
let qself = qself.as_ref().map(|q| self.lower_ty(&q.ty, itctx));
2018-03-21 04:24:27 -04:00
let resolution = self.resolver
.get_resolution(id)
.unwrap_or(PathResolution::new(Def::Err));
let proj_start = p.segments.len() - resolution.unresolved_segments();
let path = P(hir::Path {
def: resolution.base_def(),
2018-03-21 04:24:27 -04:00
segments: p.segments[..proj_start]
.iter()
.enumerate()
.map(|(i, segment)| {
let param_mode = match (qself_position, param_mode) {
(Some(j), ParamMode::Optional) if i < j => {
// This segment is part of the trait path in a
// qualified path - one of `a`, `b` or `Trait`
// in `<X as a::b::Trait>::T::U::method`.
ParamMode::Explicit
}
_ => param_mode,
};
2018-03-21 04:24:27 -04:00
// Figure out if this is a type/trait segment,
// which may need lifetime elision performed.
let parent_def_id = |this: &mut Self, def_id: DefId| DefId {
krate: def_id.krate,
2018-03-21 04:24:27 -04:00
index: this.def_key(def_id).parent.expect("missing parent"),
};
let type_def_id = match resolution.base_def() {
Def::AssociatedTy(def_id) if i + 2 == proj_start => {
Some(parent_def_id(self, def_id))
}
Def::Variant(def_id) if i + 1 == proj_start => {
Some(parent_def_id(self, def_id))
}
Def::Struct(def_id)
| Def::Union(def_id)
| Def::Enum(def_id)
| Def::TyAlias(def_id)
| Def::Trait(def_id) if i + 1 == proj_start =>
{
Some(def_id)
}
_ => None,
};
let parenthesized_generic_args = match resolution.base_def() {
// `a::b::Trait(Args)`
Def::Trait(..) if i + 1 == proj_start => ParenthesizedGenericArgs::Ok,
// `a::b::Trait(Args)::TraitItem`
Def::Method(..) | Def::AssociatedConst(..) | Def::AssociatedTy(..)
if i + 2 == proj_start =>
{
ParenthesizedGenericArgs::Ok
}
// Avoid duplicated errors
Def::Err => ParenthesizedGenericArgs::Ok,
// An error
Def::Struct(..)
| Def::Enum(..)
| Def::Union(..)
| Def::TyAlias(..)
| Def::Variant(..) if i + 1 == proj_start =>
{
ParenthesizedGenericArgs::Err
}
// A warning for now, for compatibility reasons
_ => ParenthesizedGenericArgs::Warn,
};
2018-03-21 04:24:27 -04:00
let num_lifetimes = type_def_id.map_or(0, |def_id| {
if let Some(&n) = self.type_def_lifetime_params.get(&def_id) {
return n;
}
assert!(!def_id.is_local());
2018-02-25 00:31:26 +00:00
let item_generics =
self.cstore.item_generics_cloned_untracked(def_id, self.sess);
let n = item_generics.own_counts().lifetimes;
2018-03-21 04:24:27 -04:00
self.type_def_lifetime_params.insert(def_id, n);
n
});
self.lower_path_segment(
p.span,
segment,
param_mode,
num_lifetimes,
parenthesized_generic_args,
itctx,
)
})
.collect(),
span: p.span,
});
// Simple case, either no projections, or only fully-qualified.
// E.g. `std::mem::size_of` or `<I as Iterator>::Item`.
if resolution.unresolved_segments() == 0 {
return hir::QPath::Resolved(qself, path);
}
// Create the innermost type that we're projecting from.
let mut ty = if path.segments.is_empty() {
// If the base path is empty that means there exists a
// syntactical `Self`, e.g. `&i32` in `<&i32>::clone`.
qself.expect("missing QSelf for <T>::...")
} else {
// Otherwise, the base path is an implicit `Self` type path,
// e.g. `Vec` in `Vec::new` or `<I as Iterator>::Item` in
// `<I as Iterator>::Item::default`.
2017-09-13 18:29:59 +03:00
let new_id = self.next_id();
self.ty_path(new_id, p.span, hir::QPath::Resolved(qself, path))
};
// Anything after the base path are associated "extensions",
// out of which all but the last one are associated types,
// e.g. for `std::vec::Vec::<T>::IntoIter::Item::clone`:
// * base path is `std::vec::Vec<T>`
// * "extensions" are `IntoIter`, `Item` and `clone`
// * type nodes are:
// 1. `std::vec::Vec<T>` (created above)
// 2. `<std::vec::Vec<T>>::IntoIter`
// 3. `<<std::vec::Vec<T>>::IntoIter>::Item`
// * final path is `<<<std::vec::Vec<T>>::IntoIter>::Item>::clone`
for (i, segment) in p.segments.iter().enumerate().skip(proj_start) {
2018-03-21 04:24:27 -04:00
let segment = P(self.lower_path_segment(
p.span,
segment,
param_mode,
0,
ParenthesizedGenericArgs::Warn,
itctx,
));
let qpath = hir::QPath::TypeRelative(ty, segment);
// It's finished, return the extension of the right node type.
if i == p.segments.len() - 1 {
return qpath;
}
// Wrap the associated extension in another type node.
2017-09-13 18:29:59 +03:00
let new_id = self.next_id();
ty = self.ty_path(new_id, p.span, qpath);
}
// Should've returned in the for loop above.
2018-03-21 04:24:27 -04:00
span_bug!(
p.span,
"lower_qpath: no final extension segment in {}..{}",
proj_start,
p.segments.len()
)
2015-07-31 00:04:06 -07:00
}
2018-03-21 04:24:27 -04:00
fn lower_path_extra(
&mut self,
def: Def,
2018-03-21 04:24:27 -04:00
p: &Path,
name: Option<Name>,
param_mode: ParamMode,
) -> hir::Path {
hir::Path {
def,
2018-03-21 04:24:27 -04:00
segments: p.segments
.iter()
.map(|segment| {
self.lower_path_segment(
p.span,
segment,
param_mode,
0,
ParenthesizedGenericArgs::Err,
ImplTraitContext::Disallowed,
)
})
.chain(name.map(|name| hir::PathSegment::from_name(name)))
.collect(),
span: p.span,
}
}
2018-03-21 04:24:27 -04:00
fn lower_path(&mut self, id: NodeId, p: &Path, param_mode: ParamMode) -> hir::Path {
let def = self.expect_full_def(id);
self.lower_path_extra(def, p, None, param_mode)
}
2018-03-21 04:24:27 -04:00
fn lower_path_segment(
&mut self,
path_span: Span,
segment: &PathSegment,
param_mode: ParamMode,
expected_lifetimes: usize,
parenthesized_generic_args: ParenthesizedGenericArgs,
itctx: ImplTraitContext,
) -> hir::PathSegment {
2018-02-23 17:48:54 +00:00
let (mut generic_args, infer_types) = if let Some(ref generic_args) = segment.args {
let msg = "parenthesized parameters may only be used with a trait";
match **generic_args {
GenericArgs::AngleBracketed(ref data) => {
self.lower_angle_bracketed_parameter_data(data, param_mode, itctx)
2016-12-10 06:45:58 +00:00
}
GenericArgs::Parenthesized(ref data) => match parenthesized_generic_args {
2018-03-21 04:24:27 -04:00
ParenthesizedGenericArgs::Ok => self.lower_parenthesized_parameter_data(data),
ParenthesizedGenericArgs::Warn => {
2018-03-21 04:24:27 -04:00
self.sess.buffer_lint(
PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES,
CRATE_NODE_ID,
data.span,
msg.into(),
);
(hir::GenericArgs::none(), true)
}
ParenthesizedGenericArgs::Err => {
struct_span_err!(self.sess, data.span, E0214, "{}", msg)
2018-03-21 04:24:27 -04:00
.span_label(data.span, "only traits may use parentheses")
.emit();
(hir::GenericArgs::none(), true)
}
2018-03-21 04:24:27 -04:00
},
}
2016-12-10 06:45:58 +00:00
} else {
self.lower_angle_bracketed_parameter_data(&Default::default(), param_mode, itctx)
};
if !generic_args.parenthesized && generic_args.lifetimes().count() == 0 {
2018-02-23 17:48:54 +00:00
generic_args.args =
self.elided_path_lifetimes(path_span, expected_lifetimes)
.into_iter()
.map(|lt| GenericArg::Lifetime(lt))
.chain(generic_args.args.into_iter())
.collect();
}
hir::PathSegment::new(
2018-02-23 17:48:54 +00:00
self.lower_ident(segment.ident),
generic_args,
infer_types,
)
2015-07-31 00:04:06 -07:00
}
2018-03-21 04:24:27 -04:00
fn lower_angle_bracketed_parameter_data(
&mut self,
2018-02-23 17:48:54 +00:00
data: &AngleBracketedArgs,
2018-03-21 04:24:27 -04:00
param_mode: ParamMode,
itctx: ImplTraitContext,
) -> (hir::GenericArgs, bool) {
2018-02-23 17:48:54 +00:00
let &AngleBracketedArgs { ref args, ref bindings, .. } = data;
(hir::GenericArgs {
args: args.iter().map(|a| self.lower_generic_arg(a, itctx)).collect(),
bindings: bindings.iter().map(|b| self.lower_ty_binding(b, itctx)).collect(),
parenthesized: false,
},
data.types().count() == 0 && param_mode == ParamMode::Optional)
2015-07-31 00:04:06 -07:00
}
2018-03-21 04:24:27 -04:00
fn lower_parenthesized_parameter_data(
&mut self,
data: &ParenthesizedParameterData,
) -> (hir::PathParameters, bool) {
// Switch to `PassThrough` mode for anonymous lifetimes: this
// means that we permit things like `&Ref<T>`, where `Ref` has
// a hidden lifetime parameter. This is needed for backwards
// compatibility, even in contexts like an impl header where
// we generally don't permit such things (see #51008).
self.with_anonymous_lifetime_mode(
AnonymousLifetimeMode::PassThrough,
|this| {
const DISALLOWED: ImplTraitContext = ImplTraitContext::Disallowed;
2018-02-23 17:48:54 +00:00
let &ParenthesizedParameterData { ref inputs, ref output, span } = data;
let inputs = inputs.iter().map(|ty| this.lower_ty(ty, DISALLOWED)).collect();
let mk_tup = |this: &mut Self, tys, span| {
let LoweredNodeId { node_id, hir_id } = this.next_id();
2018-02-23 17:48:54 +00:00
P(hir::Ty { node: hir::TyTup(tys), id: node_id, hir_id, span })
};
(
hir::GenericArgs {
parameters: hir_vec![GenericArg::Type(mk_tup(this, inputs, span))],
bindings: hir_vec![
hir::TypeBinding {
id: this.next_id().node_id,
name: Symbol::intern(FN_OUTPUT_NAME),
ty: output
.as_ref()
.map(|ty| this.lower_ty(&ty, DISALLOWED))
.unwrap_or_else(|| mk_tup(this, hir::HirVec::new(), span)),
span: output.as_ref().map_or(span, |ty| ty.span),
}
],
parenthesized: true,
},
false,
)
}
2018-03-21 04:24:27 -04:00
)
2015-10-06 16:03:56 +13:00
}
2015-07-31 00:04:06 -07:00
fn lower_local(&mut self, l: &Local) -> P<hir::Local> {
let LoweredNodeId { node_id, hir_id } = self.lower_node_id(l.id);
P(hir::Local {
id: node_id,
hir_id,
2018-03-21 04:24:27 -04:00
ty: l.ty
.as_ref()
.map(|t| self.lower_ty(t, ImplTraitContext::Disallowed)),
pat: self.lower_pat(&l.pat),
init: l.init.as_ref().map(|e| P(self.lower_expr(e))),
span: l.span,
attrs: l.attrs.clone(),
source: hir::LocalSource::Normal,
})
2015-10-06 16:03:56 +13:00
}
2015-07-31 00:04:06 -07:00
fn lower_mutability(&mut self, m: Mutability) -> hir::Mutability {
match m {
Mutability::Mutable => hir::MutMutable,
Mutability::Immutable => hir::MutImmutable,
}
2015-07-31 00:04:06 -07:00
}
fn lower_arg(&mut self, arg: &Arg) -> hir::Arg {
let LoweredNodeId { node_id, hir_id } = self.lower_node_id(arg.id);
hir::Arg {
id: node_id,
hir_id,
pat: self.lower_pat(&arg.pat),
}
2015-09-28 08:23:31 +13:00
}
2015-07-31 00:04:06 -07:00
2018-03-21 04:24:27 -04:00
fn lower_fn_args_to_names(&mut self, decl: &FnDecl) -> hir::HirVec<Spanned<Name>> {
decl.inputs
.iter()
.map(|arg| match arg.pat.node {
2018-03-18 16:47:09 +03:00
PatKind::Ident(_, ident, None) => respan(ident.span, ident.name),
_ => respan(arg.pat.span, keywords::Invalid.name()),
2018-03-21 04:24:27 -04:00
})
.collect()
}
2018-03-21 04:24:27 -04:00
fn lower_fn_decl(
&mut self,
decl: &FnDecl,
fn_def_id: Option<DefId>,
impl_trait_return_allow: bool,
) -> P<hir::FnDecl> {
// NOTE: The two last parameters here have to do with impl Trait. If fn_def_id is Some,
// then impl Trait arguments are lowered into generic parameters on the given
// fn_def_id, otherwise impl Trait is disallowed. (for now)
//
// Furthermore, if impl_trait_return_allow is true, then impl Trait may be used in
// return positions as well. This guards against trait declarations and their impls
// where impl Trait is disallowed. (again for now)
P(hir::FnDecl {
2018-03-21 04:24:27 -04:00
inputs: decl.inputs
.iter()
.map(|arg| {
if let Some(def_id) = fn_def_id {
self.lower_ty(&arg.ty, ImplTraitContext::Universal(def_id))
} else {
self.lower_ty(&arg.ty, ImplTraitContext::Disallowed)
}
})
.collect(),
output: match decl.output {
FunctionRetTy::Ty(ref ty) => match fn_def_id {
2018-05-22 14:31:56 +02:00
Some(def_id) if impl_trait_return_allow => {
hir::Return(self.lower_ty(ty, ImplTraitContext::Existential(def_id)))
2018-03-21 04:24:27 -04:00
}
_ => hir::Return(self.lower_ty(ty, ImplTraitContext::Disallowed)),
},
FunctionRetTy::Default(span) => hir::DefaultReturn(span),
},
variadic: decl.variadic,
2018-03-21 04:24:27 -04:00
has_implicit_self: decl.inputs.get(0).map_or(false, |arg| match arg.ty.node {
TyKind::ImplicitSelf => true,
TyKind::Rptr(_, ref mt) => mt.ty.node == TyKind::ImplicitSelf,
_ => false,
}),
})
}
2015-07-31 00:04:06 -07:00
2018-03-21 04:24:27 -04:00
fn lower_ty_param_bound(
&mut self,
tpb: &TyParamBound,
itctx: ImplTraitContext,
) -> hir::TyParamBound {
match *tpb {
2018-03-21 04:24:27 -04:00
TraitTyParamBound(ref ty, modifier) => hir::TraitTyParamBound(
self.lower_poly_trait_ref(ty, itctx),
self.lower_trait_bound_modifier(modifier),
),
RegionTyParamBound(ref lifetime) => {
hir::RegionTyParamBound(self.lower_lifetime(lifetime))
}
}
}
2015-07-31 00:04:06 -07:00
fn lower_lifetime(&mut self, l: &Lifetime) -> hir::Lifetime {
2018-03-19 03:54:56 +03:00
let span = l.ident.span;
match self.lower_ident(l.ident) {
2018-03-19 03:54:56 +03:00
x if x == "'static" => self.new_named_lifetime(l.id, span, hir::LifetimeName::Static),
x if x == "'_" => match self.anonymous_lifetime_mode {
AnonymousLifetimeMode::CreateParameter => {
2018-03-19 03:54:56 +03:00
let fresh_name = self.collect_fresh_in_band_lifetime(span);
self.new_named_lifetime(l.id, span, fresh_name)
}
AnonymousLifetimeMode::PassThrough => {
2018-03-19 03:54:56 +03:00
self.new_named_lifetime(l.id, span, hir::LifetimeName::Underscore)
}
},
2017-11-16 22:59:45 -08:00
name => {
2018-03-19 03:54:56 +03:00
self.maybe_collect_in_band_lifetime(span, name);
self.new_named_lifetime(l.id, span, hir::LifetimeName::Name(name))
2017-11-16 22:59:45 -08:00
}
}
}
2017-11-16 22:59:45 -08:00
fn new_named_lifetime(
&mut self,
id: NodeId,
span: Span,
name: hir::LifetimeName,
) -> hir::Lifetime {
hir::Lifetime {
id: self.lower_node_id(id).node_id,
span,
name: name,
2015-07-31 00:04:06 -07:00
}
}
2018-05-26 00:27:54 +01:00
fn lower_generic_param(&mut self,
param: &GenericParamAST,
add_bounds: &NodeMap<Vec<TyParamBound>>,
itctx: ImplTraitContext)
-> hir::GenericParam {
2018-05-26 19:16:21 +01:00
match param.kind {
GenericParamKindAST::Lifetime { ref bounds, ref lifetime, .. } => {
2018-05-26 00:27:54 +01:00
let was_collecting_in_band = self.is_collecting_in_band_lifetimes;
self.is_collecting_in_band_lifetimes = false;
2018-05-26 19:16:21 +01:00
let lifetime = self.lower_lifetime(lifetime);
2018-05-26 00:27:54 +01:00
let param = hir::GenericParam {
id: lifetime.id,
span: lifetime.span,
2018-05-26 19:16:21 +01:00
pure_wrt_drop: attr::contains_name(&param.attrs, "may_dangle"),
2018-05-26 00:27:54 +01:00
kind: hir::GenericParamKind::Lifetime {
name: lifetime.name,
2018-05-26 19:16:21 +01:00
bounds: bounds.iter().map(|lt| self.lower_lifetime(lt)).collect(),
2018-05-26 00:27:54 +01:00
in_band: false,
lifetime_deprecated: lifetime,
}
};
2017-11-16 22:59:45 -08:00
2018-05-26 00:27:54 +01:00
self.is_collecting_in_band_lifetimes = was_collecting_in_band;
2017-11-16 22:59:45 -08:00
2018-05-26 00:27:54 +01:00
param
}
2018-05-26 19:16:21 +01:00
GenericParamKindAST::Type { ref bounds, ref default } => {
let mut name = self.lower_ident(param.ident);
2018-05-26 00:27:54 +01:00
// Don't expose `Self` (recovered "keyword used as ident" parse error).
// `rustc::ty` expects `Self` to be only used for a trait's `Self`.
// Instead, use gensym("Self") to create a distinct name that looks the same.
if name == keywords::SelfType.name() {
name = Symbol::gensym("Self");
}
2018-05-26 19:16:21 +01:00
let mut bounds = self.lower_bounds(bounds, itctx);
let add_bounds = add_bounds.get(&param.id).map_or(&[][..], |x| &x);
2018-05-26 00:27:54 +01:00
if !add_bounds.is_empty() {
bounds = bounds
.into_iter()
.chain(self.lower_bounds(add_bounds, itctx).into_iter())
.collect();
}
2017-11-16 22:59:45 -08:00
2018-05-26 00:27:54 +01:00
hir::GenericParam {
2018-05-26 19:16:21 +01:00
id: self.lower_node_id(param.id).node_id,
span: param.ident.span,
pure_wrt_drop: attr::contains_name(&param.attrs, "may_dangle"),
2018-05-26 00:27:54 +01:00
kind: hir::GenericParamKind::Type {
name,
bounds,
2018-05-26 19:16:21 +01:00
default: default.as_ref().map(|x| {
self.lower_ty(x, ImplTraitContext::Disallowed)
}),
synthetic: param.attrs.iter()
.filter(|attr| attr.check_name("rustc_synthetic"))
.map(|_| hir::SyntheticTyParamKind::ImplTrait)
.nth(0),
attrs: self.lower_attrs(&param.attrs),
2018-05-26 00:27:54 +01:00
}
}
}
}
}
2015-07-31 00:04:06 -07:00
fn lower_generic_params(
&mut self,
params: &Vec<GenericParamAST>,
add_bounds: &NodeMap<Vec<TyParamBound>>,
itctx: ImplTraitContext,
) -> hir::HirVec<hir::GenericParam> {
2018-05-26 00:27:54 +01:00
params.iter().map(|param| self.lower_generic_param(param, add_bounds, itctx)).collect()
2015-07-31 00:04:06 -07:00
}
2018-05-26 19:16:21 +01:00
fn lower_generics(
&mut self,
generics: &Generics,
itctx: ImplTraitContext)
-> hir::Generics
{
2016-10-22 03:33:36 +03:00
// Collect `?Trait` bounds in where clause and move them to parameter definitions.
// FIXME: This could probably be done with less rightward drift. Also looks like two control
// paths where report_error is called are also the only paths that advance to after
// the match statement, so the error reporting could probably just be moved there.
2016-10-22 03:33:36 +03:00
let mut add_bounds = NodeMap();
2018-05-26 19:16:21 +01:00
for pred in &generics.where_clause.predicates {
2016-10-22 03:33:36 +03:00
if let WherePredicate::BoundPredicate(ref bound_pred) = *pred {
'next_bound: for bound in &bound_pred.bounds {
if let TraitTyParamBound(_, TraitBoundModifier::Maybe) = *bound {
let report_error = |this: &mut Self| {
2018-03-21 04:24:27 -04:00
this.diagnostic().span_err(
bound_pred.bounded_ty.span,
"`?Trait` bounds are only permitted at the \
point where a type parameter is declared",
);
2016-10-22 03:33:36 +03:00
};
// Check if the where clause type is a plain type parameter.
match bound_pred.bounded_ty.node {
TyKind::Path(None, ref path)
2018-03-21 04:24:27 -04:00
if path.segments.len() == 1
&& bound_pred.bound_generic_params.is_empty() =>
{
if let Some(Def::TyParam(def_id)) = self.resolver
.get_resolution(bound_pred.bounded_ty.id)
.map(|d| d.base_def())
{
2016-10-22 03:33:36 +03:00
if let Some(node_id) =
2018-03-21 04:24:27 -04:00
self.resolver.definitions().as_local_node_id(def_id)
{
2018-05-26 19:16:21 +01:00
for param in &generics.params {
match param.kind {
GenericParamKindAST::Type { .. } => {
if node_id == param.id {
add_bounds.entry(param.id)
.or_insert(Vec::new())
.push(bound.clone());
continue 'next_bound;
}
}
2018-05-26 19:16:21 +01:00
_ => {}
2016-10-22 03:33:36 +03:00
}
}
}
}
report_error(self)
}
2018-03-21 04:24:27 -04:00
_ => report_error(self),
2016-10-22 03:33:36 +03:00
}
}
}
}
}
hir::Generics {
2018-05-26 19:16:21 +01:00
params: self.lower_generic_params(&generics.params, &add_bounds, itctx),
where_clause: self.lower_where_clause(&generics.where_clause),
span: generics.span,
}
}
2015-07-31 00:04:06 -07:00
fn lower_where_clause(&mut self, wc: &WhereClause) -> hir::WhereClause {
hir::WhereClause {
id: self.lower_node_id(wc.id).node_id,
predicates: wc.predicates
2018-03-21 04:24:27 -04:00
.iter()
.map(|predicate| self.lower_where_predicate(predicate))
.collect(),
}
2015-10-06 16:03:56 +13:00
}
2015-07-31 00:04:06 -07:00
fn lower_where_predicate(&mut self, pred: &WherePredicate) -> hir::WherePredicate {
match *pred {
2018-03-21 04:24:27 -04:00
WherePredicate::BoundPredicate(WhereBoundPredicate {
ref bound_generic_params,
ref bounded_ty,
ref bounds,
span,
}) => {
self.with_in_scope_lifetime_defs(
2018-05-26 19:16:21 +01:00
bound_generic_params.iter().filter_map(|param| match param.kind {
GenericParamKindAST::Lifetime { .. } => Some(param),
_ => None,
}),
|this| {
hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate {
2018-03-21 04:24:27 -04:00
bound_generic_params: this.lower_generic_params(
bound_generic_params,
&NodeMap(),
ImplTraitContext::Disallowed,
2018-03-21 04:24:27 -04:00
),
bounded_ty: this.lower_ty(bounded_ty, ImplTraitContext::Disallowed),
2018-03-21 04:24:27 -04:00
bounds: bounds
.iter()
.filter_map(|bound| match *bound {
// Ignore `?Trait` bounds.
// Tthey were copied into type parameters already.
TraitTyParamBound(_, TraitBoundModifier::Maybe) => None,
_ => Some(this.lower_ty_param_bound(
bound,
ImplTraitContext::Disallowed,
)),
})
.collect(),
span,
})
2018-03-21 04:24:27 -04:00
},
)
}
2018-03-21 04:24:27 -04:00
WherePredicate::RegionPredicate(WhereRegionPredicate {
ref lifetime,
ref bounds,
span,
}) => hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate {
span,
lifetime: self.lower_lifetime(lifetime),
bounds: bounds
.iter()
.map(|bound| self.lower_lifetime(bound))
.collect(),
}),
WherePredicate::EqPredicate(WhereEqPredicate {
id,
ref lhs_ty,
ref rhs_ty,
span,
}) => hir::WherePredicate::EqPredicate(hir::WhereEqPredicate {
id: self.lower_node_id(id).node_id,
lhs_ty: self.lower_ty(lhs_ty, ImplTraitContext::Disallowed),
rhs_ty: self.lower_ty(rhs_ty, ImplTraitContext::Disallowed),
span,
}),
2015-07-31 00:04:06 -07:00
}
}
fn lower_variant_data(&mut self, vdata: &VariantData) -> hir::VariantData {
match *vdata {
2018-03-21 04:24:27 -04:00
VariantData::Struct(ref fields, id) => hir::VariantData::Struct(
fields
.iter()
.enumerate()
.map(|f| self.lower_struct_field(f))
.collect(),
self.lower_node_id(id).node_id,
),
VariantData::Tuple(ref fields, id) => hir::VariantData::Tuple(
fields
.iter()
.enumerate()
.map(|f| self.lower_struct_field(f))
.collect(),
self.lower_node_id(id).node_id,
),
VariantData::Unit(id) => hir::VariantData::Unit(self.lower_node_id(id).node_id),
2015-07-31 00:04:06 -07:00
}
}
fn lower_trait_ref(&mut self, p: &TraitRef, itctx: ImplTraitContext) -> hir::TraitRef {
let path = match self.lower_qpath(p.ref_id, &None, &p.path, ParamMode::Explicit, itctx) {
hir::QPath::Resolved(None, path) => path.and_then(|path| path),
2018-03-21 04:24:27 -04:00
qpath => bug!("lower_trait_ref: unexpected QPath `{:?}`", qpath),
};
hir::TraitRef {
path,
ref_id: self.lower_node_id(p.ref_id).node_id,
2015-07-31 00:04:06 -07:00
}
}
2018-03-21 04:24:27 -04:00
fn lower_poly_trait_ref(
&mut self,
p: &PolyTraitRef,
itctx: ImplTraitContext,
) -> hir::PolyTraitRef {
let bound_generic_params =
self.lower_generic_params(&p.bound_generic_params, &NodeMap(), itctx);
let trait_ref = self.with_parent_impl_lifetime_defs(
2018-03-21 04:24:27 -04:00
&bound_generic_params
.iter()
2018-05-26 00:27:54 +01:00
.filter_map(|param| match param.kind {
hir::GenericParamKind::Lifetime { .. } => Some(param.clone()),
_ => None,
})
.collect::<Vec<_>>(),
|this| this.lower_trait_ref(&p.trait_ref, itctx),
);
2017-11-16 22:59:45 -08:00
hir::PolyTraitRef {
bound_generic_params,
2017-11-16 22:59:45 -08:00
trait_ref,
span: p.span,
2015-07-31 00:04:06 -07:00
}
}
fn lower_struct_field(&mut self, (index, f): (usize, &StructField)) -> hir::StructField {
hir::StructField {
span: f.span,
id: self.lower_node_id(f.id).node_id,
2018-05-26 02:50:15 +03:00
ident: match f.ident {
2017-03-24 23:03:15 +00:00
Some(ident) => ident,
// FIXME(jseyfried) positional field hygiene
None => Ident::new(Symbol::intern(&index.to_string()), f.span),
2018-05-26 02:50:15 +03:00
},
vis: self.lower_visibility(&f.vis, None),
ty: self.lower_ty(&f.ty, ImplTraitContext::Disallowed),
attrs: self.lower_attrs(&f.attrs),
2015-07-31 00:04:06 -07:00
}
}
fn lower_field(&mut self, f: &Field) -> hir::Field {
hir::Field {
id: self.next_id().node_id,
2018-05-26 02:50:15 +03:00
ident: f.ident,
expr: P(self.lower_expr(&f.expr)),
span: f.span,
is_shorthand: f.is_shorthand,
2016-04-18 10:30:55 +12:00
}
}
2015-07-31 00:04:06 -07:00
fn lower_mt(&mut self, mt: &MutTy, itctx: ImplTraitContext) -> hir::MutTy {
hir::MutTy {
ty: self.lower_ty(&mt.ty, itctx),
mutbl: self.lower_mutability(mt.mutbl),
2016-04-18 10:30:55 +12:00
}
}
2015-07-31 00:04:06 -07:00
2018-03-21 04:24:27 -04:00
fn lower_bounds(
&mut self,
bounds: &[TyParamBound],
itctx: ImplTraitContext,
) -> hir::TyParamBounds {
bounds
.iter()
.map(|bound| self.lower_ty_param_bound(bound, itctx))
.collect()
}
fn lower_block(&mut self, b: &Block, targeted_by_break: bool) -> P<hir::Block> {
2016-06-23 09:51:18 +00:00
let mut expr = None;
let mut stmts = vec![];
for (index, stmt) in b.stmts.iter().enumerate() {
if index == b.stmts.len() - 1 {
if let StmtKind::Expr(ref e) = stmt.node {
expr = Some(P(self.lower_expr(e)));
} else {
stmts.extend(self.lower_stmt(stmt));
}
2016-06-23 09:51:18 +00:00
} else {
stmts.extend(self.lower_stmt(stmt));
2016-06-23 09:51:18 +00:00
}
}
let LoweredNodeId { node_id, hir_id } = self.lower_node_id(b.id);
P(hir::Block {
id: node_id,
hir_id,
2016-06-23 09:51:18 +00:00
stmts: stmts.into(),
expr,
rules: self.lower_block_check_mode(&b.rules),
span: b.span,
targeted_by_break,
recovered: b.recovered,
})
}
2018-03-21 04:24:27 -04:00
fn lower_item_kind(
&mut self,
id: NodeId,
name: &mut Name,
attrs: &hir::HirVec<Attribute>,
vis: &mut hir::Visibility,
i: &ItemKind,
) -> hir::Item_ {
match *i {
ItemKind::ExternCrate(orig_name) => hir::ItemExternCrate(orig_name),
ItemKind::Use(ref use_tree) => {
// Start with an empty prefix
let prefix = Path {
segments: vec![],
span: use_tree.span,
};
self.lower_use_tree(use_tree, &prefix, id, vis, name, attrs)
}
ItemKind::Static(ref t, m, ref e) => {
let value = self.lower_body(None, |this| this.lower_expr(e));
2018-03-21 04:24:27 -04:00
hir::ItemStatic(
self.lower_ty(t, ImplTraitContext::Disallowed),
self.lower_mutability(m),
value,
)
}
ItemKind::Const(ref t, ref e) => {
let value = self.lower_body(None, |this| this.lower_expr(e));
hir::ItemConst(self.lower_ty(t, ImplTraitContext::Disallowed), value)
}
ItemKind::Fn(ref decl, unsafety, constness, abi, ref generics, ref body) => {
let fn_def_id = self.resolver.definitions().local_def_id(id);
self.with_new_scopes(|this| {
2016-12-26 14:34:03 +01:00
let body_id = this.lower_body(Some(decl), |this| {
let body = this.lower_block(body, false);
this.expr_block(body, ThinVec::new())
});
let (generics, fn_decl) = this.add_in_band_defs(
generics,
fn_def_id,
AnonymousLifetimeMode::PassThrough,
|this| this.lower_fn_decl(decl, Some(fn_def_id), true),
);
2018-03-21 04:24:27 -04:00
hir::ItemFn(
fn_decl,
this.lower_unsafety(unsafety),
this.lower_constness(constness),
abi,
generics,
body_id,
)
2017-02-15 14:52:27 -08:00
})
}
ItemKind::Mod(ref m) => hir::ItemMod(self.lower_mod(m)),
ItemKind::ForeignMod(ref nm) => hir::ItemForeignMod(self.lower_foreign_mod(nm)),
2017-03-15 21:27:40 -05:00
ItemKind::GlobalAsm(ref ga) => hir::ItemGlobalAsm(self.lower_global_asm(ga)),
2018-03-21 04:24:27 -04:00
ItemKind::Ty(ref t, ref generics) => hir::ItemTy(
self.lower_ty(t, ImplTraitContext::Disallowed),
self.lower_generics(generics, ImplTraitContext::Disallowed),
2018-03-21 04:24:27 -04:00
),
ItemKind::Enum(ref enum_definition, ref generics) => hir::ItemEnum(
hir::EnumDef {
variants: enum_definition
.variants
.iter()
.map(|x| self.lower_variant(x))
.collect(),
},
self.lower_generics(generics, ImplTraitContext::Disallowed),
2018-03-21 04:24:27 -04:00
),
ItemKind::Struct(ref struct_def, ref generics) => {
let struct_def = self.lower_variant_data(struct_def);
hir::ItemStruct(
struct_def,
self.lower_generics(generics, ImplTraitContext::Disallowed),
)
}
ItemKind::Union(ref vdata, ref generics) => {
let vdata = self.lower_variant_data(vdata);
hir::ItemUnion(
vdata,
self.lower_generics(generics, ImplTraitContext::Disallowed),
)
}
2018-03-21 04:24:27 -04:00
ItemKind::Impl(
unsafety,
polarity,
defaultness,
ref ast_generics,
ref trait_ref,
2018-03-21 04:24:27 -04:00
ref ty,
ref impl_items,
) => {
let def_id = self.resolver.definitions().local_def_id(id);
// Lower the "impl header" first. This ordering is important
// for in-band lifetimes! Consider `'a` here:
//
// impl Foo<'a> for u32 {
// fn method(&'a self) { .. }
// }
//
// Because we start by lowering the `Foo<'a> for u32`
// part, we will add `'a` to the list of generics on
// the impl. When we then encounter it later in the
// method, it will not be considered an in-band
// lifetime to be added, but rather a reference to a
// parent lifetime.
let (generics, (trait_ref, lowered_ty)) = self.add_in_band_defs(
ast_generics,
def_id,
AnonymousLifetimeMode::CreateParameter,
|this| {
let trait_ref = trait_ref.as_ref().map(|trait_ref| {
2017-11-16 22:59:45 -08:00
this.lower_trait_ref(trait_ref, ImplTraitContext::Disallowed)
});
if let Some(ref trait_ref) = trait_ref {
2017-11-16 22:59:45 -08:00
if let Def::Trait(def_id) = trait_ref.path.def {
this.trait_impls.entry(def_id).or_insert(vec![]).push(id);
}
}
let lowered_ty = this.lower_ty(ty, ImplTraitContext::Disallowed);
(trait_ref, lowered_ty)
},
);
2017-11-16 22:59:45 -08:00
let new_impl_items = self.with_in_scope_lifetime_defs(
2018-05-26 19:16:21 +01:00
ast_generics.params.iter().filter_map(|param| match param.kind {
GenericParamKindAST::Lifetime { .. } => Some(param),
_ => None,
}),
|this| {
2018-03-21 04:24:27 -04:00
impl_items
.iter()
.map(|item| this.lower_impl_item_ref(item))
.collect()
2018-03-21 04:24:27 -04:00
},
);
2018-03-21 04:24:27 -04:00
hir::ItemImpl(
self.lower_unsafety(unsafety),
self.lower_impl_polarity(polarity),
self.lower_defaultness(defaultness, true /* [1] */),
generics,
trait_ref,
2018-03-21 04:24:27 -04:00
lowered_ty,
new_impl_items,
)
}
ItemKind::Trait(is_auto, unsafety, ref generics, ref bounds, ref items) => {
let bounds = self.lower_bounds(bounds, ImplTraitContext::Disallowed);
2018-03-21 04:24:27 -04:00
let items = items
.iter()
.map(|item| self.lower_trait_item_ref(item))
.collect();
hir::ItemTrait(
self.lower_is_auto(is_auto),
self.lower_unsafety(unsafety),
self.lower_generics(generics, ImplTraitContext::Disallowed),
2018-03-21 04:24:27 -04:00
bounds,
items,
)
}
2018-03-21 04:24:27 -04:00
ItemKind::TraitAlias(ref generics, ref bounds) => hir::ItemTraitAlias(
self.lower_generics(generics, ImplTraitContext::Disallowed),
2018-03-21 04:24:27 -04:00
self.lower_bounds(bounds, ImplTraitContext::Disallowed),
),
2017-10-02 12:28:16 +00:00
ItemKind::MacroDef(..) | ItemKind::Mac(..) => panic!("Shouldn't still be around"),
}
// [1] `defaultness.has_value()` is never called for an `impl`, always `true` in order to
// not cause an assertion failure inside the `lower_defaultness` function
2015-10-06 16:03:56 +13:00
}
2015-07-31 00:04:06 -07:00
2018-03-21 04:24:27 -04:00
fn lower_use_tree(
&mut self,
tree: &UseTree,
prefix: &Path,
id: NodeId,
vis: &mut hir::Visibility,
name: &mut Name,
attrs: &hir::HirVec<Attribute>,
) -> hir::Item_ {
let path = &tree.prefix;
match tree.kind {
UseTreeKind::Simple(rename, id1, id2) => {
*name = tree.ident().name;
// First apply the prefix to the path
let mut path = Path {
2018-03-21 04:24:27 -04:00
segments: prefix
.segments
.iter()
.chain(path.segments.iter())
.cloned()
.collect(),
2018-03-21 04:24:27 -04:00
span: path.span,
};
// Correctly resolve `self` imports
2018-03-21 04:24:27 -04:00
if path.segments.len() > 1
&& path.segments.last().unwrap().ident.name == keywords::SelfValue.name()
2018-03-21 04:24:27 -04:00
{
let _ = path.segments.pop();
if rename.is_none() {
*name = path.segments.last().unwrap().ident.name;
}
}
let parent_def_index = self.current_hir_id_owner.last().unwrap().0;
let mut defs = self.expect_full_def_from_use(id);
// we want to return *something* from this function, so hang onto the first item
// for later
let mut ret_def = defs.next().unwrap_or(Def::Err);
for (def, &new_node_id) in defs.zip([id1, id2].iter()) {
let vis = vis.clone();
let name = name.clone();
let span = path.span;
self.resolver.definitions().create_def_with_parent(
parent_def_index,
new_node_id,
DefPathData::Misc,
DefIndexAddressSpace::High,
Mark::root(),
span);
self.allocate_hir_id_counter(new_node_id, &path);
self.with_hir_id_owner(new_node_id, |this| {
let new_id = this.lower_node_id(new_node_id);
let path = this.lower_path_extra(def, &path, None, ParamMode::Explicit);
let item = hir::ItemUse(P(path), hir::UseKind::Single);
let vis = match vis {
hir::Visibility::Public => hir::Visibility::Public,
hir::Visibility::Crate(sugar) => hir::Visibility::Crate(sugar),
hir::Visibility::Inherited => hir::Visibility::Inherited,
hir::Visibility::Restricted { ref path, id: _ } => {
hir::Visibility::Restricted {
path: path.clone(),
// We are allocating a new NodeId here
id: this.next_id().node_id,
}
}
};
this.items.insert(
new_id.node_id,
hir::Item {
id: new_id.node_id,
hir_id: new_id.hir_id,
name: name,
attrs: attrs.clone(),
node: item,
vis,
span,
},
);
});
}
let path = P(self.lower_path_extra(ret_def, &path, None, ParamMode::Explicit));
hir::ItemUse(path, hir::UseKind::Single)
}
UseTreeKind::Glob => {
2018-03-21 04:24:27 -04:00
let path = P(self.lower_path(
id,
&Path {
segments: prefix
.segments
.iter()
.chain(path.segments.iter())
.cloned()
.collect(),
span: path.span,
},
ParamMode::Explicit,
));
hir::ItemUse(path, hir::UseKind::Glob)
}
UseTreeKind::Nested(ref trees) => {
let prefix = Path {
2018-03-21 04:24:27 -04:00
segments: prefix
.segments
.iter()
.chain(path.segments.iter())
.cloned()
.collect(),
span: prefix.span.to(path.span),
};
// Add all the nested PathListItems in the HIR
for &(ref use_tree, id) in trees {
self.allocate_hir_id_counter(id, &use_tree);
let LoweredNodeId {
node_id: new_id,
hir_id: new_hir_id,
} = self.lower_node_id(id);
let mut vis = vis.clone();
let mut name = name.clone();
2018-03-21 04:24:27 -04:00
let item =
self.lower_use_tree(use_tree, &prefix, new_id, &mut vis, &mut name, &attrs);
self.with_hir_id_owner(new_id, |this| {
let vis = match vis {
hir::Visibility::Public => hir::Visibility::Public,
hir::Visibility::Crate(sugar) => hir::Visibility::Crate(sugar),
hir::Visibility::Inherited => hir::Visibility::Inherited,
2018-03-21 04:24:27 -04:00
hir::Visibility::Restricted { ref path, id: _ } => {
hir::Visibility::Restricted {
path: path.clone(),
// We are allocating a new NodeId here
id: this.next_id().node_id,
}
}
};
2018-03-21 04:24:27 -04:00
this.items.insert(
new_id,
hir::Item {
id: new_id,
hir_id: new_hir_id,
name: name,
attrs: attrs.clone(),
node: item,
vis,
span: use_tree.span,
},
);
});
}
// Privatize the degenerate import base, used only to check
// the stability of `use a::{};`, to avoid it showing up as
// a re-export by accident when `pub`, e.g. in documentation.
let path = P(self.lower_path(id, &prefix, ParamMode::Explicit));
*vis = hir::Inherited;
hir::ItemUse(path, hir::UseKind::ListStem)
}
}
}
fn lower_trait_item(&mut self, i: &TraitItem) -> hir::TraitItem {
let LoweredNodeId { node_id, hir_id } = self.lower_node_id(i.id);
let trait_item_def_id = self.resolver.definitions().local_def_id(node_id);
let (generics, node) = match i.node {
TraitItemKind::Const(ref ty, ref default) => (
self.lower_generics(&i.generics, ImplTraitContext::Disallowed),
hir::TraitItemKind::Const(
self.lower_ty(ty, ImplTraitContext::Disallowed),
default
.as_ref()
.map(|x| self.lower_body(None, |this| this.lower_expr(x))),
2018-03-21 04:24:27 -04:00
),
),
TraitItemKind::Method(ref sig, None) => {
let names = self.lower_fn_args_to_names(&sig.decl);
self.add_in_band_defs(
&i.generics,
trait_item_def_id,
AnonymousLifetimeMode::PassThrough,
|this| {
hir::TraitItemKind::Method(
this.lower_method_sig(sig, trait_item_def_id, false),
hir::TraitMethod::Required(names),
)
},
)
}
TraitItemKind::Method(ref sig, Some(ref body)) => {
let body_id = self.lower_body(Some(&sig.decl), |this| {
let body = this.lower_block(body, false);
this.expr_block(body, ThinVec::new())
});
2017-11-16 22:59:45 -08:00
self.add_in_band_defs(
&i.generics,
trait_item_def_id,
AnonymousLifetimeMode::PassThrough,
|this| {
hir::TraitItemKind::Method(
this.lower_method_sig(sig, trait_item_def_id, false),
hir::TraitMethod::Provided(body_id),
)
},
)
}
TraitItemKind::Type(ref bounds, ref default) => (
self.lower_generics(&i.generics, ImplTraitContext::Disallowed),
hir::TraitItemKind::Type(
self.lower_bounds(bounds, ImplTraitContext::Disallowed),
default
.as_ref()
.map(|x| self.lower_ty(x, ImplTraitContext::Disallowed)),
2018-03-21 04:24:27 -04:00
),
),
TraitItemKind::Macro(..) => panic!("Shouldn't exist any more"),
};
2017-11-16 22:59:45 -08:00
hir::TraitItem {
id: node_id,
hir_id,
name: self.lower_ident(i.ident),
attrs: self.lower_attrs(&i.attrs),
generics,
node,
span: i.span,
}
2015-07-31 00:04:06 -07:00
}
fn lower_trait_item_ref(&mut self, i: &TraitItem) -> hir::TraitItemRef {
let (kind, has_default) = match i.node {
TraitItemKind::Const(_, ref default) => {
(hir::AssociatedItemKind::Const, default.is_some())
}
TraitItemKind::Type(_, ref default) => {
(hir::AssociatedItemKind::Type, default.is_some())
}
2018-03-21 04:24:27 -04:00
TraitItemKind::Method(ref sig, ref default) => (
hir::AssociatedItemKind::Method {
has_self: sig.decl.has_self(),
2018-03-21 04:24:27 -04:00
},
default.is_some(),
),
TraitItemKind::Macro(..) => unimplemented!(),
};
hir::TraitItemRef {
id: hir::TraitItemId { node_id: i.id },
2017-03-24 23:03:15 +00:00
name: self.lower_ident(i.ident),
span: i.span,
defaultness: self.lower_defaultness(Defaultness::Default, has_default),
kind,
}
}
fn lower_impl_item(&mut self, i: &ImplItem) -> hir::ImplItem {
let LoweredNodeId { node_id, hir_id } = self.lower_node_id(i.id);
let impl_item_def_id = self.resolver.definitions().local_def_id(node_id);
let (generics, node) = match i.node {
ImplItemKind::Const(ref ty, ref expr) => {
let body_id = self.lower_body(None, |this| this.lower_expr(expr));
(
self.lower_generics(&i.generics, ImplTraitContext::Disallowed),
hir::ImplItemKind::Const(
self.lower_ty(ty, ImplTraitContext::Disallowed),
body_id,
),
)
}
ImplItemKind::Method(ref sig, ref body) => {
let body_id = self.lower_body(Some(&sig.decl), |this| {
let body = this.lower_block(body, false);
this.expr_block(body, ThinVec::new())
});
let impl_trait_return_allow = !self.is_in_trait_impl;
2017-11-16 22:59:45 -08:00
self.add_in_band_defs(
&i.generics,
impl_item_def_id,
AnonymousLifetimeMode::PassThrough,
|this| {
hir::ImplItemKind::Method(
this.lower_method_sig(
sig,
impl_item_def_id,
impl_trait_return_allow,
),
body_id,
)
},
)
}
ImplItemKind::Type(ref ty) => (
self.lower_generics(&i.generics, ImplTraitContext::Disallowed),
hir::ImplItemKind::Type(self.lower_ty(ty, ImplTraitContext::Disallowed)),
),
ImplItemKind::Macro(..) => panic!("Shouldn't exist any more"),
};
hir::ImplItem {
id: node_id,
hir_id,
name: self.lower_ident(i.ident),
attrs: self.lower_attrs(&i.attrs),
generics,
vis: self.lower_visibility(&i.vis, None),
defaultness: self.lower_defaultness(i.defaultness, true /* [1] */),
node,
span: i.span,
}
// [1] since `default impl` is not yet implemented, this is always true in impls
2015-07-31 00:04:06 -07:00
}
fn lower_impl_item_ref(&mut self, i: &ImplItem) -> hir::ImplItemRef {
hir::ImplItemRef {
id: hir::ImplItemId { node_id: i.id },
2017-03-24 23:03:15 +00:00
name: self.lower_ident(i.ident),
span: i.span,
vis: self.lower_visibility(&i.vis, Some(i.id)),
defaultness: self.lower_defaultness(i.defaultness, true /* [1] */),
kind: match i.node {
ImplItemKind::Const(..) => hir::AssociatedItemKind::Const,
ImplItemKind::Type(..) => hir::AssociatedItemKind::Type,
2018-03-21 04:24:27 -04:00
ImplItemKind::Method(ref sig, _) => hir::AssociatedItemKind::Method {
has_self: sig.decl.has_self(),
},
ImplItemKind::Macro(..) => unimplemented!(),
},
}
// [1] since `default impl` is not yet implemented, this is always true in impls
}
fn lower_mod(&mut self, m: &Mod) -> hir::Mod {
hir::Mod {
inner: m.inner,
item_ids: m.items.iter().flat_map(|x| self.lower_item_id(x)).collect(),
}
}
2015-07-31 00:04:06 -07:00
fn lower_item_id(&mut self, i: &Item) -> SmallVector<hir::ItemId> {
match i.node {
ItemKind::Use(ref use_tree) => {
let mut vec = SmallVector::one(hir::ItemId { id: i.id });
self.lower_item_id_use_tree(use_tree, i.id, &mut vec);
return vec;
}
ItemKind::MacroDef(..) => return SmallVector::new(),
_ => {}
}
SmallVector::one(hir::ItemId { id: i.id })
2015-07-31 00:04:06 -07:00
}
fn lower_item_id_use_tree(&mut self,
tree: &UseTree,
base_id: NodeId,
vec: &mut SmallVector<hir::ItemId>)
{
match tree.kind {
2018-03-21 04:24:27 -04:00
UseTreeKind::Nested(ref nested_vec) => for &(ref nested, id) in nested_vec {
vec.push(hir::ItemId { id });
self.lower_item_id_use_tree(nested, id, vec);
2018-03-21 04:24:27 -04:00
},
UseTreeKind::Glob => {}
UseTreeKind::Simple(_, id1, id2) => {
for (_, &id) in self.expect_full_def_from_use(base_id)
.skip(1)
.zip([id1, id2].iter())
{
vec.push(hir::ItemId { id });
}
},
}
}
pub fn lower_item(&mut self, i: &Item) -> Option<hir::Item> {
let mut name = i.ident.name;
2017-03-25 01:46:38 +00:00
let mut vis = self.lower_visibility(&i.vis, None);
let attrs = self.lower_attrs(&i.attrs);
if let ItemKind::MacroDef(ref def) = i.node {
if !def.legacy || attr::contains_name(&i.attrs, "macro_export") {
rustc: Forbid interpolated tokens in the HIR Right now the HIR contains raw `syntax::ast::Attribute` structure but nowadays these can contain arbitrary tokens. One variant of the `Token` enum is an "interpolated" token which basically means to shove all the tokens for a nonterminal in this position. A "nonterminal" in this case is roughly analagous to a macro argument: macro_rules! foo { ($a:expr) => { // $a is a nonterminal as an expression } } Currently nonterminals contain namely items and expressions, and this poses a problem for incremental compilation! With incremental we want a stable hash of all HIR items, but this means we may transitively need a stable hash *of the entire AST*, which is certainly not stable w/ node ids and whatnot. Hence today there's a "bug" where the "stable hash" of an AST is just the raw hash value of the AST, and this only arises with interpolated nonterminals. The downside of this approach, however, is that a bunch of errors get spewed out during compilation about how this isn't a great idea. This PR is focused at fixing these warnings, basically deleting them from the compiler. The implementation here is to alter attributes as they're lowered from the AST to HIR, expanding all nonterminals in-place as we see them. This code for expanding a nonterminal to a token stream already exists for the `proc_macro` crate, so we basically just reuse the same implementation there. After this PR it's considered a bug to have an `Interpolated` token and hence the stable hash implementation simply uses `bug!` in this location. Closes #40946
2017-09-15 08:28:34 -07:00
let body = self.lower_token_stream(def.stream());
self.exported_macros.push(hir::MacroDef {
name,
vis,
attrs,
2017-03-25 01:46:38 +00:00
id: i.id,
span: i.span,
rustc: Forbid interpolated tokens in the HIR Right now the HIR contains raw `syntax::ast::Attribute` structure but nowadays these can contain arbitrary tokens. One variant of the `Token` enum is an "interpolated" token which basically means to shove all the tokens for a nonterminal in this position. A "nonterminal" in this case is roughly analagous to a macro argument: macro_rules! foo { ($a:expr) => { // $a is a nonterminal as an expression } } Currently nonterminals contain namely items and expressions, and this poses a problem for incremental compilation! With incremental we want a stable hash of all HIR items, but this means we may transitively need a stable hash *of the entire AST*, which is certainly not stable w/ node ids and whatnot. Hence today there's a "bug" where the "stable hash" of an AST is just the raw hash value of the AST, and this only arises with interpolated nonterminals. The downside of this approach, however, is that a bunch of errors get spewed out during compilation about how this isn't a great idea. This PR is focused at fixing these warnings, basically deleting them from the compiler. The implementation here is to alter attributes as they're lowered from the AST to HIR, expanding all nonterminals in-place as we see them. This code for expanding a nonterminal to a token stream already exists for the `proc_macro` crate, so we basically just reuse the same implementation there. After this PR it's considered a bug to have an `Interpolated` token and hence the stable hash implementation simply uses `bug!` in this location. Closes #40946
2017-09-15 08:28:34 -07:00
body,
2017-03-25 01:46:38 +00:00
legacy: def.legacy,
});
}
return None;
}
let node = self.lower_item_kind(i.id, &mut name, &attrs, &mut vis, &i.node);
let LoweredNodeId { node_id, hir_id } = self.lower_node_id(i.id);
Some(hir::Item {
id: node_id,
hir_id,
name,
attrs,
node,
vis,
2016-04-18 10:30:55 +12:00
span: i.span,
})
}
2015-07-31 00:04:06 -07:00
fn lower_foreign_item(&mut self, i: &ForeignItem) -> hir::ForeignItem {
let node_id = self.lower_node_id(i.id).node_id;
let def_id = self.resolver.definitions().local_def_id(node_id);
hir::ForeignItem {
id: node_id,
name: i.ident.name,
attrs: self.lower_attrs(&i.attrs),
node: match i.node {
ForeignItemKind::Fn(ref fdec, ref generics) => {
let (generics, (fn_dec, fn_args)) = self.add_in_band_defs(
generics,
def_id,
AnonymousLifetimeMode::PassThrough,
|this| {
(
// Disallow impl Trait in foreign items
this.lower_fn_decl(fdec, None, false),
this.lower_fn_args_to_names(fdec),
)
},
);
2017-11-16 22:59:45 -08:00
hir::ForeignItemFn(fn_dec, fn_args, generics)
}
ForeignItemKind::Static(ref t, m) => {
hir::ForeignItemStatic(self.lower_ty(t, ImplTraitContext::Disallowed), m)
}
ForeignItemKind::Ty => hir::ForeignItemType,
ForeignItemKind::Macro(_) => panic!("shouldn't exist here"),
},
vis: self.lower_visibility(&i.vis, None),
span: i.span,
}
2015-07-31 00:04:06 -07:00
}
2018-03-21 04:24:27 -04:00
fn lower_method_sig(
&mut self,
sig: &MethodSig,
fn_def_id: DefId,
2018-03-21 04:24:27 -04:00
impl_trait_return_allow: bool,
) -> hir::MethodSig {
hir::MethodSig {
abi: sig.abi,
unsafety: self.lower_unsafety(sig.unsafety),
constness: self.lower_constness(sig.constness),
decl: self.lower_fn_decl(&sig.decl, Some(fn_def_id), impl_trait_return_allow),
}
2015-07-31 00:04:06 -07:00
}
2017-10-12 11:18:55 -03:00
fn lower_is_auto(&mut self, a: IsAuto) -> hir::IsAuto {
match a {
IsAuto::Yes => hir::IsAuto::Yes,
IsAuto::No => hir::IsAuto::No,
}
}
fn lower_unsafety(&mut self, u: Unsafety) -> hir::Unsafety {
match u {
Unsafety::Unsafe => hir::Unsafety::Unsafe,
Unsafety::Normal => hir::Unsafety::Normal,
}
2015-07-31 00:04:06 -07:00
}
2016-08-10 16:20:12 -07:00
fn lower_constness(&mut self, c: Spanned<Constness>) -> hir::Constness {
match c.node {
Constness::Const => hir::Constness::Const,
Constness::NotConst => hir::Constness::NotConst,
}
2015-07-31 00:04:06 -07:00
}
fn lower_unop(&mut self, u: UnOp) -> hir::UnOp {
match u {
UnOp::Deref => hir::UnDeref,
UnOp::Not => hir::UnNot,
UnOp::Neg => hir::UnNeg,
}
2015-07-31 00:04:06 -07:00
}
fn lower_binop(&mut self, b: BinOp) -> hir::BinOp {
Spanned {
node: match b.node {
BinOpKind::Add => hir::BiAdd,
BinOpKind::Sub => hir::BiSub,
BinOpKind::Mul => hir::BiMul,
BinOpKind::Div => hir::BiDiv,
BinOpKind::Rem => hir::BiRem,
BinOpKind::And => hir::BiAnd,
BinOpKind::Or => hir::BiOr,
BinOpKind::BitXor => hir::BiBitXor,
BinOpKind::BitAnd => hir::BiBitAnd,
BinOpKind::BitOr => hir::BiBitOr,
BinOpKind::Shl => hir::BiShl,
BinOpKind::Shr => hir::BiShr,
BinOpKind::Eq => hir::BiEq,
BinOpKind::Lt => hir::BiLt,
BinOpKind::Le => hir::BiLe,
BinOpKind::Ne => hir::BiNe,
BinOpKind::Ge => hir::BiGe,
BinOpKind::Gt => hir::BiGt,
},
span: b.span,
}
}
2015-07-31 00:04:06 -07:00
fn lower_pat(&mut self, p: &Pat) -> P<hir::Pat> {
let node = match p.node {
PatKind::Wild => hir::PatKind::Wild,
2018-03-18 16:47:09 +03:00
PatKind::Ident(ref binding_mode, ident, ref sub) => {
match self.resolver.get_resolution(p.id).map(|d| d.base_def()) {
// `None` can occur in body-less function signatures
def @ None | def @ Some(Def::Local(_)) => {
let canonical_id = match def {
Some(Def::Local(id)) => id,
2018-03-21 04:24:27 -04:00
_ => p.id,
};
2018-03-21 04:24:27 -04:00
hir::PatKind::Binding(
self.lower_binding_mode(binding_mode),
canonical_id,
2018-03-18 16:47:09 +03:00
respan(ident.span, ident.name),
2018-03-21 04:24:27 -04:00
sub.as_ref().map(|x| self.lower_pat(x)),
)
}
2018-03-21 04:24:27 -04:00
Some(def) => hir::PatKind::Path(hir::QPath::Resolved(
None,
P(hir::Path {
2018-03-18 16:47:09 +03:00
span: ident.span,
def,
2018-03-18 16:47:09 +03:00
segments: hir_vec![hir::PathSegment::from_name(ident.name)],
2018-03-21 04:24:27 -04:00
}),
)),
}
}
PatKind::Lit(ref e) => hir::PatKind::Lit(P(self.lower_expr(e))),
PatKind::TupleStruct(ref path, ref pats, ddpos) => {
2018-03-21 04:24:27 -04:00
let qpath = self.lower_qpath(
p.id,
&None,
path,
ParamMode::Optional,
ImplTraitContext::Disallowed,
);
hir::PatKind::TupleStruct(
qpath,
pats.iter().map(|x| self.lower_pat(x)).collect(),
ddpos,
)
}
2018-03-21 04:24:27 -04:00
PatKind::Path(ref qself, ref path) => hir::PatKind::Path(self.lower_qpath(
p.id,
qself,
path,
ParamMode::Optional,
ImplTraitContext::Disallowed,
)),
PatKind::Struct(ref path, ref fields, etc) => {
2018-03-21 04:24:27 -04:00
let qpath = self.lower_qpath(
p.id,
&None,
path,
ParamMode::Optional,
ImplTraitContext::Disallowed,
);
let fs = fields
.iter()
.map(|f| Spanned {
span: f.span,
node: hir::FieldPat {
id: self.next_id().node_id,
2018-05-26 02:50:15 +03:00
ident: f.node.ident,
2018-03-21 04:24:27 -04:00
pat: self.lower_pat(&f.node.pat),
is_shorthand: f.node.is_shorthand,
},
})
.collect();
hir::PatKind::Struct(qpath, fs, etc)
}
PatKind::Tuple(ref elts, ddpos) => {
hir::PatKind::Tuple(elts.iter().map(|x| self.lower_pat(x)).collect(), ddpos)
}
PatKind::Box(ref inner) => hir::PatKind::Box(self.lower_pat(inner)),
PatKind::Ref(ref inner, mutbl) => {
hir::PatKind::Ref(self.lower_pat(inner), self.lower_mutability(mutbl))
}
2018-03-21 04:24:27 -04:00
PatKind::Range(ref e1, ref e2, ref end) => hir::PatKind::Range(
P(self.lower_expr(e1)),
P(self.lower_expr(e2)),
self.lower_range_end(end),
),
PatKind::Slice(ref before, ref slice, ref after) => hir::PatKind::Slice(
before.iter().map(|x| self.lower_pat(x)).collect(),
slice.as_ref().map(|x| self.lower_pat(x)),
after.iter().map(|x| self.lower_pat(x)).collect(),
),
PatKind::Paren(ref inner) => return self.lower_pat(inner),
PatKind::Mac(_) => panic!("Shouldn't exist here"),
};
let LoweredNodeId { node_id, hir_id } = self.lower_node_id(p.id);
P(hir::Pat {
id: node_id,
hir_id,
node,
span: p.span,
})
}
2015-10-06 16:03:56 +13:00
fn lower_range_end(&mut self, e: &RangeEnd) -> hir::RangeEnd {
match *e {
RangeEnd::Included(_) => hir::RangeEnd::Included,
RangeEnd::Excluded => hir::RangeEnd::Excluded,
}
}
fn lower_anon_const(&mut self, c: &AnonConst) -> hir::AnonConst {
let LoweredNodeId { node_id, hir_id } = self.lower_node_id(c.id);
hir::AnonConst {
id: node_id,
hir_id,
body: self.lower_body(None, |this| this.lower_expr(&c.value)),
}
}
fn lower_expr(&mut self, e: &Expr) -> hir::Expr {
let kind = match e.node {
2018-03-21 04:24:27 -04:00
ExprKind::Box(ref inner) => hir::ExprBox(P(self.lower_expr(inner))),
2018-05-24 17:34:09 -04:00
ExprKind::ObsoleteInPlace(..) => {
self.sess.abort_if_errors();
span_bug!(e.span, "encountered ObsoleteInPlace expr during lowering");
}
ExprKind::Array(ref exprs) => {
hir::ExprArray(exprs.iter().map(|x| self.lower_expr(x)).collect())
}
ExprKind::Repeat(ref expr, ref count) => {
let expr = P(self.lower_expr(expr));
let count = self.lower_anon_const(count);
hir::ExprRepeat(expr, count)
}
ExprKind::Tup(ref elts) => {
hir::ExprTup(elts.iter().map(|x| self.lower_expr(x)).collect())
}
ExprKind::Call(ref f, ref args) => {
let f = P(self.lower_expr(f));
hir::ExprCall(f, args.iter().map(|x| self.lower_expr(x)).collect())
}
ExprKind::MethodCall(ref seg, ref args) => {
2018-03-21 04:24:27 -04:00
let hir_seg = self.lower_path_segment(
e.span,
seg,
ParamMode::Optional,
0,
ParenthesizedGenericArgs::Err,
ImplTraitContext::Disallowed,
);
let args = args.iter().map(|x| self.lower_expr(x)).collect();
2018-03-19 03:54:56 +03:00
hir::ExprMethodCall(hir_seg, seg.ident.span, args)
}
ExprKind::Binary(binop, ref lhs, ref rhs) => {
let binop = self.lower_binop(binop);
let lhs = P(self.lower_expr(lhs));
let rhs = P(self.lower_expr(rhs));
hir::ExprBinary(binop, lhs, rhs)
}
ExprKind::Unary(op, ref ohs) => {
let op = self.lower_unop(op);
let ohs = P(self.lower_expr(ohs));
hir::ExprUnary(op, ohs)
}
ExprKind::Lit(ref l) => hir::ExprLit(P((**l).clone())),
ExprKind::Cast(ref expr, ref ty) => {
let expr = P(self.lower_expr(expr));
hir::ExprCast(expr, self.lower_ty(ty, ImplTraitContext::Disallowed))
}
ExprKind::Type(ref expr, ref ty) => {
let expr = P(self.lower_expr(expr));
hir::ExprType(expr, self.lower_ty(ty, ImplTraitContext::Disallowed))
}
ExprKind::AddrOf(m, ref ohs) => {
let m = self.lower_mutability(m);
let ohs = P(self.lower_expr(ohs));
hir::ExprAddrOf(m, ohs)
}
// More complicated than you might expect because the else branch
// might be `if let`.
ExprKind::If(ref cond, ref blk, ref else_opt) => {
let else_opt = else_opt.as_ref().map(|els| {
match els.node {
ExprKind::IfLet(..) => {
// wrap the if-let expr in a block
let span = els.span;
let els = P(self.lower_expr(els));
2018-03-21 04:24:27 -04:00
let LoweredNodeId { node_id, hir_id } = self.next_id();
let blk = P(hir::Block {
stmts: hir_vec![],
expr: Some(els),
id: node_id,
hir_id,
rules: hir::DefaultBlock,
span,
targeted_by_break: false,
recovered: blk.recovered,
});
P(self.expr_block(blk, ThinVec::new()))
}
_ => P(self.lower_expr(els)),
}
});
let then_blk = self.lower_block(blk, false);
let then_expr = self.expr_block(then_blk, ThinVec::new());
hir::ExprIf(P(self.lower_expr(cond)), P(then_expr), else_opt)
}
2018-03-21 04:24:27 -04:00
ExprKind::While(ref cond, ref body, opt_label) => self.with_loop_scope(e.id, |this| {
hir::ExprWhile(
this.with_loop_condition_scope(|this| P(this.lower_expr(cond))),
this.lower_block(body, false),
this.lower_label(opt_label),
)
}),
ExprKind::Loop(ref body, opt_label) => self.with_loop_scope(e.id, |this| {
hir::ExprLoop(
this.lower_block(body, false),
this.lower_label(opt_label),
hir::LoopSource::Loop,
)
}),
ExprKind::Catch(ref body) => {
self.with_catch_scope(body.id, |this| {
let unstable_span =
this.allow_internal_unstable(CompilerDesugaringKind::Catch, body.span);
let mut block = this.lower_block(body, true).into_inner();
let tail = block.expr.take().map_or_else(
|| {
let LoweredNodeId { node_id, hir_id } = this.next_id();
let span = this.sess.codemap().end_point(unstable_span);
hir::Expr {
id: node_id,
span,
node: hir::ExprTup(hir_vec![]),
attrs: ThinVec::new(),
hir_id,
}
},
|x: P<hir::Expr>| x.into_inner(),
);
block.expr = Some(this.wrap_in_try_constructor(
"from_ok", tail, unstable_span));
hir::ExprBlock(P(block), None)
})
}
2018-03-21 04:24:27 -04:00
ExprKind::Match(ref expr, ref arms) => hir::ExprMatch(
P(self.lower_expr(expr)),
arms.iter().map(|x| self.lower_arm(x)).collect(),
hir::MatchSource::Normal,
),
ExprKind::Closure(capture_clause, movability, ref decl, ref body, fn_decl_span) => {
self.with_new_scopes(|this| {
let mut is_generator = false;
let body_id = this.lower_body(Some(decl), |this| {
let e = this.lower_expr(body);
is_generator = this.is_generator;
e
});
let generator_option = if is_generator {
if !decl.inputs.is_empty() {
span_err!(
this.sess,
fn_decl_span,
E0628,
"generators cannot have explicit arguments"
);
this.sess.abort_if_errors();
}
Some(match movability {
Movability::Movable => hir::GeneratorMovability::Movable,
Movability::Static => hir::GeneratorMovability::Static,
})
} else {
if movability == Movability::Static {
span_err!(
this.sess,
fn_decl_span,
2018-06-10 14:04:48 +02:00
E0697,
"closures cannot be static"
);
}
None
};
hir::ExprClosure(
this.lower_capture_clause(capture_clause),
this.lower_fn_decl(decl, None, false),
body_id,
fn_decl_span,
generator_option,
)
})
}
ExprKind::Block(ref blk, opt_label) => {
hir::ExprBlock(self.lower_block(blk,
opt_label.is_some()),
self.lower_label(opt_label))
}
ExprKind::Assign(ref el, ref er) => {
hir::ExprAssign(P(self.lower_expr(el)), P(self.lower_expr(er)))
}
2018-03-21 04:24:27 -04:00
ExprKind::AssignOp(op, ref el, ref er) => hir::ExprAssignOp(
self.lower_binop(op),
P(self.lower_expr(el)),
P(self.lower_expr(er)),
),
2018-05-26 02:50:15 +03:00
ExprKind::Field(ref el, ident) => hir::ExprField(P(self.lower_expr(el)), ident),
ExprKind::Index(ref el, ref er) => {
hir::ExprIndex(P(self.lower_expr(el)), P(self.lower_expr(er)))
}
// Desugar `<start>..=<end>` to `std::ops::RangeInclusive::new(<start>, <end>)`
ExprKind::Range(Some(ref e1), Some(ref e2), RangeLimits::Closed) => {
2018-05-03 22:36:44 +08:00
// FIXME: Use e.span directly after RangeInclusive::new() is stabilized in stage0.
let span = self.allow_internal_unstable(CompilerDesugaringKind::DotFill, e.span);
2018-05-03 22:36:44 +08:00
let id = self.next_id();
let e1 = self.lower_expr(e1);
let e2 = self.lower_expr(e2);
let ty_path = P(self.std_path(span, &["ops", "RangeInclusive"], false));
let ty = self.ty_path(id, span, hir::QPath::Resolved(None, ty_path));
let new_seg = P(hir::PathSegment::from_name(Symbol::intern("new")));
let new_path = hir::QPath::TypeRelative(ty, new_seg);
let new = P(self.expr(span, hir::ExprPath(new_path), ThinVec::new()));
hir::ExprCall(new, hir_vec![e1, e2])
}
ExprKind::Range(ref e1, ref e2, lims) => {
use syntax::ast::RangeLimits::*;
let path = match (e1, e2, lims) {
(&None, &None, HalfOpen) => "RangeFull",
(&Some(..), &None, HalfOpen) => "RangeFrom",
(&None, &Some(..), HalfOpen) => "RangeTo",
(&Some(..), &Some(..), HalfOpen) => "Range",
(&None, &Some(..), Closed) => "RangeToInclusive",
(&Some(..), &Some(..), Closed) => unreachable!(),
2018-03-21 04:24:27 -04:00
(_, &None, Closed) => self.diagnostic()
.span_fatal(e.span, "inclusive range with no end")
.raise(),
};
2018-03-21 04:24:27 -04:00
let fields = e1.iter()
.map(|e| ("start", e))
.chain(e2.iter().map(|e| ("end", e)))
.map(|(s, e)| {
let expr = P(self.lower_expr(&e));
let unstable_span =
self.allow_internal_unstable(CompilerDesugaringKind::DotFill, e.span);
2018-05-26 02:50:15 +03:00
let ident = Ident::new(Symbol::intern(s), unstable_span);
self.field(ident, expr, unstable_span)
2018-03-21 04:24:27 -04:00
})
.collect::<P<[hir::Field]>>();
let is_unit = fields.is_empty();
let unstable_span =
self.allow_internal_unstable(CompilerDesugaringKind::DotFill, e.span);
2018-03-21 04:24:27 -04:00
let struct_path = iter::once("ops")
.chain(iter::once(path))
.collect::<Vec<_>>();
let struct_path = self.std_path(unstable_span, &struct_path, is_unit);
let struct_path = hir::QPath::Resolved(None, P(struct_path));
let LoweredNodeId { node_id, hir_id } = self.lower_node_id(e.id);
return hir::Expr {
id: node_id,
hir_id,
node: if is_unit {
hir::ExprPath(struct_path)
} else {
hir::ExprStruct(struct_path, fields, None)
},
span: unstable_span,
attrs: e.attrs.clone(),
};
}
2018-03-21 04:24:27 -04:00
ExprKind::Path(ref qself, ref path) => hir::ExprPath(self.lower_qpath(
e.id,
qself,
path,
ParamMode::Optional,
ImplTraitContext::Disallowed,
)),
ExprKind::Break(opt_label, ref opt_expr) => {
let destination = if self.is_in_loop_condition && opt_label.is_none() {
hir::Destination {
label: None,
target_id: Err(hir::LoopIdError::UnlabeledCfInWhileCondition).into(),
}
} else {
self.lower_loop_destination(opt_label.map(|label| (e.id, label)))
};
hir::ExprBreak(
2018-03-21 04:24:27 -04:00
destination,
opt_expr.as_ref().map(|x| P(self.lower_expr(x))),
)
}
ExprKind::Continue(opt_label) => {
hir::ExprAgain(if self.is_in_loop_condition && opt_label.is_none() {
hir::Destination {
label: None,
target_id: Err(hir::LoopIdError::UnlabeledCfInWhileCondition).into(),
2018-03-21 04:24:27 -04:00
}
} else {
self.lower_loop_destination(opt_label.map(|label| (e.id, label)))
})
}
ExprKind::Ret(ref e) => hir::ExprRet(e.as_ref().map(|x| P(self.lower_expr(x)))),
ExprKind::InlineAsm(ref asm) => {
let hir_asm = hir::InlineAsm {
inputs: asm.inputs.iter().map(|&(ref c, _)| c.clone()).collect(),
2018-03-21 04:24:27 -04:00
outputs: asm.outputs
.iter()
.map(|out| hir::InlineAsmOutput {
constraint: out.constraint.clone(),
is_rw: out.is_rw,
is_indirect: out.is_indirect,
2018-03-21 04:24:27 -04:00
})
.collect(),
asm: asm.asm.clone(),
asm_str_style: asm.asm_str_style,
clobbers: asm.clobbers.clone().into(),
volatile: asm.volatile,
alignstack: asm.alignstack,
dialect: asm.dialect,
2017-03-17 04:04:41 +00:00
ctxt: asm.ctxt,
};
2018-03-21 04:24:27 -04:00
let outputs = asm.outputs
.iter()
.map(|out| self.lower_expr(&out.expr))
.collect();
let inputs = asm.inputs
.iter()
.map(|&(_, ref input)| self.lower_expr(input))
.collect();
hir::ExprInlineAsm(P(hir_asm), outputs, inputs)
}
2018-03-21 04:24:27 -04:00
ExprKind::Struct(ref path, ref fields, ref maybe_expr) => hir::ExprStruct(
self.lower_qpath(
e.id,
&None,
path,
ParamMode::Optional,
ImplTraitContext::Disallowed,
),
fields.iter().map(|x| self.lower_field(x)).collect(),
maybe_expr.as_ref().map(|x| P(self.lower_expr(x))),
),
ExprKind::Paren(ref ex) => {
let mut ex = self.lower_expr(ex);
// include parens in span, but only if it is a super-span.
if e.span.contains(ex.span) {
ex.span = e.span;
}
// merge attributes into the inner expression.
let mut attrs = e.attrs.clone();
attrs.extend::<Vec<_>>(ex.attrs.into());
ex.attrs = attrs;
return ex;
}
2016-12-26 14:34:03 +01:00
ExprKind::Yield(ref opt_expr) => {
self.is_generator = true;
2018-03-21 04:24:27 -04:00
let expr = opt_expr
.as_ref()
.map(|x| self.lower_expr(x))
.unwrap_or_else(|| self.expr(e.span, hir::ExprTup(hir_vec![]), ThinVec::new()));
2017-07-10 21:11:31 +02:00
hir::ExprYield(P(expr))
2016-12-26 14:34:03 +01:00
}
// Desugar ExprIfLet
// From: `if let <pat> = <sub_expr> <body> [<else_opt>]`
ExprKind::IfLet(ref pats, ref sub_expr, ref body, ref else_opt) => {
// to:
//
// match <sub_expr> {
// <pat> => <body>,
// _ => [<else_opt> | ()]
// }
let mut arms = vec![];
// `<pat> => <body>`
{
let body = self.lower_block(body, false);
let body_expr = P(self.expr_block(body, ThinVec::new()));
let pats = pats.iter().map(|pat| self.lower_pat(pat)).collect();
arms.push(self.arm(pats, body_expr));
}
// _ => [<else_opt>|()]
{
let wildcard_arm: Option<&Expr> = else_opt.as_ref().map(|p| &**p);
let wildcard_pattern = self.pat_wild(e.span);
let body = if let Some(else_expr) = wildcard_arm {
2017-04-15 17:40:54 +05:30
P(self.lower_expr(else_expr))
2017-04-15 17:35:30 +05:30
} else {
2017-04-15 17:40:54 +05:30
self.expr_tuple(e.span, hir_vec![])
2017-04-15 17:35:30 +05:30
};
arms.push(self.arm(hir_vec![wildcard_pattern], body));
}
2015-09-28 17:24:42 +13:00
let contains_else_clause = else_opt.is_some();
2015-09-28 17:24:42 +13:00
let sub_expr = P(self.lower_expr(sub_expr));
2015-09-28 15:00:15 +13:00
hir::ExprMatch(
sub_expr,
arms.into(),
hir::MatchSource::IfLetDesugar {
contains_else_clause,
2018-03-21 04:24:27 -04:00
},
)
}
2015-09-28 15:00:15 +13:00
// Desugar ExprWhileLet
// From: `[opt_ident]: while let <pat> = <sub_expr> <body>`
ExprKind::WhileLet(ref pats, ref sub_expr, ref body, opt_label) => {
// to:
//
// [opt_ident]: loop {
// match <sub_expr> {
// <pat> => <body>,
// _ => break
// }
// }
// Note that the block AND the condition are evaluated in the loop scope.
// This is done to allow `break` from inside the condition of the loop.
2018-03-21 04:24:27 -04:00
let (body, break_expr, sub_expr) = self.with_loop_scope(e.id, |this| {
(
this.lower_block(body, false),
this.expr_break(e.span, ThinVec::new()),
this.with_loop_condition_scope(|this| P(this.lower_expr(sub_expr))),
)
});
// `<pat> => <body>`
let pat_arm = {
let body_expr = P(self.expr_block(body, ThinVec::new()));
let pats = pats.iter().map(|pat| self.lower_pat(pat)).collect();
self.arm(pats, body_expr)
};
2015-09-28 15:00:15 +13:00
// `_ => break`
let break_arm = {
let pat_under = self.pat_wild(e.span);
self.arm(hir_vec![pat_under], break_expr)
};
2016-05-02 00:02:38 +00:00
// `match <sub_expr> { ... }`
let arms = hir_vec![pat_arm, break_arm];
2018-03-21 04:24:27 -04:00
let match_expr = self.expr(
sub_expr.span,
hir::ExprMatch(sub_expr, arms, hir::MatchSource::WhileLetDesugar),
ThinVec::new(),
);
// `[opt_ident]: loop { ... }`
let loop_block = P(self.block_expr(P(match_expr)));
2018-03-21 04:24:27 -04:00
let loop_expr = hir::ExprLoop(
loop_block,
self.lower_label(opt_label),
hir::LoopSource::WhileLet,
);
// add attributes to the outer returned expr node
loop_expr
}
// Desugar ExprForLoop
// From: `[opt_ident]: for <pat> in <head> <body>`
ExprKind::ForLoop(ref pat, ref head, ref body, opt_label) => {
// to:
//
// {
// let result = match ::std::iter::IntoIterator::into_iter(<head>) {
// mut iter => {
// [opt_ident]: loop {
// let mut __next;
// match ::std::iter::Iterator::next(&mut iter) {
// ::std::option::Option::Some(val) => __next = val,
// ::std::option::Option::None => break
// };
// let <pat> = __next;
// StmtExpr(<body>);
// }
// }
// };
// result
// }
// expand <head>
let head = self.lower_expr(head);
let head_sp = head.span;
let iter = self.str_to_ident("iter");
let next_ident = self.str_to_ident("__next");
2018-03-21 04:24:27 -04:00
let next_pat = self.pat_ident_binding_mode(
pat.span,
next_ident,
hir::BindingAnnotation::Mutable,
);
// `::std::option::Option::Some(val) => next = val`
let pat_arm = {
let val_ident = self.str_to_ident("val");
let val_pat = self.pat_ident(pat.span, val_ident);
let val_expr = P(self.expr_ident(pat.span, val_ident, val_pat.id));
let next_expr = P(self.expr_ident(pat.span, next_ident, next_pat.id));
2018-03-21 04:24:27 -04:00
let assign = P(self.expr(
pat.span,
hir::ExprAssign(next_expr, val_expr),
ThinVec::new(),
));
let some_pat = self.pat_some(pat.span, val_pat);
self.arm(hir_vec![some_pat], assign)
};
2016-05-02 00:02:38 +00:00
// `::std::option::Option::None => break`
let break_arm = {
2018-03-21 04:24:27 -04:00
let break_expr =
self.with_loop_scope(e.id, |this| this.expr_break(e.span, ThinVec::new()));
let pat = self.pat_none(e.span);
self.arm(hir_vec![pat], break_expr)
};
2016-05-02 00:02:38 +00:00
// `mut iter`
2018-03-21 04:24:27 -04:00
let iter_pat =
self.pat_ident_binding_mode(head_sp, iter, hir::BindingAnnotation::Mutable);
// `match ::std::iter::Iterator::next(&mut iter) { ... }`
let match_expr = {
let iter = P(self.expr_ident(head_sp, iter, iter_pat.id));
let ref_mut_iter = self.expr_mut_addr_of(head_sp, iter);
let next_path = &["iter", "Iterator", "next"];
let next_path = P(self.expr_std_path(head_sp, next_path, ThinVec::new()));
2018-03-21 04:24:27 -04:00
let next_expr = P(self.expr_call(head_sp, next_path, hir_vec![ref_mut_iter]));
let arms = hir_vec![pat_arm, break_arm];
2018-03-21 04:24:27 -04:00
P(self.expr(
head_sp,
hir::ExprMatch(next_expr, arms, hir::MatchSource::ForLoopDesugar),
ThinVec::new(),
))
};
let match_stmt = respan(head_sp, hir::StmtExpr(match_expr, self.next_id().node_id));
let next_expr = P(self.expr_ident(head_sp, next_ident, next_pat.id));
// `let mut __next`
2018-03-21 04:24:27 -04:00
let next_let =
self.stmt_let_pat(head_sp, None, next_pat, hir::LocalSource::ForLoopDesugar);
// `let <pat> = __next`
let pat = self.lower_pat(pat);
2018-03-21 04:24:27 -04:00
let pat_let = self.stmt_let_pat(
head_sp,
Some(next_expr),
pat,
2018-03-21 04:24:27 -04:00
hir::LocalSource::ForLoopDesugar,
);
let body_block = self.with_loop_scope(e.id, |this| this.lower_block(body, false));
let body_expr = P(self.expr_block(body_block, ThinVec::new()));
let body_stmt = respan(body.span, hir::StmtExpr(body_expr, self.next_id().node_id));
2018-03-21 04:24:27 -04:00
let loop_block = P(self.block_all(
e.span,
hir_vec![next_let, match_stmt, pat_let, body_stmt],
None,
));
// `[opt_ident]: loop { ... }`
2018-03-21 04:24:27 -04:00
let loop_expr = hir::ExprLoop(
loop_block,
self.lower_label(opt_label),
hir::LoopSource::ForLoop,
);
let LoweredNodeId { node_id, hir_id } = self.lower_node_id(e.id);
let loop_expr = P(hir::Expr {
id: node_id,
hir_id,
node: loop_expr,
span: e.span,
attrs: ThinVec::new(),
});
2015-09-28 15:00:15 +13:00
// `mut iter => { ... }`
let iter_arm = self.arm(hir_vec![iter_pat], loop_expr);
// `match ::std::iter::IntoIterator::into_iter(<head>) { ... }`
let into_iter_expr = {
let into_iter_path = &["iter", "IntoIterator", "into_iter"];
2018-03-21 04:24:27 -04:00
let into_iter = P(self.expr_std_path(head_sp, into_iter_path, ThinVec::new()));
P(self.expr_call(head_sp, into_iter, hir_vec![head]))
};
2018-03-21 04:24:27 -04:00
let match_expr = P(self.expr_match(
head_sp,
into_iter_expr,
hir_vec![iter_arm],
hir::MatchSource::ForLoopDesugar,
));
// `{ let _result = ...; _result }`
// underscore prevents an unused_variables lint if the head diverges
let result_ident = self.str_to_ident("_result");
let (let_stmt, let_stmt_binding) =
self.stmt_let(e.span, false, result_ident, match_expr);
let result = P(self.expr_ident(e.span, result_ident, let_stmt_binding));
let block = P(self.block_all(e.span, hir_vec![let_stmt], Some(result)));
// add the attributes to the outer returned expr node
return self.expr_block(block, e.attrs.clone());
}
// Desugar ExprKind::Try
// From: `<expr>?`
ExprKind::Try(ref sub_expr) => {
// to:
//
// match Try::into_result(<expr>) {
// Ok(val) => #[allow(unreachable_code)] val,
// Err(err) => #[allow(unreachable_code)]
// // If there is an enclosing `catch {...}`
// break 'catch_target Try::from_error(From::from(err)),
// // Otherwise
// return Try::from_error(From::from(err)),
// }
let unstable_span =
self.allow_internal_unstable(CompilerDesugaringKind::QuestionMark, e.span);
// Try::into_result(<expr>)
let discr = {
// expand <expr>
let sub_expr = self.lower_expr(sub_expr);
let path = &["ops", "Try", "into_result"];
let path = P(self.expr_std_path(unstable_span, path, ThinVec::new()));
P(self.expr_call(e.span, path, hir_vec![sub_expr]))
};
// #[allow(unreachable_code)]
let attr = {
// allow(unreachable_code)
let allow = {
let allow_ident = Ident::from_str("allow").with_span_pos(e.span);
let uc_ident = Ident::from_str("unreachable_code").with_span_pos(e.span);
let uc_nested = attr::mk_nested_word_item(uc_ident);
attr::mk_list_item(e.span, allow_ident, vec![uc_nested])
};
attr::mk_spanned_attr_outer(e.span, attr::mk_attr_id(), allow)
};
let attrs = vec![attr];
// Ok(val) => #[allow(unreachable_code)] val,
let ok_arm = {
let val_ident = self.str_to_ident("val");
let val_pat = self.pat_ident(e.span, val_ident);
2018-03-21 04:24:27 -04:00
let val_expr = P(self.expr_ident_with_attrs(
e.span,
val_ident,
val_pat.id,
ThinVec::from(attrs.clone()),
));
let ok_pat = self.pat_ok(e.span, val_pat);
self.arm(hir_vec![ok_pat], val_expr)
};
// Err(err) => #[allow(unreachable_code)]
// return Try::from_error(From::from(err)),
let err_arm = {
let err_ident = self.str_to_ident("err");
let err_local = self.pat_ident(e.span, err_ident);
let from_expr = {
let path = &["convert", "From", "from"];
let from = P(self.expr_std_path(e.span, path, ThinVec::new()));
let err_expr = self.expr_ident(e.span, err_ident, err_local.id);
self.expr_call(e.span, from, hir_vec![err_expr])
};
let from_err_expr =
self.wrap_in_try_constructor("from_error", from_expr, unstable_span);
let thin_attrs = ThinVec::from(attrs);
let catch_scope = self.catch_scopes.last().map(|x| *x);
let ret_expr = if let Some(catch_node) = catch_scope {
P(self.expr(
e.span,
hir::ExprBreak(
hir::Destination {
label: None,
target_id: Ok(catch_node),
},
2018-03-21 04:24:27 -04:00
Some(from_err_expr),
),
2018-03-21 04:24:27 -04:00
thin_attrs,
))
} else {
2018-03-21 04:24:27 -04:00
P(self.expr(e.span, hir::Expr_::ExprRet(Some(from_err_expr)), thin_attrs))
};
let err_pat = self.pat_err(e.span, err_local);
self.arm(hir_vec![err_pat], ret_expr)
};
2016-05-02 00:02:38 +00:00
2018-03-21 04:24:27 -04:00
hir::ExprMatch(
discr,
hir_vec![err_arm, ok_arm],
hir::MatchSource::TryDesugar,
)
}
ExprKind::Mac(_) => panic!("Shouldn't exist here"),
};
let LoweredNodeId { node_id, hir_id } = self.lower_node_id(e.id);
hir::Expr {
id: node_id,
hir_id,
node: kind,
span: e.span,
attrs: e.attrs.clone(),
}
}
2015-07-31 00:04:06 -07:00
fn lower_stmt(&mut self, s: &Stmt) -> SmallVector<hir::Stmt> {
SmallVector::one(match s.node {
2016-06-17 02:30:01 +00:00
StmtKind::Local(ref l) => Spanned {
2018-03-21 04:24:27 -04:00
node: hir::StmtDecl(
P(Spanned {
node: hir::DeclLocal(self.lower_local(l)),
span: s.span,
}),
self.lower_node_id(s.id).node_id,
),
2016-06-17 02:30:01 +00:00
span: s.span,
},
StmtKind::Item(ref it) => {
// Can only use the ID once.
let mut id = Some(s.id);
2018-03-21 04:24:27 -04:00
return self.lower_item_id(it)
.into_iter()
.map(|item_id| Spanned {
node: hir::StmtDecl(
P(Spanned {
node: hir::DeclItem(item_id),
span: s.span,
}),
id.take()
.map(|id| self.lower_node_id(id).node_id)
.unwrap_or_else(|| self.next_id().node_id),
),
span: s.span,
2018-03-21 04:24:27 -04:00
})
.collect();
}
2018-03-21 04:24:27 -04:00
StmtKind::Expr(ref e) => Spanned {
node: hir::StmtExpr(P(self.lower_expr(e)), self.lower_node_id(s.id).node_id),
span: s.span,
},
StmtKind::Semi(ref e) => Spanned {
node: hir::StmtSemi(P(self.lower_expr(e)), self.lower_node_id(s.id).node_id),
span: s.span,
},
StmtKind::Mac(..) => panic!("Shouldn't exist here"),
})
2015-07-31 00:04:06 -07:00
}
fn lower_capture_clause(&mut self, c: CaptureBy) -> hir::CaptureClause {
match c {
CaptureBy::Value => hir::CaptureByValue,
CaptureBy::Ref => hir::CaptureByRef,
}
2015-07-31 00:04:06 -07:00
}
/// If an `explicit_owner` is given, this method allocates the `HirId` in
/// the address space of that item instead of the item currently being
/// lowered. This can happen during `lower_impl_item_ref()` where we need to
/// lower a `Visibility` value although we haven't lowered the owning
/// `ImplItem` in question yet.
2018-03-21 04:24:27 -04:00
fn lower_visibility(
&mut self,
v: &Visibility,
explicit_owner: Option<NodeId>,
) -> hir::Visibility {
2018-01-29 14:12:09 +09:00
match v.node {
VisibilityKind::Public => hir::Public,
VisibilityKind::Crate(sugar) => hir::Visibility::Crate(sugar),
2018-03-21 04:24:27 -04:00
VisibilityKind::Restricted { ref path, id, .. } => hir::Visibility::Restricted {
path: P(self.lower_path(id, path, ParamMode::Explicit)),
id: if let Some(owner) = explicit_owner {
self.lower_node_id_with_owner(id, owner).node_id
} else {
self.lower_node_id(id).node_id
},
},
2018-01-29 14:12:09 +09:00
VisibilityKind::Inherited => hir::Inherited,
}
2015-07-31 00:04:06 -07:00
}
fn lower_defaultness(&mut self, d: Defaultness, has_value: bool) -> hir::Defaultness {
match d {
2018-03-21 04:24:27 -04:00
Defaultness::Default => hir::Defaultness::Default {
has_value: has_value,
},
Defaultness::Final => {
assert!(has_value);
hir::Defaultness::Final
}
}
}
fn lower_block_check_mode(&mut self, b: &BlockCheckMode) -> hir::BlockCheckMode {
match *b {
BlockCheckMode::Default => hir::DefaultBlock,
BlockCheckMode::Unsafe(u) => hir::UnsafeBlock(self.lower_unsafe_source(u)),
}
2015-07-31 00:04:06 -07:00
}
fn lower_binding_mode(&mut self, b: &BindingMode) -> hir::BindingAnnotation {
match *b {
2018-03-21 04:24:27 -04:00
BindingMode::ByValue(Mutability::Immutable) => hir::BindingAnnotation::Unannotated,
BindingMode::ByRef(Mutability::Immutable) => hir::BindingAnnotation::Ref,
BindingMode::ByValue(Mutability::Mutable) => hir::BindingAnnotation::Mutable,
BindingMode::ByRef(Mutability::Mutable) => hir::BindingAnnotation::RefMut,
}
2015-07-31 00:04:06 -07:00
}
fn lower_unsafe_source(&mut self, u: UnsafeSource) -> hir::UnsafeSource {
match u {
CompilerGenerated => hir::CompilerGenerated,
UserProvided => hir::UserProvided,
}
2015-07-31 00:04:06 -07:00
}
fn lower_impl_polarity(&mut self, i: ImplPolarity) -> hir::ImplPolarity {
match i {
ImplPolarity::Positive => hir::ImplPolarity::Positive,
ImplPolarity::Negative => hir::ImplPolarity::Negative,
}
2015-07-31 00:04:06 -07:00
}
fn lower_trait_bound_modifier(&mut self, f: TraitBoundModifier) -> hir::TraitBoundModifier {
match f {
TraitBoundModifier::None => hir::TraitBoundModifier::None,
TraitBoundModifier::Maybe => hir::TraitBoundModifier::Maybe,
}
2015-07-31 00:04:06 -07:00
}
2015-09-28 15:00:15 +13:00
// Helper methods for building HIR.
2015-09-28 15:00:15 +13:00
fn arm(&mut self, pats: hir::HirVec<P<hir::Pat>>, expr: P<hir::Expr>) -> hir::Arm {
hir::Arm {
attrs: hir_vec![],
pats,
guard: None,
body: expr,
}
2015-09-28 15:00:15 +13:00
}
2018-05-26 02:50:15 +03:00
fn field(&mut self, ident: Ident, expr: P<hir::Expr>, span: Span) -> hir::Field {
hir::Field {
id: self.next_id().node_id,
2018-05-26 02:50:15 +03:00
ident,
span,
expr,
is_shorthand: false,
}
}
fn expr_break(&mut self, span: Span, attrs: ThinVec<Attribute>) -> P<hir::Expr> {
let expr_break = hir::ExprBreak(self.lower_loop_destination(None), None);
2017-02-15 14:52:27 -08:00
P(self.expr(span, expr_break, attrs))
}
2015-09-28 15:00:15 +13:00
2018-03-21 04:24:27 -04:00
fn expr_call(
&mut self,
span: Span,
e: P<hir::Expr>,
args: hir::HirVec<hir::Expr>,
) -> hir::Expr {
self.expr(span, hir::ExprCall(e, args), ThinVec::new())
}
2015-09-28 15:00:15 +13:00
fn expr_ident(&mut self, span: Span, id: Name, binding: NodeId) -> hir::Expr {
self.expr_ident_with_attrs(span, id, binding, ThinVec::new())
}
2018-03-21 04:24:27 -04:00
fn expr_ident_with_attrs(
&mut self,
span: Span,
id: Name,
binding: NodeId,
attrs: ThinVec<Attribute>,
) -> hir::Expr {
let expr_path = hir::ExprPath(hir::QPath::Resolved(
None,
P(hir::Path {
span,
def: Def::Local(binding),
segments: hir_vec![hir::PathSegment::from_name(id)],
}),
));
2016-05-06 08:24:04 +00:00
self.expr(span, expr_path, attrs)
}
2015-09-28 15:00:15 +13:00
fn expr_mut_addr_of(&mut self, span: Span, e: P<hir::Expr>) -> hir::Expr {
self.expr(span, hir::ExprAddrOf(hir::MutMutable, e), ThinVec::new())
}
2015-09-28 15:00:15 +13:00
2018-03-21 04:24:27 -04:00
fn expr_std_path(
&mut self,
span: Span,
components: &[&str],
attrs: ThinVec<Attribute>,
) -> hir::Expr {
let path = self.std_path(span, components, true);
2018-03-21 04:24:27 -04:00
self.expr(
span,
hir::ExprPath(hir::QPath::Resolved(None, P(path))),
attrs,
)
}
2015-09-28 15:00:15 +13:00
2018-03-21 04:24:27 -04:00
fn expr_match(
&mut self,
span: Span,
arg: P<hir::Expr>,
arms: hir::HirVec<hir::Arm>,
source: hir::MatchSource,
) -> hir::Expr {
self.expr(span, hir::ExprMatch(arg, arms, source), ThinVec::new())
}
2015-09-28 15:00:15 +13:00
fn expr_block(&mut self, b: P<hir::Block>, attrs: ThinVec<Attribute>) -> hir::Expr {
self.expr(b.span, hir::ExprBlock(b, None), attrs)
}
2015-09-28 15:00:15 +13:00
fn expr_tuple(&mut self, sp: Span, exprs: hir::HirVec<hir::Expr>) -> P<hir::Expr> {
P(self.expr(sp, hir::ExprTup(exprs), ThinVec::new()))
}
2015-09-28 17:24:42 +13:00
fn expr(&mut self, span: Span, node: hir::Expr_, attrs: ThinVec<Attribute>) -> hir::Expr {
let LoweredNodeId { node_id, hir_id } = self.next_id();
hir::Expr {
id: node_id,
hir_id,
node,
span,
attrs,
}
}
2018-03-21 04:24:27 -04:00
fn stmt_let_pat(
&mut self,
sp: Span,
ex: Option<P<hir::Expr>>,
pat: P<hir::Pat>,
source: hir::LocalSource,
) -> hir::Stmt {
let LoweredNodeId { node_id, hir_id } = self.next_id();
let local = P(hir::Local {
pat,
ty: None,
init: ex,
id: node_id,
hir_id,
span: sp,
attrs: ThinVec::new(),
source,
});
let decl = respan(sp, hir::DeclLocal(local));
respan(sp, hir::StmtDecl(P(decl), self.next_id().node_id))
}
2018-03-21 04:24:27 -04:00
fn stmt_let(
&mut self,
sp: Span,
mutbl: bool,
ident: Name,
ex: P<hir::Expr>,
) -> (hir::Stmt, NodeId) {
let pat = if mutbl {
self.pat_ident_binding_mode(sp, ident, hir::BindingAnnotation::Mutable)
} else {
self.pat_ident(sp, ident)
};
let pat_id = pat.id;
2018-03-21 04:24:27 -04:00
(
self.stmt_let_pat(sp, Some(ex), pat, hir::LocalSource::Normal),
pat_id,
)
}
2015-09-28 15:00:15 +13:00
fn block_expr(&mut self, expr: P<hir::Expr>) -> hir::Block {
self.block_all(expr.span, hir::HirVec::new(), Some(expr))
}
2015-09-28 15:00:15 +13:00
2018-03-21 04:24:27 -04:00
fn block_all(
&mut self,
span: Span,
stmts: hir::HirVec<hir::Stmt>,
expr: Option<P<hir::Expr>>,
) -> hir::Block {
let LoweredNodeId { node_id, hir_id } = self.next_id();
hir::Block {
stmts,
expr,
id: node_id,
hir_id,
rules: hir::DefaultBlock,
span,
targeted_by_break: false,
recovered: false,
}
}
2015-09-28 15:00:15 +13:00
fn pat_ok(&mut self, span: Span, pat: P<hir::Pat>) -> P<hir::Pat> {
self.pat_std_enum(span, &["result", "Result", "Ok"], hir_vec![pat])
}
2015-09-28 15:00:15 +13:00
fn pat_err(&mut self, span: Span, pat: P<hir::Pat>) -> P<hir::Pat> {
self.pat_std_enum(span, &["result", "Result", "Err"], hir_vec![pat])
}
fn pat_some(&mut self, span: Span, pat: P<hir::Pat>) -> P<hir::Pat> {
self.pat_std_enum(span, &["option", "Option", "Some"], hir_vec![pat])
}
fn pat_none(&mut self, span: Span) -> P<hir::Pat> {
self.pat_std_enum(span, &["option", "Option", "None"], hir_vec![])
}
2015-09-28 15:00:15 +13:00
2018-03-21 04:24:27 -04:00
fn pat_std_enum(
&mut self,
span: Span,
components: &[&str],
subpats: hir::HirVec<P<hir::Pat>>,
) -> P<hir::Pat> {
let path = self.std_path(span, components, true);
let qpath = hir::QPath::Resolved(None, P(path));
let pt = if subpats.is_empty() {
hir::PatKind::Path(qpath)
} else {
hir::PatKind::TupleStruct(qpath, subpats, None)
};
2016-11-29 00:33:59 +00:00
self.pat(span, pt)
}
2015-09-28 15:00:15 +13:00
2016-03-06 15:54:44 +03:00
fn pat_ident(&mut self, span: Span, name: Name) -> P<hir::Pat> {
self.pat_ident_binding_mode(span, name, hir::BindingAnnotation::Unannotated)
}
2015-09-28 15:00:15 +13:00
2018-03-21 04:24:27 -04:00
fn pat_ident_binding_mode(
&mut self,
span: Span,
name: Name,
bm: hir::BindingAnnotation,
) -> P<hir::Pat> {
let LoweredNodeId { node_id, hir_id } = self.next_id();
2015-09-28 17:24:42 +13:00
P(hir::Pat {
id: node_id,
hir_id,
2018-03-21 04:24:27 -04:00
node: hir::PatKind::Binding(bm, node_id, Spanned { span, node: name }, None),
span,
})
}
2015-09-28 15:00:15 +13:00
fn pat_wild(&mut self, span: Span) -> P<hir::Pat> {
self.pat(span, hir::PatKind::Wild)
}
2015-09-28 15:00:15 +13:00
fn pat(&mut self, span: Span, pat: hir::PatKind) -> P<hir::Pat> {
let LoweredNodeId { node_id, hir_id } = self.next_id();
P(hir::Pat {
id: node_id,
hir_id,
node: pat,
span,
})
}
2015-09-28 15:00:15 +13:00
/// Given suffix ["b","c","d"], returns path `::std::b::c::d` when
/// `fld.cx.use_std`, and `::core::b::c::d` otherwise.
/// The path is also resolved according to `is_value`.
fn std_path(&mut self, span: Span, components: &[&str], is_value: bool) -> hir::Path {
2018-03-21 04:24:27 -04:00
self.resolver
.resolve_str_path(span, self.crate_root, components, is_value)
}
2017-09-13 18:29:59 +03:00
fn ty_path(&mut self, id: LoweredNodeId, span: Span, qpath: hir::QPath) -> P<hir::Ty> {
let mut id = id;
let node = match qpath {
hir::QPath::Resolved(None, path) => {
// Turn trait object paths into `TyTraitObject` instead.
if let Def::Trait(_) = path.def {
let principal = hir::PolyTraitRef {
bound_generic_params: hir::HirVec::new(),
trait_ref: hir::TraitRef {
path: path.and_then(|path| path),
2017-09-13 18:29:59 +03:00
ref_id: id.node_id,
},
span,
};
// The original ID is taken by the `PolyTraitRef`,
// so the `Ty` itself needs a different one.
2017-09-13 18:29:59 +03:00
id = self.next_id();
hir::TyTraitObject(hir_vec![principal], self.elided_dyn_bound(span))
} else {
hir::TyPath(hir::QPath::Resolved(None, path))
}
}
2018-03-21 04:24:27 -04:00
_ => hir::TyPath(qpath),
};
2018-03-21 04:24:27 -04:00
P(hir::Ty {
id: id.node_id,
hir_id: id.hir_id,
node,
span,
})
}
/// Invoked to create the lifetime argument for a type `&T`
/// with no explicit lifetime.
fn elided_ref_lifetime(&mut self, span: Span) -> hir::Lifetime {
match self.anonymous_lifetime_mode {
// Intercept when we are in an impl header and introduce an in-band lifetime.
// Hence `impl Foo for &u32` becomes `impl<'f> Foo for &'f u32` for some fresh
// `'f`.
AnonymousLifetimeMode::CreateParameter => {
let fresh_name = self.collect_fresh_in_band_lifetime(span);
hir::Lifetime {
id: self.next_id().node_id,
span,
name: fresh_name,
}
}
AnonymousLifetimeMode::PassThrough => self.new_implicit_lifetime(span),
}
}
/// Invoked to create the lifetime argument(s) for a path like
/// `std::cell::Ref<T>`; note that implicit lifetimes in these
/// sorts of cases are deprecated. This may therefore report a warning or an
/// error, depending on the mode.
fn elided_path_lifetimes(&mut self, span: Span, count: usize) -> P<[hir::Lifetime]> {
match self.anonymous_lifetime_mode {
// NB. We intentionally ignore the create-parameter mode here
// and instead "pass through" to resolve-lifetimes, which will then
// report an error. This is because we don't want to support
// impl elision for deprecated forms like
//
// impl Foo for std::cell::Ref<u32> // note lack of '_
AnonymousLifetimeMode::CreateParameter => {}
// This is the normal case.
AnonymousLifetimeMode::PassThrough => {}
}
(0..count)
.map(|_| self.new_implicit_lifetime(span))
.collect()
}
/// Invoked to create the lifetime argument(s) for an elided trait object
/// bound, like the bound in `Box<dyn Debug>`. This method is not invoked
/// when the bound is written, even if it is written with `'_` like in
/// `Box<dyn Debug + '_>`. In those cases, `lower_lifetime` is invoked.
fn elided_dyn_bound(&mut self, span: Span) -> hir::Lifetime {
match self.anonymous_lifetime_mode {
// NB. We intentionally ignore the create-parameter mode here.
// and instead "pass through" to resolve-lifetimes, which will apply
// the object-lifetime-defaulting rules. Elided object lifetime defaults
// do not act like other elided lifetimes. In other words, given this:
//
// impl Foo for Box<dyn Debug>
//
// we do not introduce a fresh `'_` to serve as the bound, but instead
// ultimately translate to the equivalent of:
//
// impl Foo for Box<dyn Debug + 'static>
//
// `resolve_lifetime` has the code to make that happen.
AnonymousLifetimeMode::CreateParameter => {}
// This is the normal case.
AnonymousLifetimeMode::PassThrough => {}
}
self.new_implicit_lifetime(span)
}
fn new_implicit_lifetime(&mut self, span: Span) -> hir::Lifetime {
hir::Lifetime {
id: self.next_id().node_id,
span,
2017-09-19 16:36:54 -07:00
name: hir::LifetimeName::Implicit,
}
}
2018-02-22 22:44:44 -08:00
fn maybe_lint_bare_trait(&self, span: Span, id: NodeId, is_global: bool) {
2018-04-13 17:07:33 -05:00
self.sess.buffer_lint_with_diagnostic(
2018-05-19 01:13:53 +03:00
builtin::BARE_TRAIT_OBJECTS,
2018-04-13 17:07:33 -05:00
id,
span,
"trait objects without an explicit `dyn` are deprecated",
builtin::BuiltinLintDiagnostics::BareTraitObject(span, is_global),
)
2018-02-22 22:44:44 -08:00
}
fn wrap_in_try_constructor(
&mut self,
method: &'static str,
e: hir::Expr,
unstable_span: Span,
) -> P<hir::Expr> {
let path = &["ops", "Try", method];
let from_err = P(self.expr_std_path(unstable_span, path,
ThinVec::new()));
P(self.expr_call(e.span, from_err, hir_vec![e]))
}
}
2017-02-21 12:23:47 -05:00
fn body_ids(bodies: &BTreeMap<hir::BodyId, hir::Body>) -> Vec<hir::BodyId> {
// Sorting by span ensures that we get things in order within a
// file, and also puts the files in a sensible order.
let mut body_ids: Vec<_> = bodies.keys().cloned().collect();
body_ids.sort_by_key(|b| bodies[b].value.span);
body_ids
}