rust/src/librustc/hir/lowering.rs

3395 lines
132 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 14:53:55 +01: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 14:53:55 +01:00
//! being expanded. IDs are assigned to AST nodes just before lowering.
//!
2019-02-08 14:53:55 +01: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 14:53:55 +01:00
//! 'folding' an existing one), then you create a new ID using `next_id()`.
//!
2019-02-08 14:53:55 +01: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
2019-02-08 14:53:55 +01:00
//! 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 14:53:55 +01: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 00:04:06 -07:00
2019-08-10 13:50:48 +02:00
mod expr;
2019-08-10 20:13:12 +02:00
mod item;
2019-08-10 13:50:48 +02:00
2019-02-05 11:20:45 -06:00
use crate::dep_graph::DepGraph;
use crate::hir::{self, ParamName};
use crate::hir::HirVec;
use crate::hir::map::{DefKey, DefPathData, Definitions};
2019-05-08 22:07:12 +03:00
use crate::hir::def_id::{DefId, DefIndex, CRATE_DEF_INDEX};
use crate::hir::def::{Namespace, Res, DefKind, PartialRes, PerNS};
use crate::hir::{GenericArg, ConstArg};
use crate::hir::ptr::P;
2019-02-05 11:20:45 -06:00
use crate::lint::builtin::{self, PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES,
ELIDED_LIFETIMES_IN_PATHS};
2019-02-05 11:20:45 -06: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 11:24:02 +09: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 00:04:06 -07:00
2019-08-10 20:13:12 +02:00
use std::collections::BTreeMap;
2017-02-15 14:52:27 -08:00
use std::mem;
2018-08-30 11:42:16 +02:00
use smallvec::SmallVec;
use syntax::attr;
2018-02-23 17:48:54 +00:00
use syntax::ast;
use syntax::ptr::P as AstP;
2015-07-31 00:04:06 -07:00
use syntax::ast::*;
use syntax::errors;
use syntax::ext::base::SpecialDerives;
2019-07-16 01:04:05 +03:00
use syntax::ext::hygiene::ExpnId;
2017-12-15 12:27:20 -08:00
use syntax::print::pprust;
use syntax::source_map::{respan, ExpnData, ExpnKind, DesugaringKind, Spanned};
2019-05-11 17:41:37 +03:00
use syntax::symbol::{kw, sym, Symbol};
use syntax::tokenstream::{TokenStream, TokenTree};
use syntax::parse::token::{self, Token};
use syntax::visit::{self, Visitor};
use syntax_pos::{DUMMY_SP, Span};
2015-07-31 00:04:06 -07:00
const HIR_ID_COUNTER_LOCKED: u32 = 0xFFFFFFFF;
pub struct LoweringContext<'a> {
crate_root: Option<Symbol>,
2017-06-04 18:15:42 +02:00
/// Used to assign ids to HIR nodes that do not directly correspond to an AST node.
sess: &'a Session,
2017-06-04 18:15:42 +02:00
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 10:55:40 -05:00
bodies: BTreeMap<hir::BodyId, hir::Body>,
exported_macros: Vec<hir::MacroDef>,
non_exported_macro_attrs: Vec<ast::Attribute>,
trait_impls: BTreeMap<DefId, Vec<hir::HirId>>,
2018-06-06 22:13:52 +02:00
modules: BTreeMap<NodeId, hir::ModuleItems>,
generator_kind: Option<hir::GeneratorKind>,
2016-12-26 14:34:03 +01:00
/// Used to get the current `fn`'s def span to point to when using `await`
/// outside of an `async fn`.
current_item: Option<Span>,
catch_scopes: Vec<NodeId>,
2017-02-15 14:52:27 -08:00
loop_scopes: Vec<NodeId>,
is_in_loop_condition: bool,
is_in_trait_impl: bool,
is_in_dyn_type: bool,
2017-02-15 14:52:27 -08:00
/// What to do when we encounter either an "anonymous lifetime
/// reference". The term "anonymous" is meant to encompass both
/// `'_` lifetimes as well as fully elided cases where nothing is
/// written at all (e.g., `&T` or `std::cell::Ref<T>`).
anonymous_lifetime_mode: AnonymousLifetimeMode,
/// 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-16 22:59:45 -08: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.
2019-08-12 18:14:48 -04:00
///
/// We always store a `modern()` version of the param-name in this
/// vector.
in_scope_lifetimes: Vec<ParamName>,
2017-11-16 22:59:45 -08:00
2018-06-06 22:13:52 +02: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>,
allow_try_trait: Option<Lrc<[Symbol]>>,
allow_gen_future: Option<Lrc<[Symbol]>>,
}
pub trait Resolver {
/// 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 11:37:55 +05:30
/// Given suffix `["b", "c", "d"]`, creates an AST path for `[::crate_root]::b::c::d` and
/// resolves it based on `is_value`.
2018-03-21 04:24:27 -04:00
fn resolve_str_path(
&mut self,
span: Span,
crate_root: Option<Symbol>,
components: &[Symbol],
ns: Namespace,
) -> (ast::Path, Res<NodeId>);
fn has_derives(&self, node_id: NodeId, derives: SpecialDerives) -> bool;
2015-09-25 16:03:28 +12:00
}
/// Context of `impl Trait` in code, which determines whether it is allowed in an HIR subtree,
/// and if so, what meaning it has.
#[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 03:40:50 +01:00
/// Newly generated parameters should be inserted into the given `Vec`.
Universal(&'a mut Vec<hir::GenericParam>),
2019-08-01 00:41:54 +01:00
/// Treat `impl Trait` as shorthand for a new opaque type.
/// Example: `fn foo() -> impl Debug`, where `impl Debug` is conceptually
2019-08-01 00:41:54 +01:00
/// equivalent to a new opaque type like `type T = impl Debug; fn foo() -> T`.
2018-05-22 14:31:56 +02:00
///
2018-08-19 03:40:50 +01: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).
2019-08-01 00:41:54 +01:00
OpaqueTy(Option<DefId> /* fn def-ID */),
/// `impl Trait` is not accepted in this position.
Disallowed(ImplTraitPosition),
}
2019-03-21 18:40:00 +00:00
/// Position in which `impl Trait` is disallowed.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
enum ImplTraitPosition {
/// Disallowed in `let` / `const` / `static` bindings.
Binding,
/// All other posiitons.
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),
2019-08-01 00:41:54 +01:00
OpaqueTy(fn_def_id) => OpaqueTy(*fn_def_id),
Disallowed(pos) => Disallowed(*pos),
}
}
}
2018-03-21 04:24:27 -04:00
pub fn lower_crate(
sess: &Session,
cstore: &dyn CrateStore,
2018-03-21 04:24:27 -04:00
dep_graph: &DepGraph,
krate: &Crate,
resolver: &mut dyn Resolver,
2018-03-21 04:24:27 -04: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: sess.parse_sess.injected_crate_name.try_get().copied(),
sess,
cstore,
resolver,
items: BTreeMap::new(),
trait_items: BTreeMap::new(),
impl_items: BTreeMap::new(),
2017-02-21 10:55:40 -05:00
bodies: BTreeMap::new(),
trait_impls: BTreeMap::new(),
2018-06-06 22:13:52 +02:00
modules: BTreeMap::new(),
exported_macros: Vec::new(),
non_exported_macro_attrs: Vec::new(),
catch_scopes: Vec::new(),
2017-02-15 14:52:27 -08:00
loop_scopes: Vec::new(),
is_in_loop_condition: false,
is_in_trait_impl: false,
is_in_dyn_type: false,
anonymous_lifetime_mode: AnonymousLifetimeMode::PassThrough,
type_def_lifetime_params: Default::default(),
2018-06-06 22:13:52 +02: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(),
generator_kind: None,
current_item: None,
2017-11-16 22:59:45 -08:00
lifetimes_to_define: Vec::new(),
is_collecting_in_band_lifetimes: false,
in_scope_lifetimes: Vec::new(),
allow_try_trait: Some([sym::try_trait][..].into()),
allow_gen_future: Some([sym::gen_future][..].into()),
2016-05-10 05:29:13 +00:00
}.lower_crate(krate)
}
2015-09-28 15:00:15 +13:00
#[derive(Copy, Clone, PartialEq)]
enum ParamMode {
/// Any path in a type context.
Explicit,
/// Path in a type definition, where the anonymous lifetime `'_` is not allowed.
ExplicitNamed,
/// The `module::Type` in `module::Type::method` in an expression.
2018-03-21 04:24:27 -04:00
Optional,
}
enum ParenthesizedGenericArgs {
Ok,
Warn,
Err,
}
/// What to do when we encounter an **anonymous** lifetime
2019-02-08 14:53:55 +01: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 14:53:55 +01: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.
2019-08-08 03:49:45 -04:00
#[derive(Copy, Clone, Debug)]
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,
}
struct ImplTraitTypeIdVisitor<'a> { ids: &'a mut SmallVec<[NodeId; 1]> }
2018-08-19 03:40:50 +01: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 03:40:50 +01: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<'tcx, 'interner> {
2019-06-14 00:48:52 +03:00
lctx: &'tcx mut LoweringContext<'interner>,
2019-04-03 09:07:45 +02: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,
2019-07-16 01:04:05 +03:00
ExpnId::root(),
tree.prefix.span,
);
2019-03-25 19:43:04 +01:00
self.lctx.allocate_hir_id_counter(id);
}
}
UseTreeKind::Glob => (),
UseTreeKind::Nested(ref trees) => {
for &(ref use_tree, id) in trees {
2019-04-26 14:23:30 +02: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 09:07:45 +02: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
}
}
2019-06-14 00:48:52 +03:00
impl<'tcx, 'interner> Visitor<'tcx> for MiscCollector<'tcx, 'interner> {
fn visit_pat(&mut self, p: &'tcx Pat) {
2019-04-03 09:07:45 +02:00
match p.node {
// Doesn't generate a HIR node
PatKind::Paren(..) | PatKind::Rest => {},
2019-04-03 09:07:45 +02:00
_ => {
if let Some(owner) = self.hir_id_owner {
self.lctx.lower_node_id_with_owner(p.id, owner);
}
}
};
visit::walk_pat(self, p)
}
2019-06-14 00:48:52 +03:00
fn visit_item(&mut self, item: &'tcx Item) {
2019-04-26 14:23:30 +02:00
let hir_id = self.lctx.allocate_hir_id_counter(item.id);
match item.node {
2018-03-21 04:24:27 -04:00
ItemKind::Struct(_, ref generics)
| ItemKind::Union(_, ref generics)
| ItemKind::Enum(_, ref generics)
| ItemKind::TyAlias(_, ref generics)
2019-08-01 00:41:54 +01:00
| ItemKind::OpaqueTy(_, ref generics)
2018-03-21 04:24:27 -04:00
| ItemKind::Trait(_, _, ref generics, ..) => {
let def_id = self.lctx.resolver.definitions().local_def_id(item.id);
2018-03-21 04:24:27 -04:00
let count = generics
.params
.iter()
.filter(|param| match param.kind {
2018-05-27 20:07:09 +01: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 09:07:45 +02:00
self.with_hir_id_owner(Some(item.id), |this| {
visit::walk_item(this, item);
});
}
2019-06-14 00:48:52 +03:00
fn visit_trait_item(&mut self, item: &'tcx TraitItem) {
2019-03-25 19:43:04 +01:00
self.lctx.allocate_hir_id_counter(item.id);
2019-04-03 09:07:45 +02: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);
})
}
}
2019-06-14 00:48:52 +03:00
fn visit_impl_item(&mut self, item: &'tcx ImplItem) {
2019-03-25 19:43:04 +01:00
self.lctx.allocate_hir_id_counter(item.id);
2019-04-03 09:07:45 +02:00
self.with_hir_id_owner(Some(item.id), |this| {
visit::walk_impl_item(this, item);
});
}
2019-06-14 00:48:52 +03:00
fn visit_foreign_item(&mut self, i: &'tcx ForeignItem) {
2019-04-03 09:07:45 +02:00
// Ignore patterns in foreign items
self.with_hir_id_owner(None, |this| {
visit::walk_foreign_item(this, i)
});
}
2019-06-14 00:48:52 +03:00
fn visit_ty(&mut self, t: &'tcx Ty) {
2019-04-03 09:07:45 +02:00
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),
}
}
}
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 09:07:45 +02:00
visit::walk_crate(&mut MiscCollector { lctx: &mut self, hir_id_owner: None }, c);
2019-08-10 20:13:12 +02:00
visit::walk_crate(&mut item::ItemLowerer { lctx: &mut self }, c);
let module = self.lower_mod(&c.module);
let attrs = self.lower_attrs(&c.attrs);
2017-02-21 12:23:47 -05:00
let body_ids = body_ids(&self.bodies);
self.resolver
.definitions()
.init_node_id_to_hir_id_mapping(self.node_id_to_hir_id);
hir::Crate {
module,
attrs,
span: c.span,
exported_macros: hir::HirVec::from(self.exported_macros),
non_exported_macro_attrs: hir::HirVec::from(self.non_exported_macro_attrs),
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 22:13:52 +02: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 22:13:52 +02:00
self.items.insert(id, item);
self.modules.get_mut(&self.current_module).unwrap().items.insert(id);
}
2019-04-26 14:23:30 +02:00
fn allocate_hir_id_counter(&mut self, owner: NodeId) -> hir::HirId {
// Set up the counter if needed.
2019-03-25 19:43:04 +01:00
self.item_local_id_counters.entry(owner).or_insert(0);
// Always allocate the first `HirId` for the owner itself.
2019-03-25 19:43:04 +01:00
let lowered = self.lower_node_id_with_owner(owner, owner);
2019-04-26 14:23:30 +02:00
debug_assert_eq!(lowered.local_id.as_u32(), 0);
2019-03-25 19:43:04 +01:00
lowered
}
2019-04-26 14:23:30 +02:00
fn lower_node_id_generic<F>(&mut self, ast_node_id: NodeId, alloc_hir_id: F) -> hir::HirId
2018-03-21 04:24:27 -04:00
where
F: FnOnce(&mut Self) -> hir::HirId,
{
if ast_node_id == DUMMY_NODE_ID {
2019-04-26 14:23:30 +02: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 14:23:30 +02:00
hir_id
} else {
2019-04-26 14:23:30 +02:00
existing_hir_id
}
}
2018-05-22 14:31:56 +02:00
fn with_hir_id_owner<F, T>(&mut self, owner: NodeId, f: F) -> T
2018-03-21 04:24:27 -04:00
where
2018-05-22 14:31:56 +02:00
F: FnOnce(&mut Self) -> T,
{
let counter = self.item_local_id_counters
2018-03-21 04:24:27 -04:00
.insert(owner, HIR_ID_COUNTER_LOCKED)
.unwrap_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 14:31:56 +02:00
let ret = f(self);
let (new_def_index, new_counter) = self.current_hir_id_owner.pop().unwrap();
debug_assert!(def_index == new_def_index);
debug_assert!(new_counter >= counter);
2018-03-21 04:24:27 -04:00
let prev = self.item_local_id_counters
.insert(owner, new_counter)
.unwrap();
debug_assert!(prev == HIR_ID_COUNTER_LOCKED);
2018-05-22 14:31:56 +02:00
ret
}
/// This method allocates a new `HirId` for the given `NodeId` and stores it in
/// the `LoweringContext`'s `NodeId => HirId` map.
/// Take care not to call this method if the resulting `HirId` is then not
/// actually used in the HIR, as that would trigger an assertion in the
/// `HirIdValidator` later on, which makes sure that all `NodeId`s got mapped
/// properly. Calling the method twice with the same `NodeId` is fine though.
2019-04-26 14:23:30 +02: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 04:24:27 -04:00
let &mut (def_index, ref mut local_id_counter) =
this.current_hir_id_owner.last_mut().unwrap();
let local_id = *local_id_counter;
*local_id_counter += 1;
hir::HirId {
owner: def_index,
local_id: hir::ItemLocalId::from_u32(local_id),
}
})
}
2019-04-26 14:23:30 +02: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 14:31:56 +02:00
let local_id_counter = this
.item_local_id_counters
.get_mut(&owner)
.expect("called `lower_node_id_with_owner` before `allocate_hir_id_counter`");
let local_id = *local_id_counter;
// We want to be sure not to modify the counter in the map while it
// is also on the stack. Otherwise we'll get lost updates when writing
// back from the stack to the map.
debug_assert!(local_id != HIR_ID_COUNTER_LOCKED);
*local_id_counter += 1;
2018-05-22 14:31:56 +02:00
let def_index = this
.resolver
.definitions()
.opt_def_index(owner)
.expect("you forgot to call `create_def_with_parent` or are lowering node-IDs \
2018-05-22 14:31:56 +02:00
that do not belong to the current owner");
hir::HirId {
owner: def_index,
local_id: hir::ItemLocalId::from_u32(local_id),
}
})
}
2019-04-26 14:23:30 +02: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 09:07:45 +02:00
self.lower_node_id_generic(id, |_| {
panic!("expected node_id to be lowered already for res {:#?}", res)
2019-04-26 14:23:30 +02:00
})
2019-04-03 09:07:45 +02: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 15:00:15 +13:00
}
2015-10-07 08:26:22 +13: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: DesugaringKind,
span: Span,
allow_internal_unstable: Option<Lrc<[Symbol]>>,
) -> Span {
span.fresh_expansion(ExpnData {
allow_internal_unstable,
..ExpnData::default(ExpnKind::Desugaring(reason), span, self.sess.edition())
})
}
fn with_anonymous_lifetime_mode<R>(
&mut self,
anonymous_lifetime_mode: AnonymousLifetimeMode,
op: impl FnOnce(&mut Self) -> R,
) -> R {
2019-08-08 03:49:45 -04:00
debug!(
"with_anonymous_lifetime_mode(anonymous_lifetime_mode={:?})",
anonymous_lifetime_mode,
);
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;
2019-08-08 03:49:45 -04:00
debug!("with_anonymous_lifetime_mode: restoring anonymous_lifetime_mode={:?}",
old_anonymous_lifetime_mode);
result
}
/// Creates a new `hir::GenericParam` for every new lifetime and
/// type parameter encountered while evaluating `f`. Definitions
/// are created with the parent provided. If no `parent_id` is
/// provided, no definitions will be returned.
///
/// Presuming that in-band lifetimes are enabled, then
/// `self.anonymous_lifetime_mode` will be updated to match the
/// argument while `f` is running (and restored afterwards).
fn collect_in_band_defs<T, F>(
&mut self,
parent_id: DefId,
anonymous_lifetime_mode: AnonymousLifetimeMode,
f: F,
) -> (Vec<hir::GenericParam>, T)
2018-03-21 04:24:27 -04:00
where
F: FnOnce(&mut LoweringContext<'_>) -> (Vec<hir::GenericParam>, T),
2017-11-16 22:59:45 -08:00
{
assert!(!self.is_collecting_in_band_lifetimes);
assert!(self.lifetimes_to_define.is_empty());
let old_anonymous_lifetime_mode = self.anonymous_lifetime_mode;
self.anonymous_lifetime_mode = anonymous_lifetime_mode;
self.is_collecting_in_band_lifetimes = true;
2017-11-16 22:59:45 -08:00
let (in_band_ty_params, res) = f(self);
2017-11-16 22:59:45 -08:00
self.is_collecting_in_band_lifetimes = false;
self.anonymous_lifetime_mode = old_anonymous_lifetime_mode;
2017-11-16 22:59:45 -08:00
let lifetimes_to_define = self.lifetimes_to_define.split_off(0);
let params = lifetimes_to_define
.into_iter()
.map(|(span, hir_name)| self.lifetime_to_generic_param(
span, hir_name, parent_id.index,
))
2018-05-26 00:27:54 +01:00
.chain(in_band_ty_params.into_iter())
.collect();
(params, res)
2017-11-16 22:59:45 -08:00
}
/// 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 14:23:30 +02: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(_) => (
2019-05-11 17:41:37 +03:00
kw::UnderscoreLifetime.as_interned_str(),
hir::LifetimeParamKind::Elided,
),
ParamName::Error => (
2019-05-11 17:41:37 +03:00
kw::UnderscoreLifetime.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),
2019-07-16 01:04:05 +03:00
ExpnId::root(),
span,
);
hir::GenericParam {
2019-04-26 14:23:30 +02: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 23:25:33 +03: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;
}
if self.in_scope_lifetimes.contains(&ParamName::Plain(ident.modern())) {
return;
}
2018-06-28 00:12:17 +03:00
let hir_name = ParamName::Plain(ident);
2018-06-09 23:25:33 +03:00
if self.lifetimes_to_define.iter()
2018-06-28 00:12:17 +03:00
.any(|(_, lt_name)| lt_name.modern() == hir_name.modern()) {
return;
}
2018-06-09 23:25:33 +03: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 19:16:21 +01:00
// Evaluates `f` with the lifetimes in `params` in-scope.
2017-11-16 22:59:45 -08:00
// This is used to track which lifetimes have already been defined, and
// which are new in-band lifetimes that need to have a definition created
// for them.
fn with_in_scope_lifetime_defs<T, F>(&mut self, params: &[GenericParam], f: F) -> T
2018-03-21 04:24:27 -04:00
where
F: FnOnce(&mut LoweringContext<'_>) -> T,
2017-11-16 22:59:45 -08:00
{
let old_len = self.in_scope_lifetimes.len();
let lt_def_names = params.iter().filter_map(|param| match param.kind {
GenericParamKind::Lifetime { .. } => Some(ParamName::Plain(param.ident.modern())),
_ => None,
});
2017-11-16 22:59:45 -08:00
self.in_scope_lifetimes.extend(lt_def_names);
let res = f(self);
self.in_scope_lifetimes.truncate(old_len);
res
}
/// Appends in-band lifetime defs and argument-position `impl
/// Trait` defs to the existing set of generics.
///
/// Presuming that in-band lifetimes are enabled, then
/// `self.anonymous_lifetime_mode` will be updated to match the
/// argument while `f` is running (and restored afterwards).
2017-12-15 12:27:20 -08:00
fn add_in_band_defs<F, T>(
2017-11-16 22:59:45 -08:00
&mut self,
generics: &Generics,
parent_id: DefId,
anonymous_lifetime_mode: AnonymousLifetimeMode,
2018-03-21 04:24:27 -04:00
f: F,
2017-11-16 22:59:45 -08:00
) -> (hir::Generics, T)
2018-03-21 04:24:27 -04:00
where
F: FnOnce(&mut LoweringContext<'_>, &mut Vec<hir::GenericParam>) -> T,
2017-11-16 22:59:45 -08:00
{
2018-03-21 04:24:27 -04:00
let (in_band_defs, (mut lowered_generics, res)) = self.with_in_scope_lifetime_defs(
&generics.params,
2018-03-21 04:24:27 -04: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 04:24:27 -04:00
})
},
);
2017-12-15 12:27:20 -08:00
let mut lowered_params: Vec<_> = lowered_generics
2018-03-21 04:24:27 -04:00
.params
2019-06-12 11:43:15 +03:00
.into_iter()
2018-03-21 04:24:27 -04:00
.chain(in_band_defs)
.collect();
2017-11-16 22:59:45 -08:00
// FIXME(const_generics): the compiler doesn't always cope with
// unsorted generic parameters at the moment, so we make sure
// that they're ordered correctly here for now. (When we chain
// the `in_band_defs`, we might make the order unsorted.)
lowered_params.sort_by_key(|param| {
match param.kind {
hir::GenericParamKind::Lifetime { .. } => ParamKindOrd::Lifetime,
hir::GenericParamKind::Type { .. } => ParamKindOrd::Type,
hir::GenericParamKind::Const { .. } => ParamKindOrd::Const,
}
});
lowered_generics.params = lowered_params.into();
2017-11-16 22:59:45 -08:00
(lowered_generics, res)
}
fn with_dyn_type_scope<T, F>(&mut self, in_scope: bool, f: F) -> T
where
F: FnOnce(&mut LoweringContext<'_>) -> T,
{
let was_in_dyn_type = self.is_in_dyn_type;
self.is_in_dyn_type = in_scope;
let result = f(self);
self.is_in_dyn_type = was_in_dyn_type;
result
}
fn with_new_scopes<T, F>(&mut self, f: F) -> T
2018-03-21 04:24:27 -04:00
where
F: FnOnce(&mut LoweringContext<'_>) -> T,
2017-02-15 14:52:27 -08:00
{
let was_in_loop_condition = self.is_in_loop_condition;
self.is_in_loop_condition = false;
2019-06-30 11:30:01 -07:00
let catch_scopes = mem::take(&mut self.catch_scopes);
let loop_scopes = mem::take(&mut self.loop_scopes);
2018-08-19 03:40:50 +01: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 03:40:50 +01:00
ret
2017-02-15 14:52:27 -08: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_attrs_extendable(&mut self, attrs: &[Attribute]) -> Vec<Attribute> {
2018-03-21 04:24:27 -04:00
attrs
.iter()
.map(|a| self.lower_attr(a))
2018-11-05 15:30:04 +01: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 08:28:34 -07:00
}
fn lower_attrs(&mut self, attrs: &[Attribute]) -> hir::HirVec<Attribute> {
self.lower_attrs_extendable(attrs).into()
}
rustc: Forbid interpolated tokens in the HIR Right now the HIR contains raw `syntax::ast::Attribute` structure but nowadays these can contain arbitrary tokens. One variant of the `Token` enum is an "interpolated" token which basically means to shove all the tokens for a nonterminal in this position. A "nonterminal" in this case is roughly analagous to a macro argument: macro_rules! foo { ($a:expr) => { // $a is a nonterminal as an expression } } Currently nonterminals contain namely items and expressions, and this poses a problem for incremental compilation! With incremental we want a stable hash of all HIR items, but this means we may transitively need a stable hash *of the entire AST*, which is certainly not stable w/ node ids and whatnot. Hence today there's a "bug" where the "stable hash" of an AST is just the raw hash value of the AST, and this only arises with interpolated nonterminals. The downside of this approach, however, is that a bunch of errors get spewed out during compilation about how this isn't a great idea. This PR is focused at fixing these warnings, basically deleting them from the compiler. The implementation here is to alter attributes as they're lowered from the AST to HIR, expanding all nonterminals in-place as we see them. This code for expanding a nonterminal to a token stream already exists for the `proc_macro` crate, so we basically just reuse the same implementation there. After this PR it's considered a bug to have an `Interpolated` token and hence the stable hash implementation simply uses `bug!` in this location. Closes #40946
2017-09-15 08:28:34 -07:00
fn lower_attr(&mut self, attr: &Attribute) -> Attribute {
// 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 08:28:34 -07: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 04:24:27 -04:00
tokens
.into_trees()
.flat_map(|tree| self.lower_token_tree(tree).into_trees())
.collect()
rustc: Forbid interpolated tokens in the HIR Right now the HIR contains raw `syntax::ast::Attribute` structure but nowadays these can contain arbitrary tokens. One variant of the `Token` enum is an "interpolated" token which basically means to shove all the tokens for a nonterminal in this position. A "nonterminal" in this case is roughly analagous to a macro argument: macro_rules! foo { ($a:expr) => { // $a is a nonterminal as an expression } } Currently nonterminals contain namely items and expressions, and this poses a problem for incremental compilation! With incremental we want a stable hash of all HIR items, but this means we may transitively need a stable hash *of the entire AST*, which is certainly not stable w/ node ids and whatnot. Hence today there's a "bug" where the "stable hash" of an AST is just the raw hash value of the AST, and this only arises with interpolated nonterminals. The downside of this approach, however, is that a bunch of errors get spewed out during compilation about how this isn't a great idea. This PR is focused at fixing these warnings, basically deleting them from the compiler. The implementation here is to alter attributes as they're lowered from the AST to HIR, expanding all nonterminals in-place as we see them. This code for expanding a nonterminal to a token stream already exists for the `proc_macro` crate, so we basically just reuse the same implementation there. After this PR it's considered a bug to have an `Interpolated` token and hence the stable hash implementation simply uses `bug!` in this location. Closes #40946
2017-09-15 08:28:34 -07:00
}
fn lower_token_tree(&mut self, tree: TokenTree) -> TokenStream {
rustc: Forbid interpolated tokens in the HIR Right now the HIR contains raw `syntax::ast::Attribute` structure but nowadays these can contain arbitrary tokens. One variant of the `Token` enum is an "interpolated" token which basically means to shove all the tokens for a nonterminal in this position. A "nonterminal" in this case is roughly analagous to a macro argument: macro_rules! foo { ($a:expr) => { // $a is a nonterminal as an expression } } Currently nonterminals contain namely items and expressions, and this poses a problem for incremental compilation! With incremental we want a stable hash of all HIR items, but this means we may transitively need a stable hash *of the entire AST*, which is certainly not stable w/ node ids and whatnot. Hence today there's a "bug" where the "stable hash" of an AST is just the raw hash value of the AST, and this only arises with interpolated nonterminals. The downside of this approach, however, is that a bunch of errors get spewed out during compilation about how this isn't a great idea. This PR is focused at fixing these warnings, basically deleting them from the compiler. The implementation here is to alter attributes as they're lowered from the AST to HIR, expanding all nonterminals in-place as we see them. This code for expanding a nonterminal to a token stream already exists for the `proc_macro` crate, so we basically just reuse the same implementation there. After this PR it's considered a bug to have an `Interpolated` token and hence the stable hash implementation simply uses `bug!` in this location. Closes #40946
2017-09-15 08:28:34 -07:00
match tree {
TokenTree::Token(token) => self.lower_token(token),
TokenTree::Delimited(span, delim, tts) => TokenTree::Delimited(
2018-03-21 04:24:27 -04:00
span,
delim,
self.lower_token_stream(tts),
2018-03-21 04:24:27 -04:00
).into(),
rustc: Forbid interpolated tokens in the HIR Right now the HIR contains raw `syntax::ast::Attribute` structure but nowadays these can contain arbitrary tokens. One variant of the `Token` enum is an "interpolated" token which basically means to shove all the tokens for a nonterminal in this position. A "nonterminal" in this case is roughly analagous to a macro argument: macro_rules! foo { ($a:expr) => { // $a is a nonterminal as an expression } } Currently nonterminals contain namely items and expressions, and this poses a problem for incremental compilation! With incremental we want a stable hash of all HIR items, but this means we may transitively need a stable hash *of the entire AST*, which is certainly not stable w/ node ids and whatnot. Hence today there's a "bug" where the "stable hash" of an AST is just the raw hash value of the AST, and this only arises with interpolated nonterminals. The downside of this approach, however, is that a bunch of errors get spewed out during compilation about how this isn't a great idea. This PR is focused at fixing these warnings, basically deleting them from the compiler. The implementation here is to alter attributes as they're lowered from the AST to HIR, expanding all nonterminals in-place as we see them. This code for expanding a nonterminal to a token stream already exists for the `proc_macro` crate, so we basically just reuse the same implementation there. After this PR it's considered a bug to have an `Interpolated` token and hence the stable hash implementation simply uses `bug!` in this location. Closes #40946
2017-09-15 08:28:34 -07:00
}
}
fn lower_token(&mut self, token: Token) -> TokenStream {
match token.kind {
token::Interpolated(nt) => {
let tts = nt.to_tokenstream(&self.sess.parse_sess, token.span);
self.lower_token_stream(tts)
}
_ => TokenTree::Token(token).into(),
rustc: Forbid interpolated tokens in the HIR Right now the HIR contains raw `syntax::ast::Attribute` structure but nowadays these can contain arbitrary tokens. One variant of the `Token` enum is an "interpolated" token which basically means to shove all the tokens for a nonterminal in this position. A "nonterminal" in this case is roughly analagous to a macro argument: macro_rules! foo { ($a:expr) => { // $a is a nonterminal as an expression } } Currently nonterminals contain namely items and expressions, and this poses a problem for incremental compilation! With incremental we want a stable hash of all HIR items, but this means we may transitively need a stable hash *of the entire AST*, which is certainly not stable w/ node ids and whatnot. Hence today there's a "bug" where the "stable hash" of an AST is just the raw hash value of the AST, and this only arises with interpolated nonterminals. The downside of this approach, however, is that a bunch of errors get spewed out during compilation about how this isn't a great idea. This PR is focused at fixing these warnings, basically deleting them from the compiler. The implementation here is to alter attributes as they're lowered from the AST to HIR, expanding all nonterminals in-place as we see them. This code for expanding a nonterminal to a token stream already exists for the `proc_macro` crate, so we basically just reuse the same implementation there. After this PR it's considered a bug to have an `Interpolated` token and hence the stable hash implementation simply uses `bug!` in this location. Closes #40946
2017-09-15 08:28:34 -07:00
}
}
2015-07-31 00:04:06 -07:00
2019-05-08 15:56:39 -04:00
/// Given an associated type constraint like one of these:
///
/// ```
/// T: Iterator<Item: Debug>
/// ^^^^^^^^^^^
/// T: Iterator<Item = Debug>
/// ^^^^^^^^^^^^
/// ```
///
/// returns a `hir::TypeBinding` representing `Item`.
fn lower_assoc_ty_constraint(&mut self,
c: &AssocTyConstraint,
itctx: ImplTraitContext<'_>)
-> hir::TypeBinding {
debug!("lower_assoc_ty_constraint(constraint={:?}, itctx={:?})", c, itctx);
2019-05-08 15:57:06 -04:00
let kind = match c.kind {
AssocTyConstraintKind::Equality { ref ty } => hir::TypeBindingKind::Equality {
ty: self.lower_ty(ty, itctx)
},
AssocTyConstraintKind::Bound { ref bounds } => {
2019-05-10 03:46:39 +01:00
// Piggy-back on the `impl Trait` context to figure out the correct behavior.
2019-05-08 15:56:39 -04:00
let (desugar_to_impl_trait, itctx) = match itctx {
// We are in the return position:
//
2019-05-10 03:46:39 +01:00
// fn foo() -> impl Iterator<Item: Debug>
2019-05-08 15:56:39 -04:00
//
// so desugar to
//
2019-05-10 03:46:39 +01:00
// fn foo() -> impl Iterator<Item = impl Debug>
2019-08-01 00:41:54 +01:00
ImplTraitContext::OpaqueTy(_) => (true, itctx),
2019-05-08 15:56:39 -04:00
// We are in the argument position, but within a dyn type:
//
2019-05-10 03:46:39 +01:00
// fn foo(x: dyn Iterator<Item: Debug>)
2019-05-08 15:56:39 -04:00
//
// so desugar to
//
2019-05-10 03:46:39 +01:00
// fn foo(x: dyn Iterator<Item = impl Debug>)
ImplTraitContext::Universal(_) if self.is_in_dyn_type => (true, itctx),
2019-05-08 15:56:39 -04:00
2019-05-10 03:46:39 +01:00
// In `type Foo = dyn Iterator<Item: Debug>` we desugar to
// `type Foo = dyn Iterator<Item = impl Debug>` but we have to override the
// "impl trait context" to permit `impl Debug` in this position (it desugars
2019-08-01 00:41:54 +01:00
// then to an opaque type).
2019-05-08 15:56:39 -04:00
//
// FIXME: this is only needed until `impl Trait` is allowed in type aliases.
ImplTraitContext::Disallowed(_) if self.is_in_dyn_type =>
2019-08-01 00:41:54 +01:00
(true, ImplTraitContext::OpaqueTy(None)),
2019-05-08 15:56:39 -04:00
// We are in the argument position, but not within a dyn type:
//
2019-05-10 03:46:39 +01:00
// fn foo(x: impl Iterator<Item: Debug>)
2019-05-08 15:56:39 -04:00
//
2019-05-10 03:46:39 +01:00
// so we leave it as is and this gets expanded in astconv to a bound like
// `<T as Iterator>::Item: Debug` where `T` is the type parameter for the
2019-05-08 15:56:39 -04:00
// `impl Iterator`.
_ => (false, itctx),
};
2019-05-08 15:56:39 -04:00
if desugar_to_impl_trait {
2019-05-10 03:46:39 +01:00
// Desugar `AssocTy: Bounds` into `AssocTy = impl Bounds`. We do this by
2019-05-08 15:57:06 -04:00
// constructing the HIR for `impl bounds...` and then lowering that.
2019-05-04 16:09:28 +01:00
let impl_trait_node_id = self.sess.next_node_id();
let parent_def_index = self.current_hir_id_owner.last().unwrap().0;
self.resolver.definitions().create_def_with_parent(
parent_def_index,
2019-05-04 16:09:28 +01:00
impl_trait_node_id,
DefPathData::ImplTrait,
2019-07-16 01:04:05 +03:00
ExpnId::root(),
DUMMY_SP
);
self.with_dyn_type_scope(false, |this| {
2019-05-08 15:57:06 -04:00
let ty = this.lower_ty(
&Ty {
id: this.sess.next_node_id(),
2019-05-04 16:09:28 +01:00
node: TyKind::ImplTrait(impl_trait_node_id, bounds.clone()),
span: DUMMY_SP,
},
itctx,
2019-05-08 15:57:06 -04:00
);
hir::TypeBindingKind::Equality {
ty
}
})
} else {
2019-05-08 15:57:06 -04:00
// Desugar `AssocTy: Bounds` into a type binding where the
// later desugars into a trait predicate.
let bounds = self.lower_param_bounds(bounds, itctx);
2019-05-08 15:57:06 -04:00
hir::TypeBindingKind::Constraint {
bounds
}
}
}
};
hir::TypeBinding {
hir_id: self.lower_node_id(c.id),
ident: c.ident,
2019-05-08 15:57:06 -04:00
kind,
span: c.span,
}
2015-07-31 00:04:06 -07:00
}
fn lower_generic_arg(&mut self,
arg: &ast::GenericArg,
itctx: ImplTraitContext<'_>)
-> hir::GenericArg {
match arg {
2018-05-27 20:07:09 +01: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_path_ty(
&mut self,
t: &Ty,
qself: &Option<QSelf>,
path: &Path,
param_mode: ParamMode,
itctx: ImplTraitContext<'_>
) -> hir::Ty {
let id = self.lower_node_id(t.id);
let qpath = self.lower_qpath(t.id, qself, path, param_mode, itctx);
let ty = self.ty_path(id, t.span, qpath);
if let hir::TyKind::TraitObject(..) = ty.node {
self.maybe_lint_bare_trait(t.span, t.id, qself.is_none() && path.is_global());
}
ty
}
fn lower_ty_direct(&mut self, t: &Ty, mut itctx: ImplTraitContext<'_>) -> hir::Ty {
let kind = match t.node {
2018-07-11 22:41:03 +08: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 22:41:03 +08:00
hir::TyKind::Rptr(lifetime, self.lower_mt(mt, itctx))
}
2018-03-21 04:24:27 -04:00
TyKind::BareFn(ref f) => self.with_in_scope_lifetime_defs(
&f.generic_params,
2018-03-21 04:24:27 -04:00
|this| {
this.with_anonymous_lifetime_mode(
AnonymousLifetimeMode::PassThrough,
|this| {
2018-07-11 22:41:03 +08: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 04:24:27 -04:00
},
),
2018-07-11 22:41:03 +08:00
TyKind::Never => hir::TyKind::Never,
TyKind::Tup(ref tys) => {
2018-07-11 22:41:03 +08: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) => {
return self.lower_path_ty(t, qself, path, ParamMode::Explicit, itctx);
}
2019-04-03 09:07:45 +02:00
TyKind::ImplicitSelf => {
let res = self.expect_full_res(t.id);
let res = self.lower_res(res);
2019-04-03 09:07:45 +02:00
hir::TyKind::Path(hir::QPath::Resolved(
None,
P(hir::Path {
res,
2019-04-03 09:07:45 +02:00
segments: hir_vec![hir::PathSegment::from_ident(
Ident::with_dummy_span(kw::SelfUpper)
2019-04-03 09:07:45 +02:00
)],
span: t.span,
}),
))
},
TyKind::Array(ref ty, ref length) => {
2018-07-11 22:41:03 +08:00
hir::TyKind::Array(self.lower_ty(ty, itctx), self.lower_anon_const(length))
}
TyKind::Typeof(ref expr) => {
2018-07-11 22:41:03 +08:00
hir::TyKind::Typeof(self.lower_anon_const(expr))
}
2018-02-22 22:44:44 -08:00
TyKind::TraitObject(ref bounds, kind) => {
let mut lifetime_bound = None;
let (bounds, lifetime_bound) = self.with_dyn_type_scope(true, |this| {
let bounds = bounds
.iter()
.filter_map(|bound| match *bound {
GenericBound::Trait(ref ty, TraitBoundModifier::None) => {
Some(this.lower_poly_trait_ref(ty, itctx.reborrow()))
}
GenericBound::Trait(_, TraitBoundModifier::Maybe) => None,
GenericBound::Outlives(ref lifetime) => {
if lifetime_bound.is_none() {
lifetime_bound = Some(this.lower_lifetime(lifetime));
}
None
}
})
.collect();
let lifetime_bound =
lifetime_bound.unwrap_or_else(|| this.elided_dyn_bound(t.span));
(bounds, lifetime_bound)
});
2018-02-22 22:44:44 -08:00
if kind != TraitObjectSyntax::Dyn {
self.maybe_lint_bare_trait(t.span, t.id, false);
2018-02-22 22:44:44 -08:00
}
2018-07-11 22:41:03 +08:00
hir::TyKind::TraitObject(bounds, lifetime_bound)
}
TyKind::ImplTrait(def_node_id, ref bounds) => {
2017-12-15 12:27:20 -08:00
let span = t.span;
match itctx {
2019-08-01 00:41:54 +01:00
ImplTraitContext::OpaqueTy(fn_def_id) => {
self.lower_opaque_impl_trait(
span, fn_def_id, def_node_id,
|this| this.lower_param_bounds(bounds, itctx),
)
2018-03-21 04:24:27 -04: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 12:27:20 -08: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 14:23:30 +02:00
hir_id: self.lower_node_id(def_node_id),
2018-06-28 00:12:17 +03:00
name: ParamName::Plain(ident),
2017-12-15 12:27:20 -08:00
pure_wrt_drop: false,
2018-06-14 11:42:12 +01:00
attrs: hir_vec![],
2018-05-28 13:33:28 +01:00
bounds: hir_bounds,
2018-06-28 00:12:17 +03:00
span,
2018-05-26 00:27:54 +01:00
kind: hir::GenericParamKind::Type {
default: None,
synthetic: Some(hir::SyntheticTyParamKind::ImplTrait),
}
2017-12-15 12:27:20 -08:00
});
2018-07-11 22:41:03 +08:00
hir::TyKind::Path(hir::QPath::Resolved(
2018-03-21 04:24:27 -04:00
None,
P(hir::Path {
span,
res: Res::Def(DefKind::TyParam, DefId::local(def_index)),
2018-06-10 17:40:45 +03:00
segments: hir_vec![hir::PathSegment::from_ident(ident)],
2018-03-21 04:24:27 -04: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 04:24:27 -04:00
self.sess,
t.span,
E0562,
"`impl Trait` not allowed outside of {}",
allowed_in,
2018-03-21 04:24:27 -04: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 22:41:03 +08:00
hir::TyKind::Err
}
}
}
TyKind::Mac(_) => bug!("`TyMac` should have been expanded by now."),
TyKind::CVarArgs => {
// Create the implicit lifetime of the "spoofed" `VaListImpl`.
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 14:23:30 +02:00
hir_id: self.lower_node_id(t.id),
}
}
2015-07-31 00:04:06 -07:00
2019-08-01 00:41:54 +01:00
fn lower_opaque_impl_trait(
2018-06-06 15:50:59 -07:00
&mut self,
span: Span,
2018-08-19 03:40:50 +01:00
fn_def_id: Option<DefId>,
opaque_ty_node_id: NodeId,
lower_bounds: impl FnOnce(&mut LoweringContext<'_>) -> hir::GenericBounds,
2018-07-11 22:41:03 +08:00
) -> hir::TyKind {
2019-08-08 03:49:45 -04:00
debug!(
"lower_opaque_impl_trait(fn_def_id={:?}, opaque_ty_node_id={:?}, span={:?})",
fn_def_id,
opaque_ty_node_id,
span,
);
2018-06-06 15:50:59 -07: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
2018-06-06 15:50:59 -07:00
// frequently opened issues show.
let opaque_ty_span = self.mark_span_with_reason(
2019-08-01 00:41:54 +01:00
DesugaringKind::OpaqueTy,
2018-06-06 15:50:59 -07:00
span,
None,
2018-06-06 15:50:59 -07:00
);
let opaque_ty_def_index = self
2018-06-06 15:50:59 -07:00
.resolver
.definitions()
.opt_def_index(opaque_ty_node_id)
.unwrap();
self.allocate_hir_id_counter(opaque_ty_node_id);
2018-06-06 15:50:59 -07:00
let hir_bounds = self.with_hir_id_owner(opaque_ty_node_id, lower_bounds);
2018-06-06 15:50:59 -07:00
let (lifetimes, lifetime_defs) = self.lifetimes_from_impl_trait_bounds(
opaque_ty_node_id,
opaque_ty_def_index,
2018-06-06 15:50:59 -07:00
&hir_bounds,
);
2019-08-08 03:49:45 -04:00
debug!(
"lower_opaque_impl_trait: lifetimes={:#?}", lifetimes,
);
debug!(
"lower_opaque_impl_trait: lifetime_defs={:#?}", lifetime_defs,
);
self.with_hir_id_owner(opaque_ty_node_id, |lctx| {
let opaque_ty_item = hir::OpaqueTy {
2018-06-06 15:50:59 -07:00
generics: hir::Generics {
params: lifetime_defs,
where_clause: hir::WhereClause {
predicates: hir_vec![],
span,
2018-06-06 15:50:59 -07:00
},
span,
},
bounds: hir_bounds,
2018-08-19 03:40:50 +01:00
impl_trait_fn: fn_def_id,
2019-08-02 00:09:38 +01:00
origin: hir::OpaqueTyOrigin::FnReturn,
2018-06-06 15:50:59 -07:00
};
2019-08-08 03:49:45 -04:00
trace!("lower_opaque_impl_trait: {:#?}", opaque_ty_def_index);
let opaque_ty_id = lctx.generate_opaque_type(
opaque_ty_node_id,
opaque_ty_item,
span,
opaque_ty_span,
);
2018-06-06 15:50:59 -07:00
// `impl Trait` now just becomes `Foo<'a, 'b, ..>`.
hir::TyKind::Def(hir::ItemId { id: opaque_ty_id }, lifetimes)
2018-06-06 15:50:59 -07:00
})
}
2019-08-01 00:41:54 +01:00
/// Registers a new opaque type with the proper `NodeId`s and
/// returns the lowered node-ID for the opaque type.
fn generate_opaque_type(
&mut self,
opaque_ty_node_id: NodeId,
opaque_ty_item: hir::OpaqueTy,
span: Span,
opaque_ty_span: Span,
2019-04-26 14:23:30 +02:00
) -> hir::HirId {
let opaque_ty_item_kind = hir::ItemKind::OpaqueTy(opaque_ty_item);
let opaque_ty_id = self.lower_node_id(opaque_ty_node_id);
2019-08-01 00:41:54 +01:00
// Generate an `type Foo = impl Trait;` declaration.
trace!("registering opaque type with id {:#?}", opaque_ty_id);
let opaque_ty_item = hir::Item {
hir_id: opaque_ty_id,
ident: Ident::invalid(),
attrs: Default::default(),
node: opaque_ty_item_kind,
vis: respan(span.shrink_to_lo(), hir::VisibilityKind::Inherited),
span: opaque_ty_span,
};
// Insert the item into the global item list. This usually happens
2019-08-01 00:41:54 +01:00
// automatically for all AST items. But this opaque type item
// does not actually exist in the AST.
self.insert_item(opaque_ty_item);
opaque_ty_id
}
fn lifetimes_from_impl_trait_bounds(
&mut self,
opaque_ty_id: NodeId,
parent_index: DefIndex,
bounds: &hir::GenericBounds,
2018-06-29 10:58:17 +02:00
) -> (HirVec<hir::GenericArg>, HirVec<hir::GenericParam>) {
2019-08-08 03:49:45 -04:00
debug!(
"lifetimes_from_impl_trait_bounds(opaque_ty_id={:?}, \
parent_index={:?}, \
bounds={:#?})",
opaque_ty_id, parent_index, bounds,
);
// This visitor walks over `impl Trait` bounds and creates defs for all lifetimes that
// 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> {
context: &'r mut LoweringContext<'a>,
parent: DefIndex,
opaque_ty_id: NodeId,
2017-12-09 21:54:58 -08:00
collect_elided_lifetimes: bool,
currently_bound_lifetimes: Vec<hir::LifetimeName>,
already_defined_lifetimes: FxHashSet<hir::LifetimeName>,
2018-06-29 10:58:17 +02:00
output_lifetimes: Vec<hir::GenericArg>,
output_lifetime_params: Vec<hir::GenericParam>,
}
impl<'r, 'a, 'v> hir::intravisit::Visitor<'v> for ImplTraitLifetimeCollector<'r, 'a> {
2018-03-21 04:24:27 -04:00
fn nested_visit_map<'this>(
&'this mut self,
) -> hir::intravisit::NestedVisitorMap<'this, 'v> {
hir::intravisit::NestedVisitorMap::None
}
fn visit_generic_args(&mut self, span: Span, parameters: &'v hir::GenericArgs) {
2017-12-09 21:54:58 -08:00
// Don't collect elided lifetimes used inside of `Fn()` syntax.
if parameters.parenthesized {
let old_collect_elided_lifetimes = self.collect_elided_lifetimes;
self.collect_elided_lifetimes = false;
hir::intravisit::walk_generic_args(self, span, parameters);
2017-12-09 21:54:58 -08:00
self.collect_elided_lifetimes = old_collect_elided_lifetimes;
} else {
hir::intravisit::walk_generic_args(self, span, parameters);
2017-12-09 21:54:58 -08:00
}
}
fn visit_ty(&mut self, t: &'v hir::Ty) {
// Don't collect elided lifetimes used inside of `fn()` syntax.
2018-07-11 22:41:03 +08:00
if let hir::TyKind::BareFn(_) = t.node {
2017-12-09 21:54:58 -08: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-09 21:54:58 -08:00
hir::intravisit::walk_ty(self, t);
self.currently_bound_lifetimes.truncate(old_len);
2017-12-09 21:54:58 -08:00
self.collect_elided_lifetimes = old_collect_elided_lifetimes;
} else {
2018-06-27 11:24:16 +02:00
hir::intravisit::walk_ty(self, t)
2017-12-09 21:54:58 -08:00
}
}
2018-03-21 04:24:27 -04:00
fn visit_poly_trait_ref(
&mut self,
trait_ref: &'v hir::PolyTraitRef,
modifier: hir::TraitBoundModifier,
2018-03-21 04:24:27 -04:00
) {
// Record the "stack height" of `for<'a>` lifetime bindings
// to be able to later fully undo their introduction.
let old_len = self.currently_bound_lifetimes.len();
hir::intravisit::walk_poly_trait_ref(self, trait_ref, modifier);
self.currently_bound_lifetimes.truncate(old_len);
}
fn visit_generic_param(&mut self, param: &'v hir::GenericParam) {
// Record the introduction of 'a in `for<'a> ...`.
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 14:55:23 +01: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-09 21:54:58 -08:00
let name = match lifetime.name {
2018-03-21 04:24:27 -04:00
hir::LifetimeName::Implicit | hir::LifetimeName::Underscore => {
2017-12-09 21:54:58 -08:00
if self.collect_elided_lifetimes {
// Use `'_` for both implicit and underscore lifetimes in
// `type Foo<'_> = impl SomeTrait<'_>;`.
2017-12-09 21:54:58 -08:00
hir::LifetimeName::Underscore
} else {
2018-03-21 04:24:27 -04:00
return;
2017-12-09 21:54:58 -08:00
}
2018-03-21 04:24:27 -04:00
}
hir::LifetimeName::Param(_) => lifetime.name,
hir::LifetimeName::Error | hir::LifetimeName::Static => return,
2017-12-09 21:54:58 -08:00
};
2018-03-21 04:24:27 -04:00
if !self.currently_bound_lifetimes.contains(&name)
&& !self.already_defined_lifetimes.contains(&name) {
2017-12-09 21:54:58 -08:00
self.already_defined_lifetimes.insert(name);
2018-06-29 10:58:17 +02:00
self.output_lifetimes.push(hir::GenericArg::Lifetime(hir::Lifetime {
2019-04-26 14:23:30 +02:00
hir_id: self.context.next_id(),
2017-12-09 21:54:58 -08:00
span: lifetime.span,
name,
2018-06-29 10:58:17 +02:00
}));
2017-12-09 21:54:58 -08:00
2018-05-22 14:31:56 +02:00
let def_node_id = self.context.sess.next_node_id();
2019-04-26 14:23:30 +02:00
let hir_id =
self.context.lower_node_id_with_owner(def_node_id, self.opaque_ty_id);
2017-12-09 21:54:58 -08:00
self.context.resolver.definitions().create_def_with_parent(
self.parent,
def_node_id,
DefPathData::LifetimeNs(name.ident().as_interned_str()),
2019-07-16 01:04:05 +03:00
ExpnId::root(),
lifetime.span);
2018-05-26 00:27:54 +01:00
let (name, kind) = match name {
hir::LifetimeName::Underscore => (
hir::ParamName::Plain(Ident::with_dummy_span(kw::UnderscoreLifetime)),
hir::LifetimeParamKind::Elided,
),
hir::LifetimeName::Param(param_name) => (
param_name,
hir::LifetimeParamKind::Explicit,
),
_ => bug!("expected `LifetimeName::Param` or `ParamName::Plain`"),
};
2018-05-26 00:27:54 +01:00
self.output_lifetime_params.push(hir::GenericParam {
2019-02-02 15:40:08 +01:00
hir_id,
name,
2017-12-09 21:54:58 -08:00
span: lifetime.span,
2018-05-26 00:27:54 +01:00
pure_wrt_drop: false,
2018-06-14 11:42:12 +01:00
attrs: hir_vec![],
bounds: hir_vec![],
kind: hir::GenericParamKind::Lifetime { kind }
2018-05-26 00:27:54 +01:00
});
}
}
}
let mut lifetime_collector = ImplTraitLifetimeCollector {
context: self,
parent: parent_index,
opaque_ty_id,
2017-12-09 21:54:58 -08: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 04:24:27 -04:00
lifetime_collector.output_lifetime_params.into(),
)
}
2018-03-21 04:24:27 -04:00
fn lower_qpath(
&mut self,
id: NodeId,
qself: &Option<QSelf>,
p: &Path,
param_mode: ParamMode,
mut itctx: ImplTraitContext<'_>,
2018-03-21 04:24:27 -04: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 04:24:27 -04:00
segments: p.segments[..proj_start]
.iter()
.enumerate()
.map(|(i, segment)| {
let param_mode = match (qself_position, param_mode) {
(Some(j), ParamMode::Optional) if i < j => {
// This segment is part of the trait path in a
// qualified path - one of `a`, `b` or `Trait`
// in `<X as a::b::Trait>::T::U::method`.
ParamMode::Explicit
}
_ => param_mode,
};
2018-03-21 04:24:27 -04:00
// Figure out if this is a type/trait segment,
// which may need lifetime elision performed.
let parent_def_id = |this: &mut Self, def_id: DefId| DefId {
krate: def_id.krate,
2018-03-21 04:24:27 -04:00
index: this.def_key(def_id).parent.expect("missing parent"),
};
let type_def_id = match partial_res.base_res() {
Res::Def(DefKind::AssocTy, def_id) if i + 2 == proj_start => {
2018-03-21 04:24:27 -04:00
Some(parent_def_id(self, def_id))
}
Res::Def(DefKind::Variant, def_id) if i + 1 == proj_start => {
2018-03-21 04:24:27 -04: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 04:24:27 -04:00
{
Some(def_id)
}
_ => None,
};
let parenthesized_generic_args = match partial_res.base_res() {
2018-03-21 04:24:27 -04:00
// `a::b::Trait(Args)`
Res::Def(DefKind::Trait, _)
if i + 1 == proj_start => ParenthesizedGenericArgs::Ok,
2018-03-21 04:24:27 -04:00
// `a::b::Trait(Args)::TraitItem`
Res::Def(DefKind::Method, _)
| Res::Def(DefKind::AssocConst, _)
| Res::Def(DefKind::AssocTy, _)
2018-03-21 04:24:27 -04:00
if i + 2 == proj_start =>
{
ParenthesizedGenericArgs::Ok
}
// Avoid duplicated errors.
Res::Err => ParenthesizedGenericArgs::Ok,
2018-03-21 04:24:27 -04: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 04:24:27 -04:00
{
ParenthesizedGenericArgs::Err
}
// A warning for now, for compatibility reasons.
2018-03-21 04:24:27 -04:00
_ => ParenthesizedGenericArgs::Warn,
};
2018-03-21 04:24:27 -04:00
let num_lifetimes = type_def_id.map_or(0, |def_id| {
if let Some(&n) = self.type_def_lifetime_params.get(&def_id) {
return n;
}
assert!(!def_id.is_local());
2018-02-25 00:31:26 +00:00
let item_generics =
self.cstore.item_generics_cloned_untracked(def_id, self.sess);
let n = item_generics.own_counts().lifetimes;
2018-03-21 04:24:27 -04:00
self.type_def_lifetime_params.insert(def_id, n);
n
});
self.lower_path_segment(
p.span,
segment,
param_mode,
num_lifetimes,
parenthesized_generic_args,
itctx.reborrow(),
None,
2018-03-21 04:24:27 -04: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 18:29:59 +03: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 04:24:27 -04:00
let segment = P(self.lower_path_segment(
p.span,
segment,
param_mode,
0,
ParenthesizedGenericArgs::Warn,
itctx.reborrow(),
None,
2018-03-21 04:24:27 -04: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 18:29:59 +03: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 04:24:27 -04:00
span_bug!(
p.span,
"lower_qpath: no final extension segment in {}..{}",
proj_start,
p.segments.len()
)
2015-07-31 00:04:06 -07:00
}
2018-03-21 04:24:27 -04:00
fn lower_path_extra(
&mut self,
res: Res,
2018-03-21 04:24:27 -04:00
p: &Path,
param_mode: ParamMode,
explicit_owner: Option<NodeId>,
2018-03-21 04:24:27 -04:00
) -> hir::Path {
hir::Path {
res,
2018-03-21 04:24:27 -04:00
segments: p.segments
.iter()
.map(|segment| {
self.lower_path_segment(
p.span,
segment,
param_mode,
0,
ParenthesizedGenericArgs::Err,
ImplTraitContext::disallowed(),
explicit_owner,
2018-03-21 04:24:27 -04:00
)
})
.collect(),
span: p.span,
}
}
2018-03-21 04:24:27 -04:00
fn lower_path(&mut self, id: NodeId, p: &Path, param_mode: ParamMode) -> hir::Path {
let res = self.expect_full_res(id);
let res = self.lower_res(res);
self.lower_path_extra(res, p, param_mode, None)
}
2018-03-21 04:24:27 -04:00
fn lower_path_segment(
&mut self,
path_span: Span,
segment: &PathSegment,
param_mode: ParamMode,
expected_lifetimes: usize,
parenthesized_generic_args: ParenthesizedGenericArgs,
itctx: ImplTraitContext<'_>,
explicit_owner: Option<NodeId>,
2018-03-21 04:24:27 -04:00
) -> hir::PathSegment {
2019-06-07 10:18:03 +01:00
let (mut generic_args, infer_args) = 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 04:24:27 -04:00
ParenthesizedGenericArgs::Ok => self.lower_parenthesized_parameter_data(data),
ParenthesizedGenericArgs::Warn => {
2018-03-21 04:24:27 -04:00
self.sess.buffer_lint(
PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES,
CRATE_NODE_ID,
data.span,
msg.into(),
);
(hir::GenericArgs::none(), true)
}
ParenthesizedGenericArgs::Err => {
2019-01-19 19:25:28 -08: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-19 19:25:28 -08: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-19 19:25:28 -08:00
};
err.emit();
(
self.lower_angle_bracketed_parameter_data(
&data.as_angle_bracketed_args(),
param_mode,
itctx
).0,
false,
)
}
2018-03-21 04:24:27 -04:00
},
}
2016-12-10 06:45:58 +00:00
} else {
self.lower_angle_bracketed_parameter_data(&Default::default(), param_mode, itctx)
};
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_non_lt_args = generic_args.args.len() == expected_lifetimes;
let no_bindings = generic_args.bindings.is_empty();
let (incl_angl_brckt, insertion_sp, suggestion) = if no_non_lt_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 non-lifetime 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_sp,
suggestion,
);
err.emit();
}
AnonymousLifetimeMode::PassThrough |
AnonymousLifetimeMode::ReportError => {
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_sp,
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 13:35:54 -05:00
debug!(
"lower_path_segment: ident={:?} original-id={:?} new-id={:?}",
segment.ident, segment.id, id,
);
hir::PathSegment::new(
2018-06-10 17:40:45 +03:00
segment.ident,
2019-04-26 14:23:30 +02:00
Some(id),
Some(self.lower_res(res)),
generic_args,
2019-06-07 10:18:03 +01:00
infer_args,
)
2015-07-31 00:04:06 -07:00
}
2018-03-21 04:24:27 -04:00
fn lower_angle_bracketed_parameter_data(
&mut self,
2018-02-23 17:48:54 +00:00
data: &AngleBracketedArgs,
2018-03-21 04:24:27 -04:00
param_mode: ParamMode,
mut itctx: ImplTraitContext<'_>,
) -> (hir::GenericArgs, bool) {
let &AngleBracketedArgs { ref args, ref constraints, .. } = data;
let has_non_lt_args = args.iter().any(|arg| match arg {
ast::GenericArg::Lifetime(_) => false,
2018-05-27 20:07:09 +01:00
ast::GenericArg::Type(_) => true,
ast::GenericArg::Const(_) => true,
2018-05-26 23:54:48 +01:00
});
(
hir::GenericArgs {
args: args.iter().map(|a| self.lower_generic_arg(a, itctx.reborrow())).collect(),
bindings: constraints.iter()
.map(|b| self.lower_assoc_ty_constraint(b, itctx.reborrow()))
.collect(),
parenthesized: false,
},
!has_non_lt_args && param_mode == ParamMode::Optional
)
2015-07-31 00:04:06 -07:00
}
2018-03-21 04:24:27 -04:00
fn lower_parenthesized_parameter_data(
&mut self,
data: &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 14:23:30 +02: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 14:23:30 +02:00
hir_id: this.next_id(),
ident: Ident::with_dummy_span(FN_OUTPUT_NAME),
2019-05-08 15:57:06 -04:00
kind: hir::TypeBindingKind::Equality {
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 04:24:27 -04:00
)
2015-10-06 16:03:56 +13:00
}
2015-07-31 00:04:06 -07:00
fn lower_local(&mut self, l: &Local) -> (hir::Local, SmallVec<[NodeId; 1]>) {
let mut ids = SmallVec::<[NodeId; 1]>::new();
2018-08-19 03:40:50 +01: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 04:25:23 +01:00
let parent_def_id = DefId::local(self.current_hir_id_owner.last().unwrap().0);
(hir::Local {
2019-04-26 14:23:30 +02:00
hir_id: self.lower_node_id(l.id),
2018-03-21 04:24:27 -04:00
ty: l.ty
.as_ref()
2018-08-19 03:40:50 +01:00
.map(|t| self.lower_ty(t,
if self.sess.features_untracked().impl_trait_in_bindings {
2019-08-01 00:41:54 +01:00
ImplTraitContext::OpaqueTy(Some(parent_def_id))
2018-08-19 03:40:50 +01:00
} else {
ImplTraitContext::Disallowed(ImplTraitPosition::Binding)
2018-08-19 03:40:50 +01: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: hir::LocalSource::Normal,
}, ids)
2015-10-06 16:03:56 +13:00
}
2015-07-31 00:04:06 -07:00
fn lower_mutability(&mut self, m: Mutability) -> hir::Mutability {
match m {
Mutability::Mutable => hir::MutMutable,
Mutability::Immutable => hir::MutImmutable,
}
2015-07-31 00:04:06 -07:00
}
fn lower_fn_args_to_names(&mut self, decl: &FnDecl) -> hir::HirVec<Ident> {
2018-03-21 04:24:27 -04:00
decl.inputs
.iter()
.map(|arg| match arg.pat.node {
PatKind::Ident(_, ident, _) => ident,
2019-05-11 17:41:37 +03:00
_ => Ident::new(kw::Invalid, arg.pat.span),
2018-03-21 04:24:27 -04:00
})
.collect()
}
2018-06-06 15:50:59 -07: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
2018-06-06 15:50:59 -07:00
// given DefId, otherwise impl Trait is disallowed. Must be `Some` if
// `make_ret_async` is also `Some`.
// `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
2018-06-06 15:50:59 -07:00
// 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 04:24:27 -04:00
fn lower_fn_decl(
&mut self,
decl: &FnDecl,
mut in_band_ty_params: Option<(DefId, &mut Vec<hir::GenericParam>)>,
2018-03-21 04:24:27 -04:00
impl_trait_return_allow: bool,
make_ret_async: Option<NodeId>,
2018-03-21 04:24:27 -04: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
2019-08-01 00:41:54 +01:00
// they can be applied to the opaque `impl Trait` 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 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 15:50:59 -07:00
let output = if let Some(ret_id) = make_ret_async {
2018-06-06 15:50:59 -07: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,
)
2018-06-06 15:50:59 -07: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,
2019-08-01 00:41:54 +01:00
ImplTraitContext::OpaqueTy(Some(def_id))
))
}
_ => {
hir::Return(self.lower_ty(ty, ImplTraitContext::disallowed()))
2018-03-21 04:24:27 -04:00
}
},
FunctionRetTy::Default(span) => hir::DefaultReturn(span),
2018-06-06 15:50:59 -07: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 00:04:06 -07:00
// Transforms `-> T` for `async fn` into `-> OpaqueTy { .. }`
// combined with the following definition of `OpaqueTy`:
//
// type OpaqueTy<generics_from_parent_fn> = impl Future<Output = T>;
2018-06-06 15:50:59 -07: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)
// `opaque_ty_node_id`: `NodeId` of the opaque `impl Trait` type that should be created
// `elided_lt_replacement`: replacement for elided lifetimes in the return type
2018-06-06 15:50:59 -07:00
fn lower_async_fn_ret_ty(
&mut self,
output: &FunctionRetTy,
fn_def_id: DefId,
opaque_ty_node_id: NodeId,
2018-06-06 15:50:59 -07:00
) -> hir::FunctionRetTy {
2019-08-08 03:49:45 -04:00
debug!(
"lower_async_fn_ret_ty(\
output={:?}, \
fn_def_id={:?}, \
opaque_ty_node_id={:?})",
output, fn_def_id, opaque_ty_node_id,
);
let span = output.span();
2018-06-06 15:50:59 -07:00
let opaque_ty_span = self.mark_span_with_reason(
DesugaringKind::Async,
span,
None,
);
2018-06-06 15:50:59 -07:00
let opaque_ty_def_index = self
.resolver
.definitions()
.opt_def_index(opaque_ty_node_id)
.unwrap();
2018-06-06 15:50:59 -07:00
self.allocate_hir_id_counter(opaque_ty_node_id);
2018-06-06 15:50:59 -07:00
2019-08-12 19:21:13 -04:00
// When we create the opaque type for this async fn, it is going to have
// to capture all the lifetimes involved in the signature (including in the
// return type). This is done by introducing lifetime parameters for:
//
// - all the explicitly declared lifetimes from the impl and function itself;
// - all the elided lifetimes in the fn arguments;
// - all the elided lifetimes in the return type.
//
// So for example in this snippet:
//
// ```rust
// impl<'a> Foo<'a> {
// async fn bar<'b>(&self, x: &'b Vec<f64>, y: &str) -> &u32 {
// // ^ '0 ^ '1 ^ '2
// // elided lifetimes used below
// }
// }
// ```
//
// we would create an opaque type like:
//
// ```
// type Bar<'a, 'b, '0, '1, '2> = impl Future<Output = &'2 u32>;
// ```
//
// and we would then desugar `bar` to the equivalent of:
//
// ```rust
// impl<'a> Foo<'a> {
// fn bar<'b, '0, '1>(&'0 self, x: &'b Vec<f64>, y: &'1 str) -> Bar<'a, 'b, '0, '1, '_>
// }
// ```
//
// Note that the final parameter to `Bar` is `'_`, not `'2` --
// this is because the elided lifetimes from the return type
// should be figured out using the ordinary elision rules, and
// this desugaring achieves that.
//
// The variable `input_lifetimes_count` tracks the number of
// lifetime parameters to the opaque type *not counting* those
// lifetimes elided in the return type. This includes those
// that are explicitly declared (`in_scope_lifetimes`) and
// those elided lifetimes we found in the arguments (current
// content of `lifetimes_to_define`). Next, we will process
// the return type, which will cause `lifetimes_to_define` to
// grow.
let input_lifetimes_count = self.in_scope_lifetimes.len() + self.lifetimes_to_define.len();
2019-08-12 19:21:13 -04:00
let (opaque_ty_id, lifetime_params) = self.with_hir_id_owner(opaque_ty_node_id, |this| {
// We have to be careful to get elision right here. The
// idea is that we create a lifetime parameter for each
// lifetime in the return type. So, given a return type
// like `async fn foo(..) -> &[&u32]`, we lower to `impl
// Future<Output = &'1 [ &'2 u32 ]>`.
//
// Then, we will create `fn foo(..) -> Foo<'_, '_>`, and
// hence the elision takes place at the fn site.
let future_bound = this.with_anonymous_lifetime_mode(
AnonymousLifetimeMode::CreateParameter,
|this| this.lower_async_fn_output_type_to_future_bound(
output,
fn_def_id,
span,
),
);
2018-06-06 15:50:59 -07:00
2019-08-08 03:49:45 -04:00
debug!("lower_async_fn_ret_ty: future_bound={:#?}", future_bound);
// Calculate all the lifetimes that should be captured
2019-08-01 00:41:54 +01:00
// by the opaque 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(|name| (name.ident().span, name))
.chain(this.lifetimes_to_define.iter().cloned())
.collect();
2018-06-06 15:50:59 -07:00
debug!("lower_async_fn_ret_ty: in_scope_lifetimes={:#?}", this.in_scope_lifetimes);
debug!("lower_async_fn_ret_ty: lifetimes_to_define={:#?}", this.lifetimes_to_define);
debug!("lower_async_fn_ret_ty: lifetime_params={:#?}", lifetime_params);
let generic_params =
lifetime_params
.iter().cloned()
.map(|(span, hir_name)| {
this.lifetime_to_generic_param(span, hir_name, opaque_ty_def_index)
})
.collect();
2018-06-06 15:50:59 -07:00
let opaque_ty_item = hir::OpaqueTy {
generics: hir::Generics {
params: generic_params,
where_clause: hir::WhereClause {
predicates: hir_vec![],
span,
},
span,
},
bounds: hir_vec![future_bound],
impl_trait_fn: Some(fn_def_id),
2019-08-01 00:41:54 +01:00
origin: hir::OpaqueTyOrigin::AsyncFn,
2018-06-06 15:50:59 -07:00
};
trace!("exist ty from async fn def index: {:#?}", opaque_ty_def_index);
let opaque_ty_id = this.generate_opaque_type(
opaque_ty_node_id,
opaque_ty_item,
span,
opaque_ty_span,
);
2018-06-06 15:50:59 -07:00
(opaque_ty_id, lifetime_params)
});
2018-06-06 15:50:59 -07:00
2019-08-12 19:21:13 -04:00
// As documented above on the variable
// `input_lifetimes_count`, we need to create the lifetime
// arguments to our opaque type. Continuing with our example,
// we're creating the type arguments for the return type:
//
// ```
2019-08-12 19:21:13 -04:00
// Bar<'a, 'b, '0, '1, '_>
// ```
//
2019-08-12 19:21:13 -04:00
// For the "input" lifetime parameters, we wish to create
// references to the parameters themselves, including the
// "implicit" ones created from parameter types (`'a`, `'b`,
// '`0`, `'1`).
//
// For the "output" lifetime parameters, we just want to
// generate `'_`.
let mut generic_args: Vec<_> =
lifetime_params[..input_lifetimes_count]
.iter()
.map(|&(span, hir_name)| {
2019-08-12 19:21:13 -04:00
// Input lifetime like `'a` or `'1`:
GenericArg::Lifetime(hir::Lifetime {
hir_id: self.next_id(),
span,
name: hir::LifetimeName::Param(hir_name),
})
})
.collect();
generic_args.extend(
lifetime_params[input_lifetimes_count..]
.iter()
.map(|&(span, _)| {
2019-08-12 19:21:13 -04:00
// Output lifetime like `'_`.
GenericArg::Lifetime(hir::Lifetime {
hir_id: self.next_id(),
span,
name: hir::LifetimeName::Implicit,
})
})
);
2018-06-21 22:24:24 -07:00
// Create the `Foo<...>` refernece itself. Note that the `type
// Foo = impl Trait` is, internally, created as a child of the
// async fn, so the *type parameters* are inherited. It's
// only the lifetime parameters that we must supply.
let opaque_ty_ref = hir::TyKind::Def(hir::ItemId { id: opaque_ty_id }, generic_args.into());
2018-06-06 15:50:59 -07:00
hir::FunctionRetTy::Return(P(hir::Ty {
node: opaque_ty_ref,
span,
2019-04-26 14:23:30 +02:00
hir_id: self.next_id(),
}))
}
2018-06-06 15:50:59 -07:00
/// Transforms `-> 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) => {
2019-08-01 00:41:54 +01:00
self.lower_ty(ty, ImplTraitContext::OpaqueTy(Some(fn_def_id)))
2018-06-06 15:50:59 -07:00
}
FunctionRetTy::Default(ret_ty_span) => {
P(hir::Ty {
2019-04-26 14:23:30 +02:00
hir_id: self.next_id(),
node: hir::TyKind::Tup(hir_vec![]),
span: *ret_ty_span,
})
}
};
2018-06-06 15:50:59 -07:00
// "<Output = T>"
let future_params = P(hir::GenericArgs {
args: hir_vec![],
bindings: hir_vec![hir::TypeBinding {
ident: Ident::with_dummy_span(FN_OUTPUT_NAME),
2019-05-08 15:57:06 -04:00
kind: hir::TypeBindingKind::Equality {
ty: output_ty,
},
2019-04-26 14:23:30 +02:00
hir_id: self.next_id(),
span,
}],
parenthesized: false,
2018-06-06 15:50:59 -07:00
});
// ::std::future::Future<future_params>
let future_path =
P(self.std_path(span, &[sym::future, sym::Future], Some(future_params), false));
hir::GenericBound::Trait(
hir::PolyTraitRef {
trait_ref: hir::TraitRef {
path: future_path,
2019-04-26 14:23:30 +02:00
hir_ref_id: self.next_id(),
},
bound_generic_params: hir_vec![],
span,
},
hir::TraitBoundModifier::None,
)
2018-06-06 15:50:59 -07:00
}
2018-05-28 13:33:28 +01:00
fn lower_param_bound(
2018-03-21 04:24:27 -04: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 00:04:06 -07:00
fn lower_lifetime(&mut self, l: &Lifetime) -> hir::Lifetime {
2018-03-19 03:54:56 +03:00
let span = l.ident.span;
2018-06-28 00:12:17 +03:00
match l.ident {
2019-05-11 17:41:37 +03:00
ident if ident.name == kw::StaticLifetime =>
2018-06-09 23:25:33 +03:00
self.new_named_lifetime(l.id, span, hir::LifetimeName::Static),
2019-05-11 17:41:37 +03:00
ident if ident.name == kw::UnderscoreLifetime =>
2018-06-09 23:25:33 +03:00
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 23:25:33 +03:00
AnonymousLifetimeMode::PassThrough => {
self.new_named_lifetime(l.id, span, hir::LifetimeName::Underscore)
}
AnonymousLifetimeMode::ReportError => self.new_error_lifetime(Some(l.id), span),
2018-06-09 23:25:33 +03: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-16 22:59:45 -08:00
}
}
}
2017-11-16 22:59:45 -08:00
fn new_named_lifetime(
&mut self,
id: NodeId,
span: Span,
name: hir::LifetimeName,
) -> hir::Lifetime {
hir::Lifetime {
2019-04-26 14:23:30 +02:00
hir_id: self.lower_node_id(id),
span,
name: name,
2015-07-31 00:04:06 -07:00
}
}
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-26 00:27:54 +01:00
fn lower_generic_param(&mut self,
2018-05-27 20:07:09 +01:00
param: &GenericParam,
add_bounds: &NodeMap<Vec<GenericBound>>,
mut itctx: ImplTraitContext<'_>)
2018-05-26 00:27:54 +01: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-26 00:27:54 +01: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-26 00:27:54 +01:00
};
2017-11-16 22:59:45 -08:00
2018-05-26 00:27:54 +01:00
self.is_collecting_in_band_lifetimes = was_collecting_in_band;
2017-11-16 22:59:45 -08:00
(param_name, kind)
2018-05-26 00:27:54 +01:00
}
2018-05-28 13:33:28 +01:00
GenericParamKind::Type { ref default, .. } => {
2018-05-26 19:16:21 +01:00
let add_bounds = add_bounds.get(&param.id).map_or(&[][..], |x| &x);
2018-05-26 00:27:54 +01:00
if !add_bounds.is_empty() {
let params = self.lower_param_bounds(add_bounds, itctx.reborrow()).into_iter();
bounds = bounds.into_iter()
.chain(params)
.collect();
2018-05-26 00:27:54 +01:00
}
2017-11-16 22:59:45 -08:00
let kind = hir::GenericParamKind::Type {
default: default.as_ref().map(|x| {
2019-08-01 00:41:54 +01:00
self.lower_ty(x, ImplTraitContext::OpaqueTy(None))
}),
synthetic: param.attrs.iter()
.filter(|attr| attr.check_name(sym::rustc_synthetic))
.map(|_| hir::SyntheticTyParamKind::ImplTrait)
.next(),
};
2019-07-07 16:38:49 +01:00
(hir::ParamName::Plain(param.ident), kind)
2018-05-26 00:27:54 +01: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 14:23:30 +02:00
hir_id: self.lower_node_id(param.id),
name,
span: param.ident.span,
pure_wrt_drop: attr::contains_name(&param.attrs, sym::may_dangle),
attrs: self.lower_attrs(&param.attrs),
bounds,
kind,
2018-05-26 00:27:54 +01:00
}
}
2015-07-31 00:04:06 -07:00
fn lower_trait_ref(&mut self, p: &TraitRef, itctx: ImplTraitContext<'_>) -> hir::TraitRef {
let path = match self.lower_qpath(p.ref_id, &None, &p.path, ParamMode::Explicit, itctx) {
hir::QPath::Resolved(None, path) => path,
2018-03-21 04:24:27 -04:00
qpath => bug!("lower_trait_ref: unexpected QPath `{:?}`", qpath),
};
hir::TraitRef {
path,
2019-04-26 14:23:30 +02:00
hir_ref_id: self.lower_node_id(p.ref_id),
2015-07-31 00:04:06 -07:00
}
}
2018-03-21 04:24:27 -04:00
fn lower_poly_trait_ref(
&mut self,
p: &PolyTraitRef,
mut itctx: ImplTraitContext<'_>,
2018-03-21 04:24:27 -04:00
) -> hir::PolyTraitRef {
let bound_generic_params = self.lower_generic_params(
&p.bound_generic_params,
&NodeMap::default(),
itctx.reborrow(),
);
2019-06-12 11:43:15 +03:00
let trait_ref = self.with_in_scope_lifetime_defs(
&p.bound_generic_params,
|this| this.lower_trait_ref(&p.trait_ref, itctx),
);
2017-11-16 22:59:45 -08:00
hir::PolyTraitRef {
bound_generic_params,
2017-11-16 22:59:45 -08:00
trait_ref,
span: p.span,
2015-07-31 00:04:06 -07:00
}
}
fn lower_mt(&mut self, mt: &MutTy, itctx: ImplTraitContext<'_>) -> hir::MutTy {
hir::MutTy {
ty: self.lower_ty(&mt.ty, itctx),
mutbl: self.lower_mutability(mt.mutbl),
2016-04-18 10:30:55 +12:00
}
}
2015-07-31 00:04:06 -07:00
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_with_stmts(
&mut self,
b: &Block,
targeted_by_break: bool,
mut stmts: Vec<hir::Stmt>,
) -> P<hir::Block> {
2016-06-23 09:51:18 +00:00
let mut expr = None;
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 14:23:30 +02: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,
})
}
fn lower_block(&mut self, b: &Block, targeted_by_break: bool) -> P<hir::Block> {
self.lower_block_with_stmts(b, targeted_by_break, vec![])
}
fn lower_pat(&mut self, p: &Pat) -> P<hir::Pat> {
let node = match p.node {
PatKind::Wild => hir::PatKind::Wild,
2018-03-18 16:47:09 +03:00
PatKind::Ident(ref binding_mode, ident, ref sub) => {
let lower_sub = |this: &mut Self| sub.as_ref().map(|x| this.lower_pat(x));
self.lower_pat_ident(p, binding_mode, ident, lower_sub)
}
PatKind::Lit(ref e) => hir::PatKind::Lit(P(self.lower_expr(e))),
PatKind::TupleStruct(ref path, ref pats) => {
2018-03-21 04:24:27 -04:00
let qpath = self.lower_qpath(
p.id,
&None,
path,
ParamMode::Optional,
ImplTraitContext::disallowed(),
2018-03-21 04:24:27 -04:00
);
let (pats, ddpos) = self.lower_pat_tuple(pats, "tuple struct");
hir::PatKind::TupleStruct(qpath, pats, ddpos)
}
2018-10-19 15:40:07 +01:00
PatKind::Or(ref pats) => {
hir::PatKind::Or(pats.iter().map(|x| self.lower_pat(x)).collect())
}
2018-09-06 10:46:55 +08:00
PatKind::Path(ref qself, ref path) => {
let qpath = self.lower_qpath(
p.id,
qself,
path,
ParamMode::Optional,
ImplTraitContext::disallowed(),
2018-09-06 10:46:55 +08:00
);
hir::PatKind::Path(qpath)
}
PatKind::Struct(ref path, ref fields, etc) => {
2018-03-21 04:24:27 -04:00
let qpath = self.lower_qpath(
p.id,
&None,
path,
ParamMode::Optional,
ImplTraitContext::disallowed(),
2018-03-21 04:24:27 -04:00
);
let fs = fields
.iter()
.map(|f| hir::FieldPat {
hir_id: self.next_id(),
ident: f.ident,
pat: self.lower_pat(&f.pat),
is_shorthand: f.is_shorthand,
span: f.span,
2018-03-21 04:24:27 -04:00
})
.collect();
hir::PatKind::Struct(qpath, fs, etc)
}
PatKind::Tuple(ref pats) => {
let (pats, ddpos) = self.lower_pat_tuple(pats, "tuple");
hir::PatKind::Tuple(pats, 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 04:24:27 -04:00
P(self.lower_expr(e1)),
P(self.lower_expr(e2)),
self.lower_range_end(end),
),
PatKind::Slice(ref pats) => self.lower_pat_slice(pats),
2019-07-07 00:26:55 +02:00
PatKind::Rest => {
// If we reach here the `..` pattern is not semantically allowed.
self.ban_illegal_rest_pat(p.span)
}
PatKind::Paren(ref inner) => return self.lower_pat(inner),
PatKind::Mac(_) => panic!("Shouldn't exist here"),
};
self.pat_with_node_id_of(p, node)
}
2015-10-06 16:03:56 +13:00
fn lower_pat_tuple(
&mut self,
pats: &[AstP<Pat>],
ctx: &str,
) -> (HirVec<P<hir::Pat>>, Option<usize>) {
let mut elems = Vec::with_capacity(pats.len());
let mut rest = None;
let mut iter = pats.iter().enumerate();
while let Some((idx, pat)) = iter.next() {
// Interpret the first `..` pattern as a subtuple pattern.
if pat.is_rest() {
rest = Some((idx, pat.span));
break;
}
// It was not a subslice pattern so lower it normally.
elems.push(self.lower_pat(pat));
}
while let Some((_, pat)) = iter.next() {
// There was a previous subtuple pattern; make sure we don't allow more.
if pat.is_rest() {
self.ban_extra_rest_pat(pat.span, rest.unwrap().1, ctx);
} else {
elems.push(self.lower_pat(pat));
}
}
(elems.into(), rest.map(|(ddpos, _)| ddpos))
}
fn lower_pat_slice(&mut self, pats: &[AstP<Pat>]) -> hir::PatKind {
let mut before = Vec::new();
let mut after = Vec::new();
let mut slice = None;
let mut prev_rest_span = None;
let mut iter = pats.iter();
while let Some(pat) = iter.next() {
// Interpret the first `((ref mut?)? x @)? ..` pattern as a subslice pattern.
match pat.node {
PatKind::Rest => {
prev_rest_span = Some(pat.span);
slice = Some(self.pat_wild_with_node_id_of(pat));
break;
},
PatKind::Ident(ref bm, ident, Some(ref sub)) if sub.is_rest() => {
prev_rest_span = Some(sub.span);
let lower_sub = |this: &mut Self| Some(this.pat_wild_with_node_id_of(sub));
let node = self.lower_pat_ident(pat, bm, ident, lower_sub);
slice = Some(self.pat_with_node_id_of(pat, node));
break;
},
_ => {}
}
// It was not a subslice pattern so lower it normally.
before.push(self.lower_pat(pat));
}
while let Some(pat) = iter.next() {
// There was a previous subslice pattern; make sure we don't allow more.
let rest_span = match pat.node {
PatKind::Rest => Some(pat.span),
PatKind::Ident(.., Some(ref sub)) if sub.is_rest() => {
// The `HirValidator` is merciless; add a `_` pattern to avoid ICEs.
after.push(self.pat_wild_with_node_id_of(pat));
Some(sub.span)
},
_ => None,
};
if let Some(rest_span) = rest_span {
self.ban_extra_rest_pat(rest_span, prev_rest_span.unwrap(), "slice");
} else {
after.push(self.lower_pat(pat));
}
}
hir::PatKind::Slice(before.into(), slice, after.into())
}
fn lower_pat_ident(
&mut self,
p: &Pat,
binding_mode: &BindingMode,
ident: Ident,
lower_sub: impl FnOnce(&mut Self) -> Option<P<hir::Pat>>,
) -> hir::PatKind {
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,
_ => p.id,
};
hir::PatKind::Binding(
self.lower_binding_mode(binding_mode),
self.lower_node_id(canonical_id),
ident,
lower_sub(self),
)
}
Some(res) => hir::PatKind::Path(hir::QPath::Resolved(
None,
P(hir::Path {
span: ident.span,
res: self.lower_res(res),
segments: hir_vec![hir::PathSegment::from_ident(ident)],
}),
)),
}
}
fn pat_wild_with_node_id_of(&mut self, p: &Pat) -> P<hir::Pat> {
self.pat_with_node_id_of(p, hir::PatKind::Wild)
}
/// Construct a `Pat` with the `HirId` of `p.id` lowered.
fn pat_with_node_id_of(&mut self, p: &Pat, node: hir::PatKind) -> P<hir::Pat> {
P(hir::Pat {
2019-04-26 14:23:30 +02:00
hir_id: self.lower_node_id(p.id),
node,
span: p.span,
})
}
2015-10-06 16:03:56 +13:00
/// Emit a friendly error for extra `..` patterns in a tuple/tuple struct/slice pattern.
fn ban_extra_rest_pat(&self, sp: Span, prev_sp: Span, ctx: &str) {
self.diagnostic()
.struct_span_err(sp, &format!("`..` can only be used once per {} pattern", ctx))
.span_label(sp, &format!("can only be used once per {} pattern", ctx))
.span_label(prev_sp, "previously used here")
.emit();
}
2019-07-07 00:26:55 +02:00
/// Used to ban the `..` pattern in places it shouldn't be semantically.
fn ban_illegal_rest_pat(&self, sp: Span) -> hir::PatKind {
self.diagnostic()
.struct_span_err(sp, "`..` patterns are not allowed here")
.note("only allowed in tuple, tuple struct, and slice patterns")
.emit();
// We're not in a list context so `..` can be reasonably treated
// as `_` because it should always be valid and roughly matches the
// intent of `..` (notice that the rest of a single slot is that slot).
hir::PatKind::Wild
}
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 15:59:00 +02:00
self.with_new_scopes(|this| {
hir::AnonConst {
2019-04-26 14:23:30 +02:00
hir_id: this.lower_node_id(c.id),
body: this.lower_const_body(&c.value),
2018-07-20 15:59:00 +02:00
}
})
}
2018-08-30 11:42:16 +02:00
fn lower_stmt(&mut self, s: &Stmt) -> SmallVec<[hir::Stmt; 1]> {
2019-08-10 12:38:19 +02:00
let node = match s.node {
2018-08-19 03:40:50 +01:00
StmtKind::Local(ref l) => {
let (l, item_ids) = self.lower_local(l);
2018-08-30 11:42:16 +02:00
let mut ids: SmallVec<[hir::Stmt; 1]> = item_ids
2018-08-19 03:40:50 +01:00
.into_iter()
2019-02-02 15:40:08 +01:00
.map(|item_id| {
2019-04-26 14:23:30 +02:00
let item_id = hir::ItemId { id: self.lower_node_id(item_id) };
self.stmt(s.span, hir::StmtKind::Item(item_id))
2018-08-19 03:40:50 +01:00
})
.collect();
2019-02-02 15:40:08 +01:00
ids.push({
hir::Stmt {
2019-04-26 14:23:30 +02:00
hir_id: self.lower_node_id(s.id),
2019-02-02 15:40:08 +01:00
node: hir::StmtKind::Local(P(l)),
span: s.span,
}
2018-08-19 03:40:50 +01: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 04:24:27 -04:00
return self.lower_item_id(it)
.into_iter()
2019-02-02 15:40:08 +01:00
.map(|item_id| {
2019-04-26 14:23:30 +02:00
let hir_id = id.take()
2019-02-02 15:40:08 +01: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 15:40:08 +01:00
span: s.span,
}
2018-03-21 04:24:27 -04:00
})
.collect();
}
2019-08-10 12:38:19 +02:00
StmtKind::Expr(ref e) => hir::StmtKind::Expr(P(self.lower_expr(e))),
StmtKind::Semi(ref e) => hir::StmtKind::Semi(P(self.lower_expr(e))),
StmtKind::Mac(..) => panic!("Shouldn't exist here"),
2019-08-10 12:38:19 +02:00
};
smallvec![hir::Stmt {
hir_id: self.lower_node_id(s.id),
node,
span: s.span,
2018-08-13 22:15:16 +03:00
}]
2015-07-31 00:04:06 -07:00
}
fn lower_block_check_mode(&mut self, b: &BlockCheckMode) -> hir::BlockCheckMode {
match *b {
BlockCheckMode::Default => hir::DefaultBlock,
BlockCheckMode::Unsafe(u) => hir::UnsafeBlock(self.lower_unsafe_source(u)),
}
2015-07-31 00:04:06 -07:00
}
fn lower_binding_mode(&mut self, b: &BindingMode) -> hir::BindingAnnotation {
match *b {
2018-03-21 04:24:27 -04:00
BindingMode::ByValue(Mutability::Immutable) => hir::BindingAnnotation::Unannotated,
BindingMode::ByRef(Mutability::Immutable) => hir::BindingAnnotation::Ref,
BindingMode::ByValue(Mutability::Mutable) => hir::BindingAnnotation::Mutable,
BindingMode::ByRef(Mutability::Mutable) => hir::BindingAnnotation::RefMut,
}
2015-07-31 00:04:06 -07:00
}
fn lower_unsafe_source(&mut self, u: UnsafeSource) -> hir::UnsafeSource {
match u {
CompilerGenerated => hir::CompilerGenerated,
UserProvided => hir::UserProvided,
}
2015-07-31 00:04:06 -07:00
}
fn lower_trait_bound_modifier(&mut self, f: TraitBoundModifier) -> hir::TraitBoundModifier {
match f {
TraitBoundModifier::None => hir::TraitBoundModifier::None,
TraitBoundModifier::Maybe => hir::TraitBoundModifier::Maybe,
}
2015-07-31 00:04:06 -07:00
}
2015-09-28 15:00:15 +13:00
// Helper methods for building HIR.
2015-09-28 15:00:15 +13:00
fn stmt(&mut self, span: Span, node: hir::StmtKind) -> hir::Stmt {
hir::Stmt { span, node, hir_id: self.next_id() }
}
2019-08-10 12:38:19 +02:00
fn stmt_expr(&mut self, span: Span, expr: hir::Expr) -> hir::Stmt {
self.stmt(span, hir::StmtKind::Expr(P(expr)))
}
2018-03-21 04:24:27 -04:00
fn stmt_let_pat(
&mut self,
2019-07-26 19:52:37 -03:00
attrs: ThinVec<Attribute>,
span: Span,
init: Option<P<hir::Expr>>,
2018-03-21 04:24:27 -04:00
pat: P<hir::Pat>,
source: hir::LocalSource,
) -> hir::Stmt {
let local = hir::Local {
2019-07-26 19:52:37 -03:00
attrs,
2019-04-26 14:23:30 +02:00
hir_id: self.next_id(),
2019-07-26 19:52:37 -03:00
init,
pat,
source,
2019-07-26 19:52:37 -03:00
span,
ty: None,
};
self.stmt(span, hir::StmtKind::Local(P(local)))
}
2019-02-02 15:40:08 +01:00
fn block_expr(&mut self, expr: P<hir::Expr>) -> hir::Block {
self.block_all(expr.span, hir::HirVec::new(), Some(expr))
}
2015-09-28 15:00:15 +13:00
2018-03-21 04:24:27 -04:00
fn block_all(
&mut self,
span: Span,
stmts: hir::HirVec<hir::Stmt>,
expr: Option<P<hir::Expr>>,
) -> hir::Block {
hir::Block {
stmts,
expr,
2019-04-26 14:23:30 +02:00
hir_id: self.next_id(),
rules: hir::DefaultBlock,
span,
targeted_by_break: false,
}
}
2015-09-28 15:00:15 +13:00
/// Constructs a `true` or `false` literal pattern.
fn pat_bool(&mut self, span: Span, val: bool) -> P<hir::Pat> {
let expr = self.expr_bool(span, val);
self.pat(span, hir::PatKind::Lit(P(expr)))
}
fn pat_ok(&mut self, span: Span, pat: P<hir::Pat>) -> P<hir::Pat> {
self.pat_std_enum(span, &[sym::result, sym::Result, sym::Ok], hir_vec![pat])
}
2015-09-28 15:00:15 +13:00
fn pat_err(&mut self, span: Span, pat: P<hir::Pat>) -> P<hir::Pat> {
self.pat_std_enum(span, &[sym::result, sym::Result, sym::Err], hir_vec![pat])
}
fn pat_some(&mut self, span: Span, pat: P<hir::Pat>) -> P<hir::Pat> {
self.pat_std_enum(span, &[sym::option, sym::Option, sym::Some], hir_vec![pat])
}
fn pat_none(&mut self, span: Span) -> P<hir::Pat> {
self.pat_std_enum(span, &[sym::option, sym::Option, sym::None], hir_vec![])
}
2015-09-28 15:00:15 +13:00
2018-03-21 04:24:27 -04:00
fn pat_std_enum(
&mut self,
span: Span,
components: &[Symbol],
2018-03-21 04:24:27 -04:00
subpats: hir::HirVec<P<hir::Pat>>,
) -> P<hir::Pat> {
2018-06-21 22:24:24 -07: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 15:00:15 +13:00
2019-04-03 09:07:45 +02:00
fn pat_ident(&mut self, span: Span, ident: Ident) -> (P<hir::Pat>, hir::HirId) {
2018-06-10 17:40:45 +03:00
self.pat_ident_binding_mode(span, ident, hir::BindingAnnotation::Unannotated)
}
2015-09-28 15:00:15 +13:00
2018-03-21 04:24:27 -04:00
fn pat_ident_binding_mode(
&mut self,
span: Span,
2018-06-10 17:40:45 +03:00
ident: Ident,
2018-03-21 04:24:27 -04:00
bm: hir::BindingAnnotation,
2019-04-03 09:07:45 +02:00
) -> (P<hir::Pat>, hir::HirId) {
2019-04-26 14:23:30 +02:00
let hir_id = self.next_id();
2015-09-28 17:24:42 +13:00
(
P(hir::Pat {
hir_id,
2019-03-07 12:18:59 +01:00
node: hir::PatKind::Binding(bm, hir_id, ident.with_span_pos(span), None),
span,
}),
2019-04-03 09:07:45 +02:00
hir_id
)
}
2015-09-28 15:00:15 +13:00
fn pat_wild(&mut self, span: Span) -> P<hir::Pat> {
self.pat(span, hir::PatKind::Wild)
}
2015-09-28 15:00:15 +13:00
fn pat(&mut self, span: Span, pat: hir::PatKind) -> P<hir::Pat> {
P(hir::Pat {
2019-04-26 14:23:30 +02:00
hir_id: self.next_id(),
node: pat,
span,
})
}
2015-09-28 15:00:15 +13:00
/// Given a 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-21 22:24:24 -07:00
fn std_path(
&mut self,
span: Span,
components: &[Symbol],
2018-06-21 23:24:51 -07:00
params: Option<P<hir::GenericArgs>>,
is_value: bool,
2018-06-21 22:24:24 -07:00
) -> hir::Path {
let ns = if is_value { Namespace::ValueNS } else { Namespace::TypeNS };
let (path, res) = self.resolver.resolve_str_path(span, self.crate_root, components, ns);
2018-10-25 15:23:45 +13:00
let mut segments: Vec<_> = path.segments.iter().map(|segment| {
let res = self.expect_full_res(segment.id);
hir::PathSegment {
ident: segment.ident,
hir_id: Some(self.lower_node_id(segment.id)),
res: Some(self.lower_res(res)),
infer_args: true,
args: None,
}
}).collect();
segments.last_mut().unwrap().args = params;
hir::Path {
span,
res: res.map_id(|_| panic!("unexpected node_id")),
segments: segments.into(),
}
}
2019-04-26 14:23:30 +02: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 22:41:03 +08: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,
2019-04-26 14:23:30 +02: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 14:23:30 +02: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 22:41:03 +08:00
_ => hir::TyKind::Path(qpath),
};
hir::Ty {
2019-04-26 14:23:30 +02:00
hir_id,
2018-03-21 04:24:27 -04: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 14:23:30 +02: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),
}
}
/// 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 14:23:30 +02: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::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 => {}
}
self.new_implicit_lifetime(span)
}
fn new_implicit_lifetime(&mut self, span: Span) -> hir::Lifetime {
hir::Lifetime {
2019-04-26 14:23:30 +02:00
hir_id: self.next_id(),
span,
2017-09-19 16:36:54 -07:00
name: hir::LifetimeName::Implicit,
}
}
2018-02-22 22:44:44 -08:00
fn maybe_lint_bare_trait(&self, span: Span, id: NodeId, is_global: bool) {
// FIXME(davidtwco): This is a hack to detect macros which produce spans of the
// call site which do not have a macro backtrace. See #61963.
let is_macro_callsite = self.sess.source_map()
.span_to_snippet(span)
.map(|snippet| snippet.starts_with("#["))
.unwrap_or(true);
if !is_macro_callsite {
self.sess.buffer_lint_with_diagnostic(
builtin::BARE_TRAIT_OBJECTS,
id,
span,
"trait objects without an explicit `dyn` are deprecated",
builtin::BuiltinLintDiagnostics::BareTraitObject(span, is_global),
)
}
2018-02-22 22:44:44 -08:00
}
}
2017-02-21 12:23:47 -05:00
fn body_ids(bodies: &BTreeMap<hir::BodyId, hir::Body>) -> Vec<hir::BodyId> {
// Sorting by span ensures that we get things in order within a
// file, and also puts the files in a sensible order.
let mut body_ids: Vec<_> = bodies.keys().cloned().collect();
body_ids.sort_by_key(|b| bodies[b].value.span);
body_ids
}
2019-04-30 23:17:58 +01: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 23:17:58 +01: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 23:17:58 +01: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 23:17:58 +01:00
// Check whether a span corresponding to a range expression is a
// range literal, rather than an explicit struct or `new()` call.
2019-05-01 00:08:01 +01: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-05-01 00:08:01 +01:00
return is_range_path(&path) && is_lit(sess, &expr.span);
}
}
// `..` desugars to its struct path.
ExprKind::Path(QPath::Resolved(None, ref path)) => {
2019-05-01 00:08:01 +01: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 23:17:58 +01:00
let new_call = segment.ident.as_str() == "new";
2019-05-01 00:08:01 +01:00
return is_range_path(&path) && is_lit(sess, &expr.span) && new_call;
}
}
}
_ => {}
}
false
}