//! in the HIR, especially for multiple identifiers.
use dep_graph::DepGraph;
-use hir;
+use hir::{self, ParamName};
use hir::HirVec;
use hir::map::{DefKey, DefPathData, Definitions};
use hir::def_id::{DefId, DefIndex, DefIndexAddressSpace, CRATE_DEF_INDEX};
-use hir::def::{Def, PathResolution};
+use hir::def::{Def, PathResolution, PerNS};
+use hir::GenericArg;
use lint::builtin::{self, PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES};
use middle::cstore::CrateStore;
use rustc_data_structures::indexed_vec::IndexVec;
use std::iter;
use std::mem;
use syntax::attr;
+use syntax::ast;
use syntax::ast::*;
use syntax::errors;
use syntax::ext::hygiene::{Mark, SyntaxContext};
// When traversing a signature such as `fn foo(x: impl Trait)`,
// we record `impl Trait` as a new type parameter, then later
// add it on to `foo`s generics.
- in_band_ty_params: Vec<hir::TyParam>,
+ in_band_ty_params: Vec<hir::GenericParam>,
// 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`
// (i.e. it doesn't appear in the in_scope_lifetimes list), it is added
// to this list. The results of this list are then added to the list of
// lifetime definitions in the corresponding impl or function generics.
- lifetimes_to_define: Vec<(Span, hir::LifetimeName)>,
+ 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
/// Obtain the resolution for a node id
fn get_resolution(&mut self, id: NodeId) -> Option<PathResolution>;
+ /// Obtain the possible resolutions for the given `use` statement.
+ fn get_import(&mut self, id: NodeId) -> PerNS<Option<PathResolution>>;
+
/// We must keep the set of definitions up to date as we add nodes that weren't in the AST.
/// This should only return `None` during testing.
fn definitions(&mut self) -> &mut Definitions;
/// Treat `impl Trait` as shorthand for a new universal existential parameter.
/// Example: `fn foo() -> impl Debug`, where `impl Debug` is conceptually
/// equivalent to a fresh existential parameter like `abstract type T; fn foo() -> T`.
- Existential,
+ ///
+ /// We store a DefId here so we can look up necessary information later
+ Existential(DefId),
/// `impl Trait` is not accepted in this position.
Disallowed,
Optional,
}
+#[derive(Debug)]
struct LoweredNodeId {
node_id: NodeId,
hir_id: hir::HirId,
let count = generics
.params
.iter()
- .filter(|param| param.is_lifetime_param())
+ .filter(|param| match param.kind {
+ ast::GenericParamKind::Lifetime { .. } => true,
+ _ => false,
+ })
.count();
self.lctx.type_def_lifetime_params.insert(def_id, count);
}
});
if item_lowered {
- let item_lifetimes = match self.lctx.items.get(&item.id).unwrap().node {
+ let item_generics = match self.lctx.items.get(&item.id).unwrap().node {
hir::Item_::ItemImpl(_, _, _, ref generics, ..)
| hir::Item_::ItemTrait(_, _, ref generics, ..) => {
- generics.lifetimes().cloned().collect::<Vec<_>>()
+ generics.params.clone()
}
- _ => Vec::new(),
+ _ => HirVec::new(),
};
- self.lctx
- .with_parent_impl_lifetime_defs(&item_lifetimes, |this| {
- let this = &mut ItemLowerer { lctx: this };
- if let ItemKind::Impl(_, _, _, _, ref opt_trait_ref, _, _) = item.node {
- this.with_trait_impl_ref(opt_trait_ref, |this| {
- visit::walk_item(this, item)
- });
- } else {
- visit::walk_item(this, item);
- }
- });
+ self.lctx.with_parent_impl_lifetime_defs(&item_generics, |this| {
+ let this = &mut ItemLowerer { lctx: this };
+ if let ItemKind::Impl(_, _, _, _, ref opt_trait_ref, _, _) = item.node {
+ this.with_trait_impl_ref(opt_trait_ref, |this| {
+ visit::walk_item(this, item)
+ });
+ } else {
+ visit::walk_item(this, item);
+ }
+ });
}
}
}
}
- fn allocate_hir_id_counter<T: Debug>(&mut self, owner: NodeId, debug: &T) {
+ fn allocate_hir_id_counter<T: Debug>(&mut self, owner: NodeId, debug: &T) -> LoweredNodeId {
if self.item_local_id_counters.insert(owner, 0).is_some() {
bug!(
"Tried to allocate item_local_id_counter for {:?} twice",
);
}
// Always allocate the first HirId for the owner itself
- self.lower_node_id_with_owner(owner, owner);
+ self.lower_node_id_with_owner(owner, owner)
}
fn lower_node_id_generic<F>(&mut self, ast_node_id: NodeId, alloc_hir_id: F) -> LoweredNodeId
}
}
- fn with_hir_id_owner<F>(&mut self, owner: NodeId, f: F)
+ fn with_hir_id_owner<F, T>(&mut self, owner: NodeId, f: F) -> T
where
- F: FnOnce(&mut Self),
+ F: FnOnce(&mut Self) -> T,
{
let counter = self.item_local_id_counters
.insert(owner, HIR_ID_COUNTER_LOCKED)
- .unwrap();
+ .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));
- f(self);
+ let ret = f(self);
let (new_def_index, new_counter) = self.current_hir_id_owner.pop().unwrap();
debug_assert!(def_index == new_def_index);
.insert(owner, new_counter)
.unwrap();
debug_assert!(prev == HIR_ID_COUNTER_LOCKED);
+ ret
}
/// This method allocates a new HirId for the given NodeId and stores it in
fn lower_node_id_with_owner(&mut self, ast_node_id: NodeId, owner: NodeId) -> LoweredNodeId {
self.lower_node_id_generic(ast_node_id, |this| {
- let local_id_counter = this.item_local_id_counters.get_mut(&owner).unwrap();
+ 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
debug_assert!(local_id != HIR_ID_COUNTER_LOCKED);
*local_id_counter += 1;
- let def_index = this.resolver.definitions().opt_def_index(owner).unwrap();
+ let def_index = this
+ .resolver
+ .definitions()
+ .opt_def_index(owner)
+ .expect("You forgot to call `create_def_with_parent` or are lowering node ids \
+ that do not belong to the current owner");
hir::HirId {
owner: def_index,
})
}
+ fn expect_full_def_from_use(&mut self, id: NodeId) -> impl Iterator<Item=Def> {
+ self.resolver.get_import(id).present_items().map(|pr| {
+ if pr.unresolved_segments() != 0 {
+ bug!("path not fully resolved: {:?}", pr);
+ }
+ pr.base_def()
+ })
+ }
+
fn diagnostic(&self) -> &errors::Handler {
self.sess.diagnostic()
}
// that collisions are ok here and this shouldn't
// really show up for end-user.
let str_name = match hir_name {
- hir::LifetimeName::Name(n) => n.as_str(),
- hir::LifetimeName::Fresh(_) => keywords::UnderscoreLifetime.name().as_str(),
- hir::LifetimeName::Implicit
- | hir::LifetimeName::Underscore
- | hir::LifetimeName::Static => {
- span_bug!(span, "unexpected in-band lifetime name: {:?}", hir_name)
- }
+ ParamName::Plain(name) => name.as_str(),
+ ParamName::Fresh(_) => keywords::UnderscoreLifetime.name().as_str(),
};
// Add a definition for the in-band lifetime def
self.resolver.definitions().create_def_with_parent(
parent_id.index,
def_node_id,
- DefPathData::LifetimeDef(str_name.as_interned_str()),
+ DefPathData::LifetimeParam(str_name.as_interned_str()),
DefIndexAddressSpace::High,
Mark::root(),
span,
);
- hir::GenericParam::Lifetime(hir::LifetimeDef {
- lifetime: hir::Lifetime {
- id: def_node_id,
- span,
- name: hir_name,
- },
- bounds: Vec::new().into(),
+ hir::GenericParam {
+ id: def_node_id,
+ name: hir_name,
+ attrs: hir_vec![],
+ bounds: hir_vec![],
+ span,
pure_wrt_drop: false,
- in_band: true,
- })
+ kind: hir::GenericParamKind::Lifetime { in_band: true }
+ }
})
- .chain(
- in_band_ty_params
- .into_iter()
- .map(|tp| hir::GenericParam::Type(tp)),
- )
+ .chain(in_band_ty_params.into_iter())
.collect();
(params, res)
return;
}
- let hir_name = hir::LifetimeName::Name(name);
+ let hir_name = ParamName::Plain(name);
- if self.lifetimes_to_define
- .iter()
- .any(|(_, lt_name)| *lt_name == hir_name)
- {
+ if self.lifetimes_to_define.iter().any(|(_, lt_name)| *lt_name == hir_name) {
return;
}
/// When we have either an elided or `'_` lifetime in an impl
/// header, we convert it to
- fn collect_fresh_in_band_lifetime(&mut self, span: Span) -> hir::LifetimeName {
+ 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 = hir::LifetimeName::Fresh(index);
+ let hir_name = ParamName::Fresh(index);
self.lifetimes_to_define.push((span, hir_name));
hir_name
}
- // Evaluates `f` with the lifetimes in `lt_defs` in-scope.
+ // Evaluates `f` with the lifetimes in `params` in-scope.
// This is used to track which lifetimes have already been defined, and
// which are new in-band lifetimes that need to have a definition created
// for them.
- fn with_in_scope_lifetime_defs<'l, T, F>(
- &mut self,
- lt_defs: impl Iterator<Item = &'l LifetimeDef>,
- f: F,
- ) -> T
+ fn with_in_scope_lifetime_defs<T, F>(&mut self, params: &Vec<GenericParam>, f: F) -> T
where
F: FnOnce(&mut LoweringContext) -> T,
{
let old_len = self.in_scope_lifetimes.len();
- let lt_def_names = lt_defs.map(|lt_def| lt_def.lifetime.ident.name);
+ let lt_def_names = params.iter().filter_map(|param| match param.kind {
+ GenericParamKind::Lifetime { .. } => Some(param.ident.name),
+ _ => None,
+ });
self.in_scope_lifetimes.extend(lt_def_names);
let res = f(self);
res
}
- // Same as the method above, but accepts `hir::LifetimeDef`s
- // instead of `ast::LifetimeDef`s.
+ // Same as the method above, but accepts `hir::GenericParam`s
+ // instead of `ast::GenericParam`s.
// This should only be used with generics that have already had their
// in-band lifetimes added. In practice, this means that this function is
// only used when lowering a child item of a trait or impl.
- fn with_parent_impl_lifetime_defs<T, F>(&mut self, lt_defs: &[hir::LifetimeDef], f: F) -> T
- where
+ fn with_parent_impl_lifetime_defs<T, F>(&mut self,
+ params: &HirVec<hir::GenericParam>,
+ f: F
+ ) -> T where
F: FnOnce(&mut LoweringContext) -> T,
{
let old_len = self.in_scope_lifetimes.len();
- let lt_def_names = lt_defs.iter().map(|lt_def| lt_def.lifetime.name.name());
+ let lt_def_names = params.iter().filter_map(|param| match param.kind {
+ hir::GenericParamKind::Lifetime { .. } => Some(param.name.name()),
+ _ => None,
+ });
self.in_scope_lifetimes.extend(lt_def_names);
let res = f(self);
F: FnOnce(&mut LoweringContext) -> T,
{
let (in_band_defs, (mut lowered_generics, res)) = self.with_in_scope_lifetime_defs(
- generics.params.iter().filter_map(|p| match p {
- GenericParam::Lifetime(ld) => Some(ld),
- _ => None,
- }),
+ &generics.params,
|this| {
let itctx = ImplTraitContext::Universal(parent_id);
this.collect_in_band_defs(parent_id, anonymous_lifetime_mode, |this| {
result
}
+ fn make_async_expr(
+ &mut self,
+ capture_clause: CaptureBy,
+ closure_node_id: NodeId,
+ ret_ty: Option<&Ty>,
+ body: impl FnOnce(&mut LoweringContext) -> hir::Expr,
+ ) -> hir::Expr_ {
+ let prev_is_generator = mem::replace(&mut self.is_generator, true);
+ let body_expr = body(self);
+ let span = body_expr.span;
+ let output = match ret_ty {
+ Some(ty) => FunctionRetTy::Ty(P(ty.clone())),
+ None => FunctionRetTy::Default(span),
+ };
+ let decl = FnDecl {
+ inputs: vec![],
+ output,
+ variadic: false
+ };
+ let body_id = self.record_body(body_expr, Some(&decl));
+ self.is_generator = prev_is_generator;
+
+ let capture_clause = self.lower_capture_clause(capture_clause);
+ let closure_hir_id = self.lower_node_id(closure_node_id).hir_id;
+ let decl = self.lower_fn_decl(&decl, None, /* impl trait allowed */ false, false);
+ let generator = hir::Expr {
+ id: closure_node_id,
+ hir_id: closure_hir_id,
+ node: hir::ExprClosure(capture_clause, decl, body_id, span,
+ Some(hir::GeneratorMovability::Static)),
+ span,
+ attrs: ThinVec::new(),
+ };
+
+ let unstable_span = self.allow_internal_unstable(CompilerDesugaringKind::Async, span);
+ let gen_future = self.expr_std_path(
+ unstable_span, &["raw", "future_from_generator"], ThinVec::new());
+ hir::ExprCall(P(gen_future), hir_vec![generator])
+ }
+
fn lower_body<F>(&mut self, decl: Option<&FnDecl>, f: F) -> hir::BodyId
where
F: FnOnce(&mut LoweringContext) -> hir::Expr,
}
}
+ fn lower_generic_arg(&mut self,
+ arg: &ast::GenericArg,
+ itctx: ImplTraitContext)
+ -> hir::GenericArg {
+ match arg {
+ ast::GenericArg::Lifetime(lt) => GenericArg::Lifetime(self.lower_lifetime(<)),
+ ast::GenericArg::Type(ty) => GenericArg::Type(self.lower_ty(&ty, itctx)),
+ }
+ }
+
fn lower_ty(&mut self, t: &Ty, itctx: ImplTraitContext) -> P<hir::Ty> {
let kind = match t.node {
TyKind::Infer => hir::TyInfer,
hir::TyRptr(lifetime, self.lower_mt(mt, itctx))
}
TyKind::BareFn(ref f) => self.with_in_scope_lifetime_defs(
- f.generic_params.iter().filter_map(|p| match p {
- GenericParam::Lifetime(ld) => Some(ld),
- _ => None,
- }),
+ &f.generic_params,
|this| {
this.with_anonymous_lifetime_mode(
AnonymousLifetimeMode::PassThrough,
),
unsafety: this.lower_unsafety(f.unsafety),
abi: f.abi,
- decl: this.lower_fn_decl(&f.decl, None, false),
+ decl: this.lower_fn_decl(&f.decl, None, false, false),
arg_names: this.lower_fn_args_to_names(&f.decl),
}))
},
let bounds = bounds
.iter()
.filter_map(|bound| match *bound {
- TraitTyParamBound(ref ty, TraitBoundModifier::None) => {
+ GenericBound::Trait(ref ty, TraitBoundModifier::None) => {
Some(self.lower_poly_trait_ref(ty, itctx))
}
- TraitTyParamBound(_, TraitBoundModifier::Maybe) => None,
- RegionTyParamBound(ref lifetime) => {
+ GenericBound::Trait(_, TraitBoundModifier::Maybe) => None,
+ GenericBound::Outlives(ref lifetime) => {
if lifetime_bound.is_none() {
lifetime_bound = Some(self.lower_lifetime(lifetime));
}
TyKind::ImplTrait(ref bounds) => {
let span = t.span;
match itctx {
- ImplTraitContext::Existential => {
- let def_index = self.resolver.definitions().opt_def_index(t.id).unwrap();
- let hir_bounds = self.lower_bounds(bounds, itctx);
- let (lifetimes, lifetime_defs) =
- self.lifetimes_from_impl_trait_bounds(def_index, &hir_bounds);
-
- hir::TyImplTraitExistential(
- hir::ExistTy {
- generics: hir::Generics {
- params: lifetime_defs,
- where_clause: hir::WhereClause {
- id: self.next_id().node_id,
- predicates: Vec::new().into(),
- },
- span,
- },
- bounds: hir_bounds,
- },
- lifetimes,
- )
+ ImplTraitContext::Existential(fn_def_id) => {
+ // Set the name to `impl Bound1 + Bound2`
+ let exist_ty_name = Symbol::intern(&pprust::ty_to_string(t));
+ self.lower_existential_impl_trait(
+ span, fn_def_id, exist_ty_name, |this| this.lower_bounds(bounds, itctx))
}
ImplTraitContext::Universal(def_id) => {
let def_node_id = self.next_id().node_id;
let def_index = self.resolver.definitions().create_def_with_parent(
def_id.index,
def_node_id,
- DefPathData::ImplTrait,
+ DefPathData::UniversalImplTrait,
DefIndexAddressSpace::High,
Mark::root(),
span,
);
- let hir_bounds = self.lower_bounds(bounds, itctx);
+ let hir_bounds = self.lower_param_bounds(bounds, itctx);
// Set the name to `impl Bound1 + Bound2`
let name = Symbol::intern(&pprust::ty_to_string(t));
- self.in_band_ty_params.push(hir::TyParam {
- name,
+ self.in_band_ty_params.push(hir::GenericParam {
id: def_node_id,
- bounds: hir_bounds,
- default: None,
+ name: ParamName::Plain(name),
span,
pure_wrt_drop: false,
- synthetic: Some(hir::SyntheticTyParamKind::ImplTrait),
- attrs: P::new(),
+ attrs: hir_vec![],
+ bounds: hir_bounds,
+ kind: hir::GenericParamKind::Type {
+ default: None,
+ synthetic: Some(hir::SyntheticTyParamKind::ImplTrait),
+ }
});
hir::TyPath(hir::QPath::Resolved(
})
}
+ fn lower_existential_impl_trait(
+ &mut self,
+ span: Span,
+ fn_def_id: DefId,
+ exist_ty_name: Name,
+ lower_bounds: impl FnOnce(&mut LoweringContext) -> hir::TyParamBounds,
+ ) -> hir::Ty_ {
+ // We need to manually repeat the code of `next_id` because the lowering
+ // needs to happen while the owner_id is pointing to the item itself,
+ // because items are their own owners
+ let exist_ty_node_id = self.sess.next_node_id();
+
+ // Make sure we know that some funky desugaring has been going on here.
+ // This is a first: there is code in other places like for loop
+ // desugaring that explicitly states that we don't want to track that.
+ // Not tracking it makes lints in rustc and clippy very fragile as
+ // frequently opened issues show.
+ let exist_ty_span = self.allow_internal_unstable(
+ CompilerDesugaringKind::ExistentialReturnType,
+ span,
+ );
+
+ // Pull a new definition from the ether
+ let exist_ty_def_index = self
+ .resolver
+ .definitions()
+ .create_def_with_parent(
+ fn_def_id.index,
+ exist_ty_node_id,
+ DefPathData::ExistentialImplTrait,
+ DefIndexAddressSpace::High,
+ Mark::root(),
+ exist_ty_span,
+ );
+
+ self.allocate_hir_id_counter(exist_ty_node_id, &"existential impl trait");
+
+ let hir_bounds = self.with_hir_id_owner(exist_ty_node_id, lower_bounds);
+
+ let (lifetimes, lifetime_defs) = self.lifetimes_from_impl_trait_bounds(
+ exist_ty_node_id,
+ exist_ty_def_index,
+ &hir_bounds,
+ );
+
+ self.with_hir_id_owner(exist_ty_node_id, |lctx| {
+ let exist_ty_item_kind = hir::ItemExistential(hir::ExistTy {
+ generics: hir::Generics {
+ params: lifetime_defs,
+ where_clause: hir::WhereClause {
+ id: lctx.next_id().node_id,
+ predicates: Vec::new().into(),
+ },
+ span,
+ },
+ bounds: hir_bounds,
+ impl_trait_fn: Some(fn_def_id),
+ });
+ let exist_ty_id = lctx.lower_node_id(exist_ty_node_id);
+ // Generate an `existential type Foo: Trait;` declaration
+ trace!("creating existential type with id {:#?}", exist_ty_id);
+
+ trace!("exist ty def index: {:#?}", exist_ty_def_index);
+ let exist_ty_item = hir::Item {
+ id: exist_ty_id.node_id,
+ hir_id: exist_ty_id.hir_id,
+ name: exist_ty_name,
+ attrs: Default::default(),
+ node: exist_ty_item_kind,
+ vis: hir::Visibility::Inherited,
+ span: exist_ty_span,
+ };
+
+ // Insert the item into the global list. This usually happens
+ // automatically for all AST items. But this existential type item
+ // does not actually exist in the AST.
+ lctx.items.insert(exist_ty_id.node_id, exist_ty_item);
+
+ // `impl Trait` now just becomes `Foo<'a, 'b, ..>`
+ hir::TyImplTraitExistential(
+ hir::ItemId {
+ id: exist_ty_id.node_id
+ },
+ DefId::local(exist_ty_def_index),
+ lifetimes,
+ )
+ })
+ }
+
fn lifetimes_from_impl_trait_bounds(
&mut self,
+ exist_ty_id: NodeId,
parent_index: DefIndex,
- bounds: &hir::TyParamBounds,
+ bounds: &hir::GenericBounds,
) -> (HirVec<hir::Lifetime>, HirVec<hir::GenericParam>) {
// This visitor walks over impl trait bounds and creates defs for all lifetimes which
// appear in the bounds, excluding lifetimes that are created within the bounds.
struct ImplTraitLifetimeCollector<'r, 'a: 'r> {
context: &'r mut LoweringContext<'a>,
parent: DefIndex,
+ exist_ty_id: NodeId,
collect_elided_lifetimes: bool,
currently_bound_lifetimes: Vec<hir::LifetimeName>,
already_defined_lifetimes: HashSet<hir::LifetimeName>,
hir::intravisit::NestedVisitorMap::None
}
- fn visit_path_parameters(&mut self, span: Span, parameters: &'v hir::PathParameters) {
+ fn visit_generic_args(&mut self, span: Span, parameters: &'v hir::GenericArgs) {
// 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_path_parameters(self, span, parameters);
+ hir::intravisit::walk_generic_args(self, span, parameters);
self.collect_elided_lifetimes = old_collect_elided_lifetimes;
} else {
- hir::intravisit::walk_path_parameters(self, span, parameters);
+ hir::intravisit::walk_generic_args(self, span, parameters);
}
}
fn visit_generic_param(&mut self, param: &'v hir::GenericParam) {
// Record the introduction of 'a in `for<'a> ...`
- if let hir::GenericParam::Lifetime(ref lt_def) = *param {
+ 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>`
- self.currently_bound_lifetimes.push(lt_def.lifetime.name);
+ let lt_name = hir::LifetimeName::Param(param.name);
+ self.currently_bound_lifetimes.push(lt_name);
}
hir::intravisit::walk_generic_param(self, param);
return;
}
}
- name @ hir::LifetimeName::Fresh(_) => name,
- name @ hir::LifetimeName::Name(_) => name,
+ hir::LifetimeName::Param(_) => lifetime.name,
hir::LifetimeName::Static => return,
};
if !self.currently_bound_lifetimes.contains(&name)
- && !self.already_defined_lifetimes.contains(&name)
- {
+ && !self.already_defined_lifetimes.contains(&name) {
self.already_defined_lifetimes.insert(name);
self.output_lifetimes.push(hir::Lifetime {
name,
});
- let def_node_id = self.context.next_id().node_id;
+ // We need to manually create the ids here, because the
+ // definitions will go into the explicit `existential type`
+ // declaration and thus need to have their owner set to that item
+ let def_node_id = self.context.sess.next_node_id();
+ let _ = self.context.lower_node_id_with_owner(def_node_id, self.exist_ty_id);
self.context.resolver.definitions().create_def_with_parent(
self.parent,
def_node_id,
- DefPathData::LifetimeDef(name.name().as_interned_str()),
+ DefPathData::LifetimeParam(name.name().as_interned_str()),
DefIndexAddressSpace::High,
Mark::root(),
lifetime.span,
);
- let def_lifetime = hir::Lifetime {
+
+ let name = match name {
+ hir::LifetimeName::Underscore => {
+ hir::ParamName::Plain(keywords::UnderscoreLifetime.name())
+ }
+ hir::LifetimeName::Param(param_name) => param_name,
+ _ => bug!("expected LifetimeName::Param or ParamName::Plain"),
+ };
+
+ self.output_lifetime_params.push(hir::GenericParam {
id: def_node_id,
+ name,
span: lifetime.span,
- name: name,
- };
- self.output_lifetime_params
- .push(hir::GenericParam::Lifetime(hir::LifetimeDef {
- lifetime: def_lifetime,
- bounds: Vec::new().into(),
- pure_wrt_drop: false,
+ pure_wrt_drop: false,
+ attrs: hir_vec![],
+ bounds: hir_vec![],
+ kind: hir::GenericParamKind::Lifetime {
in_band: false,
- }));
+ }
+ });
}
}
}
let mut lifetime_collector = ImplTraitLifetimeCollector {
context: self,
parent: parent_index,
+ exist_ty_id,
collect_elided_lifetimes: true,
currently_bound_lifetimes: Vec::new(),
already_defined_lifetimes: HashSet::new(),
};
for bound in bounds {
- hir::intravisit::walk_ty_param_bound(&mut lifetime_collector, &bound);
+ hir::intravisit::walk_param_bound(&mut lifetime_collector, &bound);
}
(
fn lower_path_extra(
&mut self,
- id: NodeId,
+ def: Def,
p: &Path,
name: Option<Name>,
param_mode: ParamMode,
) -> hir::Path {
hir::Path {
- def: self.expect_full_def(id),
+ def,
segments: p.segments
.iter()
.map(|segment| {
}
fn lower_path(&mut self, id: NodeId, p: &Path, param_mode: ParamMode) -> hir::Path {
- self.lower_path_extra(id, p, None, param_mode)
+ let def = self.expect_full_def(id);
+ self.lower_path_extra(def, p, None, param_mode)
}
fn lower_path_segment(
parenthesized_generic_args: ParenthesizedGenericArgs,
itctx: ImplTraitContext,
) -> hir::PathSegment {
- let (mut parameters, infer_types) = if let Some(ref parameters) = segment.parameters {
+ let (mut generic_args, infer_types) = if let Some(ref generic_args) = segment.args {
let msg = "parenthesized parameters may only be used with a trait";
- match **parameters {
- PathParameters::AngleBracketed(ref data) => {
+ match **generic_args {
+ GenericArgs::AngleBracketed(ref data) => {
self.lower_angle_bracketed_parameter_data(data, param_mode, itctx)
}
- PathParameters::Parenthesized(ref data) => match parenthesized_generic_args {
+ GenericArgs::Parenthesized(ref data) => match parenthesized_generic_args {
ParenthesizedGenericArgs::Ok => self.lower_parenthesized_parameter_data(data),
ParenthesizedGenericArgs::Warn => {
self.sess.buffer_lint(
data.span,
msg.into(),
);
- (hir::PathParameters::none(), true)
+ (hir::GenericArgs::none(), true)
}
ParenthesizedGenericArgs::Err => {
struct_span_err!(self.sess, data.span, E0214, "{}", msg)
.span_label(data.span, "only traits may use parentheses")
.emit();
- (hir::PathParameters::none(), true)
+ (hir::GenericArgs::none(), true)
}
},
}
self.lower_angle_bracketed_parameter_data(&Default::default(), param_mode, itctx)
};
- if !parameters.parenthesized && parameters.lifetimes.is_empty() {
- parameters.lifetimes = self.elided_path_lifetimes(path_span, expected_lifetimes);
+ let has_lifetimes = generic_args.args.iter().any(|arg| match arg {
+ GenericArg::Lifetime(_) => true,
+ _ => false,
+ });
+ if !generic_args.parenthesized && !has_lifetimes {
+ generic_args.args =
+ self.elided_path_lifetimes(path_span, expected_lifetimes)
+ .into_iter()
+ .map(|lt| GenericArg::Lifetime(lt))
+ .chain(generic_args.args.into_iter())
+ .collect();
}
hir::PathSegment::new(
self.lower_ident(segment.ident),
- parameters,
+ generic_args,
infer_types,
)
}
fn lower_angle_bracketed_parameter_data(
&mut self,
- data: &AngleBracketedParameterData,
+ data: &AngleBracketedArgs,
param_mode: ParamMode,
itctx: ImplTraitContext,
- ) -> (hir::PathParameters, bool) {
- let &AngleBracketedParameterData {
- ref lifetimes,
- ref types,
- ref bindings,
- ..
- } = data;
- (
- hir::PathParameters {
- lifetimes: self.lower_lifetimes(lifetimes),
- types: types.iter().map(|ty| self.lower_ty(ty, itctx)).collect(),
- bindings: bindings
- .iter()
- .map(|b| self.lower_ty_binding(b, itctx))
- .collect(),
- parenthesized: false,
- },
- types.is_empty() && param_mode == ParamMode::Optional,
- )
+ ) -> (hir::GenericArgs, bool) {
+ let &AngleBracketedArgs { ref args, ref bindings, .. } = data;
+ let has_types = args.iter().any(|arg| match arg {
+ ast::GenericArg::Type(_) => true,
+ _ => false,
+ });
+ (hir::GenericArgs {
+ args: args.iter().map(|a| self.lower_generic_arg(a, itctx)).collect(),
+ bindings: bindings.iter().map(|b| self.lower_ty_binding(b, itctx)).collect(),
+ parenthesized: false,
+ },
+ !has_types && param_mode == ParamMode::Optional)
}
fn lower_parenthesized_parameter_data(
&mut self,
- data: &ParenthesizedParameterData,
- ) -> (hir::PathParameters, bool) {
+ data: &ParenthesisedArgs,
+ ) -> (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
AnonymousLifetimeMode::PassThrough,
|this| {
const DISALLOWED: ImplTraitContext = ImplTraitContext::Disallowed;
- let &ParenthesizedParameterData {
- ref inputs,
- ref output,
- span,
- } = data;
- let inputs = inputs
- .iter()
- .map(|ty| this.lower_ty(ty, DISALLOWED))
- .collect();
+ let &ParenthesisedArgs { ref inputs, ref output, span } = data;
+ let inputs = inputs.iter().map(|ty| this.lower_ty(ty, DISALLOWED)).collect();
let mk_tup = |this: &mut Self, tys, span| {
let LoweredNodeId { node_id, hir_id } = this.next_id();
- P(hir::Ty {
- node: hir::TyTup(tys),
- id: node_id,
- hir_id,
- span,
- })
+ P(hir::Ty { node: hir::TyTup(tys), id: node_id, hir_id, span })
};
(
- hir::PathParameters {
- lifetimes: hir::HirVec::new(),
- types: hir_vec![mk_tup(this, inputs, span)],
+ hir::GenericArgs {
+ args: hir_vec![GenericArg::Type(mk_tup(this, inputs, span))],
bindings: hir_vec![
hir::TypeBinding {
id: this.next_id().node_id,
.collect()
}
+ // Lowers a function declaration.
+ //
+ // decl: the unlowered (ast) function declaration.
+ // fn_def_id: if `Some`, impl Trait arguments are lowered into generic parameters on the
+ // given DefId, otherwise impl Trait is disallowed. Must be `Some` if
+ // make_ret_async is true.
+ // impl_trait_return_allow: determines whether impl Trait can be used in return position.
+ // This guards against trait declarations and implementations where impl Trait is
+ // disallowed.
+ // make_ret_async: if enabled, converts `-> T` into `-> impl Future<Output = T>` in the
+ // return type. This is used for `async fn` declarations.
fn lower_fn_decl(
&mut self,
decl: &FnDecl,
fn_def_id: Option<DefId>,
impl_trait_return_allow: bool,
+ make_ret_async: bool,
) -> P<hir::FnDecl> {
- // NOTE: The two last parameters here have to do with impl Trait. If fn_def_id is Some,
- // then impl Trait arguments are lowered into generic parameters on the given
- // fn_def_id, otherwise impl Trait is disallowed. (for now)
- //
- // Furthermore, if impl_trait_return_allow is true, then impl Trait may be used in
- // return positions as well. This guards against trait declarations and their impls
- // where impl Trait is disallowed. (again for now)
- P(hir::FnDecl {
- inputs: decl.inputs
- .iter()
- .map(|arg| {
- if let Some(def_id) = fn_def_id {
- self.lower_ty(&arg.ty, ImplTraitContext::Universal(def_id))
- } else {
- self.lower_ty(&arg.ty, ImplTraitContext::Disallowed)
- }
- })
- .collect(),
- output: match decl.output {
+ let inputs = decl.inputs
+ .iter()
+ .map(|arg| {
+ if let Some(def_id) = fn_def_id {
+ self.lower_ty(&arg.ty, ImplTraitContext::Universal(def_id))
+ } else {
+ self.lower_ty(&arg.ty, ImplTraitContext::Disallowed)
+ }
+ })
+ .collect::<HirVec<_>>();
+
+ let output = if make_ret_async {
+ self.lower_async_fn_ret_ty(
+ &inputs, &decl.output, fn_def_id.expect("make_ret_async but no fn_def_id"))
+ } else {
+ match decl.output {
FunctionRetTy::Ty(ref ty) => match fn_def_id {
- Some(_) if impl_trait_return_allow => {
- hir::Return(self.lower_ty(ty, ImplTraitContext::Existential))
+ Some(def_id) if impl_trait_return_allow => {
+ hir::Return(self.lower_ty(ty, ImplTraitContext::Existential(def_id)))
}
_ => hir::Return(self.lower_ty(ty, ImplTraitContext::Disallowed)),
},
FunctionRetTy::Default(span) => hir::DefaultReturn(span),
- },
+ }
+ };
+
+ P(hir::FnDecl {
+ inputs,
+ output,
variadic: decl.variadic,
has_implicit_self: decl.inputs.get(0).map_or(false, |arg| match arg.ty.node {
TyKind::ImplicitSelf => true,
})
}
- fn lower_ty_param_bound(
+ // Transform `-> T` into `-> impl Future<Output = T>` for `async fn`
+ //
+ // fn_span: the span of the async function declaration. Used for error reporting.
+ // 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.
+ fn lower_async_fn_ret_ty(
&mut self,
- tpb: &TyParamBound,
- itctx: ImplTraitContext,
- ) -> hir::TyParamBound {
- match *tpb {
- TraitTyParamBound(ref ty, modifier) => hir::TraitTyParamBound(
- self.lower_poly_trait_ref(ty, itctx),
- self.lower_trait_bound_modifier(modifier),
- ),
- RegionTyParamBound(ref lifetime) => {
- hir::RegionTyParamBound(self.lower_lifetime(lifetime))
+ inputs: &[P<hir::Ty>],
+ output: &FunctionRetTy,
+ fn_def_id: DefId,
+ ) -> hir::FunctionRetTy {
+ // Get lifetimes used in the input arguments to the function. Our output type must also
+ // have the same lifetime. FIXME(cramertj) multiple different lifetimes are not allowed
+ // because `impl Trait + 'a + 'b` doesn't allow for capture `'a` and `'b` where neither
+ // is a subset of the other. We really want some new lifetime that is a subset of all input
+ // lifetimes, but that doesn't exist at the moment.
+
+ struct AsyncFnLifetimeCollector<'r, 'a: 'r> {
+ context: &'r mut LoweringContext<'a>,
+ // Lifetimes bound by HRTB
+ currently_bound_lifetimes: Vec<hir::LifetimeName>,
+ // Whether to count elided lifetimes.
+ // Disabled inside of `Fn` or `fn` syntax.
+ collect_elided_lifetimes: bool,
+ // The lifetime found.
+ // Multiple different or elided lifetimes cannot appear in async fn for now.
+ output_lifetime: Option<(hir::LifetimeName, Span)>,
+ }
+
+ impl<'r, 'a: 'r, 'v> hir::intravisit::Visitor<'v> for AsyncFnLifetimeCollector<'r, 'a> {
+ fn nested_visit_map<'this>(
+ &'this mut self,
+ ) -> hir::intravisit::NestedVisitorMap<'this, 'v> {
+ hir::intravisit::NestedVisitorMap::None
+ }
+
+ fn visit_path_parameters(&mut self, span: Span, parameters: &'v hir::PathParameters) {
+ // 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_path_parameters(self, span, parameters);
+ self.collect_elided_lifetimes = old_collect_elided_lifetimes;
+ } else {
+ hir::intravisit::walk_path_parameters(self, span, parameters);
+ }
+ }
+
+ fn visit_ty(&mut self, t: &'v hir::Ty) {
+ // Don't collect elided lifetimes used inside of `fn()` syntax
+ if let &hir::Ty_::TyBareFn(_) = &t.node {
+ let old_collect_elided_lifetimes = self.collect_elided_lifetimes;
+ self.collect_elided_lifetimes = false;
+
+ // Record the "stack height" of `for<'a>` lifetime bindings
+ // to be able to later fully undo their introduction.
+ let old_len = self.currently_bound_lifetimes.len();
+ hir::intravisit::walk_ty(self, t);
+ self.currently_bound_lifetimes.truncate(old_len);
+
+ self.collect_elided_lifetimes = old_collect_elided_lifetimes;
+ } else {
+ hir::intravisit::walk_ty(self, t);
+ }
+ }
+
+ fn visit_poly_trait_ref(
+ &mut self,
+ trait_ref: &'v hir::PolyTraitRef,
+ modifier: hir::TraitBoundModifier,
+ ) {
+ // 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::GenericParam::Lifetime(ref lt_def) = *param {
+ // Introduce lifetimes one at a time so that we can handle
+ // cases like `fn foo<'d>() -> impl for<'a, 'b: 'a, 'c: 'b + 'd>`
+ self.currently_bound_lifetimes.push(lt_def.lifetime.name);
+ }
+
+ hir::intravisit::walk_generic_param(self, param);
+ }
+
+ fn visit_lifetime(&mut self, lifetime: &'v hir::Lifetime) {
+ let name = match lifetime.name {
+ hir::LifetimeName::Implicit | hir::LifetimeName::Underscore => {
+ if self.collect_elided_lifetimes {
+ // Use `'_` for both implicit and underscore lifetimes in
+ // `abstract type Foo<'_>: SomeTrait<'_>;`
+ hir::LifetimeName::Underscore
+ } else {
+ return;
+ }
+ }
+ name @ hir::LifetimeName::Fresh(_) => name,
+ name @ hir::LifetimeName::Name(_) => name,
+ hir::LifetimeName::Static => return,
+ };
+
+ if !self.currently_bound_lifetimes.contains(&name) {
+ if let Some((current_lt_name, current_lt_span)) = self.output_lifetime {
+ // We don't currently have a reliable way to desugar `async fn` with
+ // multiple potentially unrelated input lifetimes into
+ // `-> impl Trait + 'lt`, so we report an error in this case.
+ if current_lt_name != name {
+ struct_span_err!(
+ self.context.sess,
+ current_lt_span.between(lifetime.span),
+ E0703,
+ "multiple different lifetimes used in arguments of `async fn`",
+ )
+ .span_label(current_lt_span, "first lifetime here")
+ .span_label(lifetime.span, "different lifetime here")
+ .help("`async fn` can only accept borrowed values \
+ with identical lifetimes")
+ .emit()
+ } else if current_lt_name.is_elided() && name.is_elided() {
+ struct_span_err!(
+ self.context.sess,
+ current_lt_span.between(lifetime.span),
+ E0704,
+ "multiple elided lifetimes used in arguments of `async fn`",
+ )
+ .span_label(current_lt_span, "first lifetime here")
+ .span_label(lifetime.span, "different lifetime here")
+ .help("consider giving these arguments named lifetimes")
+ .emit()
+ }
+ } else {
+ self.output_lifetime = Some((name, lifetime.span));
+ }
+ }
}
}
+
+ let bound_lifetime = {
+ let mut lifetime_collector = AsyncFnLifetimeCollector {
+ context: self,
+ currently_bound_lifetimes: Vec::new(),
+ collect_elided_lifetimes: true,
+ output_lifetime: None,
+ };
+
+ for arg in inputs {
+ hir::intravisit::walk_ty(&mut lifetime_collector, arg);
+ }
+ lifetime_collector.output_lifetime
+ };
+
+ let output_ty_name_owned;
+ let (output_ty_name, span) = match output {
+ FunctionRetTy::Ty(ty) => {
+ output_ty_name_owned = pprust::ty_to_string(ty);
+ (&*output_ty_name_owned, ty.span)
+ },
+ FunctionRetTy::Default(span) => ("()", *span),
+ };
+
+ // FIXME(cramertj) add lifetimes (see FIXME below) to the name
+ let exist_ty_name = Symbol::intern(&format!("impl Future<Output = {}>", output_ty_name));
+ let impl_trait_ty = self.lower_existential_impl_trait(
+ span, fn_def_id, exist_ty_name, |this| {
+ let output_ty = match output {
+ FunctionRetTy::Ty(ty) =>
+ this.lower_ty(ty, ImplTraitContext::Existential(fn_def_id)),
+ FunctionRetTy::Default(span) => {
+ let LoweredNodeId { node_id, hir_id } = this.next_id();
+ P(hir::Ty {
+ id: node_id,
+ hir_id: hir_id,
+ node: hir::TyTup(hir_vec![]),
+ span: *span,
+ })
+ }
+ };
+
+ let hir::Path { def, segments, .. } = this.std_path(span, &["future", "Future"], false);
+ let future_path = hir::Path {
+ segments: segments.map_slice(|mut v| {
+ v.last_mut().unwrap().parameters = Some(P(hir::PathParameters {
+ lifetimes: hir_vec![],
+ types: hir_vec![],
+ bindings: hir_vec![hir::TypeBinding {
+ name: Symbol::intern(FN_OUTPUT_NAME),
+ ty: output_ty,
+ id: this.next_id().node_id,
+ span,
+ }],
+ parenthesized: false,
+ }));
+ v
+ }),
+ def, span
+ };
+
+ // FIXME(cramertj) collect input lifetimes to function and add them to
+ // the output `impl Trait` type here.
+ let mut bounds = vec![
+ hir::TyParamBound::TraitTyParamBound(
+ hir::PolyTraitRef {
+ trait_ref: hir::TraitRef {
+ path: future_path,
+ ref_id: this.next_id().node_id,
+ },
+ bound_generic_params: hir_vec![],
+ span,
+ },
+ hir::TraitBoundModifier::None
+ ),
+ ];
+
+ if let Some((name, span)) = bound_lifetime {
+ bounds.push(hir::RegionTyParamBound(
+ hir::Lifetime { id: this.next_id().node_id, name, span }));
+ }
+
+ hir::HirVec::from(bounds)
+ });
+
+ let LoweredNodeId { node_id, hir_id } = self.next_id();
+ let impl_trait_ty = P(hir::Ty {
+ id: node_id,
+ node: impl_trait_ty,
+ span,
+ hir_id,
+ });
+
+ hir::FunctionRetTy::Return(impl_trait_ty)
}
- fn lower_ty_param(
+ fn lower_param_bound(
&mut self,
- tp: &TyParam,
- add_bounds: &[TyParamBound],
+ tpb: &GenericBound,
itctx: ImplTraitContext,
- ) -> hir::TyParam {
- let mut name = self.lower_ident(tp.ident);
-
- // Don't expose `Self` (recovered "keyword used as ident" parse error).
- // `rustc::ty` expects `Self` to be only used for a trait's `Self`.
- // Instead, use gensym("Self") to create a distinct name that looks the same.
- if name == keywords::SelfType.name() {
- name = Symbol::gensym("Self");
- }
-
- let mut bounds = self.lower_bounds(&tp.bounds, itctx);
- if !add_bounds.is_empty() {
- bounds = bounds
- .into_iter()
- .chain(self.lower_bounds(add_bounds, itctx).into_iter())
- .collect();
- }
-
- hir::TyParam {
- id: self.lower_node_id(tp.id).node_id,
- name,
- bounds,
- default: tp.default
- .as_ref()
- .map(|x| self.lower_ty(x, ImplTraitContext::Disallowed)),
- span: tp.ident.span,
- pure_wrt_drop: attr::contains_name(&tp.attrs, "may_dangle"),
- synthetic: tp.attrs
- .iter()
- .filter(|attr| attr.check_name("rustc_synthetic"))
- .map(|_| hir::SyntheticTyParamKind::ImplTrait)
- .nth(0),
- attrs: self.lower_attrs(&tp.attrs),
+ ) -> 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))
+ }
}
}
x if x == "'_" => match self.anonymous_lifetime_mode {
AnonymousLifetimeMode::CreateParameter => {
let fresh_name = self.collect_fresh_in_band_lifetime(span);
- self.new_named_lifetime(l.id, span, fresh_name)
+ self.new_named_lifetime(l.id, span, hir::LifetimeName::Param(fresh_name))
}
AnonymousLifetimeMode::PassThrough => {
},
name => {
self.maybe_collect_in_band_lifetime(span, name);
- self.new_named_lifetime(l.id, span, hir::LifetimeName::Name(name))
+ let param_name = ParamName::Plain(name);
+ self.new_named_lifetime(l.id, span, hir::LifetimeName::Param(param_name))
}
}
}
}
}
- fn lower_lifetime_def(&mut self, l: &LifetimeDef) -> hir::LifetimeDef {
- let was_collecting_in_band = self.is_collecting_in_band_lifetimes;
- self.is_collecting_in_band_lifetimes = false;
-
- let def = hir::LifetimeDef {
- lifetime: self.lower_lifetime(&l.lifetime),
- bounds: self.lower_lifetimes(&l.bounds),
- pure_wrt_drop: attr::contains_name(&l.attrs, "may_dangle"),
- in_band: false,
- };
-
- self.is_collecting_in_band_lifetimes = was_collecting_in_band;
-
- def
- }
-
- fn lower_lifetimes(&mut self, lts: &Vec<Lifetime>) -> hir::HirVec<hir::Lifetime> {
- lts.iter().map(|l| self.lower_lifetime(l)).collect()
- }
-
fn lower_generic_params(
&mut self,
params: &Vec<GenericParam>,
- add_bounds: &NodeMap<Vec<TyParamBound>>,
+ add_bounds: &NodeMap<Vec<GenericBound>>,
itctx: ImplTraitContext,
) -> hir::HirVec<hir::GenericParam> {
- params
- .iter()
- .map(|param| match *param {
- GenericParam::Lifetime(ref lifetime_def) => {
- hir::GenericParam::Lifetime(self.lower_lifetime_def(lifetime_def))
+ params.iter().map(|param| self.lower_generic_param(param, add_bounds, itctx)).collect()
+ }
+
+ fn lower_generic_param(&mut self,
+ param: &GenericParam,
+ add_bounds: &NodeMap<Vec<GenericBound>>,
+ itctx: ImplTraitContext)
+ -> hir::GenericParam {
+ let mut bounds = self.lower_param_bounds(¶m.bounds, itctx);
+ match param.kind {
+ GenericParamKind::Lifetime => {
+ let was_collecting_in_band = self.is_collecting_in_band_lifetimes;
+ self.is_collecting_in_band_lifetimes = false;
+
+ let lt = self.lower_lifetime(&Lifetime { id: param.id, ident: param.ident });
+ let param_name = match lt.name {
+ hir::LifetimeName::Param(param_name) => param_name,
+ _ => hir::ParamName::Plain(lt.name.name()),
+ };
+ let param = hir::GenericParam {
+ id: lt.id,
+ name: param_name,
+ span: lt.span,
+ pure_wrt_drop: attr::contains_name(¶m.attrs, "may_dangle"),
+ attrs: self.lower_attrs(¶m.attrs),
+ bounds,
+ kind: hir::GenericParamKind::Lifetime { in_band: false }
+ };
+
+ self.is_collecting_in_band_lifetimes = was_collecting_in_band;
+
+ param
+ }
+ GenericParamKind::Type { ref default, .. } => {
+ let mut name = self.lower_ident(param.ident);
+
+ // Don't expose `Self` (recovered "keyword used as ident" parse error).
+ // `rustc::ty` expects `Self` to be only used for a trait's `Self`.
+ // Instead, use gensym("Self") to create a distinct name that looks the same.
+ if name == keywords::SelfType.name() {
+ name = Symbol::gensym("Self");
}
- GenericParam::Type(ref ty_param) => hir::GenericParam::Type(self.lower_ty_param(
- ty_param,
- add_bounds.get(&ty_param.id).map_or(&[][..], |x| &x),
- itctx,
- )),
- })
- .collect()
+
+ let add_bounds = add_bounds.get(¶m.id).map_or(&[][..], |x| &x);
+ if !add_bounds.is_empty() {
+ bounds = bounds.into_iter()
+ .chain(self.lower_param_bounds(add_bounds, itctx).into_iter())
+ .collect();
+ }
+
+ hir::GenericParam {
+ id: self.lower_node_id(param.id).node_id,
+ name: hir::ParamName::Plain(name),
+ span: param.ident.span,
+ pure_wrt_drop: attr::contains_name(¶m.attrs, "may_dangle"),
+ attrs: self.lower_attrs(¶m.attrs),
+ bounds,
+ kind: hir::GenericParamKind::Type {
+ default: default.as_ref().map(|x| {
+ self.lower_ty(x, ImplTraitContext::Disallowed)
+ }),
+ synthetic: param.attrs.iter()
+ .filter(|attr| attr.check_name("rustc_synthetic"))
+ .map(|_| hir::SyntheticTyParamKind::ImplTrait)
+ .next(),
+ }
+ }
+ }
+ }
}
- fn lower_generics(&mut self, g: &Generics, itctx: ImplTraitContext) -> hir::Generics {
+ fn lower_generics(
+ &mut self,
+ generics: &Generics,
+ itctx: ImplTraitContext)
+ -> hir::Generics
+ {
// Collect `?Trait` bounds in where clause and move them to parameter definitions.
// FIXME: This could probably be done with less rightward drift. Also looks like two control
// paths where report_error is called are also the only paths that advance to after
// the match statement, so the error reporting could probably just be moved there.
let mut add_bounds = NodeMap();
- for pred in &g.where_clause.predicates {
+ for pred in &generics.where_clause.predicates {
if let WherePredicate::BoundPredicate(ref bound_pred) = *pred {
'next_bound: for bound in &bound_pred.bounds {
- if let TraitTyParamBound(_, TraitBoundModifier::Maybe) = *bound {
+ if let GenericBound::Trait(_, TraitBoundModifier::Maybe) = *bound {
let report_error = |this: &mut Self| {
this.diagnostic().span_err(
bound_pred.bounded_ty.span,
if let Some(node_id) =
self.resolver.definitions().as_local_node_id(def_id)
{
- for param in &g.params {
- if let GenericParam::Type(ref ty_param) = *param {
- if node_id == ty_param.id {
- add_bounds
- .entry(ty_param.id)
- .or_insert(Vec::new())
- .push(bound.clone());
- continue 'next_bound;
+ for param in &generics.params {
+ match param.kind {
+ GenericParamKind::Type { .. } => {
+ if node_id == param.id {
+ add_bounds.entry(param.id)
+ .or_insert(Vec::new())
+ .push(bound.clone());
+ continue 'next_bound;
+ }
}
+ _ => {}
}
}
}
}
hir::Generics {
- params: self.lower_generic_params(&g.params, &add_bounds, itctx),
- where_clause: self.lower_where_clause(&g.where_clause),
- span: g.span,
+ params: self.lower_generic_params(&generics.params, &add_bounds, itctx),
+ where_clause: self.lower_where_clause(&generics.where_clause),
+ span: generics.span,
}
}
span,
}) => {
self.with_in_scope_lifetime_defs(
- bound_generic_params.iter().filter_map(|p| match p {
- GenericParam::Lifetime(ld) => Some(ld),
- _ => None,
- }),
+ &bound_generic_params,
|this| {
hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate {
bound_generic_params: this.lower_generic_params(
.filter_map(|bound| match *bound {
// Ignore `?Trait` bounds.
// Tthey were copied into type parameters already.
- TraitTyParamBound(_, TraitBoundModifier::Maybe) => None,
- _ => Some(this.lower_ty_param_bound(
+ GenericBound::Trait(_, TraitBoundModifier::Maybe) => None,
+ _ => Some(this.lower_param_bound(
bound,
ImplTraitContext::Disallowed,
)),
}) => hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate {
span,
lifetime: self.lower_lifetime(lifetime),
- bounds: bounds
- .iter()
- .map(|bound| self.lower_lifetime(bound))
- .collect(),
+ bounds: self.lower_param_bounds(bounds, ImplTraitContext::Disallowed),
}),
WherePredicate::EqPredicate(WhereEqPredicate {
id,
let bound_generic_params =
self.lower_generic_params(&p.bound_generic_params, &NodeMap(), itctx);
let trait_ref = self.with_parent_impl_lifetime_defs(
- &bound_generic_params
- .iter()
- .filter_map(|p| match *p {
- hir::GenericParam::Lifetime(ref ld) => Some(ld.clone()),
- _ => None,
- })
- .collect::<Vec<_>>(),
+ &bound_generic_params,
|this| this.lower_trait_ref(&p.trait_ref, itctx),
);
}
}
- fn lower_bounds(
- &mut self,
- bounds: &[TyParamBound],
- itctx: ImplTraitContext,
- ) -> hir::TyParamBounds {
- bounds
- .iter()
- .map(|bound| self.lower_ty_param_bound(bound, itctx))
- .collect()
+ fn lower_param_bounds(&mut self, bounds: &[GenericBound], itctx: ImplTraitContext)
+ -> hir::GenericBounds {
+ bounds.iter().map(|bound| self.lower_param_bound(bound, itctx)).collect()
}
fn lower_block(&mut self, b: &Block, targeted_by_break: bool) -> P<hir::Block> {
let value = self.lower_body(None, |this| this.lower_expr(e));
hir::ItemConst(self.lower_ty(t, ImplTraitContext::Disallowed), value)
}
- ItemKind::Fn(ref decl, unsafety, constness, abi, ref generics, ref body) => {
+ ItemKind::Fn(ref decl, header, ref generics, ref body) => {
let fn_def_id = self.resolver.definitions().local_def_id(id);
+
self.with_new_scopes(|this| {
+ // Note: we can use non-async decl here because lower_body
+ // only cares about the input argument patterns,
+ // not the return types.
let body_id = this.lower_body(Some(decl), |this| {
- let body = this.lower_block(body, false);
- this.expr_block(body, ThinVec::new())
+ if let IsAsync::Async(async_node_id) = header.asyncness {
+ let async_expr = this.make_async_expr(
+ CaptureBy::Value, async_node_id, None,
+ |this| {
+ let body = this.lower_block(body, false);
+ this.expr_block(body, ThinVec::new())
+ });
+ this.expr(body.span, async_expr, ThinVec::new())
+ } else {
+ let body = this.lower_block(body, false);
+ this.expr_block(body, ThinVec::new())
+ }
});
+
let (generics, fn_decl) = this.add_in_band_defs(
generics,
fn_def_id,
AnonymousLifetimeMode::PassThrough,
- |this| this.lower_fn_decl(decl, Some(fn_def_id), true),
+ |this| this.lower_fn_decl(
+ decl, Some(fn_def_id), true, header.asyncness.is_async())
);
hir::ItemFn(
fn_decl,
- this.lower_unsafety(unsafety),
- this.lower_constness(constness),
- abi,
+ this.lower_fn_header(header),
generics,
body_id,
)
);
let new_impl_items = self.with_in_scope_lifetime_defs(
- ast_generics.params.iter().filter_map(|p| match p {
- GenericParam::Lifetime(ld) => Some(ld),
- _ => None,
- }),
+ &ast_generics.params,
|this| {
impl_items
.iter()
)
}
ItemKind::Trait(is_auto, unsafety, ref generics, ref bounds, ref items) => {
- let bounds = self.lower_bounds(bounds, ImplTraitContext::Disallowed);
+ let bounds = self.lower_param_bounds(bounds, ImplTraitContext::Disallowed);
let items = items
.iter()
.map(|item| self.lower_trait_item_ref(item))
}
ItemKind::TraitAlias(ref generics, ref bounds) => hir::ItemTraitAlias(
self.lower_generics(generics, ImplTraitContext::Disallowed),
- self.lower_bounds(bounds, ImplTraitContext::Disallowed),
+ self.lower_param_bounds(bounds, ImplTraitContext::Disallowed),
),
ItemKind::MacroDef(..) | ItemKind::Mac(..) => panic!("Shouldn't still be around"),
}
let path = &tree.prefix;
match tree.kind {
- UseTreeKind::Simple(rename) => {
+ UseTreeKind::Simple(rename, id1, id2) => {
*name = tree.ident().name;
// First apply the prefix to the path
}
}
- let path = P(self.lower_path(id, &path, ParamMode::Explicit));
+ let parent_def_index = self.current_hir_id_owner.last().unwrap().0;
+ let mut defs = self.expect_full_def_from_use(id);
+ // we want to return *something* from this function, so hang onto the first item
+ // for later
+ let mut ret_def = defs.next().unwrap_or(Def::Err);
+
+ for (def, &new_node_id) in defs.zip([id1, id2].iter()) {
+ let vis = vis.clone();
+ let name = name.clone();
+ let span = path.span;
+ self.resolver.definitions().create_def_with_parent(
+ parent_def_index,
+ new_node_id,
+ DefPathData::Misc,
+ DefIndexAddressSpace::High,
+ Mark::root(),
+ span);
+ self.allocate_hir_id_counter(new_node_id, &path);
+
+ self.with_hir_id_owner(new_node_id, |this| {
+ let new_id = this.lower_node_id(new_node_id);
+ let path = this.lower_path_extra(def, &path, None, ParamMode::Explicit);
+ let item = hir::ItemUse(P(path), hir::UseKind::Single);
+ let vis = match vis {
+ hir::Visibility::Public => hir::Visibility::Public,
+ hir::Visibility::Crate(sugar) => hir::Visibility::Crate(sugar),
+ hir::Visibility::Inherited => hir::Visibility::Inherited,
+ hir::Visibility::Restricted { ref path, id: _ } => {
+ hir::Visibility::Restricted {
+ path: path.clone(),
+ // We are allocating a new NodeId here
+ id: this.next_id().node_id,
+ }
+ }
+ };
+
+ this.items.insert(
+ new_id.node_id,
+ hir::Item {
+ id: new_id.node_id,
+ hir_id: new_id.hir_id,
+ name: name,
+ attrs: attrs.clone(),
+ node: item,
+ vis,
+ span,
+ },
+ );
+ });
+ }
+
+ let path = P(self.lower_path_extra(ret_def, &path, None, ParamMode::Explicit));
hir::ItemUse(path, hir::UseKind::Single)
}
UseTreeKind::Glob => {
TraitItemKind::Type(ref bounds, ref default) => (
self.lower_generics(&i.generics, ImplTraitContext::Disallowed),
hir::TraitItemKind::Type(
- self.lower_bounds(bounds, ImplTraitContext::Disallowed),
+ self.lower_param_bounds(bounds, ImplTraitContext::Disallowed),
default
.as_ref()
.map(|x| self.lower_ty(x, ImplTraitContext::Disallowed)),
match i.node {
ItemKind::Use(ref use_tree) => {
let mut vec = SmallVector::one(hir::ItemId { id: i.id });
- self.lower_item_id_use_tree(use_tree, &mut vec);
+ self.lower_item_id_use_tree(use_tree, i.id, &mut vec);
return vec;
}
ItemKind::MacroDef(..) => return SmallVector::new(),
SmallVector::one(hir::ItemId { id: i.id })
}
- fn lower_item_id_use_tree(&self, tree: &UseTree, vec: &mut SmallVector<hir::ItemId>) {
+ fn lower_item_id_use_tree(&mut self,
+ tree: &UseTree,
+ base_id: NodeId,
+ vec: &mut SmallVector<hir::ItemId>)
+ {
match tree.kind {
UseTreeKind::Nested(ref nested_vec) => for &(ref nested, id) in nested_vec {
vec.push(hir::ItemId { id });
- self.lower_item_id_use_tree(nested, vec);
+ self.lower_item_id_use_tree(nested, id, vec);
},
UseTreeKind::Glob => {}
- UseTreeKind::Simple(..) => {}
+ UseTreeKind::Simple(_, id1, id2) => {
+ for (_, &id) in self.expect_full_def_from_use(base_id)
+ .skip(1)
+ .zip([id1, id2].iter())
+ {
+ vec.push(hir::ItemId { id });
+ }
+ },
}
}
|this| {
(
// Disallow impl Trait in foreign items
- this.lower_fn_decl(fdec, None, false),
+ this.lower_fn_decl(fdec, None, false, false),
this.lower_fn_args_to_names(fdec),
)
},
impl_trait_return_allow: bool,
) -> hir::MethodSig {
hir::MethodSig {
- abi: sig.abi,
- unsafety: self.lower_unsafety(sig.unsafety),
- constness: self.lower_constness(sig.constness),
- decl: self.lower_fn_decl(&sig.decl, Some(fn_def_id), impl_trait_return_allow),
+ header: self.lower_fn_header(sig.header),
+ decl: self.lower_fn_decl(&sig.decl, Some(fn_def_id), impl_trait_return_allow, false),
}
}
}
}
+ fn lower_fn_header(&mut self, h: FnHeader) -> hir::FnHeader {
+ hir::FnHeader {
+ unsafety: self.lower_unsafety(h.unsafety),
+ asyncness: self.lower_asyncness(h.asyncness),
+ constness: self.lower_constness(h.constness),
+ abi: h.abi,
+ }
+ }
+
fn lower_unsafety(&mut self, u: Unsafety) -> hir::Unsafety {
match u {
Unsafety::Unsafe => hir::Unsafety::Unsafe,
}
}
+ fn lower_asyncness(&mut self, a: IsAsync) -> hir::IsAsync {
+ match a {
+ IsAsync::Async(_) => hir::IsAsync::Async,
+ IsAsync::NotAsync => hir::IsAsync::NotAsync,
+ }
+ }
+
fn lower_unop(&mut self, u: UnOp) -> hir::UnOp {
match u {
UnOp::Deref => hir::UnDeref,
arms.iter().map(|x| self.lower_arm(x)).collect(),
hir::MatchSource::Normal,
),
- ExprKind::Closure(capture_clause, movability, ref decl, ref body, fn_decl_span) => {
+ ExprKind::Async(capture_clause, closure_node_id, ref block) => {
+ self.make_async_expr(capture_clause, closure_node_id, None, |this| {
+ this.with_new_scopes(|this| {
+ let block = this.lower_block(block, false);
+ this.expr_block(block, ThinVec::new())
+ })
+ })
+ },
+ ExprKind::Closure(
+ capture_clause, asyncness, movability, ref decl, ref body, fn_decl_span) =>
+ {
self.with_new_scopes(|this| {
- let mut is_generator = false;
- let body_id = this.lower_body(Some(decl), |this| {
- let e = this.lower_expr(body);
- is_generator = this.is_generator;
- e
- });
- let generator_option = if is_generator {
- if !decl.inputs.is_empty() {
- span_err!(
+ if let IsAsync::Async(async_closure_node_id) = asyncness {
+ // FIXME(cramertj) allow `async` non-`move` closures with
+ if capture_clause == CaptureBy::Ref &&
+ !decl.inputs.is_empty()
+ {
+ struct_span_err!(
this.sess,
fn_decl_span,
- E0628,
- "generators cannot have explicit arguments"
- );
- this.sess.abort_if_errors();
+ E0705,
+ "`async` non-`move` closures with arguments \
+ are not currently supported",
+ )
+ .help("consider using `let` statements to manually capture \
+ variables by reference before entering an \
+ `async move` closure")
+ .emit();
}
- Some(match movability {
- Movability::Movable => hir::GeneratorMovability::Movable,
- Movability::Static => hir::GeneratorMovability::Static,
- })
+
+ // Transform `async |x: u8| -> X { ... }` into
+ // `|x: u8| future_from_generator(|| -> X { ... })`
+ let outer_decl = FnDecl {
+ inputs: decl.inputs.clone(),
+ output: FunctionRetTy::Default(fn_decl_span),
+ variadic: false,
+ };
+ let body_id = this.lower_body(Some(&outer_decl), |this| {
+ let async_ret_ty = if let FunctionRetTy::Ty(ty) = &decl.output {
+ Some(&**ty)
+ } else { None };
+ let async_body = this.make_async_expr(
+ capture_clause, async_closure_node_id, async_ret_ty,
+ |this| {
+ this.with_new_scopes(|this| this.lower_expr(body))
+ });
+ this.expr(fn_decl_span, async_body, ThinVec::new())
+ });
+ hir::ExprClosure(
+ this.lower_capture_clause(capture_clause),
+ this.lower_fn_decl(&outer_decl, None, false, false),
+ body_id,
+ fn_decl_span,
+ None,
+ )
} else {
- if movability == Movability::Static {
- span_err!(
- this.sess,
- fn_decl_span,
- E0906,
- "closures cannot be static"
- );
- }
- None
- };
- hir::ExprClosure(
- this.lower_capture_clause(capture_clause),
- this.lower_fn_decl(decl, None, false),
- body_id,
- fn_decl_span,
- generator_option,
- )
+ let mut is_generator = false;
+ let body_id = this.lower_body(Some(decl), |this| {
+ let e = this.lower_expr(body);
+ is_generator = this.is_generator;
+ e
+ });
+ let generator_option = if is_generator {
+ if !decl.inputs.is_empty() {
+ span_err!(
+ this.sess,
+ fn_decl_span,
+ E0628,
+ "generators cannot have explicit arguments"
+ );
+ this.sess.abort_if_errors();
+ }
+ Some(match movability {
+ Movability::Movable => hir::GeneratorMovability::Movable,
+ Movability::Static => hir::GeneratorMovability::Static,
+ })
+ } else {
+ if movability == Movability::Static {
+ span_err!(
+ this.sess,
+ fn_decl_span,
+ E0906,
+ "closures cannot be static"
+ );
+ }
+ None
+ };
+ hir::ExprClosure(
+ this.lower_capture_clause(capture_clause),
+ this.lower_fn_decl(decl, None, false, false),
+ body_id,
+ fn_decl_span,
+ generator_option,
+ )
+ }
})
}
ExprKind::Block(ref blk, opt_label) => {
hir::Lifetime {
id: self.next_id().node_id,
span,
- name: fresh_name,
+ name: hir::LifetimeName::Param(fresh_name),
}
}