From 5be30f9d79b2e08128704ddb29f7925e2fb3ef88 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 2 Sep 2022 15:57:31 +0000 Subject: [PATCH] Make async fn in traits work --- compiler/rustc_ast/src/ast.rs | 4 ++-- compiler/rustc_ast_lowering/src/errors.rs | 11 ++++++++++ compiler/rustc_ast_lowering/src/expr.rs | 5 +++-- compiler/rustc_ast_lowering/src/item.rs | 14 +++++++++---- compiler/rustc_ast_lowering/src/lib.rs | 21 ++++++++++++------- .../rustc_ast_passes/src/ast_validation.rs | 7 ------- compiler/rustc_ast_passes/src/errors.rs | 11 ---------- .../locales/en-US/ast_lowering.ftl | 6 ++++++ .../locales/en-US/ast_passes.ftl | 6 ------ compiler/rustc_resolve/src/late.rs | 2 +- 10 files changed, 46 insertions(+), 41 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index e38572f609b3..c07ba88ae204 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -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 { + 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, } } diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs index 4adeaef9bbfa..c87d0ca96570 100644 --- a/compiler/rustc_ast_lowering/src/errors.rs +++ b/compiler/rustc_ast_lowering/src/errors.rs @@ -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, +} diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 5346f1ced829..f929549d7044 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -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, diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 9e05fbbdc197..96e281ca5c84 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -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, + 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) }) } diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 2e8fcd7dca45..de7e64351b94 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -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` 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, + fn_span: Span, kind: FnDeclKind, - make_ret_async: Option, + 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`"), diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index d6d8881a53a1..6c754f38d144 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -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); } } diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index 21467e576519..4f3b09c58711 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -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 { diff --git a/compiler/rustc_error_messages/locales/en-US/ast_lowering.ftl b/compiler/rustc_error_messages/locales/en-US/ast_lowering.ftl index f2790531aba4..c45e045b4dba 100644 --- a/compiler/rustc_error_messages/locales/en-US/ast_lowering.ftl +++ b/compiler/rustc_error_messages/locales/en-US/ast_lowering.ftl @@ -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 diff --git a/compiler/rustc_error_messages/locales/en-US/ast_passes.ftl b/compiler/rustc_error_messages/locales/en-US/ast_passes.ftl index d7108e1e2de3..e5cd1142b20c 100644 --- a/compiler/rustc_error_messages/locales/en-US/ast_passes.ftl +++ b/compiler/rustc_error_messages/locales/en-US/ast_passes.ftl @@ -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 diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index b37feb15890b..2d6e76c451bf 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -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