mirror of
https://github.com/rust-lang/rust.git
synced 2024-10-31 22:41:50 +00:00
Merge Async and Gen into CoroutineKind
This commit is contained in:
parent
3887b1645a
commit
48d5f1f0f2
@ -1311,7 +1311,7 @@ pub struct Closure {
|
||||
pub binder: ClosureBinder,
|
||||
pub capture_clause: CaptureBy,
|
||||
pub constness: Const,
|
||||
pub asyncness: Async,
|
||||
pub coro_kind: CoroutineKind,
|
||||
pub movability: Movability,
|
||||
pub fn_decl: P<FnDecl>,
|
||||
pub body: P<Expr>,
|
||||
@ -2406,28 +2406,38 @@ pub enum Unsafe {
|
||||
No,
|
||||
}
|
||||
|
||||
/// Describes what kind of coroutine markers, if any, a function has.
|
||||
///
|
||||
/// Coroutine markers are things that cause the function to generate a coroutine, such as `async`,
|
||||
/// which makes the function return `impl Future`, or `gen`, which makes the function return `impl
|
||||
/// Iterator`.
|
||||
#[derive(Copy, Clone, Encodable, Decodable, Debug)]
|
||||
pub enum Async {
|
||||
Yes { span: Span, closure_id: NodeId, return_impl_trait_id: NodeId },
|
||||
No,
|
||||
pub enum CoroutineKind {
|
||||
/// `async`, which evaluates to `impl Future`
|
||||
Async { span: Span, closure_id: NodeId, return_impl_trait_id: NodeId },
|
||||
/// `gen`, which evaluates to `impl Iterator`
|
||||
Gen { span: Span, closure_id: NodeId, return_impl_trait_id: NodeId },
|
||||
/// Neither `async` nor `gen`
|
||||
None,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Encodable, Decodable, Debug)]
|
||||
pub enum Gen {
|
||||
Yes { span: Span, closure_id: NodeId, return_impl_trait_id: NodeId },
|
||||
No,
|
||||
}
|
||||
|
||||
impl Async {
|
||||
impl CoroutineKind {
|
||||
pub fn is_async(self) -> bool {
|
||||
matches!(self, Async::Yes { .. })
|
||||
matches!(self, CoroutineKind::Async { .. })
|
||||
}
|
||||
|
||||
pub fn is_gen(self) -> bool {
|
||||
matches!(self, CoroutineKind::Gen { .. })
|
||||
}
|
||||
|
||||
/// In this case this is an `async` return, the `NodeId` for the generated `impl Trait` item.
|
||||
pub fn opt_return_id(self) -> Option<(NodeId, Span)> {
|
||||
match self {
|
||||
Async::Yes { return_impl_trait_id, span, .. } => Some((return_impl_trait_id, span)),
|
||||
Async::No => None,
|
||||
CoroutineKind::Async { return_impl_trait_id, span, .. }
|
||||
| CoroutineKind::Gen { return_impl_trait_id, span, .. } => {
|
||||
Some((return_impl_trait_id, span))
|
||||
}
|
||||
CoroutineKind::None => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2831,25 +2841,22 @@ impl Extern {
|
||||
pub struct FnHeader {
|
||||
/// The `unsafe` keyword, if any
|
||||
pub unsafety: Unsafe,
|
||||
/// The `async` keyword, if any
|
||||
pub asyncness: Async,
|
||||
/// Whether this is `async`, `gen`, or nothing.
|
||||
pub coro_kind: CoroutineKind,
|
||||
/// The `const` keyword, if any
|
||||
pub constness: Const,
|
||||
/// The `extern` keyword and corresponding ABI string, if any
|
||||
pub ext: Extern,
|
||||
/// The `gen` keyword, if any
|
||||
pub genness: Gen,
|
||||
}
|
||||
|
||||
impl FnHeader {
|
||||
/// Does this function header have any qualifiers or is it empty?
|
||||
pub fn has_qualifiers(&self) -> bool {
|
||||
let Self { unsafety, asyncness, constness, ext, genness } = self;
|
||||
let Self { unsafety, coro_kind, constness, ext } = self;
|
||||
matches!(unsafety, Unsafe::Yes(_))
|
||||
|| asyncness.is_async()
|
||||
|| !matches!(coro_kind, CoroutineKind::None)
|
||||
|| matches!(constness, Const::Yes(_))
|
||||
|| !matches!(ext, Extern::None)
|
||||
|| matches!(genness, Gen::Yes { .. })
|
||||
}
|
||||
}
|
||||
|
||||
@ -2857,10 +2864,9 @@ impl Default for FnHeader {
|
||||
fn default() -> FnHeader {
|
||||
FnHeader {
|
||||
unsafety: Unsafe::No,
|
||||
asyncness: Async::No,
|
||||
coro_kind: CoroutineKind::None,
|
||||
constness: Const::No,
|
||||
ext: Extern::None,
|
||||
genness: Gen::No,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3181,7 +3187,7 @@ mod size_asserts {
|
||||
static_assert_size!(Block, 32);
|
||||
static_assert_size!(Expr, 72);
|
||||
static_assert_size!(ExprKind, 40);
|
||||
static_assert_size!(Fn, 168);
|
||||
static_assert_size!(Fn, 160);
|
||||
static_assert_size!(ForeignItem, 96);
|
||||
static_assert_size!(ForeignItemKind, 24);
|
||||
static_assert_size!(GenericArg, 24);
|
||||
|
@ -121,12 +121,8 @@ pub trait MutVisitor: Sized {
|
||||
noop_visit_fn_decl(d, self);
|
||||
}
|
||||
|
||||
fn visit_asyncness(&mut self, a: &mut Async) {
|
||||
noop_visit_asyncness(a, self);
|
||||
}
|
||||
|
||||
fn visit_genness(&mut self, a: &mut Gen) {
|
||||
noop_visit_genness(a, self);
|
||||
fn visit_coro_kind(&mut self, a: &mut CoroutineKind) {
|
||||
noop_visit_coro_kind(a, self);
|
||||
}
|
||||
|
||||
fn visit_closure_binder(&mut self, b: &mut ClosureBinder) {
|
||||
@ -875,23 +871,14 @@ pub fn noop_visit_closure_binder<T: MutVisitor>(binder: &mut ClosureBinder, vis:
|
||||
}
|
||||
}
|
||||
|
||||
pub fn noop_visit_asyncness<T: MutVisitor>(asyncness: &mut Async, vis: &mut T) {
|
||||
match asyncness {
|
||||
Async::Yes { span: _, closure_id, return_impl_trait_id } => {
|
||||
pub fn noop_visit_coro_kind<T: MutVisitor>(coro_kind: &mut CoroutineKind, vis: &mut T) {
|
||||
match coro_kind {
|
||||
CoroutineKind::Async { span: _, closure_id, return_impl_trait_id }
|
||||
| CoroutineKind::Gen { span: _, closure_id, return_impl_trait_id } => {
|
||||
vis.visit_id(closure_id);
|
||||
vis.visit_id(return_impl_trait_id);
|
||||
}
|
||||
Async::No => {}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn noop_visit_genness<T: MutVisitor>(genness: &mut Gen, vis: &mut T) {
|
||||
match genness {
|
||||
Gen::Yes { span: _, closure_id, return_impl_trait_id } => {
|
||||
vis.visit_id(closure_id);
|
||||
vis.visit_id(return_impl_trait_id);
|
||||
}
|
||||
Gen::No => {}
|
||||
CoroutineKind::None => {}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1184,10 +1171,9 @@ fn visit_const_item<T: MutVisitor>(
|
||||
}
|
||||
|
||||
pub fn noop_visit_fn_header<T: MutVisitor>(header: &mut FnHeader, vis: &mut T) {
|
||||
let FnHeader { unsafety, asyncness, constness, ext: _, genness } = header;
|
||||
let FnHeader { unsafety, coro_kind, constness, ext: _ } = header;
|
||||
visit_constness(constness, vis);
|
||||
vis.visit_asyncness(asyncness);
|
||||
vis.visit_genness(genness);
|
||||
vis.visit_coro_kind(coro_kind);
|
||||
visit_unsafety(unsafety, vis);
|
||||
}
|
||||
|
||||
@ -1421,7 +1407,7 @@ pub fn noop_visit_expr<T: MutVisitor>(
|
||||
binder,
|
||||
capture_clause,
|
||||
constness,
|
||||
asyncness,
|
||||
coro_kind,
|
||||
movability: _,
|
||||
fn_decl,
|
||||
body,
|
||||
@ -1430,7 +1416,7 @@ pub fn noop_visit_expr<T: MutVisitor>(
|
||||
}) => {
|
||||
vis.visit_closure_binder(binder);
|
||||
visit_constness(constness, vis);
|
||||
vis.visit_asyncness(asyncness);
|
||||
vis.visit_coro_kind(coro_kind);
|
||||
vis.visit_capture_by(capture_clause);
|
||||
vis.visit_fn_decl(fn_decl);
|
||||
vis.visit_expr(body);
|
||||
|
@ -861,7 +861,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
|
||||
ExprKind::Closure(box Closure {
|
||||
binder,
|
||||
capture_clause,
|
||||
asyncness: _,
|
||||
coro_kind: _,
|
||||
constness: _,
|
||||
movability: _,
|
||||
fn_decl,
|
||||
|
@ -195,39 +195,37 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
binder,
|
||||
capture_clause,
|
||||
constness,
|
||||
asyncness,
|
||||
coro_kind,
|
||||
movability,
|
||||
fn_decl,
|
||||
body,
|
||||
fn_decl_span,
|
||||
fn_arg_span,
|
||||
}) => {
|
||||
if let Async::Yes { closure_id, .. } = asyncness {
|
||||
self.lower_expr_async_closure(
|
||||
binder,
|
||||
*capture_clause,
|
||||
e.id,
|
||||
hir_id,
|
||||
*closure_id,
|
||||
fn_decl,
|
||||
body,
|
||||
*fn_decl_span,
|
||||
*fn_arg_span,
|
||||
)
|
||||
} else {
|
||||
self.lower_expr_closure(
|
||||
binder,
|
||||
*capture_clause,
|
||||
e.id,
|
||||
*constness,
|
||||
*movability,
|
||||
fn_decl,
|
||||
body,
|
||||
*fn_decl_span,
|
||||
*fn_arg_span,
|
||||
)
|
||||
}
|
||||
}
|
||||
}) => match coro_kind {
|
||||
CoroutineKind::Async { closure_id, .. }
|
||||
| CoroutineKind::Gen { closure_id, .. } => self.lower_expr_async_closure(
|
||||
binder,
|
||||
*capture_clause,
|
||||
e.id,
|
||||
hir_id,
|
||||
*closure_id,
|
||||
fn_decl,
|
||||
body,
|
||||
*fn_decl_span,
|
||||
*fn_arg_span,
|
||||
),
|
||||
CoroutineKind::None => self.lower_expr_closure(
|
||||
binder,
|
||||
*capture_clause,
|
||||
e.id,
|
||||
*constness,
|
||||
*movability,
|
||||
fn_decl,
|
||||
body,
|
||||
*fn_decl_span,
|
||||
*fn_arg_span,
|
||||
),
|
||||
},
|
||||
ExprKind::Block(blk, opt_label) => {
|
||||
let opt_label = self.lower_label(*opt_label);
|
||||
hir::ExprKind::Block(self.lower_block(blk, opt_label.is_some()), opt_label)
|
||||
@ -935,7 +933,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
|
||||
let bound_generic_params = self.lower_lifetime_binder(closure_id, generic_params);
|
||||
// Lower outside new scope to preserve `is_in_loop_condition`.
|
||||
let fn_decl = self.lower_fn_decl(decl, closure_id, fn_decl_span, FnDeclKind::Closure, None);
|
||||
let fn_decl = self.lower_fn_decl(
|
||||
decl,
|
||||
closure_id,
|
||||
fn_decl_span,
|
||||
FnDeclKind::Closure,
|
||||
CoroutineKind::None,
|
||||
);
|
||||
|
||||
let c = self.arena.alloc(hir::Closure {
|
||||
def_id: self.local_def_id(closure_id),
|
||||
@ -1050,8 +1054,13 @@ 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 =
|
||||
self.lower_fn_decl(&outer_decl, closure_id, fn_decl_span, FnDeclKind::Closure, None);
|
||||
let fn_decl = self.lower_fn_decl(
|
||||
&outer_decl,
|
||||
closure_id,
|
||||
fn_decl_span,
|
||||
FnDeclKind::Closure,
|
||||
CoroutineKind::None,
|
||||
);
|
||||
|
||||
let c = self.arena.alloc(hir::Closure {
|
||||
def_id: self.local_def_id(closure_id),
|
||||
|
@ -1,5 +1,3 @@
|
||||
use crate::FnReturnTransformation;
|
||||
|
||||
use super::errors::{InvalidAbi, InvalidAbiReason, InvalidAbiSuggestion, MisplacedRelaxTraitBound};
|
||||
use super::ResolverAstLoweringExt;
|
||||
use super::{AstOwner, ImplTraitContext, ImplTraitPosition};
|
||||
@ -208,35 +206,19 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
// `impl Future<Output = T>` here because lower_body
|
||||
// only cares about the input argument patterns in the function
|
||||
// declaration (decl), not the return types.
|
||||
let asyncness = header.asyncness;
|
||||
let genness = header.genness;
|
||||
let coro_kind = header.coro_kind;
|
||||
let body_id = this.lower_maybe_coroutine_body(
|
||||
span,
|
||||
hir_id,
|
||||
decl,
|
||||
asyncness,
|
||||
genness,
|
||||
coro_kind,
|
||||
body.as_deref(),
|
||||
);
|
||||
|
||||
let itctx = ImplTraitContext::Universal;
|
||||
let (generics, decl) =
|
||||
this.lower_generics(generics, header.constness, id, &itctx, |this| {
|
||||
let ret_id = asyncness
|
||||
.opt_return_id()
|
||||
.map(|(node_id, span)| {
|
||||
crate::FnReturnTransformation::Async(node_id, span)
|
||||
})
|
||||
.or_else(|| match genness {
|
||||
Gen::Yes { span, closure_id: _, return_impl_trait_id } => {
|
||||
Some(crate::FnReturnTransformation::Iterator(
|
||||
return_impl_trait_id,
|
||||
span,
|
||||
))
|
||||
}
|
||||
_ => None,
|
||||
});
|
||||
this.lower_fn_decl(decl, id, *fn_sig_span, FnDeclKind::Fn, ret_id)
|
||||
this.lower_fn_decl(decl, id, *fn_sig_span, FnDeclKind::Fn, coro_kind)
|
||||
});
|
||||
let sig = hir::FnSig {
|
||||
decl,
|
||||
@ -620,7 +602,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
i.id,
|
||||
sig.span,
|
||||
FnDeclKind::ExternFn,
|
||||
None,
|
||||
CoroutineKind::None,
|
||||
),
|
||||
this.lower_fn_params_to_names(fdec),
|
||||
)
|
||||
@ -747,28 +729,22 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
(generics, kind, expr.is_some())
|
||||
}
|
||||
AssocItemKind::Fn(box Fn { sig, generics, body: None, .. }) => {
|
||||
let asyncness = sig.header.asyncness;
|
||||
let names = self.lower_fn_params_to_names(&sig.decl);
|
||||
let (generics, sig) = self.lower_method_sig(
|
||||
generics,
|
||||
sig,
|
||||
i.id,
|
||||
FnDeclKind::Trait,
|
||||
asyncness
|
||||
.opt_return_id()
|
||||
.map(|(node_id, span)| crate::FnReturnTransformation::Async(node_id, span)),
|
||||
sig.header.coro_kind,
|
||||
);
|
||||
(generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Required(names)), false)
|
||||
}
|
||||
AssocItemKind::Fn(box Fn { sig, generics, body: Some(body), .. }) => {
|
||||
let asyncness = sig.header.asyncness;
|
||||
let genness = sig.header.genness;
|
||||
let body_id = self.lower_maybe_coroutine_body(
|
||||
i.span,
|
||||
hir_id,
|
||||
&sig.decl,
|
||||
asyncness,
|
||||
genness,
|
||||
sig.header.coro_kind,
|
||||
Some(body),
|
||||
);
|
||||
let (generics, sig) = self.lower_method_sig(
|
||||
@ -776,9 +752,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
sig,
|
||||
i.id,
|
||||
FnDeclKind::Trait,
|
||||
asyncness
|
||||
.opt_return_id()
|
||||
.map(|(node_id, span)| crate::FnReturnTransformation::Async(node_id, span)),
|
||||
sig.header.coro_kind,
|
||||
);
|
||||
(generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Provided(body_id)), true)
|
||||
}
|
||||
@ -867,14 +841,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
},
|
||||
),
|
||||
AssocItemKind::Fn(box Fn { sig, generics, body, .. }) => {
|
||||
let asyncness = sig.header.asyncness;
|
||||
let genness = sig.header.genness;
|
||||
self.current_item = Some(i.span);
|
||||
let body_id = self.lower_maybe_coroutine_body(
|
||||
i.span,
|
||||
hir_id,
|
||||
&sig.decl,
|
||||
asyncness,
|
||||
genness,
|
||||
sig.header.coro_kind,
|
||||
body.as_deref(),
|
||||
);
|
||||
let (generics, sig) = self.lower_method_sig(
|
||||
@ -882,9 +854,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
sig,
|
||||
i.id,
|
||||
if self.is_in_trait_impl { FnDeclKind::Impl } else { FnDeclKind::Inherent },
|
||||
asyncness
|
||||
.opt_return_id()
|
||||
.map(|(node_id, span)| crate::FnReturnTransformation::Async(node_id, span)),
|
||||
sig.header.coro_kind,
|
||||
);
|
||||
|
||||
(generics, hir::ImplItemKind::Fn(sig, body_id))
|
||||
@ -1055,15 +1025,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
span: Span,
|
||||
fn_id: hir::HirId,
|
||||
decl: &FnDecl,
|
||||
asyncness: Async,
|
||||
genness: Gen,
|
||||
coro_kind: CoroutineKind,
|
||||
body: Option<&Block>,
|
||||
) -> hir::BodyId {
|
||||
let (closure_id, body) = match (asyncness, genness, body) {
|
||||
// FIXME(eholk): do something reasonable for `async gen fn`. Probably that's an error
|
||||
// for now since it's not supported.
|
||||
(Async::Yes { closure_id, .. }, _, Some(body))
|
||||
| (_, Gen::Yes { closure_id, .. }, Some(body)) => (closure_id, body),
|
||||
let (closure_id, body) = match (coro_kind, body) {
|
||||
(
|
||||
CoroutineKind::Async { closure_id, .. } | CoroutineKind::Gen { closure_id, .. },
|
||||
Some(body),
|
||||
) => (closure_id, body),
|
||||
_ => return self.lower_fn_body_block(span, decl, body),
|
||||
};
|
||||
|
||||
@ -1232,8 +1201,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
|
||||
this.expr_block(body)
|
||||
};
|
||||
let coroutine_expr = match (asyncness, genness) {
|
||||
(Async::Yes { .. }, _) => this.make_async_expr(
|
||||
let coroutine_expr = match coro_kind {
|
||||
CoroutineKind::Async { .. } => this.make_async_expr(
|
||||
CaptureBy::Value { move_kw: rustc_span::DUMMY_SP },
|
||||
closure_id,
|
||||
None,
|
||||
@ -1241,7 +1210,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
hir::CoroutineSource::Fn,
|
||||
mkbody,
|
||||
),
|
||||
(_, Gen::Yes { .. }) => this.make_gen_expr(
|
||||
CoroutineKind::Gen { .. } => this.make_gen_expr(
|
||||
CaptureBy::Value { move_kw: rustc_span::DUMMY_SP },
|
||||
closure_id,
|
||||
None,
|
||||
@ -1249,7 +1218,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
hir::CoroutineSource::Fn,
|
||||
mkbody,
|
||||
),
|
||||
_ => unreachable!("we must have either an async fn or a gen fn"),
|
||||
CoroutineKind::None => unreachable!("we must have either an async fn or a gen fn"),
|
||||
};
|
||||
|
||||
let hir_id = this.lower_node_id(closure_id);
|
||||
@ -1266,21 +1235,26 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
sig: &FnSig,
|
||||
id: NodeId,
|
||||
kind: FnDeclKind,
|
||||
transform_return_type: Option<FnReturnTransformation>,
|
||||
coro_kind: CoroutineKind,
|
||||
) -> (&'hir hir::Generics<'hir>, hir::FnSig<'hir>) {
|
||||
let header = self.lower_fn_header(sig.header);
|
||||
let itctx = ImplTraitContext::Universal;
|
||||
let (generics, decl) =
|
||||
self.lower_generics(generics, sig.header.constness, id, &itctx, |this| {
|
||||
this.lower_fn_decl(&sig.decl, id, sig.span, kind, transform_return_type)
|
||||
this.lower_fn_decl(&sig.decl, id, sig.span, kind, coro_kind)
|
||||
});
|
||||
(generics, hir::FnSig { header, decl, span: self.lower_span(sig.span) })
|
||||
}
|
||||
|
||||
fn lower_fn_header(&mut self, h: FnHeader) -> hir::FnHeader {
|
||||
let asyncness = if let CoroutineKind::Async { span, .. } = h.coro_kind {
|
||||
hir::IsAsync::Async(span)
|
||||
} else {
|
||||
hir::IsAsync::NotAsync
|
||||
};
|
||||
hir::FnHeader {
|
||||
unsafety: self.lower_unsafety(h.unsafety),
|
||||
asyncness: self.lower_asyncness(h.asyncness),
|
||||
asyncness: asyncness,
|
||||
constness: self.lower_constness(h.constness),
|
||||
abi: self.lower_extern(h.ext),
|
||||
}
|
||||
@ -1322,13 +1296,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
});
|
||||
}
|
||||
|
||||
fn lower_asyncness(&mut self, a: Async) -> hir::IsAsync {
|
||||
match a {
|
||||
Async::Yes { span, .. } => hir::IsAsync::Async(span),
|
||||
Async::No => hir::IsAsync::NotAsync,
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn lower_constness(&mut self, c: Const) -> hir::Constness {
|
||||
match c {
|
||||
Const::Yes(_) => hir::Constness::Const,
|
||||
|
@ -493,21 +493,6 @@ enum ParenthesizedGenericArgs {
|
||||
Err,
|
||||
}
|
||||
|
||||
/// Describes a return type transformation that can be performed by `LoweringContext::lower_fn_decl`
|
||||
#[derive(Debug)]
|
||||
enum FnReturnTransformation {
|
||||
/// Replaces a return type `T` with `impl Future<Output = T>`.
|
||||
///
|
||||
/// The `NodeId` is the ID of the return type `impl Trait` item, and the `Span` points to the
|
||||
/// `async` keyword.
|
||||
Async(NodeId, Span),
|
||||
/// Replaces a return type `T` with `impl Iterator<Item = T>`.
|
||||
///
|
||||
/// The `NodeId` is the ID of the return type `impl Trait` item, and the `Span` points to the
|
||||
/// `gen` keyword.
|
||||
Iterator(NodeId, Span),
|
||||
}
|
||||
|
||||
impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
fn create_def(
|
||||
&mut self,
|
||||
@ -1374,7 +1359,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
generic_params,
|
||||
unsafety: self.lower_unsafety(f.unsafety),
|
||||
abi: self.lower_extern(f.ext),
|
||||
decl: self.lower_fn_decl(&f.decl, t.id, t.span, FnDeclKind::Pointer, None),
|
||||
decl: self.lower_fn_decl(
|
||||
&f.decl,
|
||||
t.id,
|
||||
t.span,
|
||||
FnDeclKind::Pointer,
|
||||
CoroutineKind::None,
|
||||
),
|
||||
param_names: self.lower_fn_params_to_names(&f.decl),
|
||||
}))
|
||||
}
|
||||
@ -1809,7 +1800,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
fn_node_id: NodeId,
|
||||
fn_span: Span,
|
||||
kind: FnDeclKind,
|
||||
transform_return_type: Option<FnReturnTransformation>,
|
||||
coro: CoroutineKind,
|
||||
) -> &'hir hir::FnDecl<'hir> {
|
||||
let c_variadic = decl.c_variadic();
|
||||
|
||||
@ -1838,12 +1829,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
self.lower_ty_direct(¶m.ty, &itctx)
|
||||
}));
|
||||
|
||||
let output = match transform_return_type {
|
||||
Some(transform) => {
|
||||
let output = match coro {
|
||||
CoroutineKind::Async { .. } | CoroutineKind::Gen { .. } => {
|
||||
let fn_def_id = self.local_def_id(fn_node_id);
|
||||
self.lower_coroutine_fn_ret_ty(&decl.output, fn_def_id, transform, kind, fn_span)
|
||||
self.lower_coroutine_fn_ret_ty(&decl.output, fn_def_id, coro, kind, fn_span)
|
||||
}
|
||||
None => match &decl.output {
|
||||
CoroutineKind::None => match &decl.output {
|
||||
FnRetTy::Ty(ty) => {
|
||||
let context = if kind.return_impl_trait_allowed() {
|
||||
let fn_def_id = self.local_def_id(fn_node_id);
|
||||
@ -1910,16 +1901,19 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
&mut self,
|
||||
output: &FnRetTy,
|
||||
fn_def_id: LocalDefId,
|
||||
transform: FnReturnTransformation,
|
||||
coro: CoroutineKind,
|
||||
fn_kind: FnDeclKind,
|
||||
fn_span: Span,
|
||||
) -> hir::FnRetTy<'hir> {
|
||||
let span = self.lower_span(fn_span);
|
||||
let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::Async, span, None);
|
||||
|
||||
let opaque_ty_node_id = match transform {
|
||||
FnReturnTransformation::Async(opaque_ty_node_id, _)
|
||||
| FnReturnTransformation::Iterator(opaque_ty_node_id, _) => opaque_ty_node_id,
|
||||
let opaque_ty_node_id = match coro {
|
||||
CoroutineKind::Async { return_impl_trait_id, .. }
|
||||
| CoroutineKind::Gen { return_impl_trait_id, .. } => return_impl_trait_id,
|
||||
CoroutineKind::None => {
|
||||
unreachable!("lower_coroutine_fn_ret_ty must be called with either Async or Gen")
|
||||
}
|
||||
};
|
||||
|
||||
let captured_lifetimes: Vec<_> = self
|
||||
@ -1939,7 +1933,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
|this| {
|
||||
let future_bound = this.lower_coroutine_fn_output_type_to_future_bound(
|
||||
output,
|
||||
transform,
|
||||
coro,
|
||||
span,
|
||||
ImplTraitContext::ReturnPositionOpaqueTy {
|
||||
origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id),
|
||||
@ -1958,7 +1952,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
fn lower_coroutine_fn_output_type_to_future_bound(
|
||||
&mut self,
|
||||
output: &FnRetTy,
|
||||
transform: FnReturnTransformation,
|
||||
coro: CoroutineKind,
|
||||
span: Span,
|
||||
nested_impl_trait_context: ImplTraitContext,
|
||||
) -> hir::GenericBound<'hir> {
|
||||
@ -1974,11 +1968,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
};
|
||||
|
||||
// "<Output|Item = T>"
|
||||
let (symbol, lang_item) = match transform {
|
||||
FnReturnTransformation::Async(..) => (hir::FN_OUTPUT_NAME, hir::LangItem::Future),
|
||||
FnReturnTransformation::Iterator(..) => {
|
||||
(hir::ITERATOR_ITEM_NAME, hir::LangItem::Iterator)
|
||||
}
|
||||
let (symbol, lang_item) = match coro {
|
||||
CoroutineKind::Async { .. } => (hir::FN_OUTPUT_NAME, hir::LangItem::Future),
|
||||
CoroutineKind::Gen { .. } => (hir::ITERATOR_ITEM_NAME, hir::LangItem::Iterator),
|
||||
CoroutineKind::None => panic!("attemping to lower output type of non-coroutine fn"),
|
||||
};
|
||||
|
||||
let future_args = self.arena.alloc(hir::GenericArgs {
|
||||
|
@ -1271,7 +1271,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
// Functions cannot both be `const async`
|
||||
if let Some(&FnHeader {
|
||||
constness: Const::Yes(cspan),
|
||||
asyncness: Async::Yes { span: aspan, .. },
|
||||
coro_kind: CoroutineKind::Async { span: aspan, .. },
|
||||
..
|
||||
}) = fk.header()
|
||||
{
|
||||
|
@ -1490,9 +1490,15 @@ impl<'a> State<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn print_asyncness(&mut self, asyncness: ast::Async) {
|
||||
if asyncness.is_async() {
|
||||
self.word_nbsp("async");
|
||||
fn print_coro_kind(&mut self, coro_kind: ast::CoroutineKind) {
|
||||
match coro_kind {
|
||||
ast::CoroutineKind::None => {}
|
||||
ast::CoroutineKind::Gen { .. } => {
|
||||
self.word_nbsp("gen");
|
||||
}
|
||||
ast::CoroutineKind::Async { .. } => {
|
||||
self.word_nbsp("async");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1685,7 +1691,7 @@ impl<'a> State<'a> {
|
||||
|
||||
fn print_fn_header_info(&mut self, header: ast::FnHeader) {
|
||||
self.print_constness(header.constness);
|
||||
self.print_asyncness(header.asyncness);
|
||||
self.print_coro_kind(header.coro_kind);
|
||||
self.print_unsafety(header.unsafety);
|
||||
|
||||
match header.ext {
|
||||
|
@ -413,7 +413,7 @@ impl<'a> State<'a> {
|
||||
binder,
|
||||
capture_clause,
|
||||
constness,
|
||||
asyncness,
|
||||
coro_kind,
|
||||
movability,
|
||||
fn_decl,
|
||||
body,
|
||||
@ -423,7 +423,7 @@ impl<'a> State<'a> {
|
||||
self.print_closure_binder(binder);
|
||||
self.print_constness(*constness);
|
||||
self.print_movability(*movability);
|
||||
self.print_asyncness(*asyncness);
|
||||
self.print_coro_kind(*coro_kind);
|
||||
self.print_capture_clause(*capture_clause);
|
||||
|
||||
self.print_fn_params_and_ret(fn_decl, true);
|
||||
|
@ -541,7 +541,7 @@ fn check_test_signature(
|
||||
return Err(sd.emit_err(errors::TestBadFn { span: i.span, cause: span, kind: "unsafe" }));
|
||||
}
|
||||
|
||||
if let ast::Async::Yes { span, .. } = f.sig.header.asyncness {
|
||||
if let ast::CoroutineKind::Async { span, .. } = f.sig.header.coro_kind {
|
||||
return Err(sd.emit_err(errors::TestBadFn { span: i.span, cause: span, kind: "async" }));
|
||||
}
|
||||
|
||||
|
@ -547,7 +547,7 @@ impl<'a> ExtCtxt<'a> {
|
||||
binder: ast::ClosureBinder::NotPresent,
|
||||
capture_clause: ast::CaptureBy::Ref,
|
||||
constness: ast::Const::No,
|
||||
asyncness: ast::Async::No,
|
||||
coro_kind: ast::CoroutineKind::None,
|
||||
movability: ast::Movability::Movable,
|
||||
fn_decl,
|
||||
body,
|
||||
|
@ -162,7 +162,9 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T>
|
||||
// Explicitly check for lints associated with 'closure_id', since
|
||||
// it does not have a corresponding AST node
|
||||
if let ast_visit::FnKind::Fn(_, _, sig, _, _, _) = fk {
|
||||
if let ast::Async::Yes { closure_id, .. } = sig.header.asyncness {
|
||||
if let ast::CoroutineKind::Async { closure_id, .. }
|
||||
| ast::CoroutineKind::Gen { closure_id, .. } = sig.header.coro_kind
|
||||
{
|
||||
self.check_id(closure_id);
|
||||
}
|
||||
}
|
||||
@ -223,7 +225,9 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T>
|
||||
// it does not have a corresponding AST node
|
||||
match e.kind {
|
||||
ast::ExprKind::Closure(box ast::Closure {
|
||||
asyncness: ast::Async::Yes { closure_id, .. },
|
||||
coro_kind:
|
||||
ast::CoroutineKind::Async { closure_id, .. }
|
||||
| ast::CoroutineKind::Gen { closure_id, .. },
|
||||
..
|
||||
}) => self.check_id(closure_id),
|
||||
_ => {}
|
||||
|
@ -21,7 +21,9 @@ use rustc_ast::util::parser::{prec_let_scrutinee_needs_par, AssocOp, Fixity};
|
||||
use rustc_ast::visit::Visitor;
|
||||
use rustc_ast::{self as ast, AttrStyle, AttrVec, CaptureBy, ExprField, UnOp, DUMMY_NODE_ID};
|
||||
use rustc_ast::{AnonConst, BinOp, BinOpKind, FnDecl, FnRetTy, MacCall, Param, Ty, TyKind};
|
||||
use rustc_ast::{Arm, Async, BlockCheckMode, Expr, ExprKind, Label, Movability, RangeLimits};
|
||||
use rustc_ast::{
|
||||
Arm, BlockCheckMode, CoroutineKind, Expr, ExprKind, Label, Movability, RangeLimits,
|
||||
};
|
||||
use rustc_ast::{ClosureBinder, MetaItemLit, StmtKind};
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||
@ -2237,7 +2239,7 @@ impl<'a> Parser<'a> {
|
||||
let asyncness = if self.token.uninterpolated_span().at_least_rust_2018() {
|
||||
self.parse_asyncness(Case::Sensitive)
|
||||
} else {
|
||||
Async::No
|
||||
CoroutineKind::None
|
||||
};
|
||||
|
||||
let capture_clause = self.parse_capture_clause()?;
|
||||
@ -2261,7 +2263,7 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
};
|
||||
|
||||
if let Async::Yes { span, .. } = asyncness {
|
||||
if let CoroutineKind::Async { span, .. } = asyncness {
|
||||
// Feature-gate `async ||` closures.
|
||||
self.sess.gated_spans.gate(sym::async_closure, span);
|
||||
}
|
||||
@ -2284,7 +2286,7 @@ impl<'a> Parser<'a> {
|
||||
binder,
|
||||
capture_clause,
|
||||
constness,
|
||||
asyncness,
|
||||
coro_kind: asyncness,
|
||||
movability,
|
||||
fn_decl,
|
||||
body,
|
||||
|
@ -11,8 +11,8 @@ use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree};
|
||||
use rustc_ast::util::case::Case;
|
||||
use rustc_ast::MacCall;
|
||||
use rustc_ast::{self as ast, AttrVec, Attribute, DUMMY_NODE_ID};
|
||||
use rustc_ast::{Async, Const, Defaultness, IsAuto, Mutability, Unsafe, UseTree, UseTreeKind};
|
||||
use rustc_ast::{BindingAnnotation, Block, FnDecl, FnSig, Param, SelfKind};
|
||||
use rustc_ast::{Const, Defaultness, IsAuto, Mutability, Unsafe, UseTree, UseTreeKind};
|
||||
use rustc_ast::{EnumDef, FieldDef, Generics, TraitRef, Ty, TyKind, Variant, VariantData};
|
||||
use rustc_ast::{FnHeader, ForeignItem, Path, PathSegment, Visibility, VisibilityKind};
|
||||
use rustc_ast_pretty::pprust;
|
||||
@ -2401,7 +2401,7 @@ impl<'a> Parser<'a> {
|
||||
let ext_start_sp = self.token.span;
|
||||
let ext = self.parse_extern(case);
|
||||
|
||||
if let Async::Yes { span, .. } = asyncness {
|
||||
if let CoroutineKind::Async { span, .. } = asyncness {
|
||||
if span.is_rust_2015() {
|
||||
self.sess.emit_err(errors::AsyncFnIn2015 {
|
||||
span,
|
||||
@ -2410,12 +2410,14 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
if let Gen::Yes { span, .. } = genness {
|
||||
if let CoroutineKind::Gen { span, .. } = genness {
|
||||
self.sess.gated_spans.gate(sym::gen_blocks, span);
|
||||
}
|
||||
|
||||
if let (Async::Yes { span: async_span, .. }, Gen::Yes { span: gen_span, .. }) =
|
||||
(asyncness, genness)
|
||||
if let (
|
||||
CoroutineKind::Async { span: async_span, .. },
|
||||
CoroutineKind::Gen { span: gen_span, .. },
|
||||
) = (asyncness, genness)
|
||||
{
|
||||
self.sess.emit_err(errors::AsyncGenFn { span: async_span.to(gen_span) });
|
||||
}
|
||||
@ -2450,9 +2452,12 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
} else if self.check_keyword(kw::Async) {
|
||||
match asyncness {
|
||||
Async::Yes { span, .. } => Some(WrongKw::Duplicated(span)),
|
||||
Async::No => {
|
||||
recover_asyncness = Async::Yes {
|
||||
CoroutineKind::Async { span, .. } => Some(WrongKw::Duplicated(span)),
|
||||
CoroutineKind::Gen { .. } => {
|
||||
panic!("not sure how to recover here")
|
||||
}
|
||||
CoroutineKind::None => {
|
||||
recover_asyncness = CoroutineKind::Async {
|
||||
span: self.token.span,
|
||||
closure_id: DUMMY_NODE_ID,
|
||||
return_impl_trait_id: DUMMY_NODE_ID,
|
||||
@ -2537,6 +2542,8 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME(eholk): add keyword recovery logic for genness
|
||||
|
||||
if wrong_kw.is_some()
|
||||
&& self.may_recover()
|
||||
&& self.look_ahead(1, |tok| tok.is_keyword_case(kw::Fn, case))
|
||||
@ -2548,8 +2555,7 @@ impl<'a> Parser<'a> {
|
||||
return Ok(FnHeader {
|
||||
constness: recover_constness,
|
||||
unsafety: recover_unsafety,
|
||||
asyncness: recover_asyncness,
|
||||
genness, // FIXME(eholk): add keyword recovery logic here too.
|
||||
coro_kind: recover_asyncness,
|
||||
ext,
|
||||
});
|
||||
}
|
||||
@ -2559,7 +2565,13 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
Ok(FnHeader { constness, unsafety, asyncness, ext, genness })
|
||||
let coro_kind = match asyncness {
|
||||
CoroutineKind::Async { .. } => asyncness,
|
||||
CoroutineKind::Gen { .. } => unreachable!("asycness cannot be Gen"),
|
||||
CoroutineKind::None => genness,
|
||||
};
|
||||
|
||||
Ok(FnHeader { constness, unsafety, coro_kind, ext })
|
||||
}
|
||||
|
||||
/// Parses the parameter list and result type of a function declaration.
|
||||
|
@ -11,7 +11,6 @@ mod stmt;
|
||||
mod ty;
|
||||
|
||||
use crate::lexer::UnmatchedDelim;
|
||||
use ast::Gen;
|
||||
pub use attr_wrapper::AttrWrapper;
|
||||
pub use diagnostics::AttemptLocalParseRecovery;
|
||||
pub(crate) use expr::ForbiddenLetReason;
|
||||
@ -25,9 +24,10 @@ use rustc_ast::tokenstream::{AttributesData, DelimSpan, Spacing};
|
||||
use rustc_ast::tokenstream::{TokenStream, TokenTree, TokenTreeCursor};
|
||||
use rustc_ast::util::case::Case;
|
||||
use rustc_ast::AttrId;
|
||||
use rustc_ast::CoroutineKind;
|
||||
use rustc_ast::DUMMY_NODE_ID;
|
||||
use rustc_ast::{self as ast, AnonConst, Const, DelimArgs, Extern};
|
||||
use rustc_ast::{Async, AttrArgs, AttrArgsEq, Expr, ExprKind, Mutability, StrLit};
|
||||
use rustc_ast::{AttrArgs, AttrArgsEq, Expr, ExprKind, Mutability, StrLit};
|
||||
use rustc_ast::{HasAttrs, HasTokens, Unsafe, Visibility, VisibilityKind};
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
@ -1125,22 +1125,30 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
|
||||
/// Parses asyncness: `async` or nothing.
|
||||
fn parse_asyncness(&mut self, case: Case) -> Async {
|
||||
fn parse_asyncness(&mut self, case: Case) -> CoroutineKind {
|
||||
if self.eat_keyword_case(kw::Async, case) {
|
||||
let span = self.prev_token.uninterpolated_span();
|
||||
Async::Yes { span, closure_id: DUMMY_NODE_ID, return_impl_trait_id: DUMMY_NODE_ID }
|
||||
CoroutineKind::Async {
|
||||
span,
|
||||
closure_id: DUMMY_NODE_ID,
|
||||
return_impl_trait_id: DUMMY_NODE_ID,
|
||||
}
|
||||
} else {
|
||||
Async::No
|
||||
CoroutineKind::None
|
||||
}
|
||||
}
|
||||
|
||||
/// Parses genness: `gen` or nothing.
|
||||
fn parse_genness(&mut self, case: Case) -> Gen {
|
||||
fn parse_genness(&mut self, case: Case) -> CoroutineKind {
|
||||
if self.token.span.at_least_rust_2024() && self.eat_keyword_case(kw::Gen, case) {
|
||||
let span = self.prev_token.uninterpolated_span();
|
||||
Gen::Yes { span, closure_id: DUMMY_NODE_ID, return_impl_trait_id: DUMMY_NODE_ID }
|
||||
CoroutineKind::Gen {
|
||||
span,
|
||||
closure_id: DUMMY_NODE_ID,
|
||||
return_impl_trait_id: DUMMY_NODE_ID,
|
||||
}
|
||||
} else {
|
||||
Gen::No
|
||||
CoroutineKind::None
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -596,7 +596,7 @@ impl<'a> Parser<'a> {
|
||||
tokens: None,
|
||||
};
|
||||
let span_start = self.token.span;
|
||||
let ast::FnHeader { ext, unsafety, constness, asyncness, genness: _ } =
|
||||
let ast::FnHeader { ext, unsafety, constness, coro_kind } =
|
||||
self.parse_fn_front_matter(&inherited_vis, Case::Sensitive)?;
|
||||
if self.may_recover() && self.token.kind == TokenKind::Lt {
|
||||
self.recover_fn_ptr_with_generics(lo, &mut params, param_insertion_point)?;
|
||||
@ -609,7 +609,7 @@ impl<'a> Parser<'a> {
|
||||
// cover it.
|
||||
self.sess.emit_err(FnPointerCannotBeConst { span: whole_span, qualifier: span });
|
||||
}
|
||||
if let ast::Async::Yes { span, .. } = asyncness {
|
||||
if let ast::CoroutineKind::Async { span, .. } = coro_kind {
|
||||
self.sess.emit_err(FnPointerCannotBeAsync { span: whole_span, qualifier: span });
|
||||
}
|
||||
// FIXME(eholk): emit a similar error for `gen fn()`
|
||||
|
@ -157,8 +157,8 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> {
|
||||
fn visit_fn(&mut self, fn_kind: FnKind<'a>, span: Span, _: NodeId) {
|
||||
if let FnKind::Fn(_, _, sig, _, generics, body) = fn_kind {
|
||||
// FIXME(eholk): handle `async gen fn`
|
||||
if let (Async::Yes { closure_id, .. }, _) | (_, Gen::Yes { closure_id, .. }) =
|
||||
(sig.header.asyncness, sig.header.genness)
|
||||
if let CoroutineKind::Async { closure_id, .. } | CoroutineKind::Gen { closure_id, .. } =
|
||||
sig.header.coro_kind
|
||||
{
|
||||
self.visit_generics(generics);
|
||||
|
||||
@ -284,11 +284,12 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> {
|
||||
// Async closures desugar to closures inside of closures, so
|
||||
// we must create two defs.
|
||||
let closure_def = self.create_def(expr.id, kw::Empty, DefKind::Closure, expr.span);
|
||||
match closure.asyncness {
|
||||
Async::Yes { closure_id, .. } => {
|
||||
match closure.coro_kind {
|
||||
CoroutineKind::Async { closure_id, .. }
|
||||
| CoroutineKind::Gen { closure_id, .. } => {
|
||||
self.create_def(closure_id, kw::Empty, DefKind::Closure, expr.span)
|
||||
}
|
||||
Async::No => closure_def,
|
||||
CoroutineKind::None => closure_def,
|
||||
}
|
||||
}
|
||||
ExprKind::Gen(_, _, _) => {
|
||||
|
@ -916,7 +916,7 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
|
||||
&sig.decl.output,
|
||||
);
|
||||
|
||||
if let Some((async_node_id, _)) = sig.header.asyncness.opt_return_id() {
|
||||
if let Some((async_node_id, _)) = sig.header.coro_kind.opt_return_id() {
|
||||
this.record_lifetime_params_for_impl_trait(async_node_id);
|
||||
}
|
||||
},
|
||||
@ -940,7 +940,7 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
|
||||
this.visit_generics(generics);
|
||||
|
||||
let declaration = &sig.decl;
|
||||
let async_node_id = sig.header.asyncness.opt_return_id();
|
||||
let async_node_id = sig.header.coro_kind.opt_return_id();
|
||||
|
||||
this.with_lifetime_rib(
|
||||
LifetimeRibKind::AnonymousCreateParameter {
|
||||
@ -4289,7 +4289,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
|
||||
// resolve the arguments within the proper scopes so that usages of them inside the
|
||||
// closure are detected as upvars rather than normal closure arg usages.
|
||||
ExprKind::Closure(box ast::Closure {
|
||||
asyncness: Async::Yes { .. },
|
||||
coro_kind: CoroutineKind::Async { .. },
|
||||
ref fn_decl,
|
||||
ref body,
|
||||
..
|
||||
|
@ -655,6 +655,205 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
|
||||
headers
|
||||
}
|
||||
|
||||
<<<<<<< HEAD:src/tools/clippy/clippy_lints/src/doc/mod.rs
|
||||
=======
|
||||
fn check_link_quotes(cx: &LateContext<'_>, trimmed_text: &str, range: Range<usize>, fragments: Fragments<'_>) {
|
||||
if trimmed_text.starts_with('\'')
|
||||
&& trimmed_text.ends_with('\'')
|
||||
&& let Some(span) = fragments.span(cx, range)
|
||||
{
|
||||
span_lint(
|
||||
cx,
|
||||
DOC_LINK_WITH_QUOTES,
|
||||
span,
|
||||
"possible intra-doc link using quotes instead of backticks",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn check_code(cx: &LateContext<'_>, text: &str, edition: Edition, range: Range<usize>, fragments: Fragments<'_>) {
|
||||
fn has_needless_main(code: String, edition: Edition) -> bool {
|
||||
rustc_driver::catch_fatal_errors(|| {
|
||||
rustc_span::create_session_globals_then(edition, || {
|
||||
let filename = FileName::anon_source_code(&code);
|
||||
|
||||
let fallback_bundle =
|
||||
rustc_errors::fallback_fluent_bundle(rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(), false);
|
||||
let emitter = EmitterWriter::new(Box::new(io::sink()), fallback_bundle);
|
||||
let handler = Handler::with_emitter(Box::new(emitter)).disable_warnings();
|
||||
#[expect(clippy::arc_with_non_send_sync)] // `Lrc` is expected by with_span_handler
|
||||
let sm = Lrc::new(SourceMap::new(FilePathMapping::empty()));
|
||||
let sess = ParseSess::with_span_handler(handler, sm);
|
||||
|
||||
let mut parser = match maybe_new_parser_from_source_str(&sess, filename, code) {
|
||||
Ok(p) => p,
|
||||
Err(errs) => {
|
||||
drop(errs);
|
||||
return false;
|
||||
},
|
||||
};
|
||||
|
||||
let mut relevant_main_found = false;
|
||||
loop {
|
||||
match parser.parse_item(ForceCollect::No) {
|
||||
Ok(Some(item)) => match &item.kind {
|
||||
ItemKind::Fn(box Fn {
|
||||
sig, body: Some(block), ..
|
||||
}) if item.ident.name == sym::main => {
|
||||
let is_async = sig.header.coro_kind.is_async();
|
||||
let returns_nothing = match &sig.decl.output {
|
||||
FnRetTy::Default(..) => true,
|
||||
FnRetTy::Ty(ty) if ty.kind.is_unit() => true,
|
||||
FnRetTy::Ty(_) => false,
|
||||
};
|
||||
|
||||
if returns_nothing && !is_async && !block.stmts.is_empty() {
|
||||
// This main function should be linted, but only if there are no other functions
|
||||
relevant_main_found = true;
|
||||
} else {
|
||||
// This main function should not be linted, we're done
|
||||
return false;
|
||||
}
|
||||
},
|
||||
// Tests with one of these items are ignored
|
||||
ItemKind::Static(..)
|
||||
| ItemKind::Const(..)
|
||||
| ItemKind::ExternCrate(..)
|
||||
| ItemKind::ForeignMod(..)
|
||||
// Another function was found; this case is ignored
|
||||
| ItemKind::Fn(..) => return false,
|
||||
_ => {},
|
||||
},
|
||||
Ok(None) => break,
|
||||
Err(e) => {
|
||||
e.cancel();
|
||||
return false;
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
relevant_main_found
|
||||
})
|
||||
})
|
||||
.ok()
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
let trailing_whitespace = text.len() - text.trim_end().len();
|
||||
|
||||
// Because of the global session, we need to create a new session in a different thread with
|
||||
// the edition we need.
|
||||
let text = text.to_owned();
|
||||
if thread::spawn(move || has_needless_main(text, edition))
|
||||
.join()
|
||||
.expect("thread::spawn failed")
|
||||
&& let Some(span) = fragments.span(cx, range.start..range.end - trailing_whitespace)
|
||||
{
|
||||
span_lint(cx, NEEDLESS_DOCTEST_MAIN, span, "needless `fn main` in doctest");
|
||||
}
|
||||
}
|
||||
|
||||
fn check_text(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, text: &str, span: Span) {
|
||||
for word in text.split(|c: char| c.is_whitespace() || c == '\'') {
|
||||
// Trim punctuation as in `some comment (see foo::bar).`
|
||||
// ^^
|
||||
// Or even as in `_foo bar_` which is emphasized. Also preserve `::` as a prefix/suffix.
|
||||
let mut word = word.trim_matches(|c: char| !c.is_alphanumeric() && c != ':');
|
||||
|
||||
// Remove leading or trailing single `:` which may be part of a sentence.
|
||||
if word.starts_with(':') && !word.starts_with("::") {
|
||||
word = word.trim_start_matches(':');
|
||||
}
|
||||
if word.ends_with(':') && !word.ends_with("::") {
|
||||
word = word.trim_end_matches(':');
|
||||
}
|
||||
|
||||
if valid_idents.contains(word) || word.chars().all(|c| c == ':') {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Adjust for the current word
|
||||
let offset = word.as_ptr() as usize - text.as_ptr() as usize;
|
||||
let span = Span::new(
|
||||
span.lo() + BytePos::from_usize(offset),
|
||||
span.lo() + BytePos::from_usize(offset + word.len()),
|
||||
span.ctxt(),
|
||||
span.parent(),
|
||||
);
|
||||
|
||||
check_word(cx, word, span);
|
||||
}
|
||||
}
|
||||
|
||||
fn check_word(cx: &LateContext<'_>, word: &str, span: Span) {
|
||||
/// Checks if a string is upper-camel-case, i.e., starts with an uppercase and
|
||||
/// contains at least two uppercase letters (`Clippy` is ok) and one lower-case
|
||||
/// letter (`NASA` is ok).
|
||||
/// Plurals are also excluded (`IDs` is ok).
|
||||
fn is_camel_case(s: &str) -> bool {
|
||||
if s.starts_with(|c: char| c.is_ascii_digit() | c.is_ascii_lowercase()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let s = s.strip_suffix('s').unwrap_or(s);
|
||||
|
||||
s.chars().all(char::is_alphanumeric)
|
||||
&& s.chars().filter(|&c| c.is_uppercase()).take(2).count() > 1
|
||||
&& s.chars().filter(|&c| c.is_lowercase()).take(1).count() > 0
|
||||
}
|
||||
|
||||
fn has_underscore(s: &str) -> bool {
|
||||
s != "_" && !s.contains("\\_") && s.contains('_')
|
||||
}
|
||||
|
||||
fn has_hyphen(s: &str) -> bool {
|
||||
s != "-" && s.contains('-')
|
||||
}
|
||||
|
||||
if let Ok(url) = Url::parse(word) {
|
||||
// try to get around the fact that `foo::bar` parses as a valid URL
|
||||
if !url.cannot_be_a_base() {
|
||||
span_lint(
|
||||
cx,
|
||||
DOC_MARKDOWN,
|
||||
span,
|
||||
"you should put bare URLs between `<`/`>` or make a proper Markdown link",
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// We assume that mixed-case words are not meant to be put inside backticks. (Issue #2343)
|
||||
if has_underscore(word) && has_hyphen(word) {
|
||||
return;
|
||||
}
|
||||
|
||||
if has_underscore(word) || word.contains("::") || is_camel_case(word) {
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
DOC_MARKDOWN,
|
||||
span,
|
||||
"item in documentation is missing backticks",
|
||||
|diag| {
|
||||
let snippet = snippet_with_applicability(cx, span, "..", &mut applicability);
|
||||
diag.span_suggestion_with_style(
|
||||
span,
|
||||
"try",
|
||||
format!("`{snippet}`"),
|
||||
applicability,
|
||||
// always show the suggestion in a separate line, since the
|
||||
// inline presentation adds another pair of backticks
|
||||
SuggestionStyle::ShowAlways,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
>>>>>>> d116f1718f1 (Merge Async and Gen into CoroutineKind):src/tools/clippy/clippy_lints/src/doc.rs
|
||||
struct FindPanicUnwrap<'a, 'tcx> {
|
||||
cx: &'a LateContext<'tcx>,
|
||||
panic_span: Option<Span>,
|
||||
|
@ -188,7 +188,7 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool {
|
||||
Closure(box ast::Closure {
|
||||
binder: lb,
|
||||
capture_clause: lc,
|
||||
asyncness: la,
|
||||
coro_kind: la,
|
||||
movability: lm,
|
||||
fn_decl: lf,
|
||||
body: le,
|
||||
@ -197,7 +197,7 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool {
|
||||
Closure(box ast::Closure {
|
||||
binder: rb,
|
||||
capture_clause: rc,
|
||||
asyncness: ra,
|
||||
coro_kind: ra,
|
||||
movability: rm,
|
||||
fn_decl: rf,
|
||||
body: re,
|
||||
@ -565,7 +565,7 @@ pub fn eq_fn_sig(l: &FnSig, r: &FnSig) -> bool {
|
||||
|
||||
pub fn eq_fn_header(l: &FnHeader, r: &FnHeader) -> bool {
|
||||
matches!(l.unsafety, Unsafe::No) == matches!(r.unsafety, Unsafe::No)
|
||||
&& l.asyncness.is_async() == r.asyncness.is_async()
|
||||
&& (l.coro_kind.is_async() == r.coro_kind.is_async() || l.coro_kind.is_gen() == r.coro_kind.is_gen())
|
||||
&& matches!(l.constness, Const::No) == matches!(r.constness, Const::No)
|
||||
&& eq_ext(&l.ext, &r.ext)
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ pub(crate) fn rewrite_closure(
|
||||
binder: &ast::ClosureBinder,
|
||||
constness: ast::Const,
|
||||
capture: ast::CaptureBy,
|
||||
is_async: &ast::Async,
|
||||
coro_kind: &ast::CoroutineKind,
|
||||
movability: ast::Movability,
|
||||
fn_decl: &ast::FnDecl,
|
||||
body: &ast::Expr,
|
||||
@ -40,7 +40,7 @@ pub(crate) fn rewrite_closure(
|
||||
debug!("rewrite_closure {:?}", body);
|
||||
|
||||
let (prefix, extra_offset) = rewrite_closure_fn_decl(
|
||||
binder, constness, capture, is_async, movability, fn_decl, body, span, context, shape,
|
||||
binder, constness, capture, coro_kind, movability, fn_decl, body, span, context, shape,
|
||||
)?;
|
||||
// 1 = space between `|...|` and body.
|
||||
let body_shape = shape.offset_left(extra_offset)?;
|
||||
@ -233,7 +233,7 @@ fn rewrite_closure_fn_decl(
|
||||
binder: &ast::ClosureBinder,
|
||||
constness: ast::Const,
|
||||
capture: ast::CaptureBy,
|
||||
asyncness: &ast::Async,
|
||||
coro_kind: &ast::CoroutineKind,
|
||||
movability: ast::Movability,
|
||||
fn_decl: &ast::FnDecl,
|
||||
body: &ast::Expr,
|
||||
@ -263,7 +263,8 @@ fn rewrite_closure_fn_decl(
|
||||
} else {
|
||||
""
|
||||
};
|
||||
let is_async = if asyncness.is_async() { "async " } else { "" };
|
||||
let is_async = if coro_kind.is_async() { "async " } else { "" };
|
||||
let is_gen = if coro_kind.is_gen() { "gen " } else { "" };
|
||||
let mover = if matches!(capture, ast::CaptureBy::Value { .. }) {
|
||||
"move "
|
||||
} else {
|
||||
@ -272,7 +273,14 @@ fn rewrite_closure_fn_decl(
|
||||
// 4 = "|| {".len(), which is overconservative when the closure consists of
|
||||
// a single expression.
|
||||
let nested_shape = shape
|
||||
.shrink_left(binder.len() + const_.len() + immovable.len() + is_async.len() + mover.len())?
|
||||
.shrink_left(
|
||||
binder.len()
|
||||
+ const_.len()
|
||||
+ immovable.len()
|
||||
+ is_async.len()
|
||||
+ is_gen.len()
|
||||
+ mover.len(),
|
||||
)?
|
||||
.sub_width(4)?;
|
||||
|
||||
// 1 = |
|
||||
@ -310,7 +318,7 @@ fn rewrite_closure_fn_decl(
|
||||
.tactic(tactic)
|
||||
.preserve_newline(true);
|
||||
let list_str = write_list(&item_vec, &fmt)?;
|
||||
let mut prefix = format!("{binder}{const_}{immovable}{is_async}{mover}|{list_str}|");
|
||||
let mut prefix = format!("{binder}{const_}{immovable}{is_async}{is_gen}{mover}|{list_str}|");
|
||||
|
||||
if !ret_str.is_empty() {
|
||||
if prefix.contains('\n') {
|
||||
@ -339,7 +347,7 @@ pub(crate) fn rewrite_last_closure(
|
||||
ref binder,
|
||||
constness,
|
||||
capture_clause,
|
||||
ref asyncness,
|
||||
ref coro_kind,
|
||||
movability,
|
||||
ref fn_decl,
|
||||
ref body,
|
||||
@ -360,7 +368,7 @@ pub(crate) fn rewrite_last_closure(
|
||||
binder,
|
||||
constness,
|
||||
capture_clause,
|
||||
asyncness,
|
||||
coro_kind,
|
||||
movability,
|
||||
fn_decl,
|
||||
body,
|
||||
|
@ -212,7 +212,7 @@ pub(crate) fn format_expr(
|
||||
&cl.binder,
|
||||
cl.constness,
|
||||
cl.capture_clause,
|
||||
&cl.asyncness,
|
||||
&cl.coro_kind,
|
||||
cl.movability,
|
||||
&cl.fn_decl,
|
||||
&cl.body,
|
||||
|
@ -287,7 +287,7 @@ pub(crate) struct FnSig<'a> {
|
||||
decl: &'a ast::FnDecl,
|
||||
generics: &'a ast::Generics,
|
||||
ext: ast::Extern,
|
||||
is_async: Cow<'a, ast::Async>,
|
||||
coro_kind: Cow<'a, ast::CoroutineKind>,
|
||||
constness: ast::Const,
|
||||
defaultness: ast::Defaultness,
|
||||
unsafety: ast::Unsafe,
|
||||
@ -302,7 +302,7 @@ impl<'a> FnSig<'a> {
|
||||
) -> FnSig<'a> {
|
||||
FnSig {
|
||||
unsafety: method_sig.header.unsafety,
|
||||
is_async: Cow::Borrowed(&method_sig.header.asyncness),
|
||||
coro_kind: Cow::Borrowed(&method_sig.header.coro_kind),
|
||||
constness: method_sig.header.constness,
|
||||
defaultness: ast::Defaultness::Final,
|
||||
ext: method_sig.header.ext,
|
||||
@ -328,7 +328,7 @@ impl<'a> FnSig<'a> {
|
||||
generics,
|
||||
ext: fn_sig.header.ext,
|
||||
constness: fn_sig.header.constness,
|
||||
is_async: Cow::Borrowed(&fn_sig.header.asyncness),
|
||||
coro_kind: Cow::Borrowed(&fn_sig.header.coro_kind),
|
||||
defaultness,
|
||||
unsafety: fn_sig.header.unsafety,
|
||||
visibility: vis,
|
||||
@ -343,7 +343,7 @@ impl<'a> FnSig<'a> {
|
||||
result.push_str(&*format_visibility(context, self.visibility));
|
||||
result.push_str(format_defaultness(self.defaultness));
|
||||
result.push_str(format_constness(self.constness));
|
||||
result.push_str(format_async(&self.is_async));
|
||||
result.push_str(format_coro(&self.coro_kind));
|
||||
result.push_str(format_unsafety(self.unsafety));
|
||||
result.push_str(&format_extern(
|
||||
self.ext,
|
||||
|
@ -75,10 +75,11 @@ pub(crate) fn format_visibility(
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn format_async(is_async: &ast::Async) -> &'static str {
|
||||
match is_async {
|
||||
ast::Async::Yes { .. } => "async ",
|
||||
ast::Async::No => "",
|
||||
pub(crate) fn format_coro(coro_kind: &ast::CoroutineKind) -> &'static str {
|
||||
match coro_kind {
|
||||
ast::CoroutineKind::Async { .. } => "async ",
|
||||
ast::CoroutineKind::Gen { .. } => "gen ",
|
||||
ast::CoroutineKind::None => "",
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,8 @@
|
||||
// run-pass
|
||||
#![feature(gen_blocks)]
|
||||
|
||||
// make sure that a ridiculously simple gen fn works as an iterator.
|
||||
|
||||
gen fn foo() -> i32 {
|
||||
yield 1;
|
||||
yield 2;
|
||||
|
Loading…
Reference in New Issue
Block a user