1
Fork 0

Add async bound modifier to enable async Fn bounds

This commit is contained in:
Michael Goulet 2024-01-26 17:00:28 +00:00
parent cdaa12e3df
commit 0eb2adb7e8
12 changed files with 199 additions and 59 deletions

View file

@ -291,12 +291,16 @@ pub use crate::node_id::{NodeId, CRATE_NODE_ID, DUMMY_NODE_ID};
#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug)] #[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug)]
pub struct TraitBoundModifiers { pub struct TraitBoundModifiers {
pub constness: BoundConstness, pub constness: BoundConstness,
pub asyncness: BoundAsyncness,
pub polarity: BoundPolarity, pub polarity: BoundPolarity,
} }
impl TraitBoundModifiers { impl TraitBoundModifiers {
pub const NONE: Self = pub const NONE: Self = Self {
Self { constness: BoundConstness::Never, polarity: BoundPolarity::Positive }; constness: BoundConstness::Never,
asyncness: BoundAsyncness::Normal,
polarity: BoundPolarity::Positive,
};
} }
/// The AST represents all type param bounds as types. /// The AST represents all type param bounds as types.
@ -2562,6 +2566,25 @@ impl BoundConstness {
} }
} }
/// The asyncness of a trait bound.
#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug)]
#[derive(HashStable_Generic)]
pub enum BoundAsyncness {
/// `Type: Trait`
Normal,
/// `Type: async Trait`
Async(Span),
}
impl BoundAsyncness {
pub fn as_str(self) -> &'static str {
match self {
Self::Normal => "",
Self::Async(_) => "async",
}
}
}
#[derive(Clone, Encodable, Decodable, Debug)] #[derive(Clone, Encodable, Decodable, Debug)]
pub enum FnRetTy { pub enum FnRetTy {
/// Returns type is not specified. /// Returns type is not specified.
@ -3300,7 +3323,7 @@ mod size_asserts {
static_assert_size!(ForeignItem, 96); static_assert_size!(ForeignItem, 96);
static_assert_size!(ForeignItemKind, 24); static_assert_size!(ForeignItemKind, 24);
static_assert_size!(GenericArg, 24); static_assert_size!(GenericArg, 24);
static_assert_size!(GenericBound, 72); static_assert_size!(GenericBound, 88);
static_assert_size!(Generics, 40); static_assert_size!(Generics, 40);
static_assert_size!(Impl, 136); static_assert_size!(Impl, 136);
static_assert_size!(Item, 136); static_assert_size!(Item, 136);

View file

@ -100,6 +100,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
ParenthesizedGenericArgs::Err, ParenthesizedGenericArgs::Err,
&ImplTraitContext::Disallowed(ImplTraitPosition::Path), &ImplTraitContext::Disallowed(ImplTraitPosition::Path),
None, None,
// Method calls can't have bound modifiers
None,
)); ));
let receiver = self.lower_expr(receiver); let receiver = self.lower_expr(receiver);
let args = let args =

View file

