Make async fn in traits work
This commit is contained in:
parent
ed2a32f22c
commit
5be30f9d79
10 changed files with 46 additions and 41 deletions
|
@ -2367,9 +2367,9 @@ impl Async {
|
|||
}
|
||||
|
||||
/// In this case this is an `async` return, the `NodeId` for the generated `impl Trait` item.
|
||||
pub fn opt_return_id(self) -> Option<NodeId> {
|
||||
pub fn opt_return_id(self) -> Option<(NodeId, Span)> {
|
||||
match self {
|
||||
Async::Yes { return_impl_trait_id, .. } => Some(return_impl_trait_id),
|
||||
Async::Yes { return_impl_trait_id, span, .. } => Some((return_impl_trait_id, span)),
|
||||
Async::No => None,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -334,3 +334,14 @@ pub struct InclusiveRangeWithNoEnd {
|
|||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic, Clone, Copy)]
|
||||
#[diag(ast_lowering::trait_fn_async, code = "E0706")]
|
||||
#[note]
|
||||
#[note(ast_lowering::note2)]
|
||||
pub struct TraitFnAsync {
|
||||
#[primary_span]
|
||||
pub fn_span: Span,
|
||||
#[label]
|
||||
pub span: Span,
|
||||
}
|
||||
|
|
|
@ -851,7 +851,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
|
||||
self.lower_lifetime_binder(closure_id, generic_params, |lctx, bound_generic_params| {
|
||||
// Lower outside new scope to preserve `is_in_loop_condition`.
|
||||
let fn_decl = lctx.lower_fn_decl(decl, None, FnDeclKind::Closure, None);
|
||||
let fn_decl = lctx.lower_fn_decl(decl, None, fn_decl_span, FnDeclKind::Closure, None);
|
||||
|
||||
let c = lctx.arena.alloc(hir::Closure {
|
||||
binder: binder_clause,
|
||||
|
@ -955,7 +955,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
// We need to lower the declaration outside the new scope, because we
|
||||
// have to conserve the state of being inside a loop condition for the
|
||||
// closure argument types.
|
||||
let fn_decl = lctx.lower_fn_decl(&outer_decl, None, FnDeclKind::Closure, None);
|
||||
let fn_decl =
|
||||
lctx.lower_fn_decl(&outer_decl, None, fn_decl_span, FnDeclKind::Closure, None);
|
||||
|
||||
let c = lctx.arena.alloc(hir::Closure {
|
||||
binder: binder_clause,
|
||||
|
|
|
@ -269,7 +269,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
let mut itctx = ImplTraitContext::Universal;
|
||||
let (generics, decl) = this.lower_generics(generics, id, &mut itctx, |this| {
|
||||
let ret_id = asyncness.opt_return_id();
|
||||
this.lower_fn_decl(&decl, Some(id), FnDeclKind::Fn, ret_id)
|
||||
this.lower_fn_decl(&decl, Some(id), fn_sig_span, FnDeclKind::Fn, ret_id)
|
||||
});
|
||||
let sig = hir::FnSig {
|
||||
decl,
|
||||
|
@ -661,7 +661,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
self.lower_generics(generics, i.id, &mut itctx, |this| {
|
||||
(
|
||||
// Disallow `impl Trait` in foreign items.
|
||||
this.lower_fn_decl(fdec, None, FnDeclKind::ExternFn, None),
|
||||
this.lower_fn_decl(
|
||||
fdec,
|
||||
None,
|
||||
sig.span,
|
||||
FnDeclKind::ExternFn,
|
||||
None,
|
||||
),
|
||||
this.lower_fn_params_to_names(fdec),
|
||||
)
|
||||
});
|
||||
|
@ -1240,12 +1246,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
sig: &FnSig,
|
||||
id: NodeId,
|
||||
kind: FnDeclKind,
|
||||
is_async: Option<NodeId>,
|
||||
is_async: Option<(NodeId, Span)>,
|
||||
) -> (&'hir hir::Generics<'hir>, hir::FnSig<'hir>) {
|
||||
let header = self.lower_fn_header(sig.header);
|
||||
let mut itctx = ImplTraitContext::Universal;
|
||||
let (generics, decl) = self.lower_generics(generics, id, &mut itctx, |this| {
|
||||
this.lower_fn_decl(&sig.decl, Some(id), kind, is_async)
|
||||
this.lower_fn_decl(&sig.decl, Some(id), sig.span, kind, is_async)
|
||||
});
|
||||
(generics, hir::FnSig { header, decl, span: self.lower_span(sig.span) })
|
||||
}
|
||||
|
|
|
@ -42,7 +42,7 @@
|
|||
#[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;
|
||||
|
@ -1274,7 +1274,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
generic_params,
|
||||
unsafety: lctx.lower_unsafety(f.unsafety),
|
||||
abi: lctx.lower_extern(f.ext),
|
||||
decl: lctx.lower_fn_decl(&f.decl, None, FnDeclKind::Pointer, None),
|
||||
decl: lctx.lower_fn_decl(&f.decl, None, t.span, FnDeclKind::Pointer, None),
|
||||
param_names: lctx.lower_fn_params_to_names(&f.decl),
|
||||
}))
|
||||
})
|
||||
|
@ -1677,19 +1677,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
// `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();
|
||||
|
||||
|
@ -1720,7 +1718,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
}
|
||||
}));
|
||||
|
||||
let output = if let Some(ret_id) = make_ret_async {
|
||||
let output = if let Some((ret_id, span)) = make_ret_async {
|
||||
if !self.tcx.features().return_position_impl_trait_in_trait {
|
||||
self.tcx.sess.emit_feature_err(
|
||||
TraitFnAsync { fn_span, span },
|
||||
sym::return_position_impl_trait_in_trait,
|
||||
);
|
||||
}
|
||||
|
||||
self.lower_async_fn_ret_ty(
|
||||
&decl.output,
|
||||
fn_node_id.expect("`make_ret_async` but no `fn_def_id`"),
|
||||
|
|
|
@ -290,12 +290,6 @@ impl<'a> AstValidator<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn check_trait_fn_not_async(&self, fn_span: Span, asyncness: Async) {
|
||||
if let Async::Yes { span, .. } = asyncness {
|
||||
self.session.emit_err(TraitFnAsync { fn_span, span });
|
||||
}
|
||||
}
|
||||
|
||||
fn check_trait_fn_not_const(&self, constness: Const) {
|
||||
if let Const::Yes(span) = constness {
|
||||
self.session.emit_err(TraitFnConst { span });
|
||||
|
@ -1596,7 +1590,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
self.invalid_visibility(&item.vis, None);
|
||||
if let AssocItemKind::Fn(box Fn { sig, .. }) = &item.kind {
|
||||
self.check_trait_fn_not_const(sig.header.constness);
|
||||
self.check_trait_fn_not_async(item.span, sig.header.asyncness);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -79,17 +79,6 @@ pub enum InvalidVisibilityNote {
|
|||
IndividualForeignItems,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(ast_passes::trait_fn_async, code = "E0706")]
|
||||
#[note]
|
||||
#[note(ast_passes::note2)]
|
||||
pub struct TraitFnAsync {
|
||||
#[primary_span]
|
||||
pub fn_span: Span,
|
||||
#[label]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(ast_passes::trait_fn_const, code = "E0379")]
|
||||
pub struct TraitFnConst {
|
||||
|
|
|
@ -131,3 +131,9 @@ ast_lowering_arbitrary_expression_in_pattern =
|
|||
arbitrary expressions aren't allowed in patterns
|
||||
|
||||
ast_lowering_inclusive_range_with_no_end = inclusive range with no end
|
||||
|
||||
ast_lowering_trait_fn_async =
|
||||
functions in traits cannot be declared `async`
|
||||
.label = `async` because of this
|
||||
.note = `async` trait functions are not currently supported
|
||||
.note2 = consider using the `async-trait` crate: https://crates.io/crates/async-trait
|
||||
|
|
|
@ -26,12 +26,6 @@ ast_passes_invalid_visibility =
|
|||
.individual_impl_items = place qualifiers on individual impl items instead
|
||||
.individual_foreign_items = place qualifiers on individual foreign items instead
|
||||
|
||||
ast_passes_trait_fn_async =
|
||||
functions in traits cannot be declared `async`
|
||||
.label = `async` because of this
|
||||
.note = `async` trait functions are not currently supported
|
||||
.note2 = consider using the `async-trait` crate: https://crates.io/crates/async-trait
|
||||
|
||||
ast_passes_trait_fn_const =
|
||||
functions in traits cannot be declared const
|
||||
.label = functions in traits cannot be const
|
||||
|
|
|
@ -851,7 +851,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
|
|||
// We include all lifetime parameters, either named or "Fresh".
|
||||
// The order of those parameters does not matter, as long as it is
|
||||
// deterministic.
|
||||
if let Some(async_node_id) = async_node_id {
|
||||
if let Some((async_node_id, _)) = async_node_id {
|
||||
let mut extra_lifetime_params = this
|
||||
.r
|
||||
.extra_lifetime_params_map
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue