#[macro_use]
extern crate tracing;
-use crate::errors::{AssocTyParentheses, AssocTyParenthesesSub, MisplacedImplTrait};
+use crate::errors::{AssocTyParentheses, AssocTyParenthesesSub, MisplacedImplTrait, TraitFnAsync};
+use rustc_arena::declare_arena;
use rustc_ast::ptr::P;
use rustc_ast::visit;
use rustc_ast::{self as ast, *};
/// Used to allocate HIR nodes.
arena: &'hir hir::Arena<'hir>,
+ /// Used to allocate temporary AST nodes for use during lowering.
+ /// This allows us to create "fake" AST -- these nodes can sometimes
+ /// be allocated on the stack, but other times we need them to live longer
+ /// than the current stack frame, so they can be collected into vectors
+ /// and things like that.
+ ast_arena: &'a Arena<'static>,
+
/// Bodies inside the owner being lowered.
bodies: Vec<(hir::ItemLocalId, &'hir hir::Body<'hir>)>,
/// Attributes inside the owner being lowered.
generics_def_id_map: Vec<FxHashMap<LocalDefId, LocalDefId>>,
}
+declare_arena!([
+ [] tys: rustc_ast::Ty,
+ [] aba: rustc_ast::AngleBracketedArgs,
+ [] ptr: rustc_ast::PolyTraitRef,
+ // This _marker field is needed because `declare_arena` creates `Arena<'tcx>` and we need to
+ // use `'tcx`. If we don't have this we get a compile error.
+ [] _marker: std::marker::PhantomData<&'tcx ()>,
+]);
+
trait ResolverAstLoweringExt {
fn legacy_const_generic_args(&self, expr: &Expr) -> Option<Vec<usize>>;
fn get_partial_res(&self, id: NodeId) -> Option<PartialRes>;
ReturnPositionOpaqueTy {
/// Origin: Either OpaqueTyOrigin::FnReturn or OpaqueTyOrigin::AsyncFn,
origin: hir::OpaqueTyOrigin,
+ in_trait: bool,
},
/// Impl trait in type aliases.
TypeAliasesOpaqueTy,
}
}
-#[derive(Debug)]
+#[derive(Debug, PartialEq, Eq)]
enum FnDeclKind {
Fn,
Inherent,
}
impl FnDeclKind {
- fn impl_trait_return_allowed(&self) -> bool {
+ fn impl_trait_return_allowed(&self, tcx: TyCtxt<'_>) -> bool {
match self {
FnDeclKind::Fn | FnDeclKind::Inherent => true,
+ FnDeclKind::Impl if tcx.features().return_position_impl_trait_in_trait => true,
+ _ => false,
+ }
+ }
+
+ fn impl_trait_in_trait_allowed(&self, tcx: TyCtxt<'_>) -> bool {
+ match self {
+ FnDeclKind::Trait if tcx.features().return_position_impl_trait_in_trait => true,
_ => false,
}
}
tcx.definitions_untracked().def_index_count(),
);
+ let ast_arena = Arena::default();
+
for def_id in ast_index.indices() {
item::ItemLowerer {
tcx,
resolver: &mut resolver,
+ ast_arena: &ast_arena,
ast_index: &ast_index,
owners: &mut owners,
}
fn lower_assoc_ty_constraint(
&mut self,
constraint: &AssocConstraint,
- itctx: &mut ImplTraitContext,
+ itctx: &ImplTraitContext,
) -> hir::TypeBinding<'hir> {
debug!("lower_assoc_ty_constraint(constraint={:?}, itctx={:?})", constraint, itctx);
// lower generic arguments of identifier in constraint
}
GenericArgs::Parenthesized(ref data) => {
self.emit_bad_parenthesized_trait_in_assoc_ty(data);
- self.lower_angle_bracketed_parameter_data(
- &data.as_angle_bracketed_args(),
- ParamMode::Explicit,
- itctx,
- )
- .0
+ let aba = self.ast_arena.aba.alloc(data.as_angle_bracketed_args());
+ self.lower_angle_bracketed_parameter_data(aba, ParamMode::Explicit, itctx).0
}
};
gen_args_ctor.into_generic_args(self)
} else {
self.arena.alloc(hir::GenericArgs::none())
};
- let mut itctx_tait = ImplTraitContext::TypeAliasesOpaqueTy;
+ let itctx_tait = &ImplTraitContext::TypeAliasesOpaqueTy;
let kind = match constraint.kind {
AssocConstraintKind::Equality { ref term } => {
// then to an opaque type).
//
// FIXME: this is only needed until `impl Trait` is allowed in type aliases.
- ImplTraitContext::Disallowed(_) if self.is_in_dyn_type => {
- (true, &mut itctx_tait)
- }
+ ImplTraitContext::Disallowed(_) if self.is_in_dyn_type => (true, itctx_tait),
// We are in the parameter position, but not within a dyn type:
//
self.with_dyn_type_scope(false, |this| {
let node_id = this.next_node_id();
- let ty = this.lower_ty(
- &Ty {
- id: node_id,
- kind: TyKind::ImplTrait(impl_trait_node_id, bounds.clone()),
- span: this.lower_span(constraint.span),
- tokens: None,
- },
- itctx,
- );
+ let ty = this.ast_arena.tys.alloc(Ty {
+ id: node_id,
+ kind: TyKind::ImplTrait(impl_trait_node_id, bounds.clone()),
+ span: this.lower_span(constraint.span),
+ tokens: None,
+ });
+ let ty = this.lower_ty(ty, itctx);
hir::TypeBindingKind::Equality { term: ty.into() }
})
fn lower_generic_arg(
&mut self,
arg: &ast::GenericArg,
- itctx: &mut ImplTraitContext,
+ itctx: &ImplTraitContext,
) -> hir::GenericArg<'hir> {
match arg {
ast::GenericArg::Lifetime(lt) => GenericArg::Lifetime(self.lower_lifetime(<)),
}
#[instrument(level = "debug", skip(self))]
- fn lower_ty(&mut self, t: &Ty, itctx: &mut ImplTraitContext) -> &'hir hir::Ty<'hir> {
+ fn lower_ty(&mut self, t: &Ty, itctx: &ImplTraitContext) -> &'hir hir::Ty<'hir> {
self.arena.alloc(self.lower_ty_direct(t, itctx))
}
qself: &Option<QSelf>,
path: &Path,
param_mode: ParamMode,
- itctx: &mut ImplTraitContext,
+ itctx: &ImplTraitContext,
) -> hir::Ty<'hir> {
// Check whether we should interpret this as a bare trait object.
// This check mirrors the one in late resolution. We only introduce this special case in
&& let Res::Def(DefKind::Trait | DefKind::TraitAlias, _) = partial_res.base_res()
{
let (bounds, lifetime_bound) = self.with_dyn_type_scope(true, |this| {
+ let poly_trait_ref = this.ast_arena.ptr.alloc(PolyTraitRef {
+ bound_generic_params: vec![],
+ trait_ref: TraitRef { path: path.clone(), ref_id: t.id },
+ span: t.span
+ });
let bound = this.lower_poly_trait_ref(
- &PolyTraitRef {
- bound_generic_params: vec![],
- trait_ref: TraitRef { path: path.clone(), ref_id: t.id },
- span: t.span
- },
+ poly_trait_ref,
itctx,
);
let bounds = this.arena.alloc_from_iter([bound]);
let lifetime_bound = this.elided_dyn_bound(t.span);
(bounds, lifetime_bound)
});
- let kind = hir::TyKind::TraitObject(bounds, lifetime_bound, TraitObjectSyntax::None);
+ let kind = hir::TyKind::TraitObject(bounds, &lifetime_bound, TraitObjectSyntax::None);
return hir::Ty { kind, span: self.lower_span(t.span), hir_id: self.next_id() };
}
self.ty(span, hir::TyKind::Tup(tys))
}
- fn lower_ty_direct(&mut self, t: &Ty, itctx: &mut ImplTraitContext) -> hir::Ty<'hir> {
+ fn lower_ty_direct(&mut self, t: &Ty, itctx: &ImplTraitContext) -> hir::Ty<'hir> {
let kind = match t.kind {
TyKind::Infer => hir::TyKind::Infer,
TyKind::Err => hir::TyKind::Err,
generic_params,
unsafety: self.lower_unsafety(f.unsafety),
abi: self.lower_extern(f.ext),
- decl: self.lower_fn_decl(&f.decl, None, FnDeclKind::Pointer, None),
+ decl: self.lower_fn_decl(&f.decl, None, t.span, FnDeclKind::Pointer, None),
param_names: self.lower_fn_params_to_names(&f.decl),
}))
}
return self.lower_path_ty(t, qself, path, ParamMode::Explicit, itctx);
}
TyKind::ImplicitSelf => {
- let hir_id = self.lower_node_id(t.id);
+ let hir_id = self.next_id();
let res = self.expect_full_res(t.id);
let res = self.lower_res(res);
hir::TyKind::Path(hir::QPath::Resolved(
TyKind::ImplTrait(def_node_id, ref bounds) => {
let span = t.span;
match itctx {
- ImplTraitContext::ReturnPositionOpaqueTy { origin } => {
- self.lower_opaque_impl_trait(span, *origin, def_node_id, bounds, itctx)
- }
- ImplTraitContext::TypeAliasesOpaqueTy => {
- let mut nested_itctx = ImplTraitContext::TypeAliasesOpaqueTy;
- self.lower_opaque_impl_trait(
+ ImplTraitContext::ReturnPositionOpaqueTy { origin, in_trait } => self
+ .lower_opaque_impl_trait(
span,
- hir::OpaqueTyOrigin::TyAlias,
+ *origin,
def_node_id,
bounds,
- &mut nested_itctx,
- )
- }
+ *in_trait,
+ itctx,
+ ),
+ ImplTraitContext::TypeAliasesOpaqueTy => self.lower_opaque_impl_trait(
+ span,
+ hir::OpaqueTyOrigin::TyAlias,
+ def_node_id,
+ bounds,
+ false,
+ &ImplTraitContext::TypeAliasesOpaqueTy,
+ ),
ImplTraitContext::Universal => {
let span = t.span;
let ident = Ident::from_str_and_span(&pprust::ty_to_string(t), span);
}
path
}
+ ImplTraitContext::Disallowed(
+ position @ (ImplTraitPosition::TraitReturn | ImplTraitPosition::ImplReturn),
+ ) => {
+ self.tcx
+ .sess
+ .create_feature_err(
+ MisplacedImplTrait {
+ span: t.span,
+ position: DiagnosticArgFromDisplay(&position),
+ },
+ sym::return_position_impl_trait_in_trait,
+ )
+ .emit();
+ hir::TyKind::Err
+ }
ImplTraitContext::Disallowed(position) => {
self.tcx.sess.emit_err(MisplacedImplTrait {
span: t.span,
origin: hir::OpaqueTyOrigin,
opaque_ty_node_id: NodeId,
bounds: &GenericBounds,
- itctx: &mut ImplTraitContext,
+ in_trait: bool,
+ itctx: &ImplTraitContext,
) -> hir::TyKind<'hir> {
// 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
}),
bounds: hir_bounds,
origin,
+ in_trait,
};
debug!(?opaque_ty_item);
debug!(?lifetimes);
// `impl Trait` now just becomes `Foo<'a, 'b, ..>`.
- hir::TyKind::OpaqueDef(hir::ItemId { def_id: opaque_ty_def_id }, lifetimes)
+ hir::TyKind::OpaqueDef(hir::ItemId { def_id: opaque_ty_def_id }, lifetimes, in_trait)
}
/// Registers a new opaque type with the proper `NodeId`s and
// `fn_def_id`: if `Some`, impl Trait arguments are lowered into generic parameters on the
// given DefId, otherwise impl Trait is disallowed. Must be `Some` if
// `make_ret_async` is also `Some`.
- // `impl_trait_return_allow`: determines whether `impl Trait` can be used in return position.
- // This guards against trait declarations and implementations where `impl Trait` is
- // disallowed.
// `make_ret_async`: if `Some`, converts `-> T` into `-> impl Future<Output = T>` in the
// return type. This is used for `async fn` declarations. The `NodeId` is the ID of the
- // return type `impl Trait` item.
+ // return type `impl Trait` item, and the `Span` points to the `async` keyword.
#[instrument(level = "debug", skip(self))]
fn lower_fn_decl(
&mut self,
decl: &FnDecl,
fn_node_id: Option<NodeId>,
+ fn_span: Span,
kind: FnDeclKind,
- make_ret_async: Option<NodeId>,
+ make_ret_async: Option<(NodeId, Span)>,
) -> &'hir hir::FnDecl<'hir> {
let c_variadic = decl.c_variadic();
}
let inputs = self.arena.alloc_from_iter(inputs.iter().map(|param| {
if fn_node_id.is_some() {
- self.lower_ty_direct(¶m.ty, &mut ImplTraitContext::Universal)
+ self.lower_ty_direct(¶m.ty, &ImplTraitContext::Universal)
} else {
self.lower_ty_direct(
¶m.ty,
- &mut ImplTraitContext::Disallowed(match kind {
+ &ImplTraitContext::Disallowed(match kind {
FnDeclKind::Fn | FnDeclKind::Inherent => {
unreachable!("fn should allow in-band lifetimes")
}
}
}));
- let output = if let Some(ret_id) = make_ret_async {
- self.lower_async_fn_ret_ty(
- &decl.output,
- fn_node_id.expect("`make_ret_async` but no `fn_def_id`"),
- ret_id,
- )
+ let output = if let Some((ret_id, span)) = make_ret_async {
+ match kind {
+ FnDeclKind::Trait => {
+ if !kind.impl_trait_in_trait_allowed(self.tcx) {
+ self.tcx
+ .sess
+ .create_feature_err(
+ TraitFnAsync { fn_span, span },
+ sym::return_position_impl_trait_in_trait,
+ )
+ .emit();
+ }
+ self.lower_async_fn_ret_ty(
+ &decl.output,
+ fn_node_id.expect("`make_ret_async` but no `fn_def_id`"),
+ ret_id,
+ true,
+ )
+ }
+ _ => {
+ if !kind.impl_trait_return_allowed(self.tcx) {
+ if kind == FnDeclKind::Impl {
+ self.tcx
+ .sess
+ .create_feature_err(
+ TraitFnAsync { fn_span, span },
+ sym::return_position_impl_trait_in_trait,
+ )
+ .emit();
+ } else {
+ self.tcx.sess.emit_err(TraitFnAsync { fn_span, span });
+ }
+ }
+ self.lower_async_fn_ret_ty(
+ &decl.output,
+ fn_node_id.expect("`make_ret_async` but no `fn_def_id`"),
+ ret_id,
+ false,
+ )
+ }
+ }
} else {
match decl.output {
FnRetTy::Ty(ref ty) => {
let mut context = match fn_node_id {
- Some(fn_node_id) if kind.impl_trait_return_allowed() => {
+ Some(fn_node_id) if kind.impl_trait_return_allowed(self.tcx) => {
let fn_def_id = self.local_def_id(fn_node_id);
ImplTraitContext::ReturnPositionOpaqueTy {
origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id),
+ in_trait: false,
+ }
+ }
+ Some(fn_node_id) if kind.impl_trait_in_trait_allowed(self.tcx) => {
+ let fn_def_id = self.local_def_id(fn_node_id);
+ ImplTraitContext::ReturnPositionOpaqueTy {
+ origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id),
+ in_trait: true,
}
}
_ => ImplTraitContext::Disallowed(match kind {
output: &FnRetTy,
fn_node_id: NodeId,
opaque_ty_node_id: NodeId,
+ in_trait: bool,
) -> hir::FnRetTy<'hir> {
let span = output.span();
//
// Then, we will create `fn foo(..) -> Foo<'_, '_>`, and
// hence the elision takes place at the fn site.
- let future_bound =
- this.lower_async_fn_output_type_to_future_bound(output, fn_def_id, span);
+ let future_bound = this.lower_async_fn_output_type_to_future_bound(
+ output,
+ span,
+ ImplTraitContext::ReturnPositionOpaqueTy {
+ origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id),
+ in_trait,
+ },
+ );
let generic_params = this.arena.alloc_from_iter(collected_lifetimes.iter().map(
|&(new_node_id, lifetime, _)| {
}),
bounds: arena_vec![this; future_bound],
origin: hir::OpaqueTyOrigin::AsyncFn(fn_def_id),
+ in_trait,
};
trace!("exist ty from async fn def id: {:#?}", opaque_ty_def_id);
let res = res.unwrap_or(
self.resolver.get_lifetime_res(lifetime.id).unwrap_or(LifetimeRes::Error),
);
- let l = self.new_named_lifetime_with_res(id, span, ident, res);
- hir::GenericArg::Lifetime(l)
+ hir::GenericArg::Lifetime(self.new_named_lifetime_with_res(id, span, ident, res))
},
));
// 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::OpaqueDef(hir::ItemId { def_id: opaque_ty_def_id }, generic_args);
+ let opaque_ty_ref = hir::TyKind::OpaqueDef(
+ hir::ItemId { def_id: opaque_ty_def_id },
+ generic_args,
+ in_trait,
+ );
let opaque_ty = self.ty(opaque_ty_span, opaque_ty_ref);
hir::FnRetTy::Return(self.arena.alloc(opaque_ty))
}
fn lower_async_fn_output_type_to_future_bound(
&mut self,
output: &FnRetTy,
- fn_def_id: LocalDefId,
span: Span,
+ mut nested_impl_trait_context: ImplTraitContext,
) -> hir::GenericBound<'hir> {
// Compute the `T` in `Future<Output = T>` from the return type.
let output_ty = match output {
// Not `OpaqueTyOrigin::AsyncFn`: that's only used for the
// `impl Future` opaque type that `async fn` implicitly
// generates.
- let mut context = ImplTraitContext::ReturnPositionOpaqueTy {
- origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id),
- };
- self.lower_ty(ty, &mut context)
+ self.lower_ty(ty, &mut nested_impl_trait_context)
}
FnRetTy::Default(ret_ty_span) => self.arena.alloc(self.ty_tup(*ret_ty_span, &[])),
};
fn lower_param_bound(
&mut self,
tpb: &GenericBound,
- itctx: &mut ImplTraitContext,
+ itctx: &ImplTraitContext,
) -> hir::GenericBound<'hir> {
match tpb {
GenericBound::Trait(p, modifier) => hir::GenericBound::Trait(
}
}
- fn lower_lifetime(&mut self, l: &Lifetime) -> hir::Lifetime {
+ fn lower_lifetime(&mut self, l: &Lifetime) -> &'hir hir::Lifetime {
let span = self.lower_span(l.ident.span);
let ident = self.lower_ident(l.ident);
self.new_named_lifetime(l.id, l.id, span, ident)
span: Span,
ident: Ident,
res: LifetimeRes,
- ) -> hir::Lifetime {
+ ) -> &'hir hir::Lifetime {
let name = match res {
LifetimeRes::Param { param, .. } => {
let p_name = ParamName::Plain(ident);
};
debug!(?name);
- hir::Lifetime { hir_id: self.lower_node_id(id), span: self.lower_span(span), name }
+ self.arena.alloc(hir::Lifetime {
+ hir_id: self.lower_node_id(id),
+ span: self.lower_span(span),
+ name,
+ })
}
#[instrument(level = "debug", skip(self))]
new_id: NodeId,
span: Span,
ident: Ident,
- ) -> hir::Lifetime {
+ ) -> &'hir hir::Lifetime {
let res = self.resolver.get_lifetime_res(id).unwrap_or(LifetimeRes::Error);
self.new_named_lifetime_with_res(new_id, span, ident, res)
}
GenericParamKind::Type { ref default, .. } => {
let kind = hir::GenericParamKind::Type {
default: default.as_ref().map(|x| {
- self.lower_ty(x, &mut ImplTraitContext::Disallowed(ImplTraitPosition::Type))
+ self.lower_ty(x, &ImplTraitContext::Disallowed(ImplTraitPosition::Type))
}),
synthetic: false,
};
(hir::ParamName::Plain(self.lower_ident(param.ident)), kind)
}
GenericParamKind::Const { ref ty, kw_span: _, ref default } => {
- let ty =
- self.lower_ty(&ty, &mut ImplTraitContext::Disallowed(ImplTraitPosition::Type));
+ let ty = self.lower_ty(&ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Type));
let default = default.as_ref().map(|def| self.lower_anon_const(def));
(
hir::ParamName::Plain(self.lower_ident(param.ident)),
}
}
- fn lower_trait_ref(
- &mut self,
- p: &TraitRef,
- itctx: &mut ImplTraitContext,
- ) -> hir::TraitRef<'hir> {
+ fn lower_trait_ref(&mut self, p: &TraitRef, itctx: &ImplTraitContext) -> hir::TraitRef<'hir> {
let path = match self.lower_qpath(p.ref_id, &None, &p.path, ParamMode::Explicit, itctx) {
hir::QPath::Resolved(None, path) => path,
qpath => panic!("lower_trait_ref: unexpected QPath `{:?}`", qpath),
fn lower_poly_trait_ref(
&mut self,
p: &PolyTraitRef,
- itctx: &mut ImplTraitContext,
+ itctx: &ImplTraitContext,
) -> hir::PolyTraitRef<'hir> {
let bound_generic_params =
self.lower_lifetime_binder(p.trait_ref.ref_id, &p.bound_generic_params);
hir::PolyTraitRef { bound_generic_params, trait_ref, span: self.lower_span(p.span) }
}
- fn lower_mt(&mut self, mt: &MutTy, itctx: &mut ImplTraitContext) -> hir::MutTy<'hir> {
+ fn lower_mt(&mut self, mt: &MutTy, itctx: &ImplTraitContext) -> hir::MutTy<'hir> {
hir::MutTy { ty: self.lower_ty(&mt.ty, itctx), mutbl: mt.mutbl }
}
fn lower_param_bounds(
&mut self,
bounds: &[GenericBound],
- itctx: &mut ImplTraitContext,
+ itctx: &ImplTraitContext,
) -> hir::GenericBounds<'hir> {
self.arena.alloc_from_iter(self.lower_param_bounds_mut(bounds, itctx))
}
- fn lower_param_bounds_mut<'s, 'b>(
+ fn lower_param_bounds_mut<'s>(
&'s mut self,
bounds: &'s [GenericBound],
- itctx: &'b mut ImplTraitContext,
- ) -> impl Iterator<Item = hir::GenericBound<'hir>> + Captures<'s> + Captures<'a> + Captures<'b>
- {
+ itctx: &'s ImplTraitContext,
+ ) -> impl Iterator<Item = hir::GenericBound<'hir>> + Captures<'s> + Captures<'a> {
bounds.iter().map(move |bound| self.lower_param_bound(bound, itctx))
}
node_id,
&GenericParamKind::Type { default: None },
bounds,
- &mut ImplTraitContext::Universal,
+ &ImplTraitContext::Universal,
hir::PredicateOrigin::ImplTrait,
);
/// 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 {
+ fn elided_dyn_bound(&mut self, span: Span) -> &'hir hir::Lifetime {
let r = hir::Lifetime {
hir_id: self.next_id(),
span: self.lower_span(span),
name: hir::LifetimeName::ImplicitObjectLifetimeDefault,
};
debug!("elided_dyn_bound: r={:?}", r);
- r
+ self.arena.alloc(r)
}
}