@ -343,14 +343,19 @@ impl<'hir> LoweringContext<'_, 'hir> {
let itctx = ImplTraitContext::Universal; let itctx = ImplTraitContext::Universal;
let (generics, (trait_ref, lowered_ty)) = let (generics, (trait_ref, lowered_ty)) =
self.lower_generics(ast_generics, *constness, id, &itctx, |this| { self.lower_generics(ast_generics, *constness, id, &itctx, |this| {
let constness = match *constness { let modifiers = TraitBoundModifiers {
constness: match *constness {
Const::Yes(span) => BoundConstness::Maybe(span), Const::Yes(span) => BoundConstness::Maybe(span),
Const::No => BoundConstness::Never, Const::No => BoundConstness::Never,
},
asyncness: BoundAsyncness::Normal,
// we don't use this in bound lowering
polarity: BoundPolarity::Positive,
}; };
let trait_ref = trait_ref.as_ref().map(|trait_ref| { let trait_ref = trait_ref.as_ref().map(|trait_ref| {
this.lower_trait_ref( this.lower_trait_ref(
constness, modifiers,
trait_ref, trait_ref,
&ImplTraitContext::Disallowed(ImplTraitPosition::Trait), &ImplTraitContext::Disallowed(ImplTraitPosition::Trait),
) )

View file

@ -131,6 +131,7 @@ struct LoweringContext<'a, 'hir> {
allow_gen_future: Lrc<[Symbol]>, allow_gen_future: Lrc<[Symbol]>,
allow_async_iterator: Lrc<[Symbol]>, allow_async_iterator: Lrc<[Symbol]>,
allow_for_await: Lrc<[Symbol]>, allow_for_await: Lrc<[Symbol]>,
allow_async_fn_traits: Lrc<[Symbol]>,
/// Mapping from generics `def_id`s to TAIT generics `def_id`s. /// Mapping from generics `def_id`s to TAIT generics `def_id`s.
/// For each captured lifetime (e.g., 'a), we create a new lifetime parameter that is a generic /// For each captured lifetime (e.g., 'a), we create a new lifetime parameter that is a generic
@ -176,6 +177,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
[sym::gen_future].into() [sym::gen_future].into()
}, },
allow_for_await: [sym::async_iterator].into(), allow_for_await: [sym::async_iterator].into(),
allow_async_fn_traits: [sym::async_fn_traits].into(),
// FIXME(gen_blocks): how does `closure_track_caller`/`async_fn_track_caller` // FIXME(gen_blocks): how does `closure_track_caller`/`async_fn_track_caller`
// interact with `gen`/`async gen` blocks // interact with `gen`/`async gen` blocks
allow_async_iterator: [sym::gen_future, sym::async_iterator].into(), allow_async_iterator: [sym::gen_future, sym::async_iterator].into(),
@ -1311,7 +1313,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
span: t.span, span: t.span,
}, },
itctx, itctx,
ast::BoundConstness::Never, TraitBoundModifiers::NONE,
); );
let bounds = this.arena.alloc_from_iter([bound]); let bounds = this.arena.alloc_from_iter([bound]);
let lifetime_bound = this.elided_dyn_bound(t.span); let lifetime_bound = this.elided_dyn_bound(t.span);
@ -1426,7 +1428,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
itctx, itctx,
// Still, don't pass along the constness here; we don't want to // Still, don't pass along the constness here; we don't want to
// synthesize any host effect args, it'd only cause problems. // synthesize any host effect args, it'd only cause problems.
ast::BoundConstness::Never, TraitBoundModifiers {
constness: BoundConstness::Never,
..*modifiers
},
)) ))
} }
BoundPolarity::Maybe(_) => None, BoundPolarity::Maybe(_) => None,
@ -2019,7 +2024,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
) -> hir::GenericBound<'hir> { ) -> hir::GenericBound<'hir> {
match tpb { match tpb {
GenericBound::Trait(p, modifiers) => hir::GenericBound::Trait( GenericBound::Trait(p, modifiers) => hir::GenericBound::Trait(
self.lower_poly_trait_ref(p, itctx, modifiers.constness.into()), self.lower_poly_trait_ref(p, itctx, *modifiers),
self.lower_trait_bound_modifiers(*modifiers), self.lower_trait_bound_modifiers(*modifiers),
), ),
GenericBound::Outlives(lifetime) => { GenericBound::Outlives(lifetime) => {
@ -2192,7 +2197,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
fn lower_trait_ref( fn lower_trait_ref(
&mut self, &mut self,
constness: ast::BoundConstness, modifiers: ast::TraitBoundModifiers,
p: &TraitRef, p: &TraitRef,
itctx: &ImplTraitContext, itctx: &ImplTraitContext,
) -> hir::TraitRef<'hir> { ) -> hir::TraitRef<'hir> {
@ -2202,7 +2207,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
&p.path, &p.path,
ParamMode::Explicit, ParamMode::Explicit,
itctx, itctx,
Some(constness), Some(modifiers),
) { ) {
hir::QPath::Resolved(None, path) => path, hir::QPath::Resolved(None, path) => path,
qpath => panic!("lower_trait_ref: unexpected QPath `{qpath:?}`"), qpath => panic!("lower_trait_ref: unexpected QPath `{qpath:?}`"),
@ -2215,11 +2220,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
&mut self, &mut self,
p: &PolyTraitRef, p: &PolyTraitRef,
itctx: &ImplTraitContext, itctx: &ImplTraitContext,
constness: ast::BoundConstness, modifiers: ast::TraitBoundModifiers,
) -> hir::PolyTraitRef<'hir> { ) -> hir::PolyTraitRef<'hir> {
let bound_generic_params = let bound_generic_params =
self.lower_lifetime_binder(p.trait_ref.ref_id, &p.bound_generic_params); self.lower_lifetime_binder(p.trait_ref.ref_id, &p.bound_generic_params);
let trait_ref = self.lower_trait_ref(constness, &p.trait_ref, itctx); let trait_ref = self.lower_trait_ref(modifiers, &p.trait_ref, itctx);
hir::PolyTraitRef { bound_generic_params, trait_ref, span: self.lower_span(p.span) } hir::PolyTraitRef { bound_generic_params, trait_ref, span: self.lower_span(p.span) }
} }

View file

@ -6,12 +6,14 @@ use super::{GenericArgsCtor, LifetimeRes, ParenthesizedGenericArgs};
use super::{ImplTraitContext, LoweringContext, ParamMode}; use super::{ImplTraitContext, LoweringContext, ParamMode};
use rustc_ast::{self as ast, *}; use rustc_ast::{self as ast, *};
use rustc_data_structures::sync::Lrc;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::def::{DefKind, PartialRes, Res}; use rustc_hir::def::{DefKind, PartialRes, Res};
use rustc_hir::def_id::DefId;
use rustc_hir::GenericArg; use rustc_hir::GenericArg;
use rustc_middle::span_bug; use rustc_middle::span_bug;
use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::{BytePos, Span, DUMMY_SP}; use rustc_span::{BytePos, DesugaringKind, Span, Symbol, DUMMY_SP};
use smallvec::{smallvec, SmallVec}; use smallvec::{smallvec, SmallVec};
@ -24,8 +26,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
p: &Path, p: &Path,
param_mode: ParamMode, param_mode: ParamMode,
itctx: &ImplTraitContext, itctx: &ImplTraitContext,
// constness of the impl/bound if this is a trait path // modifiers of the impl/bound if this is a trait path
constness: Option<ast::BoundConstness>, modifiers: Option<ast::TraitBoundModifiers>,
) -> hir::QPath<'hir> { ) -> hir::QPath<'hir> {
let qself_position = qself.as_ref().map(|q| q.position); let qself_position = qself.as_ref().map(|q| q.position);
let qself = qself.as_ref().map(|q| self.lower_ty(&q.ty, itctx)); let qself = qself.as_ref().map(|q| self.lower_ty(&q.ty, itctx));
@ -35,10 +37,27 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
let base_res = partial_res.base_res(); let base_res = partial_res.base_res();
let unresolved_segments = partial_res.unresolved_segments(); let unresolved_segments = partial_res.unresolved_segments();
let mut res = self.lower_res(base_res);
// When we have an `async` kw on a bound, map the trait it resolves to.
let mut bound_modifier_allowed_features = None;
if let Some(TraitBoundModifiers { asyncness: BoundAsyncness::Async(_), .. }) = modifiers {
if let Res::Def(DefKind::Trait, def_id) = res {
if let Some((async_def_id, features)) = self.map_trait_to_async_trait(def_id) {
res = Res::Def(DefKind::Trait, async_def_id);
bound_modifier_allowed_features = Some(features);
} else {
panic!();
}
} else {
panic!();
}
}
let path_span_lo = p.span.shrink_to_lo(); let path_span_lo = p.span.shrink_to_lo();
let proj_start = p.segments.len() - unresolved_segments; let proj_start = p.segments.len() - unresolved_segments;
let path = self.arena.alloc(hir::Path { let path = self.arena.alloc(hir::Path {
res: self.lower_res(base_res), res,
segments: self.arena.alloc_from_iter(p.segments[..proj_start].iter().enumerate().map( segments: self.arena.alloc_from_iter(p.segments[..proj_start].iter().enumerate().map(
|(i, segment)| { |(i, segment)| {
let param_mode = match (qself_position, param_mode) { let param_mode = match (qself_position, param_mode) {
@ -77,7 +96,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
parenthesized_generic_args, parenthesized_generic_args,
itctx, itctx,
// if this is the last segment, add constness to the trait path // if this is the last segment, add constness to the trait path
if i == proj_start - 1 { constness } else { None }, if i == proj_start - 1 { modifiers.map(|m| m.constness) } else { None },
bound_modifier_allowed_features.clone(),
) )
}, },
)), )),
@ -88,6 +108,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
), ),
}); });
if let Some(bound_modifier_allowed_features) = bound_modifier_allowed_features {
path.span = self.mark_span_with_reason(
DesugaringKind::BoundModifier,
path.span,
Some(bound_modifier_allowed_features),
);
}
// Simple case, either no projections, or only fully-qualified. // Simple case, either no projections, or only fully-qualified.
// E.g., `std::mem::size_of` or `<I as Iterator>::Item`. // E.g., `std::mem::size_of` or `<I as Iterator>::Item`.
if unresolved_segments == 0 { if unresolved_segments == 0 {
@ -125,6 +153,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
ParenthesizedGenericArgs::Err, ParenthesizedGenericArgs::Err,
itctx, itctx,
None, None,
None,
)); ));
let qpath = hir::QPath::TypeRelative(ty, hir_segment); let qpath = hir::QPath::TypeRelative(ty, hir_segment);
@ -166,6 +195,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
ParenthesizedGenericArgs::Err, ParenthesizedGenericArgs::Err,
&ImplTraitContext::Disallowed(ImplTraitPosition::Path), &ImplTraitContext::Disallowed(ImplTraitPosition::Path),
None, None,
None,
) )
})), })),
span: self.lower_span(p.span), span: self.lower_span(p.span),
@ -180,6 +210,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
parenthesized_generic_args: ParenthesizedGenericArgs, parenthesized_generic_args: ParenthesizedGenericArgs,
itctx: &ImplTraitContext, itctx: &ImplTraitContext,
constness: Option<ast::BoundConstness>, constness: Option<ast::BoundConstness>,
// Additional features ungated with a bound modifier like `async`.
// This is passed down to the implicit associated type binding in
// parenthesized bounds.
bound_modifier_allowed_features: Option<Lrc<[Symbol]>>,
) -> hir::PathSegment<'hir> { ) -> hir::PathSegment<'hir> {
debug!("path_span: {:?}, lower_path_segment(segment: {:?})", path_span, segment); debug!("path_span: {:?}, lower_path_segment(segment: {:?})", path_span, segment);
let (mut generic_args, infer_args) = if let Some(generic_args) = segment.args.as_deref() { let (mut generic_args, infer_args) = if let Some(generic_args) = segment.args.as_deref() {
@ -188,9 +222,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
self.lower_angle_bracketed_parameter_data(data, param_mode, itctx) self.lower_angle_bracketed_parameter_data(data, param_mode, itctx)
} }
GenericArgs::Parenthesized(data) => match parenthesized_generic_args { GenericArgs::Parenthesized(data) => match parenthesized_generic_args {
ParenthesizedGenericArgs::ParenSugar => { ParenthesizedGenericArgs::ParenSugar => self
self.lower_parenthesized_parameter_data(data, itctx) .lower_parenthesized_parameter_data(
} data,
itctx,
bound_modifier_allowed_features,
),
ParenthesizedGenericArgs::Err => { ParenthesizedGenericArgs::Err => {
// Suggest replacing parentheses with angle brackets `Trait(params...)` to `Trait<params...>` // Suggest replacing parentheses with angle brackets `Trait(params...)` to `Trait<params...>`
let sub = if !data.inputs.is_empty() { let sub = if !data.inputs.is_empty() {
@ -357,6 +394,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
&mut self, &mut self,
data: &ParenthesizedArgs, data: &ParenthesizedArgs,
itctx: &ImplTraitContext, itctx: &ImplTraitContext,
bound_modifier_allowed_features: Option<Lrc<[Symbol]>>,
) -> (GenericArgsCtor<'hir>, bool) { ) -> (GenericArgsCtor<'hir>, bool) {
// Switch to `PassThrough` mode for anonymous lifetimes; this // Switch to `PassThrough` mode for anonymous lifetimes; this
// means that we permit things like `&Ref<T>`, where `Ref` has // means that we permit things like `&Ref<T>`, where `Ref` has
@ -392,7 +430,19 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
FnRetTy::Default(_) => self.arena.alloc(self.ty_tup(*span, &[])), FnRetTy::Default(_) => self.arena.alloc(self.ty_tup(*span, &[])),
}; };
let args = smallvec![GenericArg::Type(self.arena.alloc(self.ty_tup(*inputs_span, inputs)))]; let args = smallvec![GenericArg::Type(self.arena.alloc(self.ty_tup(*inputs_span, inputs)))];
let binding = self.assoc_ty_binding(sym::Output, output_ty.span, output_ty);
// If we have a bound like `async Fn() -> T`, make sure that we mark the
// `Output = T` associated type bound with the right feature gates.
let mut output_span = output_ty.span;
if let Some(bound_modifier_allowed_features) = bound_modifier_allowed_features {
output_span = self.mark_span_with_reason(
DesugaringKind::BoundModifier,
output_span,
Some(bound_modifier_allowed_features),
);
}
let binding = self.assoc_ty_binding(sym::Output, output_span, output_ty);
( (
GenericArgsCtor { GenericArgsCtor {
args, args,
@ -429,4 +479,23 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
kind, kind,
} }
} }
/// When a bound is annotated with `async`, it signals to lowering that the trait
/// that the bound refers to should be mapped to the "async" flavor of the trait.
///
/// This only needs to be done until we unify `AsyncFn` and `Fn` traits into one
/// that is generic over `async`ness, if that's ever possible, or modify the
/// lowering of `async Fn()` bounds to desugar to another trait like `LendingFn`.
fn map_trait_to_async_trait(&self, def_id: DefId) -> Option<(DefId, Lrc<[Symbol]>)> {
let lang_items = self.tcx.lang_items();
if Some(def_id) == lang_items.fn_trait() {
Some((lang_items.async_fn_trait()?, self.allow_async_fn_traits.clone()))
} else if Some(def_id) == lang_items.fn_mut_trait() {
Some((lang_items.async_fn_mut_trait()?, self.allow_async_fn_traits.clone()))
} else if Some(def_id) == lang_items.fn_once_trait() {
Some((lang_items.async_fn_once_trait()?, self.allow_async_fn_traits.clone()))
} else {
None
}
}
} }

View file

@ -8,6 +8,7 @@ mod item;
use crate::pp::Breaks::{Consistent, Inconsistent}; use crate::pp::Breaks::{Consistent, Inconsistent};
use crate::pp::{self, Breaks}; use crate::pp::{self, Breaks};
use crate::pprust::state::expr::FixupContext; use crate::pprust::state::expr::FixupContext;
use ast::TraitBoundModifiers;
use rustc_ast::attr::AttrIdGenerator; use rustc_ast::attr::AttrIdGenerator;
use rustc_ast::ptr::P; use rustc_ast::ptr::P;
use rustc_ast::token::{self, BinOpToken, CommentKind, Delimiter, Nonterminal, Token, TokenKind}; use rustc_ast::token::{self, BinOpToken, CommentKind, Delimiter, Nonterminal, Token, TokenKind};
@ -1590,18 +1591,28 @@ impl<'a> State<'a> {
} }
match bound { match bound {
GenericBound::Trait(tref, modifier) => { GenericBound::Trait(
match modifier.constness { tref,
TraitBoundModifiers { constness, asyncness, polarity },
) => {
match constness {
ast::BoundConstness::Never => {} ast::BoundConstness::Never => {}
ast::BoundConstness::Always(_) | ast::BoundConstness::Maybe(_) => { ast::BoundConstness::Always(_) | ast::BoundConstness::Maybe(_) => {
self.word_space(modifier.constness.as_str()); self.word_space(constness.as_str());
} }
} }
match modifier.polarity { match asyncness {
ast::BoundAsyncness::Normal => {}
ast::BoundAsyncness::Async(_) => {
self.word_space(asyncness.as_str());
}
}
match polarity {
ast::BoundPolarity::Positive => {} ast::BoundPolarity::Positive => {}
ast::BoundPolarity::Negative(_) | ast::BoundPolarity::Maybe(_) => { ast::BoundPolarity::Negative(_) | ast::BoundPolarity::Maybe(_) => {
self.word(modifier.polarity.as_str()); self.word(polarity.as_str());
} }
} }

View file

@ -141,6 +141,7 @@ impl<'a> ExtCtxt<'a> {
} else { } else {
ast::BoundConstness::Never ast::BoundConstness::Never
}, },
asyncness: ast::BoundAsyncness::Normal,
}, },
) )
} }

