rust/src/librustc/hir/lowering.rs

5539 lines
219 KiB
Rust
Raw Normal View History

// ignore-tidy-filelength
//! 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
2019-02-08 13:53:55 +00:00
//! 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
2019-02-08 13:53:55 +00:00
//! being expanded. IDs are assigned to AST nodes just before lowering.
//!
2019-02-08 13:53:55 +00:00
//! 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
2019-02-08 13:53:55 +00:00
//! 'folding' an existing one), then you create a new ID using `next_id()`.
//!
2019-02-08 13:53:55 +00:00
//! 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
2019-02-08 13:53:55 +00:00
//! 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 07:04:06 +00:00
2019-02-05 17:20:45 +00:00
use crate::dep_graph::DepGraph;
use crate::hir::{self, ParamName};
use crate::hir::HirVec;
use crate::hir::map::{DefKey, DefPathData, Definitions};
use crate::hir::def_id::{DefId, DefIndex, DefIndexAddressSpace, CRATE_DEF_INDEX};
use crate::hir::def::{Res, DefKind, PartialRes, PerNS};
use crate::hir::{GenericArg, ConstArg};
2019-02-05 17:20:45 +00:00
use crate::lint::builtin::{self, PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES,
ELIDED_LIFETIMES_IN_PATHS};
2019-02-05 17:20:45 +00:00
use crate::middle::cstore::CrateStore;
use crate::session::Session;
use crate::session::config::nightly_options;
use crate::util::common::FN_OUTPUT_NAME;
use crate::util::nodemap::{DefIdMap, NodeMap};
2019-02-09 02:24:02 +00:00
use errors::Applicability;
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::indexed_vec::IndexVec;
use rustc_data_structures::thin_vec::ThinVec;
use rustc_data_structures::sync::Lrc;
2015-07-31 07:04:06 +00:00
2018-06-06 20:13:52 +00:00
use std::collections::{BTreeSet, BTreeMap};
2017-02-15 22:52:27 +00:00
use std::mem;
2018-08-30 09:42:16 +00:00
use smallvec::SmallVec;
use syntax::attr;
2018-02-23 17:48:54 +00:00
use syntax::ast;
2015-07-31 07:04:06 +00:00
use syntax::ast::*;
use syntax::errors;
2017-03-17 04:04:41 +00:00
use syntax::ext::hygiene::{Mark, SyntaxContext};
2017-12-15 20:27:20 +00:00
use syntax::print::pprust;
2015-07-31 07:04:06 +00:00
use syntax::ptr::P;
2018-08-18 10:14:03 +00:00
use syntax::source_map::{self, respan, CompilerDesugaringKind, Spanned};
2015-09-28 02:00:15 +00:00
use syntax::std_inject;
2018-03-21 08:24:27 +00:00
use syntax::symbol::{keywords, Symbol};
use syntax::tokenstream::{TokenStream, TokenTree};
use syntax::parse::token::Token;
use syntax::visit::{self, Visitor};
use syntax_pos::Span;
2015-07-31 07:04:06 +00:00
const HIR_ID_COUNTER_LOCKED: u32 = 0xFFFFFFFF;
pub struct LoweringContext<'a> {
2015-09-28 02:00:15 +00:00
crate_root: Option<&'static str>,
2017-06-04 16:15:42 +00:00
/// Used to assign ids to HIR nodes that do not directly correspond to an AST node.
sess: &'a Session,
2017-06-04 16:15:42 +00:00
cstore: &'a dyn CrateStore,
resolver: &'a mut dyn Resolver,
/// The items being lowered are collected here.
items: BTreeMap<hir::HirId, hir::Item>,
trait_items: BTreeMap<hir::TraitItemId, hir::TraitItem>,
impl_items: BTreeMap<hir::ImplItemId, hir::ImplItem>,
2017-02-21 15:55:40 +00:00
bodies: BTreeMap<hir::BodyId, hir::Body>,
exported_macros: Vec<hir::MacroDef>,
trait_impls: BTreeMap<DefId, Vec<hir::HirId>>,
2018-06-06 20:13:52 +00:00
modules: BTreeMap<NodeId, hir::ModuleItems>,
is_generator: bool,
2016-12-26 13:34:03 +00:00
catch_scopes: Vec<NodeId>,
2017-02-15 22:52:27 +00:00
loop_scopes: Vec<NodeId>,
is_in_loop_condition: bool,
is_in_trait_impl: bool,
2017-02-15 22:52:27 +00: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,
/// 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, ParamName)>,
/// 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,
/// including implicit lifetimes from `impl_header_lifetime_elision`.
2017-11-17 06:59:45 +00:00
is_collecting_in_band_lifetimes: bool,
/// 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.
2018-06-09 20:25:33 +00:00
in_scope_lifetimes: Vec<Ident>,
2017-11-17 06:59:45 +00:00
2018-06-06 20:13:52 +00:00
current_module: NodeId,
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 path generated by the lowerer when expanding `for`, `if let`, etc.
fn resolve_hir_path(
&mut self,
path: &ast::Path,
is_value: bool,
) -> hir::Path;
/// Obtain resolution for a `NodeId` with a single resolution.
fn get_partial_res(&mut self, id: NodeId) -> Option<PartialRes>;
/// Obtain per-namespace resolutions for `use` statement with the given `NoedId`.
fn get_import_res(&mut self, id: NodeId) -> PerNS<Option<Res<NodeId>>>;
/// Obtain resolution for a label with the given `NodeId`.
fn get_label_res(&mut self, id: NodeId) -> Option<NodeId>;
/// 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 06:07:55 +00: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 08:24:27 +00:00
fn resolve_str_path(
&mut self,
span: Span,
crate_root: Option<&str>,
components: &[&str],
is_value: bool,
) -> hir::Path;
2015-09-25 04:03:28 +00:00
}
#[derive(Debug)]
enum ImplTraitContext<'a> {
/// 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)`.
///
2018-08-19 02:40:50 +00:00
/// Newly generated parameters should be inserted into the given `Vec`.
Universal(&'a mut Vec<hir::GenericParam>),
2018-08-19 02:40:50 +00:00
/// Treat `impl Trait` as shorthand for a new existential parameter.
/// Example: `fn foo() -> impl Debug`, where `impl Debug` is conceptually
2018-08-19 02:40:50 +00:00
/// equivalent to a fresh existential parameter like `existential type T; fn foo() -> T`.
2018-05-22 12:31:56 +00:00
///
2018-08-19 02:40:50 +00:00
/// We optionally store a `DefId` for the parent item here so we can look up necessary
/// information later. It is `None` when no information about the context should be stored,
/// e.g., for consts and statics.
2018-08-19 02:40:50 +00:00
Existential(Option<DefId>),
/// `impl Trait` is not accepted in this position.
Disallowed(ImplTraitPosition),
}
/// Position in which `impl Trait` is disallowed. Used for error reporting.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
enum ImplTraitPosition {
Binding,
Other,
}
impl<'a> ImplTraitContext<'a> {
#[inline]
fn disallowed() -> Self {
ImplTraitContext::Disallowed(ImplTraitPosition::Other)
}
fn reborrow(&'b mut self) -> ImplTraitContext<'b> {
use self::ImplTraitContext::*;
match self {
Universal(params) => Universal(params),
Existential(did) => Existential(*did),
Disallowed(pos) => Disallowed(*pos),
}
}
}
2018-03-21 08:24:27 +00:00
pub fn lower_crate(
sess: &Session,
cstore: &dyn CrateStore,
2018-03-21 08:24:27 +00:00
dep_graph: &DepGraph,
krate: &Crate,
resolver: &mut dyn Resolver,
2018-03-21 08:24:27 +00:00
) -> 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,
items: BTreeMap::new(),
trait_items: BTreeMap::new(),
impl_items: BTreeMap::new(),
2017-02-21 15:55:40 +00:00
bodies: BTreeMap::new(),
trait_impls: BTreeMap::new(),
2018-06-06 20:13:52 +00:00
modules: BTreeMap::new(),
exported_macros: Vec::new(),
catch_scopes: Vec::new(),
2017-02-15 22:52:27 +00:00
loop_scopes: Vec::new(),
is_in_loop_condition: false,
anonymous_lifetime_mode: AnonymousLifetimeMode::PassThrough,
type_def_lifetime_params: Default::default(),
2018-06-06 20:13:52 +00:00
current_module: CRATE_NODE_ID,
current_hir_id_owner: vec![(CRATE_DEF_INDEX, 0)],
item_local_id_counters: Default::default(),
node_id_to_hir_id: IndexVec::new(),
is_generator: false,
is_in_trait_impl: false,
2017-11-17 06:59:45 +00: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 02:00:15 +00:00
#[derive(Copy, Clone, PartialEq)]
enum ParamMode {
/// Any path in a type context.
Explicit,
/// The `module::Type` in `module::Type::method` in an expression.
2018-03-21 08:24:27 +00:00
Optional,
}
enum ParenthesizedGenericArgs {
Ok,
Warn,
Err,
}
/// What to do when we encounter an **anonymous** lifetime
2019-02-08 13:53:55 +00:00
/// 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`
2019-02-08 13:53:55 +00:00
/// 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,
/// Give a hard error when either `&` or `'_` is written. Used to
/// rule out things like `where T: Foo<'_>`. Does not imply an
/// error on default object bounds (e.g., `Box<dyn Foo>`).
ReportError,
/// Pass responsibility to `resolve_lifetime` code for all cases.
PassThrough,
/// Used in the return types of `async fn` where there exists
/// exactly one argument-position elided lifetime.
///
/// In `async fn`, we lower the arguments types using the `CreateParameter`
/// mode, meaning that non-`dyn` elided lifetimes are assigned a fresh name.
/// If any corresponding elided lifetimes appear in the output, we need to
/// replace them with references to the fresh name assigned to the corresponding
/// elided lifetime in the arguments.
///
/// For **Modern cases**, replace the anonymous parameter with a
/// reference to a specific freshly-named lifetime that was
/// introduced in argument
///
/// For **Dyn Bound** cases, pass responsibility to
/// `resole_lifetime` code.
Replace(LtReplacement),
}
/// The type of elided lifetime replacement to perform on `async fn` return types.
#[derive(Copy, Clone)]
enum LtReplacement {
/// Fresh name introduced by the single non-dyn elided lifetime
/// in the arguments of the async fn.
Some(ParamName),
/// There is no single non-dyn elided lifetime because no lifetimes
/// appeared in the arguments.
NoLifetimes,
/// There is no single non-dyn elided lifetime because multiple
/// lifetimes appeared in the arguments.
MultipleLifetimes,
}
/// Calculates the `LtReplacement` to use for elided lifetimes in the return
/// type based on the fresh elided lifetimes introduced in argument position.
fn get_elided_lt_replacement(arg_position_lifetimes: &[(Span, ParamName)]) -> LtReplacement {
match arg_position_lifetimes {
[] => LtReplacement::NoLifetimes,
[(_span, param)] => LtReplacement::Some(*param),
_ => LtReplacement::MultipleLifetimes,
}
}
struct ImplTraitTypeIdVisitor<'a> { ids: &'a mut SmallVec<[NodeId; 1]> }
2018-08-19 02:40:50 +00:00
impl<'a, 'b> Visitor<'a> for ImplTraitTypeIdVisitor<'b> {
fn visit_ty(&mut self, ty: &'a Ty) {
match ty.node {
| TyKind::Typeof(_)
| TyKind::BareFn(_)
=> return,
TyKind::ImplTrait(id, _) => self.ids.push(id),
2018-08-19 02:40:50 +00:00
_ => {},
}
visit::walk_ty(self, ty);
}
fn visit_path_segment(
&mut self,
path_span: Span,
path_segment: &'v PathSegment,
) {
if let Some(ref p) = path_segment.args {
if let GenericArgs::Parenthesized(_) = **p {
return;
}
}
visit::walk_path_segment(self, path_span, path_segment)
}
}
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>,
2019-04-03 07:07:45 +00:00
hir_id_owner: Option<NodeId>,
}
impl MiscCollector<'_, '_> {
fn allocate_use_tree_hir_id_counters(
&mut self,
tree: &UseTree,
owner: DefIndex,
) {
match tree.kind {
UseTreeKind::Simple(_, id1, id2) => {
for &id in &[id1, id2] {
self.lctx.resolver.definitions().create_def_with_parent(
owner,
id,
DefPathData::Misc,
DefIndexAddressSpace::High,
Mark::root(),
tree.prefix.span,
);
2019-03-25 18:43:04 +00:00
self.lctx.allocate_hir_id_counter(id);
}
}
UseTreeKind::Glob => (),
UseTreeKind::Nested(ref trees) => {
for &(ref use_tree, id) in trees {
2019-04-26 12:23:30 +00:00
let hir_id = self.lctx.allocate_hir_id_counter(id);
self.allocate_use_tree_hir_id_counters(use_tree, hir_id.owner);
}
}
}
}
2019-04-03 07:07:45 +00:00
fn with_hir_id_owner<F, T>(&mut self, owner: Option<NodeId>, f: F) -> T
where
F: FnOnce(&mut Self) -> T,
{
let old = mem::replace(&mut self.hir_id_owner, owner);
let r = f(self);
self.hir_id_owner = old;
r
}
}
impl<'lcx, 'interner> Visitor<'lcx> for MiscCollector<'lcx, 'interner> {
2019-04-03 07:07:45 +00:00
fn visit_pat(&mut self, p: &'lcx Pat) {
match p.node {
// Doesn't generate a HIR node
2019-04-03 07:07:45 +00:00
PatKind::Paren(..) => {},
_ => {
if let Some(owner) = self.hir_id_owner {
self.lctx.lower_node_id_with_owner(p.id, owner);
}
}
};
visit::walk_pat(self, p)
}
fn visit_fn(&mut self, fk: visit::FnKind<'lcx>, fd: &'lcx FnDecl, s: Span, _: NodeId) {
if fk.header().map(|h| h.asyncness.node.is_async()).unwrap_or(false) {
// Don't visit the original pattern for async functions as it will be
// replaced.
for arg in &fd.inputs {
if let ArgSource::AsyncFn(pat) = &arg.source { self.visit_pat(pat); }
self.visit_ty(&arg.ty)
}
self.visit_fn_ret_ty(&fd.output);
match fk {
visit::FnKind::ItemFn(_, decl, _, body) => {
self.visit_fn_header(decl);
self.visit_block(body)
},
visit::FnKind::Method(_, sig, _, body) => {
self.visit_fn_header(&sig.header);
self.visit_block(body)
},
visit::FnKind::Closure(body) => self.visit_expr(body),
}
} else {
visit::walk_fn(self, fk, fd, s)
}
}
fn visit_item(&mut self, item: &'lcx Item) {
2019-04-26 12:23:30 +00:00
let hir_id = self.lctx.allocate_hir_id_counter(item.id);
match item.node {
2018-03-21 08:24:27 +00:00
ItemKind::Struct(_, ref generics)
| ItemKind::Union(_, ref generics)
| ItemKind::Enum(_, ref generics)
| ItemKind::Ty(_, ref generics)
2018-07-03 17:38:14 +00:00
| ItemKind::Existential(_, ref generics)
2018-03-21 08:24:27 +00:00
| ItemKind::Trait(_, _, ref generics, ..) => {
let def_id = self.lctx.resolver.definitions().local_def_id(item.id);
2018-03-21 08:24:27 +00:00
let count = generics
.params
.iter()
.filter(|param| match param.kind {
2018-05-27 19:07:09 +00:00
ast::GenericParamKind::Lifetime { .. } => true,
_ => false,
})
.count();
self.lctx.type_def_lifetime_params.insert(def_id, count);
}
ItemKind::Use(ref use_tree) => {
self.allocate_use_tree_hir_id_counters(use_tree, hir_id.owner);
}
_ => {}
}
2019-04-03 07:07:45 +00:00
self.with_hir_id_owner(Some(item.id), |this| {
visit::walk_item(this, item);
});
}
fn visit_trait_item(&mut self, item: &'lcx TraitItem) {
2019-03-25 18:43:04 +00:00
self.lctx.allocate_hir_id_counter(item.id);
2019-04-03 07:07:45 +00:00
match item.node {
TraitItemKind::Method(_, None) => {
// Ignore patterns in trait methods without bodies
self.with_hir_id_owner(None, |this| {
visit::walk_trait_item(this, item)
});
}
_ => self.with_hir_id_owner(Some(item.id), |this| {
visit::walk_trait_item(this, item);
})
}
}
fn visit_impl_item(&mut self, item: &'lcx ImplItem) {
2019-03-25 18:43:04 +00:00
self.lctx.allocate_hir_id_counter(item.id);
2019-04-03 07:07:45 +00:00
self.with_hir_id_owner(Some(item.id), |this| {
visit::walk_impl_item(this, item);
});
}
fn visit_foreign_item(&mut self, i: &'lcx ForeignItem) {
// Ignore patterns in foreign items
self.with_hir_id_owner(None, |this| {
visit::walk_foreign_item(this, i)
});
}
fn visit_ty(&mut self, t: &'lcx Ty) {
match t.node {
// Mirrors the case in visit::walk_ty
TyKind::BareFn(ref f) => {
walk_list!(
self,
visit_generic_param,
&f.generic_params
);
// Mirrors visit::walk_fn_decl
for argument in &f.decl.inputs {
// We don't lower the ids of argument patterns
self.with_hir_id_owner(None, |this| {
this.visit_pat(&argument.pat);
});
self.visit_ty(&argument.ty)
}
self.visit_fn_ret_ty(&f.decl.output)
}
_ => visit::walk_ty(self, t),
}
}
}
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 08:24:27 +00: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> {
2018-06-06 20:13:52 +00:00
fn visit_mod(&mut self, m: &'lcx Mod, _s: Span, _attrs: &[Attribute], n: NodeId) {
2019-01-11 03:58:46 +00:00
self.lctx.modules.insert(n, hir::ModuleItems {
items: BTreeSet::new(),
trait_items: BTreeSet::new(),
impl_items: BTreeSet::new(),
});
2018-06-06 20:13:52 +00:00
let old = self.lctx.current_module;
self.lctx.current_module = n;
visit::walk_mod(self, m);
self.lctx.current_module = old;
}
fn visit_item(&mut self, item: &'lcx Item) {
let mut item_hir_id = None;
self.lctx.with_hir_id_owner(item.id, |lctx| {
if let Some(hir_item) = lctx.lower_item(item) {
item_hir_id = Some(hir_item.hir_id);
lctx.insert_item(hir_item);
}
});
if let Some(hir_id) = item_hir_id {
let item_generics = match self.lctx.items.get(&hir_id).unwrap().node {
2018-07-11 15:36:06 +00:00
hir::ItemKind::Impl(_, _, _, ref generics, ..)
| hir::ItemKind::Trait(_, _, ref generics, ..) => {
generics.params.clone()
2018-03-21 08:24:27 +00:00
}
_ => HirVec::new(),
2017-11-17 06:59:45 +00:00
};
2018-06-14 11:05:47 +00:00
self.lctx.with_parent_impl_lifetime_defs(&item_generics, |this| {
let this = &mut ItemLowerer { lctx: this };
2018-09-24 03:25:23 +00:00
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 hir_item = lctx.lower_trait_item(item);
2019-03-01 09:28:13 +00:00
let id = hir::TraitItemId { hir_id: hir_item.hir_id };
lctx.trait_items.insert(id, hir_item);
2018-06-06 20:13:52 +00:00
lctx.modules.get_mut(&lctx.current_module).unwrap().trait_items.insert(id);
});
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 hir_item = lctx.lower_impl_item(item);
2019-03-01 09:28:13 +00:00
let id = hir::ImplItemId { hir_id: hir_item.hir_id };
lctx.impl_items.insert(id, hir_item);
2018-06-06 20:13:52 +00:00
lctx.modules.get_mut(&lctx.current_module).unwrap().impl_items.insert(id);
});
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);
2019-04-03 07:07:45 +00:00
visit::walk_crate(&mut MiscCollector { lctx: &mut self, hir_id_owner: None }, 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 17:23:47 +00: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,
2018-06-06 20:13:52 +00:00
modules: self.modules,
}
}
fn insert_item(&mut self, item: hir::Item) {
let id = item.hir_id;
// FIXME: Use debug_asset-rt
assert_eq!(id.local_id, hir::ItemLocalId::from_u32(0));
2018-06-06 20:13:52 +00:00
self.items.insert(id, item);
self.modules.get_mut(&self.current_module).unwrap().items.insert(id);
}
2019-04-26 12:23:30 +00:00
fn allocate_hir_id_counter(&mut self, owner: NodeId) -> hir::HirId {
2019-03-25 18:43:04 +00:00
// Setup the counter if needed
self.item_local_id_counters.entry(owner).or_insert(0);
// Always allocate the first `HirId` for the owner itself.
2019-03-25 18:43:04 +00:00
let lowered = self.lower_node_id_with_owner(owner, owner);
2019-04-26 12:23:30 +00:00
debug_assert_eq!(lowered.local_id.as_u32(), 0);
2019-03-25 18:43:04 +00:00
lowered
}
2019-04-26 12:23:30 +00:00
fn lower_node_id_generic<F>(&mut self, ast_node_id: NodeId, alloc_hir_id: F) -> hir::HirId
2018-03-21 08:24:27 +00:00
where
F: FnOnce(&mut Self) -> hir::HirId,
{
if ast_node_id == DUMMY_NODE_ID {
2019-04-26 12:23:30 +00:00
return hir::DUMMY_HIR_ID;
}
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;
2019-04-26 12:23:30 +00:00
hir_id
} else {
2019-04-26 12:23:30 +00:00
existing_hir_id
}
}
2018-05-22 12:31:56 +00:00
fn with_hir_id_owner<F, T>(&mut self, owner: NodeId, f: F) -> T
2018-03-21 08:24:27 +00:00
where
2018-05-22 12:31:56 +00:00
F: FnOnce(&mut Self) -> T,
{
let counter = self.item_local_id_counters
2018-03-21 08:24:27 +00:00
.insert(owner, HIR_ID_COUNTER_LOCKED)
2018-06-06 22:50:59 +00:00
.unwrap_or_else(|| panic!("No item_local_id_counters entry for {:?}", owner));
let def_index = self.resolver.definitions().opt_def_index(owner).unwrap();
self.current_hir_id_owner.push((def_index, counter));
2018-05-22 12:31:56 +00: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 08:24:27 +00:00
let prev = self.item_local_id_counters
.insert(owner, new_counter)
.unwrap();
debug_assert!(prev == HIR_ID_COUNTER_LOCKED);
2018-05-22 12:31:56 +00: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 `NodeId`s got mapped
/// properly. Calling the method twice with the same `NodeId` is fine though.
2019-04-26 12:23:30 +00:00
fn lower_node_id(&mut self, ast_node_id: NodeId) -> hir::HirId {
self.lower_node_id_generic(ast_node_id, |this| {
2018-03-21 08:24:27 +00: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::from_u32(local_id),
}
})
}
2019-04-26 12:23:30 +00:00
fn lower_node_id_with_owner(&mut self, ast_node_id: NodeId, owner: NodeId) -> hir::HirId {
self.lower_node_id_generic(ast_node_id, |this| {
2018-05-22 12:31:56 +00: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 12:31:56 +00: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::from_u32(local_id),
}
})
}
fn record_body(&mut self, value: hir::Expr, arguments: HirVec<hir::Arg>) -> hir::BodyId {
let body = hir::Body {
is_generator: self.is_generator,
arguments,
value,
};
let id = body.id();
self.bodies.insert(id, body);
id
}
2019-04-26 12:23:30 +00:00
fn next_id(&mut self) -> hir::HirId {
self.lower_node_id(self.sess.next_node_id())
}
fn lower_res(&mut self, res: Res<NodeId>) -> Res {
res.map_id(|id| {
2019-04-03 07:07:45 +00:00
self.lower_node_id_generic(id, |_| {
panic!("expected node_id to be lowered already for res {:#?}", res)
2019-04-26 12:23:30 +00:00
})
2019-04-03 07:07:45 +00:00
})
}
fn expect_full_res(&mut self, id: NodeId) -> Res<NodeId> {
self.resolver.get_partial_res(id).map_or(Res::Err, |pr| {
if pr.unresolved_segments() != 0 {
bug!("path not fully resolved: {:?}", pr);
}
pr.base_res()
})
}
fn expect_full_res_from_use(&mut self, id: NodeId) -> impl Iterator<Item = Res<NodeId>> {
self.resolver.get_import_res(id).present_items()
}
fn diagnostic(&self) -> &errors::Handler {
self.sess.diagnostic()
2015-09-28 02:00:15 +00:00
}
2015-10-06 19:26:22 +00:00
2018-06-10 14:40:45 +00:00
fn str_to_ident(&self, s: &'static str) -> Ident {
Ident::with_empty_ctxt(Symbol::gensym(s))
2015-10-06 19:26:22 +00:00
}
/// Reuses the span but adds information like the kind of the desugaring and features that are
/// allowed inside this span.
fn mark_span_with_reason(
&self,
reason: CompilerDesugaringKind,
span: Span,
allow_internal_unstable: Option<Lrc<[Symbol]>>,
) -> Span {
2017-03-22 08:39:51 +00:00
let mark = Mark::fresh(Mark::root());
2018-08-18 10:14:03 +00:00
mark.set_expn_info(source_map::ExpnInfo {
call_site: span,
def_site: Some(span),
2018-08-18 10:14:03 +00:00
format: source_map::CompilerDesugaring(reason),
allow_internal_unstable,
allow_internal_unsafe: false,
local_inner_macros: false,
2018-08-18 10:14:03 +00:00
edition: source_map::hygiene::default_edition(),
});
2017-07-31 20:04:34 +00: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 08:24:27 +00:00
where
F: FnOnce(&mut LoweringContext<'_>) -> (Vec<hir::GenericParam>, T),
2017-11-17 06:59:45 +00:00
{
assert!(!self.is_collecting_in_band_lifetimes);
assert!(self.lifetimes_to_define.is_empty());
let old_anonymous_lifetime_mode = self.anonymous_lifetime_mode;
self.anonymous_lifetime_mode = anonymous_lifetime_mode;
self.is_collecting_in_band_lifetimes = true;
2017-11-17 06:59:45 +00:00
let (in_band_ty_params, res) = f(self);
2017-11-17 06:59:45 +00:00
self.is_collecting_in_band_lifetimes = false;
self.anonymous_lifetime_mode = old_anonymous_lifetime_mode;
2017-11-17 06:59:45 +00:00
let lifetimes_to_define = self.lifetimes_to_define.split_off(0);
let params = lifetimes_to_define
.into_iter()
.map(|(span, hir_name)| self.lifetime_to_generic_param(
span, hir_name, parent_id.index,
))
2018-05-25 23:27:54 +00:00
.chain(in_band_ty_params.into_iter())
.collect();
(params, res)
2017-11-17 06:59:45 +00:00
}
/// Converts a lifetime into a new generic parameter.
fn lifetime_to_generic_param(
&mut self,
span: Span,
hir_name: ParamName,
parent_index: DefIndex,
) -> hir::GenericParam {
2019-04-26 12:23:30 +00:00
let node_id = self.sess.next_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, kind) = match hir_name {
ParamName::Plain(ident) => (
ident.as_interned_str(),
hir::LifetimeParamKind::InBand,
),
ParamName::Fresh(_) => (
keywords::UnderscoreLifetime.name().as_interned_str(),
hir::LifetimeParamKind::Elided,
),
ParamName::Error => (
keywords::UnderscoreLifetime.name().as_interned_str(),
hir::LifetimeParamKind::Error,
),
};
// Add a definition for the in-band lifetime def.
self.resolver.definitions().create_def_with_parent(
parent_index,
node_id,
DefPathData::LifetimeNs(str_name),
DefIndexAddressSpace::High,
Mark::root(),
span,
);
hir::GenericParam {
2019-04-26 12:23:30 +00:00
hir_id: self.lower_node_id(node_id),
name: hir_name,
attrs: hir_vec![],
bounds: hir_vec![],
span,
pure_wrt_drop: false,
kind: hir::GenericParamKind::Lifetime { kind }
}
}
/// 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.
2018-06-09 20:25:33 +00:00
fn maybe_collect_in_band_lifetime(&mut self, ident: Ident) {
if !self.is_collecting_in_band_lifetimes {
return;
}
if !self.sess.features_untracked().in_band_lifetimes {
return;
}
2018-06-09 20:25:33 +00:00
if self.in_scope_lifetimes.contains(&ident.modern()) {
return;
}
2018-06-27 21:12:17 +00:00
let hir_name = ParamName::Plain(ident);
2018-06-09 20:25:33 +00:00
if self.lifetimes_to_define.iter()
2018-06-27 21:12:17 +00:00
.any(|(_, lt_name)| lt_name.modern() == hir_name.modern()) {
return;
}
2018-06-09 20:25:33 +00:00
self.lifetimes_to_define.push((ident.span, hir_name));
}
/// When we have either an elided or `'_` lifetime in an impl
/// header, we convert it to an in-band lifetime.
fn collect_fresh_in_band_lifetime(&mut self, span: Span) -> ParamName {
assert!(self.is_collecting_in_band_lifetimes);
let index = self.lifetimes_to_define.len();
let hir_name = ParamName::Fresh(index);
self.lifetimes_to_define.push((span, hir_name));
hir_name
}
2018-05-26 18:16:21 +00:00
// Evaluates `f` with the lifetimes in `params` in-scope.
2017-11-17 06:59:45 +00: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<T, F>(&mut self, params: &[GenericParam], f: F) -> T
2018-03-21 08:24:27 +00:00
where
F: FnOnce(&mut LoweringContext<'_>) -> T,
2017-11-17 06:59:45 +00:00
{
let old_len = self.in_scope_lifetimes.len();
let lt_def_names = params.iter().filter_map(|param| match param.kind {
2018-06-09 20:25:33 +00:00
GenericParamKind::Lifetime { .. } => Some(param.ident.modern()),
_ => None,
});
2017-11-17 06:59:45 +00:00
self.in_scope_lifetimes.extend(lt_def_names);
let res = f(self);
self.in_scope_lifetimes.truncate(old_len);
res
}
2018-05-26 18:16:21 +00:00
// Same as the method above, but accepts `hir::GenericParam`s
// instead of `ast::GenericParam`s.
2017-11-17 06:59:45 +00: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.
fn with_parent_impl_lifetime_defs<T, F>(&mut self,
params: &HirVec<hir::GenericParam>,
f: F
) -> T where
F: FnOnce(&mut LoweringContext<'_>) -> T,
2017-11-17 06:59:45 +00:00
{
let old_len = self.in_scope_lifetimes.len();
let lt_def_names = params.iter().filter_map(|param| match param.kind {
2018-06-09 20:25:33 +00:00
hir::GenericParamKind::Lifetime { .. } => Some(param.name.ident().modern()),
_ => None,
});
2017-11-17 06:59:45 +00: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 20:27:20 +00:00
fn add_in_band_defs<F, T>(
2017-11-17 06:59:45 +00:00
&mut self,
generics: &Generics,
parent_id: DefId,
anonymous_lifetime_mode: AnonymousLifetimeMode,
2018-03-21 08:24:27 +00:00
f: F,
2017-11-17 06:59:45 +00:00
) -> (hir::Generics, T)
2018-03-21 08:24:27 +00:00
where
F: FnOnce(&mut LoweringContext<'_>, &mut Vec<hir::GenericParam>) -> T,
2017-11-17 06:59:45 +00:00
{
2018-03-21 08:24:27 +00:00
let (in_band_defs, (mut lowered_generics, res)) = self.with_in_scope_lifetime_defs(
&generics.params,
2018-03-21 08:24:27 +00:00
|this| {
this.collect_in_band_defs(parent_id, anonymous_lifetime_mode, |this| {
let mut params = Vec::new();
// Note: it is necessary to lower generics *before* calling `f`.
// When lowering `async fn`, there's a final step when lowering
// the return type that assumes that all in-scope lifetimes have
// already been added to either `in_scope_lifetimes` or
// `lifetimes_to_define`. If we swapped the order of these two,
// in-band-lifetimes introduced by generics or where-clauses
// wouldn't have been added yet.
let generics = this.lower_generics(
generics,
ImplTraitContext::Universal(&mut params),
);
let res = f(this, &mut params);
(params, (generics, res))
2018-03-21 08:24:27 +00:00
})
},
);
2017-12-15 20:27:20 +00:00
2018-03-21 08:24:27 +00:00
lowered_generics.params = lowered_generics
.params
.iter()
.cloned()
.chain(in_band_defs)
.collect();
2017-11-17 06:59:45 +00:00
(lowered_generics, res)
}
fn with_catch_scope<T, F>(&mut self, catch_id: NodeId, f: F) -> T
2018-03-21 08:24:27 +00: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 08:24:27 +00: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
}
2018-06-06 22:50:59 +00:00
fn make_async_expr(
&mut self,
capture_clause: CaptureBy,
closure_node_id: NodeId,
ret_ty: Option<&Ty>,
span: Span,
body: impl FnOnce(&mut LoweringContext<'_>) -> hir::Expr,
2018-07-11 12:05:29 +00:00
) -> hir::ExprKind {
2018-06-06 22:50:59 +00:00
let prev_is_generator = mem::replace(&mut self.is_generator, true);
let output = match ret_ty {
Some(ty) => FunctionRetTy::Ty(P(ty.clone())),
None => FunctionRetTy::Default(span),
};
let decl = FnDecl {
inputs: vec![],
output,
c_variadic: false
2018-06-06 22:50:59 +00:00
};
// Lower the arguments before the body otherwise the body will call `lower_res` expecting
// the argument to have been assigned an id already.
let arguments = self.lower_args(Some(&decl));
let body_expr = body(self);
let body_id = self.record_body(body_expr, arguments);
2018-06-06 22:50:59 +00:00
self.is_generator = prev_is_generator;
let capture_clause = self.lower_capture_clause(capture_clause);
let decl = self.lower_fn_decl(&decl, None, /* impl trait allowed */ false, None);
2018-06-06 22:50:59 +00:00
let generator = hir::Expr {
2019-04-26 12:23:30 +00:00
hir_id: self.lower_node_id(closure_node_id),
2018-07-11 12:05:29 +00:00
node: hir::ExprKind::Closure(capture_clause, decl, body_id, span,
2018-06-06 22:50:59 +00:00
Some(hir::GeneratorMovability::Static)),
span,
attrs: ThinVec::new(),
};
let unstable_span = self.mark_span_with_reason(
CompilerDesugaringKind::Async,
span,
Some(vec![
Symbol::intern("gen_future"),
].into()),
);
2018-06-06 22:50:59 +00:00
let gen_future = self.expr_std_path(
unstable_span, &["future", "from_generator"], None, ThinVec::new());
2018-07-11 12:05:29 +00:00
hir::ExprKind::Call(P(gen_future), hir_vec![generator])
2018-06-06 22:50:59 +00:00
}
2016-12-26 13:34:03 +00:00
fn lower_body<F>(&mut self, decl: Option<&FnDecl>, f: F) -> hir::BodyId
2018-03-21 08:24:27 +00:00
where
F: FnOnce(&mut LoweringContext<'_>) -> hir::Expr,
2016-12-26 13:34:03 +00:00
{
let prev = mem::replace(&mut self.is_generator, false);
let arguments = self.lower_args(decl);
2016-12-26 13:34:03 +00:00
let result = f(self);
let r = self.record_body(result, arguments);
2017-07-11 19:57:05 +00:00
self.is_generator = prev;
2018-03-21 08:24:27 +00:00
return r;
2016-12-26 13:34:03 +00:00
}
2017-02-15 22:52:27 +00:00
fn with_loop_scope<T, F>(&mut self, loop_id: NodeId, f: F) -> T
2018-03-21 08:24:27 +00:00
where
F: FnOnce(&mut LoweringContext<'_>) -> T,
2017-02-15 22:52:27 +00: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 22:52:27 +00:00
let len = self.loop_scopes.len();
self.loop_scopes.push(loop_id);
2017-02-15 22:52:27 +00:00
let result = f(self);
2018-03-21 08:24:27 +00:00
assert_eq!(
len + 1,
self.loop_scopes.len(),
"Loop scopes should be added and removed in stack order"
);
2017-02-15 22:52:27 +00: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 08:24:27 +00: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 22:52:27 +00:00
result
}
fn with_new_scopes<T, F>(&mut self, f: F) -> T
2018-03-21 08:24:27 +00:00
where
F: FnOnce(&mut LoweringContext<'_>) -> T,
2017-02-15 22:52:27 +00: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 22:52:27 +00:00
let loop_scopes = mem::replace(&mut self.loop_scopes, Vec::new());
2018-08-19 02:40:50 +00:00
let ret = f(self);
self.catch_scopes = catch_scopes;
self.loop_scopes = loop_scopes;
self.is_in_loop_condition = was_in_loop_condition;
2018-08-19 02:40:50 +00:00
ret
2017-02-15 22:52:27 +00:00
}
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)
}
}
fn lower_label(&mut self, label: Option<Label>) -> Option<hir::Label> {
2018-03-21 08:24:27 +00:00
label.map(|label| hir::Label {
ident: label.ident,
2018-03-21 08:24:27 +00:00
})
}
2018-03-21 08:24:27 +00:00
fn lower_loop_destination(&mut self, destination: Option<(NodeId, Label)>) -> hir::Destination {
2018-07-20 13:59:00 +00:00
let target_id = match destination {
Some((id, _)) => {
if let Some(loop_id) = self.resolver.get_label_res(id) {
2019-04-26 12:23:30 +00:00
Ok(self.lower_node_id(loop_id))
2018-07-20 13:59:00 +00:00
} else {
Err(hir::LoopIdError::UnresolvedLabel)
}
}
2018-07-20 13:59:00 +00:00
None => {
self.loop_scopes
.last()
2018-09-12 10:31:11 +00:00
.cloned()
2019-04-26 12:23:30 +00:00
.map(|id| Ok(self.lower_node_id(id)))
2018-07-20 13:59:00 +00:00
.unwrap_or(Err(hir::LoopIdError::OutsideLoopScope))
.into()
}
};
hir::Destination {
label: self.lower_label(destination.map(|(_, label)| label)),
target_id,
2017-02-15 22:52:27 +00:00
}
}
2018-03-21 22:11:27 +00:00
fn lower_attrs(&mut self, attrs: &[Attribute]) -> hir::HirVec<Attribute> {
2018-03-21 08:24:27 +00:00
attrs
.iter()
.map(|a| self.lower_attr(a))
2018-11-05 14:30:04 +00:00
.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 15:28:34 +00:00
}
fn lower_attr(&mut self, attr: &Attribute) -> Attribute {
// Note that we explicitly do not walk the path. Since we don't really
// lower attributes (we use the AST version) there is nowhere to keep
// the `HirId`s. We don't actually need HIR version of attributes anyway.
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 15:28:34 +00:00
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 08:24:27 +00: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 15:28:34 +00: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 15:28:34 +00:00
match tree {
2018-03-21 08:24:27 +00:00
TokenTree::Token(span, token) => self.lower_token(token, span),
TokenTree::Delimited(span, delim, tts) => TokenTree::Delimited(
2018-03-21 08:24:27 +00:00
span,
delim,
self.lower_token_stream(tts),
2018-03-21 08:24:27 +00: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 15:28:34 +00: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 15:28:34 +00:00
match token {
Token::Interpolated(nt) => {
let tts = nt.to_tokenstream(&self.sess.parse_sess, span);
self.lower_token_stream(tts)
}
other => 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 15:28:34 +00:00
}
}
2015-07-31 07:04:06 +00: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(),
2018-08-30 04:18:11 +00:00
guard: match arm.guard {
Some(Guard::If(ref x)) => Some(hir::Guard::If(P(self.lower_expr(x)))),
_ => None,
},
body: P(self.lower_expr(&arm.body)),
}
2015-07-31 07:04:06 +00:00
}
fn lower_ty_binding(&mut self, b: &TypeBinding,
itctx: ImplTraitContext<'_>) -> hir::TypeBinding {
hir::TypeBinding {
2019-04-26 12:23:30 +00:00
hir_id: self.lower_node_id(b.id),
ident: b.ident,
ty: self.lower_ty(&b.ty, itctx),
span: b.span,
}
2015-07-31 07:04:06 +00:00
}
fn lower_generic_arg(&mut self,
2018-05-27 19:07:09 +00:00
arg: &ast::GenericArg,
itctx: ImplTraitContext<'_>)
2018-02-23 17:48:54 +00:00
-> hir::GenericArg {
match arg {
2018-05-27 19:07:09 +00:00
ast::GenericArg::Lifetime(lt) => GenericArg::Lifetime(self.lower_lifetime(&lt)),
ast::GenericArg::Type(ty) => GenericArg::Type(self.lower_ty_direct(&ty, itctx)),
ast::GenericArg::Const(ct) => {
GenericArg::Const(ConstArg {
value: self.lower_anon_const(&ct),
span: ct.value.span,
})
}
}
}
fn lower_ty(&mut self, t: &Ty, itctx: ImplTraitContext<'_>) -> P<hir::Ty> {
P(self.lower_ty_direct(t, itctx))
}
fn lower_ty_direct(&mut self, t: &Ty, mut itctx: ImplTraitContext<'_>) -> hir::Ty {
let kind = match t.node {
2018-07-11 14:41:03 +00:00
TyKind::Infer => hir::TyKind::Infer,
TyKind::Err => hir::TyKind::Err,
TyKind::Slice(ref ty) => hir::TyKind::Slice(self.lower_ty(ty, itctx)),
TyKind::Ptr(ref mt) => hir::TyKind::Ptr(self.lower_mt(mt, itctx)),
TyKind::Rptr(ref region, ref mt) => {
let span = self.sess.source_map().next_point(t.span.shrink_to_lo());
let lifetime = match *region {
Some(ref lt) => self.lower_lifetime(lt),
None => self.elided_ref_lifetime(span),
};
2018-07-11 14:41:03 +00:00
hir::TyKind::Rptr(lifetime, self.lower_mt(mt, itctx))
}
2018-03-21 08:24:27 +00:00
TyKind::BareFn(ref f) => self.with_in_scope_lifetime_defs(
&f.generic_params,
2018-03-21 08:24:27 +00:00
|this| {
this.with_anonymous_lifetime_mode(
AnonymousLifetimeMode::PassThrough,
|this| {
2018-07-11 14:41:03 +00:00
hir::TyKind::BareFn(P(hir::BareFnTy {
generic_params: this.lower_generic_params(
&f.generic_params,
&NodeMap::default(),
ImplTraitContext::disallowed(),
),
unsafety: this.lower_unsafety(f.unsafety),
abi: f.abi,
decl: this.lower_fn_decl(&f.decl, None, false, None),
arg_names: this.lower_fn_args_to_names(&f.decl),
}))
},
)
2018-03-21 08:24:27 +00:00
},
),
2018-07-11 14:41:03 +00:00
TyKind::Never => hir::TyKind::Never,
TyKind::Tup(ref tys) => {
2018-07-11 14:41:03 +00:00
hir::TyKind::Tup(tys.iter().map(|ty| {
self.lower_ty_direct(ty, itctx.reborrow())
}).collect())
}
TyKind::Paren(ref ty) => {
return self.lower_ty_direct(ty, itctx);
}
TyKind::Path(ref qself, ref path) => {
2017-09-13 15:29:59 +00:00
let id = self.lower_node_id(t.id);
let qpath = self.lower_qpath(t.id, qself, path, ParamMode::Explicit, itctx);
2018-02-23 06:44:44 +00:00
let ty = self.ty_path(id, t.span, qpath);
2018-07-11 14:41:03 +00:00
if let hir::TyKind::TraitObject(..) = ty.node {
self.maybe_lint_bare_trait(t.span, t.id, qself.is_none() && path.is_global());
2018-02-23 06:44:44 +00:00
}
return ty;
}
2019-04-03 07:07:45 +00:00
TyKind::ImplicitSelf => {
let res = self.expect_full_res(t.id);
let res = self.lower_res(res);
2019-04-03 07:07:45 +00:00
hir::TyKind::Path(hir::QPath::Resolved(
None,
P(hir::Path {
res,
2019-04-03 07:07:45 +00:00
segments: hir_vec![hir::PathSegment::from_ident(
keywords::SelfUpper.ident()
)],
span: t.span,
}),
))
},
TyKind::Array(ref ty, ref length) => {
2018-07-11 14:41:03 +00:00
hir::TyKind::Array(self.lower_ty(ty, itctx), self.lower_anon_const(length))
}
TyKind::Typeof(ref expr) => {
2018-07-11 14:41:03 +00:00
hir::TyKind::Typeof(self.lower_anon_const(expr))
}
2018-02-23 06:44:44 +00:00
TyKind::TraitObject(ref bounds, kind) => {
let mut lifetime_bound = None;
2018-03-21 08:24:27 +00:00
let bounds = bounds
.iter()
.filter_map(|bound| match *bound {
2018-06-14 11:23:46 +00:00
GenericBound::Trait(ref ty, TraitBoundModifier::None) => {
Some(self.lower_poly_trait_ref(ty, itctx.reborrow()))
}
2018-06-14 11:23:46 +00:00
GenericBound::Trait(_, TraitBoundModifier::Maybe) => None,
GenericBound::Outlives(ref lifetime) => {
if lifetime_bound.is_none() {
lifetime_bound = Some(self.lower_lifetime(lifetime));
}
None
}
2018-03-21 08:24:27 +00:00
})
.collect();
let lifetime_bound =
lifetime_bound.unwrap_or_else(|| self.elided_dyn_bound(t.span));
2018-02-23 06:44:44 +00:00
if kind != TraitObjectSyntax::Dyn {
self.maybe_lint_bare_trait(t.span, t.id, false);
2018-02-23 06:44:44 +00:00
}
2018-07-11 14:41:03 +00:00
hir::TyKind::TraitObject(bounds, lifetime_bound)
}
TyKind::ImplTrait(def_node_id, ref bounds) => {
2017-12-15 20:27:20 +00:00
let span = t.span;
match itctx {
2018-05-22 12:31:56 +00:00
ImplTraitContext::Existential(fn_def_id) => {
2018-06-06 22:50:59 +00:00
self.lower_existential_impl_trait(
span, fn_def_id, def_node_id,
|this| this.lower_param_bounds(bounds, itctx),
)
2018-03-21 08:24:27 +00:00
}
ImplTraitContext::Universal(in_band_ty_params) => {
// Add a definition for the in-band `Param`.
let def_index = self
.resolver
.definitions()
.opt_def_index(def_node_id)
.unwrap();
2017-12-15 20:27:20 +00:00
let hir_bounds = self.lower_param_bounds(
bounds,
ImplTraitContext::Universal(in_band_ty_params),
);
// Set the name to `impl Bound1 + Bound2`.
let ident = Ident::from_str(&pprust::ty_to_string(t)).with_span_pos(span);
in_band_ty_params.push(hir::GenericParam {
2019-04-26 12:23:30 +00:00
hir_id: self.lower_node_id(def_node_id),
2018-06-27 21:12:17 +00:00
name: ParamName::Plain(ident),
2017-12-15 20:27:20 +00:00
pure_wrt_drop: false,
2018-06-14 10:42:12 +00:00
attrs: hir_vec![],
2018-05-28 12:33:28 +00:00
bounds: hir_bounds,
2018-06-27 21:12:17 +00:00
span,
2018-05-25 23:27:54 +00:00
kind: hir::GenericParamKind::Type {
default: None,
synthetic: Some(hir::SyntheticTyParamKind::ImplTrait),
}
2017-12-15 20:27:20 +00:00
});
2018-07-11 14:41:03 +00:00
hir::TyKind::Path(hir::QPath::Resolved(
2018-03-21 08:24:27 +00:00
None,
P(hir::Path {
span,
res: Res::Def(DefKind::TyParam, DefId::local(def_index)),
2018-06-10 14:40:45 +00:00
segments: hir_vec![hir::PathSegment::from_ident(ident)],
2018-03-21 08:24:27 +00:00
}),
))
}
ImplTraitContext::Disallowed(pos) => {
let allowed_in = if self.sess.features_untracked()
.impl_trait_in_bindings {
"bindings or function and inherent method return types"
} else {
"function and inherent method return types"
};
let mut err = struct_span_err!(
2018-03-21 08:24:27 +00:00
self.sess,
t.span,
E0562,
"`impl Trait` not allowed outside of {}",
allowed_in,
2018-03-21 08:24:27 +00:00
);
if pos == ImplTraitPosition::Binding &&
nightly_options::is_nightly_build() {
help!(err,
"add #![feature(impl_trait_in_bindings)] to the crate attributes \
to enable");
}
err.emit();
2018-07-11 14:41:03 +00:00
hir::TyKind::Err
}
}
}
TyKind::Mac(_) => panic!("TyMac should have been expanded by now."),
TyKind::CVarArgs => {
// Create the implicit lifetime of the "spoofed" `VaList`.
let span = self.sess.source_map().next_point(t.span.shrink_to_lo());
let lt = self.new_implicit_lifetime(span);
hir::TyKind::CVarArgs(lt)
},
};
hir::Ty {
node: kind,
span: t.span,
2019-04-26 12:23:30 +00:00
hir_id: self.lower_node_id(t.id),
}
}
2015-07-31 07:04:06 +00:00
2018-06-06 22:50:59 +00:00
fn lower_existential_impl_trait(
&mut self,
span: Span,
2018-08-19 02:40:50 +00:00
fn_def_id: Option<DefId>,
exist_ty_node_id: NodeId,
lower_bounds: impl FnOnce(&mut LoweringContext<'_>) -> hir::GenericBounds,
2018-07-11 14:41:03 +00:00
) -> hir::TyKind {
2018-06-06 22:50:59 +00:00
// 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.mark_span_with_reason(
2018-06-06 22:50:59 +00:00
CompilerDesugaringKind::ExistentialReturnType,
span,
None,
2018-06-06 22:50:59 +00:00
);
let exist_ty_def_index = self
.resolver
.definitions()
.opt_def_index(exist_ty_node_id)
.unwrap();
2019-03-25 18:43:04 +00:00
self.allocate_hir_id_counter(exist_ty_node_id);
2018-06-06 22:50:59 +00:00
let hir_bounds = self.with_hir_id_owner(exist_ty_node_id, lower_bounds);
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 = hir::ExistTy {
2018-06-06 22:50:59 +00:00
generics: hir::Generics {
params: lifetime_defs,
where_clause: hir::WhereClause {
2019-04-26 12:23:30 +00:00
hir_id: lctx.next_id(),
predicates: hir_vec![],
2018-06-06 22:50:59 +00:00
},
span,
},
bounds: hir_bounds,
2018-08-19 02:40:50 +00:00
impl_trait_fn: fn_def_id,
origin: hir::ExistTyOrigin::ReturnImplTrait,
2018-06-06 22:50:59 +00:00
};
trace!("exist ty from impl trait def index: {:#?}", exist_ty_def_index);
let exist_ty_id = lctx.generate_existential_type(
exist_ty_node_id,
exist_ty_item,
span,
exist_ty_span,
);
2018-06-06 22:50:59 +00:00
// `impl Trait` now just becomes `Foo<'a, 'b, ..>`.
2019-04-26 12:23:30 +00:00
hir::TyKind::Def(hir::ItemId { id: exist_ty_id }, lifetimes)
2018-06-06 22:50:59 +00:00
})
}
/// Registers a new existential type with the proper NodeIds and
/// returns the lowered node ID for the existential type.
fn generate_existential_type(
&mut self,
exist_ty_node_id: NodeId,
exist_ty_item: hir::ExistTy,
span: Span,
exist_ty_span: Span,
2019-04-26 12:23:30 +00:00
) -> hir::HirId {
let exist_ty_item_kind = hir::ItemKind::Existential(exist_ty_item);
let exist_ty_id = self.lower_node_id(exist_ty_node_id);
// Generate an `existential type Foo: Trait;` declaration.
trace!("registering existential type with id {:#?}", exist_ty_id);
let exist_ty_item = hir::Item {
2019-04-26 12:23:30 +00:00
hir_id: exist_ty_id,
ident: keywords::Invalid.ident(),
attrs: Default::default(),
node: exist_ty_item_kind,
vis: respan(span.shrink_to_lo(), hir::VisibilityKind::Inherited),
span: exist_ty_span,
};
// Insert the item into the global item list. This usually happens
// automatically for all AST items. But this existential type item
// does not actually exist in the AST.
self.insert_item(exist_ty_item);
exist_ty_id
}
fn lifetimes_from_impl_trait_bounds(
&mut self,
2018-05-22 12:31:56 +00:00
exist_ty_id: NodeId,
parent_index: DefIndex,
bounds: &hir::GenericBounds,
2018-06-29 08:58:17 +00:00
) -> (HirVec<hir::GenericArg>, 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 12:31:56 +00:00
exist_ty_id: NodeId,
2017-12-10 05:54:58 +00:00
collect_elided_lifetimes: bool,
currently_bound_lifetimes: Vec<hir::LifetimeName>,
already_defined_lifetimes: FxHashSet<hir::LifetimeName>,
2018-06-29 08:58:17 +00:00
output_lifetimes: Vec<hir::GenericArg>,
output_lifetime_params: Vec<hir::GenericParam>,
}
impl<'r, 'a: 'r, 'v> hir::intravisit::Visitor<'v> for ImplTraitLifetimeCollector<'r, 'a> {
2018-03-21 08:24:27 +00: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-10 05:54:58 +00: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-10 05:54:58 +00:00
self.collect_elided_lifetimes = old_collect_elided_lifetimes;
} else {
hir::intravisit::walk_generic_args(self, span, parameters);
2017-12-10 05:54:58 +00:00
}
}
fn visit_ty(&mut self, t: &'v hir::Ty) {
// Don't collect elided lifetimes used inside of `fn()` syntax.
2018-07-11 14:41:03 +00:00
if let hir::TyKind::BareFn(_) = t.node {
2017-12-10 05:54:58 +00:00
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-10 05:54:58 +00:00
hir::intravisit::walk_ty(self, t);
self.currently_bound_lifetimes.truncate(old_len);
2017-12-10 05:54:58 +00:00
self.collect_elided_lifetimes = old_collect_elided_lifetimes;
} else {
2018-06-27 09:24:16 +00:00
hir::intravisit::walk_ty(self, t)
2017-12-10 05:54:58 +00:00
}
}
2018-03-21 08:24:27 +00:00
fn visit_poly_trait_ref(
&mut self,
trait_ref: &'v hir::PolyTraitRef,
modifier: hir::TraitBoundModifier,
2018-03-21 08:24:27 +00: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> ...`.
if let hir::GenericParamKind::Lifetime { .. } = 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>`.
let lt_name = hir::LifetimeName::Param(param.name);
2018-05-28 13:55:23 +00:00
self.currently_bound_lifetimes.push(lt_name);
}
hir::intravisit::walk_generic_param(self, param);
}
fn visit_lifetime(&mut self, lifetime: &'v hir::Lifetime) {
2017-12-10 05:54:58 +00:00
let name = match lifetime.name {
2018-03-21 08:24:27 +00:00
hir::LifetimeName::Implicit | hir::LifetimeName::Underscore => {
2017-12-10 05:54:58 +00:00
if self.collect_elided_lifetimes {
// Use `'_` for both implicit and underscore lifetimes in
// `abstract type Foo<'_>: SomeTrait<'_>;`.
2017-12-10 05:54:58 +00:00
hir::LifetimeName::Underscore
} else {
2018-03-21 08:24:27 +00:00
return;
2017-12-10 05:54:58 +00:00
}
2018-03-21 08:24:27 +00:00
}
hir::LifetimeName::Param(_) => lifetime.name,
hir::LifetimeName::Error | hir::LifetimeName::Static => return,
2017-12-10 05:54:58 +00:00
};
2018-03-21 08:24:27 +00:00
if !self.currently_bound_lifetimes.contains(&name)
&& !self.already_defined_lifetimes.contains(&name) {
2017-12-10 05:54:58 +00:00
self.already_defined_lifetimes.insert(name);
2018-06-29 08:58:17 +00:00
self.output_lifetimes.push(hir::GenericArg::Lifetime(hir::Lifetime {
2019-04-26 12:23:30 +00:00
hir_id: self.context.next_id(),
2017-12-10 05:54:58 +00:00
span: lifetime.span,
name,
2018-06-29 08:58:17 +00:00
}));
2017-12-10 05:54:58 +00:00
2018-05-22 12:31:56 +00:00
let def_node_id = self.context.sess.next_node_id();
2019-04-26 12:23:30 +00:00
let hir_id =
2019-02-02 14:40:08 +00:00
self.context.lower_node_id_with_owner(def_node_id, self.exist_ty_id);
2017-12-10 05:54:58 +00:00
self.context.resolver.definitions().create_def_with_parent(
self.parent,
def_node_id,
DefPathData::LifetimeNs(name.ident().as_interned_str()),
2017-12-10 05:54:58 +00:00
DefIndexAddressSpace::High,
Mark::root(),
2018-03-21 08:24:27 +00:00
lifetime.span,
2017-12-10 05:54:58 +00:00
);
2018-05-25 23:27:54 +00:00
let (name, kind) = match name {
hir::LifetimeName::Underscore => (
hir::ParamName::Plain(keywords::UnderscoreLifetime.ident()),
hir::LifetimeParamKind::Elided,
),
hir::LifetimeName::Param(param_name) => (
param_name,
hir::LifetimeParamKind::Explicit,
),
_ => bug!("expected LifetimeName::Param or ParamName::Plain"),
};
2018-05-25 23:27:54 +00:00
self.output_lifetime_params.push(hir::GenericParam {
2019-02-02 14:40:08 +00:00
hir_id,
name,
2017-12-10 05:54:58 +00:00
span: lifetime.span,
2018-05-25 23:27:54 +00:00
pure_wrt_drop: false,
2018-06-14 10:42:12 +00:00
attrs: hir_vec![],
bounds: hir_vec![],
kind: hir::GenericParamKind::Lifetime { kind }
2018-05-25 23:27:54 +00:00
});
}
}
}
let mut lifetime_collector = ImplTraitLifetimeCollector {
context: self,
parent: parent_index,
2018-05-22 12:31:56 +00:00
exist_ty_id,
2017-12-10 05:54:58 +00:00
collect_elided_lifetimes: true,
currently_bound_lifetimes: Vec::new(),
already_defined_lifetimes: FxHashSet::default(),
output_lifetimes: Vec::new(),
output_lifetime_params: Vec::new(),
};
for bound in bounds {
hir::intravisit::walk_param_bound(&mut lifetime_collector, &bound);
}
(
lifetime_collector.output_lifetimes.into(),
2018-03-21 08:24:27 +00: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 08:24:27 +00:00
items: fm.items
.iter()
.map(|x| self.lower_foreign_item(x))
.collect(),
}
2015-07-31 07:04:06 +00:00
}
2017-03-16 02:27:40 +00: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 {
2018-07-11 11:18:57 +00:00
node: hir::VariantKind {
ident: v.node.ident,
2019-04-26 12:23:30 +00:00
id: self.lower_node_id(v.node.id),
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 07:04:06 +00:00
}
2018-03-21 08:24:27 +00:00
fn lower_qpath(
&mut self,
id: NodeId,
qself: &Option<QSelf>,
p: &Path,
param_mode: ParamMode,
mut itctx: ImplTraitContext<'_>,
2018-03-21 08:24:27 +00:00
) -> 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.reborrow()));
let partial_res = self.resolver
.get_partial_res(id)
.unwrap_or_else(|| PartialRes::new(Res::Err));
let proj_start = p.segments.len() - partial_res.unresolved_segments();
let path = P(hir::Path {
res: self.lower_res(partial_res.base_res()),
2018-03-21 08:24:27 +00: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 08:24:27 +00: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 08:24:27 +00:00
index: this.def_key(def_id).parent.expect("missing parent"),
};
let type_def_id = match partial_res.base_res() {
Res::Def(DefKind::AssociatedTy, def_id) if i + 2 == proj_start => {
2018-03-21 08:24:27 +00:00
Some(parent_def_id(self, def_id))
}
Res::Def(DefKind::Variant, def_id) if i + 1 == proj_start => {
2018-03-21 08:24:27 +00:00
Some(parent_def_id(self, def_id))
}
Res::Def(DefKind::Struct, def_id)
| Res::Def(DefKind::Union, def_id)
| Res::Def(DefKind::Enum, def_id)
| Res::Def(DefKind::TyAlias, def_id)
| Res::Def(DefKind::Trait, def_id) if i + 1 == proj_start =>
2018-03-21 08:24:27 +00:00
{
Some(def_id)
}
_ => None,
};
let parenthesized_generic_args = match partial_res.base_res() {
2018-03-21 08:24:27 +00:00
// `a::b::Trait(Args)`
Res::Def(DefKind::Trait, _)
if i + 1 == proj_start => ParenthesizedGenericArgs::Ok,
2018-03-21 08:24:27 +00:00
// `a::b::Trait(Args)::TraitItem`
Res::Def(DefKind::Method, _)
| Res::Def(DefKind::AssociatedConst, _)
| Res::Def(DefKind::AssociatedTy, _)
2018-03-21 08:24:27 +00:00
if i + 2 == proj_start =>
{
ParenthesizedGenericArgs::Ok
}
// Avoid duplicated errors.
Res::Err => ParenthesizedGenericArgs::Ok,
2018-03-21 08:24:27 +00:00
// An error
Res::Def(DefKind::Struct, _)
| Res::Def(DefKind::Enum, _)
| Res::Def(DefKind::Union, _)
| Res::Def(DefKind::TyAlias, _)
| Res::Def(DefKind::Variant, _) if i + 1 == proj_start =>
2018-03-21 08:24:27 +00:00
{
ParenthesizedGenericArgs::Err
}
// A warning for now, for compatibility reasons
_ => ParenthesizedGenericArgs::Warn,
};
2018-03-21 08:24:27 +00: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 08:24:27 +00: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.reborrow(),
None,
2018-03-21 08:24:27 +00:00
)
})
.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 partial_res.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 15:29:59 +00:00
let new_id = self.next_id();
P(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 08:24:27 +00:00
let segment = P(self.lower_path_segment(
p.span,
segment,
param_mode,
0,
ParenthesizedGenericArgs::Warn,
itctx.reborrow(),
None,
2018-03-21 08:24:27 +00:00
));
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 15:29:59 +00:00
let new_id = self.next_id();
ty = P(self.ty_path(new_id, p.span, qpath));
}
// We should've returned in the for loop above.
2018-03-21 08:24:27 +00:00
span_bug!(
p.span,
"lower_qpath: no final extension segment in {}..{}",
proj_start,
p.segments.len()
)
2015-07-31 07:04:06 +00:00
}
2018-03-21 08:24:27 +00:00
fn lower_path_extra(
&mut self,
res: Res,
2018-03-21 08:24:27 +00:00
p: &Path,
param_mode: ParamMode,
explicit_owner: Option<NodeId>,
2018-03-21 08:24:27 +00:00
) -> hir::Path {
hir::Path {
res,
2018-03-21 08:24:27 +00:00
segments: p.segments
.iter()
.map(|segment| {
self.lower_path_segment(
p.span,
segment,
param_mode,
0,
ParenthesizedGenericArgs::Err,
ImplTraitContext::disallowed(),
explicit_owner,
2018-03-21 08:24:27 +00:00
)
})
.collect(),
span: p.span,
}
}
2018-03-21 08:24:27 +00:00
fn lower_path(&mut self, id: NodeId, p: &Path, param_mode: ParamMode) -> hir::Path {
let res = self.expect_full_res(id);
let res = self.lower_res(res);
self.lower_path_extra(res, p, param_mode, None)
}
2018-03-21 08:24:27 +00:00
fn lower_path_segment(
&mut self,
path_span: Span,
segment: &PathSegment,
param_mode: ParamMode,
expected_lifetimes: usize,
parenthesized_generic_args: ParenthesizedGenericArgs,
itctx: ImplTraitContext<'_>,
explicit_owner: Option<NodeId>,
2018-03-21 08:24:27 +00:00
) -> 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 type parameters may only be used with a `Fn` 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 08:24:27 +00:00
ParenthesizedGenericArgs::Ok => self.lower_parenthesized_parameter_data(data),
ParenthesizedGenericArgs::Warn => {
2018-03-21 08:24:27 +00:00
self.sess.buffer_lint(
PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES,
CRATE_NODE_ID,
data.span,
msg.into(),
);
(hir::GenericArgs::none(), true)
}
ParenthesizedGenericArgs::Err => {
2019-01-20 03:25:28 +00:00
let mut err = struct_span_err!(self.sess, data.span, E0214, "{}", msg);
err.span_label(data.span, "only `Fn` traits may use parentheses");
2019-01-20 03:25:28 +00:00
if let Ok(snippet) = self.sess.source_map().span_to_snippet(data.span) {
// Do not suggest going from `Trait()` to `Trait<>`
if data.inputs.len() > 0 {
err.span_suggestion(
data.span,
"use angle brackets instead",
format!("<{}>", &snippet[1..snippet.len() - 1]),
Applicability::MaybeIncorrect,
);
}
2019-01-20 03:25:28 +00:00
};
err.emit();
(self.lower_angle_bracketed_parameter_data(
&data.as_angle_bracketed_args(),
param_mode,
itctx).0,
false)
}
2018-03-21 08:24:27 +00:00
},
}
2016-12-10 06:45:58 +00:00
} else {
self.lower_angle_bracketed_parameter_data(&Default::default(), param_mode, itctx)
};
let has_lifetimes = generic_args.args.iter().any(|arg| match arg {
GenericArg::Lifetime(_) => true,
_ => false,
});
let first_generic_span = generic_args.args.iter().map(|a| a.span())
.chain(generic_args.bindings.iter().map(|b| b.span)).next();
if !generic_args.parenthesized && !has_lifetimes {
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();
if expected_lifetimes > 0 && param_mode == ParamMode::Explicit {
let anon_lt_suggestion = vec!["'_"; expected_lifetimes].join(", ");
let no_ty_args = generic_args.args.len() == expected_lifetimes;
let no_bindings = generic_args.bindings.is_empty();
let (incl_angl_brckt, insertion_span, suggestion) = if no_ty_args && no_bindings {
// If there are no (non-implicit) generic args or associated-type
// bindings, our suggestion includes the angle brackets.
(true, path_span.shrink_to_hi(), format!("<{}>", anon_lt_suggestion))
} else {
// Otherwise—sorry, this is kind of gross—we need to infer the
// place to splice in the `'_, ` from the generics that do exist.
let first_generic_span = first_generic_span
.expect("already checked that type args or bindings exist");
(false, first_generic_span.shrink_to_lo(), format!("{}, ", anon_lt_suggestion))
};
match self.anonymous_lifetime_mode {
// In create-parameter mode we error here because we don't want to support
// deprecated impl elision in new features like impl elision and `async fn`,
// both of which work using the `CreateParameter` mode:
//
// impl Foo for std::cell::Ref<u32> // note lack of '_
// async fn foo(_: std::cell::Ref<u32>) { ... }
AnonymousLifetimeMode::CreateParameter => {
let mut err = struct_span_err!(
self.sess,
path_span,
E0726,
"implicit elided lifetime not allowed here"
);
crate::lint::builtin::add_elided_lifetime_in_path_suggestion(
&self.sess,
&mut err,
expected_lifetimes,
path_span,
incl_angl_brckt,
insertion_span,
suggestion,
);
err.emit();
}
AnonymousLifetimeMode::PassThrough |
AnonymousLifetimeMode::ReportError |
AnonymousLifetimeMode::Replace(_) => {
self.sess.buffer_lint_with_diagnostic(
ELIDED_LIFETIMES_IN_PATHS,
CRATE_NODE_ID,
path_span,
"hidden lifetime parameters in types are deprecated",
builtin::BuiltinLintDiagnostics::ElidedLifetimesInPaths(
expected_lifetimes,
path_span,
incl_angl_brckt,
insertion_span,
suggestion,
)
);
}
}
}
}
let res = self.expect_full_res(segment.id);
let id = if let Some(owner) = explicit_owner {
self.lower_node_id_with_owner(segment.id, owner)
} else {
self.lower_node_id(segment.id)
};
2018-11-21 18:35:54 +00:00
debug!(
"lower_path_segment: ident={:?} original-id={:?} new-id={:?}",
segment.ident, segment.id, id,
);
hir::PathSegment::new(
2018-06-10 14:40:45 +00:00
segment.ident,
2019-04-26 12:23:30 +00:00
Some(id),
Some(self.lower_res(res)),
generic_args,
infer_types,
)
2015-07-31 07:04:06 +00:00
}
2018-03-21 08:24:27 +00:00
fn lower_angle_bracketed_parameter_data(
&mut self,
2018-02-23 17:48:54 +00:00
data: &AngleBracketedArgs,
2018-03-21 08:24:27 +00:00
param_mode: ParamMode,
mut itctx: ImplTraitContext<'_>,
) -> (hir::GenericArgs, bool) {
2018-02-23 17:48:54 +00:00
let &AngleBracketedArgs { ref args, ref bindings, .. } = data;
2018-05-26 22:54:48 +00:00
let has_types = args.iter().any(|arg| match arg {
2018-05-27 19:07:09 +00:00
ast::GenericArg::Type(_) => true,
2018-05-26 22:54:48 +00:00
_ => false,
});
(hir::GenericArgs {
args: args.iter().map(|a| self.lower_generic_arg(a, itctx.reborrow())).collect(),
bindings: bindings.iter().map(|b| self.lower_ty_binding(b, itctx.reborrow())).collect(),
parenthesized: false,
},
!has_types && param_mode == ParamMode::Optional)
2015-07-31 07:04:06 +00:00
}
2018-03-21 08:24:27 +00:00
fn lower_parenthesized_parameter_data(
&mut self,
data: &ParenthesizedArgs,
) -> (hir::GenericArgs, 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| {
let &ParenthesizedArgs { ref inputs, ref output, span } = data;
let inputs = inputs
.iter()
.map(|ty| this.lower_ty_direct(ty, ImplTraitContext::disallowed()))
.collect();
let mk_tup = |this: &mut Self, tys, span| {
2019-04-26 12:23:30 +00:00
hir::Ty { node: hir::TyKind::Tup(tys), hir_id: this.next_id(), span }
};
(
hir::GenericArgs {
args: hir_vec![GenericArg::Type(mk_tup(this, inputs, span))],
bindings: hir_vec![
hir::TypeBinding {
2019-04-26 12:23:30 +00:00
hir_id: this.next_id(),
ident: Ident::from_str(FN_OUTPUT_NAME),
ty: output
.as_ref()
.map(|ty| this.lower_ty(&ty, ImplTraitContext::disallowed()))
.unwrap_or_else(|| P(mk_tup(this, hir::HirVec::new(), span))),
span: output.as_ref().map_or(span, |ty| ty.span),
}
],
parenthesized: true,
},
false,
)
}
2018-03-21 08:24:27 +00:00
)
2015-10-06 03:03:56 +00:00
}
2015-07-31 07:04:06 +00:00
fn lower_local(&mut self, l: &Local) -> (hir::Local, SmallVec<[NodeId; 1]>) {
let mut ids = SmallVec::<[NodeId; 1]>::new();
2018-08-19 02:40:50 +00:00
if self.sess.features_untracked().impl_trait_in_bindings {
if let Some(ref ty) = l.ty {
let mut visitor = ImplTraitTypeIdVisitor { ids: &mut ids };
visitor.visit_ty(ty);
}
}
2018-09-24 03:25:23 +00:00
let parent_def_id = DefId::local(self.current_hir_id_owner.last().unwrap().0);
(hir::Local {
2019-04-26 12:23:30 +00:00
hir_id: self.lower_node_id(l.id),
2018-03-21 08:24:27 +00:00
ty: l.ty
.as_ref()
2018-08-19 02:40:50 +00:00
.map(|t| self.lower_ty(t,
if self.sess.features_untracked().impl_trait_in_bindings {
2018-09-24 03:25:23 +00:00
ImplTraitContext::Existential(Some(parent_def_id))
2018-08-19 02:40:50 +00:00
} else {
ImplTraitContext::Disallowed(ImplTraitPosition::Binding)
2018-08-19 02:40:50 +00:00
}
)),
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: self.lower_local_source(l.source),
}, ids)
2015-10-06 03:03:56 +00:00
}
2015-07-31 07:04:06 +00:00
fn lower_local_source(&mut self, ls: LocalSource) -> hir::LocalSource {
match ls {
LocalSource::Normal => hir::LocalSource::Normal,
LocalSource::AsyncFn => hir::LocalSource::AsyncFn,
}
}
fn lower_mutability(&mut self, m: Mutability) -> hir::Mutability {
match m {
Mutability::Mutable => hir::MutMutable,
Mutability::Immutable => hir::MutImmutable,
}
2015-07-31 07:04:06 +00:00
}
fn lower_args(&mut self, decl: Option<&FnDecl>) -> HirVec<hir::Arg> {
decl.map_or(hir_vec![], |decl| decl.inputs.iter().map(|x| self.lower_arg(x)).collect())
}
fn lower_arg(&mut self, arg: &Arg) -> hir::Arg {
hir::Arg {
2019-04-26 12:23:30 +00:00
hir_id: self.lower_node_id(arg.id),
pat: self.lower_pat(&arg.pat),
source: self.lower_arg_source(&arg.source),
}
}
fn lower_arg_source(&mut self, source: &ArgSource) -> hir::ArgSource {
match source {
ArgSource::Normal => hir::ArgSource::Normal,
ArgSource::AsyncFn(pat) => hir::ArgSource::AsyncFn(self.lower_pat(pat)),
}
2015-09-27 19:23:31 +00:00
}
2015-07-31 07:04:06 +00:00
fn lower_fn_args_to_names(&mut self, decl: &FnDecl) -> hir::HirVec<Ident> {
2018-03-21 08:24:27 +00:00
decl.inputs
.iter()
.map(|arg| match arg.pat.node {
PatKind::Ident(_, ident, _) => ident,
_ => Ident::new(keywords::Invalid.name(), arg.pat.span),
2018-03-21 08:24:27 +00:00
})
.collect()
}
2018-06-06 22:50:59 +00:00
// Lowers a function declaration.
//
// decl: the unlowered (ast) function declaration.
// fn_def_id: if `Some`, impl Trait arguments are lowered into generic parameters on the
// given DefId, otherwise impl Trait is disallowed. Must be `Some` if
// make_ret_async is also `Some`.
2018-06-06 22:50:59 +00:00
// impl_trait_return_allow: determines whether impl Trait can be used in return position.
// This guards against trait declarations and implementations where impl Trait is
// disallowed.
// make_ret_async: if `Some`, converts `-> T` into `-> impl Future<Output = T>` in the
// return type. This is used for `async fn` declarations. The `NodeId` is the id of the
// return type impl Trait item.
2018-03-21 08:24:27 +00:00
fn lower_fn_decl(
&mut self,
decl: &FnDecl,
mut in_band_ty_params: Option<(DefId, &mut Vec<hir::GenericParam>)>,
2018-03-21 08:24:27 +00:00
impl_trait_return_allow: bool,
make_ret_async: Option<NodeId>,
2018-03-21 08:24:27 +00:00
) -> P<hir::FnDecl> {
let lt_mode = if make_ret_async.is_some() {
// In `async fn`, argument-position elided lifetimes
// must be transformed into fresh generic parameters so that
// they can be applied to the existential return type.
AnonymousLifetimeMode::CreateParameter
} else {
self.anonymous_lifetime_mode
};
// Remember how many lifetimes were already around so that we can
// only look at the lifetime parameters introduced by the arguments.
let lifetime_count_before_args = self.lifetimes_to_define.len();
let inputs = self.with_anonymous_lifetime_mode(lt_mode, |this| {
decl.inputs
.iter()
.map(|arg| {
if let Some((_, ibty)) = &mut in_band_ty_params {
this.lower_ty_direct(&arg.ty, ImplTraitContext::Universal(ibty))
} else {
this.lower_ty_direct(&arg.ty, ImplTraitContext::disallowed())
}
})
.collect::<HirVec<_>>()
});
2018-06-06 22:50:59 +00:00
let output = if let Some(ret_id) = make_ret_async {
// Calculate the `LtReplacement` to use for any return-position elided
// lifetimes based on the elided lifetime parameters introduced in the args.
let lt_replacement = get_elided_lt_replacement(
&self.lifetimes_to_define[lifetime_count_before_args..]
);
2018-06-06 22:50:59 +00:00
self.lower_async_fn_ret_ty(
&decl.output,
in_band_ty_params.expect("make_ret_async but no fn_def_id").0,
ret_id,
lt_replacement,
)
2018-06-06 22:50:59 +00:00
} else {
match decl.output {
FunctionRetTy::Ty(ref ty) => match in_band_ty_params {
Some((def_id, _)) if impl_trait_return_allow => {
hir::Return(self.lower_ty(ty,
ImplTraitContext::Existential(Some(def_id))))
}
_ => {
hir::Return(self.lower_ty(ty, ImplTraitContext::disallowed()))
2018-03-21 08:24:27 +00:00
}
},
FunctionRetTy::Default(span) => hir::DefaultReturn(span),
2018-06-06 22:50:59 +00:00
}
};
P(hir::FnDecl {
inputs,
output,
c_variadic: decl.c_variadic,
implicit_self: decl.inputs.get(0).map_or(
hir::ImplicitSelfKind::None,
|arg| {
let is_mutable_pat = match arg.pat.node {
PatKind::Ident(BindingMode::ByValue(mt), _, _) |
PatKind::Ident(BindingMode::ByRef(mt), _, _) =>
mt == Mutability::Mutable,
_ => false,
};
match arg.ty.node {
TyKind::ImplicitSelf if is_mutable_pat => hir::ImplicitSelfKind::Mut,
TyKind::ImplicitSelf => hir::ImplicitSelfKind::Imm,
// Given we are only considering `ImplicitSelf` types, we needn't consider
// the case where we have a mutable pattern to a reference as that would
// no longer be an `ImplicitSelf`.
TyKind::Rptr(_, ref mt) if mt.ty.node.is_implicit_self() &&
mt.mutbl == ast::Mutability::Mutable =>
hir::ImplicitSelfKind::MutRef,
TyKind::Rptr(_, ref mt) if mt.ty.node.is_implicit_self() =>
hir::ImplicitSelfKind::ImmRef,
_ => hir::ImplicitSelfKind::None,
}
},
),
})
}
2015-07-31 07:04:06 +00:00
// Transform `-> T` for `async fn` into -> ExistTy { .. }
// combined with the following definition of `ExistTy`:
//
// existential type ExistTy<generics_from_parent_fn>: Future<Output = T>;
2018-06-06 22:50:59 +00:00
//
// inputs: lowered types of arguments to the function. Used to collect lifetimes.
// output: unlowered output type (`T` in `-> T`)
// fn_def_id: DefId of the parent function. Used to create child impl trait definition.
// exist_ty_node_id: NodeId of the existential type that should be created.
// elided_lt_replacement: replacement for elided lifetimes in the return type
2018-06-06 22:50:59 +00:00
fn lower_async_fn_ret_ty(
&mut self,
output: &FunctionRetTy,
fn_def_id: DefId,
exist_ty_node_id: NodeId,
elided_lt_replacement: LtReplacement,
2018-06-06 22:50:59 +00:00
) -> hir::FunctionRetTy {
let span = output.span();
2018-06-06 22:50:59 +00:00
let exist_ty_span = self.mark_span_with_reason(
CompilerDesugaringKind::Async,
span,
None,
);
2018-06-06 22:50:59 +00:00
let exist_ty_def_index = self
.resolver
.definitions()
.opt_def_index(exist_ty_node_id)
.unwrap();
2018-06-06 22:50:59 +00:00
self.allocate_hir_id_counter(exist_ty_node_id);
2018-06-06 22:50:59 +00:00
2019-04-26 12:23:30 +00:00
let (exist_ty_id, lifetime_params) = self.with_hir_id_owner(exist_ty_node_id, |this| {
let future_bound = this.with_anonymous_lifetime_mode(
AnonymousLifetimeMode::Replace(elided_lt_replacement),
|this| this.lower_async_fn_output_type_to_future_bound(
output,
fn_def_id,
span,
),
);
2018-06-06 22:50:59 +00:00
// Calculate all the lifetimes that should be captured
// by the existential type. This should include all in-scope
// lifetime parameters, including those defined in-band.
//
// Note: this must be done after lowering the output type,
// as the output type may introduce new in-band lifetimes.
let lifetime_params: Vec<(Span, ParamName)> =
this.in_scope_lifetimes
.iter().cloned()
.map(|ident| (ident.span, ParamName::Plain(ident)))
.chain(this.lifetimes_to_define.iter().cloned())
.collect();
2018-06-06 22:50:59 +00:00
let generic_params =
lifetime_params
.iter().cloned()
.map(|(span, hir_name)| {
this.lifetime_to_generic_param(span, hir_name, exist_ty_def_index)
})
.collect();
2018-06-06 22:50:59 +00:00
let exist_ty_item = hir::ExistTy {
generics: hir::Generics {
params: generic_params,
where_clause: hir::WhereClause {
2019-04-26 12:23:30 +00:00
hir_id: this.next_id(),
predicates: hir_vec![],
},
span,
},
bounds: hir_vec![future_bound],
impl_trait_fn: Some(fn_def_id),
origin: hir::ExistTyOrigin::AsyncFn,
2018-06-06 22:50:59 +00:00
};
trace!("exist ty from async fn def index: {:#?}", exist_ty_def_index);
let exist_ty_id = this.generate_existential_type(
exist_ty_node_id,
exist_ty_item,
span,
exist_ty_span,
);
2018-06-06 22:50:59 +00:00
2019-04-26 12:23:30 +00:00
(exist_ty_id, lifetime_params)
});
2018-06-06 22:50:59 +00:00
let generic_args =
lifetime_params
.iter().cloned()
.map(|(span, hir_name)| {
GenericArg::Lifetime(hir::Lifetime {
2019-04-26 12:23:30 +00:00
hir_id: self.next_id(),
span,
name: hir::LifetimeName::Param(hir_name),
2018-06-06 22:50:59 +00:00
})
})
.collect();
2018-06-22 05:24:24 +00:00
2019-04-26 12:23:30 +00:00
let exist_ty_ref = hir::TyKind::Def(hir::ItemId { id: exist_ty_id }, generic_args);
2018-06-06 22:50:59 +00:00
hir::FunctionRetTy::Return(P(hir::Ty {
node: exist_ty_ref,
span,
2019-04-26 12:23:30 +00:00
hir_id: self.next_id(),
}))
}
2018-06-06 22:50:59 +00:00
/// Turns `-> T` into `Future<Output = T>`
fn lower_async_fn_output_type_to_future_bound(
&mut self,
output: &FunctionRetTy,
fn_def_id: DefId,
span: Span,
) -> hir::GenericBound {
// Compute the `T` in `Future<Output = T>` from the return type.
let output_ty = match output {
FunctionRetTy::Ty(ty) => {
self.lower_ty(ty, ImplTraitContext::Existential(Some(fn_def_id)))
2018-06-06 22:50:59 +00:00
}
FunctionRetTy::Default(ret_ty_span) => {
P(hir::Ty {
2019-04-26 12:23:30 +00:00
hir_id: self.next_id(),
node: hir::TyKind::Tup(hir_vec![]),
span: *ret_ty_span,
})
}
};
2018-06-06 22:50:59 +00:00
// "<Output = T>"
let future_params = P(hir::GenericArgs {
args: hir_vec![],
bindings: hir_vec![hir::TypeBinding {
ident: Ident::from_str(FN_OUTPUT_NAME),
ty: output_ty,
2019-04-26 12:23:30 +00:00
hir_id: self.next_id(),
span,
}],
parenthesized: false,
2018-06-06 22:50:59 +00:00
});
// ::std::future::Future<future_params>
let future_path =
self.std_path(span, &["future", "Future"], Some(future_params), false);
hir::GenericBound::Trait(
hir::PolyTraitRef {
trait_ref: hir::TraitRef {
path: future_path,
2019-04-26 12:23:30 +00:00
hir_ref_id: self.next_id(),
},
bound_generic_params: hir_vec![],
span,
},
hir::TraitBoundModifier::None,
)
2018-06-06 22:50:59 +00:00
}
2018-05-28 12:33:28 +00:00
fn lower_param_bound(
2018-03-21 08:24:27 +00:00
&mut self,
tpb: &GenericBound,
itctx: ImplTraitContext<'_>,
) -> hir::GenericBound {
match *tpb {
GenericBound::Trait(ref ty, modifier) => {
hir::GenericBound::Trait(
self.lower_poly_trait_ref(ty, itctx),
self.lower_trait_bound_modifier(modifier),
)
}
GenericBound::Outlives(ref lifetime) => {
hir::GenericBound::Outlives(self.lower_lifetime(lifetime))
}
}
}
2015-07-31 07:04:06 +00:00
fn lower_lifetime(&mut self, l: &Lifetime) -> hir::Lifetime {
2018-03-19 00:54:56 +00:00
let span = l.ident.span;
2018-06-27 21:12:17 +00:00
match l.ident {
2018-06-09 20:25:33 +00:00
ident if ident.name == keywords::StaticLifetime.name() =>
self.new_named_lifetime(l.id, span, hir::LifetimeName::Static),
ident if ident.name == keywords::UnderscoreLifetime.name() =>
match self.anonymous_lifetime_mode {
AnonymousLifetimeMode::CreateParameter => {
let fresh_name = self.collect_fresh_in_band_lifetime(span);
self.new_named_lifetime(l.id, span, hir::LifetimeName::Param(fresh_name))
}
2018-06-09 20:25:33 +00:00
AnonymousLifetimeMode::PassThrough => {
self.new_named_lifetime(l.id, span, hir::LifetimeName::Underscore)
}
AnonymousLifetimeMode::ReportError => self.new_error_lifetime(Some(l.id), span),
AnonymousLifetimeMode::Replace(replacement) => {
2019-04-26 12:23:30 +00:00
let hir_id = self.lower_node_id(l.id);
self.replace_elided_lifetime(hir_id, span, replacement)
}
2018-06-09 20:25:33 +00:00
},
ident => {
self.maybe_collect_in_band_lifetime(ident);
let param_name = ParamName::Plain(ident);
self.new_named_lifetime(l.id, span, hir::LifetimeName::Param(param_name))
2017-11-17 06:59:45 +00:00
}
}
}
2017-11-17 06:59:45 +00:00
fn new_named_lifetime(
&mut self,
id: NodeId,
span: Span,
name: hir::LifetimeName,
) -> hir::Lifetime {
hir::Lifetime {
2019-04-26 12:23:30 +00:00
hir_id: self.lower_node_id(id),
span,
name: name,
2015-07-31 07:04:06 +00:00
}
}
/// Replace a return-position elided lifetime with the elided lifetime
/// from the arguments.
fn replace_elided_lifetime(
&mut self,
hir_id: hir::HirId,
span: Span,
replacement: LtReplacement,
) -> hir::Lifetime {
let multiple_or_none = match replacement {
LtReplacement::Some(name) => {
return hir::Lifetime {
hir_id,
span,
name: hir::LifetimeName::Param(name),
};
}
LtReplacement::MultipleLifetimes => "multiple",
LtReplacement::NoLifetimes => "none",
};
let mut err = crate::middle::resolve_lifetime::report_missing_lifetime_specifiers(
self.sess,
span,
1,
);
err.note(&format!(
"return-position elided lifetimes require exactly one \
input-position elided lifetime, found {}.", multiple_or_none));
err.emit();
hir::Lifetime { hir_id, span, name: hir::LifetimeName::Error }
}
fn lower_generic_params(
&mut self,
params: &[GenericParam],
add_bounds: &NodeMap<Vec<GenericBound>>,
mut itctx: ImplTraitContext<'_>,
) -> hir::HirVec<hir::GenericParam> {
params.iter().map(|param| {
self.lower_generic_param(param, add_bounds, itctx.reborrow())
}).collect()
}
2018-05-25 23:27:54 +00:00
fn lower_generic_param(&mut self,
2018-05-27 19:07:09 +00:00
param: &GenericParam,
add_bounds: &NodeMap<Vec<GenericBound>>,
mut itctx: ImplTraitContext<'_>)
2018-05-25 23:27:54 +00:00
-> hir::GenericParam {
let mut bounds = self.with_anonymous_lifetime_mode(
AnonymousLifetimeMode::ReportError,
|this| this.lower_param_bounds(&param.bounds, itctx.reborrow()),
);
let (name, kind) = match param.kind {
GenericParamKind::Lifetime => {
2018-05-25 23:27:54 +00:00
let was_collecting_in_band = self.is_collecting_in_band_lifetimes;
self.is_collecting_in_band_lifetimes = false;
let lt = self.with_anonymous_lifetime_mode(
AnonymousLifetimeMode::ReportError,
|this| this.lower_lifetime(&Lifetime { id: param.id, ident: param.ident }),
);
let param_name = match lt.name {
hir::LifetimeName::Param(param_name) => param_name,
hir::LifetimeName::Implicit
| hir::LifetimeName::Underscore
| hir::LifetimeName::Static => hir::ParamName::Plain(lt.name.ident()),
hir::LifetimeName::Error => ParamName::Error,
};
let kind = hir::GenericParamKind::Lifetime {
kind: hir::LifetimeParamKind::Explicit
2018-05-25 23:27:54 +00:00
};
2017-11-17 06:59:45 +00:00
2018-05-25 23:27:54 +00:00
self.is_collecting_in_band_lifetimes = was_collecting_in_band;
2017-11-17 06:59:45 +00:00
(param_name, kind)
2018-05-25 23:27:54 +00:00
}
2018-05-28 12:33:28 +00:00
GenericParamKind::Type { ref default, .. } => {
2018-05-25 23:27:54 +00: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.
let ident = if param.ident.name == keywords::SelfUpper.name() {
2018-06-27 21:12:17 +00:00
param.ident.gensym()
} else {
param.ident
};
2018-05-25 23:27:54 +00:00
2018-05-26 18:16:21 +00:00
let add_bounds = add_bounds.get(&param.id).map_or(&[][..], |x| &x);
2018-05-25 23:27:54 +00:00
if !add_bounds.is_empty() {
let params = self.lower_param_bounds(add_bounds, itctx.reborrow()).into_iter();
bounds = bounds.into_iter()
.chain(params)
.collect();
2018-05-25 23:27:54 +00:00
}
2017-11-17 06:59:45 +00:00
let kind = hir::GenericParamKind::Type {
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)
.next(),
};
(hir::ParamName::Plain(ident), kind)
2018-05-25 23:27:54 +00:00
}
GenericParamKind::Const { ref ty } => {
(hir::ParamName::Plain(param.ident), hir::GenericParamKind::Const {
ty: self.lower_ty(&ty, ImplTraitContext::disallowed()),
})
}
};
hir::GenericParam {
2019-04-26 12:23:30 +00:00
hir_id: self.lower_node_id(param.id),
name,
span: param.ident.span,
pure_wrt_drop: attr::contains_name(&param.attrs, "may_dangle"),
attrs: self.lower_attrs(&param.attrs),
bounds,
kind,
2018-05-25 23:27:54 +00:00
}
}
2015-07-31 07:04:06 +00:00
2018-05-26 18:16:21 +00:00
fn lower_generics(
&mut self,
generics: &Generics,
itctx: ImplTraitContext<'_>)
2018-05-26 18:16:21 +00:00
-> hir::Generics
{
2016-10-22 00:33:36 +00: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.
let mut add_bounds: NodeMap<Vec<_>> = Default::default();
2018-05-26 18:16:21 +00:00
for pred in &generics.where_clause.predicates {
2016-10-22 00:33:36 +00:00
if let WherePredicate::BoundPredicate(ref bound_pred) = *pred {
'next_bound: for bound in &bound_pred.bounds {
if let GenericBound::Trait(_, TraitBoundModifier::Maybe) = *bound {
2016-10-22 00:33:36 +00:00
let report_error = |this: &mut Self| {
2018-03-21 08:24:27 +00: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 00:33:36 +00: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 08:24:27 +00:00
if path.segments.len() == 1
&& bound_pred.bound_generic_params.is_empty() =>
{
if let Some(Res::Def(DefKind::TyParam, def_id)) = self.resolver
.get_partial_res(bound_pred.bounded_ty.id)
.map(|d| d.base_res())
2018-03-21 08:24:27 +00:00
{
2016-10-22 00:33:36 +00:00
if let Some(node_id) =
2018-03-21 08:24:27 +00:00
self.resolver.definitions().as_local_node_id(def_id)
{
2018-05-26 18:16:21 +00:00
for param in &generics.params {
match param.kind {
2018-05-27 19:07:09 +00:00
GenericParamKind::Type { .. } => {
2018-05-26 18:16:21 +00:00
if node_id == param.id {
add_bounds.entry(param.id)
.or_default()
2018-05-26 18:16:21 +00:00
.push(bound.clone());
continue 'next_bound;
}
}
2018-05-26 18:16:21 +00:00
_ => {}
2016-10-22 00:33:36 +00:00
}
}
}
}
report_error(self)
}
2018-03-21 08:24:27 +00:00
_ => report_error(self),
2016-10-22 00:33:36 +00:00
}
}
}
}
}
hir::Generics {
2018-05-26 18:16:21 +00: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 07:04:06 +00:00
fn lower_where_clause(&mut self, wc: &WhereClause) -> hir::WhereClause {
self.with_anonymous_lifetime_mode(
AnonymousLifetimeMode::ReportError,
|this| {
hir::WhereClause {
2019-04-26 12:23:30 +00:00
hir_id: this.lower_node_id(wc.id),
predicates: wc.predicates
.iter()
.map(|predicate| this.lower_where_predicate(predicate))
.collect(),
}
},
)
2015-10-06 03:03:56 +00:00
}
2015-07-31 07:04:06 +00:00
fn lower_where_predicate(&mut self, pred: &WherePredicate) -> hir::WherePredicate {
match *pred {
2018-03-21 08:24:27 +00:00
WherePredicate::BoundPredicate(WhereBoundPredicate {
ref bound_generic_params,
ref bounded_ty,
ref bounds,
span,
}) => {
self.with_in_scope_lifetime_defs(
&bound_generic_params,
|this| {
hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate {
2018-03-21 08:24:27 +00:00
bound_generic_params: this.lower_generic_params(
bound_generic_params,
&NodeMap::default(),
ImplTraitContext::disallowed(),
2018-03-21 08:24:27 +00:00
),
bounded_ty: this.lower_ty(bounded_ty, ImplTraitContext::disallowed()),
2018-03-21 08:24:27 +00:00
bounds: bounds
.iter()
.filter_map(|bound| match *bound {
// Ignore `?Trait` bounds.
// They were copied into type parameters already.
GenericBound::Trait(_, TraitBoundModifier::Maybe) => None,
2018-05-28 12:33:28 +00:00
_ => Some(this.lower_param_bound(
2018-03-21 08:24:27 +00:00
bound,
ImplTraitContext::disallowed(),
2018-03-21 08:24:27 +00:00
)),
})
.collect(),
span,
})
2018-03-21 08:24:27 +00:00
},
)
}
2018-03-21 08:24:27 +00:00
WherePredicate::RegionPredicate(WhereRegionPredicate {
ref lifetime,
ref bounds,
span,
}) => hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate {
span,
lifetime: self.lower_lifetime(lifetime),
bounds: self.lower_param_bounds(bounds, ImplTraitContext::disallowed()),
2018-03-21 08:24:27 +00:00
}),
WherePredicate::EqPredicate(WhereEqPredicate {
id,
ref lhs_ty,
ref rhs_ty,
span,
2019-02-02 14:40:08 +00:00
}) => {
hir::WherePredicate::EqPredicate(hir::WhereEqPredicate {
2019-04-26 12:23:30 +00:00
hir_id: self.lower_node_id(id),
2019-02-02 14:40:08 +00:00
lhs_ty: self.lower_ty(lhs_ty, ImplTraitContext::disallowed()),
rhs_ty: self.lower_ty(rhs_ty, ImplTraitContext::disallowed()),
span,
})
},
2015-07-31 07:04:06 +00:00
}
}
fn lower_variant_data(&mut self, vdata: &VariantData) -> hir::VariantData {
match *vdata {
VariantData::Struct(ref fields, recovered) => hir::VariantData::Struct(
fields.iter().enumerate().map(|f| self.lower_struct_field(f)).collect(),
recovered,
),
2019-02-02 14:40:08 +00:00
VariantData::Tuple(ref fields, id) => {
hir::VariantData::Tuple(
fields
.iter()
.enumerate()
.map(|f| self.lower_struct_field(f))
.collect(),
2019-04-26 12:23:30 +00:00
self.lower_node_id(id),
2019-02-02 14:40:08 +00:00
)
},
VariantData::Unit(id) => {
2019-04-26 12:23:30 +00:00
hir::VariantData::Unit(self.lower_node_id(id))
2019-02-02 14:40:08 +00:00
},
2015-07-31 07:04:06 +00: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 08:24:27 +00:00
qpath => bug!("lower_trait_ref: unexpected QPath `{:?}`", qpath),
};
hir::TraitRef {
path,
2019-04-26 12:23:30 +00:00
hir_ref_id: self.lower_node_id(p.ref_id),
2015-07-31 07:04:06 +00:00
}
}
2018-03-21 08:24:27 +00:00
fn lower_poly_trait_ref(
&mut self,
p: &PolyTraitRef,
mut itctx: ImplTraitContext<'_>,
2018-03-21 08:24:27 +00:00
) -> hir::PolyTraitRef {
let bound_generic_params = self.lower_generic_params(
&p.bound_generic_params,
&NodeMap::default(),
itctx.reborrow(),
);
let trait_ref = self.with_parent_impl_lifetime_defs(
&bound_generic_params,
|this| this.lower_trait_ref(&p.trait_ref, itctx),
);
2017-11-17 06:59:45 +00:00
hir::PolyTraitRef {
bound_generic_params,
2017-11-17 06:59:45 +00:00
trait_ref,
span: p.span,
2015-07-31 07:04:06 +00:00
}
}
fn lower_struct_field(&mut self, (index, f): (usize, &StructField)) -> hir::StructField {
hir::StructField {
span: f.span,
2019-04-26 12:23:30 +00:00
hir_id: self.lower_node_id(f.id),
2018-05-25 23:50:15 +00: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-25 23:50:15 +00: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 07:04:06 +00:00
}
}
fn lower_field(&mut self, f: &Field) -> hir::Field {
hir::Field {
2019-04-26 12:23:30 +00:00
hir_id: self.next_id(),
2018-05-25 23:50:15 +00:00
ident: f.ident,
expr: P(self.lower_expr(&f.expr)),
span: f.span,
is_shorthand: f.is_shorthand,
2016-04-17 22:30:55 +00:00
}
}
2015-07-31 07:04:06 +00: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-17 22:30:55 +00:00
}
}
2015-07-31 07:04:06 +00:00
fn lower_param_bounds(&mut self, bounds: &[GenericBound], mut itctx: ImplTraitContext<'_>)
-> hir::GenericBounds {
bounds.iter().map(|bound| self.lower_param_bound(bound, itctx.reborrow())).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
}
}
P(hir::Block {
2019-04-26 12:23:30 +00:00
hir_id: self.lower_node_id(b.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,
})
}
2018-06-27 15:32:48 +00:00
fn lower_async_body(
&mut self,
decl: &FnDecl,
asyncness: &IsAsync,
2018-06-27 15:32:48 +00:00
body: &Block,
) -> hir::BodyId {
self.lower_body(Some(&decl), |this| {
if let IsAsync::Async { closure_id, ref arguments, .. } = asyncness {
let mut body = body.clone();
// Async function arguments are lowered into the closure body so that they are
// captured and so that the drop order matches the equivalent non-async functions.
//
// async fn foo(<pattern>: <ty>, <pattern>: <ty>, <pattern>: <ty>) {
// async move {
// }
// }
//
// // ...becomes...
// fn foo(__arg0: <ty>, __arg1: <ty>, __arg2: <ty>) {
// async move {
// let __arg2 = __arg2;
// let <pattern> = __arg2;
// let __arg1 = __arg1;
// let <pattern> = __arg1;
// let __arg0 = __arg0;
// let <pattern> = __arg0;
// }
// }
//
// If `<pattern>` is a simple ident, then it is lowered to a single
// `let <pattern> = <pattern>;` statement as an optimization.
for a in arguments.iter().rev() {
if let Some(pat_stmt) = a.pat_stmt.clone() {
body.stmts.insert(0, pat_stmt);
}
body.stmts.insert(0, a.move_stmt.clone());
}
2018-06-27 15:32:48 +00:00
let async_expr = this.make_async_expr(
CaptureBy::Value, *closure_id, None, body.span,
2018-06-27 15:32:48 +00:00
|this| {
let body = this.lower_block(&body, false);
2018-06-27 15:32:48 +00:00
this.expr_block(body, ThinVec::new())
});
this.expr(body.span, async_expr, ThinVec::new())
} else {
let body = this.lower_block(body, false);
this.expr_block(body, ThinVec::new())
}
})
}
2018-03-21 08:24:27 +00:00
fn lower_item_kind(
&mut self,
id: NodeId,
ident: &mut Ident,
2018-03-21 08:24:27 +00:00
attrs: &hir::HirVec<Attribute>,
2018-11-22 11:41:26 +00:00
vis: &mut hir::Visibility,
2018-03-21 08:24:27 +00:00
i: &ItemKind,
2018-07-11 15:36:06 +00:00
) -> hir::ItemKind {
match *i {
2018-07-11 15:36:06 +00:00
ItemKind::ExternCrate(orig_name) => hir::ItemKind::ExternCrate(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, ident, attrs)
}
ItemKind::Static(ref t, m, ref e) => {
let value = self.lower_body(None, |this| this.lower_expr(e));
2018-07-11 15:36:06 +00:00
hir::ItemKind::Static(
self.lower_ty(
t,
if self.sess.features_untracked().impl_trait_in_bindings {
ImplTraitContext::Existential(None)
} else {
ImplTraitContext::Disallowed(ImplTraitPosition::Binding)
}
),
2018-03-21 08:24:27 +00:00
self.lower_mutability(m),
value,
)
}
ItemKind::Const(ref t, ref e) => {
let value = self.lower_body(None, |this| this.lower_expr(e));
hir::ItemKind::Const(
self.lower_ty(
t,
if self.sess.features_untracked().impl_trait_in_bindings {
ImplTraitContext::Existential(None)
} else {
ImplTraitContext::Disallowed(ImplTraitPosition::Binding)
}
),
value
)
}
ItemKind::Fn(ref decl, ref header, ref generics, ref body) => {
let fn_def_id = self.resolver.definitions().local_def_id(id);
2018-09-24 03:25:23 +00:00
self.with_new_scopes(|this| {
let mut lower_fn = |decl: &FnDecl| {
// Note: we don't need to change the return type from `T` to
// `impl Future<Output = T>` here because lower_body
// only cares about the input argument patterns in the function
// declaration (decl), not the return types.
let body_id = this.lower_async_body(&decl, &header.asyncness.node, body);
let (generics, fn_decl) = this.add_in_band_defs(
generics,
fn_def_id,
AnonymousLifetimeMode::PassThrough,
|this, idty| this.lower_fn_decl(
&decl,
Some((fn_def_id, idty)),
true,
header.asyncness.node.opt_return_id()
),
);
2018-09-24 03:25:23 +00:00
(body_id, generics, fn_decl)
};
let (body_id, generics, fn_decl) = if let IsAsync::Async {
arguments, ..
} = &header.asyncness.node {
let mut decl = decl.clone();
// Replace the arguments of this async function with the generated
// arguments that will be moved into the closure.
for (i, a) in arguments.clone().drain(..).enumerate() {
if let Some(arg) = a.arg {
decl.inputs[i] = arg;
}
}
lower_fn(&decl)
} else {
lower_fn(decl)
};
2018-06-06 22:50:59 +00:00
2018-09-24 03:25:23 +00:00
hir::ItemKind::Fn(
fn_decl,
this.lower_fn_header(header),
generics,
body_id,
)
2017-02-15 22:52:27 +00:00
})
}
2018-07-11 15:36:06 +00:00
ItemKind::Mod(ref m) => hir::ItemKind::Mod(self.lower_mod(m)),
ItemKind::ForeignMod(ref nm) => hir::ItemKind::ForeignMod(self.lower_foreign_mod(nm)),
ItemKind::GlobalAsm(ref ga) => hir::ItemKind::GlobalAsm(self.lower_global_asm(ga)),
ItemKind::Ty(ref t, ref generics) => hir::ItemKind::Ty(
self.lower_ty(t, ImplTraitContext::disallowed()),
self.lower_generics(generics, ImplTraitContext::disallowed()),
2018-03-21 08:24:27 +00:00
),
2018-07-03 17:38:14 +00:00
ItemKind::Existential(ref b, ref generics) => hir::ItemKind::Existential(hir::ExistTy {
generics: self.lower_generics(generics, ImplTraitContext::disallowed()),
bounds: self.lower_param_bounds(b, ImplTraitContext::disallowed()),
2018-07-03 17:38:14 +00:00
impl_trait_fn: None,
origin: hir::ExistTyOrigin::ExistentialType,
2018-07-03 17:38:14 +00:00
}),
2018-07-11 15:36:06 +00:00
ItemKind::Enum(ref enum_definition, ref generics) => hir::ItemKind::Enum(
2018-03-21 08:24:27 +00:00
hir::EnumDef {
variants: enum_definition
.variants
.iter()
.map(|x| self.lower_variant(x))
.collect(),
},
self.lower_generics(generics, ImplTraitContext::disallowed()),
2018-03-21 08:24:27 +00:00
),
ItemKind::Struct(ref struct_def, ref generics) => {
let struct_def = self.lower_variant_data(struct_def);
2018-07-11 15:36:06 +00:00
hir::ItemKind::Struct(
struct_def,
self.lower_generics(generics, ImplTraitContext::disallowed()),
)
}
ItemKind::Union(ref vdata, ref generics) => {
let vdata = self.lower_variant_data(vdata);
2018-07-11 15:36:06 +00:00
hir::ItemKind::Union(
vdata,
self.lower_generics(generics, ImplTraitContext::disallowed()),
)
}
2018-03-21 08:24:27 +00:00
ItemKind::Impl(
unsafety,
polarity,
defaultness,
ref ast_generics,
ref trait_ref,
2018-03-21 08:24:27 +00: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.
2019-04-26 12:23:30 +00:00
let lowered_trait_impl_id = self.lower_node_id(id);
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| {
this.lower_trait_ref(trait_ref, ImplTraitContext::disallowed())
2017-11-17 06:59:45 +00:00
});
if let Some(ref trait_ref) = trait_ref {
if let Res::Def(DefKind::Trait, def_id) = trait_ref.path.res {
this.trait_impls.entry(def_id).or_default().push(
lowered_trait_impl_id);
2017-11-17 06:59:45 +00:00
}
}
let lowered_ty = this.lower_ty(ty, ImplTraitContext::disallowed());
2017-11-17 06:59:45 +00:00
(trait_ref, lowered_ty)
},
);
2017-11-17 06:59:45 +00:00
let new_impl_items = self.with_in_scope_lifetime_defs(
&ast_generics.params,
|this| {
2018-03-21 08:24:27 +00:00
impl_items
.iter()
.map(|item| this.lower_impl_item_ref(item))
.collect()
2018-03-21 08:24:27 +00:00
},
);
2018-07-11 15:36:06 +00:00
hir::ItemKind::Impl(
2018-03-21 08:24:27 +00:00
self.lower_unsafety(unsafety),
self.lower_impl_polarity(polarity),
self.lower_defaultness(defaultness, true /* [1] */),
generics,
trait_ref,
2018-03-21 08:24:27 +00:00
lowered_ty,
new_impl_items,
)
}
ItemKind::Trait(is_auto, unsafety, ref generics, ref bounds, ref items) => {
let bounds = self.lower_param_bounds(bounds, ImplTraitContext::disallowed());
2018-03-21 08:24:27 +00:00
let items = items
.iter()
.map(|item| self.lower_trait_item_ref(item))
.collect();
2018-07-11 15:36:06 +00:00
hir::ItemKind::Trait(
2018-03-21 08:24:27 +00:00
self.lower_is_auto(is_auto),
self.lower_unsafety(unsafety),
self.lower_generics(generics, ImplTraitContext::disallowed()),
2018-03-21 08:24:27 +00:00
bounds,
items,
)
}
2018-07-11 15:36:06 +00:00
ItemKind::TraitAlias(ref generics, ref bounds) => hir::ItemKind::TraitAlias(
self.lower_generics(generics, ImplTraitContext::disallowed()),
self.lower_param_bounds(bounds, ImplTraitContext::disallowed()),
2018-03-21 08:24:27 +00:00
),
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 03:03:56 +00:00
}
2015-07-31 07:04:06 +00:00
2018-03-21 08:24:27 +00:00
fn lower_use_tree(
&mut self,
tree: &UseTree,
prefix: &Path,
id: NodeId,
2018-11-22 11:41:26 +00:00
vis: &mut hir::Visibility,
ident: &mut Ident,
2018-03-21 08:24:27 +00:00
attrs: &hir::HirVec<Attribute>,
2018-07-11 15:36:06 +00:00
) -> hir::ItemKind {
2018-11-21 18:35:54 +00:00
debug!("lower_use_tree(tree={:?})", tree);
debug!("lower_use_tree: vis = {:?}", vis);
let path = &tree.prefix;
let segments = prefix
.segments
.iter()
.chain(path.segments.iter())
.cloned()
.collect();
match tree.kind {
UseTreeKind::Simple(rename, id1, id2) => {
*ident = tree.ident();
// First, apply the prefix to the path.
let mut path = Path {
segments,
2018-03-21 08:24:27 +00:00
span: path.span,
};
// Correctly resolve `self` imports.
2018-03-21 08:24:27 +00:00
if path.segments.len() > 1
&& path.segments.last().unwrap().ident.name == keywords::SelfLower.name()
2018-03-21 08:24:27 +00:00
{
let _ = path.segments.pop();
if rename.is_none() {
*ident = path.segments.last().unwrap().ident;
}
}
let mut resolutions = self.expect_full_res_from_use(id);
// We want to return *something* from this function, so hold onto the first item
// for later.
let ret_res = self.lower_res(resolutions.next().unwrap_or(Res::Err));
// Here, we are looping over namespaces, if they exist for the definition
// being imported. We only handle type and value namespaces because we
// won't be dealing with macros in the rest of the compiler.
// Essentially a single `use` which imports two names is desugared into
// two imports.
for (res, &new_node_id) in resolutions.zip([id1, id2].iter()) {
let vis = vis.clone();
let ident = ident.clone();
let mut path = path.clone();
for seg in &mut path.segments {
seg.id = self.sess.next_node_id();
}
let span = path.span;
self.with_hir_id_owner(new_node_id, |this| {
let new_id = this.lower_node_id(new_node_id);
let res = this.lower_res(res);
let path =
this.lower_path_extra(res, &path, ParamMode::Explicit, None);
2018-07-11 15:36:06 +00:00
let item = hir::ItemKind::Use(P(path), hir::UseKind::Single);
let vis_kind = match vis.node {
hir::VisibilityKind::Public => hir::VisibilityKind::Public,
hir::VisibilityKind::Crate(sugar) => hir::VisibilityKind::Crate(sugar),
hir::VisibilityKind::Inherited => hir::VisibilityKind::Inherited,
2019-02-26 14:55:01 +00:00
hir::VisibilityKind::Restricted { ref path, hir_id: _ } => {
let path = this.renumber_segment_ids(path);
hir::VisibilityKind::Restricted {
path,
2019-04-26 12:23:30 +00:00
hir_id: this.next_id(),
}
}
};
let vis = respan(vis.span, vis_kind);
2018-06-06 20:13:52 +00:00
this.insert_item(
hir::Item {
2019-04-26 12:23:30 +00:00
hir_id: new_id,
ident,
attrs: attrs.clone(),
node: item,
vis,
span,
},
);
});
}
let path =
P(self.lower_path_extra(ret_res, &path, ParamMode::Explicit, None));
2018-07-11 15:36:06 +00:00
hir::ItemKind::Use(path, hir::UseKind::Single)
}
UseTreeKind::Glob => {
2018-03-21 08:24:27 +00:00
let path = P(self.lower_path(
id,
&Path {
segments,
2018-03-21 08:24:27 +00:00
span: path.span,
},
ParamMode::Explicit,
));
2018-07-11 15:36:06 +00:00
hir::ItemKind::Use(path, hir::UseKind::Glob)
}
UseTreeKind::Nested(ref trees) => {
// Nested imports are desugared into simple imports.
// So, if we start with
2018-11-22 11:48:13 +00:00
//
// ```
// pub(x) use foo::{a, b};
// ```
//
// we will create three items:
//
// ```
// pub(x) use foo::a;
// pub(x) use foo::b;
// pub(x) use foo::{}; // <-- this is called the `ListStem`
// ```
//
// The first two are produced by recursively invoking
// `lower_use_tree` (and indeed there may be things
// like `use foo::{a::{b, c}}` and so forth). They
// wind up being directly added to
// `self.items`. However, the structure of this
// function also requires us to return one item, and
// for that we return the `{}` import (called the
// `ListStem`).
let prefix = Path {
segments,
span: prefix.span.to(path.span),
};
// Add all the nested `PathListItem`s to the HIR.
for &(ref use_tree, id) in trees {
2019-04-26 12:23:30 +00:00
let new_hir_id = self.lower_node_id(id);
2018-11-22 11:41:26 +00:00
let mut vis = vis.clone();
let mut ident = ident.clone();
let mut prefix = prefix.clone();
// Give the segments new node-ids since they are being cloned.
for seg in &mut prefix.segments {
seg.id = self.sess.next_node_id();
}
// Each `use` import is an item and thus are owners of the
// names in the path. Up to this point the nested import is
// the current owner, since we want each desugared import to
// own its own names, we have to adjust the owner before
// lowering the rest of the import.
2019-04-26 12:23:30 +00:00
self.with_hir_id_owner(id, |this| {
let item = this.lower_use_tree(use_tree,
&prefix,
2019-04-26 12:23:30 +00:00
id,
2018-11-22 11:41:26 +00:00
&mut vis,
&mut ident,
attrs);
let vis_kind = match vis.node {
hir::VisibilityKind::Public => hir::VisibilityKind::Public,
hir::VisibilityKind::Crate(sugar) => hir::VisibilityKind::Crate(sugar),
hir::VisibilityKind::Inherited => hir::VisibilityKind::Inherited,
2019-02-26 14:55:01 +00:00
hir::VisibilityKind::Restricted { ref path, hir_id: _ } => {
let path = this.renumber_segment_ids(path);
hir::VisibilityKind::Restricted {
path: path,
2019-04-26 12:23:30 +00:00
hir_id: this.next_id(),
}
}
};
let vis = respan(vis.span, vis_kind);
2018-06-06 20:13:52 +00:00
this.insert_item(
2018-03-21 08:24:27 +00:00
hir::Item {
hir_id: new_hir_id,
ident,
2018-03-21 08:24:27 +00:00
attrs: attrs.clone(),
node: item,
vis,
span: use_tree.span,
},
);
});
}
2018-11-22 11:41:26 +00:00
// Subtle and a bit hacky: we lower the privacy level
// of the list stem to "private" most of the time, but
// not for "restricted" paths. The key thing is that
// we don't want it to stay as `pub` (with no caveats)
// because that affects rustdoc and also the lints
// about `pub` items. But we can't *always* make it
// private -- particularly not for restricted paths --
// because it contains node-ids that would then be
// unused, failing the check that HirIds are "densely
// assigned".
match vis.node {
hir::VisibilityKind::Public |
hir::VisibilityKind::Crate(_) |
hir::VisibilityKind::Inherited => {
*vis = respan(prefix.span.shrink_to_lo(), hir::VisibilityKind::Inherited);
}
hir::VisibilityKind::Restricted { .. } => {
// Do nothing here, as described in the comment on the match.
2018-11-22 11:41:26 +00:00
}
}
let res = self.expect_full_res_from_use(id).next().unwrap_or(Res::Err);
let res = self.lower_res(res);
let path = P(self.lower_path_extra(res, &prefix, ParamMode::Explicit, None));
2018-07-11 15:36:06 +00:00
hir::ItemKind::Use(path, hir::UseKind::ListStem)
}
}
}
/// Paths like the visibility path in `pub(super) use foo::{bar, baz}` are repeated
/// many times in the HIR tree; for each occurrence, we need to assign distinct
2019-02-08 13:53:55 +00:00
/// `NodeId`s. (See, e.g., #56128.)
fn renumber_segment_ids(&mut self, path: &P<hir::Path>) -> P<hir::Path> {
debug!("renumber_segment_ids(path = {:?})", path);
let mut path = path.clone();
for seg in path.segments.iter_mut() {
2019-03-06 13:44:24 +00:00
if seg.hir_id.is_some() {
2019-04-26 12:23:30 +00:00
seg.hir_id = Some(self.next_id());
}
}
path
}
fn lower_trait_item(&mut self, i: &TraitItem) -> hir::TraitItem {
2019-04-26 12:23:30 +00:00
let trait_item_def_id = self.resolver.definitions().local_def_id(i.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 08:24:27 +00:00
),
),
TraitItemKind::Method(ref sig, None) => {
2018-09-24 03:25:23 +00:00
let names = self.lower_fn_args_to_names(&sig.decl);
let (generics, sig) = self.lower_method_sig(
&i.generics,
sig,
trait_item_def_id,
false,
None,
);
(generics, hir::TraitItemKind::Method(sig, hir::TraitMethod::Required(names)))
}
TraitItemKind::Method(ref sig, Some(ref body)) => {
2018-09-24 03:25:23 +00:00
let body_id = self.lower_body(Some(&sig.decl), |this| {
let body = this.lower_block(body, false);
this.expr_block(body, ThinVec::new())
});
let (generics, sig) = self.lower_method_sig(
&i.generics,
sig,
trait_item_def_id,
false,
None,
);
(generics, hir::TraitItemKind::Method(sig, hir::TraitMethod::Provided(body_id)))
}
TraitItemKind::Type(ref bounds, ref default) => (
self.lower_generics(&i.generics, ImplTraitContext::disallowed()),
hir::TraitItemKind::Type(
self.lower_param_bounds(bounds, ImplTraitContext::disallowed()),
default
.as_ref()
.map(|x| self.lower_ty(x, ImplTraitContext::disallowed())),
2018-03-21 08:24:27 +00:00
),
),
TraitItemKind::Macro(..) => panic!("Shouldn't exist any more"),
};
2017-11-17 06:59:45 +00:00
hir::TraitItem {
2019-04-26 12:23:30 +00:00
hir_id: self.lower_node_id(i.id),
ident: i.ident,
attrs: self.lower_attrs(&i.attrs),
generics,
node,
span: i.span,
}
2015-07-31 07:04:06 +00: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 08:24:27 +00:00
TraitItemKind::Method(ref sig, ref default) => (
hir::AssociatedItemKind::Method {
has_self: sig.decl.has_self(),
2018-03-21 08:24:27 +00:00
},
default.is_some(),
),
TraitItemKind::Macro(..) => unimplemented!(),
};
hir::TraitItemRef {
2019-04-26 12:23:30 +00:00
id: hir::TraitItemId { hir_id: self.lower_node_id(i.id) },
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 {
2019-04-26 12:23:30 +00:00
let impl_item_def_id = self.resolver.definitions().local_def_id(i.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 mut lower_method = |sig: &MethodSig| {
let body_id = self.lower_async_body(
&sig.decl, &sig.header.asyncness.node, body
);
let impl_trait_return_allow = !self.is_in_trait_impl;
let (generics, sig) = self.lower_method_sig(
&i.generics,
sig,
impl_item_def_id,
impl_trait_return_allow,
sig.header.asyncness.node.opt_return_id(),
);
(body_id, generics, sig)
};
let (body_id, generics, sig) = if let IsAsync::Async {
ref arguments, ..
} = sig.header.asyncness.node {
let mut sig = sig.clone();
// Replace the arguments of this async function with the generated
// arguments that will be moved into the closure.
for (i, a) in arguments.clone().drain(..).enumerate() {
if let Some(arg) = a.arg {
sig.decl.inputs[i] = arg;
}
}
lower_method(&sig)
} else {
lower_method(sig)
};
2018-09-24 03:25:23 +00:00
(generics, hir::ImplItemKind::Method(sig, body_id))
}
ImplItemKind::Type(ref ty) => (
self.lower_generics(&i.generics, ImplTraitContext::disallowed()),
hir::ImplItemKind::Type(self.lower_ty(ty, ImplTraitContext::disallowed())),
),
2018-07-03 17:38:14 +00:00
ImplItemKind::Existential(ref bounds) => (
self.lower_generics(&i.generics, ImplTraitContext::disallowed()),
2018-07-03 17:38:14 +00:00
hir::ImplItemKind::Existential(
self.lower_param_bounds(bounds, ImplTraitContext::disallowed()),
2018-07-03 17:38:14 +00:00
),
),
ImplItemKind::Macro(..) => panic!("Shouldn't exist any more"),
};
hir::ImplItem {
2019-04-26 12:23:30 +00:00
hir_id: self.lower_node_id(i.id),
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 07:04:06 +00:00
}
fn lower_impl_item_ref(&mut self, i: &ImplItem) -> hir::ImplItemRef {
hir::ImplItemRef {
2019-04-26 12:23:30 +00:00
id: hir::ImplItemId { hir_id: self.lower_node_id(i.id) },
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-07-03 17:38:14 +00:00
ImplItemKind::Existential(..) => hir::AssociatedItemKind::Existential,
2018-03-21 08:24:27 +00: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 07:04:06 +00:00
2018-08-30 09:42:16 +00:00
fn lower_item_id(&mut self, i: &Item) -> SmallVec<[hir::ItemId; 1]> {
let node_ids = match i.node {
ItemKind::Use(ref use_tree) => {
let mut vec = smallvec![i.id];
self.lower_item_id_use_tree(use_tree, i.id, &mut vec);
vec
}
2018-08-30 09:42:16 +00:00
ItemKind::MacroDef(..) => SmallVec::new(),
ItemKind::Fn(..) |
ItemKind::Impl(.., None, _, _) => smallvec![i.id],
ItemKind::Static(ref ty, ..) => {
let mut ids = smallvec![i.id];
if self.sess.features_untracked().impl_trait_in_bindings {
let mut visitor = ImplTraitTypeIdVisitor { ids: &mut ids };
visitor.visit_ty(ty);
}
ids
},
ItemKind::Const(ref ty, ..) => {
let mut ids = smallvec![i.id];
if self.sess.features_untracked().impl_trait_in_bindings {
let mut visitor = ImplTraitTypeIdVisitor { ids: &mut ids };
visitor.visit_ty(ty);
}
ids
},
_ => smallvec![i.id],
};
node_ids.into_iter().map(|node_id| hir::ItemId {
2019-04-26 12:23:30 +00:00
id: self.allocate_hir_id_counter(node_id)
}).collect()
2015-07-31 07:04:06 +00:00
}
fn lower_item_id_use_tree(&mut self,
tree: &UseTree,
base_id: NodeId,
vec: &mut SmallVec<[NodeId; 1]>)
{
match tree.kind {
2018-03-21 08:24:27 +00:00
UseTreeKind::Nested(ref nested_vec) => for &(ref nested, id) in nested_vec {
vec.push(id);
self.lower_item_id_use_tree(nested, id, vec);
2018-03-21 08:24:27 +00:00
},
UseTreeKind::Glob => {}
UseTreeKind::Simple(_, id1, id2) => {
for (_, &id) in self.expect_full_res_from_use(base_id)
.skip(1)
.zip([id1, id2].iter())
{
vec.push(id);
}
},
}
}
pub fn lower_item(&mut self, i: &Item) -> Option<hir::Item> {
let mut ident = i.ident;
2018-11-22 11:41:26 +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") ||
attr::contains_name(&i.attrs, "rustc_doc_only_macro") {
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 15:28:34 +00:00
let body = self.lower_token_stream(def.stream());
2019-04-26 12:23:30 +00:00
let hir_id = self.lower_node_id(i.id);
self.exported_macros.push(hir::MacroDef {
name: ident.name,
vis,
attrs,
2019-02-02 14:40:08 +00:00
hir_id,
2017-03-25 01:46:38 +00:00
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 15:28:34 +00:00
body,
2017-03-25 01:46:38 +00:00
legacy: def.legacy,
});
}
return None;
}
let node = self.lower_item_kind(i.id, &mut ident, &attrs, &mut vis, &i.node);
Some(hir::Item {
2019-04-26 12:23:30 +00:00
hir_id: self.lower_node_id(i.id),
ident,
attrs,
node,
vis,
2016-04-17 22:30:55 +00:00
span: i.span,
})
}
2015-07-31 07:04:06 +00:00
fn lower_foreign_item(&mut self, i: &ForeignItem) -> hir::ForeignItem {
2019-04-26 12:23:30 +00:00
let def_id = self.resolver.definitions().local_def_id(i.id);
hir::ForeignItem {
2019-04-26 12:23:30 +00:00
hir_id: self.lower_node_id(i.id),
ident: i.ident,
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, None),
this.lower_fn_args_to_names(fdec),
)
},
);
2017-11-17 06:59:45 +00:00
2018-07-11 14:56:44 +00:00
hir::ForeignItemKind::Fn(fn_dec, fn_args, generics)
}
ForeignItemKind::Static(ref t, m) => {
hir::ForeignItemKind::Static(
self.lower_ty(t, ImplTraitContext::disallowed()), self.lower_mutability(m))
}
2018-07-11 14:56:44 +00:00
ForeignItemKind::Ty => hir::ForeignItemKind::Type,
ForeignItemKind::Macro(_) => panic!("shouldn't exist here"),
},
vis: self.lower_visibility(&i.vis, None),
span: i.span,
}
2015-07-31 07:04:06 +00:00
}
2018-03-21 08:24:27 +00:00
fn lower_method_sig(
&mut self,
generics: &Generics,
2018-03-21 08:24:27 +00:00
sig: &MethodSig,
fn_def_id: DefId,
2018-03-21 08:24:27 +00:00
impl_trait_return_allow: bool,
is_async: Option<NodeId>,
) -> (hir::Generics, hir::MethodSig) {
let header = self.lower_fn_header(&sig.header);
let (generics, decl) = self.add_in_band_defs(
generics,
fn_def_id,
AnonymousLifetimeMode::PassThrough,
|this, idty| this.lower_fn_decl(
&sig.decl,
Some((fn_def_id, idty)),
impl_trait_return_allow,
is_async,
),
);
(generics, hir::MethodSig { header, decl })
2015-07-31 07:04:06 +00:00
}
2017-10-12 14:18:55 +00: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_fn_header(&mut self, h: &FnHeader) -> hir::FnHeader {
hir::FnHeader {
unsafety: self.lower_unsafety(h.unsafety),
asyncness: self.lower_asyncness(&h.asyncness.node),
constness: self.lower_constness(h.constness),
abi: h.abi,
}
}
fn lower_unsafety(&mut self, u: Unsafety) -> hir::Unsafety {
match u {
Unsafety::Unsafe => hir::Unsafety::Unsafe,
Unsafety::Normal => hir::Unsafety::Normal,
}
2015-07-31 07:04:06 +00:00
}
2016-08-10 23:20:12 +00: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 07:04:06 +00:00
}
fn lower_asyncness(&mut self, a: &IsAsync) -> hir::IsAsync {
match a {
IsAsync::Async { .. } => hir::IsAsync::Async,
IsAsync::NotAsync => hir::IsAsync::NotAsync,
}
}
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 07:04:06 +00:00
}
fn lower_binop(&mut self, b: BinOp) -> hir::BinOp {
Spanned {
node: match b.node {
2018-07-11 10:44:53 +00:00
BinOpKind::Add => hir::BinOpKind::Add,
BinOpKind::Sub => hir::BinOpKind::Sub,
BinOpKind::Mul => hir::BinOpKind::Mul,
BinOpKind::Div => hir::BinOpKind::Div,
BinOpKind::Rem => hir::BinOpKind::Rem,
BinOpKind::And => hir::BinOpKind::And,
BinOpKind::Or => hir::BinOpKind::Or,
BinOpKind::BitXor => hir::BinOpKind::BitXor,
BinOpKind::BitAnd => hir::BinOpKind::BitAnd,
BinOpKind::BitOr => hir::BinOpKind::BitOr,
BinOpKind::Shl => hir::BinOpKind::Shl,
BinOpKind::Shr => hir::BinOpKind::Shr,
BinOpKind::Eq => hir::BinOpKind::Eq,
BinOpKind::Lt => hir::BinOpKind::Lt,
BinOpKind::Le => hir::BinOpKind::Le,
BinOpKind::Ne => hir::BinOpKind::Ne,
BinOpKind::Ge => hir::BinOpKind::Ge,
BinOpKind::Gt => hir::BinOpKind::Gt,
},
span: b.span,
}
}
2015-07-31 07:04:06 +00:00
fn lower_pat(&mut self, p: &Pat) -> P<hir::Pat> {
let node = match p.node {
PatKind::Wild => hir::PatKind::Wild,
2018-03-18 13:47:09 +00:00
PatKind::Ident(ref binding_mode, ident, ref sub) => {
match self.resolver.get_partial_res(p.id).map(|d| d.base_res()) {
// `None` can occur in body-less function signatures
res @ None | res @ Some(Res::Local(_)) => {
let canonical_id = match res {
Some(Res::Local(id)) => id,
2018-03-21 08:24:27 +00:00
_ => p.id,
};
2019-03-07 11:18:59 +00:00
2018-03-21 08:24:27 +00:00
hir::PatKind::Binding(
self.lower_binding_mode(binding_mode),
2019-04-26 12:23:30 +00:00
self.lower_node_id(canonical_id),
ident,
2018-03-21 08:24:27 +00:00
sub.as_ref().map(|x| self.lower_pat(x)),
)
}
Some(res) => hir::PatKind::Path(hir::QPath::Resolved(
2018-03-21 08:24:27 +00:00
None,
P(hir::Path {
2018-03-18 13:47:09 +00:00
span: ident.span,
res: self.lower_res(res),
2018-06-10 14:40:45 +00:00
segments: hir_vec![hir::PathSegment::from_ident(ident)],
2018-03-21 08:24:27 +00:00
}),
)),
}
}
PatKind::Lit(ref e) => hir::PatKind::Lit(P(self.lower_expr(e))),
PatKind::TupleStruct(ref path, ref pats, ddpos) => {
2018-03-21 08:24:27 +00:00
let qpath = self.lower_qpath(
p.id,
&None,
path,
ParamMode::Optional,
ImplTraitContext::disallowed(),
2018-03-21 08:24:27 +00:00
);
hir::PatKind::TupleStruct(
qpath,
pats.iter().map(|x| self.lower_pat(x)).collect(),
ddpos,
)
}
2018-09-06 02:46:55 +00:00
PatKind::Path(ref qself, ref path) => {
let qpath = self.lower_qpath(
p.id,
qself,
path,
ParamMode::Optional,
ImplTraitContext::disallowed(),
2018-09-06 02:46:55 +00:00
);
hir::PatKind::Path(qpath)
}
PatKind::Struct(ref path, ref fields, etc) => {
2018-03-21 08:24:27 +00:00
let qpath = self.lower_qpath(
p.id,
&None,
path,
ParamMode::Optional,
ImplTraitContext::disallowed(),
2018-03-21 08:24:27 +00:00
);
let fs = fields
.iter()
2019-02-02 14:40:08 +00:00
.map(|f| {
Spanned {
span: f.span,
node: hir::FieldPat {
2019-04-26 12:23:30 +00:00
hir_id: self.next_id(),
2019-02-02 14:40:08 +00:00
ident: f.node.ident,
pat: self.lower_pat(&f.node.pat),
is_shorthand: f.node.is_shorthand,
},
}
2018-03-21 08:24:27 +00:00
})
.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))
}
PatKind::Range(ref e1, ref e2, Spanned { node: ref end, .. }) => hir::PatKind::Range(
2018-03-21 08:24:27 +00:00
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"),
};
P(hir::Pat {
2019-04-26 12:23:30 +00:00
hir_id: self.lower_node_id(p.id),
node,
span: p.span,
})
}
2015-10-06 03:03:56 +00: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 {
2018-07-20 13:59:00 +00:00
self.with_new_scopes(|this| {
hir::AnonConst {
2019-04-26 12:23:30 +00:00
hir_id: this.lower_node_id(c.id),
2018-07-20 13:59:00 +00:00
body: this.lower_body(None, |this| this.lower_expr(&c.value)),
}
})
}
fn lower_expr(&mut self, e: &Expr) -> hir::Expr {
let kind = match e.node {
2018-07-11 12:05:29 +00:00
ExprKind::Box(ref inner) => hir::ExprKind::Box(P(self.lower_expr(inner))),
2018-05-24 21:34:09 +00:00
ExprKind::ObsoleteInPlace(..) => {
self.sess.abort_if_errors();
span_bug!(e.span, "encountered ObsoleteInPlace expr during lowering");
}
ExprKind::Array(ref exprs) => {
2018-07-11 12:05:29 +00:00
hir::ExprKind::Array(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);
2018-07-11 12:05:29 +00:00
hir::ExprKind::Repeat(expr, count)
}
ExprKind::Tup(ref elts) => {
2018-07-11 12:05:29 +00:00
hir::ExprKind::Tup(elts.iter().map(|x| self.lower_expr(x)).collect())
}
ExprKind::Call(ref f, ref args) => {
let f = P(self.lower_expr(f));
2018-07-11 12:05:29 +00:00
hir::ExprKind::Call(f, args.iter().map(|x| self.lower_expr(x)).collect())
}
ExprKind::MethodCall(ref seg, ref args) => {
let hir_seg = P(self.lower_path_segment(
2018-03-21 08:24:27 +00:00
e.span,
seg,
ParamMode::Optional,
0,
ParenthesizedGenericArgs::Err,
ImplTraitContext::disallowed(),
None,
));
let args = args.iter().map(|x| self.lower_expr(x)).collect();
2018-07-11 12:05:29 +00:00
hir::ExprKind::MethodCall(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));
2018-07-11 12:05:29 +00:00
hir::ExprKind::Binary(binop, lhs, rhs)
}
ExprKind::Unary(op, ref ohs) => {
let op = self.lower_unop(op);
let ohs = P(self.lower_expr(ohs));
2018-07-11 12:05:29 +00:00
hir::ExprKind::Unary(op, ohs)
}
ExprKind::Lit(ref l) => hir::ExprKind::Lit((*l).clone()),
ExprKind::Cast(ref expr, ref ty) => {
let expr = P(self.lower_expr(expr));
hir::ExprKind::Cast(expr, self.lower_ty(ty, ImplTraitContext::disallowed()))
}
ExprKind::Type(ref expr, ref ty) => {
let expr = P(self.lower_expr(expr));
hir::ExprKind::Type(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));
2018-07-11 12:05:29 +00:00
hir::ExprKind::AddrOf(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));
let blk = P(hir::Block {
stmts: hir_vec![],
expr: Some(els),
2019-04-26 12:23:30 +00:00
hir_id: self.next_id(),
rules: hir::DefaultBlock,
span,
targeted_by_break: false,
});
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());
2018-07-11 12:05:29 +00:00
hir::ExprKind::If(P(self.lower_expr(cond)), P(then_expr), else_opt)
}
2018-03-21 08:24:27 +00:00
ExprKind::While(ref cond, ref body, opt_label) => self.with_loop_scope(e.id, |this| {
2018-07-11 12:05:29 +00:00
hir::ExprKind::While(
2018-03-21 08:24:27 +00:00
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| {
2018-07-11 12:05:29 +00:00
hir::ExprKind::Loop(
2018-03-21 08:24:27 +00:00
this.lower_block(body, false),
this.lower_label(opt_label),
hir::LoopSource::Loop,
)
}),
ExprKind::TryBlock(ref body) => {
self.with_catch_scope(body.id, |this| {
let unstable_span = this.mark_span_with_reason(
CompilerDesugaringKind::TryBlock,
body.span,
Some(vec![
Symbol::intern("try_trait"),
].into()),
);
let mut block = this.lower_block(body, true).into_inner();
let tail = block.expr.take().map_or_else(
|| {
2018-08-18 10:14:09 +00:00
let span = this.sess.source_map().end_point(unstable_span);
hir::Expr {
span,
2018-07-11 12:05:29 +00:00
node: hir::ExprKind::Tup(hir_vec![]),
attrs: ThinVec::new(),
2019-04-26 12:23:30 +00:00
hir_id: this.next_id(),
}
},
|x: P<hir::Expr>| x.into_inner(),
);
block.expr = Some(this.wrap_in_try_constructor(
"from_ok", tail, unstable_span));
2018-07-11 12:05:29 +00:00
hir::ExprKind::Block(P(block), None)
})
}
2018-07-11 12:05:29 +00:00
ExprKind::Match(ref expr, ref arms) => hir::ExprKind::Match(
2018-03-21 08:24:27 +00:00
P(self.lower_expr(expr)),
arms.iter().map(|x| self.lower_arm(x)).collect(),
hir::MatchSource::Normal,
),
2018-06-06 22:50:59 +00:00
ExprKind::Async(capture_clause, closure_node_id, ref block) => {
self.make_async_expr(capture_clause, closure_node_id, None, block.span, |this| {
2018-06-06 22:50:59 +00:00
this.with_new_scopes(|this| {
let block = this.lower_block(block, false);
this.expr_block(block, ThinVec::new())
})
})
}
2018-06-06 22:50:59 +00:00
ExprKind::Closure(
capture_clause, ref asyncness, movability, ref decl, ref body, fn_decl_span
) => {
2018-06-26 14:35:52 +00:00
if let IsAsync::Async { closure_id, .. } = asyncness {
let outer_decl = FnDecl {
inputs: decl.inputs.clone(),
output: FunctionRetTy::Default(fn_decl_span),
c_variadic: false,
};
// We need to lower the declaration outside the new scope, because we
// have to conserve the state of being inside a loop condition for the
// closure argument types.
let fn_decl = self.lower_fn_decl(&outer_decl, None, false, None);
self.with_new_scopes(|this| {
// FIXME(cramertj): allow `async` non-`move` closures with arguments.
2018-06-06 22:50:59 +00:00
if capture_clause == CaptureBy::Ref &&
!decl.inputs.is_empty()
{
struct_span_err!(
this.sess,
fn_decl_span,
2018-06-23 18:14:04 +00:00
E0708,
2018-06-06 22:50:59 +00:00
"`async` non-`move` closures with arguments \
are not currently supported",
)
.help("consider using `let` statements to manually capture \
variables by reference before entering an \
`async move` closure")
2018-06-06 22:50:59 +00:00
.emit();
}
2018-06-06 22:50:59 +00:00
// Transform `async |x: u8| -> X { ... }` into
// `|x: u8| future_from_generator(|| -> X { ... })`.
2018-06-06 22:50:59 +00:00
let body_id = this.lower_body(Some(&outer_decl), |this| {
let async_ret_ty = if let FunctionRetTy::Ty(ty) = &decl.output {
Some(&**ty)
} else { None };
let async_body = this.make_async_expr(
capture_clause, *closure_id, async_ret_ty, body.span,
2018-06-06 22:50:59 +00:00
|this| {
this.with_new_scopes(|this| this.lower_expr(body))
});
this.expr(fn_decl_span, async_body, ThinVec::new())
});
2018-07-11 12:05:29 +00:00
hir::ExprKind::Closure(
2018-06-06 22:50:59 +00:00
this.lower_capture_clause(capture_clause),
fn_decl,
2018-06-06 22:50:59 +00:00
body_id,
fn_decl_span,
None,
)
})
} else {
// Lower outside new scope to preserve `is_in_loop_condition`.
let fn_decl = self.lower_fn_decl(decl, None, false, None);
self.with_new_scopes(|this| {
2018-06-06 22:50:59 +00:00
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-23 18:14:04 +00:00
E0697,
2018-06-06 22:50:59 +00:00
"closures cannot be static"
);
}
None
};
2018-07-11 12:05:29 +00:00
hir::ExprKind::Closure(
2018-06-06 22:50:59 +00:00
this.lower_capture_clause(capture_clause),
fn_decl,
2018-06-06 22:50:59 +00:00
body_id,
fn_decl_span,
generator_option,
)
})
}
}
ExprKind::Block(ref blk, opt_label) => {
2018-07-11 12:05:29 +00:00
hir::ExprKind::Block(self.lower_block(blk,
opt_label.is_some()),
self.lower_label(opt_label))
}
ExprKind::Assign(ref el, ref er) => {
2018-07-11 12:05:29 +00:00
hir::ExprKind::Assign(P(self.lower_expr(el)), P(self.lower_expr(er)))
}
2018-07-11 12:05:29 +00:00
ExprKind::AssignOp(op, ref el, ref er) => hir::ExprKind::AssignOp(
2018-03-21 08:24:27 +00:00
self.lower_binop(op),
P(self.lower_expr(el)),
P(self.lower_expr(er)),
),
2018-07-11 12:05:29 +00:00
ExprKind::Field(ref el, ident) => hir::ExprKind::Field(P(self.lower_expr(el)), ident),
ExprKind::Index(ref el, ref er) => {
2018-07-11 12:05:29 +00:00
hir::ExprKind::Index(P(self.lower_expr(el)), P(self.lower_expr(er)))
}
// Desugar `<start>..=<end>` into `std::ops::RangeInclusive::new(<start>, <end>)`.
ExprKind::Range(Some(ref e1), Some(ref e2), RangeLimits::Closed) => {
2018-05-03 14:36:44 +00:00
let id = self.next_id();
let e1 = self.lower_expr(e1);
let e2 = self.lower_expr(e2);
2018-08-01 13:37:38 +00:00
let ty_path = P(self.std_path(e.span, &["ops", "RangeInclusive"], None, false));
let ty = P(self.ty_path(id, e.span, hir::QPath::Resolved(None, ty_path)));
2018-06-27 21:12:17 +00:00
let new_seg = P(hir::PathSegment::from_ident(Ident::from_str("new")));
let new_path = hir::QPath::TypeRelative(ty, new_seg);
2018-08-01 13:37:38 +00:00
let new = P(self.expr(e.span, hir::ExprKind::Path(new_path), ThinVec::new()));
2018-07-11 12:05:29 +00:00
hir::ExprKind::Call(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 08:24:27 +00:00
(_, &None, Closed) => self.diagnostic()
.span_fatal(e.span, "inclusive range with no end")
.raise(),
};
2018-03-21 08:24:27 +00: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));
2018-08-01 13:37:38 +00:00
let ident = Ident::new(Symbol::intern(s), e.span);
self.field(ident, expr, e.span)
2018-03-21 08:24:27 +00:00
})
.collect::<P<[hir::Field]>>();
let is_unit = fields.is_empty();
let struct_path = ["ops", path];
2018-08-01 13:37:38 +00:00
let struct_path = self.std_path(e.span, &struct_path, None, is_unit);
let struct_path = hir::QPath::Resolved(None, P(struct_path));
return hir::Expr {
2019-04-26 12:23:30 +00:00
hir_id: self.lower_node_id(e.id),
node: if is_unit {
2018-07-11 12:05:29 +00:00
hir::ExprKind::Path(struct_path)
} else {
hir::ExprKind::Struct(P(struct_path), fields, None)
},
2018-08-01 13:37:38 +00:00
span: e.span,
attrs: e.attrs.clone(),
};
}
2018-09-06 02:46:55 +00:00
ExprKind::Path(ref qself, ref path) => {
let qpath = self.lower_qpath(
e.id,
qself,
path,
ParamMode::Optional,
ImplTraitContext::disallowed(),
2018-09-06 02:46:55 +00:00
);
hir::ExprKind::Path(qpath)
}
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)))
};
2018-07-11 12:05:29 +00:00
hir::ExprKind::Break(
2018-03-21 08:24:27 +00:00
destination,
opt_expr.as_ref().map(|x| P(self.lower_expr(x))),
)
}
ExprKind::Continue(opt_label) => {
2018-07-11 12:05:29 +00:00
hir::ExprKind::Continue(if self.is_in_loop_condition && opt_label.is_none() {
2018-03-21 08:24:27 +00:00
hir::Destination {
label: None,
target_id: Err(hir::LoopIdError::UnlabeledCfInWhileCondition).into(),
2018-03-21 08:24:27 +00:00
}
} else {
self.lower_loop_destination(opt_label.map(|label| (e.id, label)))
})
}
2018-07-11 12:05:29 +00:00
ExprKind::Ret(ref e) => hir::ExprKind::Ret(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 08:24:27 +00:00
outputs: asm.outputs
.iter()
.map(|out| hir::InlineAsmOutput {
constraint: out.constraint.clone(),
is_rw: out.is_rw,
is_indirect: out.is_indirect,
span: out.expr.span,
2018-03-21 08:24:27 +00: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 08:24:27 +00: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();
2018-07-11 12:05:29 +00:00
hir::ExprKind::InlineAsm(P(hir_asm), outputs, inputs)
}
2018-07-11 12:05:29 +00:00
ExprKind::Struct(ref path, ref fields, ref maybe_expr) => hir::ExprKind::Struct(
P(self.lower_qpath(
2018-03-21 08:24:27 +00:00
e.id,
&None,
path,
ParamMode::Optional,
ImplTraitContext::disallowed(),
)),
2018-03-21 08:24:27 +00:00
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 13:34:03 +00:00
ExprKind::Yield(ref opt_expr) => {
self.is_generator = true;
2018-03-21 08:24:27 +00:00
let expr = opt_expr
.as_ref()
.map(|x| self.lower_expr(x))
2018-07-12 00:20:31 +00:00
.unwrap_or_else(||
self.expr(e.span, hir::ExprKind::Tup(hir_vec![]), ThinVec::new())
);
2018-07-11 12:05:29 +00:00
hir::ExprKind::Yield(P(expr))
2016-12-26 13:34:03 +00:00
}
ExprKind::Err => hir::ExprKind::Err,
// 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 12:10:54 +00:00
P(self.lower_expr(else_expr))
2017-04-15 12:05:30 +00:00
} else {
2017-04-15 12:10:54 +00:00
self.expr_tuple(e.span, hir_vec![])
2017-04-15 12:05:30 +00:00
};
arms.push(self.arm(hir_vec![wildcard_pattern], body));
}
2015-09-28 04:24:42 +00:00
let contains_else_clause = else_opt.is_some();
2015-09-28 04:24:42 +00:00
let sub_expr = P(self.lower_expr(sub_expr));
2015-09-28 02:00:15 +00:00
2018-07-11 12:05:29 +00:00
hir::ExprKind::Match(
sub_expr,
arms.into(),
hir::MatchSource::IfLetDesugar {
contains_else_clause,
2018-03-21 08:24:27 +00:00
},
)
}
2015-09-28 02:00:15 +00: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 08:24:27 +00: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 02:00:15 +00: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 08:24:27 +00:00
let match_expr = self.expr(
sub_expr.span,
2018-07-11 12:05:29 +00:00
hir::ExprKind::Match(sub_expr, arms, hir::MatchSource::WhileLetDesugar),
2018-03-21 08:24:27 +00:00
ThinVec::new(),
);
// `[opt_ident]: loop { ... }`
let loop_block = P(self.block_expr(P(match_expr)));
2018-07-11 12:05:29 +00:00
let loop_expr = hir::ExprKind::Loop(
2018-03-21 08:24:27 +00:00
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;
2018-07-11 10:54:37 +00:00
// StmtKind::Expr(<body>);
// }
// }
// };
// result
// }
// expand <head>
let mut head = self.lower_expr(head);
let head_sp = head.span;
let desugared_span = self.mark_span_with_reason(
CompilerDesugaringKind::ForLoop,
head_sp,
None,
);
head.span = desugared_span;
let iter = self.str_to_ident("iter");
let next_ident = self.str_to_ident("__next");
2019-04-03 07:07:45 +00:00
let (next_pat, next_pat_hid) = self.pat_ident_binding_mode(
desugared_span,
2018-03-21 08:24:27 +00:00
next_ident,
hir::BindingAnnotation::Mutable,
);
// `::std::option::Option::Some(val) => next = val`
let pat_arm = {
let val_ident = self.str_to_ident("val");
2019-04-03 07:07:45 +00:00
let (val_pat, val_pat_hid) = self.pat_ident(pat.span, val_ident);
let val_expr = P(self.expr_ident(pat.span, val_ident, val_pat_hid));
let next_expr = P(self.expr_ident(pat.span, next_ident, next_pat_hid));
2018-03-21 08:24:27 +00:00
let assign = P(self.expr(
pat.span,
2018-07-11 12:05:29 +00:00
hir::ExprKind::Assign(next_expr, val_expr),
2018-03-21 08:24:27 +00:00
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 08:24:27 +00: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`
let (iter_pat, iter_pat_nid) = self.pat_ident_binding_mode(
desugared_span,
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_nid));
let ref_mut_iter = self.expr_mut_addr_of(head_sp, iter);
let next_path = &["iter", "Iterator", "next"];
2018-06-22 05:24:24 +00:00
let next_path = P(self.expr_std_path(head_sp, next_path, None, ThinVec::new()));
2018-03-21 08:24:27 +00: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 08:24:27 +00:00
P(self.expr(
head_sp,
2018-07-12 00:20:31 +00:00
hir::ExprKind::Match(
next_expr,
arms,
hir::MatchSource::ForLoopDesugar
),
2018-03-21 08:24:27 +00:00
ThinVec::new(),
))
};
let match_stmt = hir::Stmt {
2019-04-26 12:23:30 +00:00
hir_id: self.next_id(),
node: hir::StmtKind::Expr(match_expr),
span: head_sp,
};
2019-04-03 07:07:45 +00:00
let next_expr = P(self.expr_ident(head_sp, next_ident, next_pat_hid));
// `let mut __next`
let next_let = self.stmt_let_pat(
desugared_span,
None,
next_pat,
hir::LocalSource::ForLoopDesugar,
);
// `let <pat> = __next`
let pat = self.lower_pat(pat);
2018-03-21 08:24:27 +00:00
let pat_let = self.stmt_let_pat(
head_sp,
Some(next_expr),
pat,
2018-03-21 08:24:27 +00: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 = hir::Stmt {
2019-04-26 12:23:30 +00:00
hir_id: self.next_id(),
node: hir::StmtKind::Expr(body_expr),
span: body.span,
};
2018-03-21 08:24:27 +00: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-07-11 12:05:29 +00:00
let loop_expr = hir::ExprKind::Loop(
2018-03-21 08:24:27 +00:00
loop_block,
self.lower_label(opt_label),
hir::LoopSource::ForLoop,
);
let loop_expr = P(hir::Expr {
2019-04-26 12:23:30 +00:00
hir_id: self.lower_node_id(e.id),
node: loop_expr,
span: e.span,
attrs: ThinVec::new(),
});
2015-09-28 02:00:15 +00: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-06-22 05:24:24 +00:00
let into_iter = P(self.expr_std_path(
head_sp, into_iter_path, None, ThinVec::new()));
P(self.expr_call(head_sp, into_iter, hir_vec![head]))
};
2018-03-21 08:24:27 +00:00
let match_expr = P(self.expr_match(
head_sp,
into_iter_expr,
hir_vec![iter_arm],
hir::MatchSource::ForLoopDesugar,
));
// This is effectively `{ let _result = ...; _result }`.
// The construct was introduced in #21984.
// FIXME(60253): Is this still necessary?
// Also, add the attributes to the outer returned expr node.
return self.expr_drop_temps(head_sp, match_expr, e.attrs.clone())
}
// Desugar `ExprKind::Try`
// from: `<expr>?`
ExprKind::Try(ref sub_expr) => {
// into:
//
// 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.mark_span_with_reason(
CompilerDesugaringKind::QuestionMark,
e.span,
Some(vec![
Symbol::intern("try_trait")
].into()),
);
let try_span = self.sess.source_map().end_point(e.span);
let try_span = self.mark_span_with_reason(
CompilerDesugaringKind::QuestionMark,
try_span,
Some(vec![
Symbol::intern("try_trait")
].into()),
);
// `Try::into_result(<expr>)`
let discr = {
// expand <expr>
let sub_expr = self.lower_expr(sub_expr);
let path = &["ops", "Try", "into_result"];
2018-06-22 05:24:24 +00:00
let path = P(self.expr_std_path(
unstable_span, path, None, 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, val_pat_nid) = self.pat_ident(e.span, val_ident);
2018-03-21 08:24:27 +00:00
let val_expr = P(self.expr_ident_with_attrs(
e.span,
val_ident,
val_pat_nid,
2018-03-21 08:24:27 +00:00
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, err_local_nid) = self.pat_ident(try_span, err_ident);
let from_expr = {
let path = &["convert", "From", "from"];
2018-06-22 05:24:24 +00:00
let from = P(self.expr_std_path(
try_span, path, None, ThinVec::new()));
let err_expr = self.expr_ident(try_span, err_ident, err_local_nid);
self.expr_call(try_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 {
2019-04-26 12:23:30 +00:00
let target_id = Ok(self.lower_node_id(catch_node));
P(self.expr(
try_span,
2018-07-11 12:05:29 +00:00
hir::ExprKind::Break(
hir::Destination {
label: None,
target_id,
},
2018-03-21 08:24:27 +00:00
Some(from_err_expr),
),
2018-03-21 08:24:27 +00:00
thin_attrs,
))
} else {
P(self.expr(try_span, hir::ExprKind::Ret(Some(from_err_expr)), thin_attrs))
};
let err_pat = self.pat_err(try_span, err_local);
self.arm(hir_vec![err_pat], ret_expr)
};
2016-05-02 00:02:38 +00:00
2018-07-11 12:05:29 +00:00
hir::ExprKind::Match(
2018-03-21 08:24:27 +00:00
discr,
hir_vec![err_arm, ok_arm],
hir::MatchSource::TryDesugar,
)
}
ExprKind::Mac(_) => panic!("Shouldn't exist here"),
};
hir::Expr {
2019-04-26 12:23:30 +00:00
hir_id: self.lower_node_id(e.id),
node: kind,
span: e.span,
attrs: e.attrs.clone(),
}
}
2015-07-31 07:04:06 +00:00
2018-08-30 09:42:16 +00:00
fn lower_stmt(&mut self, s: &Stmt) -> SmallVec<[hir::Stmt; 1]> {
2018-08-13 19:15:16 +00:00
smallvec![match s.node {
2018-08-19 02:40:50 +00:00
StmtKind::Local(ref l) => {
let (l, item_ids) = self.lower_local(l);
2018-08-30 09:42:16 +00:00
let mut ids: SmallVec<[hir::Stmt; 1]> = item_ids
2018-08-19 02:40:50 +00:00
.into_iter()
2019-02-02 14:40:08 +00:00
.map(|item_id| {
2019-04-26 12:23:30 +00:00
let item_id = hir::ItemId { id: self.lower_node_id(item_id) };
2019-02-02 14:40:08 +00:00
hir::Stmt {
2019-04-26 12:23:30 +00:00
hir_id: self.next_id(),
node: hir::StmtKind::Item(item_id),
2019-02-02 14:40:08 +00:00
span: s.span,
}
2018-08-19 02:40:50 +00:00
})
.collect();
2019-02-02 14:40:08 +00:00
ids.push({
hir::Stmt {
2019-04-26 12:23:30 +00:00
hir_id: self.lower_node_id(s.id),
2019-02-02 14:40:08 +00:00
node: hir::StmtKind::Local(P(l)),
span: s.span,
}
2018-08-19 02:40:50 +00:00
});
return ids;
2016-06-17 02:30:01 +00:00
},
StmtKind::Item(ref it) => {
// Can only use the ID once.
let mut id = Some(s.id);
2018-03-21 08:24:27 +00:00
return self.lower_item_id(it)
.into_iter()
2019-02-02 14:40:08 +00:00
.map(|item_id| {
2019-04-26 12:23:30 +00:00
let hir_id = id.take()
2019-02-02 14:40:08 +00:00
.map(|id| self.lower_node_id(id))
.unwrap_or_else(|| self.next_id());
hir::Stmt {
hir_id,
node: hir::StmtKind::Item(item_id),
2019-02-02 14:40:08 +00:00
span: s.span,
}
2018-03-21 08:24:27 +00:00
})
.collect();
}
2019-02-02 14:40:08 +00:00
StmtKind::Expr(ref e) => {
hir::Stmt {
2019-04-26 12:23:30 +00:00
hir_id: self.lower_node_id(s.id),
2019-02-02 14:40:08 +00:00
node: hir::StmtKind::Expr(P(self.lower_expr(e))),
span: s.span,
}
2018-03-21 08:24:27 +00:00
},
2019-02-02 14:40:08 +00:00
StmtKind::Semi(ref e) => {
hir::Stmt {
2019-04-26 12:23:30 +00:00
hir_id: self.lower_node_id(s.id),
2019-02-02 14:40:08 +00:00
node: hir::StmtKind::Semi(P(self.lower_expr(e))),
span: s.span,
}
2018-03-21 08:24:27 +00:00
},
StmtKind::Mac(..) => panic!("Shouldn't exist here"),
2018-08-13 19:15:16 +00:00
}]
2015-07-31 07:04:06 +00:00
}
fn lower_capture_clause(&mut self, c: CaptureBy) -> hir::CaptureClause {
match c {
CaptureBy::Value => hir::CaptureByValue,
CaptureBy::Ref => hir::CaptureByRef,
}
2015-07-31 07:04:06 +00: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 08:24:27 +00:00
fn lower_visibility(
&mut self,
v: &Visibility,
explicit_owner: Option<NodeId>,
) -> hir::Visibility {
let node = match v.node {
VisibilityKind::Public => hir::VisibilityKind::Public,
VisibilityKind::Crate(sugar) => hir::VisibilityKind::Crate(sugar),
VisibilityKind::Restricted { ref path, id } => {
2018-11-21 18:35:54 +00:00
debug!("lower_visibility: restricted path id = {:?}", id);
let lowered_id = if let Some(owner) = explicit_owner {
self.lower_node_id_with_owner(id, owner)
2018-03-21 08:24:27 +00:00
} else {
self.lower_node_id(id)
};
let res = self.expect_full_res(id);
let res = self.lower_res(res);
hir::VisibilityKind::Restricted {
path: P(self.lower_path_extra(
res,
path,
ParamMode::Explicit,
explicit_owner,
)),
2019-04-26 12:23:30 +00:00
hir_id: lowered_id,
}
2018-03-21 08:24:27 +00:00
},
VisibilityKind::Inherited => hir::VisibilityKind::Inherited,
};
respan(v.span, node)
2015-07-31 07:04:06 +00:00
}
2018-07-03 17:38:14 +00:00
fn lower_defaultness(&self, d: Defaultness, has_value: bool) -> hir::Defaultness {
match d {
2018-03-21 08:24:27 +00: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 07:04:06 +00:00
}
fn lower_binding_mode(&mut self, b: &BindingMode) -> hir::BindingAnnotation {
match *b {
2018-03-21 08:24:27 +00: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 07:04:06 +00:00
}
fn lower_unsafe_source(&mut self, u: UnsafeSource) -> hir::UnsafeSource {
match u {
CompilerGenerated => hir::CompilerGenerated,
UserProvided => hir::UserProvided,
}
2015-07-31 07:04:06 +00: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 07:04:06 +00: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 07:04:06 +00:00
}
2015-09-28 02:00:15 +00:00
// Helper methods for building HIR.
2015-09-28 02:00:15 +00: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 02:00:15 +00:00
}
2018-05-25 23:50:15 +00:00
fn field(&mut self, ident: Ident, expr: P<hir::Expr>, span: Span) -> hir::Field {
hir::Field {
2019-04-26 12:23:30 +00:00
hir_id: self.next_id(),
2018-05-25 23:50:15 +00:00
ident,
span,
expr,
is_shorthand: false,
}
}
fn expr_break(&mut self, span: Span, attrs: ThinVec<Attribute>) -> P<hir::Expr> {
2018-07-11 12:05:29 +00:00
let expr_break = hir::ExprKind::Break(self.lower_loop_destination(None), None);
2017-02-15 22:52:27 +00:00
P(self.expr(span, expr_break, attrs))
}
2015-09-28 02:00:15 +00:00
2018-03-21 08:24:27 +00:00
fn expr_call(
&mut self,
span: Span,
e: P<hir::Expr>,
args: hir::HirVec<hir::Expr>,
) -> hir::Expr {
2018-07-11 12:05:29 +00:00
self.expr(span, hir::ExprKind::Call(e, args), ThinVec::new())
}
2015-09-28 02:00:15 +00:00
2019-04-03 07:07:45 +00:00
fn expr_ident(&mut self, span: Span, ident: Ident, binding: hir::HirId) -> hir::Expr {
2018-06-10 14:40:45 +00:00
self.expr_ident_with_attrs(span, ident, binding, ThinVec::new())
}
2018-03-21 08:24:27 +00:00
fn expr_ident_with_attrs(
&mut self,
span: Span,
2018-06-10 14:40:45 +00:00
ident: Ident,
2019-04-03 07:07:45 +00:00
binding: hir::HirId,
2018-03-21 08:24:27 +00:00
attrs: ThinVec<Attribute>,
) -> hir::Expr {
2018-07-11 12:05:29 +00:00
let expr_path = hir::ExprKind::Path(hir::QPath::Resolved(
2018-03-21 08:24:27 +00:00
None,
P(hir::Path {
span,
res: Res::Local(binding),
2018-06-10 14:40:45 +00:00
segments: hir_vec![hir::PathSegment::from_ident(ident)],
2018-03-21 08:24:27 +00:00
}),
));
2016-05-06 08:24:04 +00:00
self.expr(span, expr_path, attrs)
}
2015-09-28 02:00:15 +00:00
fn expr_mut_addr_of(&mut self, span: Span, e: P<hir::Expr>) -> hir::Expr {
2018-07-11 12:05:29 +00:00
self.expr(span, hir::ExprKind::AddrOf(hir::MutMutable, e), ThinVec::new())
}
2015-09-28 02:00:15 +00:00
2018-03-21 08:24:27 +00:00
fn expr_std_path(
&mut self,
span: Span,
components: &[&str],
2018-06-22 06:24:51 +00:00
params: Option<P<hir::GenericArgs>>,
2018-03-21 08:24:27 +00:00
attrs: ThinVec<Attribute>,
) -> hir::Expr {
2018-06-22 05:24:24 +00:00
let path = self.std_path(span, components, params, true);
2018-03-21 08:24:27 +00:00
self.expr(
span,
2018-07-11 12:05:29 +00:00
hir::ExprKind::Path(hir::QPath::Resolved(None, P(path))),
2018-03-21 08:24:27 +00:00
attrs,
)
}
2015-09-28 02:00:15 +00:00
/// Wrap the given `expr` in a terminating scope using `hir::ExprKind::DropTemps`.
///
/// In terms of drop order, it has the same effect as wrapping `expr` in
/// `{ let _t = $expr; _t }` but should provide better compile-time performance.
///
/// The drop order can be important in e.g. `if expr { .. }`.
fn expr_drop_temps(
&mut self,
span: Span,
expr: P<hir::Expr>,
attrs: ThinVec<Attribute>
) -> hir::Expr {
self.expr(span, hir::ExprKind::DropTemps(expr), attrs)
}
2018-03-21 08:24:27 +00:00
fn expr_match(
&mut self,
span: Span,
arg: P<hir::Expr>,
arms: hir::HirVec<hir::Arm>,
source: hir::MatchSource,
) -> hir::Expr {
2018-07-11 12:05:29 +00:00
self.expr(span, hir::ExprKind::Match(arg, arms, source), ThinVec::new())
}
2015-09-28 02:00:15 +00:00
fn expr_block(&mut self, b: P<hir::Block>, attrs: ThinVec<Attribute>) -> hir::Expr {
2018-07-11 12:05:29 +00:00
self.expr(b.span, hir::ExprKind::Block(b, None), attrs)
}
2015-09-28 02:00:15 +00:00
fn expr_tuple(&mut self, sp: Span, exprs: hir::HirVec<hir::Expr>) -> P<hir::Expr> {
2018-07-11 12:05:29 +00:00
P(self.expr(sp, hir::ExprKind::Tup(exprs), ThinVec::new()))
}
2015-09-28 04:24:42 +00:00
2018-07-11 12:05:29 +00:00
fn expr(&mut self, span: Span, node: hir::ExprKind, attrs: ThinVec<Attribute>) -> hir::Expr {
hir::Expr {
2019-04-26 12:23:30 +00:00
hir_id: self.next_id(),
node,
span,
attrs,
}
}
2018-03-21 08:24:27 +00:00
fn stmt_let_pat(
&mut self,
sp: Span,
ex: Option<P<hir::Expr>>,
pat: P<hir::Pat>,
source: hir::LocalSource,
) -> hir::Stmt {
let local = hir::Local {
pat,
ty: None,
init: ex,
2019-04-26 12:23:30 +00:00
hir_id: self.next_id(),
span: sp,
attrs: ThinVec::new(),
source,
};
2019-02-02 14:40:08 +00:00
hir::Stmt {
2019-04-26 12:23:30 +00:00
hir_id: self.next_id(),
node: hir::StmtKind::Local(P(local)),
span: sp
}
}
fn block_expr(&mut self, expr: P<hir::Expr>) -> hir::Block {
self.block_all(expr.span, hir::HirVec::new(), Some(expr))
}
2015-09-28 02:00:15 +00:00
2018-03-21 08:24:27 +00:00
fn block_all(
&mut self,
span: Span,
stmts: hir::HirVec<hir::Stmt>,
expr: Option<P<hir::Expr>>,
) -> hir::Block {
hir::Block {
stmts,
expr,
2019-04-26 12:23:30 +00:00
hir_id: self.next_id(),
rules: hir::DefaultBlock,
span,
targeted_by_break: false,
}
}
2015-09-28 02:00:15 +00: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 02:00:15 +00: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 02:00:15 +00:00
2018-03-21 08:24:27 +00:00
fn pat_std_enum(
&mut self,
span: Span,
components: &[&str],
subpats: hir::HirVec<P<hir::Pat>>,
) -> P<hir::Pat> {
2018-06-22 05:24:24 +00:00
let path = self.std_path(span, components, None, 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 02:00:15 +00:00
2019-04-03 07:07:45 +00:00
fn pat_ident(&mut self, span: Span, ident: Ident) -> (P<hir::Pat>, hir::HirId) {
2018-06-10 14:40:45 +00:00
self.pat_ident_binding_mode(span, ident, hir::BindingAnnotation::Unannotated)
}
2015-09-28 02:00:15 +00:00
2018-03-21 08:24:27 +00:00
fn pat_ident_binding_mode(
&mut self,
span: Span,
2018-06-10 14:40:45 +00:00
ident: Ident,
2018-03-21 08:24:27 +00:00
bm: hir::BindingAnnotation,
2019-04-03 07:07:45 +00:00
) -> (P<hir::Pat>, hir::HirId) {
2019-04-26 12:23:30 +00:00
let hir_id = self.next_id();
2015-09-28 04:24:42 +00:00
(
P(hir::Pat {
hir_id,
2019-03-07 11:18:59 +00:00
node: hir::PatKind::Binding(bm, hir_id, ident.with_span_pos(span), None),
span,
}),
2019-04-03 07:07:45 +00:00
hir_id
)
}
2015-09-28 02:00:15 +00:00
fn pat_wild(&mut self, span: Span) -> P<hir::Pat> {
self.pat(span, hir::PatKind::Wild)
}
2015-09-28 02:00:15 +00:00
fn pat(&mut self, span: Span, pat: hir::PatKind) -> P<hir::Pat> {
P(hir::Pat {
2019-04-26 12:23:30 +00:00
hir_id: self.next_id(),
node: pat,
span,
})
}
2015-09-28 02:00:15 +00: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`.
2018-06-22 05:24:24 +00:00
fn std_path(
&mut self,
span: Span,
components: &[&str],
2018-06-22 06:24:51 +00:00
params: Option<P<hir::GenericArgs>>,
2018-06-22 05:24:24 +00:00
is_value: bool
) -> hir::Path {
let mut path = self.resolver
2018-10-25 02:23:45 +00:00
.resolve_str_path(span, self.crate_root, components, is_value);
path.segments.last_mut().unwrap().args = params;
for seg in path.segments.iter_mut() {
2019-03-06 13:44:24 +00:00
if seg.hir_id.is_some() {
2019-04-26 12:23:30 +00:00
seg.hir_id = Some(self.next_id());
}
}
path
}
2019-04-26 12:23:30 +00:00
fn ty_path(&mut self, mut hir_id: hir::HirId, span: Span, qpath: hir::QPath) -> hir::Ty {
let node = match qpath {
hir::QPath::Resolved(None, path) => {
2018-07-11 14:41:03 +00:00
// Turn trait object paths into `TyKind::TraitObject` instead.
match path.res {
Res::Def(DefKind::Trait, _) | Res::Def(DefKind::TraitAlias, _) => {
let principal = hir::PolyTraitRef {
bound_generic_params: hir::HirVec::new(),
trait_ref: hir::TraitRef {
path: path.and_then(|path| path),
2019-04-26 12:23:30 +00:00
hir_ref_id: hir_id,
},
span,
};
// The original ID is taken by the `PolyTraitRef`,
// so the `Ty` itself needs a different one.
2019-04-26 12:23:30 +00:00
hir_id = self.next_id();
hir::TyKind::TraitObject(hir_vec![principal], self.elided_dyn_bound(span))
}
_ => hir::TyKind::Path(hir::QPath::Resolved(None, path)),
}
}
2018-07-11 14:41:03 +00:00
_ => hir::TyKind::Path(qpath),
};
hir::Ty {
2019-04-26 12:23:30 +00:00
hir_id,
2018-03-21 08:24:27 +00:00
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 or async fn 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 {
2019-04-26 12:23:30 +00:00
hir_id: self.next_id(),
span,
name: hir::LifetimeName::Param(fresh_name),
}
}
AnonymousLifetimeMode::ReportError => self.new_error_lifetime(None, span),
AnonymousLifetimeMode::PassThrough => self.new_implicit_lifetime(span),
AnonymousLifetimeMode::Replace(replacement) => {
self.new_replacement_lifetime(replacement, span)
}
}
}
/// Report an error on illegal use of `'_` or a `&T` with no explicit lifetime;
/// return a "error lifetime".
fn new_error_lifetime(&mut self, id: Option<NodeId>, span: Span) -> hir::Lifetime {
let (id, msg, label) = match id {
Some(id) => (id, "`'_` cannot be used here", "`'_` is a reserved lifetime name"),
None => (
2019-04-26 12:23:30 +00:00
self.sess.next_node_id(),
"`&` without an explicit lifetime name cannot be used here",
"explicit lifetime name needed here",
),
};
let mut err = struct_span_err!(
self.sess,
span,
E0637,
"{}",
msg,
);
err.span_label(span, label);
err.emit();
self.new_named_lifetime(id, span, hir::LifetimeName::Error)
}
/// 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]> {
(0..count)
.map(|_| self.elided_path_lifetime(span))
.collect()
}
fn elided_path_lifetime(&mut self, span: Span) -> hir::Lifetime {
match self.anonymous_lifetime_mode {
AnonymousLifetimeMode::CreateParameter => {
// We should have emitted E0726 when processing this path above
self.sess.delay_span_bug(
span,
"expected 'implicit elided lifetime not allowed' error",
);
let id = self.sess.next_node_id();
self.new_named_lifetime(id, span, hir::LifetimeName::Error)
}
// This is the normal case.
AnonymousLifetimeMode::PassThrough => self.new_implicit_lifetime(span),
AnonymousLifetimeMode::Replace(replacement) => {
self.new_replacement_lifetime(replacement, span)
}
AnonymousLifetimeMode::ReportError => self.new_error_lifetime(None, span),
}
}
/// 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 => {}
AnonymousLifetimeMode::ReportError => {
// ReportError applies to explicit use of `'_`.
}
// This is the normal case.
AnonymousLifetimeMode::PassThrough => {}
// We don't need to do any replacement here as this lifetime
// doesn't refer to an elided lifetime elsewhere in the function
// signature.
AnonymousLifetimeMode::Replace(_) => {}
}
self.new_implicit_lifetime(span)
}
fn new_replacement_lifetime(
&mut self,
replacement: LtReplacement,
span: Span,
) -> hir::Lifetime {
2019-04-26 12:23:30 +00:00
let hir_id = self.next_id();
self.replace_elided_lifetime(hir_id, span, replacement)
}
fn new_implicit_lifetime(&mut self, span: Span) -> hir::Lifetime {
hir::Lifetime {
2019-04-26 12:23:30 +00:00
hir_id: self.next_id(),
span,
2017-09-19 23:36:54 +00:00
name: hir::LifetimeName::Implicit,
}
}
2018-02-23 06:44:44 +00:00
fn maybe_lint_bare_trait(&self, span: Span, id: NodeId, is_global: bool) {
2018-04-13 22:07:33 +00:00
self.sess.buffer_lint_with_diagnostic(
2018-05-18 22:13:53 +00:00
builtin::BARE_TRAIT_OBJECTS,
2018-04-13 22:07:33 +00:00
id,
span,
"trait objects without an explicit `dyn` are deprecated",
builtin::BuiltinLintDiagnostics::BareTraitObject(span, is_global),
)
2018-02-23 06:44:44 +00: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];
2018-06-22 05:24:24 +00:00
let from_err = P(self.expr_std_path(unstable_span, path, None,
ThinVec::new()));
P(self.expr_call(e.span, from_err, hir_vec![e]))
}
}
2017-02-21 17:23:47 +00: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
}
2019-04-30 22:17:58 +00:00
/// Checks if the specified expression is a built-in range literal.
/// (See: `LoweringContext::lower_expr()`).
pub fn is_range_literal(sess: &Session, expr: &hir::Expr) -> bool {
use hir::{Path, QPath, ExprKind, TyKind};
2019-04-30 22:17:58 +00:00
// Returns whether the given path represents a (desugared) range,
// either in std or core, i.e. has either a `::std::ops::Range` or
// `::core::ops::Range` prefix.
fn is_range_path(path: &Path) -> bool {
let segs: Vec<_> = path.segments.iter().map(|seg| seg.ident.as_str().to_string()).collect();
let segs: Vec<_> = segs.iter().map(|seg| &**seg).collect();
2019-04-30 22:17:58 +00:00
// "{{root}}" is the equivalent of `::` prefix in `Path`.
if let ["{{root}}", std_core, "ops", range] = segs.as_slice() {
(*std_core == "std" || *std_core == "core") && range.starts_with("Range")
} else {
false
}
};
2019-04-30 22:17:58 +00:00
// Check whether a span corresponding to a range expression is a
// range literal, rather than an explicit struct or `new()` call.
2019-04-30 23:08:01 +00:00
fn is_lit(sess: &Session, span: &Span) -> bool {
let source_map = sess.source_map();
let end_point = source_map.end_point(*span);
if let Ok(end_string) = source_map.span_to_snippet(end_point) {
!(end_string.ends_with("}") || end_string.ends_with(")"))
} else {
false
}
};
match expr.node {
// All built-in range literals but `..=` and `..` desugar to `Struct`s.
ExprKind::Struct(ref qpath, _, _) => {
if let QPath::Resolved(None, ref path) = **qpath {
2019-04-30 23:08:01 +00:00
return is_range_path(&path) && is_lit(sess, &expr.span);
}
}
// `..` desugars to its struct path.
ExprKind::Path(QPath::Resolved(None, ref path)) => {
2019-04-30 23:08:01 +00:00
return is_range_path(&path) && is_lit(sess, &expr.span);
}
// `..=` desugars into `::std::ops::RangeInclusive::new(...)`.
ExprKind::Call(ref func, _) => {
if let ExprKind::Path(QPath::TypeRelative(ref ty, ref segment)) = func.node {
if let TyKind::Path(QPath::Resolved(None, ref path)) = ty.node {
2019-04-30 22:17:58 +00:00
let new_call = segment.ident.as_str() == "new";
2019-04-30 23:08:01 +00:00
return is_range_path(&path) && is_lit(sess, &expr.span) && new_call;
}
}
}
_ => {}
}
false
}