Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stabilize async fn and return-position impl Trait in trait #115822

Merged
merged 3 commits into from Oct 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 0 additions & 6 deletions compiler/rustc_ast_lowering/messages.ftl
Expand Up @@ -136,12 +136,6 @@ ast_lowering_template_modifier = template modifier

ast_lowering_this_not_async = this is not `async`

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

ast_lowering_underscore_expr_lhs_assign =
in expressions, `_` can only be used on the left-hand side of an assignment
.label = `_` not allowed here
Expand Down
11 changes: 0 additions & 11 deletions compiler/rustc_ast_lowering/src/errors.rs
Expand Up @@ -354,17 +354,6 @@ pub struct InclusiveRangeWithNoEnd {
pub span: Span,
}

#[derive(Diagnostic, 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,
}

#[derive(Diagnostic)]
pub enum BadReturnTypeNotation {
#[diag(ast_lowering_bad_return_type_notation_inputs)]
Expand Down
77 changes: 15 additions & 62 deletions compiler/rustc_ast_lowering/src/lib.rs
Expand Up @@ -40,7 +40,7 @@
#[macro_use]
extern crate tracing;

use crate::errors::{AssocTyParentheses, AssocTyParenthesesSub, MisplacedImplTrait, TraitFnAsync};
use crate::errors::{AssocTyParentheses, AssocTyParenthesesSub, MisplacedImplTrait};

use rustc_ast::ptr::P;
use rustc_ast::visit;
Expand Down Expand Up @@ -271,8 +271,6 @@ enum ImplTraitPosition {
ClosureReturn,
PointerReturn,
FnTraitReturn,
TraitReturn,
ImplReturn,
GenericDefault,
ConstTy,
StaticTy,
Expand Down Expand Up @@ -302,8 +300,6 @@ impl std::fmt::Display for ImplTraitPosition {
ImplTraitPosition::ClosureReturn => "closure return types",
ImplTraitPosition::PointerReturn => "`fn` pointer return types",
ImplTraitPosition::FnTraitReturn => "`Fn` trait return types",
ImplTraitPosition::TraitReturn => "trait method return types",
ImplTraitPosition::ImplReturn => "`impl` method return types",
ImplTraitPosition::GenericDefault => "generic parameter defaults",
ImplTraitPosition::ConstTy => "const types",
ImplTraitPosition::StaticTy => "static types",
Expand Down Expand Up @@ -334,20 +330,9 @@ impl FnDeclKind {
matches!(self, FnDeclKind::Fn | FnDeclKind::Inherent | FnDeclKind::Impl | FnDeclKind::Trait)
}

fn return_impl_trait_allowed(&self, tcx: TyCtxt<'_>) -> bool {
fn return_impl_trait_allowed(&self) -> bool {
match self {
FnDeclKind::Fn | FnDeclKind::Inherent => true,
FnDeclKind::Impl if tcx.features().return_position_impl_trait_in_trait => true,
FnDeclKind::Trait if tcx.features().return_position_impl_trait_in_trait => true,
_ => false,
}
}

fn async_fn_allowed(&self, tcx: TyCtxt<'_>) -> bool {
match self {
FnDeclKind::Fn | FnDeclKind::Inherent => true,
FnDeclKind::Impl if tcx.features().async_fn_in_trait => true,
FnDeclKind::Trait if tcx.features().async_fn_in_trait => true,
FnDeclKind::Fn | FnDeclKind::Inherent | FnDeclKind::Impl | FnDeclKind::Trait => true,
_ => false,
}
}
Expand Down Expand Up @@ -1805,53 +1790,30 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
self.lower_ty_direct(&param.ty, &itctx)
}));

let output = if let Some((ret_id, span)) = make_ret_async {
if !kind.async_fn_allowed(self.tcx) {
match kind {
FnDeclKind::Trait | FnDeclKind::Impl => {
self.tcx
.sess
.create_feature_err(
TraitFnAsync { fn_span, span },
sym::async_fn_in_trait,
)
.emit();
}
_ => {
self.tcx.sess.emit_err(TraitFnAsync { fn_span, span });
}
}
}

let output = if let Some((ret_id, _span)) = make_ret_async {
let fn_def_id = self.local_def_id(fn_node_id);
self.lower_async_fn_ret_ty(&decl.output, fn_def_id, ret_id, kind, fn_span)
} else {
match &decl.output {
FnRetTy::Ty(ty) => {
let context = if kind.return_impl_trait_allowed(self.tcx) {
let context = if kind.return_impl_trait_allowed() {
let fn_def_id = self.local_def_id(fn_node_id);
ImplTraitContext::ReturnPositionOpaqueTy {
origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id),
fn_kind: kind,
}
} else {
let position = match kind {
FnDeclKind::Fn | FnDeclKind::Inherent => {
unreachable!("fn should allow in-band lifetimes")
ImplTraitContext::Disallowed(match kind {
FnDeclKind::Fn
| FnDeclKind::Inherent
| FnDeclKind::Trait
| FnDeclKind::Impl => {
unreachable!("fn should allow return-position impl trait in traits")
}
FnDeclKind::ExternFn => ImplTraitPosition::ExternFnReturn,
FnDeclKind::Closure => ImplTraitPosition::ClosureReturn,
FnDeclKind::Pointer => ImplTraitPosition::PointerReturn,
FnDeclKind::Trait => ImplTraitPosition::TraitReturn,
FnDeclKind::Impl => ImplTraitPosition::ImplReturn,
};
match kind {
FnDeclKind::Trait | FnDeclKind::Impl => ImplTraitContext::FeatureGated(
position,
sym::return_position_impl_trait_in_trait,
),
_ => ImplTraitContext::Disallowed(position),
}
})
};
hir::FnRetTy::Return(self.lower_ty(ty, &context))
}
Expand Down Expand Up @@ -1924,18 +1886,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
let future_bound = this.lower_async_fn_output_type_to_future_bound(
output,
span,
if let FnDeclKind::Trait = fn_kind
&& !this.tcx.features().return_position_impl_trait_in_trait
{
ImplTraitContext::FeatureGated(
ImplTraitPosition::TraitReturn,
sym::return_position_impl_trait_in_trait,
)
} else {
ImplTraitContext::ReturnPositionOpaqueTy {
origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id),
fn_kind,
}
ImplTraitContext::ReturnPositionOpaqueTy {
origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id),
fn_kind,
},
);
arena_vec![this; future_bound]
Expand Down
6 changes: 4 additions & 2 deletions compiler/rustc_error_codes/src/error_codes/E0706.md
@@ -1,8 +1,10 @@
#### Note: this error code is no longer emitted by the compiler.

`async fn`s are not yet supported in traits in Rust.

Erroneous code example:

```compile_fail,edition2018
```ignore,edition2018
trait T {
// Neither case is currently supported.
async fn foo() {}
Expand All @@ -13,7 +15,7 @@ trait T {
`async fn`s return an `impl Future`, making the following two examples
equivalent:

```edition2018,ignore (example-of-desugaring-equivalence)
```ignore,edition2018 (example-of-desugaring-equivalence)
async fn foo() -> User {
unimplemented!()
}
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_feature/src/accepted.rs
compiler-errors marked this conversation as resolved.
Show resolved Hide resolved
Expand Up @@ -67,6 +67,8 @@ declare_features! (
(accepted, associated_types, "1.0.0", None, None),
/// Allows free and inherent `async fn`s, `async` blocks, and `<expr>.await` expressions.
(accepted, async_await, "1.39.0", Some(50547), None),
/// Allows async functions to be declared, implemented, and used in traits.
(accepted, async_fn_in_trait, "CURRENT_RUSTC_VERSION", Some(91611), None),
/// Allows all literals in attribute lists and values of key-value pairs.
(accepted, attr_literals, "1.30.0", Some(34981), None),
/// Allows overloading augmented assignment operations like `a += b`.
Expand Down Expand Up @@ -306,6 +308,8 @@ declare_features! (
(accepted, repr_packed, "1.33.0", Some(33158), None),
/// Allows `#[repr(transparent)]` attribute on newtype structs.
(accepted, repr_transparent, "1.28.0", Some(43036), None),
/// Allows return-position `impl Trait` in traits.
(accepted, return_position_impl_trait_in_trait, "CURRENT_RUSTC_VERSION", Some(91611), None),
/// Allows code like `let x: &'static u32 = &42` to work (RFC 1414).
(accepted, rvalue_static_promotion, "1.21.0", Some(38865), None),
/// Allows `Self` in type definitions (RFC 2300).
Expand Down
4 changes: 0 additions & 4 deletions compiler/rustc_feature/src/active.rs
Expand Up @@ -351,8 +351,6 @@ declare_features! (
(active, associated_type_defaults, "1.2.0", Some(29661), None),
/// Allows `async || body` closures.
(active, async_closure, "1.37.0", Some(62290), None),
/// Allows async functions to be declared, implemented, and used in traits.
(active, async_fn_in_trait, "1.66.0", Some(91611), None),
/// Allows `#[track_caller]` on async functions.
(active, async_fn_track_caller, "1.73.0", Some(110011), None),
/// Allows builtin # foo() syntax
Expand Down Expand Up @@ -551,8 +549,6 @@ declare_features! (
(incomplete, repr128, "1.16.0", Some(56071), None),
/// Allows `repr(simd)` and importing the various simd intrinsics.
(active, repr_simd, "1.4.0", Some(27731), None),
/// Allows return-position `impl Trait` in traits.
(active, return_position_impl_trait_in_trait, "1.65.0", Some(91611), None),
/// Allows bounding the return type of AFIT/RPITIT.
(incomplete, return_type_notation, "1.70.0", Some(109417), None),
/// Allows `extern "rust-cold"`.
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_hir_analysis/src/check/check.rs
Expand Up @@ -783,21 +783,21 @@ fn check_impl_items_against_trait<'tcx>(
let (msg, feature) = if tcx.asyncness(def_id).is_async() {
(
format!("async {descr} in trait cannot be specialized"),
sym::async_fn_in_trait,
"async functions in traits",
)
} else {
(
format!(
"{descr} with return-position `impl Trait` in trait cannot be specialized"
),
sym::return_position_impl_trait_in_trait,
"return position `impl Trait` in traits",
)
};
tcx.sess
.struct_span_err(tcx.def_span(def_id), msg)
.note(format!(
"specialization behaves in inconsistent and \
surprising ways with `#![feature({feature})]`, \
surprising ways with {feature}, \
and for now is disallowed"
))
.emit();
Expand Down
2 changes: 0 additions & 2 deletions compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
Expand Up @@ -633,8 +633,6 @@ fn compare_asyncness<'tcx>(
/// For example, given the sample code:
///
/// ```
/// #![feature(return_position_impl_trait_in_trait)]
///
/// use std::ops::Deref;
///
/// trait Foo {
Expand Down
3 changes: 0 additions & 3 deletions compiler/rustc_lint/src/async_fn_in_trait.rs
Expand Up @@ -11,7 +11,6 @@ declare_lint! {
/// ### Example
///
/// ```rust
/// # #![feature(async_fn_in_trait)]
/// pub trait Trait {
/// async fn method(&self);
/// }
Expand All @@ -33,7 +32,6 @@ declare_lint! {
/// For example, this code is invalid:
///
/// ```rust,compile_fail
/// # #![feature(async_fn_in_trait)]
/// pub trait Trait {
/// async fn method(&self) {}
/// }
Expand All @@ -51,7 +49,6 @@ declare_lint! {
/// For example, instead of:
///
/// ```rust
/// # #![feature(async_fn_in_trait)]
/// pub trait Trait {
/// async fn method(&self) {}
/// }
Expand Down
1 change: 0 additions & 1 deletion compiler/rustc_lint_defs/src/builtin.rs
Expand Up @@ -4574,7 +4574,6 @@ declare_lint! {
/// ### Example
///
/// ```rust,compile_fail
/// #![feature(return_position_impl_trait_in_trait)]
/// #![deny(refining_impl_trait)]
///
/// use std::fmt::Display;
Expand Down
1 change: 0 additions & 1 deletion src/tools/clippy/tests/ui/implied_bounds_in_impls.fixed
@@ -1,6 +1,5 @@
#![warn(clippy::implied_bounds_in_impls)]
#![allow(dead_code)]
#![feature(return_position_impl_trait_in_trait)]

use std::ops::{Deref, DerefMut};

Expand Down
1 change: 0 additions & 1 deletion src/tools/clippy/tests/ui/implied_bounds_in_impls.rs
@@ -1,6 +1,5 @@
#![warn(clippy::implied_bounds_in_impls)]
#![allow(dead_code)]
#![feature(return_position_impl_trait_in_trait)]

use std::ops::{Deref, DerefMut};

Expand Down