View file

@ -8,14 +8,13 @@ use crate::errors::{
}; };
use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole}; use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
use ast::DUMMY_NODE_ID;
use rustc_ast::ptr::P; use rustc_ast::ptr::P;
use rustc_ast::token::{self, Delimiter, Token, TokenKind}; use rustc_ast::token::{self, Delimiter, Token, TokenKind};
use rustc_ast::util::case::Case; use rustc_ast::util::case::Case;
use rustc_ast::{ use rustc_ast::{
self as ast, BareFnTy, BoundConstness, BoundPolarity, FnRetTy, GenericBound, GenericBounds, self as ast, BareFnTy, BoundAsyncness, BoundConstness, BoundPolarity, FnRetTy, GenericBound,
GenericParam, Generics, Lifetime, MacCall, MutTy, Mutability, PolyTraitRef, GenericBounds, GenericParam, Generics, Lifetime, MacCall, MutTy, Mutability, PolyTraitRef,
TraitBoundModifiers, TraitObjectSyntax, Ty, TyKind, TraitBoundModifiers, TraitObjectSyntax, Ty, TyKind, DUMMY_NODE_ID,
}; };
use rustc_errors::{Applicability, PResult}; use rustc_errors::{Applicability, PResult};
use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::symbol::{kw, sym, Ident};
@ -880,6 +879,13 @@ impl<'a> Parser<'a> {
BoundConstness::Never BoundConstness::Never
}; };
let asyncness = if self.token.span.at_least_rust_2018() && self.eat_keyword(kw::Async) {
self.sess.gated_spans.gate(sym::async_closure, self.prev_token.span);
BoundAsyncness::Async(self.prev_token.span)
} else {
BoundAsyncness::Normal
};
let polarity = if self.eat(&token::Question) { let polarity = if self.eat(&token::Question) {
BoundPolarity::Maybe(self.prev_token.span) BoundPolarity::Maybe(self.prev_token.span)
} else if self.eat(&token::Not) { } else if self.eat(&token::Not) {
@ -889,7 +895,7 @@ impl<'a> Parser<'a> {
BoundPolarity::Positive BoundPolarity::Positive
}; };
Ok(TraitBoundModifiers { constness, polarity }) Ok(TraitBoundModifiers { constness, asyncness, polarity })
} }
/// Parses a type bound according to: /// Parses a type bound according to:

View file

@ -1154,6 +1154,8 @@ pub enum DesugaringKind {
Await, Await,
ForLoop, ForLoop,
WhileLoop, WhileLoop,
/// `async Fn()` bound modifier
BoundModifier,
} }
impl DesugaringKind { impl DesugaringKind {
@ -1169,6 +1171,7 @@ impl DesugaringKind {
DesugaringKind::OpaqueTy => "`impl Trait`", DesugaringKind::OpaqueTy => "`impl Trait`",
DesugaringKind::ForLoop => "`for` loop", DesugaringKind::ForLoop => "`for` loop",
DesugaringKind::WhileLoop => "`while` loop", DesugaringKind::WhileLoop => "`while` loop",
DesugaringKind::BoundModifier => "trait bound modifier",
} }
} }
} }

View file

@ -423,6 +423,7 @@ symbols! {
async_fn_mut, async_fn_mut,
async_fn_once, async_fn_once,
async_fn_track_caller, async_fn_track_caller,
async_fn_traits,
async_for_loop, async_for_loop,
async_iterator, async_iterator,
async_iterator_poll_next, async_iterator_poll_next,

View file

@ -0,0 +1,14 @@
// edition: 2021
// check-pass
#![feature(async_closure)]
async fn foo() {}
async fn call_asyncly(f: impl async Fn(i32) -> i32) -> i32 {
f(1).await
}
fn main() {
let fut = call_asyncly(|x| async move { x + 1 });
}

View file

@ -5,8 +5,8 @@ ast-stats-1 GenericArgs 40 ( 0.6%) 1 40
ast-stats-1 - AngleBracketed 40 ( 0.6%) 1 ast-stats-1 - AngleBracketed 40 ( 0.6%) 1
ast-stats-1 Crate 40 ( 0.6%) 1 40 ast-stats-1 Crate 40 ( 0.6%) 1 40
ast-stats-1 ExprField 48 ( 0.7%) 1 48 ast-stats-1 ExprField 48 ( 0.7%) 1 48
ast-stats-1 WherePredicate 56 ( 0.9%) 1 56 ast-stats-1 WherePredicate 56 ( 0.8%) 1 56
ast-stats-1 - BoundPredicate 56 ( 0.9%) 1 ast-stats-1 - BoundPredicate 56 ( 0.8%) 1
ast-stats-1 Attribute 64 ( 1.0%) 2 32 ast-stats-1 Attribute 64 ( 1.0%) 2 32
ast-stats-1 - Normal 32 ( 0.5%) 1 ast-stats-1 - Normal 32 ( 0.5%) 1
ast-stats-1 - DocComment 32 ( 0.5%) 1 ast-stats-1 - DocComment 32 ( 0.5%) 1
@ -22,38 +22,38 @@ ast-stats-1 - MacCall 32 ( 0.5%) 1
ast-stats-1 - Expr 96 ( 1.5%) 3 ast-stats-1 - Expr 96 ( 1.5%) 3
ast-stats-1 Param 160 ( 2.4%) 4 40 ast-stats-1 Param 160 ( 2.4%) 4 40
ast-stats-1 Block 192 ( 2.9%) 6 32 ast-stats-1 Block 192 ( 2.9%) 6 32
ast-stats-1 Variant 208 ( 3.2%) 2 104 ast-stats-1 Variant 208 ( 3.1%) 2 104
ast-stats-1 GenericBound 288 ( 4.4%) 4 72 ast-stats-1 GenericBound 352 ( 5.3%) 4 88
ast-stats-1 - Trait 288 ( 4.4%) 4 ast-stats-1 - Trait 352 ( 5.3%) 4
ast-stats-1 AssocItem 352 ( 5.4%) 4 88 ast-stats-1 AssocItem 352 ( 5.3%) 4 88
ast-stats-1 - Type 176 ( 2.7%) 2 ast-stats-1 - Type 176 ( 2.7%) 2
ast-stats-1 - Fn 176 ( 2.7%) 2 ast-stats-1 - Fn 176 ( 2.7%) 2
ast-stats-1 GenericParam 480 ( 7.3%) 5 96 ast-stats-1 GenericParam 480 ( 7.3%) 5 96
ast-stats-1 Pat 504 ( 7.7%) 7 72 ast-stats-1 Pat 504 ( 7.6%) 7 72
ast-stats-1 - Struct 72 ( 1.1%) 1 ast-stats-1 - Struct 72 ( 1.1%) 1
ast-stats-1 - Wild 72 ( 1.1%) 1 ast-stats-1 - Wild 72 ( 1.1%) 1
ast-stats-1 - Ident 360 ( 5.5%) 5 ast-stats-1 - Ident 360 ( 5.4%) 5
ast-stats-1 Expr 576 ( 8.8%) 8 72 ast-stats-1 Expr 576 ( 8.7%) 8 72
ast-stats-1 - Path 72 ( 1.1%) 1 ast-stats-1 - Path 72 ( 1.1%) 1
ast-stats-1 - Match 72 ( 1.1%) 1 ast-stats-1 - Match 72 ( 1.1%) 1
ast-stats-1 - Struct 72 ( 1.1%) 1 ast-stats-1 - Struct 72 ( 1.1%) 1
ast-stats-1 - Lit 144 ( 2.2%) 2 ast-stats-1 - Lit 144 ( 2.2%) 2
ast-stats-1 - Block 216 ( 3.3%) 3 ast-stats-1 - Block 216 ( 3.3%) 3
ast-stats-1 PathSegment 720 (11.0%) 30 24 ast-stats-1 PathSegment 720 (10.9%) 30 24
ast-stats-1 Ty 896 (13.7%) 14 64 ast-stats-1 Ty 896 (13.5%) 14 64
ast-stats-1 - Ptr 64 ( 1.0%) 1 ast-stats-1 - Ptr 64 ( 1.0%) 1
ast-stats-1 - Ref 64 ( 1.0%) 1 ast-stats-1 - Ref 64 ( 1.0%) 1
ast-stats-1 - ImplicitSelf 128 ( 2.0%) 2 ast-stats-1 - ImplicitSelf 128 ( 1.9%) 2
ast-stats-1 - Path 640 ( 9.8%) 10 ast-stats-1 - Path 640 ( 9.7%) 10
ast-stats-1 Item 1_224 (18.7%) 9 136 ast-stats-1 Item 1_224 (18.5%) 9 136
ast-stats-1 - Trait 136 ( 2.1%) 1 ast-stats-1 - Trait 136 ( 2.1%) 1
ast-stats-1 - Enum 136 ( 2.1%) 1 ast-stats-1 - Enum 136 ( 2.1%) 1
ast-stats-1 - ForeignMod 136 ( 2.1%) 1 ast-stats-1 - ForeignMod 136 ( 2.1%) 1
ast-stats-1 - Impl 136 ( 2.1%) 1 ast-stats-1 - Impl 136 ( 2.1%) 1
ast-stats-1 - Fn 272 ( 4.2%) 2 ast-stats-1 - Fn 272 ( 4.1%) 2
ast-stats-1 - Use 408 ( 6.2%) 3 ast-stats-1 - Use 408 ( 6.2%) 3
ast-stats-1 ---------------------------------------------------------------- ast-stats-1 ----------------------------------------------------------------
ast-stats-1 Total 6_552 ast-stats-1 Total 6_616
ast-stats-1 ast-stats-1
ast-stats-2 POST EXPANSION AST STATS ast-stats-2 POST EXPANSION AST STATS
ast-stats-2 Name Accumulated Size Count Item Size ast-stats-2 Name Accumulated Size Count Item Size
@ -81,39 +81,39 @@ ast-stats-2 - Expr 96 ( 1.3%) 3
ast-stats-2 Param 160 ( 2.2%) 4 40 ast-stats-2 Param 160 ( 2.2%) 4 40
ast-stats-2 Block 192 ( 2.7%) 6 32 ast-stats-2 Block 192 ( 2.7%) 6 32
ast-stats-2 Variant 208 ( 2.9%) 2 104 ast-stats-2 Variant 208 ( 2.9%) 2 104
ast-stats-2 GenericBound 288 ( 4.0%) 4 72 ast-stats-2 GenericBound 352 ( 4.9%) 4 88
ast-stats-2 - Trait 288 ( 4.0%) 4 ast-stats-2 - Trait 352 ( 4.9%) 4
ast-stats-2 AssocItem 352 ( 4.9%) 4 88 ast-stats-2 AssocItem 352 ( 4.9%) 4 88
ast-stats-2 - Type 176 ( 2.5%) 2 ast-stats-2 - Type 176 ( 2.4%) 2
ast-stats-2 - Fn 176 ( 2.5%) 2 ast-stats-2 - Fn 176 ( 2.4%) 2
ast-stats-2 GenericParam 480 ( 6.7%) 5 96 ast-stats-2 GenericParam 480 ( 6.7%) 5 96
ast-stats-2 Pat 504 ( 7.0%) 7 72 ast-stats-2 Pat 504 ( 7.0%) 7 72
ast-stats-2 - Struct 72 ( 1.0%) 1 ast-stats-2 - Struct 72 ( 1.0%) 1
ast-stats-2 - Wild 72 ( 1.0%) 1 ast-stats-2 - Wild 72 ( 1.0%) 1
ast-stats-2 - Ident 360 ( 5.0%) 5 ast-stats-2 - Ident 360 ( 5.0%) 5
ast-stats-2 Expr 648 ( 9.1%) 9 72 ast-stats-2 Expr 648 ( 9.0%) 9 72
ast-stats-2 - Path 72 ( 1.0%) 1 ast-stats-2 - Path 72 ( 1.0%) 1
ast-stats-2 - Match 72 ( 1.0%) 1 ast-stats-2 - Match 72 ( 1.0%) 1
ast-stats-2 - Struct 72 ( 1.0%) 1 ast-stats-2 - Struct 72 ( 1.0%) 1
ast-stats-2 - InlineAsm 72 ( 1.0%) 1 ast-stats-2 - InlineAsm 72 ( 1.0%) 1
ast-stats-2 - Lit 144 ( 2.0%) 2 ast-stats-2 - Lit 144 ( 2.0%) 2
ast-stats-2 - Block 216 ( 3.0%) 3 ast-stats-2 - Block 216 ( 3.0%) 3
ast-stats-2 PathSegment 792 (11.1%) 33 24 ast-stats-2 PathSegment 792 (11.0%) 33 24
ast-stats-2 Ty 896 (12.5%) 14 64 ast-stats-2 Ty 896 (12.4%) 14 64
ast-stats-2 - Ptr 64 ( 0.9%) 1 ast-stats-2 - Ptr 64 ( 0.9%) 1
ast-stats-2 - Ref 64 ( 0.9%) 1 ast-stats-2 - Ref 64 ( 0.9%) 1
ast-stats-2 - ImplicitSelf 128 ( 1.8%) 2 ast-stats-2 - ImplicitSelf 128 ( 1.8%) 2
ast-stats-2 - Path 640 ( 8.9%) 10 ast-stats-2 - Path 640 ( 8.9%) 10
ast-stats-2 Item 1_496 (20.9%) 11 136 ast-stats-2 Item 1_496 (20.7%) 11 136
ast-stats-2 - Trait 136 ( 1.9%) 1 ast-stats-2 - Trait 136 ( 1.9%) 1
ast-stats-2 - Enum 136 ( 1.9%) 1 ast-stats-2 - Enum 136 ( 1.9%) 1
ast-stats-2 - ExternCrate 136 ( 1.9%) 1 ast-stats-2 - ExternCrate 136 ( 1.9%) 1
ast-stats-2 - ForeignMod 136 ( 1.9%) 1 ast-stats-2 - ForeignMod 136 ( 1.9%) 1
ast-stats-2 - Impl 136 ( 1.9%) 1 ast-stats-2 - Impl 136 ( 1.9%) 1
ast-stats-2 - Fn 272 ( 3.8%) 2 ast-stats-2 - Fn 272 ( 3.8%) 2
ast-stats-2 - Use 544 ( 7.6%) 4 ast-stats-2 - Use 544 ( 7.5%) 4
ast-stats-2 ---------------------------------------------------------------- ast-stats-2 ----------------------------------------------------------------
ast-stats-2 Total 7_152 ast-stats-2 Total 7_216
ast-stats-2 ast-stats-2
hir-stats HIR STATS hir-stats HIR STATS
hir-stats Name Accumulated Size Count Item Size hir-stats Name Accumulated Size Count Item Size